chore(vendor): import pi 1.3.0
Imported as a linear vendor commit so forge rebases do not replay the upstream root tree. git-subtree-dir: third_party/pi git-subtree-split: 71023aec1546d6d677a65669c5665c0927ce0dd0
This commit is contained in:
1 parent
719370c8f7
commit
6081e3e325
1743 files changed
+205459
-131704
No files matched your search
@@ -0,0 +1,221 @@
|
||||
import { defineDoc, defineDocFamily } from "@earendil-works/pi-durable";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { context, createConversation, documentChanges, flush, openTestSession } from "./session-support.ts";
|
||||
|
||||
type State = { value: number; retained: { label: string } };
|
||||
|
||||
const StateDoc = defineDoc<State>({
|
||||
kind: "state.state",
|
||||
version: 1,
|
||||
scope: "session",
|
||||
initial: () => ({ value: 0, retained: { label: "stable" } }),
|
||||
});
|
||||
|
||||
const FamilyDoc = defineDocFamily<{ value: number }, string>({
|
||||
kind: "state.family",
|
||||
version: 1,
|
||||
family: true,
|
||||
scope: "session",
|
||||
initial: (seed) => ({ value: seed.length }),
|
||||
});
|
||||
|
||||
async function createState(): Promise<ReturnType<typeof openTestSession>> {
|
||||
const harness = openTestSession();
|
||||
await harness.session.commit((tx) => tx.doc(StateDoc).then(() => undefined), context);
|
||||
await flush();
|
||||
return harness;
|
||||
}
|
||||
|
||||
describe("Session document states", () => {
|
||||
it("never creates an absent document", async () => {
|
||||
const { session, storage } = openTestSession();
|
||||
const commits = storage.commits.length;
|
||||
expect(await session.documentState(StateDoc, context)).toBeUndefined();
|
||||
expect(await session.documentState(FamilyDoc, "missing", context)).toBeUndefined();
|
||||
expect(storage.commits).toHaveLength(commits);
|
||||
expect(storage.mintCount).toBe(0);
|
||||
});
|
||||
|
||||
it("returns an immediately hydrated read-only state with contiguous Chord deliveries", async () => {
|
||||
const { session } = await createState();
|
||||
const baseline = (await session.snapshot(StateDoc, context))!;
|
||||
const state = (await session.documentState(StateDoc, context))!;
|
||||
const deliveries: Array<{ value: Readonly<State> | null; sequence: number }> = [];
|
||||
state.subscribe((value, _context, delivery) => deliveries.push({ value, sequence: delivery.sequence }));
|
||||
expect(state.value).toBe(baseline);
|
||||
|
||||
await session.commit(async (tx) => {
|
||||
(await tx.doc(StateDoc)).value = 1;
|
||||
}, context);
|
||||
await session.commit(async (tx) => {
|
||||
(await tx.doc(StateDoc)).value = 2;
|
||||
}, context);
|
||||
await flush();
|
||||
|
||||
expect(deliveries.map(({ sequence }) => sequence)).toEqual([0, 1, 2]);
|
||||
expect(deliveries.map(({ value }) => value?.value)).toEqual([0, 1, 2]);
|
||||
expect(state.value).toBe(await session.snapshot(StateDoc, context));
|
||||
state.dispose();
|
||||
});
|
||||
|
||||
it("creates independent disposable states for one incarnation", async () => {
|
||||
const { session } = await createState();
|
||||
const first = (await session.documentState(StateDoc, context))!;
|
||||
const second = (await session.documentState(StateDoc, context))!;
|
||||
expect(second).not.toBe(first);
|
||||
await session.commit(async (tx) => {
|
||||
(await tx.doc(StateDoc)).value = 1;
|
||||
}, context);
|
||||
await flush();
|
||||
expect(first.value?.value).toBe(1);
|
||||
expect(second.value?.value).toBe(1);
|
||||
|
||||
first.dispose();
|
||||
await session.commit(async (tx) => {
|
||||
(await tx.doc(StateDoc)).value = 2;
|
||||
}, context);
|
||||
await flush();
|
||||
expect(first.value?.value).toBe(1);
|
||||
expect(second.value?.value).toBe(2);
|
||||
second.dispose();
|
||||
});
|
||||
|
||||
it("shares exact committed value references with Chord", async () => {
|
||||
const { session, publications } = await createState();
|
||||
const state = (await session.documentState(StateDoc, context))!;
|
||||
await session.commit(async (tx) => {
|
||||
(await tx.doc(StateDoc)).value = 4;
|
||||
}, context);
|
||||
await flush();
|
||||
const published = documentChanges(publications.at(-1)!)[0]!;
|
||||
expect(state.value).toBe(published.value);
|
||||
expect(state.value?.retained).toBe((await session.snapshot(StateDoc, context))!.retained);
|
||||
state.dispose();
|
||||
});
|
||||
|
||||
it("captures a late baseline without redelivering an already covered commit", async () => {
|
||||
const { session } = await createState();
|
||||
await session.commit(async (tx) => {
|
||||
(await tx.doc(StateDoc)).value = 1;
|
||||
}, context);
|
||||
const state = (await session.documentState(StateDoc, context))!;
|
||||
const deliveries: number[] = [];
|
||||
state.subscribe((_value, _context, delivery) => deliveries.push(delivery.sequence));
|
||||
await flush();
|
||||
expect(state.value?.value).toBe(1);
|
||||
expect(deliveries).toEqual([0]);
|
||||
state.dispose();
|
||||
});
|
||||
|
||||
it("publishes null retirement and never follows a replacement incarnation", async () => {
|
||||
const { session } = await createState();
|
||||
const oldState = (await session.documentState(StateDoc, context))!;
|
||||
await session.commit(async (tx) => {
|
||||
await tx.retireDoc(StateDoc);
|
||||
(await tx.doc(StateDoc)).value = 10;
|
||||
}, context);
|
||||
await flush();
|
||||
expect(oldState.value).toBeNull();
|
||||
|
||||
const replacement = (await session.documentState(StateDoc, context))!;
|
||||
expect(replacement.value?.value).toBe(10);
|
||||
await session.commit(async (tx) => {
|
||||
(await tx.doc(StateDoc)).value = 11;
|
||||
}, context);
|
||||
await flush();
|
||||
expect(oldState.value).toBeNull();
|
||||
expect(replacement.value?.value).toBe(11);
|
||||
oldState.dispose();
|
||||
replacement.dispose();
|
||||
});
|
||||
|
||||
it("cold-loads a definition-free fork copy", async () => {
|
||||
const Copied = defineDoc<{ value: number }>({
|
||||
kind: "state.copied",
|
||||
version: 1,
|
||||
scope: "conversation",
|
||||
history: "latest",
|
||||
fork: "current",
|
||||
initial: () => ({ value: 0 }),
|
||||
});
|
||||
const { session, storage } = openTestSession();
|
||||
const parentId = await createConversation(session);
|
||||
const entry = await session.commit(async (tx) => {
|
||||
const created = await tx.appendEntry(parentId, { kind: "point" });
|
||||
(await tx.doc(Copied, parentId)).value = 7;
|
||||
return created;
|
||||
}, context);
|
||||
const childId = await session.commit(
|
||||
async (tx) => (await tx.forkConversation(parentId, entry.id, { ownership: { kind: "ownerless" } })).id,
|
||||
context,
|
||||
);
|
||||
const reads = storage.documentReadCount;
|
||||
const state = (await session.documentState(Copied, childId, context))!;
|
||||
expect(state.value).toEqual({ value: 7 });
|
||||
expect(storage.documentReadCount).toBeGreaterThan(reads);
|
||||
state.dispose();
|
||||
});
|
||||
|
||||
it("hydrates a migrated tracker without writing and skips an equal version-base update", async () => {
|
||||
const Old = defineDoc<{ value: number }>({
|
||||
kind: "state.migration",
|
||||
version: 1,
|
||||
scope: "session",
|
||||
initial: () => ({ value: 3 }),
|
||||
});
|
||||
const Current = defineDoc<{ value: number; migrated: boolean }>({
|
||||
kind: "state.migration",
|
||||
version: 2,
|
||||
scope: "session",
|
||||
initial: () => ({ value: 0, migrated: false }),
|
||||
migrate: (value) => ({ value: value.value as number, migrated: true }),
|
||||
});
|
||||
const { session, storage } = openTestSession();
|
||||
await session.commit((tx) => tx.doc(Old).then(() => undefined), context);
|
||||
await session.unloadDocuments();
|
||||
const commits = storage.commits.length;
|
||||
const state = (await session.documentState(Current, context))!;
|
||||
expect(state.value).toEqual({ value: 3, migrated: true });
|
||||
expect(storage.commits).toHaveLength(commits);
|
||||
const baseline = state.value;
|
||||
|
||||
await session.commit((tx) => tx.doc(Current).then(() => undefined), context);
|
||||
await flush();
|
||||
expect(storage.commits).toHaveLength(commits + 1);
|
||||
expect(state.value).toBe(baseline);
|
||||
await session.commit(async (tx) => {
|
||||
(await tx.doc(Current)).value = 4;
|
||||
}, context);
|
||||
await flush();
|
||||
expect(state.value).toEqual({ value: 4, migrated: true });
|
||||
state.dispose();
|
||||
});
|
||||
|
||||
it("continues from exact committed values after the tracker cache unloads", async () => {
|
||||
const { session, storage } = await createState();
|
||||
const state = (await session.documentState(StateDoc, context))!;
|
||||
const baseline = state.value;
|
||||
const reads = storage.documentReadCount;
|
||||
await session.unloadDocuments();
|
||||
const reloaded = await session.snapshot(StateDoc, context);
|
||||
expect(reloaded).toEqual(baseline);
|
||||
expect(reloaded).not.toBe(baseline);
|
||||
expect(storage.documentReadCount).toBeGreaterThan(reads);
|
||||
await session.commit(async (tx) => {
|
||||
(await tx.doc(StateDoc)).value = 6;
|
||||
}, context);
|
||||
await flush();
|
||||
expect(state.value?.value).toBe(6);
|
||||
state.dispose();
|
||||
});
|
||||
|
||||
it("exposes trusted shared immutable values without freezing", async () => {
|
||||
const { session } = await createState();
|
||||
const snapshot = (await session.snapshot(StateDoc, context))!;
|
||||
const state = (await session.documentState(StateDoc, context))!;
|
||||
expect(state.value).toBe(snapshot);
|
||||
expect(Object.isFrozen(state.value)).toBe(false);
|
||||
expect(Object.isFrozen(state.value!.retained)).toBe(false);
|
||||
state.dispose();
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user