Skip to content

Commit 18ed9ab

Browse files
committed
test(status): qualify lease selection on PostgreSQL
Signed-off-by: huangruiteng <huangrt01@163.com>
1 parent d9b2929 commit 18ed9ab

1 file changed

Lines changed: 46 additions & 25 deletions

File tree

‎tests/control_plane_ts/canonical_snapshot_page.test.ts‎

Lines changed: 46 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import assert from "node:assert/strict";
22
import test from "node:test";
3+
import {randomUUID} from "node:crypto";
34
import {mkdtemp, rm, readdir, writeFile, rename} from "node:fs/promises";
45
import {tmpdir} from "node:os";
56
import {join} from "node:path";
7+
import {Pool} from "pg";
68
import type {JsonObject} from "../../loopx/control_plane/effect_program.ts";
79
import {FileAuthorityStore} from "../../loopx/control_plane/coordination/file_authority_store.ts";
810
import {SqliteAuthorityStore} from "../../loopx/control_plane/coordination/sqlite_authority_store.ts";
11+
import {PostgreSqlAuthorityStore, installPostgreSqlAuthorityStoreSchema} from "../../loopx/control_plane/coordination/postgresql_authority_store.ts";
912
import {sqliteRuntimeIdentity} from "../../loopx/control_plane/coordination/sqlite_runtime.ts";
1013
import {coordinationTodoReadModel} from "../../loopx/control_plane/coordination/coordination_projection.ts";
1114
import {readCanonicalSnapshotFromStore, readCanonicalSnapshotPage, readCanonicalSnapshot,
@@ -29,35 +32,49 @@ async function fixture(t: test.TestContext, kind: "file" | "sqlite" = "file") {
2932
const Store = kind === "file" ? FileAuthorityStore : SqliteAuthorityStore;
3033
return {store: new Store(root, "goal-a"), contender: new Store(root, "goal-a")};
3134
}
35+
async function postgresqlFixture(t: test.TestContext): Promise<AuthorityStore> {
36+
const pool = new Pool({connectionString: process.env.LOOPX_TEST_POSTGRES_URL, max: 2});
37+
t.after(() => pool.end());
38+
const database = {connect: async () => {
39+
const client = await pool.connect();
40+
return {query: async (sql: string, values?: readonly unknown[]) => client.query(sql, values ? [...values] : undefined),
41+
release: () => client.release()};
42+
}};
43+
await installPostgreSqlAuthorityStoreSchema(database, `postgresql:${"b".repeat(32)}`);
44+
return new PostgreSqlAuthorityStore(database, {tenant_id: `snapshot-${randomUUID()}`, goal_id: "goal-a"});
45+
}
46+
async function verifyLeaseSelection(store: AuthorityStore): Promise<void> {
47+
const {projection} = productionScaleCoordinationFixture("goal-a", "native");
48+
await seedSnapshot(store, projection);
49+
const before = await store.loadAuthority();
50+
const full = await readCanonicalSnapshotFromStore(snapshotRequest(), store, CANONICAL_SNAPSHOT_LOCAL_BYTES);
51+
const leases = projection.leases as JsonObject[];
52+
const selected = [leases.find(lease => lease.status === "active")!, leases.find(lease => lease.status === "released")!];
53+
const ids = [...selected.map(lease => lease.todo_id), "todo_without_lease"];
54+
const request = snapshotRequest({lease_todo_ids: ids});
55+
const page = await readCanonicalSnapshotFromStore(request, store);
56+
assert.equal(page.status, "page");
57+
assert.deepEqual(page.todos, []);
58+
assert.deepEqual(page.leases, (full.leases as JsonObject[]).filter(lease => ids.includes(lease.todo_id)));
59+
assert.equal((page.leases as JsonObject[]).length, 2);
60+
const snapshot = page.snapshot as JsonObject;
61+
assert.equal(snapshot.provider_revision, (full.snapshot as JsonObject).provider_revision);
62+
assert.equal(snapshot.store_identity, (full.snapshot as JsonObject).store_identity);
63+
assert.notEqual(snapshot.query_sha256, (full.snapshot as JsonObject).query_sha256);
64+
const after = {snapshot, todo_offset: 0, lease_offset: 1};
65+
const last = await readCanonicalSnapshotFromStore({...request, lease_todo_ids: ids.toReversed(), after}, store);
66+
assert.deepEqual(last.leases, (page.leases as JsonObject[]).slice(1));
67+
await assert.rejects(readCanonicalSnapshotFromStore({...request,
68+
lease_todo_ids: [...ids.slice(0, 2), "todo_different_missing_lease"], after}, store), /canonical snapshot changed/);
69+
await assert.rejects(readCanonicalSnapshotFromStore({...request, include_leases: false}, store),
70+
/lease selection requires/);
71+
assert.deepEqual(await store.loadAuthority(), before);
72+
}
3273
const qualifiedSqlite = sqliteRuntimeIdentity().sqlite_authority_qualified;
3374
for (const provider of (qualifiedSqlite ? ["file", "sqlite"] : ["file"]) as ("file" | "sqlite")[]) {
3475
test(`${provider}: lease selection preserves matching lease records and binds continuation scope`, async t => {
3576
const {store} = await fixture(t, provider);
36-
const {projection} = productionScaleCoordinationFixture("goal-a", "native");
37-
await seedSnapshot(store, projection);
38-
const before = await store.loadAuthority();
39-
const full = await readCanonicalSnapshotFromStore(snapshotRequest(), store, CANONICAL_SNAPSHOT_LOCAL_BYTES);
40-
const leases = projection.leases as JsonObject[];
41-
const selected = [leases.find(lease => lease.status === "active")!, leases.find(lease => lease.status === "released")!];
42-
const ids = [...selected.map(lease => lease.todo_id), "todo_without_lease"];
43-
const request = snapshotRequest({lease_todo_ids: ids});
44-
const page = await readCanonicalSnapshotFromStore(request, store);
45-
assert.equal(page.status, "page");
46-
assert.deepEqual(page.todos, []);
47-
assert.deepEqual(page.leases, (full.leases as JsonObject[]).filter(lease => ids.includes(lease.todo_id)));
48-
assert.equal((page.leases as JsonObject[]).length, 2);
49-
const snapshot = page.snapshot as JsonObject;
50-
assert.equal(snapshot.provider_revision, (full.snapshot as JsonObject).provider_revision);
51-
assert.equal(snapshot.store_identity, (full.snapshot as JsonObject).store_identity);
52-
assert.notEqual(snapshot.query_sha256, (full.snapshot as JsonObject).query_sha256);
53-
const after = {snapshot, todo_offset: 0, lease_offset: 1};
54-
const last = await readCanonicalSnapshotFromStore({...request, lease_todo_ids: ids.toReversed(), after}, store);
55-
assert.deepEqual(last.leases, (page.leases as JsonObject[]).slice(1));
56-
await assert.rejects(readCanonicalSnapshotFromStore({...request,
57-
lease_todo_ids: [...ids.slice(0, 2), "todo_different_missing_lease"], after}, store), /canonical snapshot changed/);
58-
await assert.rejects(readCanonicalSnapshotFromStore({...request, include_leases: false}, store),
59-
/lease selection requires/);
60-
assert.deepEqual(await store.loadAuthority(), before);
77+
await verifyLeaseSelection(store);
6178
});
6279
for (const defect of ["manifest", "digest"] as const) {
6380
test(`${provider}: invalid projection is distinct from an invalid snapshot request (${defect})`, async t => {
@@ -90,6 +107,10 @@ for (const provider of (qualifiedSqlite ? ["file", "sqlite"] : ["file"]) as ("fi
90107
});
91108
}
92109
}
110+
test("postgresql: lease selection preserves matching lease records and binds continuation scope",
111+
{skip: !process.env.LOOPX_TEST_POSTGRES_URL}, async t => {
112+
await verifyLeaseSelection(await postgresqlFixture(t));
113+
});
93114
if (qualifiedSqlite) {
94115
test("selected SQLite snapshot retains the complete independent read contract", async t => {
95116
const {store} = await fixture(t, "sqlite");

0 commit comments

Comments
 (0)