@onekeyfe/hd-core 1.2.0-alpha.116 → 1.2.0-alpha.118
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/__tests__/DeviceCommands.test.ts +2 -2
- package/__tests__/device-lifecycle-events.test.ts +1 -1
- package/__tests__/device-state-mapper.test.ts +4 -4
- package/__tests__/device-utils.test.ts +1 -1
- package/__tests__/firmware-update/firmware-update-v4-install-poll.test.ts +36 -89
- package/__tests__/get-device-state.test.ts +8 -8
- package/__tests__/protocol-v2-resources.test.ts +20 -0
- package/__tests__/protocol-v2.test.ts +411 -246
- package/dist/api/FirmwareUpdateV4.d.ts +0 -3
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceFirmwareUpdate.d.ts +3 -1
- package/dist/api/protocol-v2/DeviceFirmwareUpdate.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceInfoGet.d.ts +1 -1
- package/dist/api/protocol-v2/DeviceInfoGet.d.ts.map +1 -1
- package/dist/index.d.ts +5 -20
- package/dist/index.js +191 -257
- package/dist/protocols/protocol-v2/features.d.ts +4 -4
- package/dist/protocols/protocol-v2/resources.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts.map +1 -1
- package/dist/types/settings.d.ts +4 -19
- package/dist/types/settings.d.ts.map +1 -1
- package/dist/utils/patch.d.ts +1 -1
- package/dist/utils/patch.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/FirmwareUpdateV4.ts +170 -243
- package/src/api/protocol-v2/DeviceFactoryInfoSet.ts +1 -1
- package/src/api/protocol-v2/DeviceFirmwareUpdate.ts +6 -28
- package/src/api/protocol-v2/DeviceInfoGet.ts +3 -3
- package/src/data/messages/messages-protocol-v2.json +31 -14
- package/src/device/DeviceStateMapper.ts +15 -15
- package/src/deviceProfile/buildDeviceFeatures.ts +3 -3
- package/src/protocols/protocol-v2/features.ts +6 -6
- package/src/protocols/protocol-v2/resources.ts +10 -49
- package/src/protocols/protocol-v2/unlockPolicyRunner.ts +1 -0
- package/src/types/settings.ts +4 -19
|
@@ -613,7 +613,7 @@ const protocolV2BootloaderDeviceInfo: ProtocolV2DeviceInfo = {
|
|
|
613
613
|
hw: {
|
|
614
614
|
serial_no: 'PR9999999999',
|
|
615
615
|
},
|
|
616
|
-
|
|
616
|
+
main_mcu: {
|
|
617
617
|
bootloader: {
|
|
618
618
|
version: '0.0.1',
|
|
619
619
|
},
|
|
@@ -677,7 +677,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
677
677
|
const deviceInfo: ProtocolV2DeviceInfo = {
|
|
678
678
|
protocol_version: 1,
|
|
679
679
|
hw: { serial_no: 'P2-STATIC' },
|
|
680
|
-
|
|
680
|
+
main_mcu: { application: { version: '1.0.0' } },
|
|
681
681
|
coprocessor: { bt_adv_name: 'Pro2 STATIC' },
|
|
682
682
|
};
|
|
683
683
|
const deviceStatus: DeviceStatus = {
|
|
@@ -751,7 +751,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
751
751
|
Device_type: DeviceType.PRO2,
|
|
752
752
|
serial_no: 'PR2SERIAL',
|
|
753
753
|
},
|
|
754
|
-
|
|
754
|
+
main_mcu: {
|
|
755
755
|
romloader: {
|
|
756
756
|
version: '0.1.0',
|
|
757
757
|
build_id: 'rom-build',
|
|
@@ -841,7 +841,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
841
841
|
hw: {
|
|
842
842
|
serial_no: 'PR2BOOT',
|
|
843
843
|
},
|
|
844
|
-
|
|
844
|
+
main_mcu: {
|
|
845
845
|
bootloader: {
|
|
846
846
|
version: '0.2.0',
|
|
847
847
|
},
|
|
@@ -863,7 +863,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
863
863
|
const features = normalizeProtocolV2Features(descriptor as any, {
|
|
864
864
|
protocol_version: 1,
|
|
865
865
|
hw: { serial_no: 'PR2NORMAL' },
|
|
866
|
-
|
|
866
|
+
main_mcu: { bootloader: { version: '0.2.0' } },
|
|
867
867
|
});
|
|
868
868
|
|
|
869
869
|
expect(features.mode).toBe('normal');
|
|
@@ -876,7 +876,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
876
876
|
hw: {
|
|
877
877
|
serial_no: 'PR2ROM',
|
|
878
878
|
},
|
|
879
|
-
|
|
879
|
+
main_mcu: {
|
|
880
880
|
romloader: {
|
|
881
881
|
version: '1.0.0',
|
|
882
882
|
},
|
|
@@ -917,17 +917,17 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
917
917
|
|
|
918
918
|
expect(
|
|
919
919
|
getProtocolV2RuntimeMode(legacyProtocolInfo, {
|
|
920
|
-
|
|
920
|
+
main_mcu: { bootloader: { version: '0.2.0' } },
|
|
921
921
|
})
|
|
922
922
|
).toBe('bootloader');
|
|
923
923
|
expect(
|
|
924
924
|
getProtocolV2RuntimeMode(legacyProtocolInfo, {
|
|
925
|
-
|
|
925
|
+
main_mcu: { romloader: { version: '1.0.0' } },
|
|
926
926
|
})
|
|
927
927
|
).toBe('romloader');
|
|
928
928
|
expect(
|
|
929
929
|
getProtocolV2RuntimeMode(legacyProtocolInfo, {
|
|
930
|
-
|
|
930
|
+
main_mcu: {
|
|
931
931
|
application: { version: '1.2.3' },
|
|
932
932
|
bootloader: { version: '0.2.0' },
|
|
933
933
|
},
|
|
@@ -1998,7 +1998,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
1998
1998
|
{ ...descriptor, protocolType: 'V2' } as any,
|
|
1999
1999
|
{
|
|
2000
2000
|
protocol_version: 2,
|
|
2001
|
-
|
|
2001
|
+
main_mcu: { application: { version: '1.2.3' } },
|
|
2002
2002
|
se1: { application: { version: '4.5.6' } },
|
|
2003
2003
|
status: { unlocked: false, passphrase_enabled: false },
|
|
2004
2004
|
}
|
|
@@ -2035,7 +2035,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
2035
2035
|
deviceInfo: {
|
|
2036
2036
|
protocol_version: 1,
|
|
2037
2037
|
hw: { serial_no: 'PR9999999999' },
|
|
2038
|
-
|
|
2038
|
+
main_mcu: { application: { version: '1.0.0' } },
|
|
2039
2039
|
},
|
|
2040
2040
|
deviceStatus: {
|
|
2041
2041
|
device_id: 'firmware-reconnect-id',
|
|
@@ -2400,7 +2400,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
2400
2400
|
(device as any).features = {
|
|
2401
2401
|
...normalizeProtocolV2Features({ ...descriptor, protocolType: 'V2' } as any, {
|
|
2402
2402
|
hw: { serial_no: 'PR2SERIAL' },
|
|
2403
|
-
|
|
2403
|
+
main_mcu: { application: { version: '4.15.0' } },
|
|
2404
2404
|
status: { passphrase_enabled: true },
|
|
2405
2405
|
}),
|
|
2406
2406
|
unlocked: true,
|
|
@@ -2825,7 +2825,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
2825
2825
|
type: 'DeviceInfo',
|
|
2826
2826
|
message: {
|
|
2827
2827
|
hw: { Device_type: DeviceType.PRO2, serial_no: 'PR2SERIAL' },
|
|
2828
|
-
|
|
2828
|
+
main_mcu: { application: { version: '1.2.3' } },
|
|
2829
2829
|
},
|
|
2830
2830
|
}),
|
|
2831
2831
|
};
|
|
@@ -2846,7 +2846,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
2846
2846
|
{
|
|
2847
2847
|
targets: {
|
|
2848
2848
|
hw: true,
|
|
2849
|
-
|
|
2849
|
+
main_mcu: true,
|
|
2850
2850
|
coprocessor: true,
|
|
2851
2851
|
},
|
|
2852
2852
|
types: {
|
|
@@ -2955,7 +2955,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
2955
2955
|
const device = stubDevice({
|
|
2956
2956
|
originalDescriptor: { protocolType: 'V2' },
|
|
2957
2957
|
features: normalizeProtocolV2Features({ ...descriptor, protocolType: 'V2' } as any, {
|
|
2958
|
-
|
|
2958
|
+
main_mcu: {
|
|
2959
2959
|
application: {
|
|
2960
2960
|
version: '4.14.0',
|
|
2961
2961
|
},
|
|
@@ -3009,7 +3009,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
3009
3009
|
type: 'DeviceInfo',
|
|
3010
3010
|
message: {
|
|
3011
3011
|
hw: { Device_type: DeviceType.PRO2, serial_no: 'PR2SERIAL' },
|
|
3012
|
-
|
|
3012
|
+
main_mcu: { application: { version: '1.2.3' } },
|
|
3013
3013
|
},
|
|
3014
3014
|
})
|
|
3015
3015
|
.mockResolvedValueOnce({
|
|
@@ -3044,7 +3044,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
3044
3044
|
{
|
|
3045
3045
|
targets: {
|
|
3046
3046
|
hw: true,
|
|
3047
|
-
|
|
3047
|
+
main_mcu: true,
|
|
3048
3048
|
coprocessor: true,
|
|
3049
3049
|
},
|
|
3050
3050
|
types: {
|
|
@@ -3073,7 +3073,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
3073
3073
|
type: 'DeviceInfo',
|
|
3074
3074
|
message: {
|
|
3075
3075
|
hw: { serial_no: 'PR2SERIAL' },
|
|
3076
|
-
|
|
3076
|
+
main_mcu: { bootloader: { version: '0.2.0' } },
|
|
3077
3077
|
se1: {},
|
|
3078
3078
|
},
|
|
3079
3079
|
})
|
|
@@ -3123,7 +3123,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
3123
3123
|
|
|
3124
3124
|
await device.probeProtocolV2RuntimeState({
|
|
3125
3125
|
hw: { Device_type: DeviceType.PRO2, serial_no: 'PR2SERIAL' },
|
|
3126
|
-
|
|
3126
|
+
main_mcu: { romloader: { version: '1.0.0' } },
|
|
3127
3127
|
});
|
|
3128
3128
|
|
|
3129
3129
|
expect(typedCall).toHaveBeenCalledTimes(1);
|
|
@@ -3151,7 +3151,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
3151
3151
|
await expect(
|
|
3152
3152
|
device.probeProtocolV2RuntimeState({
|
|
3153
3153
|
hw: { Device_type: DeviceType.PRO, serial_no: 'PRO-SERIAL' },
|
|
3154
|
-
|
|
3154
|
+
main_mcu: { romloader: { version: '1.0.0' } },
|
|
3155
3155
|
})
|
|
3156
3156
|
).rejects.toMatchObject({ errorCode: HardwareErrorCode.DeviceInitializeFailed });
|
|
3157
3157
|
|
|
@@ -3176,7 +3176,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
3176
3176
|
|
|
3177
3177
|
await device.probeProtocolV2RuntimeState({
|
|
3178
3178
|
hw: { serial_no: 'PR2SERIAL' },
|
|
3179
|
-
|
|
3179
|
+
main_mcu: { application: { version: '1.2.3' } },
|
|
3180
3180
|
});
|
|
3181
3181
|
|
|
3182
3182
|
expect(typedCall).toHaveBeenCalledTimes(1);
|
|
@@ -3208,7 +3208,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
3208
3208
|
|
|
3209
3209
|
await device.probeProtocolV2RuntimeState({
|
|
3210
3210
|
hw: { serial_no: 'PR2SERIAL' },
|
|
3211
|
-
|
|
3211
|
+
main_mcu: { application: { version: '1.2.3' } },
|
|
3212
3212
|
});
|
|
3213
3213
|
|
|
3214
3214
|
expect(typedCall).toHaveBeenCalledTimes(2);
|
|
@@ -3236,7 +3236,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
3236
3236
|
|
|
3237
3237
|
await device.probeProtocolV2RuntimeState({
|
|
3238
3238
|
hw: { Device_type: DeviceType.PRO2, serial_no: 'PR2SERIAL' },
|
|
3239
|
-
|
|
3239
|
+
main_mcu: { bootloader: { version: '0.2.0' } },
|
|
3240
3240
|
});
|
|
3241
3241
|
|
|
3242
3242
|
expect(device.features).toMatchObject({
|
|
@@ -3265,7 +3265,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
3265
3265
|
await expect(
|
|
3266
3266
|
device.probeProtocolV2RuntimeState({
|
|
3267
3267
|
hw: { Device_type: DeviceType.PRO2, serial_no: 'PR2SERIAL' },
|
|
3268
|
-
|
|
3268
|
+
main_mcu: { application: { version: '1.2.3' } },
|
|
3269
3269
|
})
|
|
3270
3270
|
).rejects.toBe(linkError);
|
|
3271
3271
|
|
|
@@ -3290,7 +3290,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
3290
3290
|
await expect(
|
|
3291
3291
|
device.probeProtocolV2RuntimeState({
|
|
3292
3292
|
hw: { serial_no: 'PR2SERIAL' },
|
|
3293
|
-
|
|
3293
|
+
main_mcu: { application: { version: '1.2.3' } },
|
|
3294
3294
|
})
|
|
3295
3295
|
).rejects.toMatchObject({ errorCode: HardwareErrorCode.DeviceInitializeFailed });
|
|
3296
3296
|
expect(typedCall).toHaveBeenCalledTimes(1);
|
|
@@ -3307,7 +3307,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
3307
3307
|
type: 'DeviceInfo',
|
|
3308
3308
|
message: {
|
|
3309
3309
|
hw: { Device_type: DeviceType.PRO2, serial_no: 'PR2SERIAL' },
|
|
3310
|
-
|
|
3310
|
+
main_mcu: { bootloader: { version: '0.2.0' } },
|
|
3311
3311
|
},
|
|
3312
3312
|
})
|
|
3313
3313
|
.mockResolvedValueOnce({
|
|
@@ -3357,7 +3357,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
3357
3357
|
await device.probeProtocolV2RuntimeState(
|
|
3358
3358
|
{
|
|
3359
3359
|
hw: { Device_type: DeviceType.PRO2, serial_no: 'PR2SERIAL' },
|
|
3360
|
-
|
|
3360
|
+
main_mcu: { application: { version: '1.2.3' } },
|
|
3361
3361
|
},
|
|
3362
3362
|
5000
|
|
3363
3363
|
);
|
|
@@ -3402,7 +3402,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
3402
3402
|
|
|
3403
3403
|
await device.probeProtocolV2RuntimeState({
|
|
3404
3404
|
hw: { Device_type: DeviceType.NEO, serial_no: 'NEOSERIAL' },
|
|
3405
|
-
|
|
3405
|
+
main_mcu: { bootloader: { version: '0.2.0' } },
|
|
3406
3406
|
});
|
|
3407
3407
|
|
|
3408
3408
|
expect(typedCall).toHaveBeenNthCalledWith(1, 'ProtocolInfoRequest', 'ProtocolInfo', {
|
|
@@ -3436,7 +3436,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
3436
3436
|
|
|
3437
3437
|
await device.probeProtocolV2RuntimeState({
|
|
3438
3438
|
hw: { Device_type: DeviceType.PRO2, serial_no: 'PR2SERIAL' },
|
|
3439
|
-
|
|
3439
|
+
main_mcu: { romloader: { version: '1.0.0' } },
|
|
3440
3440
|
});
|
|
3441
3441
|
|
|
3442
3442
|
expect(typedCall).toHaveBeenCalledTimes(1);
|
|
@@ -3474,7 +3474,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
3474
3474
|
await expect(
|
|
3475
3475
|
device.probeProtocolV2RuntimeState({
|
|
3476
3476
|
hw: { serial_no: 'PR2SERIAL' },
|
|
3477
|
-
|
|
3477
|
+
main_mcu: { application: { version: '1.0.0' } },
|
|
3478
3478
|
})
|
|
3479
3479
|
).rejects.toThrow('state update failed');
|
|
3480
3480
|
|
|
@@ -3499,7 +3499,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
3499
3499
|
type: 'DeviceInfo',
|
|
3500
3500
|
message: {
|
|
3501
3501
|
hw: { Device_type: DeviceType.PRO2, serial_no: 'PR2SERIAL' },
|
|
3502
|
-
|
|
3502
|
+
main_mcu: { application: { version: '1.2.3' } },
|
|
3503
3503
|
},
|
|
3504
3504
|
})
|
|
3505
3505
|
.mockResolvedValueOnce({
|
|
@@ -3514,7 +3514,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
3514
3514
|
type: 'DeviceInfo',
|
|
3515
3515
|
message: {
|
|
3516
3516
|
hw: { Device_type: DeviceType.PRO2, serial_no: 'PR2SERIAL' },
|
|
3517
|
-
|
|
3517
|
+
main_mcu: { application: { version: '1.2.4' } },
|
|
3518
3518
|
},
|
|
3519
3519
|
})
|
|
3520
3520
|
.mockResolvedValueOnce({
|
|
@@ -3546,7 +3546,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
3546
3546
|
{
|
|
3547
3547
|
targets: {
|
|
3548
3548
|
hw: true,
|
|
3549
|
-
|
|
3549
|
+
main_mcu: true,
|
|
3550
3550
|
coprocessor: true,
|
|
3551
3551
|
},
|
|
3552
3552
|
types: {
|
|
@@ -3567,7 +3567,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
3567
3567
|
type: 'DeviceInfo',
|
|
3568
3568
|
message: {
|
|
3569
3569
|
hw: { serial_no: 'PR2SERIAL' },
|
|
3570
|
-
|
|
3570
|
+
main_mcu: { application: { version: '1.2.4' } },
|
|
3571
3571
|
},
|
|
3572
3572
|
})
|
|
3573
3573
|
.mockResolvedValueOnce({
|
|
@@ -3644,7 +3644,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
3644
3644
|
{ ...descriptor, protocolType: 'V2' } as any,
|
|
3645
3645
|
{
|
|
3646
3646
|
hw: { Device_type: DeviceType.PRO2, serial_no: 'PR2SERIAL' },
|
|
3647
|
-
|
|
3647
|
+
main_mcu: { application: { version: '1.2.3' } },
|
|
3648
3648
|
status: { init_states: true },
|
|
3649
3649
|
}
|
|
3650
3650
|
);
|
|
@@ -3684,7 +3684,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
3684
3684
|
{ ...descriptor, protocolType: 'V2' } as any,
|
|
3685
3685
|
{
|
|
3686
3686
|
hw: { serial_no: 'PR2SERIAL' },
|
|
3687
|
-
|
|
3687
|
+
main_mcu: { application: { version: '4.15.0' } },
|
|
3688
3688
|
status: { passphrase_enabled: false },
|
|
3689
3689
|
}
|
|
3690
3690
|
);
|
|
@@ -3731,7 +3731,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
3731
3731
|
(device as any).features = normalizeProtocolV2Features(
|
|
3732
3732
|
{ ...descriptor, protocolType: 'V2' } as any,
|
|
3733
3733
|
{
|
|
3734
|
-
|
|
3734
|
+
main_mcu: { application: { version: '1.2.3' } },
|
|
3735
3735
|
status: { unlocked: false },
|
|
3736
3736
|
}
|
|
3737
3737
|
);
|
|
@@ -4160,7 +4160,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
4160
4160
|
type: 'DeviceInfo',
|
|
4161
4161
|
message: {
|
|
4162
4162
|
hw: { serial_no: 'BLE-PRO2-SERIAL' },
|
|
4163
|
-
|
|
4163
|
+
main_mcu: {
|
|
4164
4164
|
bootloader: { version: '0.0.0' },
|
|
4165
4165
|
application: { version: '0.0.0' },
|
|
4166
4166
|
},
|
|
@@ -4212,7 +4212,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
4212
4212
|
{
|
|
4213
4213
|
targets: {
|
|
4214
4214
|
hw: true,
|
|
4215
|
-
|
|
4215
|
+
main_mcu: true,
|
|
4216
4216
|
coprocessor: true,
|
|
4217
4217
|
se1: true,
|
|
4218
4218
|
se2: true,
|
|
@@ -4631,43 +4631,6 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
4631
4631
|
expect(method.postTipMessage).toHaveBeenCalledWith('GoToBootloaderSuccess');
|
|
4632
4632
|
});
|
|
4633
4633
|
|
|
4634
|
-
test('keeps an ambiguous legacy runtime on the direct loader update path', async () => {
|
|
4635
|
-
const method = new FirmwareUpdateV4({
|
|
4636
|
-
id: 1,
|
|
4637
|
-
payload: {
|
|
4638
|
-
method: 'firmwareUpdateV4',
|
|
4639
|
-
},
|
|
4640
|
-
});
|
|
4641
|
-
(method as any).device = stubDevice({
|
|
4642
|
-
originalDescriptor: { id: 'usb-id', path: 'legacy-path', protocolType: 'V2' },
|
|
4643
|
-
state: {
|
|
4644
|
-
raw: {
|
|
4645
|
-
protocolV2ProtocolInfo: {
|
|
4646
|
-
version: 1,
|
|
4647
|
-
build_fingerprint: '',
|
|
4648
|
-
supported_messages: [],
|
|
4649
|
-
protobuf_definition: null,
|
|
4650
|
-
},
|
|
4651
|
-
},
|
|
4652
|
-
},
|
|
4653
|
-
features: {
|
|
4654
|
-
deviceType: 'pro2',
|
|
4655
|
-
mode: 'bootloader',
|
|
4656
|
-
bootloaderMode: true,
|
|
4657
|
-
capabilities: [],
|
|
4658
|
-
},
|
|
4659
|
-
isBootloader: () => true,
|
|
4660
|
-
isRomloader: () => false,
|
|
4661
|
-
});
|
|
4662
|
-
(method as any).protocolV2Reboot = jest.fn();
|
|
4663
|
-
method.postTipMessage = jest.fn();
|
|
4664
|
-
|
|
4665
|
-
await expect((method as any).enterProtocolV2BootloaderMode()).resolves.toBe(false);
|
|
4666
|
-
|
|
4667
|
-
expect((method as any).protocolV2LegacyDirectUpdate).toBe(true);
|
|
4668
|
-
expect((method as any).protocolV2Reboot).not.toHaveBeenCalled();
|
|
4669
|
-
});
|
|
4670
|
-
|
|
4671
4634
|
test('keeps Protocol V2 romloader active before firmware transfer', async () => {
|
|
4672
4635
|
const method = new FirmwareUpdateV4({
|
|
4673
4636
|
id: 1,
|
|
@@ -5116,7 +5079,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
5116
5079
|
type: 'DeviceInfo',
|
|
5117
5080
|
message: {
|
|
5118
5081
|
hw: { serial_no: 'PR2SERIAL' },
|
|
5119
|
-
|
|
5082
|
+
main_mcu: { application: { version: '1.0.0' } },
|
|
5120
5083
|
},
|
|
5121
5084
|
});
|
|
5122
5085
|
(method as any).protocolV2ExpectedSerialNumber = 'expected-serial';
|
|
@@ -5243,49 +5206,50 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
5243
5206
|
);
|
|
5244
5207
|
});
|
|
5245
5208
|
|
|
5246
|
-
test('
|
|
5209
|
+
test('stages targets before sending the empty Protocol V2 install request', async () => {
|
|
5247
5210
|
const method = new FirmwareUpdateV4({
|
|
5248
5211
|
id: 1,
|
|
5249
5212
|
payload: {
|
|
5250
5213
|
method: 'firmwareUpdateV4',
|
|
5251
5214
|
},
|
|
5252
5215
|
});
|
|
5253
|
-
const
|
|
5254
|
-
|
|
5255
|
-
|
|
5256
|
-
Object.assign(
|
|
5257
|
-
new Error("Failed to execute 'open' on 'USBDevice': The device was disconnected"),
|
|
5258
|
-
{ name: 'NotFoundError' }
|
|
5259
|
-
)
|
|
5260
|
-
);
|
|
5216
|
+
const targets = [{ target_id: 4, path: 'vol1:firmware.bin' }];
|
|
5217
|
+
const typedCall = jest.fn().mockResolvedValue({ type: 'Success', message: {} });
|
|
5218
|
+
const call = jest.fn().mockResolvedValue({ type: 'WriteCompleted', message: {} });
|
|
5261
5219
|
|
|
5262
5220
|
(method as any).device = stubDevice({
|
|
5263
|
-
getCommands: () => ({ typedCall }),
|
|
5221
|
+
getCommands: () => ({ typedCall, call }),
|
|
5264
5222
|
});
|
|
5265
5223
|
method.postTipMessage = jest.fn();
|
|
5266
5224
|
method.postProgressMessage = jest.fn();
|
|
5267
5225
|
|
|
5268
5226
|
await expect(
|
|
5269
|
-
(method as any).protocolV2StartFirmwareUpdate({
|
|
5270
|
-
|
|
5271
|
-
})
|
|
5272
|
-
).rejects.toThrow();
|
|
5227
|
+
(method as any).protocolV2StartFirmwareUpdate({ targets })
|
|
5228
|
+
).resolves.toBeUndefined();
|
|
5273
5229
|
|
|
5274
|
-
expect(
|
|
5275
|
-
expect(
|
|
5230
|
+
expect(typedCall).toHaveBeenCalledWith('DeviceFirmwareUpdateStage', 'Success', { targets });
|
|
5231
|
+
expect(call).toHaveBeenCalledWith(
|
|
5232
|
+
'DeviceFirmwareUpdateRequest',
|
|
5233
|
+
{},
|
|
5234
|
+
{ returnAfterWrite: true }
|
|
5235
|
+
);
|
|
5236
|
+
expect(typedCall.mock.invocationCallOrder[0]).toBeLessThan(call.mock.invocationCallOrder[0]);
|
|
5237
|
+
expect(method.postTipMessage).toHaveBeenCalledWith('FirmwareUpdating');
|
|
5238
|
+
expect(method.postProgressMessage).toHaveBeenCalledWith(0, 'installingFirmware');
|
|
5276
5239
|
});
|
|
5277
5240
|
|
|
5278
|
-
test('does not
|
|
5241
|
+
test('does not send the install request when Protocol V2 staging fails', async () => {
|
|
5279
5242
|
const method = new FirmwareUpdateV4({
|
|
5280
5243
|
id: 1,
|
|
5281
5244
|
payload: {
|
|
5282
5245
|
method: 'firmwareUpdateV4',
|
|
5283
5246
|
},
|
|
5284
5247
|
});
|
|
5285
|
-
const typedCall = jest.fn().mockRejectedValue(new Error('
|
|
5248
|
+
const typedCall = jest.fn().mockRejectedValue(new Error('stage failed'));
|
|
5249
|
+
const call = jest.fn();
|
|
5286
5250
|
|
|
5287
5251
|
(method as any).device = stubDevice({
|
|
5288
|
-
getCommands: () => ({ typedCall }),
|
|
5252
|
+
getCommands: () => ({ typedCall, call }),
|
|
5289
5253
|
});
|
|
5290
5254
|
method.postTipMessage = jest.fn();
|
|
5291
5255
|
method.postProgressMessage = jest.fn();
|
|
@@ -5294,89 +5258,36 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
5294
5258
|
(method as any).protocolV2StartFirmwareUpdate({
|
|
5295
5259
|
targets: [{ target_id: 4, path: 'vol1:application_p1.bin' }],
|
|
5296
5260
|
})
|
|
5297
|
-
).rejects.toThrow('
|
|
5261
|
+
).rejects.toThrow('stage failed');
|
|
5298
5262
|
|
|
5263
|
+
expect(call).not.toHaveBeenCalled();
|
|
5299
5264
|
expect(method.postTipMessage).not.toHaveBeenCalled();
|
|
5300
5265
|
expect(method.postProgressMessage).not.toHaveBeenCalled();
|
|
5301
5266
|
});
|
|
5302
5267
|
|
|
5303
|
-
test
|
|
5304
|
-
'Failure_InvalidMessage,Handler not registered',
|
|
5305
|
-
'Failure_InvalidMessage,Unsupported message',
|
|
5306
|
-
])('reboots a legacy App when the direct update endpoint is unavailable: %s', async message => {
|
|
5268
|
+
test('does not enter install state when writing the empty request fails', async () => {
|
|
5307
5269
|
const method = new FirmwareUpdateV4({
|
|
5308
5270
|
id: 1,
|
|
5309
5271
|
payload: {
|
|
5310
5272
|
method: 'firmwareUpdateV4',
|
|
5311
5273
|
},
|
|
5312
5274
|
});
|
|
5313
|
-
const
|
|
5314
|
-
const
|
|
5315
|
-
const bootloaderTypedCall = jest
|
|
5316
|
-
.fn()
|
|
5317
|
-
.mockResolvedValueOnce({ type: 'Success', message: { message: '' } });
|
|
5318
|
-
let activeCommands = { typedCall: appTypedCall };
|
|
5275
|
+
const typedCall = jest.fn().mockResolvedValue({ type: 'Success', message: {} });
|
|
5276
|
+
const call = jest.fn().mockRejectedValue(new Error('write failed'));
|
|
5319
5277
|
|
|
5320
5278
|
(method as any).device = stubDevice({
|
|
5321
|
-
getCommands: () =>
|
|
5322
|
-
});
|
|
5323
|
-
(method as any).protocolV2LegacyDirectUpdate = true;
|
|
5324
|
-
(method as any).rebootProtocolV2ToBootloader = jest.fn().mockImplementation(() => {
|
|
5325
|
-
activeCommands = { typedCall: bootloaderTypedCall };
|
|
5326
|
-
return Promise.resolve(true);
|
|
5279
|
+
getCommands: () => ({ typedCall, call }),
|
|
5327
5280
|
});
|
|
5328
5281
|
method.postTipMessage = jest.fn();
|
|
5329
5282
|
method.postProgressMessage = jest.fn();
|
|
5330
5283
|
|
|
5331
|
-
await expect((method as any).protocolV2StartFirmwareUpdate({ targets })).resolves.toEqual({
|
|
5332
|
-
type: 'Success',
|
|
5333
|
-
message: { message: '' },
|
|
5334
|
-
});
|
|
5335
|
-
|
|
5336
|
-
expect(appTypedCall).toHaveBeenCalledTimes(1);
|
|
5337
|
-
expect(appTypedCall).toHaveBeenCalledWith(
|
|
5338
|
-
'DeviceFirmwareUpdateRequest',
|
|
5339
|
-
'Success',
|
|
5340
|
-
{ targets },
|
|
5341
|
-
{ timeoutMs: 180000 }
|
|
5342
|
-
);
|
|
5343
|
-
expect(bootloaderTypedCall).toHaveBeenCalledTimes(1);
|
|
5344
|
-
expect(bootloaderTypedCall).toHaveBeenCalledWith(
|
|
5345
|
-
'DeviceFirmwareUpdateRequest',
|
|
5346
|
-
'Success',
|
|
5347
|
-
{ targets },
|
|
5348
|
-
{ timeoutMs: 180000 }
|
|
5349
|
-
);
|
|
5350
|
-
expect((method as any).rebootProtocolV2ToBootloader).toHaveBeenCalledTimes(1);
|
|
5351
|
-
expect(method.postTipMessage).toHaveBeenCalledWith('FirmwareUpdating');
|
|
5352
|
-
expect(method.postProgressMessage).toHaveBeenCalledWith(0, 'installingFirmware');
|
|
5353
|
-
});
|
|
5354
|
-
|
|
5355
|
-
test('does not replay a legacy direct update after a link failure', async () => {
|
|
5356
|
-
const method = new FirmwareUpdateV4({
|
|
5357
|
-
id: 1,
|
|
5358
|
-
payload: {
|
|
5359
|
-
method: 'firmwareUpdateV4',
|
|
5360
|
-
},
|
|
5361
|
-
});
|
|
5362
|
-
const typedCall = jest.fn().mockRejectedValue(new Error('LIBUSB_TRANSFER_TIMED_OUT'));
|
|
5363
|
-
|
|
5364
|
-
(method as any).device = stubDevice({
|
|
5365
|
-
getCommands: () => ({ typedCall }),
|
|
5366
|
-
});
|
|
5367
|
-
(method as any).protocolV2LegacyDirectUpdate = true;
|
|
5368
|
-
(method as any).rebootProtocolV2ToBootloader = jest.fn();
|
|
5369
|
-
method.postTipMessage = jest.fn();
|
|
5370
|
-
method.postProgressMessage = jest.fn();
|
|
5371
|
-
|
|
5372
5284
|
await expect(
|
|
5373
5285
|
(method as any).protocolV2StartFirmwareUpdate({
|
|
5374
5286
|
targets: [{ target_id: 4, path: 'vol0:/application_p1.bin' }],
|
|
5375
5287
|
})
|
|
5376
|
-
).rejects.toThrow('
|
|
5288
|
+
).rejects.toThrow('write failed');
|
|
5377
5289
|
|
|
5378
|
-
expect(
|
|
5379
|
-
expect((method as any).rebootProtocolV2ToBootloader).not.toHaveBeenCalled();
|
|
5290
|
+
expect(call).toHaveBeenCalledTimes(1);
|
|
5380
5291
|
expect(method.postTipMessage).not.toHaveBeenCalled();
|
|
5381
5292
|
expect(method.postProgressMessage).not.toHaveBeenCalled();
|
|
5382
5293
|
});
|
|
@@ -5424,7 +5335,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
5424
5335
|
expect(method.postProgressMessage).toHaveBeenCalledWith(100, 'installingFirmware');
|
|
5425
5336
|
});
|
|
5426
5337
|
|
|
5427
|
-
test('
|
|
5338
|
+
test('keeps polling after install ACK until the target finishes', async () => {
|
|
5428
5339
|
const method = new FirmwareUpdateV4({
|
|
5429
5340
|
id: 1,
|
|
5430
5341
|
payload: {
|
|
@@ -5433,45 +5344,125 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
5433
5344
|
});
|
|
5434
5345
|
const typedCall = jest
|
|
5435
5346
|
.fn()
|
|
5436
|
-
.
|
|
5347
|
+
.mockResolvedValueOnce({ type: 'Success', message: {} })
|
|
5348
|
+
.mockResolvedValueOnce({
|
|
5349
|
+
type: 'DeviceFirmwareUpdateStatus',
|
|
5350
|
+
message: { records: [] },
|
|
5351
|
+
})
|
|
5352
|
+
.mockResolvedValueOnce({
|
|
5353
|
+
type: 'DeviceFirmwareUpdateStatus',
|
|
5354
|
+
message: { records: [{ target_id: 4, status: 0 }] },
|
|
5355
|
+
})
|
|
5356
|
+
.mockResolvedValueOnce({
|
|
5357
|
+
type: 'DeviceFirmwareUpdateStatus',
|
|
5358
|
+
message: { records: [{ target_id: 4, status: 2 }] },
|
|
5359
|
+
});
|
|
5437
5360
|
const reconnectProtocolV2Device = jest.fn().mockResolvedValue(undefined);
|
|
5361
|
+
const setTimeoutSpy = jest.spyOn(global, 'setTimeout').mockImplementation(((
|
|
5362
|
+
callback: () => void
|
|
5363
|
+
) => {
|
|
5364
|
+
callback();
|
|
5365
|
+
return 0 as any;
|
|
5366
|
+
}) as typeof setTimeout);
|
|
5438
5367
|
|
|
5439
5368
|
(method as any).device = stubDevice({
|
|
5440
5369
|
getCommands: () => ({ typedCall }),
|
|
5441
5370
|
});
|
|
5442
5371
|
(method as any).reconnectProtocolV2Device = reconnectProtocolV2Device;
|
|
5443
|
-
|
|
5444
|
-
(method as any).verifyProtocolV2ReconnectIdentity = jest.fn().mockResolvedValue(deviceInfo);
|
|
5445
|
-
(method as any).probeProtocolV2NormalMode = jest.fn().mockResolvedValue(true);
|
|
5446
|
-
(method as any).protocolV2InstallAckReceived = true;
|
|
5372
|
+
(method as any).verifyProtocolV2ReconnectIdentity = jest.fn().mockResolvedValue(undefined);
|
|
5447
5373
|
method.postProgressMessage = jest.fn();
|
|
5448
5374
|
|
|
5449
|
-
|
|
5450
|
-
|
|
5451
|
-
|
|
5375
|
+
try {
|
|
5376
|
+
await (method as any).waitForProtocolV2FirmwareUpdateComplete([
|
|
5377
|
+
{ target_id: 4, path: 'vol0:/application_p1.bin' },
|
|
5378
|
+
]);
|
|
5379
|
+
} finally {
|
|
5380
|
+
setTimeoutSpy.mockRestore();
|
|
5381
|
+
}
|
|
5452
5382
|
|
|
5453
5383
|
expect(reconnectProtocolV2Device).toHaveBeenCalledTimes(1);
|
|
5454
|
-
expect(typedCall.mock.calls.map(call => call[0])).toEqual([
|
|
5455
|
-
|
|
5384
|
+
expect(typedCall.mock.calls.map(call => call[0])).toEqual([
|
|
5385
|
+
'DeviceFirmwareUpdateStatusGet',
|
|
5386
|
+
'DeviceFirmwareUpdateStatusGet',
|
|
5387
|
+
'DeviceFirmwareUpdateStatusGet',
|
|
5388
|
+
'DeviceFirmwareUpdateStatusGet',
|
|
5389
|
+
]);
|
|
5390
|
+
expect((method as any).protocolV2FinalStatusVerified).toBe(true);
|
|
5456
5391
|
expect(method.postProgressMessage).toHaveBeenCalledWith(100, 'installingFirmware');
|
|
5457
5392
|
});
|
|
5458
5393
|
|
|
5459
|
-
test('
|
|
5394
|
+
test('keeps waiting while firmware status records are empty before user confirmation', async () => {
|
|
5460
5395
|
const method = new FirmwareUpdateV4({
|
|
5461
5396
|
id: 1,
|
|
5462
5397
|
payload: {
|
|
5463
5398
|
method: 'firmwareUpdateV4',
|
|
5464
5399
|
},
|
|
5465
5400
|
});
|
|
5466
|
-
const typedCall = jest
|
|
5467
|
-
|
|
5468
|
-
|
|
5401
|
+
const typedCall = jest
|
|
5402
|
+
.fn()
|
|
5403
|
+
.mockResolvedValueOnce({
|
|
5404
|
+
type: 'DeviceFirmwareUpdateStatus',
|
|
5405
|
+
message: { records: [] },
|
|
5406
|
+
})
|
|
5407
|
+
.mockResolvedValueOnce({
|
|
5408
|
+
type: 'DeviceFirmwareUpdateStatus',
|
|
5409
|
+
message: { records: [{ target_id: 4, status: 0 }] },
|
|
5410
|
+
})
|
|
5411
|
+
.mockResolvedValueOnce({
|
|
5412
|
+
type: 'DeviceFirmwareUpdateStatus',
|
|
5413
|
+
message: { records: [{ target_id: 4, status: 2 }] },
|
|
5414
|
+
});
|
|
5415
|
+
const setTimeoutSpy = jest.spyOn(global, 'setTimeout').mockImplementation(((
|
|
5416
|
+
callback: () => void
|
|
5417
|
+
) => {
|
|
5418
|
+
callback();
|
|
5419
|
+
return 0 as any;
|
|
5420
|
+
}) as typeof setTimeout);
|
|
5421
|
+
|
|
5422
|
+
(method as any).device = stubDevice({
|
|
5423
|
+
getCommands: () => ({ typedCall }),
|
|
5469
5424
|
});
|
|
5470
|
-
|
|
5471
|
-
|
|
5472
|
-
|
|
5473
|
-
|
|
5474
|
-
|
|
5425
|
+
(method as any).reconnectProtocolV2Device = jest.fn().mockResolvedValue(undefined);
|
|
5426
|
+
(method as any).verifyProtocolV2ReconnectIdentity = jest.fn().mockResolvedValue(undefined);
|
|
5427
|
+
method.postProgressMessage = jest.fn();
|
|
5428
|
+
|
|
5429
|
+
try {
|
|
5430
|
+
await (method as any).waitForProtocolV2FirmwareUpdateComplete(
|
|
5431
|
+
[{ target_id: 4, path: 'vol0:/application_p1.bin' }],
|
|
5432
|
+
true
|
|
5433
|
+
);
|
|
5434
|
+
} finally {
|
|
5435
|
+
setTimeoutSpy.mockRestore();
|
|
5436
|
+
}
|
|
5437
|
+
|
|
5438
|
+
expect(typedCall).toHaveBeenCalledTimes(3);
|
|
5439
|
+
expect(method.postProgressMessage).toHaveBeenCalledWith(100, 'installingFirmware');
|
|
5440
|
+
});
|
|
5441
|
+
|
|
5442
|
+
test('ignores stale finished records until the current install starts', async () => {
|
|
5443
|
+
const method = new FirmwareUpdateV4({
|
|
5444
|
+
id: 1,
|
|
5445
|
+
payload: {
|
|
5446
|
+
method: 'firmwareUpdateV4',
|
|
5447
|
+
},
|
|
5448
|
+
});
|
|
5449
|
+
const typedCall = jest
|
|
5450
|
+
.fn()
|
|
5451
|
+
.mockResolvedValueOnce({
|
|
5452
|
+
type: 'DeviceFirmwareUpdateStatus',
|
|
5453
|
+
message: { records: [{ target_id: 4, status: 2, path: 'vol0:/application_p1.bin' }] },
|
|
5454
|
+
})
|
|
5455
|
+
.mockResolvedValueOnce({
|
|
5456
|
+
type: 'DeviceFirmwareUpdateStatus',
|
|
5457
|
+
message: { records: [{ target_id: 4, status: 0, path: 'vol0:/application_p1.bin' }] },
|
|
5458
|
+
})
|
|
5459
|
+
.mockResolvedValueOnce({
|
|
5460
|
+
type: 'DeviceFirmwareUpdateStatus',
|
|
5461
|
+
message: { records: [{ target_id: 4, status: 2, path: 'vol0:/application_p1.bin' }] },
|
|
5462
|
+
});
|
|
5463
|
+
const setTimeoutSpy = jest.spyOn(global, 'setTimeout').mockImplementation(((
|
|
5464
|
+
callback: () => void
|
|
5465
|
+
) => {
|
|
5475
5466
|
callback();
|
|
5476
5467
|
return 0 as any;
|
|
5477
5468
|
}) as typeof setTimeout);
|
|
@@ -5480,22 +5471,70 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
5480
5471
|
getCommands: () => ({ typedCall }),
|
|
5481
5472
|
});
|
|
5482
5473
|
(method as any).reconnectProtocolV2Device = jest.fn().mockResolvedValue(undefined);
|
|
5483
|
-
(method as any).verifyProtocolV2ReconnectIdentity = jest.fn().mockResolvedValue(
|
|
5484
|
-
(method as any).probeProtocolV2NormalMode = jest.fn().mockResolvedValue(true);
|
|
5485
|
-
(method as any).protocolV2InstallAckReceived = true;
|
|
5474
|
+
(method as any).verifyProtocolV2ReconnectIdentity = jest.fn().mockResolvedValue(undefined);
|
|
5486
5475
|
method.postProgressMessage = jest.fn();
|
|
5487
5476
|
|
|
5488
|
-
|
|
5489
|
-
(method as any).waitForProtocolV2FirmwareUpdateComplete(
|
|
5490
|
-
{ target_id: 4, path: 'vol0:/application_p1.bin' },
|
|
5491
|
-
|
|
5492
|
-
|
|
5477
|
+
try {
|
|
5478
|
+
await (method as any).waitForProtocolV2FirmwareUpdateComplete(
|
|
5479
|
+
[{ target_id: 4, path: 'vol0:/application_p1.bin' }],
|
|
5480
|
+
true
|
|
5481
|
+
);
|
|
5482
|
+
} finally {
|
|
5483
|
+
setTimeoutSpy.mockRestore();
|
|
5484
|
+
}
|
|
5493
5485
|
|
|
5494
|
-
expect(typedCall).toHaveBeenCalledTimes(
|
|
5495
|
-
expect((method as any).probeProtocolV2NormalMode).toHaveBeenCalledWith(deviceInfo);
|
|
5486
|
+
expect(typedCall).toHaveBeenCalledTimes(3);
|
|
5496
5487
|
expect(method.postProgressMessage).toHaveBeenCalledWith(100, 'installingFirmware');
|
|
5497
5488
|
});
|
|
5498
5489
|
|
|
5490
|
+
test('ignores stale failed records until the current install starts', async () => {
|
|
5491
|
+
const method = new FirmwareUpdateV4({
|
|
5492
|
+
id: 1,
|
|
5493
|
+
payload: {
|
|
5494
|
+
method: 'firmwareUpdateV4',
|
|
5495
|
+
},
|
|
5496
|
+
});
|
|
5497
|
+
const typedCall = jest
|
|
5498
|
+
.fn()
|
|
5499
|
+
.mockResolvedValueOnce({
|
|
5500
|
+
type: 'DeviceFirmwareUpdateStatus',
|
|
5501
|
+
message: { records: [{ target_id: 4, status: 3 }] },
|
|
5502
|
+
})
|
|
5503
|
+
.mockResolvedValueOnce({
|
|
5504
|
+
type: 'DeviceFirmwareUpdateStatus',
|
|
5505
|
+
message: { records: [{ target_id: 4, status: 0 }] },
|
|
5506
|
+
})
|
|
5507
|
+
.mockResolvedValueOnce({
|
|
5508
|
+
type: 'DeviceFirmwareUpdateStatus',
|
|
5509
|
+
message: { records: [{ target_id: 4, status: 3 }] },
|
|
5510
|
+
});
|
|
5511
|
+
const setTimeoutSpy = jest.spyOn(global, 'setTimeout').mockImplementation(((
|
|
5512
|
+
callback: () => void
|
|
5513
|
+
) => {
|
|
5514
|
+
callback();
|
|
5515
|
+
return 0 as any;
|
|
5516
|
+
}) as typeof setTimeout);
|
|
5517
|
+
|
|
5518
|
+
(method as any).device = stubDevice({
|
|
5519
|
+
getCommands: () => ({ typedCall }),
|
|
5520
|
+
});
|
|
5521
|
+
(method as any).reconnectProtocolV2Device = jest.fn().mockResolvedValue(undefined);
|
|
5522
|
+
(method as any).verifyProtocolV2ReconnectIdentity = jest.fn().mockResolvedValue(undefined);
|
|
5523
|
+
|
|
5524
|
+
try {
|
|
5525
|
+
await expect(
|
|
5526
|
+
(method as any).waitForProtocolV2FirmwareUpdateComplete(
|
|
5527
|
+
[{ target_id: 4, path: 'vol0:/application_p1.bin' }],
|
|
5528
|
+
true
|
|
5529
|
+
)
|
|
5530
|
+
).rejects.toMatchObject({ errorCode: HardwareErrorCode.FirmwareError });
|
|
5531
|
+
} finally {
|
|
5532
|
+
setTimeoutSpy.mockRestore();
|
|
5533
|
+
}
|
|
5534
|
+
|
|
5535
|
+
expect(typedCall).toHaveBeenCalledTimes(3);
|
|
5536
|
+
});
|
|
5537
|
+
|
|
5499
5538
|
test('rejects normal mode without install ACK, target status, or a version change', async () => {
|
|
5500
5539
|
const method = new FirmwareUpdateV4({
|
|
5501
5540
|
id: 1,
|
|
@@ -5806,7 +5845,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
5806
5845
|
);
|
|
5807
5846
|
});
|
|
5808
5847
|
|
|
5809
|
-
test('polls target status after
|
|
5848
|
+
test('polls target status after the install request and finishes when all targets complete', async () => {
|
|
5810
5849
|
const method = new FirmwareUpdateV4({
|
|
5811
5850
|
id: 1,
|
|
5812
5851
|
payload: {
|
|
@@ -5841,7 +5880,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
5841
5880
|
expect(reconnectProtocolV2Device).toHaveBeenCalledTimes(1);
|
|
5842
5881
|
expect(typedCall).toHaveBeenCalledWith(
|
|
5843
5882
|
'DeviceFirmwareUpdateStatusGet',
|
|
5844
|
-
'DeviceFirmwareUpdateStatus',
|
|
5883
|
+
['DeviceFirmwareUpdateStatus', 'Success'],
|
|
5845
5884
|
expect.anything(),
|
|
5846
5885
|
expect.anything()
|
|
5847
5886
|
);
|
|
@@ -6117,7 +6156,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
6117
6156
|
});
|
|
6118
6157
|
expect(typedCall).toHaveBeenCalledWith(
|
|
6119
6158
|
'DeviceFirmwareUpdateStatusGet',
|
|
6120
|
-
'DeviceFirmwareUpdateStatus',
|
|
6159
|
+
['DeviceFirmwareUpdateStatus', 'Success'],
|
|
6121
6160
|
{
|
|
6122
6161
|
fields: {
|
|
6123
6162
|
status: true,
|
|
@@ -6212,12 +6251,15 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
6212
6251
|
],
|
|
6213
6252
|
});
|
|
6214
6253
|
expect((method as any).waitForProtocolV2FirmwareUpdateComplete).toHaveBeenCalledTimes(1);
|
|
6215
|
-
expect((method as any).waitForProtocolV2FirmwareUpdateComplete).toHaveBeenCalledWith(
|
|
6216
|
-
|
|
6217
|
-
|
|
6218
|
-
|
|
6219
|
-
|
|
6220
|
-
|
|
6254
|
+
expect((method as any).waitForProtocolV2FirmwareUpdateComplete).toHaveBeenCalledWith(
|
|
6255
|
+
[
|
|
6256
|
+
{ target_id: 4, path: 'vol0:/application_p1.bin' },
|
|
6257
|
+
{ target_id: 7, path: 'vol0:/se01.bin' },
|
|
6258
|
+
{ target_id: 3, path: 'vol0:/bootloader.bin' },
|
|
6259
|
+
{ target_id: 6, path: 'vol0:/coprocessor.bin' },
|
|
6260
|
+
],
|
|
6261
|
+
true
|
|
6262
|
+
);
|
|
6221
6263
|
expect((method as any).exitProtocolV2BootloaderToNormal).not.toHaveBeenCalled();
|
|
6222
6264
|
expect(method.postProgressMessage).toHaveBeenCalledWith(100, 'transferData');
|
|
6223
6265
|
expect((method as any).completeProtocolV2FinalVerification).toHaveBeenCalledTimes(1);
|
|
@@ -6537,6 +6579,8 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
6537
6579
|
target: 'APPLICATION_P1',
|
|
6538
6580
|
url: 'https://example.com/applicationP1.pp.bin',
|
|
6539
6581
|
...componentIntegrity('https://example.com/applicationP1.pp.bin'),
|
|
6582
|
+
// Core treats the package as opaque; the device owns its internal format validation.
|
|
6583
|
+
payloadHash: '00'.repeat(64),
|
|
6540
6584
|
},
|
|
6541
6585
|
applicationP2: {
|
|
6542
6586
|
target: 'APPLICATION_P2',
|
|
@@ -6905,7 +6949,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
6905
6949
|
const archiveBinary = await zip.generateAsync({ type: 'arraybuffer' });
|
|
6906
6950
|
const preparedEntries = [
|
|
6907
6951
|
{
|
|
6908
|
-
entryName: 'manifest.json',
|
|
6952
|
+
entryName: 'pro2-resource/manifest.json',
|
|
6909
6953
|
artifact: {
|
|
6910
6954
|
artifactRef: 'manifest',
|
|
6911
6955
|
size: manifestBinary.byteLength,
|
|
@@ -6913,7 +6957,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
6913
6957
|
},
|
|
6914
6958
|
},
|
|
6915
6959
|
{
|
|
6916
|
-
entryName: 'bundles/images/images.okpkg',
|
|
6960
|
+
entryName: 'pro2-resource/bundles/images/images.okpkg',
|
|
6917
6961
|
artifact: {
|
|
6918
6962
|
artifactRef: 'images',
|
|
6919
6963
|
size: imagesBinary.byteLength,
|
|
@@ -6921,13 +6965,21 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
6921
6965
|
},
|
|
6922
6966
|
},
|
|
6923
6967
|
{
|
|
6924
|
-
entryName: 'loaders/bootloader/boot_resource.okpkg',
|
|
6968
|
+
entryName: 'pro2-resource/loaders/bootloader/boot_resource.okpkg',
|
|
6925
6969
|
artifact: {
|
|
6926
6970
|
artifactRef: 'boot',
|
|
6927
6971
|
size: bootBinary.byteLength,
|
|
6928
6972
|
sha256: bootSha256,
|
|
6929
6973
|
},
|
|
6930
6974
|
},
|
|
6975
|
+
{
|
|
6976
|
+
entryName: 'pro2-resource/build-info.txt',
|
|
6977
|
+
artifact: {
|
|
6978
|
+
artifactRef: 'build-info',
|
|
6979
|
+
size: 1,
|
|
6980
|
+
sha256: 'f'.repeat(64),
|
|
6981
|
+
},
|
|
6982
|
+
},
|
|
6931
6983
|
];
|
|
6932
6984
|
const artifacts = new Map([['archive', archiveBinary]]);
|
|
6933
6985
|
(method as any).params = {
|
|
@@ -6971,11 +7023,6 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
6971
7023
|
}),
|
|
6972
7024
|
]);
|
|
6973
7025
|
await Promise.all(sources.map(source => source.source.close()));
|
|
6974
|
-
|
|
6975
|
-
preparedEntries[1].artifact.sha256 = 'f'.repeat(64);
|
|
6976
|
-
await expect((method as any).prepareProtocolV2ResourceArchiveSources()).rejects.toThrow(
|
|
6977
|
-
'entries do not match the approved archive'
|
|
6978
|
-
);
|
|
6979
7026
|
});
|
|
6980
7027
|
|
|
6981
7028
|
test('binds a prepared resource archive to the selected host generation', () => {
|
|
@@ -7317,9 +7364,10 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
7317
7364
|
],
|
|
7318
7365
|
};
|
|
7319
7366
|
const zip = new JSZip();
|
|
7320
|
-
zip.file('manifest.json', JSON.stringify(manifest));
|
|
7321
|
-
zip.file('bundles/images/images.okpkg', imagesBinary);
|
|
7322
|
-
zip.file('loaders/bootloader/boot_resource.okpkg', bootResourceBinary);
|
|
7367
|
+
zip.file('pro2-resource/manifest.json', JSON.stringify(manifest));
|
|
7368
|
+
zip.file('pro2-resource/bundles/images/images.okpkg', imagesBinary);
|
|
7369
|
+
zip.file('pro2-resource/loaders/bootloader/boot_resource.okpkg', bootResourceBinary);
|
|
7370
|
+
zip.file('pro2-resource/build-info.txt', 'ignored');
|
|
7323
7371
|
const resourceArchiveBinary = await zip.generateAsync({ type: 'arraybuffer' });
|
|
7324
7372
|
const applicationP1Binary = new Uint8Array([7, 8, 9]).buffer;
|
|
7325
7373
|
const bootloaderBinary = new Uint8Array([10, 11, 12]).buffer;
|
|
@@ -7395,6 +7443,39 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
7395
7443
|
}
|
|
7396
7444
|
});
|
|
7397
7445
|
|
|
7446
|
+
test('accepts a local resource ZIP without manifest.json', async () => {
|
|
7447
|
+
const imagesBinary = new Uint8Array([1, 2, 3]).buffer;
|
|
7448
|
+
const bootResourceBinary = new Uint8Array([4, 5, 6]).buffer;
|
|
7449
|
+
const zip = new JSZip();
|
|
7450
|
+
zip.file('pro2-resource/bundles/images/images.okpkg', imagesBinary);
|
|
7451
|
+
zip.file('pro2-resource/loaders/bootloader/boot_resource.okpkg', bootResourceBinary);
|
|
7452
|
+
zip.file('pro2-resource/build-info.txt', 'ignored');
|
|
7453
|
+
const method = new FirmwareUpdateV4({
|
|
7454
|
+
id: 1,
|
|
7455
|
+
payload: {
|
|
7456
|
+
method: 'firmwareUpdateV4',
|
|
7457
|
+
platform: 'web',
|
|
7458
|
+
targetsToUpdate: ['resource'],
|
|
7459
|
+
},
|
|
7460
|
+
});
|
|
7461
|
+
method.init();
|
|
7462
|
+
|
|
7463
|
+
await expect(
|
|
7464
|
+
(method as any).prepareProtocolV2LocalResourceArchive(
|
|
7465
|
+
await zip.generateAsync({ type: 'arraybuffer' })
|
|
7466
|
+
)
|
|
7467
|
+
).resolves.toMatchObject({
|
|
7468
|
+
materializedEntries: [
|
|
7469
|
+
{ entryName: 'manifest.json' },
|
|
7470
|
+
{ entryName: 'bundles/images/images.okpkg', binary: imagesBinary },
|
|
7471
|
+
{
|
|
7472
|
+
entryName: 'loaders/bootloader/boot_resource.okpkg',
|
|
7473
|
+
binary: bootResourceBinary,
|
|
7474
|
+
},
|
|
7475
|
+
],
|
|
7476
|
+
});
|
|
7477
|
+
});
|
|
7478
|
+
|
|
7398
7479
|
test('rejects a local resource ZIP whose file hash does not match its manifest', async () => {
|
|
7399
7480
|
const resourceBinary = new Uint8Array([1, 2, 3]).buffer;
|
|
7400
7481
|
const bootResourceBinary = new Uint8Array([4, 5, 6]).buffer;
|
|
@@ -7485,18 +7566,57 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
7485
7566
|
|
|
7486
7567
|
test('rejects an oversized ZIP entry before allocating its decompressed bytes', async () => {
|
|
7487
7568
|
const extractEntry = jest.fn();
|
|
7488
|
-
const
|
|
7489
|
-
|
|
7490
|
-
|
|
7491
|
-
|
|
7492
|
-
|
|
7493
|
-
|
|
7494
|
-
|
|
7495
|
-
|
|
7569
|
+
const oversizedFileSize = 257 * 1024 * 1024;
|
|
7570
|
+
const manifestBinary = new TextEncoder().encode(
|
|
7571
|
+
JSON.stringify({
|
|
7572
|
+
files: [
|
|
7573
|
+
{
|
|
7574
|
+
archive_path: 'loaders/bootloader/boot_resource.okpkg',
|
|
7575
|
+
original_name: 'boot_resource.okpkg',
|
|
7576
|
+
device_path: 'vol0:/loaders/bootloader/boot_resource.okpkg',
|
|
7577
|
+
size: oversizedFileSize,
|
|
7578
|
+
sha256: '0'.repeat(64),
|
|
7579
|
+
signed: true,
|
|
7580
|
+
sig_algo: 'ed25519',
|
|
7496
7581
|
},
|
|
7497
|
-
|
|
7582
|
+
{
|
|
7583
|
+
archive_path: 'bundles/images/images.okpkg',
|
|
7584
|
+
original_name: 'images.okpkg',
|
|
7585
|
+
device_path: 'vol0:/bundles/images/images.okpkg',
|
|
7586
|
+
size: oversizedFileSize,
|
|
7587
|
+
sha256: '0'.repeat(64),
|
|
7588
|
+
signed: true,
|
|
7589
|
+
sig_algo: 'ed25519',
|
|
7590
|
+
},
|
|
7591
|
+
],
|
|
7592
|
+
})
|
|
7593
|
+
);
|
|
7594
|
+
const zipFiles = {
|
|
7595
|
+
'manifest.json': {
|
|
7596
|
+
name: 'manifest.json',
|
|
7597
|
+
dir: false,
|
|
7598
|
+
_data: {
|
|
7599
|
+
compressedSize: manifestBinary.byteLength,
|
|
7600
|
+
uncompressedSize: manifestBinary.byteLength,
|
|
7498
7601
|
},
|
|
7602
|
+
async: jest.fn().mockResolvedValue(manifestBinary.buffer),
|
|
7603
|
+
},
|
|
7604
|
+
'loaders/bootloader/boot_resource.okpkg': {
|
|
7605
|
+
name: 'loaders/bootloader/boot_resource.okpkg',
|
|
7606
|
+
dir: false,
|
|
7607
|
+
_data: { compressedSize: 1, uncompressedSize: oversizedFileSize },
|
|
7608
|
+
async: extractEntry,
|
|
7499
7609
|
},
|
|
7610
|
+
'bundles/images/images.okpkg': {
|
|
7611
|
+
name: 'bundles/images/images.okpkg',
|
|
7612
|
+
dir: false,
|
|
7613
|
+
_data: { compressedSize: 1, uncompressedSize: oversizedFileSize },
|
|
7614
|
+
async: extractEntry,
|
|
7615
|
+
},
|
|
7616
|
+
};
|
|
7617
|
+
const loadSpy = jest.spyOn(JSZip, 'loadAsync').mockResolvedValue({
|
|
7618
|
+
files: zipFiles,
|
|
7619
|
+
file: (name: string) => zipFiles[name as keyof typeof zipFiles] ?? null,
|
|
7500
7620
|
} as unknown as JSZip);
|
|
7501
7621
|
const method = new FirmwareUpdateV4({
|
|
7502
7622
|
id: 1,
|
|
@@ -7511,7 +7631,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
7511
7631
|
try {
|
|
7512
7632
|
await expect(
|
|
7513
7633
|
(method as any).prepareProtocolV2LocalResourceArchive(new Uint8Array([1]).buffer)
|
|
7514
|
-
).rejects.toThrow('declared size
|
|
7634
|
+
).rejects.toThrow('declared size is invalid');
|
|
7515
7635
|
expect(extractEntry).not.toHaveBeenCalled();
|
|
7516
7636
|
} finally {
|
|
7517
7637
|
loadSpy.mockRestore();
|
|
@@ -7807,7 +7927,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
7807
7927
|
expect(writePayloads.map(payload => payload.file.data.byteLength)).toEqual([4000, 97]);
|
|
7808
7928
|
expect(writePayloads.map(payload => payload.overwrite)).toEqual([true, false]);
|
|
7809
7929
|
expect(writePayloads.every(payload => payload.append === false)).toBe(true);
|
|
7810
|
-
expect(writePayloads.map(payload => payload.ui_percentage)).toEqual([0,
|
|
7930
|
+
expect(writePayloads.map(payload => payload.ui_percentage)).toEqual([0, 99]);
|
|
7811
7931
|
expect(method.postMessage).toHaveBeenLastCalledWith({
|
|
7812
7932
|
event: 'UI_EVENT',
|
|
7813
7933
|
type: UI_REQUEST.FIRMWARE_PROGRESS,
|
|
@@ -7888,9 +8008,9 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
7888
8008
|
|
|
7889
8009
|
const writePayloads = typedCall.mock.calls.map(call => call[2]);
|
|
7890
8010
|
const deviceProgress = writePayloads.map(payload => payload.ui_percentage);
|
|
7891
|
-
expect(deviceProgress).toEqual([0, 50, 99,
|
|
8011
|
+
expect(deviceProgress).toEqual([0, 50, 99, 99]);
|
|
7892
8012
|
expect(deviceProgress.filter(progress => progress === 0)).toHaveLength(1);
|
|
7893
|
-
expect(deviceProgress.filter(progress => progress === 100)).toHaveLength(
|
|
8013
|
+
expect(deviceProgress.filter(progress => progress === 100)).toHaveLength(0);
|
|
7894
8014
|
expect(method.postTipMessage).toHaveBeenCalledTimes(2);
|
|
7895
8015
|
expect(method.postTipMessage).toHaveBeenNthCalledWith(1, 'StartTransferData');
|
|
7896
8016
|
expect(method.postTipMessage).toHaveBeenNthCalledWith(2, 'ConfirmOnDevice');
|
|
@@ -8208,7 +8328,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
8208
8328
|
const writePayloads = typedCall.mock.calls.map(call => call[2]);
|
|
8209
8329
|
expect(writePayloads.map(payload => payload.file.offset)).toEqual([0, 1800]);
|
|
8210
8330
|
expect(writePayloads.map(payload => payload.file.data.byteLength)).toEqual([1800, 1]);
|
|
8211
|
-
expect(writePayloads.map(payload => payload.ui_percentage)).toEqual([0,
|
|
8331
|
+
expect(writePayloads.map(payload => payload.ui_percentage)).toEqual([0, 99]);
|
|
8212
8332
|
expect(typedCall.mock.calls.map(call => call[3])).toEqual([
|
|
8213
8333
|
expect.objectContaining({
|
|
8214
8334
|
writeWithResponse: false,
|
|
@@ -8267,23 +8387,24 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
8267
8387
|
expect(writePayloads.map(payload => payload.file.data.byteLength)).toEqual([1960, 1]);
|
|
8268
8388
|
});
|
|
8269
8389
|
|
|
8270
|
-
test('
|
|
8390
|
+
test('starts install progress only after Stage and the empty Request are written', async () => {
|
|
8271
8391
|
const method = new FirmwareUpdateV4({
|
|
8272
8392
|
id: 1,
|
|
8273
8393
|
payload: {
|
|
8274
8394
|
method: 'firmwareUpdateV4',
|
|
8275
8395
|
},
|
|
8276
8396
|
});
|
|
8277
|
-
let
|
|
8278
|
-
const typedCall = jest.fn().
|
|
8397
|
+
let resolveWrite: ((value: unknown) => void) | undefined;
|
|
8398
|
+
const typedCall = jest.fn().mockResolvedValue({ type: 'Success', message: {} });
|
|
8399
|
+
const call = jest.fn().mockImplementation(
|
|
8279
8400
|
() =>
|
|
8280
8401
|
new Promise(resolve => {
|
|
8281
|
-
|
|
8402
|
+
resolveWrite = resolve;
|
|
8282
8403
|
})
|
|
8283
8404
|
);
|
|
8284
8405
|
|
|
8285
8406
|
(method as any).device = stubDevice({
|
|
8286
|
-
getCommands: () => ({ typedCall }),
|
|
8407
|
+
getCommands: () => ({ typedCall, call }),
|
|
8287
8408
|
});
|
|
8288
8409
|
method.postProgressMessage = jest.fn();
|
|
8289
8410
|
method.postTipMessage = jest.fn();
|
|
@@ -8291,21 +8412,31 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
8291
8412
|
const startPromise = (method as any).protocolV2StartFirmwareUpdate({
|
|
8292
8413
|
targets: [{ target_id: 4, path: 'vol1:firmware.bin' }],
|
|
8293
8414
|
});
|
|
8294
|
-
await Promise
|
|
8415
|
+
await new Promise<void>(resolve => {
|
|
8416
|
+
setImmediate(resolve);
|
|
8417
|
+
});
|
|
8295
8418
|
|
|
8296
|
-
expect(typedCall.mock.calls[0]
|
|
8297
|
-
|
|
8419
|
+
expect(typedCall.mock.calls[0]).toEqual([
|
|
8420
|
+
'DeviceFirmwareUpdateStage',
|
|
8421
|
+
'Success',
|
|
8422
|
+
{ targets: [{ target_id: 4, path: 'vol1:firmware.bin' }] },
|
|
8423
|
+
]);
|
|
8424
|
+
expect(call).toHaveBeenCalledWith(
|
|
8425
|
+
'DeviceFirmwareUpdateRequest',
|
|
8426
|
+
{},
|
|
8427
|
+
{ returnAfterWrite: true }
|
|
8428
|
+
);
|
|
8298
8429
|
expect(method.postTipMessage).not.toHaveBeenCalled();
|
|
8299
8430
|
expect(method.postProgressMessage).not.toHaveBeenCalled();
|
|
8300
8431
|
|
|
8301
|
-
|
|
8432
|
+
resolveWrite?.({ type: 'WriteCompleted', message: {} });
|
|
8302
8433
|
await startPromise;
|
|
8303
8434
|
expect(method.postTipMessage).toHaveBeenCalledWith('FirmwareUpdating');
|
|
8304
8435
|
expect(method.postProgressMessage).toHaveBeenCalledWith(0, 'installingFirmware');
|
|
8305
8436
|
expect(method.postTipMessage).toHaveBeenCalledTimes(1);
|
|
8306
8437
|
});
|
|
8307
8438
|
|
|
8308
|
-
test('
|
|
8439
|
+
test('sends an empty Protocol V2 firmware install request without waiting for its response', async () => {
|
|
8309
8440
|
const method = new FirmwareUpdateV4({
|
|
8310
8441
|
id: 1,
|
|
8311
8442
|
payload: {
|
|
@@ -8316,9 +8447,10 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
8316
8447
|
type: 'Success',
|
|
8317
8448
|
message: { message: 'accepted' },
|
|
8318
8449
|
});
|
|
8450
|
+
const call = jest.fn().mockResolvedValue({ type: 'WriteCompleted', message: {} });
|
|
8319
8451
|
|
|
8320
8452
|
(method as any).device = stubDevice({
|
|
8321
|
-
getCommands: () => ({ typedCall }),
|
|
8453
|
+
getCommands: () => ({ typedCall, call }),
|
|
8322
8454
|
});
|
|
8323
8455
|
method.postProgressMessage = jest.fn();
|
|
8324
8456
|
method.postTipMessage = jest.fn();
|
|
@@ -8327,13 +8459,18 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
8327
8459
|
targets: [{ target_id: 4, path: 'vol1:firmware.bin' }],
|
|
8328
8460
|
});
|
|
8329
8461
|
|
|
8330
|
-
expect(typedCall.mock.calls[0][
|
|
8462
|
+
expect(typedCall.mock.calls[0][0]).toBe('DeviceFirmwareUpdateStage');
|
|
8463
|
+
expect(call).toHaveBeenCalledWith(
|
|
8464
|
+
'DeviceFirmwareUpdateRequest',
|
|
8465
|
+
{},
|
|
8466
|
+
{ returnAfterWrite: true }
|
|
8467
|
+
);
|
|
8331
8468
|
expect(method.postTipMessage).toHaveBeenCalledWith('FirmwareUpdating');
|
|
8332
8469
|
});
|
|
8333
8470
|
});
|
|
8334
8471
|
|
|
8335
8472
|
describe('Protocol V2 firmware update method', () => {
|
|
8336
|
-
test('
|
|
8473
|
+
test('stages targets before sending the empty low-level update trigger', async () => {
|
|
8337
8474
|
const method = new DeviceFirmwareUpdate({
|
|
8338
8475
|
id: 1,
|
|
8339
8476
|
payload: {
|
|
@@ -8344,22 +8481,25 @@ describe('Protocol V2 firmware update method', () => {
|
|
|
8344
8481
|
});
|
|
8345
8482
|
method.init();
|
|
8346
8483
|
|
|
8347
|
-
const typedCall = jest.fn().mockResolvedValue({
|
|
8348
|
-
|
|
8349
|
-
message: { records: [{ target_id: 4, status: 1 }] },
|
|
8350
|
-
});
|
|
8484
|
+
const typedCall = jest.fn().mockResolvedValue({ type: 'Success', message: {} });
|
|
8485
|
+
const call = jest.fn().mockResolvedValue({ type: 'WriteCompleted', message: {} });
|
|
8351
8486
|
|
|
8352
8487
|
(method as any).device = stubDevice({
|
|
8353
|
-
commands: { typedCall },
|
|
8488
|
+
commands: { typedCall, call },
|
|
8354
8489
|
});
|
|
8355
8490
|
|
|
8356
8491
|
await expect(method.run()).resolves.toEqual({
|
|
8357
|
-
|
|
8492
|
+
message: 'Device firmware update started',
|
|
8358
8493
|
});
|
|
8359
|
-
expect(typedCall
|
|
8360
|
-
expect(typedCall.mock.calls[0][2]).toEqual({
|
|
8494
|
+
expect(typedCall).toHaveBeenCalledWith('DeviceFirmwareUpdateStage', 'Success', {
|
|
8361
8495
|
targets: [{ target_id: 4, path: 'vol0:firmware.bin' }],
|
|
8362
8496
|
});
|
|
8497
|
+
expect(call).toHaveBeenCalledWith(
|
|
8498
|
+
'DeviceFirmwareUpdateRequest',
|
|
8499
|
+
{},
|
|
8500
|
+
{ returnAfterWrite: true }
|
|
8501
|
+
);
|
|
8502
|
+
expect(typedCall.mock.invocationCallOrder[0]).toBeLessThan(call.mock.invocationCallOrder[0]);
|
|
8363
8503
|
});
|
|
8364
8504
|
|
|
8365
8505
|
test('treats WebUSB open NotFoundError from low-level update trigger as expected disconnect', async () => {
|
|
@@ -8458,6 +8598,7 @@ describe('Protocol V2 firmware update method', () => {
|
|
|
8458
8598
|
|
|
8459
8599
|
test('accepts targetId alias inside firmware targets', async () => {
|
|
8460
8600
|
const typedCall = jest.fn().mockResolvedValue({ message: {} });
|
|
8601
|
+
const call = jest.fn().mockResolvedValue({ type: 'WriteCompleted', message: {} });
|
|
8461
8602
|
const method = new DeviceFirmwareUpdate({
|
|
8462
8603
|
id: 1,
|
|
8463
8604
|
payload: {
|
|
@@ -8473,7 +8614,7 @@ describe('Protocol V2 firmware update method', () => {
|
|
|
8473
8614
|
});
|
|
8474
8615
|
method.init();
|
|
8475
8616
|
(method as any).device = stubDevice({
|
|
8476
|
-
commands: { typedCall },
|
|
8617
|
+
commands: { typedCall, call },
|
|
8477
8618
|
});
|
|
8478
8619
|
|
|
8479
8620
|
await method.run();
|
|
@@ -8484,6 +8625,7 @@ describe('Protocol V2 firmware update method', () => {
|
|
|
8484
8625
|
|
|
8485
8626
|
test('accepts firmware target enum names from low-level update params', async () => {
|
|
8486
8627
|
const typedCall = jest.fn().mockResolvedValue({ message: {} });
|
|
8628
|
+
const call = jest.fn().mockResolvedValue({ type: 'WriteCompleted', message: {} });
|
|
8487
8629
|
const method = new DeviceFirmwareUpdate({
|
|
8488
8630
|
id: 1,
|
|
8489
8631
|
payload: {
|
|
@@ -8494,7 +8636,7 @@ describe('Protocol V2 firmware update method', () => {
|
|
|
8494
8636
|
});
|
|
8495
8637
|
method.init();
|
|
8496
8638
|
(method as any).device = stubDevice({
|
|
8497
|
-
commands: { typedCall },
|
|
8639
|
+
commands: { typedCall, call },
|
|
8498
8640
|
});
|
|
8499
8641
|
|
|
8500
8642
|
await method.run();
|
|
@@ -9222,6 +9364,29 @@ describe('Protocol V2 protected method execution', () => {
|
|
|
9222
9364
|
}
|
|
9223
9365
|
);
|
|
9224
9366
|
|
|
9367
|
+
test('skips DeviceStatus and unlock when Protocol V2 is not initialized', async () => {
|
|
9368
|
+
const method = {
|
|
9369
|
+
name: 'firmwareUpdateV4',
|
|
9370
|
+
unlockPolicy: 'unlock-before-run',
|
|
9371
|
+
run: jest.fn().mockResolvedValue({ message: 'updating' }),
|
|
9372
|
+
};
|
|
9373
|
+
const device = {
|
|
9374
|
+
state: { status: { initialized: false } },
|
|
9375
|
+
commands: { typedCall: jest.fn() },
|
|
9376
|
+
isProtocolV2: () => true,
|
|
9377
|
+
isBootloader: () => false,
|
|
9378
|
+
isRomloader: () => false,
|
|
9379
|
+
unlockDevice: jest.fn(),
|
|
9380
|
+
};
|
|
9381
|
+
|
|
9382
|
+
await expect(runMethodWithUnlockPolicy(method as any, device as any)).resolves.toEqual({
|
|
9383
|
+
message: 'updating',
|
|
9384
|
+
});
|
|
9385
|
+
expect(device.commands.typedCall).not.toHaveBeenCalled();
|
|
9386
|
+
expect(device.unlockDevice).not.toHaveBeenCalled();
|
|
9387
|
+
expect(method.run).toHaveBeenCalledTimes(1);
|
|
9388
|
+
});
|
|
9389
|
+
|
|
9225
9390
|
test('keeps Protocol V1 and lock-free methods outside the preflight path', async () => {
|
|
9226
9391
|
for (const [isProtocolV2, unlockPolicy] of [
|
|
9227
9392
|
[false, 'unlock-before-run'],
|
|
@@ -9401,7 +9566,7 @@ describe('Protocol V2 current low-level methods', () => {
|
|
|
9401
9566
|
info: {
|
|
9402
9567
|
version: undefined,
|
|
9403
9568
|
serial_number: 'PR2SERIAL',
|
|
9404
|
-
|
|
9569
|
+
factory_burn_in_completed: true,
|
|
9405
9570
|
factory_test_completed: undefined,
|
|
9406
9571
|
manufacture_time: undefined,
|
|
9407
9572
|
},
|
|
@@ -9651,7 +9816,7 @@ describe('Protocol V2 raw device info method', () => {
|
|
|
9651
9816
|
'DeviceInfoGet',
|
|
9652
9817
|
'DeviceInfo',
|
|
9653
9818
|
{
|
|
9654
|
-
targets: { hw: true,
|
|
9819
|
+
targets: { hw: true, main_mcu: true, coprocessor: true },
|
|
9655
9820
|
types: { version: true, specific: true },
|
|
9656
9821
|
},
|
|
9657
9822
|
{ timeoutMs: PROTOCOL_V2_DEVICE_INFO_TIMEOUT_MS }
|