@hot-updater/test-utils 1.0.0-rc.29 → 1.0.0-rc.31
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/dist/index.mjs +50 -229
- package/package.json +10 -10
package/dist/index.mjs
CHANGED
|
@@ -3198,6 +3198,27 @@ const READ_BUDGETS = [
|
|
|
3198
3198
|
},
|
|
3199
3199
|
check: (count) => expect(count).toBe(11)
|
|
3200
3200
|
}),
|
|
3201
|
+
budget({
|
|
3202
|
+
api: "countEventSeries: buckets in the window × shards, all used",
|
|
3203
|
+
read: ({ insights }) => insights.countEventSeries({
|
|
3204
|
+
filter: bundleEvents,
|
|
3205
|
+
timeRange: {
|
|
3206
|
+
start: T0,
|
|
3207
|
+
end: T0 + 3 * DAY
|
|
3208
|
+
},
|
|
3209
|
+
intervalMs: DAY
|
|
3210
|
+
}),
|
|
3211
|
+
adapter: reads(0, 0, 1, 25),
|
|
3212
|
+
engine: {
|
|
3213
|
+
calls: 1,
|
|
3214
|
+
rows: 6
|
|
3215
|
+
},
|
|
3216
|
+
check: (points) => expect(points.map(({ events }) => events)).toEqual([
|
|
3217
|
+
24,
|
|
3218
|
+
0,
|
|
3219
|
+
1
|
|
3220
|
+
])
|
|
3221
|
+
}),
|
|
3201
3222
|
budget({
|
|
3202
3223
|
api: "countLatestEvents: buckets in the window × shards, all used",
|
|
3203
3224
|
read: ({ insights }) => insights.countLatestEvents({
|
|
@@ -3243,26 +3264,7 @@ const READ_BUDGETS = [
|
|
|
3243
3264
|
calls: 1,
|
|
3244
3265
|
rows: 1
|
|
3245
3266
|
},
|
|
3246
|
-
check: ({ data }) => expect(data[0].metrics.
|
|
3247
|
-
}),
|
|
3248
|
-
budget({
|
|
3249
|
-
api: "release activity over a window: buckets × shards, all used",
|
|
3250
|
-
read: ({ insights }) => insights.getReleaseActivity({
|
|
3251
|
-
scope: {
|
|
3252
|
-
platform: "ios",
|
|
3253
|
-
channel: "production"
|
|
3254
|
-
},
|
|
3255
|
-
timeRange: {
|
|
3256
|
-
start: T0,
|
|
3257
|
-
end: T0 + 3 * DAY
|
|
3258
|
-
}
|
|
3259
|
-
}),
|
|
3260
|
-
adapter: reads(0, 0, 2, 24),
|
|
3261
|
-
engine: {
|
|
3262
|
-
calls: 2,
|
|
3263
|
-
rows: 4
|
|
3264
|
-
},
|
|
3265
|
-
check: ({ data }) => expect(data[0].metrics.launches).toBe(25)
|
|
3267
|
+
check: ({ data }) => expect(data[0].metrics.applies).toBe(25)
|
|
3266
3268
|
}),
|
|
3267
3269
|
budget({
|
|
3268
3270
|
api: "app usage: nonzero distribution and usage-sketch rows in the window, all used",
|
|
@@ -3285,27 +3287,6 @@ const READ_BUDGETS = [
|
|
|
3285
3287
|
installations: 24
|
|
3286
3288
|
}])
|
|
3287
3289
|
}),
|
|
3288
|
-
budget({
|
|
3289
|
-
api: "daily bundle share: only scoped aggregate shards in the requested days",
|
|
3290
|
-
read: ({ insights }) => insights.getDistributionHistory({
|
|
3291
|
-
channel: "production",
|
|
3292
|
-
platform: "ios",
|
|
3293
|
-
timeRange: {
|
|
3294
|
-
start: T0,
|
|
3295
|
-
end: T0 + 3 * DAY
|
|
3296
|
-
}
|
|
3297
|
-
}),
|
|
3298
|
-
adapter: reads(0, 0, 1, 15),
|
|
3299
|
-
engine: {
|
|
3300
|
-
calls: 1,
|
|
3301
|
-
rows: 2
|
|
3302
|
-
},
|
|
3303
|
-
check: ({ points }) => expect(points.map(({ bundles }) => bundles.reduce((n, row) => n + row.installations, 0))).toEqual([
|
|
3304
|
-
24,
|
|
3305
|
-
0,
|
|
3306
|
-
1
|
|
3307
|
-
])
|
|
3308
|
-
}),
|
|
3309
3290
|
budget({
|
|
3310
3291
|
api: "update failures of a release over a window: buckets × shards, all used",
|
|
3311
3292
|
read: ({ insights }) => insights.getUpdateFailures({
|
|
@@ -3409,10 +3390,10 @@ const READ_BUDGETS = [
|
|
|
3409
3390
|
install_id: "install-2",
|
|
3410
3391
|
received_at_ms: T0 + 3 * HOUR
|
|
3411
3392
|
})),
|
|
3412
|
-
adapter: reads(
|
|
3393
|
+
adapter: reads(4, 6, 0, 0),
|
|
3413
3394
|
engine: {
|
|
3414
|
-
calls:
|
|
3415
|
-
rows:
|
|
3395
|
+
calls: 2,
|
|
3396
|
+
rows: 1
|
|
3416
3397
|
},
|
|
3417
3398
|
writes: 1
|
|
3418
3399
|
})
|
|
@@ -4434,12 +4415,13 @@ const registerInsightsModelTests = (state) => {
|
|
|
4434
4415
|
beforeReceivedAtMs: 100
|
|
4435
4416
|
})).resolves.toBe(0);
|
|
4436
4417
|
});
|
|
4437
|
-
it("maintains idempotent release,
|
|
4418
|
+
it("maintains idempotent release, event series, usage, and latest-distribution summaries", async () => {
|
|
4438
4419
|
const model = state.getDatabase();
|
|
4439
4420
|
const releaseA = "00000000-0000-7000-8000-000000008001";
|
|
4440
4421
|
const releaseB = "00000000-0000-7000-8000-000000008002";
|
|
4422
|
+
const base = createBundleEventRowFixture("9801", 1e3);
|
|
4441
4423
|
const download = {
|
|
4442
|
-
...
|
|
4424
|
+
...base,
|
|
4443
4425
|
type: "UPDATE_DOWNLOADED",
|
|
4444
4426
|
install_id: "summary-install-a",
|
|
4445
4427
|
from_release_id: releaseA,
|
|
@@ -4484,57 +4466,39 @@ const registerInsightsModelTests = (state) => {
|
|
|
4484
4466
|
const lifetime = await model.getReleaseActivity({ releases });
|
|
4485
4467
|
expect(lifetime.data.map(({ metrics }) => metrics)).toEqual([{
|
|
4486
4468
|
downloads: 0,
|
|
4487
|
-
|
|
4469
|
+
applies: 0,
|
|
4488
4470
|
failedLaunches: 0
|
|
4489
4471
|
}, {
|
|
4490
4472
|
downloads: 1,
|
|
4491
|
-
|
|
4473
|
+
applies: 2,
|
|
4492
4474
|
failedLaunches: 1
|
|
4493
4475
|
}]);
|
|
4494
|
-
const
|
|
4495
|
-
|
|
4496
|
-
platform: "ios",
|
|
4497
|
-
channel: "production"
|
|
4498
|
-
},
|
|
4499
|
-
timeRange: {
|
|
4500
|
-
start: 0,
|
|
4501
|
-
end: 36e5
|
|
4502
|
-
}
|
|
4503
|
-
});
|
|
4504
|
-
expect(scope.data[0]?.metrics).toMatchObject({
|
|
4505
|
-
downloads: 1,
|
|
4506
|
-
launches: 3,
|
|
4507
|
-
failedLaunches: 1,
|
|
4508
|
-
uniqueUsers: 2
|
|
4509
|
-
});
|
|
4510
|
-
const hourly = await model.getReleaseActivity({
|
|
4511
|
-
releases: [releases[1]],
|
|
4476
|
+
const hourly = (filter) => model.countEventSeries({
|
|
4477
|
+
filter,
|
|
4512
4478
|
timeRange: {
|
|
4513
4479
|
start: 0,
|
|
4514
4480
|
end: 108e5
|
|
4515
4481
|
},
|
|
4516
4482
|
intervalMs: 36e5
|
|
4517
4483
|
});
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
}
|
|
4537
|
-
]);
|
|
4484
|
+
const points = (...counts) => counts.map((events, index) => ({
|
|
4485
|
+
startMs: index * 36e5,
|
|
4486
|
+
events
|
|
4487
|
+
}));
|
|
4488
|
+
const scope = {
|
|
4489
|
+
platform: "ios",
|
|
4490
|
+
channel: "production"
|
|
4491
|
+
};
|
|
4492
|
+
await expectInsightsIndex(() => hourly({
|
|
4493
|
+
...scope,
|
|
4494
|
+
type: "UPDATE_APPLIED",
|
|
4495
|
+
toBundleId: base.to_bundle_id
|
|
4496
|
+
}), points(2, 0, 0));
|
|
4497
|
+
await expectInsightsIndex(() => hourly({
|
|
4498
|
+
...scope,
|
|
4499
|
+
type: "RECOVERED",
|
|
4500
|
+
fromBundleId: base.from_bundle_id
|
|
4501
|
+
}), points(1, 0, 0));
|
|
4538
4502
|
const usage = await model.getAppUsage({
|
|
4539
4503
|
channel: "production",
|
|
4540
4504
|
platform: "all",
|
|
@@ -4561,109 +4525,6 @@ const registerInsightsModelTests = (state) => {
|
|
|
4561
4525
|
installations: 1
|
|
4562
4526
|
}]));
|
|
4563
4527
|
});
|
|
4564
|
-
it("keeps one daily running-bundle observation through updates, recovery, retries, and later days", async () => {
|
|
4565
|
-
const model = state.getDatabase();
|
|
4566
|
-
const day = 864e5;
|
|
4567
|
-
const start = Math.floor(Date.now() / day) * day - 3 * day;
|
|
4568
|
-
const a = "00000000-0000-7000-8000-000000008001";
|
|
4569
|
-
const b = "00000000-0000-7000-8000-000000008002";
|
|
4570
|
-
const download = {
|
|
4571
|
-
...createBundleEventRowFixture("9901", start + 100),
|
|
4572
|
-
type: "UPDATE_DOWNLOADED",
|
|
4573
|
-
install_id: "daily-one",
|
|
4574
|
-
from_release_id: a,
|
|
4575
|
-
to_release_id: b
|
|
4576
|
-
};
|
|
4577
|
-
const applied = {
|
|
4578
|
-
...download,
|
|
4579
|
-
type: "UPDATE_APPLIED",
|
|
4580
|
-
id: createBundleEventRowFixture("9902", 0).id,
|
|
4581
|
-
received_at_ms: start + 200
|
|
4582
|
-
};
|
|
4583
|
-
const read = () => model.getDistributionHistory({
|
|
4584
|
-
platform: "ios",
|
|
4585
|
-
channel: "production",
|
|
4586
|
-
timeRange: {
|
|
4587
|
-
start,
|
|
4588
|
-
end: start + 3 * day
|
|
4589
|
-
}
|
|
4590
|
-
});
|
|
4591
|
-
await record(model, download);
|
|
4592
|
-
await expectInsightsIndex(async () => (await read()).points[0].bundles, [{
|
|
4593
|
-
appVersion: "1.0.0",
|
|
4594
|
-
releaseId: a,
|
|
4595
|
-
bundleKind: "release",
|
|
4596
|
-
installations: 1
|
|
4597
|
-
}]);
|
|
4598
|
-
for (const row of [
|
|
4599
|
-
applied,
|
|
4600
|
-
applied,
|
|
4601
|
-
{
|
|
4602
|
-
...applied,
|
|
4603
|
-
id: createBundleEventRowFixture("9903", 0).id,
|
|
4604
|
-
install_id: "daily-two"
|
|
4605
|
-
}
|
|
4606
|
-
]) await record(model, row);
|
|
4607
|
-
const recovered = {
|
|
4608
|
-
...applied,
|
|
4609
|
-
id: createBundleEventRowFixture("9904", 0).id,
|
|
4610
|
-
type: "RECOVERED",
|
|
4611
|
-
from_release_id: b,
|
|
4612
|
-
to_release_id: a,
|
|
4613
|
-
received_at_ms: start + 300
|
|
4614
|
-
};
|
|
4615
|
-
await record(model, recovered);
|
|
4616
|
-
await record(model, {
|
|
4617
|
-
...applied,
|
|
4618
|
-
id: createBundleEventRowFixture("9905", 0).id,
|
|
4619
|
-
received_at_ms: start + day + 100
|
|
4620
|
-
});
|
|
4621
|
-
await record(model, {
|
|
4622
|
-
...applied,
|
|
4623
|
-
id: createBundleEventRowFixture("9906", 0).id,
|
|
4624
|
-
received_at_ms: start + 250
|
|
4625
|
-
});
|
|
4626
|
-
await record(model, {
|
|
4627
|
-
...applied,
|
|
4628
|
-
id: createBundleEventRowFixture("9907", 0).id,
|
|
4629
|
-
install_id: "other-scope",
|
|
4630
|
-
channel: "preview"
|
|
4631
|
-
});
|
|
4632
|
-
await expectInsightsIndex(async () => {
|
|
4633
|
-
return (await read()).points.map((point) => ({
|
|
4634
|
-
...point,
|
|
4635
|
-
bundles: [...point.bundles].sort((x, y) => (x.releaseId ?? "").localeCompare(y.releaseId ?? ""))
|
|
4636
|
-
}));
|
|
4637
|
-
}, [
|
|
4638
|
-
{
|
|
4639
|
-
startMs: start,
|
|
4640
|
-
bundles: [{
|
|
4641
|
-
appVersion: "1.0.0",
|
|
4642
|
-
releaseId: a,
|
|
4643
|
-
bundleKind: "release",
|
|
4644
|
-
installations: 1
|
|
4645
|
-
}, {
|
|
4646
|
-
appVersion: "1.0.0",
|
|
4647
|
-
releaseId: b,
|
|
4648
|
-
bundleKind: "release",
|
|
4649
|
-
installations: 1
|
|
4650
|
-
}]
|
|
4651
|
-
},
|
|
4652
|
-
{
|
|
4653
|
-
startMs: start + day,
|
|
4654
|
-
bundles: [{
|
|
4655
|
-
appVersion: "1.0.0",
|
|
4656
|
-
releaseId: b,
|
|
4657
|
-
bundleKind: "release",
|
|
4658
|
-
installations: 1
|
|
4659
|
-
}]
|
|
4660
|
-
},
|
|
4661
|
-
{
|
|
4662
|
-
startMs: start + 2 * day,
|
|
4663
|
-
bundles: []
|
|
4664
|
-
}
|
|
4665
|
-
]);
|
|
4666
|
-
});
|
|
4667
4528
|
it("pages insights events newest first with a stable cursor", async () => {
|
|
4668
4529
|
const model = state.getDatabase();
|
|
4669
4530
|
const first = createBundleEventRowFixture("701", 100);
|
|
@@ -4865,46 +4726,6 @@ const setupInsightsHttpTestSuite = (options) => {
|
|
|
4865
4726
|
return (await (await client.admin(`/overview?platform=ios&channel=${encodeURIComponent(channel)}&window=24h`)).json()).reportingInstallations.count;
|
|
4866
4727
|
}, 1);
|
|
4867
4728
|
});
|
|
4868
|
-
it("serves daily observed bundles through the authenticated admin API", async () => {
|
|
4869
|
-
const client = options.getClient();
|
|
4870
|
-
const channel = `share-${crypto.randomUUID()}`;
|
|
4871
|
-
const day = 864e5;
|
|
4872
|
-
const start = Math.floor(Date.now() / day) * day;
|
|
4873
|
-
const event = {
|
|
4874
|
-
appVersion: "1.0.0",
|
|
4875
|
-
channel,
|
|
4876
|
-
cohort: "default",
|
|
4877
|
-
fingerprintHash: null,
|
|
4878
|
-
fromBundleId: null,
|
|
4879
|
-
fromReleaseId: null,
|
|
4880
|
-
installId: `share-${crypto.randomUUID()}`,
|
|
4881
|
-
platform: "ios",
|
|
4882
|
-
toBundleId: "00000000-0000-0000-0000-000000000000",
|
|
4883
|
-
toReleaseId: null,
|
|
4884
|
-
type: "UNCHANGED",
|
|
4885
|
-
updateStrategy: null
|
|
4886
|
-
};
|
|
4887
|
-
const reported = await client.client("/events", jsonRequest$1("POST", event));
|
|
4888
|
-
expect(reported.status).toBe(204);
|
|
4889
|
-
await reported.text();
|
|
4890
|
-
const path = `/distribution-history?platform=ios&channel=${channel}&start=${start}&end=${start + day}`;
|
|
4891
|
-
await expectInsightsIndex(async () => {
|
|
4892
|
-
const response = await client.admin(path);
|
|
4893
|
-
expect(response.status).toBe(200);
|
|
4894
|
-
return (await response.json()).points;
|
|
4895
|
-
}, [{
|
|
4896
|
-
startMs: start,
|
|
4897
|
-
bundles: [{
|
|
4898
|
-
appVersion: "1.0.0",
|
|
4899
|
-
releaseId: null,
|
|
4900
|
-
bundleKind: "builtin",
|
|
4901
|
-
installations: 1
|
|
4902
|
-
}]
|
|
4903
|
-
}]);
|
|
4904
|
-
const invalid = await client.admin(`/distribution-history?platform=ios&channel=${channel}&start=${start}&end=${start + 40 * day}`);
|
|
4905
|
-
expect(invalid.status).toBe(400);
|
|
4906
|
-
await invalid.text();
|
|
4907
|
-
});
|
|
4908
4729
|
it.each([
|
|
4909
4730
|
{
|
|
4910
4731
|
type: "UNCHANGED",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hot-updater/test-utils",
|
|
3
|
-
"version": "1.0.0-rc.
|
|
3
|
+
"version": "1.0.0-rc.31",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Test utilities for Hot Updater packages",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -50,10 +50,10 @@
|
|
|
50
50
|
"mysql2": "*",
|
|
51
51
|
"pg": "*",
|
|
52
52
|
"vitest": "^4.0.0",
|
|
53
|
-
"@hot-updater/plugin-insights": "^1.0.0-rc.
|
|
54
|
-
"@hot-updater/server": "^1.0.0-rc.
|
|
55
|
-
"@hot-updater/protocol": "^1.0.0-rc.
|
|
56
|
-
"@hot-updater/plugin-core": "^1.0.0-rc.
|
|
53
|
+
"@hot-updater/plugin-insights": "^1.0.0-rc.33",
|
|
54
|
+
"@hot-updater/server": "^1.0.0-rc.33",
|
|
55
|
+
"@hot-updater/protocol": "^1.0.0-rc.29",
|
|
56
|
+
"@hot-updater/plugin-core": "^1.0.0-rc.29"
|
|
57
57
|
},
|
|
58
58
|
"peerDependenciesMeta": {
|
|
59
59
|
"@electric-sql/pglite": {
|
|
@@ -83,11 +83,11 @@
|
|
|
83
83
|
"typescript": "npm:@typescript/typescript6@6.0.2",
|
|
84
84
|
"vitest": "4.1.4",
|
|
85
85
|
"workspace-tools": "^0.41.7",
|
|
86
|
-
"@hot-updater/plugin-insights": "1.0.0-rc.
|
|
87
|
-
"@hot-updater/
|
|
88
|
-
"@hot-updater/
|
|
89
|
-
"@hot-updater/
|
|
90
|
-
"@hot-updater/
|
|
86
|
+
"@hot-updater/plugin-insights": "1.0.0-rc.33",
|
|
87
|
+
"@hot-updater/protocol": "1.0.0-rc.29",
|
|
88
|
+
"@hot-updater/plugin-core": "1.0.0-rc.29",
|
|
89
|
+
"@hot-updater/server": "1.0.0-rc.33",
|
|
90
|
+
"@hot-updater/js": "1.0.0-rc.27"
|
|
91
91
|
},
|
|
92
92
|
"inlinedDependencies": {
|
|
93
93
|
"@nodelib/fs.scandir": "2.1.5",
|