@fluidframework/id-compressor 2.0.0-rc.1.0.4 → 2.0.0-rc.2.0.0
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/{.eslintrc.js → .eslintrc.cjs} +5 -5
- package/{.mocharc.js → .mocharc.cjs} +1 -1
- package/CHANGELOG.md +8 -0
- package/{api-extractor-esm.json → api-extractor-cjs.json} +5 -1
- package/api-extractor-lint.json +1 -1
- package/api-extractor.json +1 -1
- package/api-report/id-compressor.api.md +5 -42
- package/dist/finalSpace.d.ts +2 -2
- package/dist/finalSpace.d.ts.map +1 -1
- package/dist/finalSpace.js +4 -4
- package/dist/finalSpace.js.map +1 -1
- package/dist/id-compressor-alpha.d.ts +117 -112
- package/dist/id-compressor-beta.d.ts +84 -77
- package/dist/id-compressor-public.d.ts +84 -77
- package/dist/id-compressor-untrimmed.d.ts +117 -112
- package/dist/idCompressor.d.ts +15 -19
- package/dist/idCompressor.d.ts.map +1 -1
- package/dist/idCompressor.js +107 -94
- package/dist/idCompressor.js.map +1 -1
- package/dist/identifiers.d.ts +1 -1
- package/dist/identifiers.d.ts.map +1 -1
- package/dist/identifiers.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -10
- package/dist/index.js.map +1 -1
- package/dist/package.json +3 -0
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/persistanceUtilities.d.ts +1 -1
- package/dist/persistanceUtilities.d.ts.map +1 -1
- package/dist/persistanceUtilities.js.map +1 -1
- package/dist/sessionSpaceNormalizer.d.ts +2 -2
- package/dist/sessionSpaceNormalizer.d.ts.map +1 -1
- package/dist/sessionSpaceNormalizer.js +4 -4
- package/dist/sessionSpaceNormalizer.js.map +1 -1
- package/dist/sessions.d.ts +2 -2
- package/dist/sessions.d.ts.map +1 -1
- package/dist/sessions.js +12 -12
- package/dist/sessions.js.map +1 -1
- package/dist/test/appendOnlySortedMap.perf.spec.d.ts +6 -0
- package/dist/test/appendOnlySortedMap.perf.spec.d.ts.map +1 -0
- package/dist/test/appendOnlySortedMap.perf.spec.js.map +1 -0
- package/dist/test/appendOnlySortedMap.spec.d.ts +6 -0
- package/dist/test/appendOnlySortedMap.spec.d.ts.map +1 -0
- package/dist/test/appendOnlySortedMap.spec.js.map +1 -0
- package/dist/test/idCompressor.perf.spec.d.ts +6 -0
- package/dist/test/idCompressor.perf.spec.d.ts.map +1 -0
- package/dist/test/idCompressor.perf.spec.js.map +1 -0
- package/dist/test/idCompressor.spec.d.ts +6 -0
- package/dist/test/idCompressor.spec.d.ts.map +1 -0
- package/dist/test/idCompressor.spec.js.map +1 -0
- package/dist/test/idCompressorTestUtilities.d.ts +245 -0
- package/dist/test/idCompressorTestUtilities.d.ts.map +1 -0
- package/dist/test/idCompressorTestUtilities.js +589 -0
- package/dist/test/idCompressorTestUtilities.js.map +1 -0
- package/dist/test/index.d.ts +9 -0
- package/dist/test/index.d.ts.map +1 -0
- package/dist/test/index.js +13 -0
- package/dist/test/index.js.map +1 -0
- package/dist/test/numericUuid.spec.d.ts +6 -0
- package/dist/test/numericUuid.spec.d.ts.map +1 -0
- package/dist/test/numericUuid.spec.js.map +1 -0
- package/dist/test/sessionSpaceNormalizer.spec.d.ts +6 -0
- package/dist/test/sessionSpaceNormalizer.spec.d.ts.map +1 -0
- package/dist/test/sessionSpaceNormalizer.spec.js.map +1 -0
- package/dist/test/snapshots/dirname.cjs +16 -0
- package/dist/test/snapshots/dirname.cjs.map +1 -0
- package/dist/test/snapshots/dirname.d.cts +6 -0
- package/dist/test/snapshots/dirname.d.cts.map +1 -0
- package/{lib/types/idCompressor.mjs → dist/test/snapshots/summary.spec.d.ts} +1 -1
- package/dist/test/snapshots/summary.spec.d.ts.map +1 -0
- package/dist/test/snapshots/summary.spec.js.map +1 -0
- package/dist/test/testCommon.d.ts +90 -0
- package/dist/test/testCommon.d.ts.map +1 -0
- package/dist/test/testCommon.js +90 -0
- package/dist/test/testCommon.js.map +1 -0
- package/dist/tsdoc-metadata.json +1 -1
- package/dist/types/idCompressor.d.ts +134 -67
- package/dist/types/idCompressor.d.ts.map +1 -1
- package/dist/types/idCompressor.js.map +1 -1
- package/dist/types/index.d.ts +3 -3
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/types/persisted-types/0.0.1.d.ts +1 -1
- package/dist/types/persisted-types/0.0.1.d.ts.map +1 -1
- package/dist/types/persisted-types/0.0.1.js.map +1 -1
- package/dist/types/persisted-types/index.d.ts +1 -1
- package/dist/types/persisted-types/index.d.ts.map +1 -1
- package/dist/types/persisted-types/index.js.map +1 -1
- package/dist/utilities.d.ts +2 -2
- package/dist/utilities.d.ts.map +1 -1
- package/dist/utilities.js.map +1 -1
- package/lib/{appendOnlySortedMap.d.mts → appendOnlySortedMap.d.ts} +1 -1
- package/lib/appendOnlySortedMap.d.ts.map +1 -0
- package/lib/{appendOnlySortedMap.mjs → appendOnlySortedMap.js} +3 -1
- package/lib/appendOnlySortedMap.js.map +1 -0
- package/lib/{finalSpace.d.mts → finalSpace.d.ts} +3 -3
- package/lib/finalSpace.d.ts.map +1 -0
- package/lib/{finalSpace.mjs → finalSpace.js} +2 -2
- package/lib/finalSpace.js.map +1 -0
- package/lib/{id-compressor-alpha.d.mts → id-compressor-alpha.d.ts} +117 -112
- package/lib/id-compressor-beta.d.ts +179 -0
- package/lib/id-compressor-public.d.ts +179 -0
- package/lib/{id-compressor-untrimmed.d.mts → id-compressor-untrimmed.d.ts} +117 -112
- package/lib/{idCompressor.d.mts → idCompressor.d.ts} +16 -20
- package/lib/idCompressor.d.ts.map +1 -0
- package/lib/{idCompressor.mjs → idCompressor.js} +54 -41
- package/lib/idCompressor.js.map +1 -0
- package/lib/{identifiers.d.mts → identifiers.d.ts} +2 -2
- package/lib/identifiers.d.ts.map +1 -0
- package/lib/{identifiers.mjs → identifiers.js} +1 -1
- package/lib/identifiers.js.map +1 -0
- package/lib/{index.d.mts → index.d.ts} +7 -4
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +10 -0
- package/lib/index.js.map +1 -0
- package/lib/{packageVersion.d.mts → packageVersion.d.ts} +2 -2
- package/lib/packageVersion.d.ts.map +1 -0
- package/lib/{packageVersion.mjs → packageVersion.js} +2 -2
- package/lib/packageVersion.js.map +1 -0
- package/lib/{persistanceUtilities.d.mts → persistanceUtilities.d.ts} +2 -2
- package/lib/persistanceUtilities.d.ts.map +1 -0
- package/lib/{persistanceUtilities.mjs → persistanceUtilities.js} +1 -1
- package/lib/persistanceUtilities.js.map +1 -0
- package/lib/{sessionSpaceNormalizer.d.mts → sessionSpaceNormalizer.d.ts} +3 -3
- package/lib/sessionSpaceNormalizer.d.ts.map +1 -0
- package/lib/{sessionSpaceNormalizer.mjs → sessionSpaceNormalizer.js} +3 -3
- package/lib/sessionSpaceNormalizer.js.map +1 -0
- package/lib/{sessions.d.mts → sessions.d.ts} +3 -3
- package/lib/sessions.d.ts.map +1 -0
- package/lib/{sessions.mjs → sessions.js} +2 -2
- package/lib/sessions.js.map +1 -0
- package/lib/test/appendOnlySortedMap.perf.spec.d.ts +6 -0
- package/lib/test/appendOnlySortedMap.perf.spec.d.ts.map +1 -0
- package/lib/test/appendOnlySortedMap.perf.spec.js +49 -0
- package/lib/test/appendOnlySortedMap.perf.spec.js.map +1 -0
- package/lib/test/appendOnlySortedMap.spec.d.ts +6 -0
- package/lib/test/appendOnlySortedMap.spec.d.ts.map +1 -0
- package/lib/test/appendOnlySortedMap.spec.js +166 -0
- package/lib/test/appendOnlySortedMap.spec.js.map +1 -0
- package/lib/test/idCompressor.perf.spec.d.ts +6 -0
- package/lib/test/idCompressor.perf.spec.d.ts.map +1 -0
- package/lib/test/idCompressor.perf.spec.js +281 -0
- package/lib/test/idCompressor.perf.spec.js.map +1 -0
- package/lib/test/idCompressor.spec.d.ts +6 -0
- package/lib/test/idCompressor.spec.d.ts.map +1 -0
- package/lib/test/idCompressor.spec.js +953 -0
- package/lib/test/idCompressor.spec.js.map +1 -0
- package/lib/test/idCompressorTestUtilities.d.ts +245 -0
- package/lib/test/idCompressorTestUtilities.d.ts.map +1 -0
- package/lib/test/idCompressorTestUtilities.js +576 -0
- package/lib/test/idCompressorTestUtilities.js.map +1 -0
- package/lib/test/index.d.ts +9 -0
- package/lib/test/index.d.ts.map +1 -0
- package/lib/test/index.js +9 -0
- package/lib/test/index.js.map +1 -0
- package/lib/test/numericUuid.spec.d.ts +6 -0
- package/lib/test/numericUuid.spec.d.ts.map +1 -0
- package/lib/test/numericUuid.spec.js +74 -0
- package/lib/test/numericUuid.spec.js.map +1 -0
- package/lib/test/sessionSpaceNormalizer.spec.d.ts +6 -0
- package/lib/test/sessionSpaceNormalizer.spec.d.ts.map +1 -0
- package/lib/test/sessionSpaceNormalizer.spec.js +43 -0
- package/lib/test/sessionSpaceNormalizer.spec.js.map +1 -0
- package/lib/test/snapshots/dirname.cjs +16 -0
- package/lib/test/snapshots/dirname.cjs.map +1 -0
- package/lib/test/snapshots/dirname.d.cts +6 -0
- package/lib/test/snapshots/dirname.d.cts.map +1 -0
- package/lib/test/snapshots/summary.spec.d.ts +6 -0
- package/lib/test/snapshots/summary.spec.d.ts.map +1 -0
- package/lib/test/snapshots/summary.spec.js +127 -0
- package/lib/test/snapshots/summary.spec.js.map +1 -0
- package/lib/test/testCommon.d.ts +90 -0
- package/lib/test/testCommon.d.ts.map +1 -0
- package/lib/test/testCommon.js +80 -0
- package/lib/test/testCommon.js.map +1 -0
- package/lib/types/{idCompressor.d.mts → idCompressor.d.ts} +135 -68
- package/lib/types/idCompressor.d.ts.map +1 -0
- package/lib/types/{identifiers.mjs → idCompressor.js} +1 -1
- package/lib/types/idCompressor.js.map +1 -0
- package/lib/types/{identifiers.d.mts → identifiers.d.ts} +1 -1
- package/lib/types/identifiers.d.ts.map +1 -0
- package/lib/types/identifiers.js +6 -0
- package/lib/types/identifiers.js.map +1 -0
- package/lib/types/{index.d.mts → index.d.ts} +4 -4
- package/lib/types/index.d.ts.map +1 -0
- package/lib/types/{persisted-types/0.0.1.mjs → index.js} +1 -1
- package/lib/types/index.js.map +1 -0
- package/lib/types/persisted-types/{0.0.1.d.mts → 0.0.1.d.ts} +2 -2
- package/lib/types/persisted-types/0.0.1.d.ts.map +1 -0
- package/lib/types/persisted-types/{index.mjs → 0.0.1.js} +1 -1
- package/lib/types/persisted-types/0.0.1.js.map +1 -0
- package/lib/types/persisted-types/{index.d.mts → index.d.ts} +2 -2
- package/lib/types/persisted-types/index.d.ts.map +1 -0
- package/lib/types/{index.mjs → persisted-types/index.js} +1 -1
- package/lib/types/persisted-types/index.js.map +1 -0
- package/lib/{utilities.d.mts → utilities.d.ts} +3 -3
- package/lib/utilities.d.ts.map +1 -0
- package/lib/{utilities.mjs → utilities.js} +2 -1
- package/lib/utilities.js.map +1 -0
- package/package.json +87 -21
- package/src/finalSpace.ts +2 -2
- package/src/idCompressor.ts +75 -59
- package/src/identifiers.ts +1 -1
- package/src/index.ts +3 -3
- package/src/packageVersion.ts +1 -1
- package/src/persistanceUtilities.ts +1 -1
- package/src/sessionSpaceNormalizer.ts +3 -3
- package/src/sessions.ts +3 -3
- package/src/test/idCompressorTestUtilities.ts +921 -0
- package/src/test/index.ts +10 -0
- package/src/test/snapshots/dirname.cts +13 -0
- package/src/test/snapshots/files/compressor-with-finalized-range-from-one-client +1 -0
- package/src/test/snapshots/files/compressor-with-finalized-range-from-one-client-client2 +1 -0
- package/src/test/snapshots/files/compressors-with-finalized-ranges-from-two-clients +1 -0
- package/src/test/snapshots/files/compressors-with-finalized-ranges-from-two-clients-client2 +1 -0
- package/src/test/snapshots/files/empty-compressor-summary +1 -0
- package/src/test/snapshots/files/expansion-semantics +1 -0
- package/src/test/snapshots/files/expansion-semantics-client2 +1 -0
- package/src/test/testCommon.ts +143 -0
- package/src/test/tsconfig.cjs.json +12 -0
- package/src/test/tsconfig.json +20 -0
- package/src/types/idCompressor.ts +147 -72
- package/src/types/index.ts +8 -3
- package/src/types/persisted-types/0.0.1.ts +1 -1
- package/src/types/persisted-types/index.ts +1 -1
- package/src/utilities.ts +2 -2
- package/tsconfig.cjs.json +7 -0
- package/tsconfig.json +2 -5
- package/lib/appendOnlySortedMap.d.mts.map +0 -1
- package/lib/appendOnlySortedMap.mjs.map +0 -1
- package/lib/finalSpace.d.mts.map +0 -1
- package/lib/finalSpace.mjs.map +0 -1
- package/lib/id-compressor-beta.d.mts +0 -172
- package/lib/id-compressor-public.d.mts +0 -172
- package/lib/idCompressor.d.mts.map +0 -1
- package/lib/idCompressor.mjs.map +0 -1
- package/lib/identifiers.d.mts.map +0 -1
- package/lib/identifiers.mjs.map +0 -1
- package/lib/index.d.mts.map +0 -1
- package/lib/index.mjs +0 -7
- package/lib/index.mjs.map +0 -1
- package/lib/packageVersion.d.mts.map +0 -1
- package/lib/packageVersion.mjs.map +0 -1
- package/lib/persistanceUtilities.d.mts.map +0 -1
- package/lib/persistanceUtilities.mjs.map +0 -1
- package/lib/sessionSpaceNormalizer.d.mts.map +0 -1
- package/lib/sessionSpaceNormalizer.mjs.map +0 -1
- package/lib/sessions.d.mts.map +0 -1
- package/lib/sessions.mjs.map +0 -1
- package/lib/types/idCompressor.d.mts.map +0 -1
- package/lib/types/idCompressor.mjs.map +0 -1
- package/lib/types/identifiers.d.mts.map +0 -1
- package/lib/types/identifiers.mjs.map +0 -1
- package/lib/types/index.d.mts.map +0 -1
- package/lib/types/index.mjs.map +0 -1
- package/lib/types/persisted-types/0.0.1.d.mts.map +0 -1
- package/lib/types/persisted-types/0.0.1.mjs.map +0 -1
- package/lib/types/persisted-types/index.d.mts.map +0 -1
- package/lib/types/persisted-types/index.mjs.map +0 -1
- package/lib/utilities.d.mts.map +0 -1
- package/lib/utilities.mjs.map +0 -1
|
@@ -0,0 +1,589 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*!
|
|
3
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
4
|
+
* Licensed under the MIT License.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.createAlwaysFinalizedIdCompressor = exports.generateCompressedIds = exports.performFuzzActions = exports.makeOpGenerator = exports.mergeArrayMaps = exports.expectSerializes = exports.roundtrip = exports.IdCompressorTestNetwork = exports.sessionIds = exports.buildHugeCompressor = exports.CompressorFactory = exports.DestinationClient = exports.OriginatingClient = exports.OutsideClient = exports.MetaClient = exports.Client = void 0;
|
|
8
|
+
const assert_1 = require("assert");
|
|
9
|
+
const stochastic_test_utils_1 = require("@fluid-private/stochastic-test-utils");
|
|
10
|
+
const index_js_1 = require("..//index.js");
|
|
11
|
+
const idCompressor_js_1 = require("../idCompressor.js");
|
|
12
|
+
const utilities_js_1 = require("../utilities.js");
|
|
13
|
+
const testCommon_js_1 = require("./testCommon.js");
|
|
14
|
+
/** Identifies a compressor in a network */
|
|
15
|
+
var Client;
|
|
16
|
+
(function (Client) {
|
|
17
|
+
Client["Client1"] = "Client1";
|
|
18
|
+
Client["Client2"] = "Client2";
|
|
19
|
+
Client["Client3"] = "Client3";
|
|
20
|
+
})(Client || (exports.Client = Client = {}));
|
|
21
|
+
/** Identifies categories of compressors */
|
|
22
|
+
var MetaClient;
|
|
23
|
+
(function (MetaClient) {
|
|
24
|
+
MetaClient["All"] = "All";
|
|
25
|
+
})(MetaClient || (exports.MetaClient = MetaClient = {}));
|
|
26
|
+
/** Identifies a compressor inside the network but outside the three specially tracked clients. */
|
|
27
|
+
var OutsideClient;
|
|
28
|
+
(function (OutsideClient) {
|
|
29
|
+
OutsideClient["Remote"] = "Remote";
|
|
30
|
+
})(OutsideClient || (exports.OutsideClient = OutsideClient = {}));
|
|
31
|
+
exports.OriginatingClient = { ...Client, ...OutsideClient };
|
|
32
|
+
exports.DestinationClient = { ...Client, ...MetaClient };
|
|
33
|
+
// eslint-disable-next-line @typescript-eslint/no-extraneous-class
|
|
34
|
+
class CompressorFactory {
|
|
35
|
+
/**
|
|
36
|
+
* Creates a new compressor with the supplied cluster capacity.
|
|
37
|
+
*/
|
|
38
|
+
static createCompressor(client, clusterCapacity = 5, logger) {
|
|
39
|
+
return CompressorFactory.createCompressorWithSession(exports.sessionIds.get(client), clusterCapacity, logger);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Creates a new compressor with the supplied cluster capacity.
|
|
43
|
+
*/
|
|
44
|
+
static createCompressorWithSession(sessionId, clusterCapacity = 5, logger) {
|
|
45
|
+
const compressor = (0, index_js_1.createIdCompressor)(sessionId, logger);
|
|
46
|
+
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
47
|
+
compressor["nextRequestedClusterSize"] = clusterCapacity;
|
|
48
|
+
return compressor;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
exports.CompressorFactory = CompressorFactory;
|
|
52
|
+
/**
|
|
53
|
+
* Utility for building a huge compressor.
|
|
54
|
+
* Build via the compressor factory.
|
|
55
|
+
*/
|
|
56
|
+
function buildHugeCompressor(numSessions = 10000, capacity = 10, numClustersPerSession = 3) {
|
|
57
|
+
const compressor = CompressorFactory.createCompressorWithSession((0, utilities_js_1.createSessionId)(), capacity);
|
|
58
|
+
const sessions = [];
|
|
59
|
+
for (let i = 0; i < numSessions; i++) {
|
|
60
|
+
sessions.push((0, utilities_js_1.createSessionId)());
|
|
61
|
+
}
|
|
62
|
+
for (let i = 0; i < numSessions * numClustersPerSession; i++) {
|
|
63
|
+
const sessionId = sessions[i % numSessions];
|
|
64
|
+
if (Math.random() > 0.1) {
|
|
65
|
+
for (let j = 0; j < Math.round(capacity / 2); j++) {
|
|
66
|
+
compressor.generateCompressedId();
|
|
67
|
+
}
|
|
68
|
+
compressor.finalizeCreationRange(compressor.takeNextCreationRange());
|
|
69
|
+
}
|
|
70
|
+
compressor.finalizeCreationRange({
|
|
71
|
+
sessionId,
|
|
72
|
+
ids: {
|
|
73
|
+
firstGenCount: Math.floor(i / numSessions) * capacity + 1,
|
|
74
|
+
count: capacity,
|
|
75
|
+
requestedClusterSize: capacity,
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
return compressor;
|
|
80
|
+
}
|
|
81
|
+
exports.buildHugeCompressor = buildHugeCompressor;
|
|
82
|
+
function makeSessionIds() {
|
|
83
|
+
const stableIds = new Map();
|
|
84
|
+
const clients = Object.values(Client);
|
|
85
|
+
for (let i = 0; i < clients.length; i++) {
|
|
86
|
+
// Place session uuids roughly in the middle of uuid space to increase odds of encountering interesting
|
|
87
|
+
// orderings in sorted collections
|
|
88
|
+
const sessionId = (0, utilities_js_1.assertIsSessionId)(`88888888-8888-4888-b${i}88-888888888888`);
|
|
89
|
+
stableIds.set(clients[i], sessionId);
|
|
90
|
+
}
|
|
91
|
+
return stableIds;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* An array of session ID strings corresponding to all non-local `Client` entries.
|
|
95
|
+
*/
|
|
96
|
+
exports.sessionIds = makeSessionIds();
|
|
97
|
+
/**
|
|
98
|
+
* Simulates a network of ID compressors.
|
|
99
|
+
* Not suitable for performance testing.
|
|
100
|
+
*/
|
|
101
|
+
class IdCompressorTestNetwork {
|
|
102
|
+
constructor(initialClusterSize = 5) {
|
|
103
|
+
this.initialClusterSize = initialClusterSize;
|
|
104
|
+
/** The log of operations seen by the server so far. Append-only. */
|
|
105
|
+
this.serverOperations = [];
|
|
106
|
+
const compressors = new Map();
|
|
107
|
+
const clientProgress = new Map();
|
|
108
|
+
const clientIds = new Map();
|
|
109
|
+
const clientSequencedIds = new Map();
|
|
110
|
+
for (const client of Object.values(Client)) {
|
|
111
|
+
const compressor = CompressorFactory.createCompressor(client, initialClusterSize);
|
|
112
|
+
compressors.set(client, compressor);
|
|
113
|
+
clientProgress.set(client, 0);
|
|
114
|
+
clientIds.set(client, []);
|
|
115
|
+
clientSequencedIds.set(client, []);
|
|
116
|
+
}
|
|
117
|
+
this.compressors = compressors;
|
|
118
|
+
this.clientProgress = clientProgress;
|
|
119
|
+
this.idLogs = clientIds;
|
|
120
|
+
this.sequencedIdLogs = clientSequencedIds;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Returns the number of undelivered operations for the given client that are in flight in the network.
|
|
124
|
+
*/
|
|
125
|
+
getPendingOperations(destination) {
|
|
126
|
+
return this.serverOperations.length - this.clientProgress.get(destination);
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Returns an immutable handle to a compressor in the network.
|
|
130
|
+
*/
|
|
131
|
+
getCompressor(client) {
|
|
132
|
+
const compressors = this.compressors;
|
|
133
|
+
const handler = {
|
|
134
|
+
get(_, property) {
|
|
135
|
+
return compressors.get(client)[property];
|
|
136
|
+
},
|
|
137
|
+
set(_, property, value) {
|
|
138
|
+
compressors.get(client)[property] = value;
|
|
139
|
+
return true;
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
return new Proxy({}, handler);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Returns a mutable handle to a compressor in the network. Use of mutation methods will break the network invariants and
|
|
146
|
+
* should only be used if the network will not be used again.
|
|
147
|
+
*/
|
|
148
|
+
getCompressorUnsafe(client) {
|
|
149
|
+
return this.getCompressor(client);
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Returns a mutable handle to a compressor in the network. Use of mutation methods will break the network invariants and
|
|
153
|
+
* should only be used if the network will not be used again. Additionally, the returned compressor will be invalidated/unusable
|
|
154
|
+
* if any network operations cause it to be regenerated (serialization/deserialization, etc.).
|
|
155
|
+
*/
|
|
156
|
+
getCompressorUnsafeNoProxy(client) {
|
|
157
|
+
return this.compressors.get(client);
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Returns data for all IDs created and received by this client, including ack's of their own (i.e. their own IDs will appear twice)
|
|
161
|
+
*/
|
|
162
|
+
getIdLog(client) {
|
|
163
|
+
return this.idLogs.get(client);
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Returns data for all IDs received by this client, including ack's of their own.
|
|
167
|
+
*/
|
|
168
|
+
getSequencedIdLog(client) {
|
|
169
|
+
return this.sequencedIdLogs.get(client);
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Get all compressors for the given destination
|
|
173
|
+
*/
|
|
174
|
+
getTargetCompressors(clientTo) {
|
|
175
|
+
return clientTo === MetaClient.All
|
|
176
|
+
? [...this.compressors.entries()]
|
|
177
|
+
: [[clientTo, this.getCompressor(clientTo)]];
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Changes the capacity request amount for a client. It will take effect immediately.
|
|
181
|
+
*/
|
|
182
|
+
changeCapacity(client, newClusterCapacity) {
|
|
183
|
+
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
184
|
+
this.compressors.get(client)["nextRequestedClusterSize"] = newClusterCapacity;
|
|
185
|
+
}
|
|
186
|
+
addNewId(client, id, originatingClient, sessionIdFrom, isSequenced) {
|
|
187
|
+
const idData = {
|
|
188
|
+
id,
|
|
189
|
+
originatingClient,
|
|
190
|
+
sessionId: sessionIdFrom,
|
|
191
|
+
isSequenced,
|
|
192
|
+
};
|
|
193
|
+
const clientIds = this.idLogs.get(client);
|
|
194
|
+
clientIds.push(idData);
|
|
195
|
+
if (isSequenced) {
|
|
196
|
+
const sequencedIds = this.sequencedIdLogs.get(client);
|
|
197
|
+
sequencedIds.push(idData);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Allocates a new range of local IDs and enqueues them for future delivery via a `testIdDelivery` action.
|
|
202
|
+
* Calls to this method determine the total order of delivery, regardless of when `deliverOperations` is called.
|
|
203
|
+
*/
|
|
204
|
+
allocateAndSendIds(clientFrom, numIds) {
|
|
205
|
+
return this.allocateAndSendIdsFromRemoteClient(clientFrom, exports.sessionIds.get(clientFrom), numIds);
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Same contract as `allocateAndSendIds`, but the originating client will be a client with the supplied sessionId.
|
|
209
|
+
*/
|
|
210
|
+
allocateAndSendIdsFromRemoteClient(clientFrom, sessionIdFrom, numIds) {
|
|
211
|
+
(0, assert_1.strict)(numIds > 0, "Must allocate a non-zero number of IDs");
|
|
212
|
+
if (clientFrom === exports.OriginatingClient.Remote) {
|
|
213
|
+
const range = {
|
|
214
|
+
sessionId: sessionIdFrom,
|
|
215
|
+
ids: {
|
|
216
|
+
firstGenCount: 1,
|
|
217
|
+
count: numIds,
|
|
218
|
+
requestedClusterSize: this.getCompressor(Client.Client1)[
|
|
219
|
+
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
220
|
+
"nextRequestedClusterSize"],
|
|
221
|
+
},
|
|
222
|
+
};
|
|
223
|
+
const opSpaceIds = [];
|
|
224
|
+
for (let i = 0; i < numIds; i++) {
|
|
225
|
+
opSpaceIds.push(-(i + 1));
|
|
226
|
+
}
|
|
227
|
+
this.serverOperations.push([range, opSpaceIds, clientFrom, sessionIdFrom]);
|
|
228
|
+
return opSpaceIds;
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
(0, assert_1.strict)(sessionIdFrom === exports.sessionIds.get(clientFrom));
|
|
232
|
+
const compressor = this.compressors.get(clientFrom);
|
|
233
|
+
const sessionSpaceIds = generateCompressedIds(compressor, numIds);
|
|
234
|
+
for (let i = 0; i < numIds; i++) {
|
|
235
|
+
this.addNewId(clientFrom, sessionSpaceIds[i], clientFrom, sessionIdFrom, false);
|
|
236
|
+
}
|
|
237
|
+
const opSpaceIds = sessionSpaceIds.map((id) => compressor.normalizeToOpSpace(id));
|
|
238
|
+
const creationRange = compressor.takeNextCreationRange();
|
|
239
|
+
this.serverOperations.push([creationRange, opSpaceIds, clientFrom, sessionIdFrom]);
|
|
240
|
+
return opSpaceIds;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Delivers all undelivered ID ranges from the server to the target clients.
|
|
245
|
+
*/
|
|
246
|
+
deliverOperations(clientTakingDelivery, opsToDeliver) {
|
|
247
|
+
let opIndexBound;
|
|
248
|
+
if (clientTakingDelivery === exports.DestinationClient.All) {
|
|
249
|
+
(0, assert_1.strict)(opsToDeliver === undefined);
|
|
250
|
+
opIndexBound = this.serverOperations.length;
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
opIndexBound =
|
|
254
|
+
opsToDeliver !== undefined
|
|
255
|
+
? this.clientProgress.get(clientTakingDelivery) + opsToDeliver
|
|
256
|
+
: this.serverOperations.length;
|
|
257
|
+
}
|
|
258
|
+
for (const [clientTo, compressorTo] of this.getTargetCompressors(clientTakingDelivery)) {
|
|
259
|
+
for (let i = this.clientProgress.get(clientTo); i < opIndexBound; i++) {
|
|
260
|
+
const [range, opSpaceIds, clientFrom, sessionIdFrom] = this.serverOperations[i];
|
|
261
|
+
compressorTo.finalizeCreationRange(range);
|
|
262
|
+
const ids = range.ids;
|
|
263
|
+
if (ids !== undefined) {
|
|
264
|
+
for (const id of opSpaceIds) {
|
|
265
|
+
const sessionSpaceId = compressorTo.normalizeToSessionSpace(id, range.sessionId);
|
|
266
|
+
this.addNewId(clientTo, sessionSpaceId, clientFrom, sessionIdFrom, true);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
this.clientProgress.set(clientTo, opIndexBound);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Simulate a client disconnecting (and serializing), then reconnecting (and deserializing)
|
|
275
|
+
*/
|
|
276
|
+
goOfflineThenResume(client) {
|
|
277
|
+
const compressor = this.compressors.get(client);
|
|
278
|
+
const [_, resumedCompressor] = roundtrip(compressor, true);
|
|
279
|
+
this.compressors.set(client, resumedCompressor);
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Ensure general validity of the network state. Useful for calling periodically or at the end of test scenarios.
|
|
283
|
+
*/
|
|
284
|
+
assertNetworkState() {
|
|
285
|
+
const sequencedLogs = Object.values(Client).map((client) => [this.compressors.get(client), this.getSequencedIdLog(client)]);
|
|
286
|
+
// First, ensure all clients each generated a unique ID for each of their own calls to generate.
|
|
287
|
+
for (const [compressor, ids] of sequencedLogs) {
|
|
288
|
+
const allUuids = new Set();
|
|
289
|
+
for (const idData of ids) {
|
|
290
|
+
const uuid = compressor.decompress(idData.id);
|
|
291
|
+
assert_1.strict.strictEqual(!allUuids.has(uuid), true, "Duplicate UUID generated.");
|
|
292
|
+
allUuids.add(uuid);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
const maxLogLength = sequencedLogs
|
|
296
|
+
.map(([_, data]) => data.length)
|
|
297
|
+
.reduce((p, n) => Math.max(p, n));
|
|
298
|
+
function getNextLogWithEntryAt(logsIndex, entryIndex) {
|
|
299
|
+
for (let i = logsIndex; i < sequencedLogs.length; i++) {
|
|
300
|
+
const log = sequencedLogs[i];
|
|
301
|
+
if (log[1].length > entryIndex) {
|
|
302
|
+
return i;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
return undefined;
|
|
306
|
+
}
|
|
307
|
+
const uuids = new Set();
|
|
308
|
+
const finalIds = new Set();
|
|
309
|
+
const idIndicesAggregator = new Map();
|
|
310
|
+
function* getIdLogEntries(columnIndex) {
|
|
311
|
+
let current = getNextLogWithEntryAt(0, columnIndex);
|
|
312
|
+
while (current !== undefined) {
|
|
313
|
+
const next = getNextLogWithEntryAt(current + 1, columnIndex);
|
|
314
|
+
const [compressor, log] = sequencedLogs[current];
|
|
315
|
+
if (next === undefined) {
|
|
316
|
+
yield [[compressor, log[columnIndex]]];
|
|
317
|
+
}
|
|
318
|
+
else {
|
|
319
|
+
const [compressorNext, logNext] = sequencedLogs[next];
|
|
320
|
+
yield [
|
|
321
|
+
[compressor, log[columnIndex]],
|
|
322
|
+
[compressorNext, logNext[columnIndex]],
|
|
323
|
+
];
|
|
324
|
+
}
|
|
325
|
+
current = next;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
for (let i = 0; i < maxLogLength; i++) {
|
|
329
|
+
let idCreatorCount = 0;
|
|
330
|
+
let originatingSession;
|
|
331
|
+
for (const [current, next] of getIdLogEntries(i)) {
|
|
332
|
+
const [compressorA, idDataA] = current;
|
|
333
|
+
const sessionSpaceIdA = idDataA.id;
|
|
334
|
+
const idIndex = (0, testCommon_js_1.getOrCreate)(idIndicesAggregator, idDataA.sessionId, () => 0);
|
|
335
|
+
originatingSession ?? (originatingSession = idDataA.sessionId);
|
|
336
|
+
(0, assert_1.strict)(idDataA.sessionId === originatingSession, "Test infra gave wrong originating client to TestIdData");
|
|
337
|
+
// Only one client should have this ID as local in its session space, as only one client could have created this ID
|
|
338
|
+
if ((0, testCommon_js_1.isLocalId)(sessionSpaceIdA)) {
|
|
339
|
+
if (originatingSession !== exports.OriginatingClient.Remote) {
|
|
340
|
+
assert_1.strict.strictEqual(idDataA.sessionId, this.compressors.get(idDataA.originatingClient)
|
|
341
|
+
.localSessionId);
|
|
342
|
+
}
|
|
343
|
+
idCreatorCount++;
|
|
344
|
+
}
|
|
345
|
+
const uuidASessionSpace = compressorA.decompress(sessionSpaceIdA);
|
|
346
|
+
assert_1.strict.strictEqual(uuidASessionSpace, (0, testCommon_js_1.incrementStableId)(idDataA.sessionId, idIndex));
|
|
347
|
+
assert_1.strict.strictEqual(compressorA.recompress(uuidASessionSpace), sessionSpaceIdA);
|
|
348
|
+
uuids.add(uuidASessionSpace);
|
|
349
|
+
const opSpaceIdA = compressorA.normalizeToOpSpace(sessionSpaceIdA);
|
|
350
|
+
if (!(0, testCommon_js_1.isFinalId)(opSpaceIdA)) {
|
|
351
|
+
(0, testCommon_js_1.fail)("IDs should have been finalized.");
|
|
352
|
+
}
|
|
353
|
+
const reNormalizedIdA = compressorA.normalizeToSessionSpace(opSpaceIdA, compressorA.localSessionId);
|
|
354
|
+
assert_1.strict.strictEqual(reNormalizedIdA, sessionSpaceIdA);
|
|
355
|
+
finalIds.add(opSpaceIdA);
|
|
356
|
+
const uuidAOpSpace = compressorA.decompress(reNormalizedIdA);
|
|
357
|
+
assert_1.strict.strictEqual(uuidASessionSpace, uuidAOpSpace);
|
|
358
|
+
if (next !== undefined) {
|
|
359
|
+
const [compressorB, idDataB] = next;
|
|
360
|
+
const sessionSpaceIdB = idDataB.id;
|
|
361
|
+
const uuidBSessionSpace = compressorB.decompress(sessionSpaceIdB);
|
|
362
|
+
assert_1.strict.strictEqual(uuidASessionSpace, uuidBSessionSpace);
|
|
363
|
+
const opSpaceIdB = compressorB.normalizeToOpSpace(sessionSpaceIdB);
|
|
364
|
+
if (opSpaceIdA !== opSpaceIdB) {
|
|
365
|
+
compressorB.normalizeToOpSpace(sessionSpaceIdB);
|
|
366
|
+
compressorA.normalizeToOpSpace(sessionSpaceIdA);
|
|
367
|
+
}
|
|
368
|
+
assert_1.strict.strictEqual(opSpaceIdA, opSpaceIdB);
|
|
369
|
+
if (!(0, testCommon_js_1.isFinalId)(opSpaceIdB)) {
|
|
370
|
+
(0, testCommon_js_1.fail)("IDs should have been finalized.");
|
|
371
|
+
}
|
|
372
|
+
const uuidBOpSpace = compressorB.decompress(opSpaceIdB);
|
|
373
|
+
assert_1.strict.strictEqual(uuidAOpSpace, uuidBOpSpace);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
(0, assert_1.strict)(idCreatorCount <= 1, "Only one client can create an ID.");
|
|
377
|
+
assert_1.strict.strictEqual(uuids.size, finalIds.size);
|
|
378
|
+
(0, assert_1.strict)(originatingSession !== undefined, "Expected originating client to be defined");
|
|
379
|
+
idIndicesAggregator.set(originatingSession,
|
|
380
|
+
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
|
|
381
|
+
(idIndicesAggregator.get(originatingSession) ??
|
|
382
|
+
(0, testCommon_js_1.fail)("Expected pre-existing index for originating client")) + 1);
|
|
383
|
+
}
|
|
384
|
+
for (const [compressor] of sequencedLogs) {
|
|
385
|
+
expectSerializes(compressor);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
exports.IdCompressorTestNetwork = IdCompressorTestNetwork;
|
|
390
|
+
function roundtrip(compressor, withSession) {
|
|
391
|
+
if (withSession) {
|
|
392
|
+
const serialized = compressor.serialize(withSession);
|
|
393
|
+
return [serialized, idCompressor_js_1.IdCompressor.deserialize(serialized)];
|
|
394
|
+
}
|
|
395
|
+
const nonLocalSerialized = compressor.serialize(withSession);
|
|
396
|
+
return [nonLocalSerialized, idCompressor_js_1.IdCompressor.deserialize(nonLocalSerialized, (0, utilities_js_1.createSessionId)())];
|
|
397
|
+
}
|
|
398
|
+
exports.roundtrip = roundtrip;
|
|
399
|
+
/**
|
|
400
|
+
* Asserts that the supplied compressor correctly roundtrips through serialization/deserialization.
|
|
401
|
+
*/
|
|
402
|
+
function expectSerializes(compressor) {
|
|
403
|
+
function expectSerializesWithSession(withSession) {
|
|
404
|
+
let serialized;
|
|
405
|
+
let deserialized;
|
|
406
|
+
if (withSession) {
|
|
407
|
+
[serialized, deserialized] = roundtrip(compressor, true);
|
|
408
|
+
}
|
|
409
|
+
else {
|
|
410
|
+
[serialized, deserialized] = roundtrip(compressor, false);
|
|
411
|
+
}
|
|
412
|
+
assert_1.strict.strictEqual(compressor.equals(deserialized, withSession), true);
|
|
413
|
+
return serialized;
|
|
414
|
+
}
|
|
415
|
+
return [
|
|
416
|
+
expectSerializesWithSession(false),
|
|
417
|
+
expectSerializesWithSession(true),
|
|
418
|
+
];
|
|
419
|
+
}
|
|
420
|
+
exports.expectSerializes = expectSerializes;
|
|
421
|
+
/**
|
|
422
|
+
* Merges 'from' into 'to', and returns 'to'.
|
|
423
|
+
*/
|
|
424
|
+
function mergeArrayMaps(to, from) {
|
|
425
|
+
for (const [key, value] of from.entries()) {
|
|
426
|
+
const entry = to.get(key);
|
|
427
|
+
if (entry !== undefined) {
|
|
428
|
+
entry.push(...value);
|
|
429
|
+
}
|
|
430
|
+
else {
|
|
431
|
+
to.set(key, [...value]);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
return to;
|
|
435
|
+
}
|
|
436
|
+
exports.mergeArrayMaps = mergeArrayMaps;
|
|
437
|
+
const defaultOptions = {
|
|
438
|
+
maxClusterSize: 25,
|
|
439
|
+
validateInterval: 200,
|
|
440
|
+
outsideAllocationFraction: 0.1,
|
|
441
|
+
};
|
|
442
|
+
function makeOpGenerator(options) {
|
|
443
|
+
const { maxClusterSize, validateInterval, outsideAllocationFraction } = {
|
|
444
|
+
...defaultOptions,
|
|
445
|
+
...options,
|
|
446
|
+
};
|
|
447
|
+
(0, assert_1.strict)(outsideAllocationFraction >= 0 && outsideAllocationFraction <= 1);
|
|
448
|
+
function allocateIdsGenerator({ activeClients, clusterSize, random, }) {
|
|
449
|
+
const client = random.pick(activeClients);
|
|
450
|
+
const maxIdsPerUsage = clusterSize * 2;
|
|
451
|
+
const numIds = Math.floor(random.real(0, 1) ** 3 * maxIdsPerUsage) + 1;
|
|
452
|
+
return {
|
|
453
|
+
type: "allocateIds",
|
|
454
|
+
client,
|
|
455
|
+
numIds,
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
function allocateOutsideIdsGenerator({ clusterSize, random, }) {
|
|
459
|
+
const maxIdsPerUsage = clusterSize * 2;
|
|
460
|
+
const numIds = Math.floor(random.real(0, 1) ** 3 * maxIdsPerUsage) + 1;
|
|
461
|
+
return {
|
|
462
|
+
type: "allocateOutsideIds",
|
|
463
|
+
sessionId: (0, utilities_js_1.createSessionId)(),
|
|
464
|
+
numIds,
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
function changeCapacityGenerator({ random, activeClients }) {
|
|
468
|
+
return {
|
|
469
|
+
type: "changeCapacity",
|
|
470
|
+
client: random.pick(activeClients),
|
|
471
|
+
newSize: Math.min(Math.floor(random.real(0, 1) ** 2 * maxClusterSize) + 1, maxClusterSize),
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
function deliverAllOperationsGenerator() {
|
|
475
|
+
return {
|
|
476
|
+
type: "deliverAllOperations",
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
function deliverSomeOperationsGenerator({ random, selectableClients, network, }) {
|
|
480
|
+
const pendingClients = selectableClients.filter((c) => network.getPendingOperations(c) > 0);
|
|
481
|
+
if (pendingClients.length === 0) {
|
|
482
|
+
return {
|
|
483
|
+
type: "deliverSomeOperations",
|
|
484
|
+
client: random.pick(selectableClients),
|
|
485
|
+
count: 0,
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
const client = random.pick(pendingClients);
|
|
489
|
+
return {
|
|
490
|
+
type: "deliverSomeOperations",
|
|
491
|
+
client,
|
|
492
|
+
count: random.integer(1, network.getPendingOperations(client)),
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
function reconnectGenerator({ activeClients, random }) {
|
|
496
|
+
return { type: "reconnect", client: random.pick(activeClients) };
|
|
497
|
+
}
|
|
498
|
+
const allocationWeight = 16;
|
|
499
|
+
return (0, stochastic_test_utils_1.interleave)((0, stochastic_test_utils_1.createWeightedGenerator)([
|
|
500
|
+
[changeCapacityGenerator, 1],
|
|
501
|
+
[allocateIdsGenerator, Math.round(allocationWeight * (1 - outsideAllocationFraction))],
|
|
502
|
+
[allocateOutsideIdsGenerator, Math.round(allocationWeight * outsideAllocationFraction)],
|
|
503
|
+
[deliverAllOperationsGenerator, 2],
|
|
504
|
+
[deliverSomeOperationsGenerator, 6],
|
|
505
|
+
[reconnectGenerator, 1],
|
|
506
|
+
]), (0, stochastic_test_utils_1.take)(1, (0, stochastic_test_utils_1.repeat)({ type: "validate" })), validateInterval);
|
|
507
|
+
}
|
|
508
|
+
exports.makeOpGenerator = makeOpGenerator;
|
|
509
|
+
/**
|
|
510
|
+
* Performs random actions on a test network.
|
|
511
|
+
* @param generator - the generator used to provide operations
|
|
512
|
+
* @param network - the test network to test
|
|
513
|
+
* @param seed - the seed for the random generation of the fuzz actions
|
|
514
|
+
* @param observerClient - if provided, this client will never generate local ids
|
|
515
|
+
* @param synchronizeAtEnd - if provided, all client will have all operations delivered from the server at the end of the test
|
|
516
|
+
* @param validator - if provided, this callback will be invoked periodically during the fuzz test.
|
|
517
|
+
*/
|
|
518
|
+
function performFuzzActions(generator, network, seed, observerClient, synchronizeAtEnd = true, validator, saveInfo) {
|
|
519
|
+
const random = (0, stochastic_test_utils_1.makeRandom)(seed);
|
|
520
|
+
const selectableClients = network
|
|
521
|
+
.getTargetCompressors(MetaClient.All)
|
|
522
|
+
.map(([client]) => client);
|
|
523
|
+
const initialState = {
|
|
524
|
+
random,
|
|
525
|
+
network,
|
|
526
|
+
activeClients: selectableClients.filter((c) => c !== observerClient),
|
|
527
|
+
selectableClients,
|
|
528
|
+
clusterSize: network.initialClusterSize,
|
|
529
|
+
};
|
|
530
|
+
(0, stochastic_test_utils_1.performFuzzActions)(generator, {
|
|
531
|
+
allocateIds: (state, { client, numIds }) => {
|
|
532
|
+
network.allocateAndSendIdsFromRemoteClient(client, exports.sessionIds.get(client), numIds);
|
|
533
|
+
return state;
|
|
534
|
+
},
|
|
535
|
+
allocateOutsideIds: (state, { sessionId, numIds }) => {
|
|
536
|
+
network.allocateAndSendIdsFromRemoteClient(exports.OriginatingClient.Remote, sessionId, numIds);
|
|
537
|
+
return state;
|
|
538
|
+
},
|
|
539
|
+
changeCapacity: (state, op) => {
|
|
540
|
+
network.changeCapacity(op.client, op.newSize);
|
|
541
|
+
return { ...state, clusterSize: op.newSize };
|
|
542
|
+
},
|
|
543
|
+
deliverSomeOperations: (state, op) => {
|
|
544
|
+
network.deliverOperations(op.client, op.count);
|
|
545
|
+
return state;
|
|
546
|
+
},
|
|
547
|
+
deliverAllOperations: (state) => {
|
|
548
|
+
network.deliverOperations(exports.DestinationClient.All);
|
|
549
|
+
return state;
|
|
550
|
+
},
|
|
551
|
+
reconnect: (state, { client }) => {
|
|
552
|
+
network.goOfflineThenResume(client);
|
|
553
|
+
return state;
|
|
554
|
+
},
|
|
555
|
+
validate: (state) => {
|
|
556
|
+
network.deliverOperations(exports.DestinationClient.All);
|
|
557
|
+
validator?.(network);
|
|
558
|
+
return state;
|
|
559
|
+
},
|
|
560
|
+
}, initialState, saveInfo);
|
|
561
|
+
if (synchronizeAtEnd) {
|
|
562
|
+
network.deliverOperations(exports.DestinationClient.All);
|
|
563
|
+
validator?.(network);
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
exports.performFuzzActions = performFuzzActions;
|
|
567
|
+
/**
|
|
568
|
+
* Helper to generate a fixed number of IDs.
|
|
569
|
+
*/
|
|
570
|
+
function generateCompressedIds(compressor, count) {
|
|
571
|
+
const ids = [];
|
|
572
|
+
for (let i = 0; i < count; i++) {
|
|
573
|
+
ids.push(compressor.generateCompressedId());
|
|
574
|
+
}
|
|
575
|
+
return ids;
|
|
576
|
+
}
|
|
577
|
+
exports.generateCompressedIds = generateCompressedIds;
|
|
578
|
+
function createAlwaysFinalizedIdCompressor(sessionIdOrLogger, loggerOrUndefined) {
|
|
579
|
+
const compressor = sessionIdOrLogger === undefined
|
|
580
|
+
? (0, index_js_1.createIdCompressor)()
|
|
581
|
+
: typeof sessionIdOrLogger === "string"
|
|
582
|
+
? (0, index_js_1.createIdCompressor)(sessionIdOrLogger, loggerOrUndefined)
|
|
583
|
+
: (0, index_js_1.createIdCompressor)(sessionIdOrLogger);
|
|
584
|
+
// Permanently put the compressor in a ghost session
|
|
585
|
+
compressor.startGhostSession((0, utilities_js_1.createSessionId)());
|
|
586
|
+
return compressor;
|
|
587
|
+
}
|
|
588
|
+
exports.createAlwaysFinalizedIdCompressor = createAlwaysFinalizedIdCompressor;
|
|
589
|
+
//# sourceMappingURL=idCompressorTestUtilities.js.map
|