import { beforeEach, describe, expect, test } from "bun:test"; import type { AssistantConfig } from "../../config/schema.js"; import { recordConfigSettingSnapshot, resetConfigSettingSnapshotForTesting, } from "../config-setting-snapshot.js"; import { pendingOutboxPayloads, resetOutboxTable, setShareAnalytics, } from "./outbox-test-harness.js"; function makeConfig( memoryEnabled: boolean, v2Enabled: boolean, v3Live = false, ): AssistantConfig { return { memory: { enabled: memoryEnabled, v2: { enabled: v2Enabled }, v3: { live: v3Live }, }, } as AssistantConfig; } function recordedPairs(): Array<[string, string]> { return pendingOutboxPayloads<{ config_key: string; config_value: string; }>("config_setting").map((event) => [event.config_key, event.config_value]); } describe("config-setting-snapshot", () => { beforeEach(() => { setShareAnalytics(true); resetOutboxTable(); resetConfigSettingSnapshotForTesting(); }); test("records every tracked setting on the first snapshot", () => { recordConfigSettingSnapshot(makeConfig(true, false)); expect(recordedPairs().sort()).toEqual([ ["memory.enabled", "true"], ["memory.v2.enabled", "false"], ["memory.v3.live", "false"], ]); }); test("repeated snapshots with unchanged values record nothing new", () => { recordConfigSettingSnapshot(makeConfig(true, true)); recordConfigSettingSnapshot(makeConfig(true, true)); recordConfigSettingSnapshot(makeConfig(true, true)); expect(recordedPairs()).toHaveLength(3); }); test("a changed value records only the changed key", () => { recordConfigSettingSnapshot(makeConfig(true, true)); resetOutboxTable(); recordConfigSettingSnapshot(makeConfig(true, false)); expect(recordedPairs()).toEqual([["memory.v2.enabled", "false"]]); }); test("memory.v3.live is tracked and its flip is captured", () => { recordConfigSettingSnapshot(makeConfig(true, true, false)); expect(recordedPairs()).toContainEqual(["memory.v3.live", "false"]); resetOutboxTable(); recordConfigSettingSnapshot(makeConfig(true, true, true)); expect(recordedPairs()).toEqual([["memory.v3.live", "true"]]); }); test("unknown consent skips entirely — no rows, no memo", () => { setShareAnalytics("unknown"); recordConfigSettingSnapshot(makeConfig(true, false)); // A snapshot is re-derivable state (unlike outbox events), so nothing is // recorded while consent is unresolved... expect(recordedPairs()).toHaveLength(0); // ...and nothing was memoized: once consent resolves, the next snapshot // records the complete current set. setShareAnalytics(true); recordConfigSettingSnapshot(makeConfig(true, false)); expect(recordedPairs().sort()).toEqual([ ["memory.enabled", "true"], ["memory.v2.enabled", "false"], ["memory.v3.live", "false"], ]); }); test("consent off drops the snapshot without poisoning the memo", () => { setShareAnalytics(false); recordConfigSettingSnapshot(makeConfig(true, true)); expect(recordedPairs()).toHaveLength(0); // A later opted-in snapshot records the full set — the opted-out attempt // must not have memoized the values (mirrors the reporter's flush retry // once consent resolves). setShareAnalytics(true); recordConfigSettingSnapshot(makeConfig(true, true)); expect(recordedPairs()).toHaveLength(3); }); test("re-opt-in after an opt-out re-records the full snapshot", () => { // Recorded while opted in. recordConfigSettingSnapshot(makeConfig(true, true)); expect(recordedPairs()).toHaveLength(3); resetOutboxTable(); // Opt out: the reporter's opt-out flush discards any pending rows, so the // memo must be cleared here too. setShareAnalytics(false); recordConfigSettingSnapshot(makeConfig(true, true)); expect(recordedPairs()).toHaveLength(0); // Re-opt-in with the SAME config: the full snapshot re-records rather than // being skipped by a stale memo. setShareAnalytics(true); recordConfigSettingSnapshot(makeConfig(true, true)); expect(recordedPairs().sort()).toEqual([ ["memory.enabled", "true"], ["memory.v2.enabled", "true"], ["memory.v3.live", "false"], ]); }); test("a partial config skips missing keys instead of throwing", () => { recordConfigSettingSnapshot({} as AssistantConfig); expect(recordedPairs()).toHaveLength(0); recordConfigSettingSnapshot({ memory: { enabled: true }, } as AssistantConfig); expect(recordedPairs()).toEqual([["memory.enabled", "true"]]); }); });