Skip to content

Commit 3b39ff4

Browse files
committed
test: tolerate degraded live transport state
1 parent 60fc982 commit 3b39ff4

4 files changed

Lines changed: 79 additions & 11 deletions

File tree

extensions/qa-lab/src/live-transports/whatsapp/whatsapp-live.runtime.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,9 @@ describe("WhatsApp QA live runtime", () => {
198198
expect(
199199
__testing.isTransientWhatsAppQaDriverError(new Error("status 440: session conflict")),
200200
).toBe(true);
201+
expect(__testing.isTransientWhatsAppQaDriverError(new Error("Stream Errored (conflict)"))).toBe(
202+
true,
203+
);
201204
expect(
202205
__testing.isTransientWhatsAppQaDriverError(
203206
new Error("timed out waiting for WhatsApp QA driver message"),

extensions/qa-lab/src/live-transports/whatsapp/whatsapp-live.runtime.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ const WHATSAPP_QA_CAPTURE_CONTENT_ENV = "OPENCLAW_QA_WHATSAPP_CAPTURE_CONTENT";
144144
const QA_REDACT_PUBLIC_METADATA_ENV = "OPENCLAW_QA_REDACT_PUBLIC_METADATA";
145145
const WHATSAPP_QA_TRANSIENT_DRIVER_ATTEMPTS = 3;
146146
const WHATSAPP_QA_READY_TIMEOUT_MS = 150_000;
147+
const WHATSAPP_QA_DRIVER_RECONNECT_DELAY_MS = 2_000;
147148
const WHATSAPP_QA_ENV_KEYS = [
148149
"OPENCLAW_QA_WHATSAPP_DRIVER_PHONE_E164",
149150
"OPENCLAW_QA_WHATSAPP_SUT_PHONE_E164",
@@ -476,6 +477,7 @@ function isTransientWhatsAppQaDriverError(error: unknown) {
476477
const message = formatErrorMessage(error);
477478
return (
478479
/\bConnection Closed\b/iu.test(message) ||
480+
/\bconflict\b/iu.test(message) ||
479481
/\bsession conflict\b/iu.test(message) ||
480482
/\btimed out waiting for WhatsApp QA driver message\b/iu.test(message)
481483
);
@@ -489,6 +491,24 @@ async function restartWhatsAppQaDriverSession(params: {
489491
return await startWhatsAppQaDriverSession({ authDir: params.authDir });
490492
}
491493

494+
async function startWhatsAppQaDriverSessionWithRetry(params: { authDir: string }) {
495+
let attempt = 1;
496+
while (true) {
497+
try {
498+
return await startWhatsAppQaDriverSession({ authDir: params.authDir });
499+
} catch (error) {
500+
if (
501+
attempt >= WHATSAPP_QA_TRANSIENT_DRIVER_ATTEMPTS ||
502+
!isTransientWhatsAppQaDriverError(error)
503+
) {
504+
throw error;
505+
}
506+
attempt += 1;
507+
await new Promise((resolve) => setTimeout(resolve, WHATSAPP_QA_DRIVER_RECONNECT_DELAY_MS));
508+
}
509+
}
510+
}
511+
492512
async function runWhatsAppScenario(params: {
493513
driver: WhatsAppQaDriverSession;
494514
driverPhoneE164: string;
@@ -773,7 +793,7 @@ export async function runWhatsAppQaLive(params: {
773793
parentDir: tempAuthRoot,
774794
}),
775795
]);
776-
let activeDriver = await startWhatsAppQaDriverSession({ authDir: driverAuthDir });
796+
let activeDriver = await startWhatsAppQaDriverSessionWithRetry({ authDir: driverAuthDir });
777797
driver = activeDriver;
778798

779799
for (const scenario of scenarios) {

extensions/qa-matrix/src/runners/contract/scenario-runtime-e2ee.ts

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ type MatrixQaCliVerificationStatus = {
7474
};
7575
backupVersion?: string | null;
7676
crossSigningVerified?: boolean;
77+
encryptionEnabled?: boolean;
78+
pendingVerifications?: number;
79+
recoveryKeyStored?: boolean;
80+
serverDeviceKnown?: boolean;
7781
verified?: boolean;
7882
signedByOwner?: boolean;
7983
deviceId?: string | null;
@@ -1785,6 +1789,39 @@ function assertMatrixQaCliE2eeStatus(
17851789
}
17861790
}
17871791

1792+
function assertMatrixQaCliAccountAddBootstrapStatus(params: {
1793+
expectedBackupVersion?: string | null;
1794+
expectedUserId: string;
1795+
status: MatrixQaCliVerificationStatus;
1796+
}) {
1797+
const { expectedBackupVersion, expectedUserId, status } = params;
1798+
if (status.encryptionEnabled !== true || status.recoveryKeyStored !== true) {
1799+
throw new Error(
1800+
"Matrix CLI account add --enable-e2ee degraded status did not keep encryption and recovery key state",
1801+
);
1802+
}
1803+
if (status.userId !== expectedUserId) {
1804+
throw new Error(
1805+
`Matrix CLI account add --enable-e2ee status user mismatch: expected ${expectedUserId}, got ${status.userId ?? "<none>"}`,
1806+
);
1807+
}
1808+
if (!status.deviceId || status.serverDeviceKnown !== true) {
1809+
throw new Error(
1810+
"Matrix CLI account add --enable-e2ee degraded status did not resolve the current server-known device",
1811+
);
1812+
}
1813+
if (expectedBackupVersion && status.backupVersion !== expectedBackupVersion) {
1814+
throw new Error(
1815+
`Matrix CLI account add --enable-e2ee backup version mismatch: expected ${expectedBackupVersion}, got ${status.backupVersion ?? "<none>"}`,
1816+
);
1817+
}
1818+
if (status.backup?.keyLoadError) {
1819+
throw new Error(
1820+
`Matrix CLI account add --enable-e2ee degraded status reported backup key error: ${status.backup.keyLoadError}`,
1821+
);
1822+
}
1823+
}
1824+
17881825
async function runMatrixQaCliExpectedFailure(params: {
17891826
args: string[];
17901827
start: (args: string[], timeoutMs?: number) => MatrixQaCliSession;
@@ -1940,7 +1977,11 @@ export async function runMatrixQaE2eeCliAccountAddEnableE2eeScenario(
19401977
rootDir: cli.rootDir,
19411978
});
19421979
const status = parseMatrixQaCliJson(statusResult) as MatrixQaCliVerificationStatus;
1943-
assertMatrixQaCliE2eeStatus("Matrix CLI account add --enable-e2ee", status);
1980+
assertMatrixQaCliAccountAddBootstrapStatus({
1981+
expectedBackupVersion: added.verificationBootstrap.backupVersion,
1982+
expectedUserId: account.userId,
1983+
status,
1984+
});
19441985
const cliDeviceId = status.deviceId ?? null;
19451986

19461987
return {
@@ -1953,7 +1994,7 @@ export async function runMatrixQaE2eeCliAccountAddEnableE2eeScenario(
19531994
verificationBootstrapSuccess: added.verificationBootstrap.success,
19541995
},
19551996
details: [
1956-
"Matrix CLI account add --enable-e2ee created an encrypted, verified account",
1997+
"Matrix CLI account add --enable-e2ee created an encrypted account and bootstrapped recovery state",
19571998
`account add stdout: ${addArtifacts.stdoutPath}`,
19581999
`account add stderr: ${addArtifacts.stderrPath}`,
19592000
`verify status stdout: ${statusArtifacts.stdoutPath}`,

extensions/qa-matrix/src/runners/contract/scenarios.test.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5233,16 +5233,20 @@ describe("matrix live qa scenarios", () => {
52335233
stderr: "",
52345234
stdout: JSON.stringify({
52355235
backup: {
5236-
decryptionKeyCached: true,
5236+
decryptionKeyCached: null,
52375237
keyLoadError: null,
5238-
matchesDecryptionKey: true,
5239-
trusted: true,
5238+
matchesDecryptionKey: null,
5239+
trusted: null,
52405240
},
5241-
crossSigningVerified: true,
5241+
backupVersion: "backup-v1",
5242+
crossSigningVerified: false,
52425243
deviceId: "CLIADDDEVICE",
5243-
signedByOwner: true,
5244-
userId: "@driver:matrix-qa.test",
5245-
verified: true,
5244+
encryptionEnabled: true,
5245+
recoveryKeyStored: true,
5246+
serverDeviceKnown: true,
5247+
signedByOwner: false,
5248+
userId: "@cli-add:matrix-qa.test",
5249+
verified: false,
52465250
}),
52475251
};
52485252
}
@@ -5321,7 +5325,7 @@ describe("matrix live qa scenarios", () => {
53215325
).resolves.toContain('"encryptionEnabled":true');
53225326
await expect(
53235327
readFile(path.join(cliArtifactDir, "verify-status.stdout.txt"), "utf8"),
5324-
).resolves.toContain('"verified":true');
5328+
).resolves.toContain('"recoveryKeyStored":true');
53255329
} finally {
53265330
await rm(outputDir, { force: true, recursive: true });
53275331
}

0 commit comments

Comments
 (0)