import type { EnvironmentId, ThreadId } from "@t3tools/contracts";import { describe, expect, it } from "@effect/vitest";import * as Effect from "effect/Effect";import * as Layer from "effect/Layer"; import { ThreadHistoryController, threadHistoryControllerLayer, type ThreadHistoryHandler, type ThreadHistoryLoadEarlierResult,} from "./threadHistoryController.ts"; const ENV = "env-history" as EnvironmentId;const THREAD = "thread-history" as ThreadId; function handler( tag: string,): ThreadHistoryHandler & { readonly tag: string; readonly calls: number } { const state = { tag, calls: 0 }; return { get tag() { return state.tag; }, get calls() { return state.calls; }, loadEarlier: () => { state.calls += 1; return Effect.succeed({ _tag: "loaded" } satisfies ThreadHistoryLoadEarlierResult); }, };} describe("ThreadHistoryController", () => { it.effect("does not let an older finalizer delete a newer registration", () => Effect.gen(function* () { const controller = yield* ThreadHistoryController; const older = handler("older"); const newer = handler("newer"); const olderRegistration = yield* controller.register(ENV, THREAD, older); const newerRegistration = yield* controller.register(ENV, THREAD, newer); // Older fiber finalizes after the newer handler is already registered. yield* controller.unregister(olderRegistration); const result = yield* controller.loadEarlier(ENV, THREAD); expect(result).toEqual({ _tag: "loaded" }); expect(newer.calls).toBe(1); expect(older.calls).toBe(0); yield* controller.unregister(newerRegistration); expect(yield* controller.loadEarlier(ENV, THREAD)).toEqual({ _tag: "noop" }); }).pipe(Effect.provide(threadHistoryControllerLayer)), ); it.effect("unregister removes only its own matching registration", () => Effect.gen(function* () { const controller = yield* ThreadHistoryController; const first = handler("first"); const registration = yield* controller.register(ENV, THREAD, first); yield* controller.unregister(registration); expect(yield* controller.loadEarlier(ENV, THREAD)).toEqual({ _tag: "noop" }); }).pipe(Effect.provide(Layer.fresh(threadHistoryControllerLayer))), );});
import type { EnvironmentId, ThreadId } from "@t3tools/contracts";
import { describe, expect, it } from "@effect/vitest";
import * as Effect from "effect/Effect";
import * as Layer from "effect/Layer";
import {
ThreadHistoryController,
threadHistoryControllerLayer,
type ThreadHistoryHandler,
type ThreadHistoryLoadEarlierResult,
} from "./threadHistoryController.ts";
const ENV = "env-history" as EnvironmentId;
const THREAD = "thread-history" as ThreadId;
function handler(
tag: string,
): ThreadHistoryHandler & { readonly tag: string; readonly calls: number } {
const state = { tag, calls: 0 };
return {
get tag() {
return state.tag;
},
get calls() {
return state.calls;
},
loadEarlier: () => {
state.calls += 1;
return Effect.succeed({ _tag: "loaded" } satisfies ThreadHistoryLoadEarlierResult);
},
};
}
describe("ThreadHistoryController", () => {
it.effect("does not let an older finalizer delete a newer registration", () =>
Effect.gen(function* () {
const controller = yield* ThreadHistoryController;
const older = handler("older");
const newer = handler("newer");
const olderRegistration = yield* controller.register(ENV, THREAD, older);
const newerRegistration = yield* controller.register(ENV, THREAD, newer);
// Older fiber finalizes after the newer handler is already registered.
yield* controller.unregister(olderRegistration);
const result = yield* controller.loadEarlier(ENV, THREAD);
expect(result).toEqual({ _tag: "loaded" });
expect(newer.calls).toBe(1);
expect(older.calls).toBe(0);
yield* controller.unregister(newerRegistration);
expect(yield* controller.loadEarlier(ENV, THREAD)).toEqual({ _tag: "noop" });
}).pipe(Effect.provide(threadHistoryControllerLayer)),
);
it.effect("unregister removes only its own matching registration", () =>
Effect.gen(function* () {
const controller = yield* ThreadHistoryController;
const first = handler("first");
const registration = yield* controller.register(ENV, THREAD, first);
yield* controller.unregister(registration);
expect(yield* controller.loadEarlier(ENV, THREAD)).toEqual({ _tag: "noop" });
}).pipe(Effect.provide(Layer.fresh(threadHistoryControllerLayer))),
);
});