mirror of
https://fastgit.cc/github.com/openclaw/openclaw
synced 2026-04-30 14:02:56 +08:00
fix(matrix): avoid device cleanup sync races
This commit is contained in:
@@ -96,7 +96,7 @@ describe("matrix device actions", () => {
|
||||
},
|
||||
],
|
||||
}));
|
||||
withStartedActionClientMock.mockImplementation(async (_opts, run) => {
|
||||
withResolvedActionClientMock.mockImplementation(async (_opts, run) => {
|
||||
return await run({
|
||||
listOwnDevices: vi.fn(async () => [
|
||||
{
|
||||
@@ -150,5 +150,10 @@ describe("matrix device actions", () => {
|
||||
current: true,
|
||||
}),
|
||||
]);
|
||||
expect(withResolvedActionClientMock).toHaveBeenCalledWith(
|
||||
{ accountId: "poe" },
|
||||
expect.any(Function),
|
||||
);
|
||||
expect(withStartedActionClientMock).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { summarizeMatrixDeviceHealth } from "../device-health.js";
|
||||
import { withResolvedActionClient, withStartedActionClient } from "./client.js";
|
||||
import { withResolvedActionClient } from "./client.js";
|
||||
import type { MatrixActionClientOpts } from "./types.js";
|
||||
|
||||
export async function listMatrixOwnDevices(opts: MatrixActionClientOpts = {}) {
|
||||
@@ -7,7 +7,7 @@ export async function listMatrixOwnDevices(opts: MatrixActionClientOpts = {}) {
|
||||
}
|
||||
|
||||
export async function pruneMatrixStaleGatewayDevices(opts: MatrixActionClientOpts = {}) {
|
||||
return await withStartedActionClient(opts, async (client) => {
|
||||
return await withResolvedActionClient(opts, async (client) => {
|
||||
const devices = await client.listOwnDevices();
|
||||
const health = summarizeMatrixDeviceHealth(devices);
|
||||
const staleGatewayDeviceIds = health.staleOpenClawDevices.map((device) => device.deviceId);
|
||||
|
||||
@@ -81,6 +81,19 @@ type MatrixQaDestructiveSetup = {
|
||||
seededEventId: string;
|
||||
};
|
||||
|
||||
async function cleanupMatrixQaTempDevices(
|
||||
client: MatrixQaE2eeScenarioClient,
|
||||
deviceIds: Array<string | null | undefined>,
|
||||
): Promise<void> {
|
||||
await client.stop().catch(() => undefined);
|
||||
const uniqueDeviceIds = [
|
||||
...new Set(deviceIds.filter((deviceId): deviceId is string => !!deviceId)),
|
||||
];
|
||||
if (uniqueDeviceIds.length > 0) {
|
||||
await client.deleteOwnDevices(uniqueDeviceIds).catch(() => undefined);
|
||||
}
|
||||
}
|
||||
|
||||
function requireMatrixQaE2eeOutputDir(context: MatrixQaScenarioContext) {
|
||||
if (!context.outputDir) {
|
||||
throw new Error("Matrix E2EE destructive QA scenarios require an output directory");
|
||||
@@ -668,8 +681,7 @@ export async function runMatrixQaE2eeStateLossExternalRecoveryKeyScenario(
|
||||
};
|
||||
} finally {
|
||||
await cli.dispose().catch(() => undefined);
|
||||
await setup.owner.deleteOwnDevices([device.deviceId]).catch(() => undefined);
|
||||
await setup.owner.stop().catch(() => undefined);
|
||||
await cleanupMatrixQaTempDevices(setup.owner, [device.deviceId]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -748,8 +760,7 @@ export async function runMatrixQaE2eeStateLossStoredRecoveryKeyScenario(
|
||||
};
|
||||
} finally {
|
||||
await cli.dispose().catch(() => undefined);
|
||||
await setup.owner.deleteOwnDevices([device.deviceId]).catch(() => undefined);
|
||||
await setup.owner.stop().catch(() => undefined);
|
||||
await cleanupMatrixQaTempDevices(setup.owner, [device.deviceId]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -793,8 +804,7 @@ export async function runMatrixQaE2eeStateLossNoRecoveryKeyScenario(
|
||||
};
|
||||
} finally {
|
||||
await cli.dispose().catch(() => undefined);
|
||||
await setup.owner.deleteOwnDevices([device.deviceId]).catch(() => undefined);
|
||||
await setup.owner.stop().catch(() => undefined);
|
||||
await cleanupMatrixQaTempDevices(setup.owner, [device.deviceId]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -863,8 +873,7 @@ export async function runMatrixQaE2eeStaleRecoveryKeyAfterBackupResetScenario(
|
||||
};
|
||||
} finally {
|
||||
await cli.dispose().catch(() => undefined);
|
||||
await setup.owner.deleteOwnDevices([device.deviceId]).catch(() => undefined);
|
||||
await setup.owner.stop().catch(() => undefined);
|
||||
await cleanupMatrixQaTempDevices(setup.owner, [device.deviceId]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1026,8 +1035,7 @@ export async function runMatrixQaE2eeServerBackupDeletedLocalReuploadRestoresSce
|
||||
};
|
||||
} finally {
|
||||
await cli.dispose().catch(() => undefined);
|
||||
await setup.owner.deleteOwnDevices([device.deviceId]).catch(() => undefined);
|
||||
await setup.owner.stop().catch(() => undefined);
|
||||
await cleanupMatrixQaTempDevices(setup.owner, [device.deviceId]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1101,8 +1109,7 @@ export async function runMatrixQaE2eeCorruptCryptoIdbSnapshotScenario(
|
||||
};
|
||||
} finally {
|
||||
await cli.dispose().catch(() => undefined);
|
||||
await setup.owner.deleteOwnDevices([device.deviceId]).catch(() => undefined);
|
||||
await setup.owner.stop().catch(() => undefined);
|
||||
await cleanupMatrixQaTempDevices(setup.owner, [device.deviceId]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1141,6 +1148,7 @@ export async function runMatrixQaE2eeServerDeviceDeletedLocalStateIntactScenario
|
||||
assertMatrixQaCliBackupRestoreSucceeded(restored.payload, "deleted-device preflight");
|
||||
await setup.owner.deleteOwnDevices([device.deviceId]);
|
||||
const ownerDevicesAfterDelete = await setup.owner.listOwnDevices();
|
||||
await setup.owner.stop().catch(() => undefined);
|
||||
const defaultStatus = await runMatrixQaCliJson<MatrixQaCliVerificationStatus>({
|
||||
allowNonZero: true,
|
||||
args: ["matrix", "verify", "status", "--account", "deleted-device", "--json"],
|
||||
@@ -1238,6 +1246,7 @@ export async function runMatrixQaE2eeServerDeviceDeletedReloginRecoversScenario(
|
||||
|
||||
await setup.owner.deleteOwnDevices([deleted.device.deviceId]);
|
||||
const ownerDevicesAfterDelete = await setup.owner.listOwnDevices();
|
||||
await setup.owner.stop().catch(() => undefined);
|
||||
const defaultStatus = await runMatrixQaCliJson<MatrixQaCliVerificationStatus>({
|
||||
allowNonZero: true,
|
||||
args: ["matrix", "verify", "status", "--account", "deleted-device-recovery", "--json"],
|
||||
@@ -1322,12 +1331,11 @@ export async function runMatrixQaE2eeServerDeviceDeletedReloginRecoversScenario(
|
||||
};
|
||||
} finally {
|
||||
await replacement?.cli.dispose().catch(() => undefined);
|
||||
if (replacement?.device.deviceId) {
|
||||
await setup.owner.deleteOwnDevices([replacement.device.deviceId]).catch(() => undefined);
|
||||
}
|
||||
await deleted.cli.dispose().catch(() => undefined);
|
||||
await setup.owner.deleteOwnDevices([deleted.device.deviceId]).catch(() => undefined);
|
||||
await setup.owner.stop().catch(() => undefined);
|
||||
await cleanupMatrixQaTempDevices(setup.owner, [
|
||||
replacement?.device.deviceId,
|
||||
deleted.device.deviceId,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1566,6 +1574,7 @@ export async function runMatrixQaE2eeWrongAccountRecoveryKeyScenario(
|
||||
};
|
||||
} finally {
|
||||
await cli?.dispose().catch(() => undefined);
|
||||
await observer.stop().catch(() => undefined);
|
||||
if (device) {
|
||||
await observer.deleteOwnDevices([device.deviceId]).catch(() => undefined);
|
||||
}
|
||||
@@ -1627,7 +1636,6 @@ export async function runMatrixQaE2eeHistoryExistsBackupEmptyScenario(
|
||||
};
|
||||
} finally {
|
||||
await cli.dispose().catch(() => undefined);
|
||||
await setup.owner.deleteOwnDevices([device.deviceId]).catch(() => undefined);
|
||||
await setup.owner.stop().catch(() => undefined);
|
||||
await cleanupMatrixQaTempDevices(setup.owner, [device.deviceId]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1495,6 +1495,7 @@ export async function runMatrixQaE2eeRecoveryKeyLifecycleScenario(
|
||||
}
|
||||
}
|
||||
await recoveryClient.stop();
|
||||
await client.stop().catch(() => undefined);
|
||||
await client.deleteOwnDevices([recoveryDevice.deviceId]).catch(() => undefined);
|
||||
cleanupRecoveryDevice = false;
|
||||
return {
|
||||
@@ -1530,6 +1531,7 @@ export async function runMatrixQaE2eeRecoveryKeyLifecycleScenario(
|
||||
} finally {
|
||||
if (cleanupRecoveryDevice) {
|
||||
await recoveryClient.stop().catch(() => undefined);
|
||||
await client.stop().catch(() => undefined);
|
||||
await client.deleteOwnDevices([recoveryDevice.deviceId]).catch(() => undefined);
|
||||
}
|
||||
}
|
||||
@@ -1609,6 +1611,7 @@ export async function runMatrixQaE2eeRecoveryOwnerVerificationRequiredScenario(
|
||||
].join("\n"),
|
||||
};
|
||||
} finally {
|
||||
await client.stop().catch(() => undefined);
|
||||
await client.deleteOwnDevices([recoveryDevice.deviceId]).catch(() => undefined);
|
||||
}
|
||||
},
|
||||
@@ -3136,6 +3139,7 @@ export async function runMatrixQaE2eeStaleDeviceHygieneScenario(
|
||||
if (!before.some((device) => device.deviceId === secondary.deviceId)) {
|
||||
throw new Error("Matrix stale-device list did not include the secondary login");
|
||||
}
|
||||
await client.stop().catch(() => undefined);
|
||||
const deleted = await client.deleteOwnDevices([secondary.deviceId]);
|
||||
const remainingDeviceIds = deleted.remainingDevices.map((device) => device.deviceId);
|
||||
if (remainingDeviceIds.includes(secondary.deviceId)) {
|
||||
|
||||
Reference in New Issue
Block a user