import { describe, expect, it, vi } from "vitest";
import { ensureSecafsMountForSession, type SessionEntryView } from "./auto-mount-hook.js";
function entry(partial: Partial<SessionEntryView>): SessionEntryView {
return {
sessionId: "sid",
updatedAt: 0,
...partial,
};
}
function makeDeps(store: Record<string, SessionEntryView>) {
const rpc = { mount: vi.fn().mockResolvedValue({ hostPath: "/mnt/abc", mounted: true }) };
const patchSession = vi.fn().mockResolvedValue(undefined);
const wsSet = vi.fn().mockResolvedValue(undefined);
return {
rpc,
patchSession,
wsSet,
deps: {
loadStore: () => store,
patchSession,
workspace: { set: wsSet },
rpc,
mountRoot: "/mnt",
},
};
}
describe("ensureSecafsMountForSession", () => {
it("no-ops for empty session key", async () => {
const { deps, rpc } = makeDeps({});
await ensureSecafsMountForSession(deps, undefined);
expect(rpc.mount).not.toHaveBeenCalled();
});
it("no-ops for non-secafs sessions", async () => {
const store = {
"agent:main:main": entry({ sessionId: "regular", mountState: undefined }),
};
const { deps, rpc } = makeDeps(store);
await ensureSecafsMountForSession(deps, "agent:main:main");
expect(rpc.mount).not.toHaveBeenCalled();
});
it("no-ops when secafs session is already mounted", async () => {
const store = {
"main:abc": entry({
sessionId: "abc",
kind: "secafs",
mountState: "mounted",
}),
};
const { deps, rpc, patchSession } = makeDeps(store);
await ensureSecafsMountForSession(deps, "main:abc");
expect(rpc.mount).not.toHaveBeenCalled();
expect(patchSession).not.toHaveBeenCalled();
});
it("mounts and re-sets workspace + mountState when bare key is unmounted", async () => {
const store = {
"main:abc": entry({
sessionId: "abc",
kind: "secafs",
mountState: "unmounted",
}),
};
const { deps, rpc, patchSession, wsSet } = makeDeps(store);
await ensureSecafsMountForSession(deps, "main:abc");
expect(rpc.mount).toHaveBeenCalledWith({
conversationId: "abc",
hostPath: "/mnt/abc",
});
expect(wsSet).toHaveBeenCalledWith("main:abc", { path: "/mnt/abc" });
expect(patchSession).toHaveBeenCalledWith("main:abc", { mountState: "mounted" });
});
it("resolves SecAFS metadata via bare key when invoked with agent-canonical key", async () => {
const store = {
"main:abc": entry({
sessionId: "abc",
kind: "secafs",
mountState: "unmounted",
}),
"agent:main:main:abc": entry({ sessionId: "agent-side" }),
};
const { deps, rpc, patchSession, wsSet } = makeDeps(store);
await ensureSecafsMountForSession(deps, "agent:main:main:abc");
expect(rpc.mount).toHaveBeenCalledWith({
conversationId: "abc",
hostPath: "/mnt/abc",
});
expect(wsSet).toHaveBeenCalledWith("main:abc", { path: "/mnt/abc" });
expect(patchSession).toHaveBeenCalledWith("main:abc", { mountState: "mounted" });
});
it("logs and swallows mount errors (does not throw)", async () => {
const store = {
"main:abc": entry({
sessionId: "abc",
kind: "secafs",
mountState: "unmounted",
}),
};
const { deps, rpc, patchSession } = makeDeps(store);
rpc.mount.mockRejectedValueOnce(new Error("daemon unreachable"));
const warn = vi.fn();
await expect(
ensureSecafsMountForSession({ ...deps, logger: { warn, info: vi.fn() } }, "main:abc"),
).resolves.toBeUndefined();
expect(warn).toHaveBeenCalled();
expect(patchSession).not.toHaveBeenCalled();
});
});