@rotorsoft/act-tck 1.35.0 → 1.36.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.
@@ -17,6 +17,18 @@ export type StorePropertyTckOptions = {
17
17
  factory: () => Store | Promise<Store>;
18
18
  /** fast-check runs per property. Default 100; lower for durable adapters. */
19
19
  numRuns?: number;
20
+ /**
21
+ * Per-property timeout in milliseconds. Default 5000, matching vitest.
22
+ *
23
+ * Every run of a property is a full reset plus a dozen or more round
24
+ * trips, so against a real database the wall time is dominated by I/O and
25
+ * by whatever else the machine is doing. Vitest's default is comfortable
26
+ * in isolation and not under a parallel suite sharing one server, which
27
+ * showed up as this file intermittently timing out rather than failing an
28
+ * assertion. Durable adapters should raise it; the in-memory store has no
29
+ * reason to.
30
+ */
31
+ timeoutMs?: number;
20
32
  };
21
33
  export declare const runStorePropertyTck: (options: StorePropertyTckOptions) => void;
22
34
  //# sourceMappingURL=store-property-tck.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"store-property-tck.d.ts","sourceRoot":"","sources":["../../src/store-property-tck.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAwClD;;;;;;;;;;GAUG;AACH,MAAM,MAAM,uBAAuB,GAAG;IACpC,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,wEAAwE;IACxE,OAAO,EAAE,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IACtC,6EAA6E;IAC7E,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAkBF,eAAO,MAAM,mBAAmB,YAAa,uBAAuB,KAAG,IAgNtE,CAAC"}
1
+ {"version":3,"file":"store-property-tck.d.ts","sourceRoot":"","sources":["../../src/store-property-tck.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAwClD;;;;;;;;;;GAUG;AACH,MAAM,MAAM,uBAAuB,GAAG;IACpC,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,wEAAwE;IACxE,OAAO,EAAE,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IACtC,6EAA6E;IAC7E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;;;;OAUG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAkBF,eAAO,MAAM,mBAAmB,YAAa,uBAAuB,KAAG,IAyNtE,CAAC"}
@@ -26,6 +26,17 @@ export type StoreCapabilities = {
26
26
  * rollback on mid-iteration throw.
27
27
  */
28
28
  readonly restore?: boolean;
29
+ /**
30
+ * Adapter honours `subscribe`'s optional `correlator` argument and answers
31
+ * `correlating` (#1532). When `true`, the TCK runs the correlation-lease
32
+ * suite — exclusive acquisition, renewal by the same holder, re-acquisition
33
+ * after expiry, per-key independence, and the keyed checkpoint.
34
+ *
35
+ * Optional because a store that ignores the argument simply lets every
36
+ * worker scan, which is the pre-#1532 behaviour and remains correct: the
37
+ * marks are idempotent, so the duplication is waste rather than error.
38
+ */
39
+ readonly lease_correlation?: boolean;
29
40
  /**
30
41
  * Adapter supports sensitive-data isolation (#566): accepts the
31
42
  * optional `pii` field on commit messages, returns it on load
@@ -1 +1 @@
1
- {"version":3,"file":"store-tck.d.ts","sourceRoot":"","sources":["../../src/store-tck.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAQV,KAAK,EAIN,MAAM,sBAAsB,CAAC;AAc9B;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;;;OAMG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B;;;;;;;OAOG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;IACjC;;;;;;;;;OASG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IACpC;;;;;;;;OAQG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;IAClC;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IACxC;;;;;;;;OAQG;IACH,QAAQ,CAAC,gCAAgC,CAAC,EAAE,OAAO,CAAC;IACpD;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;;;;OAOG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAC/C;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IACxD;;OAEG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,iBAAiB,CAAC;CAC3C,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,eAAO,MAAM,WAAW,YAAa,eAAe,KAAG,IAitJtD,CAAC"}
1
+ {"version":3,"file":"store-tck.d.ts","sourceRoot":"","sources":["../../src/store-tck.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAQV,KAAK,EAIN,MAAM,sBAAsB,CAAC;AAc9B;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;;;OAMG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B;;;;;;;;;OASG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IACrC;;;;;;;OAOG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;IACjC;;;;;;;;;OASG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IACpC;;;;;;;;OAQG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;IAClC;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IACxC;;;;;;;;OAQG;IACH,QAAQ,CAAC,gCAAgC,CAAC,EAAE,OAAO,CAAC;IACpD;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;;;;OAOG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAC/C;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IACxD;;OAEG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,iBAAiB,CAAC;CAC3C,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,eAAO,MAAM,WAAW,YAAa,eAAe,KAAG,IAg2JtD,CAAC"}
package/dist/index.cjs CHANGED
@@ -962,6 +962,7 @@ var opArb = import_vitest7.fc.oneof(
962
962
  var events = (count) => Array.from({ length: count }, () => inc(1));
963
963
  var runStorePropertyTck = (options) => {
964
964
  const numRuns = options.numRuns ?? 100;
965
+ const timeout = options.timeoutMs ?? 5e3;
965
966
  (0, import_vitest8.describe)(`TCK / Store properties / ${options.name}`, () => {
966
967
  let store;
967
968
  (0, import_vitest8.beforeAll)(async () => {
@@ -1001,7 +1002,8 @@ var runStorePropertyTck = (options) => {
1001
1002
  (0, import_vitest8.expect)(e.version).toBe(i);
1002
1003
  });
1003
1004
  }
1004
- }
1005
+ },
1006
+ timeout
1005
1007
  );
1006
1008
  import_vitest7.test.prop([import_vitest7.fc.array(commitArb, { minLength: 1, maxLength: 20 })], {
1007
1009
  numRuns
@@ -1028,7 +1030,8 @@ var runStorePropertyTck = (options) => {
1028
1030
  ).rejects.toThrow();
1029
1031
  const after = await collect(store, { stream, stream_exact: true });
1030
1032
  (0, import_vitest8.expect)(after.length).toBe(before.length);
1031
- }
1033
+ },
1034
+ timeout
1032
1035
  );
1033
1036
  });
1034
1037
  (0, import_vitest8.describe)("claim/lease lifecycle invariants", () => {
@@ -1075,7 +1078,8 @@ var runStorePropertyTck = (options) => {
1075
1078
  }
1076
1079
  }
1077
1080
  (0, import_vitest8.expect)(totalResolved + pending.length).toBe(totalClaims);
1078
- }
1081
+ },
1082
+ timeout
1079
1083
  );
1080
1084
  import_vitest7.test.prop(
1081
1085
  [
@@ -1118,35 +1122,40 @@ var runStorePropertyTck = (options) => {
1118
1122
  watermark1.get(lease.stream)
1119
1123
  );
1120
1124
  }
1121
- }
1125
+ },
1126
+ timeout
1122
1127
  );
1123
1128
  import_vitest7.test.prop([import_vitest7.fc.array(claimStreamArb, { minLength: 1, maxLength: 5 })], {
1124
1129
  numRuns
1125
- })("blocked streams cannot be claimed again", async (commits) => {
1126
- await reset2();
1127
- const streams = [...new Set(commits)];
1128
- await store.subscribe(streams.map((stream) => ({ stream })));
1129
- for (const stream of commits) {
1130
+ })(
1131
+ "blocked streams cannot be claimed again",
1132
+ async (commits) => {
1133
+ await reset2();
1134
+ const streams = [...new Set(commits)];
1135
+ await store.subscribe(streams.map((stream) => ({ stream })));
1136
+ for (const stream of commits) {
1137
+ await store.commit(
1138
+ stream,
1139
+ [inc(1)],
1140
+ make_meta({ stream })
1141
+ );
1142
+ }
1143
+ await mark_all2(store);
1144
+ const claimed = await store.claim(10, 10, "worker", 6e4);
1145
+ await store.block(claimed.map((l) => ({ ...l, error: "test" })));
1146
+ const blockedSet = new Set(claimed.map((l) => l.stream));
1147
+ await store.subscribe([{ stream: "ctrl" }]);
1130
1148
  await store.commit(
1131
- stream,
1149
+ "ctrl",
1132
1150
  [inc(1)],
1133
- make_meta({ stream })
1151
+ make_meta({ stream: "ctrl" })
1134
1152
  );
1135
- }
1136
- await mark_all2(store);
1137
- const claimed = await store.claim(10, 10, "worker", 6e4);
1138
- await store.block(claimed.map((l) => ({ ...l, error: "test" })));
1139
- const blockedSet = new Set(claimed.map((l) => l.stream));
1140
- await store.subscribe([{ stream: "ctrl" }]);
1141
- await store.commit(
1142
- "ctrl",
1143
- [inc(1)],
1144
- make_meta({ stream: "ctrl" })
1145
- );
1146
- await mark_all2(store);
1147
- const reclaim = await store.claim(10, 10, "worker2", 6e4);
1148
- for (const l of reclaim) (0, import_vitest8.expect)(blockedSet.has(l.stream)).toBe(false);
1149
- });
1153
+ await mark_all2(store);
1154
+ const reclaim = await store.claim(10, 10, "worker2", 6e4);
1155
+ for (const l of reclaim) (0, import_vitest8.expect)(blockedSet.has(l.stream)).toBe(false);
1156
+ },
1157
+ timeout
1158
+ );
1150
1159
  });
1151
1160
  });
1152
1161
  };
@@ -4196,6 +4205,103 @@ var runStoreTck = (options) => {
4196
4205
  }
4197
4206
  });
4198
4207
  });
4208
+ import_vitest9.describe.skipIf(!caps.lease_correlation)(
4209
+ "correlation lease via subscribe (capability)",
4210
+ () => {
4211
+ const by = () => `corr-${uid()}`;
4212
+ const key = () => `key-${uid()}`;
4213
+ const take = (k, who, millis = 1e4) => store.subscribe([], void 0, { key: k, by: who, millis });
4214
+ const release = async (k, who) => {
4215
+ await take(k, who, 1);
4216
+ await new Promise((r) => setTimeout(r, 20));
4217
+ };
4218
+ (0, import_vitest9.it)("grants the lease to the first caller", async () => {
4219
+ const k = key();
4220
+ const who = by();
4221
+ (0, import_vitest9.expect)((await take(k, who)).correlating).toBe(true);
4222
+ await release(k, who);
4223
+ });
4224
+ (0, import_vitest9.it)("answers undefined when no correlator is supplied", async () => {
4225
+ (0, import_vitest9.expect)(await store.subscribe([])).not.toHaveProperty("correlating");
4226
+ });
4227
+ (0, import_vitest9.it)("refuses a second holder while the lease is live", async () => {
4228
+ const k = key();
4229
+ const who = by();
4230
+ (0, import_vitest9.expect)((await take(k, who)).correlating).toBe(true);
4231
+ (0, import_vitest9.expect)((await take(k, by())).correlating).toBe(false);
4232
+ await release(k, who);
4233
+ });
4234
+ (0, import_vitest9.it)("lets the same holder renew rather than failing", async () => {
4235
+ const k = key();
4236
+ const who = by();
4237
+ (0, import_vitest9.expect)((await take(k, who)).correlating).toBe(true);
4238
+ (0, import_vitest9.expect)((await take(k, who)).correlating).toBe(true);
4239
+ await release(k, who);
4240
+ });
4241
+ (0, import_vitest9.it)("becomes available again once the lease expires", async () => {
4242
+ const k = key();
4243
+ (0, import_vitest9.expect)((await take(k, by(), 1)).correlating).toBe(true);
4244
+ await new Promise((r) => setTimeout(r, 30));
4245
+ const next = by();
4246
+ (0, import_vitest9.expect)((await take(k, next)).correlating).toBe(true);
4247
+ await release(k, next);
4248
+ });
4249
+ (0, import_vitest9.it)("keys leases independently, so one correlator cannot starve another", async () => {
4250
+ const a = key();
4251
+ const b = key();
4252
+ const holder_a = by();
4253
+ const holder_b = by();
4254
+ (0, import_vitest9.expect)((await take(a, holder_a)).correlating).toBe(true);
4255
+ (0, import_vitest9.expect)((await take(b, holder_b)).correlating).toBe(true);
4256
+ await release(a, holder_a);
4257
+ await release(b, holder_b);
4258
+ });
4259
+ (0, import_vitest9.it)("still advances the checkpoint for a caller that loses the lease", async () => {
4260
+ const k = key();
4261
+ const holder = by();
4262
+ (0, import_vitest9.expect)((await take(k, holder)).correlating).toBe(true);
4263
+ const loser = await store.subscribe([], 7777, {
4264
+ key: k,
4265
+ by: by(),
4266
+ millis: 1e4
4267
+ });
4268
+ (0, import_vitest9.expect)(loser.correlating).toBe(false);
4269
+ (0, import_vitest9.expect)(loser.correlated_at).toBeGreaterThanOrEqual(7777);
4270
+ await release(k, holder);
4271
+ });
4272
+ (0, import_vitest9.it)("seeds a new key from the shared floor, then lets it diverge", async () => {
4273
+ const a = key();
4274
+ const holder_a = by();
4275
+ const first = await store.subscribe([], 4100, {
4276
+ key: a,
4277
+ by: holder_a,
4278
+ millis: 1e4
4279
+ });
4280
+ (0, import_vitest9.expect)(first.correlated_at).toBeGreaterThanOrEqual(4100);
4281
+ const b = key();
4282
+ const holder_b = by();
4283
+ const second = await store.subscribe([], void 0, {
4284
+ key: b,
4285
+ by: holder_b,
4286
+ millis: 1e4
4287
+ });
4288
+ (0, import_vitest9.expect)(second.correlated_at).toBeGreaterThanOrEqual(4100);
4289
+ await store.subscribe([], 9e3, {
4290
+ key: a,
4291
+ by: holder_a,
4292
+ millis: 1e4
4293
+ });
4294
+ const b_again = await store.subscribe([], void 0, {
4295
+ key: b,
4296
+ by: holder_b,
4297
+ millis: 1e4
4298
+ });
4299
+ (0, import_vitest9.expect)(b_again.correlated_at).toBe(second.correlated_at);
4300
+ await release(a, holder_a);
4301
+ await release(b, holder_b);
4302
+ });
4303
+ }
4304
+ );
4199
4305
  import_vitest9.describe.skipIf(!caps.restore)("restore (capability)", () => {
4200
4306
  beforeEach(async () => {
4201
4307
  await store.drop();