File size: 1,776 Bytes
4c76b0d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import { describe, expect, it } from "vitest";
import { createDeferred } from "../../../test/helpers/promise.js";
import { withOpenClawTestState } from "../../test-utils/openclaw-test-state.js";
import { createRuntimeAgent } from "./runtime-agent.js";

describe("plugin runtime session patches", () => {
  it("rejects a patch whose owner closes during asynchronous preparation", async () => {
    await withOpenClawTestState({ label: "plugin-runtime-patch-owner" }, async () => {
      const runtime = createRuntimeAgent();
      const scope = { agentId: "main", sessionKey: "agent:main:reef:group:room" };
      await runtime.session.upsertSessionEntry({
        ...scope,
        entry: { sessionId: "original", updatedAt: 100, displayName: "Original title" },
      });
      const original = runtime.session.getSessionEntry(scope);
      const preparing = createDeferred();
      const releasePreparation = createDeferred();
      let ownerActive = true;
      const patch = runtime.session.patchSessionEntry({
        ...scope,
        preserveActivity: true,
        assertCommitAllowed: () => {
          if (!ownerActive) {
            throw new Error("Session patch owner closed");
          }
        },
        update: async () => {
          preparing.resolve();
          await releasePreparation.promise;
          return { displayName: "Stale title" };
        },
      });
      try {
        await preparing.promise;
        ownerActive = false;
        releasePreparation.resolve();
        await expect(patch).rejects.toThrow("Session patch owner closed");
        expect(runtime.session.getSessionEntry(scope)).toEqual(original);
      } finally {
        releasePreparation.resolve();
        await patch.catch(() => undefined);
      }
    });
  });
});