Skip to content

test(ci): OS-level sidecar watcher for the Windows silent ELIFECYCLE#7846

Merged
JohnMcLear merged 1 commit into
developfrom
test-ci-flake-os-sidecar-watcher
May 26, 2026
Merged

test(ci): OS-level sidecar watcher for the Windows silent ELIFECYCLE#7846
JohnMcLear merged 1 commit into
developfrom
test-ci-flake-os-sidecar-watcher

Conversation

@JohnMcLear
Copy link
Copy Markdown
Member

Summary

Adds a bash background loop to both Windows backend-test steps (with- and without-plugins) that polls Windows OS state every 500 ms and writes to the existing node-report/ artifact directory:

  • netstat.log — localhost TCP socket states (ESTABLISHED / TIME_WAIT / CLOSE_WAIT / FIN_WAIT) per tick.
  • tasklist.lognode.exe process handle count, working set, CPU time per tick.

Why

Eleven captured silent-ELIFECYCLE deaths from the merged in-process diagnostics (#7838, #7842) all share the same shape: the V8 main isolate goes event-loop-starved for 200–400 ms (5 Hz heartbeat falls silent), then the process is externally terminated bypassing all JS handlers, --report-on-fatalerror, and --report-uncaught-exception. The libuv handle list in our pre-kill node-report snapshots is nominal — but libuv only knows about handles Node currently owns. The kernel can hold many more sockets in disposal states (TIME_WAIT etc.) that we never see.

To capture state during the starvation window we need a probe whose scheduling doesn't depend on the dying process's event loop. A bash background loop is the simplest such probe — its scheduling is the runner's bash, not the Node isolate.

What this changes

Workflow-only — no code changes. Both Windows steps now wrap pnpm test -- --exit like this:

( while true; do
    ts=$(date '+%H:%M:%S.%3N')
    { echo "=== $ts ==="; netstat -an | grep TCP ...; } >> "$OUT/netstat.log"
    { echo "=== $ts ==="; tasklist /v /fi "imagename eq node.exe" /fo csv; } >> "$OUT/tasklist.log"
    sleep 0.5
done ) &
WATCHER_PID=$!
set +e; pnpm test -- --exit; EXIT=$?; set -e
kill "$WATCHER_PID" 2>/dev/null || true
exit $EXIT

Linux jobs are untouched (the flake is Windows-only).

Expected next capture

On the next silent ELIFECYCLE Win+plugins failure we'll get, for the first time:

  • 500 ms-resolution external snapshots of localhost TCP state across the death window
  • Node process handle count from the OS view independent of V8 responsiveness

Either signal can be the smoking gun (or rule out a class of hypotheses, e.g. TIME_WAIT exhaustion).

Risk

netstat -an and tasklist are cheap. The sleep loop runs in its own bash process so it doesn't compete with Node for the event loop. 500 ms cadence keeps CPU overhead negligible.

🤖 Generated with Claude Code

In-process diagnostics (diagnostics.ts heartbeat at 5 Hz + node-report
snapshots on every beforeEach and heartbeat tick) merged in #7838 and
#7842 reach a hard ceiling: during every captured death window the V8
main isolate is event-loop-starved for 200-400 ms before the process
is externally terminated, so any timer-driven probe (heartbeat,
setTimeout, --report-on-signal handler) never gets serviced and we
have zero JS-visible state from the actual moment of death.

To capture state during the starvation window we need a probe whose
own scheduling does not depend on the dying process's libuv event
loop. This commit adds a tiny bash background loop to the Windows
backend-test steps (both with- and without-plugins). Every 500 ms it
appends:
  - netstat.log: localhost TCP socket state — surfaces TIME_WAIT /
    CLOSE_WAIT accumulation or ephemeral-port exhaustion that the
    in-process libuv handle list can't see (libuv only shows handles
    Node currently knows about; the kernel may hold many more sockets
    in disposal states).
  - tasklist.log: node.exe process state from the Windows OS view
    (handle count, working set, CPU time), independent of whether V8
    is responsive.

Both files land in $GITHUB_WORKSPACE/node-report/ which is already
the artifact-upload target on failure, so they ride for free on
existing infrastructure. The watcher is killed cleanly after `pnpm
test` returns so it never holds the runner open.

On the next captured silent ELIFECYCLE we'll have, for the first
time, a 500 ms-resolution external observation of TCP and process
state across the death window.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@qodo-code-review
Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@qodo-free-for-open-source-projects
Copy link
Copy Markdown

Review Summary by Qodo

Add OS-level sidecar watcher for Windows silent ELIFECYCLE flake

🧪 Tests ✨ Enhancement

Grey Divider

Walkthroughs

Description
• Add OS-level sidecar watcher to Windows backend test jobs
• Poll TCP socket states and process metrics every 500ms
• Capture external diagnostics during event-loop starvation window
• Write netstat and tasklist logs to artifact directory
Diagram
flowchart LR
  A["Test Job Start"] --> B["Launch Bash Watcher Loop"]
  B --> C["Poll Every 500ms"]
  C --> D["netstat.log<br/>TCP States"]
  C --> E["tasklist.log<br/>Process Metrics"]
  F["pnpm test --exit"] --> G["Test Execution"]
  G --> H["Kill Watcher"]
  H --> I["Upload Artifacts"]
  D --> I
  E --> I

Loading

File Changes

1. .github/workflows/backend-tests.yml 🧪 Tests +74/-0

Add OS-level diagnostic watcher to Windows test jobs

• Added bash background loop to Windows backend-test job (without-plugins) that polls OS state every
 500ms
• Loop captures TCP socket states via netstat and node.exe process metrics via tasklist to
 node-report/ directory
• Implemented proper watcher lifecycle management: start before tests, capture exit code, kill
 watcher after tests complete
• Added identical watcher implementation to Windows backend-test job (with-plugins) for consistency
• Both implementations write timestamped logs to existing artifact upload target for zero-cost
 infrastructure reuse

.github/workflows/backend-tests.yml


Grey Divider

Qodo Logo

@qodo-free-for-open-source-projects
Copy link
Copy Markdown

qodo-free-for-open-source-projects Bot commented May 25, 2026

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0)

Grey Divider


Action required

1. Broken netstat grep filter 🐞 Bug ≡ Correctness
Description
The watcher uses grep -E "TCP\s+...", but \s is not a whitespace escape in extended regular
expressions, so the filter is likely to match nothing and netstat.log won’t capture the intended
socket-state timeline. This breaks the primary diagnostic signal the watcher is meant to provide in
both Windows test jobs.
Code

.github/workflows/backend-tests.yml[246]

Evidence
Both Windows watcher blocks use grep -E with the pattern TCP\s+..., which in ERE does not
represent whitespace, so the intended match on the whitespace-separated netstat columns will fail
and the logs will miss the socket lines.

.github/workflows/backend-tests.yml[241-247]
.github/workflows/backend-tests.yml[375-381]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The workflow’s background watcher pipes `netstat` output into `grep -E "TCP\s+..."`. In `grep -E` (extended regular expressions), `\s` is not a special whitespace token, so the pattern will not match typical `netstat` lines (which separate columns with spaces).

### Issue Context
This watcher is intended to capture localhost TCP socket states during Windows silent-ELIFECYCLE failures. If the filter matches nothing, `netstat.log` becomes mostly timestamps with no actionable data.

### Fix
Replace `\s+` with a POSIX character class, or switch to PCRE mode.
Examples:
- `grep -E "TCP[[:space:]]+(127\.0\.0\.1|\[::1\])"`
- or `grep -P "TCP\s+(127\.0\.0\.1|\[::1\])"` (only if `grep -P` is guaranteed on the runner)

Apply the same fix in both duplicated watcher blocks.

### Fix Focus Areas
- .github/workflows/backend-tests.yml[246-246]
- .github/workflows/backend-tests.yml[380-380]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Unbounded watcher log growth 🐞 Bug ☼ Reliability
Description
The background watcher runs an infinite while true loop and appends (>>) netstat and
tasklist output every 500ms with no rotation or size cap, so long or hung runs can generate very
large log files/artifacts and add avoidable overhead. This can degrade CI reliability (disk usage,
artifact upload time) during exactly the flaky scenarios being investigated.
Code

.github/workflows/backend-tests.yml[R241-253]

Evidence
The workflow starts a while true loop that appends to two log files every 500ms and only stops
when explicitly killed after pnpm test returns, meaning log growth is unbounded for the duration
of the test (or a hang).

.github/workflows/backend-tests.yml[241-266]
.github/workflows/backend-tests.yml[375-400]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The watcher appends to `node-report/netstat.log` and `node-report/tasklist.log` every 0.5s in an infinite loop until the test command finishes. With no size limit, logs can grow without bound (especially if tests hang), leading to large artifacts and extra I/O/CPU.

### Issue Context
These steps run on Windows CI, where flaky behavior may also correlate with resource pressure. Minimizing added overhead and bounding disk usage improves the signal-to-noise of the diagnostic.

### Fix
Add a bounded logging strategy, for example:
- Rotate files every N iterations (e.g., `netstat.log.1`, `.2`) and keep only the last K.
- Or cap file size: if `wc -c` exceeds a threshold, truncate/keep tail (`tail -n`) before continuing.
- Or reduce cadence after some duration (e.g., 0.5s for first 2 minutes, then 2s).

### Fix Focus Areas
- .github/workflows/backend-tests.yml[241-253]
- .github/workflows/backend-tests.yml[375-387]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

ts=$(date '+%H:%M:%S.%3N')
{
echo "=== $ts ==="
netstat -an 2>/dev/null | grep -E "TCP\s+(127\.0\.0\.1|\[::1\])" || true
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Broken netstat grep filter 🐞 Bug ≡ Correctness

The watcher uses grep -E "TCP\s+...", but \s is not a whitespace escape in extended regular
expressions, so the filter is likely to match nothing and netstat.log won’t capture the intended
socket-state timeline. This breaks the primary diagnostic signal the watcher is meant to provide in
both Windows test jobs.
Agent Prompt
### Issue description
The workflow’s background watcher pipes `netstat` output into `grep -E "TCP\s+..."`. In `grep -E` (extended regular expressions), `\s` is not a special whitespace token, so the pattern will not match typical `netstat` lines (which separate columns with spaces).

### Issue Context
This watcher is intended to capture localhost TCP socket states during Windows silent-ELIFECYCLE failures. If the filter matches nothing, `netstat.log` becomes mostly timestamps with no actionable data.

### Fix
Replace `\s+` with a POSIX character class, or switch to PCRE mode.
Examples:
- `grep -E "TCP[[:space:]]+(127\.0\.0\.1|\[::1\])"`
- or `grep -P "TCP\s+(127\.0\.0\.1|\[::1\])"` (only if `grep -P` is guaranteed on the runner)

Apply the same fix in both duplicated watcher blocks.

### Fix Focus Areas
- .github/workflows/backend-tests.yml[246-246]
- .github/workflows/backend-tests.yml[380-380]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@qodo-free-for-open-source-projects
Copy link
Copy Markdown

CI Feedback 🧐

A test triggered by this PR failed. Here is an AI-generated analysis of the failure:

Action: Windows without plugins (24)

Failed stage: Run the backend tests [❌]

Failed test name: D:\a\etherpad\etherpad\src\tests\backend\specs\api\importexportGetPost.ts Imports and Exports export from read-only pad ID requireAuthentication = true export to etherpad re-import to read-write pad ID gives 200 OK

Failure summary:

The GitHub Action failed during the test run (pnpm test -- --exit) because the test command
terminated with a non-zero ELIFECYCLE exit code.
- At log lines 1516–1518, the suite starts the test
D:\a\etherpad\etherpad\src\tests\backend\specs\api\importexportGetPost.ts ... re-import to
read-write pad ID gives 200 OK and then immediately reports: [ELIFECYCLE] Test failed. See above for
more details.
- The workflow step then fails with Process completed with exit code 255 (line 1518).

- The summarized log does not include the actual assertion/error output (“See above”), so the
precise underlying test failure message is not visible here; only the failing/halt point in the
suite is identifiable.

Relevant error logs:
1:  ##[group]Runner Image Provisioner
2:  Hosted Compute Agent
...

357:  ##[group]Run powershell -Command "(gc settings.json.template) -replace '\"max\": 10', '\"max\": 10000' | Out-File -encoding ASCII settings.json.holder"
358:  �[36;1mpowershell -Command "(gc settings.json.template) -replace '\"max\": 10', '\"max\": 10000' | Out-File -encoding ASCII settings.json.holder"�[0m
359:  �[36;1mpowershell -Command "(gc settings.json.holder) -replace '\"points\": 10', '\"points\": 1000' | Out-File -encoding ASCII settings.json"�[0m
360:  shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'"
361:  env:
362:  PNPM_HOME: C:\Users\runneradmin\setup-pnpm\node_modules\.bin
363:  ##[endgroup]
364:  ##[group]Run mkdir -p "D:\a\etherpad\etherpad/node-report"
365:  �[36;1mmkdir -p "D:\a\etherpad\etherpad/node-report"�[0m
366:  �[36;1mOUT="D:\a\etherpad\etherpad/node-report"�[0m
367:  �[36;1m# Out-of-process OS-level watcher for the silent-ELIFECYCLE flake.�[0m
368:  �[36;1m# In-process diagnostics (diagnostics.ts heartbeat + node-report�[0m
369:  �[36;1m# snapshots) showed that during the death window the V8 main�[0m
370:  �[36;1m# isolate is starved — heartbeat stops firing entirely, then the�[0m
371:  �[36;1m# process is externally terminated, bypassing all JS handlers and�[0m
372:  �[36;1m# Node's --report-on-fatalerror. To capture state during that�[0m
373:  �[36;1m# starvation we need a process that doesn't depend on the dying�[0m
374:  �[36;1m# process's event loop. A bash background loop polling Windows�[0m
375:  �[36;1m# OS state every 500 ms gives us that:�[0m
376:  �[36;1m#   - netstat.log: localhost TCP socket states over time�[0m
377:  �[36;1m#     (TIME_WAIT/CLOSE_WAIT accumulation, handle exhaustion)�[0m
378:  �[36;1m#   - tasklist.log: node.exe process handle count, working set,�[0m
379:  �[36;1m#     CPU time — captured by the OS independent of V8.�[0m
380:  �[36;1m# Both logs are appended to node-report/ which already gets�[0m
381:  �[36;1m# uploaded as an artifact on failure.�[0m
382:  �[36;1m(�[0m
...

396:  �[36;1mWATCHER_PID=$!�[0m
397:  �[36;1m# --exit forces process.exit(failures) after the suite completes,�[0m
398:  �[36;1m# closing the post-suite event-loop drain window where Windows +�[0m
399:  �[36;1m# Node 24 hard-kills the process. Scoped to Windows so Linux/local�[0m
400:  �[36;1m# runs still surface real handle leaks via natural drain.�[0m
401:  �[36;1mset +e�[0m
402:  �[36;1mpnpm test -- --exit�[0m
403:  �[36;1mEXIT=$?�[0m
404:  �[36;1mset -e�[0m
405:  �[36;1mkill "$WATCHER_PID" 2>/dev/null || true�[0m
406:  �[36;1mwait "$WATCHER_PID" 2>/dev/null || true�[0m
407:  �[36;1mexit $EXIT�[0m
408:  shell: C:\Program Files\Git\bin\bash.EXE --noprofile --norc -e -o pipefail {0}
409:  env:
410:  PNPM_HOME: C:\Users\runneradmin\setup-pnpm\node_modules\.bin
411:  NODE_OPTIONS: --report-on-fatalerror --report-uncaught-exception --report-on-signal --report-compact --report-directory=D:\a\etherpad\etherpad/node-report
412:  ##[endgroup]
...

450:  �[32m[2026-05-25T21:02:06.933] [INFO] plugins - �[39mLoaded 1 plugins
451:  �[32m[2026-05-25T21:02:07.329] [INFO] server - �[39mInstalled plugins: 
452:  �[32m[2026-05-25T21:02:07.331] [INFO] settings - �[39mReport bugs at https://github.com/ether/etherpad/issues
453:  �[32m[2026-05-25T21:02:07.331] [INFO] settings - �[39mYour Etherpad version is 3.2.0 (20ca133)
454:  [diag +5253ms] hb running="<no test running>" lastFinished="<no test finished yet>" rss=345M heap=172M handles=3 requests=39
455:  Writing Node.js report to file: hb-0008-_no_test_running_.json
456:  Node.js report completed
457:  [diag +6264ms] hb running="<no test running>" lastFinished="<no test finished yet>" rss=384M heap=172M handles=3 requests=7
458:  Writing Node.js report to file: hb-0009-_no_test_running_.json
459:  Node.js report completed
460:  �[32m[2026-05-25T21:02:08.477] [INFO] updater - �[39mupdater: install method = git, tier = notify
461:  �[32m[2026-05-25T21:02:08.480] [INFO] http - �[39mHTTP server listening for connections
462:  �[32m[2026-05-25T21:02:08.480] [INFO] settings - �[39mYou can access your Etherpad instance at http://localhost:0/
463:  �[33m[2026-05-25T21:02:08.480] [WARN] settings - �[39mAdmin username and password not set in settings.json. To access admin please uncomment and edit "users" in settings.json
464:  �[32m[2026-05-25T21:02:08.480] [INFO] server - �[39mEtherpad is running
465:  D:\a\etherpad\etherpad\src\tests\backend\specs\admin\adminSettingsAuthError.ts
466:  [diag +6401ms] test start: D:\a\etherpad\etherpad\src\tests\backend\specs\admin\adminSettingsAuthError.ts emits admin_auth_error and disconnects when not authenticated as admin
467:  Writing Node.js report to file: be-0010-D_a_etherpad_etherpad_src_tests_backend_specs_admin_adminSettingsAuthError.ts_em.json
468:  Node.js report completed
469:  [diag +6504ms] hb running="D:\a\etherpad\etherpad\src\tests\backend\specs\admin\adminSettingsAuthError.ts emits admin_auth_error and disconnects when not authenticated as admin" lastFinished="<no test finished yet>" rss=384M heap=173M handles=4 requests=0
470:  Writing Node.js report to file: hb-0011-D_a_etherpad_etherpad_src_tests_backend_specs_admin_adminSettingsAuthError.ts_em.json
471:  Node.js report completed
472:  ✔ emits admin_auth_error and disconnects when not authenticated as admin
473:  AdminSettingsRedact
474:  [diag +6631ms] test start: AdminSettingsRedact returns a deep clone, never mutates input
475:  Writing Node.js report to file: be-0012-AdminSettingsRedact_returns_a_deep_clone_never_mutates_input.json
476:  Node.js report completed
477:  [diag +6725ms] hb running="AdminSettingsRedact returns a deep clone, never mutates input" lastFinished="D:\a\etherpad\etherpad\src\tests\backend\specs\admin\adminSettingsAuthError.ts emits admin_auth_error and disconnects when not authenticated as admin" rss=385M heap=174M handles=4 requests=0
478:  Writing Node.js report to file: hb-0013-AdminSettingsRedact_returns_a_deep_clone_never_mutates_input.json
...

556:  ✔ preserves /* */ comments in the written file
557:  D:\a\etherpad\etherpad\src\tests\backend\specs\admin\anonymizeAuthorSocket.ts
558:  �[32m[2026-05-25T21:02:10.565] [INFO] http - �[39mSuccessful authentication from IP ANONYMOUS for user test-admin
559:  [diag +8486ms] hb running="<no test running>" lastFinished="D:\a\etherpad\etherpad\src\tests\backend\specs\admin\adminSettingsSave.ts preserves /* */ comments in the written file" rss=401M heap=180M handles=5 requests=1
560:  Writing Node.js report to file: hb-0029-_no_test_running_.json
561:  Node.js report completed
562:  [diag +8588ms] test start: D:\a\etherpad\etherpad\src\tests\backend\specs\admin\anonymizeAuthorSocket.ts authorLoad returns paginated rows
563:  Writing Node.js report to file: be-0030-D_a_etherpad_etherpad_src_tests_backend_specs_admin_anonymizeAuthorSocket.ts_aut.json
564:  Node.js report completed
565:  ✔ authorLoad returns paginated rows
566:  [diag +8676ms] test start: D:\a\etherpad\etherpad\src\tests\backend\specs\admin\anonymizeAuthorSocket.ts anonymizeAuthorPreview returns counters without flipping erased
567:  ✔ anonymizeAuthorPreview returns counters without flipping erased
568:  [diag +8678ms] test start: D:\a\etherpad\etherpad\src\tests\backend\specs\admin\anonymizeAuthorSocket.ts anonymizeAuthor commits when the flag is enabled
569:  �[32m[2026-05-25T21:02:10.762] [INFO] adminSettings - �[39manonymizeAuthor (admin socket): a.aMrt8pxpo0JslFo9
570:  ✔ anonymizeAuthor commits when the flag is enabled
571:  [diag +8681ms] test start: D:\a\etherpad\etherpad\src\tests\backend\specs\admin\anonymizeAuthorSocket.ts anonymizeAuthor returns {error: "disabled"} when flag is off
572:  ✔ anonymizeAuthor returns {error: "disabled"} when flag is off
573:  [diag +8682ms] test start: D:\a\etherpad\etherpad\src\tests\backend\specs\admin\anonymizeAuthorSocket.ts anonymizeAuthorPreview returns {error: "disabled"} when flag is off
574:  ✔ anonymizeAuthorPreview returns {error: "disabled"} when flag is off
575:  [diag +8683ms] test start: D:\a\etherpad\etherpad\src\tests\backend\specs\admin\anonymizeAuthorSocket.ts authorLoad returns {error: "disabled"} when flag is off
576:  ✔ authorLoad returns {error: "disabled"} when flag is off
577:  [diag +8684ms] test start: D:\a\etherpad\etherpad\src\tests\backend\specs\admin\anonymizeAuthorSocket.ts handlers do not crash on payload-less emits
...

641:  ✔ filter:"active" excludes pads with no active users
642:  [diag +10391ms] hb running="<no test running>" lastFinished="D:\a\etherpad\etherpad\src\tests\backend\specs\admin\padLoadFilter.ts filter:"active" excludes pads with no active users" rss=402M heap=123M handles=6 requests=1
643:  Writing Node.js report to file: hb-0046-_no_test_running_.json
644:  Node.js report completed
645:  D:\a\etherpad\etherpad\src\tests\backend\specs\anonymizeAuthor.ts
646:  [diag +10483ms] test start: D:\a\etherpad\etherpad\src\tests\backend\specs\anonymizeAuthor.ts zeroes the display identity on globalAuthor:<id>
647:  Writing Node.js report to file: be-0047-D_a_etherpad_etherpad_src_tests_backend_specs_anonymizeAuthor.ts_zeroes_the_disp.json
648:  Node.js report completed
649:  ✔ zeroes the display identity on globalAuthor:<id>
650:  [diag +10573ms] test start: D:\a\etherpad\etherpad\src\tests\backend\specs\anonymizeAuthor.ts drops token2author and mapper2author mappings pointing at the author
651:  [diag +10575ms] test start: D:\a\etherpad\etherpad\src\tests\backend\specs\anonymizeAuthor.ts is idempotent — second call returns zero counters
652:  ✔ drops token2author and mapper2author mappings pointing at the author
653:  ✔ is idempotent — second call returns zero counters
654:  [diag +10577ms] test start: D:\a\etherpad\etherpad\src\tests\backend\specs\anonymizeAuthor.ts returns zero counters for an unknown authorID
655:  ✔ returns zero counters for an unknown authorID
656:  [diag +10578ms] test start: D:\a\etherpad\etherpad\src\tests\backend\specs\anonymizeAuthor.ts re-runs the sweep when a prior call errored before setting erased=true
657:  ✔ re-runs the sweep when a prior call errored before setting erased=true
658:  [diag +10579ms] test start: D:\a\etherpad\etherpad\src\tests\backend\specs\anonymizeAuthor.ts dryRun returns the same counter shape but does not mutate the record
...

700:  ✔ returns ANONYMOUS for '' in full mode
701:  [diag +10983ms] test start: D:\a\etherpad\etherpad\src\tests\backend\specs\anonymizeIp.ts empty / null input returns ANONYMOUS for null in truncated mode
702:  [diag +10983ms] test start: D:\a\etherpad\etherpad\src\tests\backend\specs\anonymizeIp.ts empty / null input returns ANONYMOUS for '' in truncated mode
703:  ✔ returns ANONYMOUS for null in truncated mode
704:  [diag +10984ms] test start: D:\a\etherpad\etherpad\src\tests\backend\specs\anonymizeIp.ts empty / null input returns ANONYMOUS for null in anonymous mode
705:  ✔ returns ANONYMOUS for '' in truncated mode
706:  ✔ returns ANONYMOUS for null in anonymous mode
707:  [diag +10984ms] test start: D:\a\etherpad\etherpad\src\tests\backend\specs\anonymizeIp.ts empty / null input returns ANONYMOUS for '' in anonymous mode
708:  ✔ returns ANONYMOUS for '' in anonymous mode
709:  D:\a\etherpad\etherpad\src\tests\backend\specs\api\anonymizeAuthor.ts
710:  [diag +10990ms] test start: D:\a\etherpad\etherpad\src\tests\backend\specs\api\anonymizeAuthor.ts anonymizeAuthor zeroes the author and returns counters
711:  [diag +11006ms] hb running="D:\a\etherpad\etherpad\src\tests\backend\specs\api\anonymizeAuthor.ts anonymizeAuthor zeroes the author and returns counters" lastFinished="D:\a\etherpad\etherpad\src\tests\backend\specs\anonymizeIp.ts empty / null input returns ANONYMOUS for '' in anonymous mode" rss=403M heap=130M handles=4 requests=0
712:  Writing Node.js report to file: hb-0052-D_a_etherpad_etherpad_src_tests_backend_specs_api_anonymizeAuthor.ts_anonymizeAu.json
713:  Node.js report completed
714:  ✔ anonymizeAuthor zeroes the author and returns counters (114ms)
715:  [diag +11104ms] test start: D:\a\etherpad\etherpad\src\tests\backend\specs\api\anonymizeAuthor.ts anonymizeAuthor with missing authorID returns an error
716:  Writing Node.js report to file: be-0053-D_a_etherpad_etherpad_src_tests_backend_specs_api_anonymizeAuthor.ts_anonymizeAu.json
717:  Node.js report completed
718:  [diag +11223ms] hb running="D:\a\etherpad\etherpad\src\tests\backend\specs\api\anonymizeAuthor.ts anonymizeAuthor with missing authorID returns an error" lastFinished="D:\a\etherpad\etherpad\src\tests\backend\specs\api\anonymizeAuthor.ts anonymizeAuthor zeroes the author and returns counters" rss=386M heap=130M handles=4 requests=0
719:  Writing Node.js report to file: hb-0054-D_a_etherpad_etherpad_src_tests_backend_specs_api_anonymizeAuthor.ts_anonymizeAu.json
720:  Node.js report completed
721:  ✔ anonymizeAuthor with missing authorID returns an error
722:  [diag +11362ms] test start: D:\a\etherpad\etherpad\src\tests\backend\specs\api\anonymizeAuthor.ts anonymizeAuthor returns an apierror when gdprAuthorErasure is disabled
723:  Writing Node.js report to file: be-0055-D_a_etherpad_etherpad_src_tests_backend_specs_api_anonymizeAuthor.ts_anonymizeAu.json
724:  Node.js report completed
725:  [diag +11464ms] hb running="D:\a\etherpad\etherpad\src\tests\backend\specs\api\anonymizeAuthor.ts anonymizeAuthor returns an apierror when gdprAuthorErasure is disabled" lastFinished="D:\a\etherpad\etherpad\src\tests\backend\specs\api\anonymizeAuthor.ts anonymizeAuthor with missing authorID returns an error" rss=387M heap=131M handles=5 requests=1
726:  Writing Node.js report to file: hb-0056-D_a_etherpad_etherpad_src_tests_backend_specs_api_anonymizeAuthor.ts_anonymizeAu.json
727:  Node.js report completed
728:  ✔ anonymizeAuthor returns an apierror when gdprAuthorErasure is disabled
729:  D:\a\etherpad\etherpad\src\tests\backend\specs\api\api.ts
...

796:  [diag +15120ms] test start: D:\a\etherpad\etherpad\src\tests\backend\specs\api\appendTextAuthor.ts appendText without authorId does not attribute to any author
797:  Writing Node.js report to file: be-0071-D_a_etherpad_etherpad_src_tests_backend_specs_api_appendTextAuthor.ts_appendText.json
798:  Node.js report completed
799:  [diag +15206ms] hb running="D:\a\etherpad\etherpad\src\tests\backend\specs\api\appendTextAuthor.ts appendText without authorId does not attribute to any author" lastFinished="D:\a\etherpad\etherpad\src\tests\backend\specs\api\appendTextAuthor.ts appendText with authorId attributes the text to that author" rss=389M heap=132M handles=4 requests=0
800:  Writing Node.js report to file: hb-0072-D_a_etherpad_etherpad_src_tests_backend_specs_api_appendTextAuthor.ts_appendText.json
801:  Node.js report completed
802:  ✔ appendText without authorId does not attribute to any author
803:  D:\a\etherpad\etherpad\src\tests\backend\specs\api\characterEncoding.ts
804:  Sanity checks
805:  [diag +15308ms] test start: D:\a\etherpad\etherpad\src\tests\backend\specs\api\characterEncoding.ts Sanity checks can connect
806:  Writing Node.js report to file: be-0073-D_a_etherpad_etherpad_src_tests_backend_specs_api_characterEncoding.ts_Sanity_ch.json
807:  Node.js report completed
808:  ✔ can connect
809:  [diag +15393ms] test start: D:\a\etherpad\etherpad\src\tests\backend\specs\api\characterEncoding.ts Sanity checks finds the version tag
810:  ✔ finds the version tag
811:  [diag +15396ms] test start: D:\a\etherpad\etherpad\src\tests\backend\specs\api\characterEncoding.ts Sanity checks errors with invalid OAuth token
812:  ✔ errors with invalid OAuth token
813:  [diag +15400ms] test start: D:\a\etherpad\etherpad\src\tests\backend\specs\api\characterEncoding.ts Sanity checks errors with unprivileged OAuth token
814:  ✔ errors with unprivileged OAuth token
815:  Tests
816:  [diag +15403ms] test start: D:\a\etherpad\etherpad\src\tests\backend\specs\api\characterEncoding.ts Tests creates a new Pad
817:  [diag +15406ms] hb running="D:\a\etherpad\etherpad\src\tests\backend\specs\api\characterEncoding.ts Tests creates a new Pad" lastFinished="D:\a\etherpad\etherpad\src\tests\backend\specs\api\characterEncoding.ts Sanity checks errors with unprivileged OAuth token" rss=389M heap=136M handles=6 requests=0
818:  Writing Node.js report to file: hb-0074-D_a_etherpad_etherpad_src_tests_backend_specs_api_characterEncoding.ts_Tests_cre.json
...

824:  [diag +15847ms] hb running="D:\a\etherpad\etherpad\src\tests\backend\specs\api\characterEncoding.ts Tests Sets the HTML of a Pad attempting to weird utf8 encoded content" lastFinished="D:\a\etherpad\etherpad\src\tests\backend\specs\api\characterEncoding.ts Tests creates a new Pad" rss=395M heap=170M handles=6 requests=1
825:  Writing Node.js report to file: hb-0076-D_a_etherpad_etherpad_src_tests_backend_specs_api_characterEncoding.ts_Tests_Set.json
826:  Node.js report completed
827:  Writing Node.js report to file: mt-0077-D_a_etherpad_etherpad_src_tests_backend_specs_api_characterEncoding.ts_Tests_Set.json
828:  Node.js report completed
829:  ✔ Sets the HTML of a Pad attempting to weird utf8 encoded content (441ms)
830:  [diag +16014ms] test start: D:\a\etherpad\etherpad\src\tests\backend\specs\api\characterEncoding.ts Tests get the HTML of Pad with emojis
831:  Writing Node.js report to file: be-0078-D_a_etherpad_etherpad_src_tests_backend_specs_api_characterEncoding.ts_Tests_get.json
832:  Node.js report completed
833:  [diag +16109ms] hb running="D:\a\etherpad\etherpad\src\tests\backend\specs\api\characterEncoding.ts Tests get the HTML of Pad with emojis" lastFinished="D:\a\etherpad\etherpad\src\tests\backend\specs\api\characterEncoding.ts Tests Sets the HTML of a Pad attempting to weird utf8 encoded content" rss=371M heap=170M handles=4 requests=0
834:  Writing Node.js report to file: hb-0079-D_a_etherpad_etherpad_src_tests_backend_specs_api_characterEncoding.ts_Tests_get.json
835:  Node.js report completed
836:  ✔ get the HTML of Pad with emojis
837:  D:\a\etherpad\etherpad\src\tests\backend\specs\api\chat.ts
838:  API Versioning
839:  [diag +16205ms] test start: D:\a\etherpad\etherpad\src\tests\backend\specs\api\chat.ts API Versioning errors if can not connect
840:  Writing Node.js report to file: be-0080-D_a_etherpad_etherpad_src_tests_backend_specs_api_chat.ts_API_Versioning_errors_.json
841:  Node.js report completed
842:  ✔ errors if can not connect
843:  Chat functionality
844:  [diag +16309ms] test start: D:\a\etherpad\etherpad\src\tests\backend\specs\api\chat.ts Chat functionality creates a new Pad
845:  Writing Node.js report to file: be-0081-D_a_etherpad_etherpad_src_tests_backend_specs_api_chat.ts_Chat_functionality_cre.json
846:  Node.js report completed
847:  [diag +16393ms] hb running="D:\a\etherpad\etherpad\src\tests\backend\specs\api\chat.ts Chat functionality creates a new Pad" lastFinished="D:\a\etherpad\etherpad\src\tests\backend\specs\api\chat.ts API Versioning errors if can not connect" rss=391M heap=172M handles=4 requests=0
848:  Writing Node.js report to file: hb-0082-D_a_etherpad_etherpad_src_tests_backend_specs_api_chat.ts_Chat_functionality_cre.json
...

1502:  �[32m[2026-05-25T21:02:30.113] [INFO] settings - �[39mExporting pad "r.cc92a4ec1e60af88134b06528a1f3f88" in etherpad format
1503:  ✔ export OK
1504:  [diag +28032ms] test start: D:\a\etherpad\etherpad\src\tests\backend\specs\api\importexportGetPost.ts Imports and Exports export from read-only pad ID requireAuthentication = true export to etherpad writable pad ID is not leaked
1505:  Writing Node.js report to file: be-0203-D_a_etherpad_etherpad_src_tests_backend_specs_api_importexportGetPost.ts_Imports.json
1506:  Node.js report completed
1507:  [diag +28113ms] hb running="D:\a\etherpad\etherpad\src\tests\backend\specs\api\importexportGetPost.ts Imports and Exports export from read-only pad ID requireAuthentication = true export to etherpad writable pad ID is not leaked" lastFinished="D:\a\etherpad\etherpad\src\tests\backend\specs\api\importexportGetPost.ts Imports and Exports export from read-only pad ID requireAuthentication = true export to etherpad export OK" rss=398M heap=172M handles=4 requests=0
1508:  Writing Node.js report to file: hb-0204-D_a_etherpad_etherpad_src_tests_backend_specs_api_importexportGetPost.ts_Imports.json
1509:  Node.js report completed
1510:  ✔ writable pad ID is not leaked
1511:  [diag +28194ms] test start: D:\a\etherpad\etherpad\src\tests\backend\specs\api\importexportGetPost.ts Imports and Exports export from read-only pad ID requireAuthentication = true export to etherpad re-import to read-only pad ID gives 403 forbidden
1512:  Writing Node.js report to file: be-0205-D_a_etherpad_etherpad_src_tests_backend_specs_api_importexportGetPost.ts_Imports.json
1513:  Node.js report completed
1514:  �[32m[2026-05-25T21:02:30.361] [INFO] http - �[39mSuccessful authentication from IP ANONYMOUS for user user
1515:  ✔ re-import to read-only pad ID gives 403 forbidden
1516:  [diag +28281ms] test start: D:\a\etherpad\etherpad\src\tests\backend\specs\api\importexportGetPost.ts Imports and Exports export from read-only pad ID requireAuthentication = true export to etherpad re-import to read-write pad ID gives 200 OK
1517:  [ELIFECYCLE] Test failed. See above for more details.
1518:  ##[error]Process completed with exit code 255.
1519:  ##[group]Run actions/upload-artifact@v7

@JohnMcLear JohnMcLear merged commit c4d2467 into develop May 26, 2026
35 of 36 checks passed
@JohnMcLear JohnMcLear deleted the test-ci-flake-os-sidecar-watcher branch May 26, 2026 11:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant