File size: 2,723 Bytes
f778c12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import type { MigrationPlan, MigrationProviderPlugin } from "../../plugins/types.js";
import { planProviderMemoryImport } from "./memory-import.js";

const tempRoots: string[] = [];

async function makeSourceDir(): Promise<string> {
  const dir = await fs.realpath(await fs.mkdtemp(path.join(os.tmpdir(), "memory-import-test-")));
  tempRoots.push(dir);
  return dir;
}

afterEach(async () => {
  await Promise.all(tempRoots.splice(0).map((dir) => fs.rm(dir, { force: true, recursive: true })));
});

async function memoryPlan(sourceDir: string, ids: string[]): Promise<MigrationPlan> {
  const items = await Promise.all(
    ids.map(async (id, index) => {
      // Duplicate ids still resolve to distinct real files so the dedupe check,
      // not a missing-file error, is what rejects them.
      const source = path.join(sourceDir, `${id}-${index}.md`);
      await fs.writeFile(source, `# ${id}\n`);
      return {
        id,
        kind: "memory" as const,
        action: "copy" as const,
        status: "planned" as const,
        source,
        target: `/target/${id}-${index}.md`,
      };
    }),
  );
  return {
    providerId: "test",
    source: sourceDir,
    summary: {
      total: items.length,
      planned: items.length,
      migrated: 0,
      skipped: 0,
      conflicts: 0,
      errors: 0,
      sensitive: 0,
    },
    items,
  };
}

function stubProvider(plan: MigrationPlan): MigrationProviderPlugin {
  return {
    id: "test",
    label: "Test",
    supportedItemKinds: ["memory"],
    detect: () => ({ found: true, source: plan.source }),
    plan: () => plan,
    apply: () => ({ ...plan, summary: plan.summary }),
  };
}

const config = {} as OpenClawConfig;

describe("planProviderMemoryImport memory-only shaping", () => {
  it("rejects a plan with duplicate memory item ids", async () => {
    const dir = await makeSourceDir();
    await expect(
      planProviderMemoryImport({
        provider: stubProvider(await memoryPlan(dir, ["same-id", "same-id"])),
        config,
        agentId: "main",
      }),
    ).rejects.toThrow('duplicate memory migration item id "same-id"');
  });

  it("accepts a plan with unique memory item ids", async () => {
    const dir = await makeSourceDir();
    const { plan } = await planProviderMemoryImport({
      provider: stubProvider(await memoryPlan(dir, ["memory-a", "memory-b"])),
      config,
      agentId: "main",
    });
    expect(plan.items.map((item) => item.id)).toEqual(["memory-a", "memory-b"]);
  });
});