167 lines · 5.9 KB · TypeScript
RawDownload
import { assert, describe, it } from "@effect/vitest";import * as Effect from "effect/Effect"; import { OPENCODE_PROVIDER } from "./OpenCodeAdapterV2.ts";import {  OPENCODE_SDK_REPLAY_PROTOCOL,  OpenCodeReplayController,  OpenCodeReplayMismatchError,} from "./OpenCodeAdapterV2.testkit.ts"; describe("OpenCodeAdapterV2 replay testkit", () => {  const metadata = {    provider: OPENCODE_PROVIDER,    protocol: OPENCODE_SDK_REPLAY_PROTOCOL,    version: "test",  };  const promptFrame = (messageID: string, text = "recorded-user") => ({    type: "session.promptAsync",    input: { sessionID: "native-session", messageID, parts: [{ type: "text", text }] },  });   it.effect("correlates a prompt ID without adopting unrelated messages or rewriting text", () =>    Effect.gen(function* () {      const userEvent = (id: string) => ({        type: "message.updated",        properties: { sessionID: "native-session", info: { id, role: "user" } },      });      const controller = new OpenCodeReplayController({        ...metadata,        scenario: "prompt-message-identity",        entries: [          { type: "expect_outbound", frame: promptFrame("recorded-user") },          {            type: "emit_inbound",            frame: { type: "sdk.event", event: userEvent("unrelated-user") },          },          {            type: "emit_inbound",            frame: { type: "sdk.event", event: userEvent("recorded-user") },          },          {            type: "emit_inbound",            frame: {              type: "sdk.event",              event: {                type: "message.updated",                properties: {                  sessionID: "native-session",                  info: { id: "assistant-message", role: "assistant", parentID: "recorded-user" },                },              },            },          },          {            type: "expect_outbound",            frame: { type: "session.revert", input: { messageID: "recorded-user" } },          },          {            type: "emit_inbound",            frame: {              type: "sdk.response",              operation: "session.revert",              data: { id: "native-session", revert: { messageID: "recorded-user" } },            },          },          { type: "runtime_exit", status: "success" },        ],      });      yield* Effect.promise(() => controller.expectOutbound(promptFrame("generated-user")));      const iterator = controller.events()[Symbol.asyncIterator]();      const unrelated = yield* Effect.promise(() => iterator.next());      const admitted = yield* Effect.promise(() => iterator.next());      const assistant = yield* Effect.promise(() => iterator.next());      assert.deepEqual(unrelated.value, userEvent("unrelated-user"));      assert.deepEqual(admitted.value, userEvent("generated-user"));      assert.deepEqual(assistant.value, {        type: "message.updated",        properties: {          sessionID: "native-session",          info: { id: "assistant-message", role: "assistant", parentID: "generated-user" },        },      });      yield* Effect.promise(() =>        controller.expectOutbound({          type: "session.revert",          input: { messageID: "generated-user" },        }),      );      assert.deepEqual(yield* Effect.promise(() => controller.response("session.revert")), {        id: "native-session",        revert: { messageID: "generated-user" },      });      assert.isTrue((yield* Effect.promise(() => iterator.next())).done);      controller.assertComplete();    }),  );   it.effect("still rejects changed prompt text when binding a generated message ID", () =>    Effect.gen(function* () {      const controller = new OpenCodeReplayController({        ...metadata,        scenario: "prompt-text-mismatch",        entries: [{ type: "expect_outbound", frame: promptFrame("recorded-user") }],      });      const error = yield* Effect.tryPromise(() =>        controller.expectOutbound(promptFrame("generated-user", "different prompt")),      ).pipe(Effect.flip);      assert.instanceOf(error.cause, OpenCodeReplayMismatchError);    }),  );   for (const [name, recordedId, actualId] of [    ["rebinding an existing recorded ID", "recorded-user", "another-generated-user"],    [      "reusing one generated ID for distinct recorded users",      "another-recorded-user",      "generated-user",    ],  ] as const) {    it.effect(`rejects ${name}`, () =>      Effect.gen(function* () {        const controller = new OpenCodeReplayController({          ...metadata,          scenario: "conflicting-message-identity",          entries: [            { type: "expect_outbound", frame: promptFrame("recorded-user") },            { type: "expect_outbound", frame: promptFrame(recordedId) },          ],        });        yield* Effect.promise(() => controller.expectOutbound(promptFrame("generated-user")));        const error = yield* Effect.tryPromise(() =>          controller.expectOutbound(promptFrame(actualId)),        ).pipe(Effect.flip);        assert.instanceOf(error.cause, OpenCodeReplayMismatchError);      }),    );  }   it.effect("stops an event stream when abort races with listener registration", () =>    Effect.gen(function* () {      let aborted = false;      const signal = {        get aborted() {          return aborted;        },        addEventListener: () => {          aborted = true;        },        removeEventListener: () => {},      } as unknown as AbortSignal;      const controller = new OpenCodeReplayController({        provider: OPENCODE_PROVIDER,        protocol: OPENCODE_SDK_REPLAY_PROTOCOL,        version: "test",        scenario: "abort-during-listener-registration",        entries: [],      });      const iterator = controller.events(signal)[Symbol.asyncIterator]();       const result = yield* Effect.promise(() => iterator.next()).pipe(        Effect.timeout("100 millis"),      );       assert.isTrue(result.done);    }),  );});