@fragno-dev/test 1.0.1 → 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.
Files changed (42) hide show
  1. package/.turbo/turbo-build.log +31 -15
  2. package/CHANGELOG.md +54 -0
  3. package/dist/adapters.d.ts +21 -3
  4. package/dist/adapters.d.ts.map +1 -1
  5. package/dist/adapters.js +125 -31
  6. package/dist/adapters.js.map +1 -1
  7. package/dist/db-test.d.ts.map +1 -1
  8. package/dist/db-test.js +33 -2
  9. package/dist/db-test.js.map +1 -1
  10. package/dist/durable-hooks.d.ts +7 -0
  11. package/dist/durable-hooks.d.ts.map +1 -0
  12. package/dist/durable-hooks.js +12 -0
  13. package/dist/durable-hooks.js.map +1 -0
  14. package/dist/index.d.ts +8 -4
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +6 -2
  17. package/dist/index.js.map +1 -1
  18. package/dist/model-checker-actors.d.ts +41 -0
  19. package/dist/model-checker-actors.d.ts.map +1 -0
  20. package/dist/model-checker-actors.js +406 -0
  21. package/dist/model-checker-actors.js.map +1 -0
  22. package/dist/model-checker-adapter.d.ts +32 -0
  23. package/dist/model-checker-adapter.d.ts.map +1 -0
  24. package/dist/model-checker-adapter.js +109 -0
  25. package/dist/model-checker-adapter.js.map +1 -0
  26. package/dist/model-checker.d.ts +128 -0
  27. package/dist/model-checker.d.ts.map +1 -0
  28. package/dist/model-checker.js +443 -0
  29. package/dist/model-checker.js.map +1 -0
  30. package/package.json +13 -12
  31. package/src/adapter-conformance.test.ts +322 -0
  32. package/src/adapters.ts +199 -36
  33. package/src/db-test.test.ts +2 -2
  34. package/src/db-test.ts +53 -3
  35. package/src/durable-hooks.ts +13 -0
  36. package/src/index.test.ts +84 -7
  37. package/src/index.ts +39 -4
  38. package/src/model-checker-actors.test.ts +78 -0
  39. package/src/model-checker-actors.ts +642 -0
  40. package/src/model-checker-adapter.ts +200 -0
  41. package/src/model-checker.test.ts +399 -0
  42. package/src/model-checker.ts +799 -0
package/src/index.ts CHANGED
@@ -5,6 +5,7 @@ import type {
5
5
  KyselySqliteAdapter,
6
6
  KyselyPgliteAdapter,
7
7
  DrizzlePgliteAdapter,
8
+ InMemoryAdapterConfig,
8
9
  } from "./adapters";
9
10
  import type { DatabaseAdapter } from "@fragno-dev/db";
10
11
  import type { SimpleQueryInterface } from "@fragno-dev/db/query";
@@ -22,11 +23,45 @@ export type {
22
23
  KyselySqliteAdapter,
23
24
  KyselyPgliteAdapter,
24
25
  DrizzlePgliteAdapter,
26
+ InMemoryAdapterConfig,
25
27
  AdapterContext,
26
28
  } from "./adapters";
27
29
 
28
30
  // Re-export new builder-based database test utilities
29
31
  export { buildDatabaseFragmentsTest, DatabaseFragmentsTestBuilder } from "./db-test";
32
+ export { drainDurableHooks } from "./durable-hooks";
33
+ export {
34
+ runModelChecker,
35
+ defaultStateHasher,
36
+ defaultTraceHasher,
37
+ type ModelCheckerConfig,
38
+ type ModelCheckerBounds,
39
+ type ModelCheckerRunResult,
40
+ type ModelCheckerScheduleResult,
41
+ type ModelCheckerMode,
42
+ type ModelCheckerStep,
43
+ type ModelCheckerTraceEvent,
44
+ type ModelCheckerTrace,
45
+ type ModelCheckerTraceRecorder,
46
+ type ModelCheckerTraceHasher,
47
+ type ModelCheckerTraceHashMode,
48
+ type NormalizedMutationOperation,
49
+ type RawUowTransaction,
50
+ type RawUowTransactionBuilder,
51
+ type RawUowTransactionContext,
52
+ type RawUowMutateContext,
53
+ createRawUowTransaction,
54
+ } from "./model-checker";
55
+
56
+ export {
57
+ runModelCheckerWithActors,
58
+ type ModelCheckerActor,
59
+ type ModelCheckerInvariant,
60
+ type ModelCheckerInvariantContext,
61
+ type ModelCheckerActorsConfig,
62
+ } from "./model-checker-actors";
63
+
64
+ export { ModelCheckerAdapter, type ModelCheckerScheduler } from "./model-checker-adapter";
30
65
 
31
66
  /**
32
67
  * Base test context with common functionality across all adapters
@@ -42,7 +77,7 @@ export interface BaseTestContext {
42
77
  * Internal interface with getOrm for adapter implementations
43
78
  */
44
79
  export interface InternalTestContextMethods {
45
- getOrm: <TSchema extends AnySchema>(namespace: string) => SimpleQueryInterface<TSchema>;
80
+ getOrm: <TSchema extends AnySchema>(namespace: string | null) => SimpleQueryInterface<TSchema>;
46
81
  }
47
82
 
48
83
  /**
@@ -51,13 +86,13 @@ export interface InternalTestContextMethods {
51
86
  */
52
87
  export function createCommonTestContextMethods(
53
88
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
54
- ormMap: Map<string, SimpleQueryInterface<any>>,
89
+ ormMap: Map<string | null, SimpleQueryInterface<any>>,
55
90
  ): InternalTestContextMethods {
56
91
  return {
57
- getOrm: <TSchema extends AnySchema>(namespace: string) => {
92
+ getOrm: <TSchema extends AnySchema>(namespace: string | null) => {
58
93
  const orm = ormMap.get(namespace);
59
94
  if (!orm) {
60
- throw new Error(`No ORM found for namespace: ${namespace}`);
95
+ throw new Error(`No ORM found for namespace: ${String(namespace)}`);
61
96
  }
62
97
  return orm as SimpleQueryInterface<TSchema>;
63
98
  },
@@ -0,0 +1,78 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { InMemoryAdapter } from "@fragno-dev/db";
3
+ import { column, idColumn, schema } from "@fragno-dev/db/schema";
4
+ import { ModelCheckerAdapter } from "./model-checker-adapter";
5
+ import { runModelCheckerWithActors } from "./model-checker-actors";
6
+
7
+ const testSchema = schema("test", (s) =>
8
+ s.addTable("items", (t) => t.addColumn("id", idColumn()).addColumn("name", column("string"))),
9
+ );
10
+
11
+ const createContext = async () => {
12
+ const adapter = new InMemoryAdapter({ idSeed: "model-checker-actors" });
13
+ const modelAdapter = new ModelCheckerAdapter(adapter);
14
+ const queryEngine = modelAdapter.createQueryEngine(testSchema, "model-checker-actors");
15
+
16
+ return {
17
+ adapter: modelAdapter,
18
+ ctx: { queryEngine },
19
+ queryEngine,
20
+ cleanup: async () => {
21
+ await adapter.close();
22
+ },
23
+ };
24
+ };
25
+
26
+ describe("model checker actors", () => {
27
+ it("exhaustively explores bounded interleavings", async () => {
28
+ const result = await runModelCheckerWithActors({
29
+ schema: testSchema,
30
+ mode: "bounded-exhaustive",
31
+ bounds: { maxSteps: 2 },
32
+ history: false,
33
+ createContext,
34
+ setup: async ({ queryEngine }) => {
35
+ await queryEngine.create("items", { name: "seed" });
36
+ },
37
+ buildActors: ({ queryEngine }) => [
38
+ {
39
+ name: "tx-a",
40
+ run: async () => {
41
+ const uow = queryEngine.createUnitOfWork("tx-a");
42
+ uow.find("items", (b) => b.whereIndex("primary"));
43
+ await uow.executeRetrieve();
44
+ uow.create("items", { name: "alpha" });
45
+ const { success } = await uow.executeMutations();
46
+ if (!success) {
47
+ throw new Error("tx-a mutation failed");
48
+ }
49
+ },
50
+ },
51
+ {
52
+ name: "tx-b",
53
+ run: async () => {
54
+ const uow = queryEngine.createUnitOfWork("tx-b");
55
+ uow.find("items", (b) => b.whereIndex("primary"));
56
+ await uow.executeRetrieve();
57
+ uow.create("items", { name: "beta" });
58
+ const { success } = await uow.executeMutations();
59
+ if (!success) {
60
+ throw new Error("tx-b mutation failed");
61
+ }
62
+ },
63
+ },
64
+ ],
65
+ });
66
+
67
+ const prefixes = new Set(
68
+ result.schedules.map((entry) =>
69
+ entry.schedule
70
+ .slice(0, 2)
71
+ .map((step) => `${step.txId}:${step.phase}`)
72
+ .join("|"),
73
+ ),
74
+ );
75
+
76
+ expect(prefixes.size).toBe(2);
77
+ });
78
+ });