test: harden Docker E2E readiness

This commit is contained in:
Peter Steinberger
2026-04-24 07:10:54 +01:00
parent 7ac35b4f69
commit bcea5e75eb
5 changed files with 47 additions and 32 deletions

View File

@@ -131,7 +131,7 @@ async function runCronCleanupScenario(params: {
payload: {
kind: "agentTurn",
message: "Use available context and then stop.",
timeoutSeconds: 12,
timeoutSeconds: 90,
lightContext: true,
},
delivery: { mode: "none" },
@@ -182,7 +182,7 @@ async function runCronCleanupScenario(params: {
entry.payload.jobId === job.id &&
entry.payload.action === "finished",
)?.payload,
90_000,
150_000,
);
assert(finished, "missing cron finished event");
@@ -212,7 +212,7 @@ async function runSubagentCleanupScenario(params: {
cleanupBundleMcpOnRunEnd: true,
idempotencyKey: randomUUID(),
deliver: false,
timeout: 20,
timeout: 90,
bestEffortDeliver: true,
});
assert(

View File

@@ -34,16 +34,21 @@ async function main() {
mcp = mcpHandle.client;
}
const listed = (await mcp.callTool({
name: "conversations_list",
arguments: {},
})) as {
structuredContent?: { conversations?: Array<Record<string, unknown>> };
};
const conversation = listed.structuredContent?.conversations?.find(
(entry) => entry.sessionKey === "agent:main:main",
const conversation = await waitFor(
"seeded conversation in conversations_list",
async () => {
const listed = (await mcp.callTool({
name: "conversations_list",
arguments: {},
})) as {
structuredContent?: { conversations?: Array<Record<string, unknown>> };
};
return listed.structuredContent?.conversations?.find(
(entry) => entry.sessionKey === "agent:main:main",
);
},
240_000,
);
assert(conversation, "expected seeded conversation in conversations_list");
assert(conversation.channel === "imessage", "expected seeded channel");
assert(conversation.to === "+15551234567", "expected seeded target");
@@ -60,19 +65,31 @@ async function main() {
"conversation_get returned wrong session",
);
const history = (await mcp.callTool({
name: "messages_read",
arguments: { session_key: "agent:main:main", limit: 10 },
})) as {
structuredContent?: { messages?: Array<Record<string, unknown>> };
};
const messages = history.structuredContent?.messages ?? [];
assert(messages.length >= 2, "expected seeded transcript messages");
const attachmentMessage = messages.find((entry) => {
const raw = entry.__openclaw;
return raw && typeof raw === "object" && (raw as { id?: unknown }).id === "msg-attachment";
});
assert(attachmentMessage, "expected seeded attachment message");
const messages = await waitFor(
"seeded transcript messages",
async () => {
const history = (await mcp.callTool({
name: "messages_read",
arguments: { session_key: "agent:main:main", limit: 10 },
})) as {
structuredContent?: { messages?: Array<Record<string, unknown>> };
};
const currentMessages = history.structuredContent?.messages ?? [];
return currentMessages.length >= 2 ? currentMessages : undefined;
},
240_000,
);
await waitFor(
"seeded attachment message",
() =>
messages.find((entry) => {
const raw = entry.__openclaw;
return (
raw && typeof raw === "object" && (raw as { id?: unknown }).id === "msg-attachment"
);
}),
240_000,
);
const attachments = (await mcp.callTool({
name: "attachments_fetch",

View File

@@ -74,12 +74,12 @@ export function extractTextFromGatewayPayload(
export async function waitFor<T>(
label: string,
predicate: () => T | undefined,
predicate: () => Promise<T | undefined> | T | undefined,
timeoutMs = 10_000,
): Promise<T> {
const started = Date.now();
while (Date.now() - started < timeoutMs) {
const value = predicate();
const value = await predicate();
if (value !== undefined) {
return value;
}

View File

@@ -432,10 +432,8 @@ if (!serialized.includes(token)) {
}
NODE
assert_dep_present "$DEP_SENTINEL"
echo "Running doctor after activated plugin dep install..."
openclaw doctor --non-interactive >/tmp/openclaw-doctor.log 2>&1
echo "Running doctor after channel activation..."
openclaw doctor --repair --non-interactive >/tmp/openclaw-doctor.log 2>&1
assert_dep_present "$DEP_SENTINEL"
echo "Running local agent turn against mocked OpenAI..."