@onekeyfe/hd-core 1.2.0-alpha.105 → 1.2.0-alpha.106
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 +90 -26
- package/__tests__/check-all-firmware-release-protocol-v2.test.ts +0 -2
- package/__tests__/device-pool-state.test.ts +1 -5
- package/__tests__/deviceSettings.test.ts +0 -1
- package/__tests__/firmware-update/firmware-update-v4-install-poll.test.ts +145 -0
- package/__tests__/logBlockEvent.test.ts +13 -1
- package/__tests__/protocol-v2.test.ts +447 -122
- package/__tests__/refresh-device-state.test.ts +0 -1
- package/__tests__/search-devices.test.ts +0 -2
- package/dist/api/FirmwareUpdateV4.d.ts +7 -3
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/GetDeviceState.d.ts.map +1 -1
- package/dist/api/SearchDevices.d.ts.map +1 -1
- package/dist/api/firmware/protocolV2Release.d.ts.map +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/device/Device.d.ts +0 -3
- package/dist/device/Device.d.ts.map +1 -1
- package/dist/device/DeviceCommands.d.ts.map +1 -1
- package/dist/device/DevicePool.d.ts +1 -1
- package/dist/device/DevicePool.d.ts.map +1 -1
- package/dist/events/logBlockEvent.d.ts.map +1 -1
- package/dist/index.d.ts +0 -6
- package/dist/index.js +251 -184
- package/dist/protocols/protocol-v2/features.d.ts +1 -1
- package/dist/protocols/protocol-v2/features.d.ts.map +1 -1
- package/dist/types/api/getDeviceState.d.ts +0 -1
- package/dist/types/api/getDeviceState.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/FirmwareUpdateV4.ts +262 -172
- package/src/api/GetDeviceState.ts +0 -1
- package/src/api/SearchDevices.ts +0 -2
- package/src/api/firmware/protocolV2Release.ts +0 -1
- package/src/core/index.ts +6 -6
- package/src/device/Device.ts +11 -48
- package/src/device/DeviceCommands.ts +4 -14
- package/src/device/DevicePool.ts +3 -11
- package/src/events/logBlockEvent.ts +14 -1
- package/src/protocols/protocol-v2/features.ts +9 -2
- package/src/types/api/getDeviceState.ts +0 -2
- package/src/utils/deviceSettings.ts +1 -1
- package/__tests__/protocol-v2-legacy-recovery.test.ts +0 -29
- package/dist/core/protocolV2LegacyRecovery.d.ts +0 -5
- package/dist/core/protocolV2LegacyRecovery.d.ts.map +0 -1
- package/src/core/protocolV2LegacyRecovery.ts +0 -12
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Buffer } from 'buffer';
|
|
2
|
-
import { EFirmwareType, ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
2
|
+
import { EDeviceType, EFirmwareType, ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
3
3
|
import { sha256 } from '@noble/hashes/sha256';
|
|
4
4
|
import { bytesToHex } from '@noble/hashes/utils';
|
|
5
5
|
import JSZip from 'jszip';
|
|
@@ -907,6 +907,34 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
907
907
|
).toBeUndefined();
|
|
908
908
|
});
|
|
909
909
|
|
|
910
|
+
test('infers legacy Protocol V2 loader mode from firmware image metadata', () => {
|
|
911
|
+
const legacyProtocolInfo = {
|
|
912
|
+
version: 1,
|
|
913
|
+
build_fingerprint: '',
|
|
914
|
+
supported_messages: [],
|
|
915
|
+
protobuf_definition: null,
|
|
916
|
+
};
|
|
917
|
+
|
|
918
|
+
expect(
|
|
919
|
+
getProtocolV2RuntimeMode(legacyProtocolInfo, {
|
|
920
|
+
fw: { bootloader: { version: '0.2.0' } },
|
|
921
|
+
})
|
|
922
|
+
).toBe('bootloader');
|
|
923
|
+
expect(
|
|
924
|
+
getProtocolV2RuntimeMode(legacyProtocolInfo, {
|
|
925
|
+
fw: { romloader: { version: '1.0.0' } },
|
|
926
|
+
})
|
|
927
|
+
).toBe('romloader');
|
|
928
|
+
expect(
|
|
929
|
+
getProtocolV2RuntimeMode(legacyProtocolInfo, {
|
|
930
|
+
fw: {
|
|
931
|
+
application: { version: '1.2.3' },
|
|
932
|
+
bootloader: { version: '0.2.0' },
|
|
933
|
+
},
|
|
934
|
+
})
|
|
935
|
+
).toBeUndefined();
|
|
936
|
+
});
|
|
937
|
+
|
|
910
938
|
test('keeps the Protocol V2 main wallet on the default empty-passphrase context', async () => {
|
|
911
939
|
const features = normalizeProtocolV2Features(descriptor as any);
|
|
912
940
|
features.firmwareVersion = '1.2.3';
|
|
@@ -3268,33 +3296,43 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
3268
3296
|
expect(typedCall).toHaveBeenCalledTimes(1);
|
|
3269
3297
|
});
|
|
3270
3298
|
|
|
3271
|
-
test('
|
|
3299
|
+
test('initializes a legacy Protocol V2 bootloader without compatibility options', async () => {
|
|
3272
3300
|
const device = Device.fromDescriptor({
|
|
3273
3301
|
path: 'usb-path',
|
|
3274
3302
|
protocolType: 'V2',
|
|
3275
3303
|
} as any);
|
|
3276
|
-
const typedCall = jest
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3304
|
+
const typedCall = jest
|
|
3305
|
+
.fn()
|
|
3306
|
+
.mockResolvedValueOnce({
|
|
3307
|
+
type: 'DeviceInfo',
|
|
3308
|
+
message: {
|
|
3309
|
+
hw: { Device_type: DeviceType.PRO2, serial_no: 'PR2SERIAL' },
|
|
3310
|
+
fw: { bootloader: { version: '0.2.0' } },
|
|
3311
|
+
},
|
|
3312
|
+
})
|
|
3313
|
+
.mockResolvedValueOnce({
|
|
3314
|
+
type: 'ProtocolInfo',
|
|
3315
|
+
message: {
|
|
3316
|
+
version: 1,
|
|
3317
|
+
build_fingerprint: '',
|
|
3318
|
+
supported_messages: [],
|
|
3319
|
+
protobuf_definition: null,
|
|
3320
|
+
},
|
|
3321
|
+
});
|
|
3285
3322
|
(device as any).commands = { typedCall };
|
|
3286
3323
|
|
|
3287
|
-
await
|
|
3288
|
-
device.probeProtocolV2RuntimeState({
|
|
3289
|
-
hw: { Device_type: DeviceType.PRO2, serial_no: 'PR2SERIAL' },
|
|
3290
|
-
fw: { application: { version: '1.2.3' } },
|
|
3291
|
-
})
|
|
3292
|
-
).rejects.toMatchObject({ errorCode: HardwareErrorCode.DeviceInitializeFailed });
|
|
3324
|
+
await device.initialize();
|
|
3293
3325
|
|
|
3294
|
-
expect(typedCall).toHaveBeenCalledTimes(
|
|
3326
|
+
expect(typedCall).toHaveBeenCalledTimes(2);
|
|
3327
|
+
expect(typedCall).not.toHaveBeenCalledWith('DeviceStatusGet', 'DeviceStatus', {});
|
|
3328
|
+
expect(device.features).toMatchObject({
|
|
3329
|
+
mode: 'bootloader',
|
|
3330
|
+
bootloaderMode: true,
|
|
3331
|
+
initialized: null,
|
|
3332
|
+
});
|
|
3295
3333
|
});
|
|
3296
3334
|
|
|
3297
|
-
test('uses DeviceStatusGet to identify App mode for
|
|
3335
|
+
test('uses DeviceStatusGet to identify App mode for legacy ProtocolInfo', async () => {
|
|
3298
3336
|
const device = Device.fromDescriptor({
|
|
3299
3337
|
path: 'usb-path',
|
|
3300
3338
|
protocolType: 'V2',
|
|
@@ -3321,8 +3359,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
3321
3359
|
hw: { Device_type: DeviceType.PRO2, serial_no: 'PR2SERIAL' },
|
|
3322
3360
|
fw: { application: { version: '1.2.3' } },
|
|
3323
3361
|
},
|
|
3324
|
-
5000
|
|
3325
|
-
{ allowLegacyProtocolV2ProtocolInfo: true }
|
|
3362
|
+
5000
|
|
3326
3363
|
);
|
|
3327
3364
|
|
|
3328
3365
|
expect(typedCall).toHaveBeenNthCalledWith(
|
|
@@ -3347,38 +3384,32 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
3347
3384
|
});
|
|
3348
3385
|
});
|
|
3349
3386
|
|
|
3350
|
-
test('maps
|
|
3387
|
+
test('maps legacy bootloader metadata without calling DeviceStatusGet', async () => {
|
|
3351
3388
|
const device = Device.fromDescriptor({
|
|
3352
3389
|
path: 'usb-path',
|
|
3353
3390
|
protocolType: 'V2',
|
|
3354
3391
|
} as any);
|
|
3355
|
-
const typedCall = jest
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
},
|
|
3365
|
-
})
|
|
3366
|
-
.mockRejectedValueOnce(new Error('Failure_UnexpectedMessage,Unknown message'));
|
|
3392
|
+
const typedCall = jest.fn().mockResolvedValueOnce({
|
|
3393
|
+
type: 'ProtocolInfo',
|
|
3394
|
+
message: {
|
|
3395
|
+
version: 1,
|
|
3396
|
+
build_fingerprint: '',
|
|
3397
|
+
supported_messages: [],
|
|
3398
|
+
protobuf_definition: null,
|
|
3399
|
+
},
|
|
3400
|
+
});
|
|
3367
3401
|
(device as any).commands = { typedCall };
|
|
3368
3402
|
|
|
3369
|
-
await device.probeProtocolV2RuntimeState(
|
|
3370
|
-
{
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
},
|
|
3374
|
-
undefined,
|
|
3375
|
-
{ allowLegacyProtocolV2ProtocolInfo: true }
|
|
3376
|
-
);
|
|
3403
|
+
await device.probeProtocolV2RuntimeState({
|
|
3404
|
+
hw: { Device_type: DeviceType.NEO, serial_no: 'NEOSERIAL' },
|
|
3405
|
+
fw: { bootloader: { version: '0.2.0' } },
|
|
3406
|
+
});
|
|
3377
3407
|
|
|
3378
3408
|
expect(typedCall).toHaveBeenNthCalledWith(1, 'ProtocolInfoRequest', 'ProtocolInfo', {
|
|
3379
3409
|
eventless_wallet_session: true,
|
|
3380
3410
|
});
|
|
3381
|
-
expect(typedCall).
|
|
3411
|
+
expect(typedCall).toHaveBeenCalledTimes(1);
|
|
3412
|
+
expect(typedCall).not.toHaveBeenCalledWith('DeviceStatusGet', 'DeviceStatus', {});
|
|
3382
3413
|
expect(device.features).toMatchObject({
|
|
3383
3414
|
deviceType: 'neo',
|
|
3384
3415
|
mode: 'bootloader',
|
|
@@ -3387,6 +3418,37 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
3387
3418
|
});
|
|
3388
3419
|
});
|
|
3389
3420
|
|
|
3421
|
+
test('maps legacy romloader metadata without calling DeviceStatusGet', async () => {
|
|
3422
|
+
const device = Device.fromDescriptor({
|
|
3423
|
+
path: 'usb-path',
|
|
3424
|
+
protocolType: 'V2',
|
|
3425
|
+
} as any);
|
|
3426
|
+
const typedCall = jest.fn().mockResolvedValueOnce({
|
|
3427
|
+
type: 'ProtocolInfo',
|
|
3428
|
+
message: {
|
|
3429
|
+
version: 1,
|
|
3430
|
+
build_fingerprint: '',
|
|
3431
|
+
supported_messages: [],
|
|
3432
|
+
protobuf_definition: null,
|
|
3433
|
+
},
|
|
3434
|
+
});
|
|
3435
|
+
(device as any).commands = { typedCall };
|
|
3436
|
+
|
|
3437
|
+
await device.probeProtocolV2RuntimeState({
|
|
3438
|
+
hw: { Device_type: DeviceType.PRO2, serial_no: 'PR2SERIAL' },
|
|
3439
|
+
fw: { romloader: { version: '1.0.0' } },
|
|
3440
|
+
});
|
|
3441
|
+
|
|
3442
|
+
expect(typedCall).toHaveBeenCalledTimes(1);
|
|
3443
|
+
expect(typedCall).not.toHaveBeenCalledWith('DeviceStatusGet', 'DeviceStatus', {});
|
|
3444
|
+
expect(device.features).toMatchObject({
|
|
3445
|
+
deviceType: 'pro2',
|
|
3446
|
+
mode: 'romloader',
|
|
3447
|
+
bootloaderMode: true,
|
|
3448
|
+
initialized: null,
|
|
3449
|
+
});
|
|
3450
|
+
});
|
|
3451
|
+
|
|
3390
3452
|
test('does not reinterpret a state update error as runtime detection failure', async () => {
|
|
3391
3453
|
const device = Device.fromDescriptor({
|
|
3392
3454
|
path: 'usb-path',
|
|
@@ -4291,7 +4353,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
4291
4353
|
).toEqual([3, 4]);
|
|
4292
4354
|
});
|
|
4293
4355
|
|
|
4294
|
-
test('
|
|
4356
|
+
test('keeps external-only resource updates on the prepared host path', async () => {
|
|
4295
4357
|
const method = new FirmwareUpdateV4({
|
|
4296
4358
|
id: 1,
|
|
4297
4359
|
payload: {
|
|
@@ -4301,6 +4363,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
4301
4363
|
},
|
|
4302
4364
|
});
|
|
4303
4365
|
method.init();
|
|
4366
|
+
jest.spyOn(DataManager, 'getSettings').mockReturnValue('external-only' as never);
|
|
4304
4367
|
|
|
4305
4368
|
(method as any).device = stubDevice({
|
|
4306
4369
|
originalDescriptor: { id: 'usb-id', path: 'app-path', protocolType: 'V2' },
|
|
@@ -4328,6 +4391,132 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
4328
4391
|
expect((method as any).enterProtocolV2BootloaderMode).not.toHaveBeenCalled();
|
|
4329
4392
|
});
|
|
4330
4393
|
|
|
4394
|
+
test('downloads Protocol V2 resource archives in SDK-managed mode', async () => {
|
|
4395
|
+
const resourceArchiveBinary = new Uint8Array([1, 2, 3, 4]).buffer;
|
|
4396
|
+
const applicationP1Binary = new Uint8Array([5, 6, 7, 8]).buffer;
|
|
4397
|
+
const applicationP1InstallItem = {
|
|
4398
|
+
fileName: 'application_p1.bin',
|
|
4399
|
+
binary: applicationP1Binary,
|
|
4400
|
+
targetId: 4,
|
|
4401
|
+
kind: 'firmware',
|
|
4402
|
+
};
|
|
4403
|
+
const resourceArchiveSha256 = bytesToHex(sha256(new Uint8Array(resourceArchiveBinary)));
|
|
4404
|
+
const method = new FirmwareUpdateV4({
|
|
4405
|
+
id: 1,
|
|
4406
|
+
payload: {
|
|
4407
|
+
method: 'firmwareUpdateV4',
|
|
4408
|
+
platform: 'ext',
|
|
4409
|
+
targetsToUpdate: ['app_v1', 'resource'],
|
|
4410
|
+
},
|
|
4411
|
+
});
|
|
4412
|
+
method.init();
|
|
4413
|
+
|
|
4414
|
+
(method as any).device = stubDevice({
|
|
4415
|
+
originalDescriptor: { id: 'usb-id', path: 'app-path', protocolType: 'V2' },
|
|
4416
|
+
features: {
|
|
4417
|
+
deviceType: 'pro2',
|
|
4418
|
+
firmwareVersion: '1.0.0',
|
|
4419
|
+
mode: 'normal',
|
|
4420
|
+
bootloaderMode: false,
|
|
4421
|
+
capabilities: [],
|
|
4422
|
+
},
|
|
4423
|
+
getCurrentDeviceType: () => 'pro2',
|
|
4424
|
+
isBootloader: () => false,
|
|
4425
|
+
isRomloader: () => false,
|
|
4426
|
+
});
|
|
4427
|
+
(method as any).captureProtocolV2PhysicalIdentity = jest.fn().mockResolvedValue(undefined);
|
|
4428
|
+
(method as any).prepareRemoteProtocolV2Binaries = jest.fn().mockResolvedValue({
|
|
4429
|
+
bootloaderBinary: null,
|
|
4430
|
+
fwBinaryMap: [
|
|
4431
|
+
{
|
|
4432
|
+
fileName: applicationP1InstallItem.fileName,
|
|
4433
|
+
binary: applicationP1Binary,
|
|
4434
|
+
targetId: applicationP1InstallItem.targetId,
|
|
4435
|
+
},
|
|
4436
|
+
],
|
|
4437
|
+
installItems: [applicationP1InstallItem],
|
|
4438
|
+
});
|
|
4439
|
+
const release = jest.fn();
|
|
4440
|
+
(method as any).prepareProtocolV2LocalMemoryHost = jest.fn().mockResolvedValue({ release });
|
|
4441
|
+
(method as any).runProtocolV2PreparedArtifacts = jest
|
|
4442
|
+
.fn()
|
|
4443
|
+
.mockResolvedValue('sdk-managed-resource-result');
|
|
4444
|
+
method.postTipMessage = jest.fn();
|
|
4445
|
+
jest.spyOn(DataManager, 'getSettings').mockReturnValue('sdk-managed' as never);
|
|
4446
|
+
jest.spyOn(DataManager, 'getProtocolV2ResourceSource').mockReturnValue({
|
|
4447
|
+
archiveUrl: 'https://example.com/pro2-resource.zip',
|
|
4448
|
+
archiveSize: resourceArchiveBinary.byteLength,
|
|
4449
|
+
archiveSha256: resourceArchiveSha256,
|
|
4450
|
+
});
|
|
4451
|
+
const getSysResourceBinarySpy = jest
|
|
4452
|
+
.spyOn(firmwareBinaryApi, 'getSysResourceBinary')
|
|
4453
|
+
.mockResolvedValue({ binary: resourceArchiveBinary });
|
|
4454
|
+
|
|
4455
|
+
await expect(method.run()).resolves.toBe('sdk-managed-resource-result');
|
|
4456
|
+
|
|
4457
|
+
expect(forceReloadDataSpy).toHaveBeenCalledWith({
|
|
4458
|
+
requireResources: true,
|
|
4459
|
+
resourceDeviceType: EDeviceType.Pro2,
|
|
4460
|
+
});
|
|
4461
|
+
expect(getSysResourceBinarySpy).toHaveBeenCalledWith('https://example.com/pro2-resource.zip');
|
|
4462
|
+
expect((method as any).params.resourceArchiveBinary).toBe(resourceArchiveBinary);
|
|
4463
|
+
expect((method as any).prepareProtocolV2LocalMemoryHost).toHaveBeenCalledWith({
|
|
4464
|
+
features: expect.objectContaining({ deviceType: 'pro2' }),
|
|
4465
|
+
firmwareType: EFirmwareType.Universal,
|
|
4466
|
+
availableInstallItems: [applicationP1InstallItem],
|
|
4467
|
+
});
|
|
4468
|
+
expect((method as any).runProtocolV2PreparedArtifacts).toHaveBeenCalledTimes(1);
|
|
4469
|
+
expect(release).toHaveBeenCalledTimes(1);
|
|
4470
|
+
});
|
|
4471
|
+
|
|
4472
|
+
test('preserves SDK-managed resource installation errors after preparation', async () => {
|
|
4473
|
+
const resourceArchiveBinary = new Uint8Array([1, 2, 3, 4]).buffer;
|
|
4474
|
+
const installError = ERRORS.TypedError(
|
|
4475
|
+
HardwareErrorCode.FirmwareError,
|
|
4476
|
+
'device rejected the prepared resource installation'
|
|
4477
|
+
);
|
|
4478
|
+
const method = new FirmwareUpdateV4({
|
|
4479
|
+
id: 1,
|
|
4480
|
+
payload: {
|
|
4481
|
+
method: 'firmwareUpdateV4',
|
|
4482
|
+
platform: 'ext',
|
|
4483
|
+
targetsToUpdate: ['resource'],
|
|
4484
|
+
},
|
|
4485
|
+
});
|
|
4486
|
+
method.init();
|
|
4487
|
+
|
|
4488
|
+
(method as any).device = stubDevice({
|
|
4489
|
+
originalDescriptor: { id: 'usb-id', path: 'app-path', protocolType: 'V2' },
|
|
4490
|
+
features: {
|
|
4491
|
+
deviceType: 'pro2',
|
|
4492
|
+
firmwareVersion: '1.0.0',
|
|
4493
|
+
mode: 'normal',
|
|
4494
|
+
bootloaderMode: false,
|
|
4495
|
+
capabilities: [],
|
|
4496
|
+
},
|
|
4497
|
+
getCurrentDeviceType: () => 'pro2',
|
|
4498
|
+
isBootloader: () => false,
|
|
4499
|
+
isRomloader: () => false,
|
|
4500
|
+
});
|
|
4501
|
+
(method as any).captureProtocolV2PhysicalIdentity = jest.fn().mockResolvedValue(undefined);
|
|
4502
|
+
(method as any).downloadRemoteProtocolV2ResourceArchive = jest
|
|
4503
|
+
.fn()
|
|
4504
|
+
.mockResolvedValue(resourceArchiveBinary);
|
|
4505
|
+
const release = jest.fn();
|
|
4506
|
+
(method as any).prepareProtocolV2LocalMemoryHost = jest.fn().mockResolvedValue({ release });
|
|
4507
|
+
(method as any).runProtocolV2PreparedArtifacts = jest.fn().mockRejectedValue(installError);
|
|
4508
|
+
method.postTipMessage = jest.fn();
|
|
4509
|
+
jest.spyOn(DataManager, 'getSettings').mockReturnValue('sdk-managed' as never);
|
|
4510
|
+
|
|
4511
|
+
await expect(method.run()).rejects.toBe(installError);
|
|
4512
|
+
|
|
4513
|
+
expect(forceReloadDataSpy).toHaveBeenCalledWith({
|
|
4514
|
+
requireResources: true,
|
|
4515
|
+
resourceDeviceType: EDeviceType.Pro2,
|
|
4516
|
+
});
|
|
4517
|
+
expect(release).toHaveBeenCalledTimes(1);
|
|
4518
|
+
});
|
|
4519
|
+
|
|
4331
4520
|
test('reboots Protocol V2 normal-mode device to bootloader before transfer', async () => {
|
|
4332
4521
|
const method = new FirmwareUpdateV4({
|
|
4333
4522
|
id: 1,
|
|
@@ -5253,6 +5442,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
5253
5442
|
const deviceInfo = { hw: { serial_no: 'PRO2-PHYSICAL-1' } };
|
|
5254
5443
|
(method as any).verifyProtocolV2ReconnectIdentity = jest.fn().mockResolvedValue(deviceInfo);
|
|
5255
5444
|
(method as any).probeProtocolV2NormalMode = jest.fn().mockResolvedValue(true);
|
|
5445
|
+
(method as any).protocolV2InstallAckReceived = true;
|
|
5256
5446
|
method.postProgressMessage = jest.fn();
|
|
5257
5447
|
|
|
5258
5448
|
await (method as any).waitForProtocolV2FirmwareUpdateComplete([
|
|
@@ -5291,6 +5481,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
5291
5481
|
(method as any).reconnectProtocolV2Device = jest.fn().mockResolvedValue(undefined);
|
|
5292
5482
|
(method as any).verifyProtocolV2ReconnectIdentity = jest.fn().mockResolvedValue(deviceInfo);
|
|
5293
5483
|
(method as any).probeProtocolV2NormalMode = jest.fn().mockResolvedValue(true);
|
|
5484
|
+
(method as any).protocolV2InstallAckReceived = true;
|
|
5294
5485
|
method.postProgressMessage = jest.fn();
|
|
5295
5486
|
|
|
5296
5487
|
await expect(
|
|
@@ -5304,6 +5495,78 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
5304
5495
|
expect(method.postProgressMessage).toHaveBeenCalledWith(100, 'installingFirmware');
|
|
5305
5496
|
});
|
|
5306
5497
|
|
|
5498
|
+
test('rejects normal mode without install ACK, target status, or a version change', async () => {
|
|
5499
|
+
const method = new FirmwareUpdateV4({
|
|
5500
|
+
id: 1,
|
|
5501
|
+
payload: {
|
|
5502
|
+
method: 'firmwareUpdateV4',
|
|
5503
|
+
},
|
|
5504
|
+
});
|
|
5505
|
+
const typedCall = jest
|
|
5506
|
+
.fn()
|
|
5507
|
+
.mockRejectedValue(new Error('Failure: Handler not registered for this message'));
|
|
5508
|
+
const deviceInfo = { hw: { serial_no: 'PRO2-PHYSICAL-1' } };
|
|
5509
|
+
let now = 0;
|
|
5510
|
+
jest.spyOn(Date, 'now').mockImplementation(() => now);
|
|
5511
|
+
jest.spyOn(global, 'setTimeout').mockImplementation(((callback: () => void) => {
|
|
5512
|
+
now += 31 * 1000;
|
|
5513
|
+
callback();
|
|
5514
|
+
return 0 as any;
|
|
5515
|
+
}) as typeof setTimeout);
|
|
5516
|
+
|
|
5517
|
+
(method as any).device = stubDevice({
|
|
5518
|
+
getCommands: () => ({ typedCall }),
|
|
5519
|
+
});
|
|
5520
|
+
(method as any).reconnectProtocolV2Device = jest.fn().mockResolvedValue(undefined);
|
|
5521
|
+
(method as any).verifyProtocolV2ReconnectIdentity = jest.fn().mockResolvedValue(deviceInfo);
|
|
5522
|
+
(method as any).probeProtocolV2NormalMode = jest.fn().mockResolvedValue(true);
|
|
5523
|
+
method.postProgressMessage = jest.fn();
|
|
5524
|
+
|
|
5525
|
+
await expect(
|
|
5526
|
+
(method as any).waitForProtocolV2FirmwareUpdateComplete([
|
|
5527
|
+
{ target_id: 4, path: 'vol0:/application_p1.bin' },
|
|
5528
|
+
])
|
|
5529
|
+
).rejects.toMatchObject({ errorCode: HardwareErrorCode.FirmwareError });
|
|
5530
|
+
|
|
5531
|
+
expect(method.postProgressMessage).not.toHaveBeenCalledWith(100, 'installingFirmware');
|
|
5532
|
+
});
|
|
5533
|
+
|
|
5534
|
+
test('accepts ACK-less normal mode after the requested target version changes', async () => {
|
|
5535
|
+
const method = new FirmwareUpdateV4({
|
|
5536
|
+
id: 1,
|
|
5537
|
+
payload: {
|
|
5538
|
+
method: 'firmwareUpdateV4',
|
|
5539
|
+
},
|
|
5540
|
+
});
|
|
5541
|
+
const typedCall = jest
|
|
5542
|
+
.fn()
|
|
5543
|
+
.mockRejectedValue(new Error('Failure: Handler not registered for this message'));
|
|
5544
|
+
const deviceInfo = { hw: { serial_no: 'PRO2-PHYSICAL-1' } };
|
|
5545
|
+
const probeProtocolV2RuntimeState = jest.fn().mockResolvedValue({
|
|
5546
|
+
mode: 'normal',
|
|
5547
|
+
bootloaderMode: false,
|
|
5548
|
+
firmwareVersion: '2.0.0',
|
|
5549
|
+
});
|
|
5550
|
+
|
|
5551
|
+
(method as any).device = stubDevice({
|
|
5552
|
+
getCommands: () => ({ typedCall }),
|
|
5553
|
+
probeProtocolV2RuntimeState,
|
|
5554
|
+
});
|
|
5555
|
+
(method as any).protocolV2InstallBaselineVersions = new Map([[4, '1.0.0']]);
|
|
5556
|
+
(method as any).reconnectProtocolV2Device = jest.fn().mockResolvedValue(undefined);
|
|
5557
|
+
(method as any).verifyProtocolV2ReconnectIdentity = jest.fn().mockResolvedValue(deviceInfo);
|
|
5558
|
+
method.postProgressMessage = jest.fn();
|
|
5559
|
+
|
|
5560
|
+
await expect(
|
|
5561
|
+
(method as any).waitForProtocolV2FirmwareUpdateComplete([
|
|
5562
|
+
{ target_id: 4, path: 'vol0:/application_p1.bin' },
|
|
5563
|
+
])
|
|
5564
|
+
).resolves.toBeUndefined();
|
|
5565
|
+
|
|
5566
|
+
expect(probeProtocolV2RuntimeState).toHaveBeenCalledWith(deviceInfo, 5000);
|
|
5567
|
+
expect(method.postProgressMessage).toHaveBeenCalledWith(100, 'installingFirmware');
|
|
5568
|
+
});
|
|
5569
|
+
|
|
5307
5570
|
test.each([
|
|
5308
5571
|
[{ mode: 'normal', bootloaderMode: false }, true],
|
|
5309
5572
|
[{ mode: 'bootloader', bootloaderMode: true }, false],
|
|
@@ -5319,9 +5582,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
5319
5582
|
(method as any).device = stubDevice({ probeProtocolV2RuntimeState });
|
|
5320
5583
|
|
|
5321
5584
|
await expect((method as any).probeProtocolV2NormalMode(deviceInfo)).resolves.toBe(expected);
|
|
5322
|
-
expect(probeProtocolV2RuntimeState).toHaveBeenCalledWith(deviceInfo, 5000
|
|
5323
|
-
allowLegacyProtocolV2ProtocolInfo: true,
|
|
5324
|
-
});
|
|
5585
|
+
expect(probeProtocolV2RuntimeState).toHaveBeenCalledWith(deviceInfo, 5000);
|
|
5325
5586
|
});
|
|
5326
5587
|
|
|
5327
5588
|
test('keeps polling when the firmware status handler is missing in loader mode', async () => {
|
|
@@ -5867,7 +6128,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
5867
6128
|
);
|
|
5868
6129
|
});
|
|
5869
6130
|
|
|
5870
|
-
test('
|
|
6131
|
+
test('preserves component-first target order for the firmware-owned loader handoff', async () => {
|
|
5871
6132
|
const method = new FirmwareUpdateV4({
|
|
5872
6133
|
id: 1,
|
|
5873
6134
|
payload: {
|
|
@@ -5896,54 +6157,72 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
5896
6157
|
.mockResolvedValue(undefined);
|
|
5897
6158
|
|
|
5898
6159
|
await (method as any).executeProtocolV2Update({
|
|
5899
|
-
|
|
5900
|
-
|
|
6160
|
+
// The active bootloader installs its component runners in records order and
|
|
6161
|
+
// leaves the bootloader record pending for romloader after reboot. Keep boot
|
|
6162
|
+
// deliberately after components to prove Core does not synthesize boot-first.
|
|
6163
|
+
installItems: [
|
|
5901
6164
|
{
|
|
5902
|
-
fileName: '
|
|
5903
|
-
binary: new Uint8Array([
|
|
5904
|
-
targetId:
|
|
6165
|
+
fileName: 'application_p1.bin',
|
|
6166
|
+
binary: new Uint8Array([8]).buffer,
|
|
6167
|
+
targetId: 4,
|
|
6168
|
+
kind: 'firmware',
|
|
5905
6169
|
},
|
|
5906
6170
|
{
|
|
5907
6171
|
fileName: 'se01.bin',
|
|
5908
6172
|
binary: new Uint8Array([7]).buffer,
|
|
5909
6173
|
targetId: 7,
|
|
6174
|
+
kind: 'firmware',
|
|
5910
6175
|
},
|
|
5911
6176
|
{
|
|
5912
|
-
fileName: '
|
|
5913
|
-
binary: new Uint8Array([
|
|
5914
|
-
targetId:
|
|
6177
|
+
fileName: 'bootloader.bin',
|
|
6178
|
+
binary: new Uint8Array([4, 5]).buffer,
|
|
6179
|
+
targetId: 3,
|
|
6180
|
+
kind: 'bootloader',
|
|
6181
|
+
},
|
|
6182
|
+
{
|
|
6183
|
+
fileName: 'coprocessor.bin',
|
|
6184
|
+
binary: new Uint8Array([6]).buffer,
|
|
6185
|
+
targetId: 6,
|
|
6186
|
+
kind: 'firmware',
|
|
5915
6187
|
},
|
|
5916
6188
|
],
|
|
5917
6189
|
});
|
|
5918
6190
|
|
|
5919
6191
|
expect(writtenPaths).toEqual([
|
|
6192
|
+
'vol0:/application_p1.bin',
|
|
6193
|
+
'vol0:/se01.bin',
|
|
5920
6194
|
'vol0:/bootloader.bin',
|
|
5921
6195
|
'vol0:/coprocessor.bin',
|
|
5922
|
-
'vol0:/se01.bin',
|
|
5923
|
-
'vol0:/application_p1.bin',
|
|
5924
6196
|
]);
|
|
5925
6197
|
expect((method as any).verifyProtocolV2StagedFile).toHaveBeenCalledTimes(4);
|
|
5926
6198
|
expect((method as any).verifyProtocolV2StagedFile).toHaveBeenNthCalledWith(
|
|
5927
6199
|
2,
|
|
5928
|
-
'vol0:/
|
|
6200
|
+
'vol0:/se01.bin',
|
|
5929
6201
|
1
|
|
5930
6202
|
);
|
|
5931
|
-
expect((method as any).
|
|
5932
|
-
expect((method as any).protocolV2StartFirmwareUpdate).
|
|
5933
|
-
|
|
5934
|
-
});
|
|
5935
|
-
expect((method as any).protocolV2StartFirmwareUpdate).toHaveBeenNthCalledWith(2, {
|
|
6203
|
+
expect((method as any).enterProtocolV2BootloaderMode).toHaveBeenCalledTimes(1);
|
|
6204
|
+
expect((method as any).protocolV2StartFirmwareUpdate).toHaveBeenCalledTimes(1);
|
|
6205
|
+
expect((method as any).protocolV2StartFirmwareUpdate).toHaveBeenCalledWith({
|
|
5936
6206
|
targets: [
|
|
5937
|
-
{ target_id: 6, path: 'vol0:/coprocessor.bin' },
|
|
5938
|
-
{ target_id: 7, path: 'vol0:/se01.bin' },
|
|
5939
6207
|
{ target_id: 4, path: 'vol0:/application_p1.bin' },
|
|
6208
|
+
{ target_id: 7, path: 'vol0:/se01.bin' },
|
|
6209
|
+
{ target_id: 3, path: 'vol0:/bootloader.bin' },
|
|
6210
|
+
{ target_id: 6, path: 'vol0:/coprocessor.bin' },
|
|
5940
6211
|
],
|
|
5941
6212
|
});
|
|
6213
|
+
expect((method as any).waitForProtocolV2FirmwareUpdateComplete).toHaveBeenCalledTimes(1);
|
|
6214
|
+
expect((method as any).waitForProtocolV2FirmwareUpdateComplete).toHaveBeenCalledWith([
|
|
6215
|
+
{ target_id: 4, path: 'vol0:/application_p1.bin' },
|
|
6216
|
+
{ target_id: 7, path: 'vol0:/se01.bin' },
|
|
6217
|
+
{ target_id: 3, path: 'vol0:/bootloader.bin' },
|
|
6218
|
+
{ target_id: 6, path: 'vol0:/coprocessor.bin' },
|
|
6219
|
+
]);
|
|
6220
|
+
expect((method as any).exitProtocolV2BootloaderToNormal).not.toHaveBeenCalled();
|
|
5942
6221
|
expect(method.postProgressMessage).toHaveBeenCalledWith(100, 'transferData');
|
|
5943
|
-
expect((method as any).
|
|
6222
|
+
expect((method as any).completeProtocolV2FinalVerification).toHaveBeenCalledTimes(1);
|
|
5944
6223
|
});
|
|
5945
6224
|
|
|
5946
|
-
test('
|
|
6225
|
+
test('uses one global transfer range for resources and firmware', async () => {
|
|
5947
6226
|
const method = new FirmwareUpdateV4({
|
|
5948
6227
|
id: 1,
|
|
5949
6228
|
payload: {
|
|
@@ -6000,18 +6279,24 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
6000
6279
|
],
|
|
6001
6280
|
});
|
|
6002
6281
|
|
|
6003
|
-
expect(method.
|
|
6282
|
+
expect((method as any).enterProtocolV2BootloaderMode).toHaveBeenCalledTimes(1);
|
|
6283
|
+
expect(method.postTipMessage).toHaveBeenCalledTimes(2);
|
|
6004
6284
|
expect(method.postTipMessage).toHaveBeenNthCalledWith(1, 'StartTransferData');
|
|
6005
|
-
expect(method.postTipMessage).toHaveBeenNthCalledWith(2, '
|
|
6006
|
-
expect(method.postTipMessage).toHaveBeenNthCalledWith(3, 'ConfirmOnDevice');
|
|
6285
|
+
expect(method.postTipMessage).toHaveBeenNthCalledWith(2, 'ConfirmOnDevice');
|
|
6007
6286
|
expect((method as any).protocolV2SourceUpdateProcess).toHaveBeenNthCalledWith(
|
|
6008
6287
|
1,
|
|
6009
|
-
expect.objectContaining({ processedSize: 0, totalSize:
|
|
6288
|
+
expect.objectContaining({ processedSize: 0, totalSize: 3 })
|
|
6010
6289
|
);
|
|
6011
6290
|
expect((method as any).protocolV2SourceUpdateProcess).toHaveBeenNthCalledWith(
|
|
6012
6291
|
2,
|
|
6013
|
-
expect.objectContaining({ processedSize:
|
|
6292
|
+
expect.objectContaining({ processedSize: 2, totalSize: 3 })
|
|
6014
6293
|
);
|
|
6294
|
+
expect(method.postProgressMessage).toHaveBeenCalledTimes(1);
|
|
6295
|
+
expect(method.postProgressMessage).toHaveBeenCalledWith(100, 'transferData');
|
|
6296
|
+
expect((method as any).protocolV2StartFirmwareUpdate).toHaveBeenCalledTimes(1);
|
|
6297
|
+
expect((method as any).protocolV2StartFirmwareUpdate).toHaveBeenCalledWith({
|
|
6298
|
+
targets: [{ target_id: 4, path: 'vol0:/application_p1.bin' }],
|
|
6299
|
+
});
|
|
6015
6300
|
expect((method as any).isProtocolV2ResourceBundleUpToDate).toHaveBeenCalledWith(
|
|
6016
6301
|
expect.objectContaining({
|
|
6017
6302
|
version: [1, 2, 3],
|
|
@@ -6021,50 +6306,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
6021
6306
|
);
|
|
6022
6307
|
});
|
|
6023
6308
|
|
|
6024
|
-
test('
|
|
6025
|
-
const method = new FirmwareUpdateV4({
|
|
6026
|
-
id: 1,
|
|
6027
|
-
payload: { method: 'firmwareUpdateV4' },
|
|
6028
|
-
});
|
|
6029
|
-
const phases = (method as any).buildProtocolV2ExecutionPhases({
|
|
6030
|
-
installSources: [{ kind: 'bootloader' }, { kind: 'component' }],
|
|
6031
|
-
resourceSources: [{ kind: 'resource' }],
|
|
6032
|
-
});
|
|
6033
|
-
|
|
6034
|
-
expect(phases.map((phase: { kind: string }) => phase.kind)).toEqual([
|
|
6035
|
-
'bootloader-install',
|
|
6036
|
-
'bootloader-verify',
|
|
6037
|
-
'resource-sync',
|
|
6038
|
-
'component-install',
|
|
6039
|
-
'final-verify',
|
|
6040
|
-
]);
|
|
6041
|
-
});
|
|
6042
|
-
|
|
6043
|
-
test('stages the mounted boot resource before any firmware install phase', () => {
|
|
6044
|
-
const method = new FirmwareUpdateV4({
|
|
6045
|
-
id: 1,
|
|
6046
|
-
payload: { method: 'firmwareUpdateV4' },
|
|
6047
|
-
});
|
|
6048
|
-
const bootResource = {
|
|
6049
|
-
devicePath: 'vol0:/loaders/bootloader/boot_resource.okpkg',
|
|
6050
|
-
};
|
|
6051
|
-
const phases = (method as any).buildProtocolV2ExecutionPhases({
|
|
6052
|
-
installSources: [{ kind: 'bootloader' }, { kind: 'component' }],
|
|
6053
|
-
resourceSources: [bootResource, { devicePath: 'vol0:/resource/images/images.okpkg' }],
|
|
6054
|
-
});
|
|
6055
|
-
|
|
6056
|
-
expect(phases.map((phase: { kind: string }) => phase.kind)).toEqual([
|
|
6057
|
-
'resource-sync',
|
|
6058
|
-
'bootloader-install',
|
|
6059
|
-
'bootloader-verify',
|
|
6060
|
-
'resource-sync',
|
|
6061
|
-
'component-install',
|
|
6062
|
-
'final-verify',
|
|
6063
|
-
]);
|
|
6064
|
-
expect(phases[0].resourceSources).toEqual([bootResource]);
|
|
6065
|
-
});
|
|
6066
|
-
|
|
6067
|
-
test('removes stale boot resource staging before a component-only reboot', async () => {
|
|
6309
|
+
test('removes stale boot resource staging before the combined transfer', async () => {
|
|
6068
6310
|
const method = new FirmwareUpdateV4({
|
|
6069
6311
|
id: 1,
|
|
6070
6312
|
payload: { method: 'firmwareUpdateV4' },
|
|
@@ -6091,18 +6333,18 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
6091
6333
|
events.push('transfer-component');
|
|
6092
6334
|
return Promise.resolve();
|
|
6093
6335
|
});
|
|
6094
|
-
(method as any).
|
|
6095
|
-
events.push('
|
|
6096
|
-
return Promise.resolve();
|
|
6336
|
+
(method as any).completeProtocolV2FinalVerification = jest.fn().mockImplementation(() => {
|
|
6337
|
+
events.push('final-verify');
|
|
6338
|
+
return Promise.resolve({});
|
|
6097
6339
|
});
|
|
6098
|
-
(method as any).completeProtocolV2FinalVerification = jest.fn().mockResolvedValue({});
|
|
6099
6340
|
|
|
6100
6341
|
await (method as any).executeProtocolV2SourceUpdate({
|
|
6101
6342
|
installSources: [{ kind: 'firmware' }],
|
|
6102
6343
|
resourceSources: [],
|
|
6103
6344
|
});
|
|
6104
6345
|
|
|
6105
|
-
expect(
|
|
6346
|
+
expect((method as any).enterProtocolV2BootloaderMode).toHaveBeenCalledTimes(1);
|
|
6347
|
+
expect(events).toEqual(['delete-stale-staging', 'transfer-component', 'final-verify']);
|
|
6106
6348
|
expect(typedCall).toHaveBeenNthCalledWith(2, 'FilesystemFileDelete', 'Success', {
|
|
6107
6349
|
path: 'vol0:/loaders/bootloader/boot_resource.okpkg.staging',
|
|
6108
6350
|
});
|
|
@@ -7449,6 +7691,9 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
7449
7691
|
method.postProgressMessage = jest.fn();
|
|
7450
7692
|
(method as any).protocolV2SourceUpdateProcess = jest.fn().mockResolvedValue(3);
|
|
7451
7693
|
(method as any).enterProtocolV2BootloaderMode = jest.fn().mockResolvedValue(undefined);
|
|
7694
|
+
(method as any).ensureProtocolV2BootResourceStagingIsEmpty = jest
|
|
7695
|
+
.fn()
|
|
7696
|
+
.mockResolvedValue(undefined);
|
|
7452
7697
|
(method as any).completeProtocolV2FinalVerification = jest.fn().mockResolvedValue({});
|
|
7453
7698
|
(method as any).verifyProtocolV2StagedFile = jest.fn().mockResolvedValue(undefined);
|
|
7454
7699
|
|
|
@@ -7575,6 +7820,86 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
7575
7820
|
});
|
|
7576
7821
|
});
|
|
7577
7822
|
|
|
7823
|
+
test('sends one monotonic device transfer progress range across multiple files', async () => {
|
|
7824
|
+
const method = new FirmwareUpdateV4({
|
|
7825
|
+
id: 1,
|
|
7826
|
+
payload: {
|
|
7827
|
+
method: 'firmwareUpdateV4',
|
|
7828
|
+
},
|
|
7829
|
+
});
|
|
7830
|
+
const typedCall = jest.fn(
|
|
7831
|
+
(
|
|
7832
|
+
_name: string,
|
|
7833
|
+
_resType: string,
|
|
7834
|
+
params: { file: { offset: number; data: { byteLength: number } } }
|
|
7835
|
+
) =>
|
|
7836
|
+
Promise.resolve({
|
|
7837
|
+
type: 'FilesystemFile',
|
|
7838
|
+
message: {
|
|
7839
|
+
processed_byte: params.file.offset + params.file.data.byteLength,
|
|
7840
|
+
},
|
|
7841
|
+
})
|
|
7842
|
+
);
|
|
7843
|
+
|
|
7844
|
+
(method as any).device = stubDevice({
|
|
7845
|
+
getCommands: () => ({ typedCall }),
|
|
7846
|
+
getCurrentDeviceType: () => 'pro2',
|
|
7847
|
+
toMessageObject: () => ({ connectId: 'firmware-device' }),
|
|
7848
|
+
});
|
|
7849
|
+
method.postMessage = jest.fn();
|
|
7850
|
+
method.postTipMessage = jest.fn();
|
|
7851
|
+
method.postProgressMessage = jest.fn();
|
|
7852
|
+
(method as any).isProtocolV2ResourceBundleUpToDate = jest.fn().mockResolvedValue(false);
|
|
7853
|
+
(method as any).verifyProtocolV2StagedFile = jest.fn().mockResolvedValue(undefined);
|
|
7854
|
+
(method as any).protocolV2StartFirmwareUpdate = jest.fn().mockResolvedValue(undefined);
|
|
7855
|
+
(method as any).waitForProtocolV2FirmwareUpdateComplete = jest
|
|
7856
|
+
.fn()
|
|
7857
|
+
.mockResolvedValue(undefined);
|
|
7858
|
+
|
|
7859
|
+
const resourceSource = await openFirmwareByteSource({
|
|
7860
|
+
binary: new Uint8Array(4097).buffer,
|
|
7861
|
+
});
|
|
7862
|
+
const firmwareSource = await openFirmwareByteSource({
|
|
7863
|
+
binary: new Uint8Array(4097).buffer,
|
|
7864
|
+
});
|
|
7865
|
+
try {
|
|
7866
|
+
await (method as any).executeProtocolV2TransferPhase({
|
|
7867
|
+
resourceSources: [
|
|
7868
|
+
{
|
|
7869
|
+
name: 'images.okpkg',
|
|
7870
|
+
source: resourceSource,
|
|
7871
|
+
devicePath: 'vol0:/resource/images/images.okpkg',
|
|
7872
|
+
},
|
|
7873
|
+
],
|
|
7874
|
+
installSources: [
|
|
7875
|
+
{
|
|
7876
|
+
fileName: 'application_p1.bin',
|
|
7877
|
+
source: firmwareSource,
|
|
7878
|
+
targetId: 4,
|
|
7879
|
+
kind: 'firmware',
|
|
7880
|
+
},
|
|
7881
|
+
],
|
|
7882
|
+
});
|
|
7883
|
+
} finally {
|
|
7884
|
+
await resourceSource?.close();
|
|
7885
|
+
await firmwareSource?.close();
|
|
7886
|
+
}
|
|
7887
|
+
|
|
7888
|
+
const writePayloads = typedCall.mock.calls.map(call => call[2]);
|
|
7889
|
+
const deviceProgress = writePayloads.map(payload => payload.ui_percentage);
|
|
7890
|
+
expect(deviceProgress).toEqual([0, 50, 99, 100]);
|
|
7891
|
+
expect(deviceProgress.filter(progress => progress === 0)).toHaveLength(1);
|
|
7892
|
+
expect(deviceProgress.filter(progress => progress === 100)).toHaveLength(1);
|
|
7893
|
+
expect(method.postTipMessage).toHaveBeenCalledTimes(2);
|
|
7894
|
+
expect(method.postTipMessage).toHaveBeenNthCalledWith(1, 'StartTransferData');
|
|
7895
|
+
expect(method.postTipMessage).toHaveBeenNthCalledWith(2, 'ConfirmOnDevice');
|
|
7896
|
+
expect(
|
|
7897
|
+
(method.postProgressMessage as jest.Mock).mock.calls.filter(
|
|
7898
|
+
([progress, progressType]) => progress === 100 && progressType === 'transferData'
|
|
7899
|
+
)
|
|
7900
|
+
).toHaveLength(1);
|
|
7901
|
+
});
|
|
7902
|
+
|
|
7578
7903
|
// TODO(#850/#855): PR #855 added resume-on-retry and per-chunk retry on the
|
|
7579
7904
|
// writeProtocolV2File path. PR #850 replaced that path with FirmwareByteSource
|
|
7580
7905
|
// streaming (protocolV2SourceUpdateProcess), which restarts a failed transfer from
|