Skip to content

Commit 8a9cb7c

Browse files
Merge pull request #190 from cloudflare/fix-ci
fix(e2e): find start-openclaw.sh process correctly in log dump
2 parents 5593ac1 + 810dfb7 commit 8a9cb7c

7 files changed

Lines changed: 52 additions & 37 deletions

File tree

src/gateway/sync.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ describe('syncToR2', () => {
4343
const { sandbox, startProcessMock } = createMockSandbox();
4444
startProcessMock
4545
.mockResolvedValueOnce(createMockProcess('s3fs on /data/moltbot type fuse.s3fs\n'))
46-
.mockResolvedValueOnce(createMockProcess('')) // No openclaw.json
47-
.mockResolvedValueOnce(createMockProcess('')); // No clawdbot.json either
46+
.mockResolvedValueOnce(createMockProcess('', { exitCode: 1 })) // No openclaw.json
47+
.mockResolvedValueOnce(createMockProcess('', { exitCode: 1 })); // No clawdbot.json either
4848

4949
const env = createMockEnvWithR2();
5050

src/gateway/sync.ts

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -43,21 +43,15 @@ export async function syncToR2(sandbox: Sandbox, env: MoltbotEnv): Promise<SyncR
4343

4444
// Determine which config directory exists
4545
// Check new path first, fall back to legacy
46+
// Use exit code (0 = exists) rather than stdout parsing to avoid log-flush races
4647
let configDir = '/root/.openclaw';
4748
try {
48-
const checkNew = await sandbox.startProcess(
49-
'test -f /root/.openclaw/openclaw.json && echo "ok"',
50-
);
49+
const checkNew = await sandbox.startProcess('test -f /root/.openclaw/openclaw.json');
5150
await waitForProcess(checkNew, 5000);
52-
const newLogs = await checkNew.getLogs();
53-
if (!newLogs.stdout?.includes('ok')) {
54-
// Try legacy path
55-
const checkLegacy = await sandbox.startProcess(
56-
'test -f /root/.clawdbot/clawdbot.json && echo "ok"',
57-
);
51+
if (checkNew.exitCode !== 0) {
52+
const checkLegacy = await sandbox.startProcess('test -f /root/.clawdbot/clawdbot.json');
5853
await waitForProcess(checkLegacy, 5000);
59-
const legacyLogs = await checkLegacy.getLogs();
60-
if (legacyLogs.stdout?.includes('ok')) {
54+
if (checkLegacy.exitCode === 0) {
6155
configDir = '/root/.clawdbot';
6256
} else {
6357
return {

src/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,12 @@ async function scheduled(
456456
const options = buildSandboxOptions(env);
457457
const sandbox = getSandbox(env.Sandbox, 'moltbot', options);
458458

459+
const gatewayProcess = await findExistingMoltbotProcess(sandbox);
460+
if (!gatewayProcess) {
461+
console.log('[cron] Gateway not running yet, skipping sync');
462+
return;
463+
}
464+
459465
console.log('[cron] Starting backup sync to R2...');
460466
const result = await syncToR2(sandbox, env);
461467

test/e2e/_setup.txt

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ start playwright browser
1313
===
1414
./start-browser
1515
---
16-
ready
16+
{{ output }}
17+
---
18+
where
19+
* strip(output) endswith "ready"
1720

1821
===
1922
start video recording
@@ -31,7 +34,11 @@ navigate to main page and wait for worker to be ready
3134
===
3235
TOKEN=$(cat "$CCTR_FIXTURE_DIR/gateway-token.txt")
3336
WORKER_URL=$(cat "$CCTR_FIXTURE_DIR/worker-url.txt")
34-
./pw --session=moltworker-e2e open "$WORKER_URL/?token=$TOKEN"
37+
# Use page.goto() instead of 'open' — 'open' creates a new browser process,
38+
# which loses the CF-Access headers set via setExtraHTTPHeaders in start-browser.
39+
./pw --session=moltworker-e2e run-code "async page => {
40+
await page.goto('$WORKER_URL/?token=$TOKEN');
41+
}"
3542
# Wait for pairing required message (worker shows loading screen first, then UI loads)
3643
./pw --session=moltworker-e2e run-code "async page => {
3744
await page.waitForSelector('text=Pairing required', { timeout: 480000 });

test/e2e/_teardown.txt

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,13 @@ dump gateway logs for debugging
44
WORKER_URL=$(cat "$CCTR_FIXTURE_DIR/worker-url.txt" 2>/dev/null || echo "")
55
if [ -n "$WORKER_URL" ]; then
66
PROCS=$(./curl-auth -s "$WORKER_URL/debug/processes" 2>/dev/null || echo "")
7-
PROC_ID=$(echo "$PROCS" | grep -o '"id":"[^"]*"' | head -1 | cut -d'"' -f4)
7+
PROC_ID=$(echo "$PROCS" | jq -r '[.processes[] | select(.command | contains("start-openclaw"))][0].id // empty' 2>/dev/null)
88
if [ -n "$PROC_ID" ]; then
99
echo "=== Gateway process logs ($PROC_ID) ==="
10-
./curl-auth -s "$WORKER_URL/debug/logs?id=$PROC_ID" 2>/dev/null | python3 -c "
11-
import sys, json
12-
try:
13-
d = json.load(sys.stdin)
14-
if d.get('stdout'): print('STDOUT:', d['stdout'][-3000:])
15-
if d.get('stderr'): print('STDERR:', d['stderr'][-3000:])
16-
except: print('Failed to parse logs')
17-
" || echo "Failed to fetch logs"
10+
LOGS=$(./curl-auth -s "$WORKER_URL/debug/logs?id=$PROC_ID" 2>/dev/null)
11+
echo "$LOGS" | jq -r '"STATUS: \(.process_status)\nSTDOUT: \(.stdout)\nSTDERR: \(.stderr)"' 2>/dev/null || echo "Failed to parse logs"
1812
else
19-
echo "No gateway process found"
13+
echo "No start-openclaw.sh process found"
2014
echo "Processes: $PROCS"
2115
fi
2216
else

test/e2e/fixture/start-browser

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,40 +4,38 @@
44
set -e
55

66
SESSION_NAME="moltworker-e2e"
7-
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
87

98
# Support running directly (not via cctr)
109
if [ -z "$CCTR_FIXTURE_DIR" ]; then
1110
CCTR_FIXTURE_DIR="/tmp/e2e-cloud-manual"
1211
fi
1312

14-
# Stop and delete any existing session
15-
playwright-cli session-stop "$SESSION_NAME" >/dev/null 2>&1 || true
16-
playwright-cli session-delete "$SESSION_NAME" >/dev/null 2>&1 || true
17-
1813
# Build the args
1914
GLOBAL_ARGS=("--session=$SESSION_NAME")
2015

2116
if [ "${PLAYWRIGHT_HEADED:-}" = "1" ] || [ "${PLAYWRIGHT_HEADED:-}" = "true" ]; then
2217
GLOBAL_ARGS+=("--headed")
2318
fi
2419

25-
# Open the browser to a blank page first
26-
playwright-cli "${GLOBAL_ARGS[@]}" open "about:blank" >/dev/null 2>&1 &
27-
sleep 2
20+
# Open the browser to a blank page first (output to stderr to keep stdout clean for cctr)
21+
playwright-cli "${GLOBAL_ARGS[@]}" open "about:blank" >&2 &
22+
sleep 20
2823

2924
# Read Access credentials
3025
CF_ACCESS_CLIENT_ID=$(cat "$CCTR_FIXTURE_DIR/cf-access-client-id.txt" 2>/dev/null || echo "")
3126
CF_ACCESS_CLIENT_SECRET=$(cat "$CCTR_FIXTURE_DIR/cf-access-client-secret.txt" 2>/dev/null || echo "")
3227

3328
if [ -n "$CF_ACCESS_CLIENT_ID" ] && [ -n "$CF_ACCESS_CLIENT_SECRET" ]; then
34-
# Set extra HTTP headers for Access authentication
29+
# Set extra HTTP headers for Access authentication (output to stderr).
30+
# IMPORTANT: All subsequent navigation MUST use 'run-code page.goto()' instead of 'open',
31+
# because 'open' creates a new browser process which loses these headers.
3532
playwright-cli "${GLOBAL_ARGS[@]}" run-code "async page => {
3633
await page.context().setExtraHTTPHeaders({
3734
'CF-Access-Client-Id': '$CF_ACCESS_CLIENT_ID',
3835
'CF-Access-Client-Secret': '$CF_ACCESS_CLIENT_SECRET'
3936
});
40-
}" >/dev/null 2>&1
37+
}" >&2
4138
fi
4239

40+
sleep 1 # Let stderr flush before stdout
4341
echo "ready"

test/e2e/pairing_and_conversation.txt

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ navigate to admin page to approve device
44
===
55
TOKEN=$(cat "$CCTR_FIXTURE_DIR/gateway-token.txt")
66
WORKER_URL=$(cat "$CCTR_FIXTURE_DIR/worker-url.txt")
7-
./pw --session=moltworker-e2e open "$WORKER_URL/_admin/?token=$TOKEN"
7+
./pw --session=moltworker-e2e run-code "async page => {
8+
await page.goto('$WORKER_URL/_admin/?token=$TOKEN');
9+
}"
810
---
911

1012
===
@@ -41,7 +43,9 @@ navigate back to main chat page
4143
===
4244
TOKEN=$(cat "$CCTR_FIXTURE_DIR/gateway-token.txt")
4345
WORKER_URL=$(cat "$CCTR_FIXTURE_DIR/worker-url.txt")
44-
./pw --session=moltworker-e2e open "$WORKER_URL/?token=$TOKEN"
46+
./pw --session=moltworker-e2e run-code "async page => {
47+
await page.goto('$WORKER_URL/?token=$TOKEN');
48+
}"
4549
---
4650

4751
===
@@ -53,6 +57,18 @@ wait for chat interface to load
5357
}"
5458
---
5559

60+
===
61+
send /models command
62+
%require
63+
===
64+
./pw --session=moltworker-e2e run-code "async page => {
65+
const textarea = await page.waitForSelector('textarea');
66+
await textarea.fill('/models');
67+
const btn = await page.waitForSelector('button:has-text(\"Send\")');
68+
await btn.click();
69+
}"
70+
---
71+
5672
===
5773
type math question into chat
5874
%require

0 commit comments

Comments
 (0)