2020-02-08 11:55:27 -07:00
const data = require ( './stub/data' ) ;
const logger = require ( './stub/logger' ) ;
const zigbeeHerdsman = require ( './stub/zigbeeHerdsman' ) ;
const MQTT = require ( './stub/mqtt' ) ;
const settings = require ( '../lib/util/settings' ) ;
const Controller = require ( '../lib/controller' ) ;
const flushPromises = ( ) => new Promise ( setImmediate ) ;
const zigbeeHerdsmanConverters = require ( 'zigbee-herdsman-converters' ) ;
2020-09-24 09:06:43 -07:00
const stringify = require ( 'json-stable-stringify-without-jsonify' ) ;
2020-02-08 11:55:27 -07:00
describe ( 'OTA update' , ( ) => {
let controller ;
mockClear = ( mapped ) => {
mapped . ota . updateToLatest = jest . fn ( ) ;
mapped . ota . isUpdateAvailable = jest . fn ( ) ;
}
beforeEach ( async ( ) => {
data . writeDefaultConfiguration ( ) ;
settings . _reRead ( ) ;
2020-12-09 11:51:16 -07:00
settings . set ( [ 'advanced' , 'ikea_ota_use_test_url' ] , true ) ;
2020-02-08 11:55:27 -07:00
data . writeEmptyState ( ) ;
controller = new Controller ( ) ;
await controller . start ( ) ;
await flushPromises ( ) ;
MQTT . publish . mockClear ( ) ;
} ) ;
it ( 'Should OTA update a device' , async ( ) => {
const device = zigbeeHerdsman . devices . bulb ;
2020-02-09 12:44:37 -07:00
const endpoint = device . endpoints [ 0 ] ;
let count = 0 ;
endpoint . read . mockImplementation ( ( ) => {
count ++ ;
return { swBuildId : count , dateCode : '2019010' + count }
} ) ;
2020-04-13 12:15:08 -07:00
const mapped = zigbeeHerdsmanConverters . findByDevice ( device )
2020-02-08 11:55:27 -07:00
mockClear ( mapped ) ;
logger . info . mockClear ( ) ;
2020-02-09 12:44:37 -07:00
device . save . mockClear ( ) ;
2020-02-08 11:55:27 -07:00
mapped . ota . updateToLatest . mockImplementationOnce ( ( a , b , onUpdate ) => {
2020-02-09 12:44:37 -07:00
onUpdate ( 0 , null ) ;
2020-08-02 14:09:43 -07:00
onUpdate ( 10 , 3600.2123 ) ;
2020-02-08 11:55:27 -07:00
} ) ;
2020-07-13 14:00:33 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/device/ota_update/update' , 'bulb' ) ;
2020-02-08 11:55:27 -07:00
await flushPromises ( ) ;
2020-02-09 12:44:37 -07:00
expect ( logger . info ) . toHaveBeenCalledWith ( ` Updating 'bulb' to latest firmware ` ) ;
expect ( mapped . ota . isUpdateAvailable ) . toHaveBeenCalledTimes ( 0 ) ;
2020-02-08 11:55:27 -07:00
expect ( mapped . ota . updateToLatest ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( mapped . ota . updateToLatest ) . toHaveBeenCalledWith ( device , logger , expect . any ( Function ) ) ;
2020-04-24 13:38:51 -07:00
expect ( logger . info ) . toHaveBeenCalledWith ( ` Update of 'bulb' at 0.00% ` ) ;
expect ( logger . info ) . toHaveBeenCalledWith ( ` Update of 'bulb' at 10.00%, +- 60 minutes remaining ` ) ;
2020-08-13 11:00:35 -07:00
expect ( logger . info ) . toHaveBeenCalledWith ( ` Finished update of 'bulb', from '{"dateCode":"20190101","softwareBuildID":1}' to '{"dateCode":"20190102","softwareBuildID":2}' ` ) ;
2020-02-09 12:44:37 -07:00
expect ( device . save ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( device . dateCode ) . toBe ( '20190102' ) ;
expect ( device . softwareBuildID ) . toBe ( 2 ) ;
2020-08-02 14:09:43 -07:00
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bulb' ,
2020-08-13 11:00:35 -07:00
stringify ( { "update_available" : false , "update" : { "state" : "updating" , "progress" : 0 } } ) ,
2020-08-02 14:09:43 -07:00
{ retain : true , qos : 0 } , expect . any ( Function )
) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bulb' ,
2020-08-13 11:00:35 -07:00
stringify ( { "update_available" : false , "update" : { "state" : "updating" , "progress" : 10 , "remaining" : 3600 } } ) ,
2020-08-02 14:09:43 -07:00
{ retain : true , qos : 0 } , expect . any ( Function )
) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bulb' ,
2020-08-13 11:00:35 -07:00
stringify ( { "update_available" : false , "update" : { "state" : "idle" } } ) ,
2020-08-02 14:09:43 -07:00
{ retain : true , qos : 0 } , expect . any ( Function )
) ;
2020-07-08 14:23:44 -07:00
expect ( MQTT . publish ) . toHaveBeenCalledWith (
2020-07-13 14:00:33 -07:00
'zigbee2mqtt/bridge/response/device/ota_update/update' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { "id" : "bulb" , "from" : { "software_build_id" : 1 , "date_code" : "20190101" } , "to" : { "software_build_id" : 2 , "date_code" : "20190102" } } , "status" : "ok" } ) ,
2020-07-08 14:23:44 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
2020-09-15 13:13:30 -07:00
) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/devices' ,
expect . any ( String ) ,
{ retain : true , qos : 0 } ,
expect . any ( Function )
2020-07-08 14:23:44 -07:00
) ;
2020-02-08 11:55:27 -07:00
} ) ;
2020-02-09 12:44:37 -07:00
it ( 'Should handle when OTA update fails' , async ( ) => {
2020-02-08 11:55:27 -07:00
const device = zigbeeHerdsman . devices . bulb ;
2020-02-09 12:44:37 -07:00
const endpoint = device . endpoints [ 0 ] ;
endpoint . read . mockImplementation ( ( ) => { return { swBuildId : 1 , dateCode : '2019010' } } ) ;
2020-04-13 12:15:08 -07:00
const mapped = zigbeeHerdsmanConverters . findByDevice ( device )
2020-02-08 11:55:27 -07:00
mockClear ( mapped ) ;
2020-02-09 12:44:37 -07:00
device . save . mockClear ( ) ;
mapped . ota . updateToLatest . mockImplementationOnce ( ( a , b , onUpdate ) => {
throw new Error ( 'Update failed' ) ;
} ) ;
2020-02-08 11:55:27 -07:00
2020-08-13 11:00:35 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/device/ota_update/update' , stringify ( { id : "bulb" } ) ) ;
2020-02-08 11:55:27 -07:00
await flushPromises ( ) ;
2020-08-02 14:09:43 -07:00
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bulb' ,
2020-08-13 11:00:35 -07:00
stringify ( { "update_available" : true , "update" : { "state" : "available" } } ) ,
2020-08-02 14:09:43 -07:00
{ retain : true , qos : 0 } , expect . any ( Function )
) ;
2020-07-08 14:23:44 -07:00
expect ( MQTT . publish ) . toHaveBeenCalledWith (
2020-07-13 14:00:33 -07:00
'zigbee2mqtt/bridge/response/device/ota_update/update' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { "id" : "bulb" } , "status" : "error" , "error" : "Update of 'bulb' failed (Update failed)" } ) ,
2020-07-08 14:23:44 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
2020-02-08 11:55:27 -07:00
} ) ;
it ( 'Should be able to check if OTA update is available' , async ( ) => {
const device = zigbeeHerdsman . devices . bulb ;
2020-04-13 12:15:08 -07:00
const mapped = zigbeeHerdsmanConverters . findByDevice ( device )
2020-02-08 11:55:27 -07:00
mockClear ( mapped ) ;
2020-02-09 12:44:37 -07:00
2020-02-08 11:55:27 -07:00
mapped . ota . isUpdateAvailable . mockReturnValueOnce ( false ) ;
2020-07-13 14:00:33 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/device/ota_update/check' , "bulb" ) ;
2020-02-08 11:55:27 -07:00
await flushPromises ( ) ;
expect ( mapped . ota . isUpdateAvailable ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( mapped . ota . updateToLatest ) . toHaveBeenCalledTimes ( 0 ) ;
2020-07-08 14:23:44 -07:00
expect ( MQTT . publish ) . toHaveBeenCalledWith (
2020-07-13 14:00:33 -07:00
'zigbee2mqtt/bridge/response/device/ota_update/check' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { "id" : "bulb" , "updateAvailable" : false } , "status" : "ok" } ) ,
2020-07-08 14:23:44 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
2020-02-09 12:44:37 -07:00
2020-07-08 14:23:44 -07:00
MQTT . publish . mockClear ( ) ;
2020-02-09 12:44:37 -07:00
mapped . ota . isUpdateAvailable . mockReturnValueOnce ( true ) ;
2020-07-13 14:00:33 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/device/ota_update/check' , "bulb" ) ;
2020-02-09 12:44:37 -07:00
await flushPromises ( ) ;
expect ( mapped . ota . isUpdateAvailable ) . toHaveBeenCalledTimes ( 2 ) ;
expect ( mapped . ota . updateToLatest ) . toHaveBeenCalledTimes ( 0 ) ;
2020-07-08 14:23:44 -07:00
expect ( MQTT . publish ) . toHaveBeenCalledWith (
2020-07-13 14:00:33 -07:00
'zigbee2mqtt/bridge/response/device/ota_update/check' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { "id" : "bulb" , "updateAvailable" : true } , "status" : "ok" } ) ,
2020-07-08 14:23:44 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
2020-02-09 12:44:37 -07:00
} ) ;
it ( 'Should handle if OTA update check fails' , async ( ) => {
const device = zigbeeHerdsman . devices . bulb ;
2020-04-13 12:15:08 -07:00
const mapped = zigbeeHerdsmanConverters . findByDevice ( device )
2020-02-09 12:44:37 -07:00
mockClear ( mapped ) ;
mapped . ota . isUpdateAvailable . mockImplementationOnce ( ( ) => { throw new Error ( 'RF singals disturbed because of dogs barking' ) } ) ;
2020-07-13 14:00:33 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/device/ota_update/check' , "bulb" ) ;
2020-02-09 12:44:37 -07:00
await flushPromises ( ) ;
expect ( mapped . ota . isUpdateAvailable ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( mapped . ota . updateToLatest ) . toHaveBeenCalledTimes ( 0 ) ;
2020-07-08 14:23:44 -07:00
expect ( MQTT . publish ) . toHaveBeenCalledWith (
2020-07-13 14:00:33 -07:00
'zigbee2mqtt/bridge/response/device/ota_update/check' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { "id" : "bulb" } , "status" : "error" , "error" : ` Failed to check if update available for 'bulb' (RF singals disturbed because of dogs barking) ` } ) ,
2020-07-08 14:23:44 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
it ( 'Should fail when device does not exist' , async ( ) => {
2020-07-13 14:00:33 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/device/ota_update/check' , "not_existing_deviceooo" ) ;
2020-07-08 14:23:44 -07:00
await flushPromises ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
2020-07-13 14:00:33 -07:00
'zigbee2mqtt/bridge/response/device/ota_update/check' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { "id" : "not_existing_deviceooo" } , "status" : "error" , "error" : ` Device 'not_existing_deviceooo' does not exist ` } ) ,
2020-07-08 14:23:44 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
2020-02-08 11:55:27 -07:00
} ) ;
it ( 'Should not check for OTA when device does not support it' , async ( ) => {
2020-07-13 14:00:33 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/device/ota_update/check' , "ZNLDP12LM" ) ;
2020-02-08 11:55:27 -07:00
await flushPromises ( ) ;
2020-07-08 14:23:44 -07:00
expect ( MQTT . publish ) . toHaveBeenCalledWith (
2020-07-13 14:00:33 -07:00
'zigbee2mqtt/bridge/response/device/ota_update/check' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { "id" : "ZNLDP12LM" } , "status" : "error" , "error" : ` Device 'ZNLDP12LM' does not support OTA updates ` } ) ,
2020-07-08 14:23:44 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
2020-02-08 11:55:27 -07:00
} ) ;
2020-02-09 12:44:37 -07:00
it ( 'Should refuse to check/update when already in progress' , async ( ) => {
jest . useFakeTimers ( ) ;
const device = zigbeeHerdsman . devices . bulb ;
2020-04-13 12:15:08 -07:00
const mapped = zigbeeHerdsmanConverters . findByDevice ( device )
2020-02-09 12:44:37 -07:00
mockClear ( mapped ) ;
mapped . ota . isUpdateAvailable . mockImplementationOnce ( ( ) => {
return new Promise ( ( resolve , reject ) => { setTimeout ( ( ) => resolve ( ) , 99999 ) } )
} ) ;
2020-07-13 14:00:33 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/device/ota_update/check' , "bulb" ) ;
2020-02-09 12:44:37 -07:00
await flushPromises ( ) ;
2020-07-13 14:00:33 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/device/ota_update/check' , "bulb" ) ;
2020-02-09 12:44:37 -07:00
await flushPromises ( ) ;
expect ( mapped . ota . isUpdateAvailable ) . toHaveBeenCalledTimes ( 1 ) ;
jest . runAllTimers ( ) ;
await flushPromises ( ) ;
2020-07-08 14:23:44 -07:00
expect ( MQTT . publish ) . toHaveBeenCalledWith (
2020-07-13 14:00:33 -07:00
'zigbee2mqtt/bridge/response/device/ota_update/check' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { "id" : "bulb" } , "status" : "error" , "error" : ` Update or check for update already in progress for 'bulb' ` } ) ,
2020-07-08 14:23:44 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
2020-02-09 12:44:37 -07:00
} ) ;
2020-02-13 13:10:44 -07:00
2020-07-14 13:09:11 -07:00
it ( 'Shouldnt crash when read modelID before/after OTA update fails' , async ( ) => {
2020-02-13 13:10:44 -07:00
const device = zigbeeHerdsman . devices . bulb ;
const endpoint = device . endpoints [ 0 ] ;
let count = 0 ;
2020-07-14 13:09:11 -07:00
endpoint . read . mockImplementation ( ( ) => { throw new Error ( 'Failed!' ) } ) ;
2020-02-13 13:10:44 -07:00
2020-04-13 12:15:08 -07:00
const mapped = zigbeeHerdsmanConverters . findByDevice ( device )
2020-02-13 13:10:44 -07:00
mockClear ( mapped ) ;
2020-07-13 14:00:33 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/device/ota_update/update' , "bulb" ) ;
2020-02-13 13:10:44 -07:00
await flushPromises ( ) ;
2020-07-08 14:23:44 -07:00
expect ( MQTT . publish ) . toHaveBeenCalledWith (
2020-07-13 14:00:33 -07:00
'zigbee2mqtt/bridge/response/device/ota_update/update' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { "id" : "bulb" , "from" : null , "to" : null } , "status" : "ok" } ) ,
2020-07-08 14:23:44 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
2020-02-13 13:10:44 -07:00
} ) ;
2020-02-16 08:00:15 -07:00
it ( 'Should check for update when device requests it' , async ( ) => {
const device = zigbeeHerdsman . devices . bulb ;
const data = { imageType : 12382 } ;
2020-04-13 12:15:08 -07:00
const mapped = zigbeeHerdsmanConverters . findByDevice ( device )
2020-02-16 08:00:15 -07:00
mockClear ( mapped ) ;
2020-02-20 12:01:26 -07:00
mapped . ota . isUpdateAvailable . mockReturnValueOnce ( true ) ;
2020-02-16 08:00:15 -07:00
const payload = { data , cluster : 'genOta' , device , endpoint : device . getEndpoint ( 1 ) , type : 'commandQueryNextImageRequest' , linkquality : 10 } ;
2020-02-20 12:01:26 -07:00
logger . info . mockClear ( ) ;
2020-02-16 08:00:15 -07:00
await zigbeeHerdsman . events . message ( payload ) ;
await flushPromises ( ) ;
expect ( mapped . ota . isUpdateAvailable ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( mapped . ota . isUpdateAvailable ) . toHaveBeenCalledWith ( device , logger , { "imageType" : 12382 } ) ;
2020-02-28 15:42:59 -07:00
expect ( logger . info ) . toHaveBeenCalledWith ( ` Update available for 'bulb' ` ) ;
2020-02-29 04:43:53 -07:00
expect ( device . endpoints [ 0 ] . commandResponse ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( device . endpoints [ 0 ] . commandResponse ) . toHaveBeenCalledWith ( "genOta" , "queryNextImageResponse" , { "status" : 0x95 } ) ;
2020-02-16 08:00:15 -07:00
// Should not request again when device asks again after a short time
await zigbeeHerdsman . events . message ( payload ) ;
await flushPromises ( ) ;
expect ( mapped . ota . isUpdateAvailable ) . toHaveBeenCalledTimes ( 1 ) ;
2020-02-20 12:01:26 -07:00
const extension = controller . extensions . find ( ( e ) => e . constructor . name === 'OTAUpdate' ) ;
extension . lastChecked = { } ;
logger . info . mockClear ( ) ;
mapped . ota . isUpdateAvailable . mockReturnValueOnce ( false ) ;
await zigbeeHerdsman . events . message ( payload ) ;
await flushPromises ( ) ;
2020-08-02 14:09:43 -07:00
expect ( logger . info ) . not . toHaveBeenCalledWith ( ` Update available for 'bulb' ` ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bulb' ,
2020-08-13 11:00:35 -07:00
stringify ( { "update_available" : true , "update" : { "state" : "available" } } ) ,
2020-08-02 14:09:43 -07:00
{ retain : true , qos : 0 } , expect . any ( Function )
) ;
2020-02-16 08:00:15 -07:00
} ) ;
2020-02-28 15:30:33 -07:00
it ( 'Should respond with NO_IMAGE_AVAILABLE when not supporting OTA' , async ( ) => {
2020-03-15 14:26:03 -07:00
const device = zigbeeHerdsman . devices . QBKG04LM ;
2020-02-28 15:30:33 -07:00
const data = { imageType : 12382 } ;
const payload = { data , cluster : 'genOta' , device , endpoint : device . getEndpoint ( 1 ) , type : 'commandQueryNextImageRequest' , linkquality : 10 } ;
await zigbeeHerdsman . events . message ( payload ) ;
await flushPromises ( ) ;
2020-02-29 04:43:53 -07:00
expect ( device . endpoints [ 0 ] . commandResponse ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( device . endpoints [ 0 ] . commandResponse ) . toHaveBeenCalledWith ( "genOta" , "queryNextImageResponse" , { "status" : 152 } ) ;
2020-02-28 15:30:33 -07:00
} ) ;
2020-04-28 12:23:32 -07:00
it ( 'Shouldnt respond with NO_IMAGE_AVAILABLE when not supporting OTA and device has no OTA endpoint' , async ( ) => {
const device = zigbeeHerdsman . devices . QBKG03LM ;
const data = { imageType : 12382 } ;
const payload = { data , cluster : 'genOta' , device , endpoint : device . getEndpoint ( 1 ) , type : 'commandQueryNextImageRequest' , linkquality : 10 } ;
logger . error . mockClear ( ) ;
await zigbeeHerdsman . events . message ( payload ) ;
await flushPromises ( ) ;
expect ( device . endpoints [ 0 ] . commandResponse ) . toHaveBeenCalledTimes ( 0 ) ;
expect ( logger . error ) . toHaveBeenCalledTimes ( 0 ) ;
} ) ;
2020-07-08 14:23:44 -07:00
it ( 'Legacy api: Should OTA update a device' , async ( ) => {
const device = zigbeeHerdsman . devices . bulb ;
const endpoint = device . endpoints [ 0 ] ;
let count = 0 ;
endpoint . read . mockImplementation ( ( ) => {
count ++ ;
return { swBuildId : count , dateCode : '2019010' + count }
} ) ;
const mapped = zigbeeHerdsmanConverters . findByDevice ( device )
mockClear ( mapped ) ;
logger . info . mockClear ( ) ;
logger . error . mockClear ( ) ;
device . save . mockClear ( ) ;
mapped . ota . updateToLatest . mockImplementationOnce ( ( a , b , onUpdate ) => {
onUpdate ( 0 , null ) ;
onUpdate ( 10 , 3600 ) ;
} ) ;
MQTT . events . message ( 'zigbee2mqtt/bridge/ota_update/update' , 'bulb' ) ;
await flushPromises ( ) ;
expect ( logger . info ) . toHaveBeenCalledWith ( ` Updating 'bulb' to latest firmware ` ) ;
expect ( mapped . ota . isUpdateAvailable ) . toHaveBeenCalledTimes ( 0 ) ;
expect ( mapped . ota . updateToLatest ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( mapped . ota . updateToLatest ) . toHaveBeenCalledWith ( device , logger , expect . any ( Function ) ) ;
expect ( logger . info ) . toHaveBeenCalledWith ( ` Update of 'bulb' at 0.00% ` ) ;
expect ( logger . info ) . toHaveBeenCalledWith ( ` Update of 'bulb' at 10.00%, +- 60 minutes remaining ` ) ;
2020-08-13 11:00:35 -07:00
expect ( logger . info ) . toHaveBeenCalledWith ( ` Finished update of 'bulb', from '{"dateCode":"20190101","softwareBuildID":1}' to '{"dateCode":"20190102","softwareBuildID":2}' ` ) ;
2020-07-08 14:23:44 -07:00
expect ( logger . error ) . toHaveBeenCalledTimes ( 0 ) ;
expect ( device . save ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( device . dateCode ) . toBe ( '20190102' ) ;
expect ( device . softwareBuildID ) . toBe ( 2 ) ;
} ) ;
it ( 'Legacy api: Should handle when OTA update fails' , async ( ) => {
const device = zigbeeHerdsman . devices . bulb ;
const endpoint = device . endpoints [ 0 ] ;
endpoint . read . mockImplementation ( ( ) => { return { swBuildId : 1 , dateCode : '2019010' } } ) ;
const mapped = zigbeeHerdsmanConverters . findByDevice ( device )
mockClear ( mapped ) ;
logger . info . mockClear ( ) ;
logger . error . mockClear ( ) ;
device . save . mockClear ( ) ;
mapped . ota . updateToLatest . mockImplementationOnce ( ( a , b , onUpdate ) => {
throw new Error ( 'Update failed' ) ;
} ) ;
MQTT . events . message ( 'zigbee2mqtt/bridge/ota_update/update' , 'bulb' ) ;
await flushPromises ( ) ;
expect ( logger . error ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( logger . error ) . toHaveBeenCalledWith ( ` Update of 'bulb' failed (Update failed) ` ) ;
} ) ;
it ( 'Legacy api: Should be able to check if OTA update is available' , async ( ) => {
const device = zigbeeHerdsman . devices . bulb ;
const mapped = zigbeeHerdsmanConverters . findByDevice ( device )
mockClear ( mapped ) ;
logger . info . mockClear ( ) ;
mapped . ota . isUpdateAvailable . mockReturnValueOnce ( false ) ;
MQTT . events . message ( 'zigbee2mqtt/bridge/ota_update/check' , 'bulb' ) ;
await flushPromises ( ) ;
expect ( mapped . ota . isUpdateAvailable ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( mapped . ota . updateToLatest ) . toHaveBeenCalledTimes ( 0 ) ;
expect ( logger . info ) . toHaveBeenCalledWith ( ` No update available for 'bulb' ` ) ;
logger . info . mockClear ( ) ;
mapped . ota . isUpdateAvailable . mockReturnValueOnce ( true ) ;
MQTT . events . message ( 'zigbee2mqtt/bridge/ota_update/check' , 'bulb' ) ;
await flushPromises ( ) ;
expect ( mapped . ota . isUpdateAvailable ) . toHaveBeenCalledTimes ( 2 ) ;
expect ( mapped . ota . updateToLatest ) . toHaveBeenCalledTimes ( 0 ) ;
expect ( logger . info ) . toHaveBeenCalledWith ( ` Update available for 'bulb' ` ) ;
} ) ;
it ( 'Legacy api: Should handle if OTA update check fails' , async ( ) => {
const device = zigbeeHerdsman . devices . bulb ;
const mapped = zigbeeHerdsmanConverters . findByDevice ( device )
mockClear ( mapped ) ;
logger . error . mockClear ( ) ;
mapped . ota . isUpdateAvailable . mockImplementationOnce ( ( ) => { throw new Error ( 'RF singals disturbed because of dogs barking' ) } ) ;
MQTT . events . message ( 'zigbee2mqtt/bridge/ota_update/check' , 'bulb' ) ;
await flushPromises ( ) ;
expect ( mapped . ota . isUpdateAvailable ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( mapped . ota . updateToLatest ) . toHaveBeenCalledTimes ( 0 ) ;
expect ( logger . error ) . toHaveBeenCalledWith ( ` Failed to check if update available for 'bulb' (RF singals disturbed because of dogs barking) ` ) ;
} ) ;
it ( 'Legacy api: Should not check for OTA when device does not support it' , async ( ) => {
MQTT . events . message ( 'zigbee2mqtt/bridge/ota_update/check' , 'ZNLDP12LM' ) ;
await flushPromises ( ) ;
expect ( logger . error ) . toHaveBeenCalledWith ( ` Device 'ZNLDP12LM' does not support OTA updates ` ) ;
} ) ;
it ( 'Legacy api: Shouldnt crash when read modelID after OTA update fails' , async ( ) => {
const device = zigbeeHerdsman . devices . bulb ;
const endpoint = device . endpoints [ 0 ] ;
let count = 0 ;
endpoint . read . mockImplementation ( ( ) => {
if ( count === 1 ) throw new Error ( 'Failed!' )
count ++ ;
return { swBuildId : 1 , dateCode : '2019010' }
} ) ;
const mapped = zigbeeHerdsmanConverters . findByDevice ( device )
mockClear ( mapped ) ;
logger . info . mockClear ( ) ;
MQTT . events . message ( 'zigbee2mqtt/bridge/ota_update/update' , 'bulb' ) ;
await flushPromises ( ) ;
expect ( logger . info ) . toHaveBeenCalledWith ( ` Finished update of 'bulb' ` ) ;
} ) ;
2020-02-08 11:55:27 -07:00
} ) ;