mirror of
https://github.com/moltbot/moltbot.git
synced 2026-04-20 21:23:23 +00:00
test(matrix): share client startup and backfill fixtures
This commit is contained in:
@@ -70,6 +70,24 @@ function primeAccountClientMocks(params?: {
|
||||
return { mainAuth, opsAuth, mainClient, opsClient };
|
||||
}
|
||||
|
||||
function createPendingSharedStartup(mainAuth = authFor("main")) {
|
||||
let resolveStartup: (() => void) | undefined;
|
||||
const mainClient = {
|
||||
...createMockClient("main"),
|
||||
start: vi.fn(
|
||||
async () =>
|
||||
await new Promise<void>((resolve) => {
|
||||
resolveStartup = resolve;
|
||||
}),
|
||||
),
|
||||
};
|
||||
|
||||
resolveMatrixAuthMock.mockResolvedValue(mainAuth);
|
||||
createMatrixClientMock.mockResolvedValue(mainClient);
|
||||
|
||||
return { mainClient, resolveStartup: () => resolveStartup?.() };
|
||||
}
|
||||
|
||||
describe("resolveSharedMatrixClient", () => {
|
||||
beforeAll(async () => {
|
||||
({
|
||||
@@ -234,25 +252,11 @@ describe("resolveSharedMatrixClient", () => {
|
||||
});
|
||||
|
||||
it("lets a later waiter abort while shared startup continues for the owner", async () => {
|
||||
const mainAuth = authFor("main");
|
||||
let resolveStartup: (() => void) | undefined;
|
||||
const mainClient = {
|
||||
...createMockClient("main"),
|
||||
start: vi.fn(
|
||||
async () =>
|
||||
await new Promise<void>((resolve) => {
|
||||
resolveStartup = resolve;
|
||||
}),
|
||||
),
|
||||
};
|
||||
|
||||
resolveMatrixAuthMock.mockResolvedValue(mainAuth);
|
||||
createMatrixClientMock.mockResolvedValue(mainClient);
|
||||
const { mainClient, resolveStartup } = createPendingSharedStartup();
|
||||
|
||||
const ownerPromise = resolveSharedMatrixClient({ accountId: "main" });
|
||||
await vi.waitFor(() => {
|
||||
expect(mainClient.start).toHaveBeenCalledTimes(1);
|
||||
expect(resolveStartup).toEqual(expect.any(Function));
|
||||
});
|
||||
|
||||
const abortController = new AbortController();
|
||||
@@ -267,30 +271,16 @@ describe("resolveSharedMatrixClient", () => {
|
||||
name: "AbortError",
|
||||
});
|
||||
|
||||
resolveStartup?.();
|
||||
resolveStartup();
|
||||
await expect(ownerPromise).resolves.toBe(mainClient);
|
||||
});
|
||||
|
||||
it("keeps the shared startup lock while an aborted waiter exits early", async () => {
|
||||
const mainAuth = authFor("main");
|
||||
let resolveStartup: (() => void) | undefined;
|
||||
const mainClient = {
|
||||
...createMockClient("main"),
|
||||
start: vi.fn(
|
||||
async () =>
|
||||
await new Promise<void>((resolve) => {
|
||||
resolveStartup = resolve;
|
||||
}),
|
||||
),
|
||||
};
|
||||
|
||||
resolveMatrixAuthMock.mockResolvedValue(mainAuth);
|
||||
createMatrixClientMock.mockResolvedValue(mainClient);
|
||||
const { mainClient, resolveStartup } = createPendingSharedStartup();
|
||||
|
||||
const ownerPromise = resolveSharedMatrixClient({ accountId: "main" });
|
||||
await vi.waitFor(() => {
|
||||
expect(mainClient.start).toHaveBeenCalledTimes(1);
|
||||
expect(resolveStartup).toEqual(expect.any(Function));
|
||||
});
|
||||
|
||||
const abortController = new AbortController();
|
||||
@@ -307,7 +297,7 @@ describe("resolveSharedMatrixClient", () => {
|
||||
const followerPromise = resolveSharedMatrixClient({ accountId: "main" });
|
||||
expect(mainClient.start).toHaveBeenCalledTimes(1);
|
||||
|
||||
resolveStartup?.();
|
||||
resolveStartup();
|
||||
await expect(ownerPromise).resolves.toBe(mainClient);
|
||||
await expect(followerPromise).resolves.toBe(mainClient);
|
||||
expect(mainClient.start).toHaveBeenCalledTimes(1);
|
||||
|
||||
@@ -129,6 +129,85 @@ describe("matrix client storage paths", () => {
|
||||
});
|
||||
}
|
||||
|
||||
function setupCurrentTokenBackfillScenario(params: {
|
||||
currentRootFiles: "thread-bindings" | "startup-verification";
|
||||
oldRootFiles: "crypto-only" | "thread-bindings";
|
||||
}) {
|
||||
const stateDir = setupStateDir();
|
||||
const canonicalPaths = resolveMatrixAccountStorageRoot({
|
||||
stateDir,
|
||||
homeserver: defaultStorageAuth.homeserver,
|
||||
userId: defaultStorageAuth.userId,
|
||||
accessToken: "secret-token-new",
|
||||
});
|
||||
fs.mkdirSync(canonicalPaths.rootDir, { recursive: true });
|
||||
writeJson(canonicalPaths.rootDir, "storage-meta.json", {
|
||||
homeserver: defaultStorageAuth.homeserver,
|
||||
userId: defaultStorageAuth.userId,
|
||||
accountId: "default",
|
||||
accessTokenHash: canonicalPaths.tokenHash,
|
||||
deviceId: null,
|
||||
});
|
||||
if (params.currentRootFiles === "thread-bindings") {
|
||||
writeJson(canonicalPaths.rootDir, "thread-bindings.json", {
|
||||
version: 1,
|
||||
bindings: [
|
||||
{
|
||||
accountId: "default",
|
||||
conversationId: "$thread-new",
|
||||
targetKind: "subagent",
|
||||
targetSessionKey: "agent:ops:subagent:new",
|
||||
boundAt: 1,
|
||||
lastActivityAt: 1,
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(
|
||||
claimCurrentTokenStorageState({
|
||||
rootDir: canonicalPaths.rootDir,
|
||||
}),
|
||||
).toBe(true);
|
||||
} else {
|
||||
writeJson(canonicalPaths.rootDir, "startup-verification.json", {
|
||||
deviceId: "DEVICE123",
|
||||
});
|
||||
}
|
||||
|
||||
const oldStoragePaths = seedExistingStorageRoot({
|
||||
accessToken: "secret-token-old",
|
||||
deviceId: "DEVICE123",
|
||||
storageMeta: {
|
||||
homeserver: defaultStorageAuth.homeserver,
|
||||
userId: defaultStorageAuth.userId,
|
||||
accountId: "default",
|
||||
accessTokenHash: resolveDefaultStoragePaths({ accessToken: "secret-token-old" }).tokenHash,
|
||||
deviceId: "DEVICE123",
|
||||
},
|
||||
});
|
||||
fs.mkdirSync(oldStoragePaths.cryptoPath, { recursive: true });
|
||||
if (params.oldRootFiles === "thread-bindings") {
|
||||
writeJson(oldStoragePaths.rootDir, "thread-bindings.json", {
|
||||
version: 1,
|
||||
bindings: [
|
||||
{
|
||||
accountId: "default",
|
||||
conversationId: "$thread-old",
|
||||
targetKind: "subagent",
|
||||
targetSessionKey: "agent:ops:subagent:old",
|
||||
boundAt: 1,
|
||||
lastActivityAt: 1,
|
||||
},
|
||||
],
|
||||
});
|
||||
} else {
|
||||
writeJson(oldStoragePaths.rootDir, "startup-verification.json", {
|
||||
deviceId: "DEVICE123",
|
||||
});
|
||||
}
|
||||
|
||||
return { stateDir, canonicalPaths, oldStoragePaths };
|
||||
}
|
||||
|
||||
it("resolves state file paths inside the selected storage root", () => {
|
||||
setupStateDir();
|
||||
const filePath = resolveMatrixStateFilePath({
|
||||
@@ -497,53 +576,9 @@ describe("matrix client storage paths", () => {
|
||||
});
|
||||
|
||||
it("keeps the current-token storage root stable after deviceId backfill when startup claimed state there", () => {
|
||||
const stateDir = setupStateDir();
|
||||
const canonicalPaths = resolveMatrixAccountStorageRoot({
|
||||
stateDir,
|
||||
homeserver: defaultStorageAuth.homeserver,
|
||||
userId: defaultStorageAuth.userId,
|
||||
accessToken: "secret-token-new",
|
||||
});
|
||||
fs.mkdirSync(canonicalPaths.rootDir, { recursive: true });
|
||||
writeJson(canonicalPaths.rootDir, "storage-meta.json", {
|
||||
homeserver: defaultStorageAuth.homeserver,
|
||||
userId: defaultStorageAuth.userId,
|
||||
accountId: "default",
|
||||
accessTokenHash: canonicalPaths.tokenHash,
|
||||
deviceId: null,
|
||||
});
|
||||
writeJson(canonicalPaths.rootDir, "thread-bindings.json", {
|
||||
version: 1,
|
||||
bindings: [
|
||||
{
|
||||
accountId: "default",
|
||||
conversationId: "$thread-new",
|
||||
targetKind: "subagent",
|
||||
targetSessionKey: "agent:ops:subagent:new",
|
||||
boundAt: 1,
|
||||
lastActivityAt: 1,
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(
|
||||
claimCurrentTokenStorageState({
|
||||
rootDir: canonicalPaths.rootDir,
|
||||
}),
|
||||
).toBe(true);
|
||||
const oldStoragePaths = seedExistingStorageRoot({
|
||||
accessToken: "secret-token-old",
|
||||
deviceId: "DEVICE123",
|
||||
storageMeta: {
|
||||
homeserver: defaultStorageAuth.homeserver,
|
||||
userId: defaultStorageAuth.userId,
|
||||
accountId: "default",
|
||||
accessTokenHash: resolveDefaultStoragePaths({ accessToken: "secret-token-old" }).tokenHash,
|
||||
deviceId: "DEVICE123",
|
||||
},
|
||||
});
|
||||
fs.mkdirSync(oldStoragePaths.cryptoPath, { recursive: true });
|
||||
writeJson(oldStoragePaths.rootDir, "startup-verification.json", {
|
||||
deviceId: "DEVICE123",
|
||||
const { stateDir, canonicalPaths } = setupCurrentTokenBackfillScenario({
|
||||
currentRootFiles: "thread-bindings",
|
||||
oldRootFiles: "crypto-only",
|
||||
});
|
||||
|
||||
repairCurrentTokenStorageMetaDeviceId({
|
||||
@@ -572,48 +607,9 @@ describe("matrix client storage paths", () => {
|
||||
});
|
||||
|
||||
it("does not keep the current-token storage root sticky when only marker files exist after backfill", () => {
|
||||
const stateDir = setupStateDir();
|
||||
const canonicalPaths = resolveMatrixAccountStorageRoot({
|
||||
stateDir,
|
||||
homeserver: defaultStorageAuth.homeserver,
|
||||
userId: defaultStorageAuth.userId,
|
||||
accessToken: "secret-token-new",
|
||||
});
|
||||
fs.mkdirSync(canonicalPaths.rootDir, { recursive: true });
|
||||
writeJson(canonicalPaths.rootDir, "storage-meta.json", {
|
||||
homeserver: defaultStorageAuth.homeserver,
|
||||
userId: defaultStorageAuth.userId,
|
||||
accountId: "default",
|
||||
accessTokenHash: canonicalPaths.tokenHash,
|
||||
deviceId: null,
|
||||
});
|
||||
writeJson(canonicalPaths.rootDir, "startup-verification.json", {
|
||||
deviceId: "DEVICE123",
|
||||
});
|
||||
const oldStoragePaths = seedExistingStorageRoot({
|
||||
accessToken: "secret-token-old",
|
||||
deviceId: "DEVICE123",
|
||||
storageMeta: {
|
||||
homeserver: defaultStorageAuth.homeserver,
|
||||
userId: defaultStorageAuth.userId,
|
||||
accountId: "default",
|
||||
accessTokenHash: resolveDefaultStoragePaths({ accessToken: "secret-token-old" }).tokenHash,
|
||||
deviceId: "DEVICE123",
|
||||
},
|
||||
});
|
||||
fs.mkdirSync(oldStoragePaths.cryptoPath, { recursive: true });
|
||||
writeJson(oldStoragePaths.rootDir, "thread-bindings.json", {
|
||||
version: 1,
|
||||
bindings: [
|
||||
{
|
||||
accountId: "default",
|
||||
conversationId: "$thread-old",
|
||||
targetKind: "subagent",
|
||||
targetSessionKey: "agent:ops:subagent:old",
|
||||
boundAt: 1,
|
||||
lastActivityAt: 1,
|
||||
},
|
||||
],
|
||||
const { stateDir, oldStoragePaths } = setupCurrentTokenBackfillScenario({
|
||||
currentRootFiles: "startup-verification",
|
||||
oldRootFiles: "thread-bindings",
|
||||
});
|
||||
|
||||
repairCurrentTokenStorageMetaDeviceId({
|
||||
|
||||
Reference in New Issue
Block a user