@onekeyfe/hd-core 1.2.0-alpha.77 → 1.2.0-alpha.79
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__/check-all-firmware-release-protocol-v2.test.ts +12 -71
- package/__tests__/device-state-mapper.test.ts +16 -1
- package/__tests__/device-state-projector.test.ts +20 -0
- package/__tests__/device-state-store.test.ts +27 -0
- package/__tests__/homescreen.test.ts +17 -0
- package/__tests__/method-protocol-support.test.ts +13 -1
- package/__tests__/protocol-v2-resources.test.ts +113 -222
- package/__tests__/protocol-v2.test.ts +110 -380
- package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV4.d.ts +0 -6
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/UploadPortfolio.d.ts.map +1 -1
- package/dist/api/utils.d.ts +2 -0
- package/dist/api/utils.d.ts.map +1 -1
- package/dist/data-manager/DataManager.d.ts +1 -2
- package/dist/data-manager/DataManager.d.ts.map +1 -1
- package/dist/device/DeviceStateMapper.d.ts.map +1 -1
- package/dist/device/DeviceStateProjector.d.ts.map +1 -1
- package/dist/device/DeviceStateStore.d.ts.map +1 -1
- package/dist/index.d.ts +96 -33
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +515 -597
- package/dist/inject.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/resources.d.ts +31 -28
- package/dist/protocols/protocol-v2/resources.d.ts.map +1 -1
- package/dist/types/api/checkAllFirmwareRelease.d.ts +1 -0
- package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
- package/dist/types/api/export.d.ts +1 -0
- package/dist/types/api/export.d.ts.map +1 -1
- package/dist/types/api/index.d.ts +2 -0
- package/dist/types/api/index.d.ts.map +1 -1
- package/dist/types/api/protocolV2ResourceManifest.d.ts +17 -0
- package/dist/types/api/protocolV2ResourceManifest.d.ts.map +1 -0
- package/dist/types/device.d.ts +8 -0
- package/dist/types/device.d.ts.map +1 -1
- package/dist/types/settings.d.ts +30 -21
- package/dist/types/settings.d.ts.map +1 -1
- package/dist/utils/homescreen.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/CheckAllFirmwareRelease.ts +5 -34
- package/src/api/FirmwareUpdateV4.ts +48 -220
- package/src/api/UploadPortfolio.ts +18 -0
- package/src/api/utils.ts +25 -0
- package/src/data-manager/DataManager.ts +17 -6
- package/src/device/DeviceStateMapper.ts +42 -0
- package/src/device/DeviceStateProjector.ts +58 -0
- package/src/device/DeviceStateStore.ts +31 -0
- package/src/index.ts +8 -0
- package/src/inject.ts +2 -0
- package/src/protocols/protocol-v2/resources.ts +193 -324
- package/src/types/api/checkAllFirmwareRelease.ts +1 -0
- package/src/types/api/export.ts +4 -0
- package/src/types/api/index.ts +2 -0
- package/src/types/api/protocolV2ResourceManifest.ts +19 -0
- package/src/types/device.ts +16 -0
- package/src/types/settings.ts +30 -36
- package/src/utils/homescreen.ts +5 -1
|
@@ -4,20 +4,13 @@ import { HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
|
4
4
|
|
|
5
5
|
import { DataManager } from '../src/data-manager';
|
|
6
6
|
import {
|
|
7
|
-
PROTOCOL_V2_RESOURCE_DEVICE_PATHS,
|
|
8
|
-
PROTOCOL_V2_RESOURCE_TYPES,
|
|
9
|
-
buildProtocolV2ResourceUpdatePlan,
|
|
10
7
|
isProtocolV2ResourceFileValid,
|
|
8
|
+
parseProtocolV2ResourceManifest,
|
|
11
9
|
parseProtocolV2Resources,
|
|
12
|
-
|
|
10
|
+
prepareProtocolV2ResourceFiles,
|
|
13
11
|
} from '../src/protocols/protocol-v2/resources';
|
|
14
12
|
|
|
15
|
-
import type {
|
|
16
|
-
ConnectSettings,
|
|
17
|
-
IProtocolV2BootResources,
|
|
18
|
-
IProtocolV2Resource,
|
|
19
|
-
RemoteConfigResponse,
|
|
20
|
-
} from '../src/types';
|
|
13
|
+
import type { ConnectSettings, RemoteConfigResponse } from '../src/types';
|
|
21
14
|
|
|
22
15
|
jest.mock('axios');
|
|
23
16
|
jest.mock('../src/data/config', () => ({
|
|
@@ -28,45 +21,69 @@ jest.mock('../src/data/config', () => ({
|
|
|
28
21
|
const bytesToHex = (bytes: Uint8Array) =>
|
|
29
22
|
Array.from(bytes, byte => byte.toString(16).padStart(2, '0')).join('');
|
|
30
23
|
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
const createResourceHeader = (headerHash: string) => {
|
|
34
|
-
const header = new Uint8Array(PROTOCOL_V2_OKPP_HEADER_SIZE);
|
|
35
|
-
const view = new DataView(header.buffer);
|
|
36
|
-
'OKPP'.split('').forEach((char, index) => {
|
|
37
|
-
header[index] = char.charCodeAt(0);
|
|
38
|
-
});
|
|
39
|
-
'RESC'.split('').forEach((char, index) => {
|
|
40
|
-
header[0x08 + index] = char.charCodeAt(0);
|
|
41
|
-
});
|
|
42
|
-
view.setUint32(0x0c, header.byteLength, true);
|
|
43
|
-
for (let index = 0; index < headerHash.length / 2; index++) {
|
|
44
|
-
header[0x240 + index] = Number.parseInt(headerHash.slice(index * 2, index * 2 + 2), 16);
|
|
45
|
-
}
|
|
46
|
-
return header;
|
|
24
|
+
const resourceSource = {
|
|
25
|
+
manifestUrl: 'https://example.com/resource/manifest.json',
|
|
47
26
|
};
|
|
48
27
|
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
28
|
+
const manifestFiles = [
|
|
29
|
+
['bundles/firmware_logo-build.okpkg', 'firmware_logo.okpkg', 'vol0:/bundles/firmware_logo.okpkg'],
|
|
30
|
+
['bundles/font/noto-build.okpkg', 'noto.okpkg', 'vol0:/bundles/font/noto.okpkg'],
|
|
31
|
+
['bundles/font/roobert-build.okpkg', 'roobert.okpkg', 'vol0:/bundles/font/roobert.okpkg'],
|
|
32
|
+
[
|
|
33
|
+
'bundles/images/animation-build.okpkg',
|
|
34
|
+
'animation.okpkg',
|
|
35
|
+
'vol0:/bundles/images/animation.okpkg',
|
|
36
|
+
],
|
|
37
|
+
['bundles/images/images-build.okpkg', 'images.okpkg', 'vol0:/bundles/images/images.okpkg'],
|
|
38
|
+
[
|
|
39
|
+
'bundles/images/wallpaper-build.okpkg',
|
|
40
|
+
'wallpaper.okpkg',
|
|
41
|
+
'vol0:/bundles/images/wallpaper.okpkg',
|
|
42
|
+
],
|
|
43
|
+
[
|
|
44
|
+
'bundles/translations/translations-build.okpkg',
|
|
45
|
+
'translations.okpkg',
|
|
46
|
+
'vol0:/bundles/translations/translations.okpkg',
|
|
47
|
+
],
|
|
48
|
+
[
|
|
49
|
+
'loaders/bootloader/boot_resource-build.okpkg',
|
|
50
|
+
'boot_resource.okpkg',
|
|
51
|
+
'vol0:/loaders/bootloader/boot_resource.okpkg',
|
|
52
|
+
],
|
|
53
|
+
['loaders/rom/params-build.okpkg', 'params.okpkg', 'vol0:/loaders/rom/params.okpkg'],
|
|
54
|
+
].map(([archive_path, original_name, device_path], index) => {
|
|
55
|
+
const binary = new Uint8Array([index + 1]).buffer;
|
|
56
|
+
return {
|
|
57
|
+
archive_path,
|
|
58
|
+
original_name,
|
|
59
|
+
device_path,
|
|
60
|
+
size: 1,
|
|
61
|
+
sha256: bytesToHex(sha256(new Uint8Array(binary))),
|
|
62
|
+
signed: true,
|
|
63
|
+
sig_algo: device_path.startsWith('vol0:/bundles/') ? 'ed25519' : 'mldsa65',
|
|
64
|
+
payload_version: '1.0.0',
|
|
65
|
+
binary,
|
|
66
|
+
};
|
|
67
|
+
});
|
|
56
68
|
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
const resourceManifest = {
|
|
70
|
+
schema: 1,
|
|
71
|
+
artifact_name: 'pro2-resource-build',
|
|
72
|
+
release_name: 'resource-build',
|
|
73
|
+
variant: 'resource',
|
|
74
|
+
commit: 'a'.repeat(40),
|
|
75
|
+
short_sha: 'aaaaaaa',
|
|
76
|
+
timestamp_utc: '20260807_091424',
|
|
77
|
+
core_version: '1.0.0',
|
|
78
|
+
key_set: 'dev',
|
|
79
|
+
device_root: 'vol0:',
|
|
80
|
+
restore_mode: 'bootloader_update',
|
|
81
|
+
trees: [
|
|
82
|
+
{ path: 'bundles', device: 'vol0:/bundles' },
|
|
83
|
+
{ path: 'loaders/bootloader', device: 'vol0:/loaders/bootloader' },
|
|
84
|
+
{ path: 'loaders/rom', device: 'vol0:/loaders/rom' },
|
|
69
85
|
],
|
|
86
|
+
files: manifestFiles.map(({ binary: _binary, ...file }) => file),
|
|
70
87
|
};
|
|
71
88
|
|
|
72
89
|
const createSettings = (configFetcher: ConnectSettings['configFetcher']): ConnectSettings =>
|
|
@@ -85,7 +102,7 @@ const createRemoteConfig = (): RemoteConfigResponse =>
|
|
|
85
102
|
mini: { firmware: [], ble: [] },
|
|
86
103
|
touch: { firmware: [], ble: [] },
|
|
87
104
|
pro: { firmware: [], ble: [] },
|
|
88
|
-
pro2: { firmware: [], ble: [], resources: {
|
|
105
|
+
pro2: { firmware: [], ble: [], resources: { source: resourceSource } },
|
|
89
106
|
bridge: {},
|
|
90
107
|
} as unknown as RemoteConfigResponse);
|
|
91
108
|
|
|
@@ -95,186 +112,51 @@ describe('Pro2 resource configuration', () => {
|
|
|
95
112
|
DataManager.lastCheckTimestamp = 0;
|
|
96
113
|
});
|
|
97
114
|
|
|
98
|
-
test('accepts
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
boot: bootResources,
|
|
115
|
+
test('accepts the manifest source and the CI schema 1 file set', () => {
|
|
116
|
+
expect(parseProtocolV2Resources({ source: resourceSource })).toEqual({
|
|
117
|
+
source: resourceSource,
|
|
102
118
|
});
|
|
103
|
-
|
|
104
|
-
expect(parsed?.stable.map(item => item.type)).toEqual(PROTOCOL_V2_RESOURCE_TYPES);
|
|
105
|
-
expect(parsed?.boot).toEqual(bootResources);
|
|
106
|
-
expect(PROTOCOL_V2_RESOURCE_DEVICE_PATHS.translations).toBe(
|
|
107
|
-
'vol0:/bundles/translations/translations.okpkg'
|
|
108
|
-
);
|
|
109
|
-
expect(PROTOCOL_V2_RESOURCE_DEVICE_PATHS.firmware_logo).toBe(
|
|
110
|
-
'vol0:/bundles/firmware_logo.okpkg'
|
|
111
|
-
);
|
|
119
|
+
expect(parseProtocolV2ResourceManifest(resourceManifest).files).toHaveLength(9);
|
|
112
120
|
});
|
|
113
121
|
|
|
114
|
-
test('rejects
|
|
115
|
-
expect(() => parseProtocolV2Resources({
|
|
116
|
-
'7 unique resource types'
|
|
117
|
-
);
|
|
122
|
+
test('rejects missing source and malformed manifest paths', () => {
|
|
123
|
+
expect(() => parseProtocolV2Resources({})).toThrow('source is required');
|
|
118
124
|
expect(() =>
|
|
119
|
-
parseProtocolV2Resources({
|
|
120
|
-
).toThrow('
|
|
125
|
+
parseProtocolV2Resources({ source: { manifestUrl: 'http://example.com/manifest.json' } })
|
|
126
|
+
).toThrow('must use HTTPS');
|
|
121
127
|
expect(() =>
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
128
|
+
parseProtocolV2ResourceManifest({
|
|
129
|
+
...resourceManifest,
|
|
130
|
+
files: resourceManifest.files.map((file, index) =>
|
|
131
|
+
index === 0 ? { ...file, archive_path: '../outside.okpkg' } : file
|
|
125
132
|
),
|
|
126
133
|
})
|
|
127
|
-
).toThrow('
|
|
134
|
+
).toThrow('archive_path');
|
|
128
135
|
});
|
|
129
136
|
|
|
130
|
-
test('
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
)
|
|
137
|
+
test('verifies selected manifest files and preserves manifest device paths', () => {
|
|
138
|
+
const prepared = prepareProtocolV2ResourceFiles({
|
|
139
|
+
manifest: resourceManifest,
|
|
140
|
+
files: manifestFiles.map(file => ({
|
|
141
|
+
archivePath: file.archive_path,
|
|
142
|
+
binary: file.binary,
|
|
143
|
+
})),
|
|
144
|
+
targetsToUpdate: ['boot_resources'],
|
|
145
|
+
});
|
|
146
|
+
expect(prepared.map(file => file.devicePath)).toEqual([
|
|
147
|
+
'vol0:/loaders/bootloader/boot_resource.okpkg',
|
|
148
|
+
'vol0:/loaders/rom/params.okpkg',
|
|
149
|
+
]);
|
|
143
150
|
expect(() =>
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
},
|
|
151
|
+
prepareProtocolV2ResourceFiles({
|
|
152
|
+
manifest: resourceManifest,
|
|
153
|
+
files: manifestFiles.map((file, index) => ({
|
|
154
|
+
archivePath: file.archive_path,
|
|
155
|
+
binary: index === 0 ? new Uint8Array([0]).buffer : file.binary,
|
|
156
|
+
})),
|
|
157
|
+
targetsToUpdate: ['resource'],
|
|
150
158
|
})
|
|
151
|
-
).toThrow('
|
|
152
|
-
|
|
153
|
-
for (const devicePath of [
|
|
154
|
-
'vol0:/assets/loaders\\bootloader_crest.bin',
|
|
155
|
-
'vol0:/assets/loaders\\\\bootloader_crest.bin',
|
|
156
|
-
]) {
|
|
157
|
-
expect(() =>
|
|
158
|
-
parseProtocolV2Resources({
|
|
159
|
-
stable: resources,
|
|
160
|
-
boot: {
|
|
161
|
-
...bootResources,
|
|
162
|
-
files: [{ ...bootResources.files[0], devicePath }],
|
|
163
|
-
},
|
|
164
|
-
})
|
|
165
|
-
).toThrow('devicePath');
|
|
166
|
-
}
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
test('downloads nothing when all resource identities match', () => {
|
|
170
|
-
const inventory = resources.map(({ type, size, headerHash }) => ({ type, size, headerHash }));
|
|
171
|
-
|
|
172
|
-
expect(
|
|
173
|
-
buildProtocolV2ResourceUpdatePlan({ resources, inventory, mode: 'application' })
|
|
174
|
-
).toEqual({ status: 'valid', resources: [] });
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
test('builds inventory from existing filesystem calls without ResourceInventoryGet', async () => {
|
|
178
|
-
const installedResources = resources.map((resource, index) => ({
|
|
179
|
-
...resource,
|
|
180
|
-
size: PROTOCOL_V2_OKPP_HEADER_SIZE + index + 1,
|
|
181
|
-
}));
|
|
182
|
-
const resourceByPath = new Map(
|
|
183
|
-
installedResources.map(resource => [
|
|
184
|
-
PROTOCOL_V2_RESOURCE_DEVICE_PATHS[resource.type],
|
|
185
|
-
resource,
|
|
186
|
-
])
|
|
187
|
-
);
|
|
188
|
-
const typedCall = jest.fn(
|
|
189
|
-
(requestType: string, _responseType: string, payload: Record<string, any>) => {
|
|
190
|
-
if (requestType === 'ResourceInventoryGet') {
|
|
191
|
-
throw new Error('ResourceInventoryGet is unavailable on released firmware');
|
|
192
|
-
}
|
|
193
|
-
if (requestType === 'FilesystemPathInfoQuery') {
|
|
194
|
-
const resource = resourceByPath.get(payload.path);
|
|
195
|
-
return {
|
|
196
|
-
message: {
|
|
197
|
-
exist: Boolean(resource),
|
|
198
|
-
directory: false,
|
|
199
|
-
size: resource?.size ?? 0,
|
|
200
|
-
},
|
|
201
|
-
};
|
|
202
|
-
}
|
|
203
|
-
if (requestType === 'FilesystemFileRead') {
|
|
204
|
-
const resource = resourceByPath.get(payload.file.path);
|
|
205
|
-
if (!resource) throw new Error('missing resource');
|
|
206
|
-
const header = createResourceHeader(resource.headerHash);
|
|
207
|
-
const offset = Number(payload.file.offset);
|
|
208
|
-
const chunkLength = Number(payload.chunk_len);
|
|
209
|
-
return {
|
|
210
|
-
message: {
|
|
211
|
-
data: header.slice(offset, offset + chunkLength),
|
|
212
|
-
},
|
|
213
|
-
};
|
|
214
|
-
}
|
|
215
|
-
throw new Error(`Unexpected request: ${requestType}`);
|
|
216
|
-
}
|
|
217
|
-
);
|
|
218
|
-
|
|
219
|
-
await expect(
|
|
220
|
-
readProtocolV2ResourceInventory({
|
|
221
|
-
commands: { typedCall },
|
|
222
|
-
resources: installedResources,
|
|
223
|
-
chunkSize: 4000,
|
|
224
|
-
})
|
|
225
|
-
).resolves.toEqual(
|
|
226
|
-
installedResources.map(({ type, size, headerHash }) => ({ type, size, headerHash }))
|
|
227
|
-
);
|
|
228
|
-
expect(typedCall.mock.calls.some(call => call[0] === 'ResourceInventoryGet')).toBe(false);
|
|
229
|
-
expect(typedCall.mock.calls.filter(call => call[0] === 'FilesystemPathInfoQuery')).toHaveLength(
|
|
230
|
-
7
|
|
231
|
-
);
|
|
232
|
-
expect(typedCall.mock.calls.some(call => call[0] === 'FilesystemFileRead')).toBe(true);
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
test('selects only the changed or missing resource in application mode', () => {
|
|
236
|
-
const inventory = resources
|
|
237
|
-
.filter(resource => resource.type !== 'noto')
|
|
238
|
-
.map(({ type, size, headerHash }) => ({
|
|
239
|
-
type,
|
|
240
|
-
size: type === 'images' ? size + 1 : size,
|
|
241
|
-
headerHash,
|
|
242
|
-
}));
|
|
243
|
-
|
|
244
|
-
const result = buildProtocolV2ResourceUpdatePlan({
|
|
245
|
-
resources,
|
|
246
|
-
inventory,
|
|
247
|
-
mode: 'application',
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
expect(result.status).toBe('outdated');
|
|
251
|
-
expect(result.resources.map(resource => resource.type)).toEqual(['images', 'noto']);
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
test('reports unknown without an application inventory and selects all in recovery mode', () => {
|
|
255
|
-
expect(buildProtocolV2ResourceUpdatePlan({ resources, mode: 'application' })).toEqual({
|
|
256
|
-
status: 'unknown',
|
|
257
|
-
resources: [],
|
|
258
|
-
});
|
|
259
|
-
expect(
|
|
260
|
-
buildProtocolV2ResourceUpdatePlan({ resources, mode: 'bootloader-recovery' }).resources
|
|
261
|
-
).toHaveLength(7);
|
|
262
|
-
});
|
|
263
|
-
|
|
264
|
-
test('uses a filesystem inventory for incremental recovery mode updates', () => {
|
|
265
|
-
const inventory = resources.slice(1).map(({ type, size, headerHash }) => ({
|
|
266
|
-
type,
|
|
267
|
-
size,
|
|
268
|
-
headerHash,
|
|
269
|
-
}));
|
|
270
|
-
|
|
271
|
-
expect(
|
|
272
|
-
buildProtocolV2ResourceUpdatePlan({
|
|
273
|
-
resources,
|
|
274
|
-
inventory,
|
|
275
|
-
mode: 'bootloader-recovery',
|
|
276
|
-
}).resources.map(resource => resource.type)
|
|
277
|
-
).toEqual(['images']);
|
|
159
|
+
).toThrow('verification failed');
|
|
278
160
|
});
|
|
279
161
|
|
|
280
162
|
test('verifies both full file size and SHA-256 before transfer', () => {
|
|
@@ -289,7 +171,7 @@ describe('Pro2 resource configuration', () => {
|
|
|
289
171
|
);
|
|
290
172
|
});
|
|
291
173
|
|
|
292
|
-
test('applies a validated pre-release config and exposes
|
|
174
|
+
test('applies a validated pre-release config and exposes its manifest source', async () => {
|
|
293
175
|
const configFetcher = jest.fn().mockResolvedValue(createRemoteConfig());
|
|
294
176
|
|
|
295
177
|
await expect(DataManager.load(createSettings(configFetcher))).resolves.toBe(true);
|
|
@@ -297,24 +179,33 @@ describe('Pro2 resource configuration', () => {
|
|
|
297
179
|
expect(configFetcher).toHaveBeenCalledWith(
|
|
298
180
|
expect.stringMatching(/^https:\/\/data\.onekey\.so\/pre-config\.json\?noCache=/)
|
|
299
181
|
);
|
|
300
|
-
expect(DataManager.
|
|
301
|
-
expect(DataManager.
|
|
182
|
+
expect(DataManager.getProtocolV2ResourceSource()).toEqual(resourceSource);
|
|
183
|
+
expect(DataManager.lastCheckTimestamp).toBeGreaterThan(0);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
test('reuses the configuration fetched during SDK initialization for an immediate update', async () => {
|
|
187
|
+
const configFetcher = jest.fn().mockResolvedValue(createRemoteConfig());
|
|
188
|
+
const settings = createSettings(configFetcher);
|
|
189
|
+
|
|
190
|
+
await expect(DataManager.load(settings)).resolves.toBe(true);
|
|
191
|
+
await expect(DataManager.forceReloadData({ requireResources: true })).resolves.toBeUndefined();
|
|
192
|
+
|
|
193
|
+
expect(configFetcher).toHaveBeenCalledTimes(1);
|
|
302
194
|
});
|
|
303
195
|
|
|
304
196
|
test('keeps base SDK initialization available when remote Pro2 resources are invalid', async () => {
|
|
305
197
|
const remoteConfig = createRemoteConfig();
|
|
306
|
-
(remoteConfig.pro2 as { resources?: unknown }).resources = {
|
|
198
|
+
(remoteConfig.pro2 as { resources?: unknown }).resources = { source: {} };
|
|
307
199
|
const configFetcher = jest.fn().mockResolvedValue(remoteConfig);
|
|
308
200
|
|
|
309
201
|
await expect(DataManager.load(createSettings(configFetcher))).resolves.toBe(true);
|
|
310
202
|
|
|
311
|
-
expect(DataManager.
|
|
312
|
-
expect(DataManager.getProtocolV2BootResources()).toBeUndefined();
|
|
203
|
+
expect(DataManager.getProtocolV2ResourceSource()).toBeUndefined();
|
|
313
204
|
});
|
|
314
205
|
|
|
315
206
|
test('only blocks resource mutation when the refreshed Pro2 resources are invalid', async () => {
|
|
316
207
|
const remoteConfig = createRemoteConfig();
|
|
317
|
-
(remoteConfig.pro2 as { resources?: unknown }).resources = {
|
|
208
|
+
(remoteConfig.pro2 as { resources?: unknown }).resources = { source: {} };
|
|
318
209
|
const settings = createSettings(jest.fn().mockResolvedValue(remoteConfig));
|
|
319
210
|
DataManager.settings = settings;
|
|
320
211
|
|