Skip to content

test(windows-prep): add Stream 0 regression-net tests for POSIX behavior#1278

Merged
stack72 merged 1 commit intomainfrom
stream-0-regression-net
May 1, 2026
Merged

test(windows-prep): add Stream 0 regression-net tests for POSIX behavior#1278
stack72 merged 1 commit intomainfrom
stream-0-regression-net

Conversation

@stack72
Copy link
Copy Markdown
Contributor

@stack72 stack72 commented May 1, 2026

Summary

Adds 13 regression-net tests on macOS/Linux that lock in existing POSIX behavior before three planned Windows-readiness refactor streams (Docker/vault, cross-platform shellouts, signal/env helpers). Tests-only PR — no production code modified.

The high-leverage additions plug previously-zero-coverage code paths:

  • swamp update end-to-end (download → extract → chmod → macOS xattr clear)
  • swamp serve SIGINT shutdown via real subprocess + signal
  • swamp doctor audit integration test
  • Datastore SIGINT lock-release within the 5s force-exit deadline
  • Vault directory mode 0o700 invariant

The remaining additions pin existing contracts that were previously implicit:

  • Docker driver SIGTERM exit-code propagation, stdout/stderr interleaving
  • executeProcess AbortSignal handling (streaming-mode contract)
  • executeProcess timeout SIGTERM behavior
  • ~/ expansion via HOME env var
  • Forward-slash preservation in model-type and extension-resolver logical keys (regression net for the deliberate decision to not migrate these to @std/path)

One item deferred: findSystemDeno multi-line output parsing. The helper is private and only reachable when Deno.build.standalone === true AND the embedded binary's health check fails — no public seam exists for testing without modifying production code. Will land alongside the cross-platform resolve_command helper in the next stream.

Test Plan

  • deno fmt --check clean (1277 files)
  • deno lint clean (1156 files)
  • deno check clean
  • deno run test — 5099 passed, 0 failed, 23 ignored
  • No production source files modified

Tests-only PR locking in existing POSIX (macOS/Linux) behavior before three
parallel Windows-readiness refactor streams begin: A (Docker/vault), B
(cross-platform shellouts), and C (signals/env/paths). No production code
modified.

Coverage added:
- DockerExecutionDriver: SIGTERM-trapping child error path; interleaved
  stdout/stderr capture without loss
- LocalEncryptionVaultProvider: vault directory created with mode 0o700
- HttpUpdateChecker.downloadAndInstall: tarball extract + chmod 0o755
  end-to-end; macOS quarantine xattr cleared on darwin host
- executeProcess: AbortSignal mid-execution surfaces AbortError;
  timeout sends SIGTERM (not SIGKILL) and surfaces "timed out"
- swamp doctor audit (integration): JSON contract holds with --tool none
- swamp serve (integration): SIGINT triggers clean shutdown within 6s
- datastore sync coordinator: SIGINT handler releases locks within the
  5s force-exit deadline (subprocess form)
- input_parser: ~/file expands via HOME on POSIX; literal path preserved
  when HOME unset
- ModelType: normalize/toDirectoryPath always emit forward slashes
- ExtensionAutoResolver: candidate names preserve forward-slash separators

Two items deferred:
- embedded_deno_runtime findSystemDeno multi-line which output: helper is
  private with no injection seam; only invoked in standalone-mode failure
  path which dev-mode tests can't reach.

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

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Code Review

Clean, well-structured tests-only PR. All 13 regression-net tests are well-organized, properly gate on ignore: Deno.build.os === "windows" (or !== "darwin" for the xattr test), and clean up resources in finally blocks. No blocking issues found.

Verified:

  • AGPLv3 license headers present on both new files and all modified files
  • No libswamp internal-path import violations — all test imports use adjacent module paths correctly
  • Test naming follows existing conventions in each file (- in docker/extension tests, : in process/model tests)
  • @std/path used correctly for all path operations (no hand-rolled path concatenation)
  • Subprocess lifecycle properly managed (SIGKILL fallback in finally, sanitizeResources: false / sanitizeOps: false where needed)
  • No security concerns — temp dirs, local port: 0 servers, proper cleanup
  • DDD layer organization correct (domain tests in src/domain/, infrastructure in src/infrastructure/, integration in integration/)

Blocking Issues

None.

Suggestions

  1. Comment density: Several tests have multi-line comment blocks (4-7 lines) above them. CLAUDE.md prefers minimal comments ("one short line max"). For regression-net tests the WHY is valuable, but some of the longer blocks could be condensed — e.g., the block at serve_shutdown_test.ts:24-30 repeats information already in the test name and PR description.

  2. waitForLine timeout robustness (serve_shutdown_test.ts:175-208): The timeout check is between reader.read() calls, so if the subprocess never writes to stdout, the function blocks on reader.read() indefinitely until the Deno test timeout fires. Wrapping the read in a Promise.race with a timer would make the timeout self-contained. Not a practical concern since the Deno test timeout is the fallback, but worth noting.

  3. Uncleaned setTimeout in Promise.race patterns (serve_shutdown_test.ts:260-269, datastore_sync_coordinator_test.ts:608-618): The reject timers are never cleared when the process exits before the deadline. With sanitizeOps: false this doesn't cause failures, but storing the timer ID and calling clearTimeout on the success path would be tidier.

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Adversarial Review

Critical / High

No critical or high severity findings.

Medium

  1. src/domain/drivers/docker_execution_driver_test.ts:496-515 — Conditional assertion block silently skips stdout verification if output kind changes.

    The interleaved stdout/stderr test wraps all stdout content assertions inside if (result.outputs[0].kind === "pending"). If a refactor changes the output kind (e.g., to "resolved"), every assertStringIncludes and occurrence-count check is silently skipped, and the test passes with zero stdout verification. This defeats the purpose of a regression net.

    Breaking example: Production code changes kind: "pending" to kind: "resolved" → the if block is skipped → test passes green despite potentially broken stdout capture.

    Suggested fix: Assert the kind unconditionally before the content checks:

    assertEquals(result.outputs[0].kind, "pending");
    const text = new TextDecoder().decode(result.outputs[0].content);
    // ... rest of assertions without the if wrapper
  2. src/infrastructure/update/http_update_checker_test.ts:1031-1083 (macOS xattr test) — Vacuous assertion: locally-written files never carry com.apple.quarantine.

    The test verifies that the installed binary doesn't have the quarantine xattr. But files written locally by Deno (not downloaded via a browser or curl) are never tagged with com.apple.quarantine in the first place. The local Deno.servefetch path doesn't trigger macOS quarantine tagging. This means the assertion passes regardless of whether the removeQuarantine() call exists or is deleted.

    The test comment acknowledges this ("Files written via Deno on a local filesystem typically aren't tagged"), which means the test is documenting a known gap rather than providing real coverage. It would only catch the narrow scenario where a refactor both removes the xattr call AND introduces quarantine tagging — an unlikely conjunction.

    Impact: Low practical risk since the test at least exercises the full downloadAndInstall path on darwin. But it doesn't verify the quarantine removal code actually runs. Consider adding a step that explicitly sets the quarantine xattr before calling downloadAndInstall, then verifying it's removed:

    // Tag the target path (or extracted binary) before install
    await new Deno.Command("xattr", {
      args: ["-w", "com.apple.quarantine", "0081;...", binaryPath],
    }).output();
    await checker.downloadAndInstall(url, binaryPath, checksum);
    // Now the assertion actually tests removeQuarantine()

Low

  1. integration/serve_shutdown_test.ts:175-192waitForLine timeout is only checked between reader.read() calls. If reader.read() blocks indefinitely (e.g., subprocess hangs producing no output and doesn't exit), the timeout never fires and the test hangs. In practice, the 15s Deno test timeout or CI timeout would catch this, so the blast radius is limited to slow CI feedback rather than incorrect results.

  2. integration/serve_shutdown_test.ts:155-169CLI_LAUNCH_ARGS duplicates integration/test_helpers.ts:CLI_ARGS with the addition of --allow-net. Not a correctness issue, but if CLI_ARGS is updated (e.g., new unstable flags), this copy won't track. A minor maintenance concern.

  3. src/infrastructure/persistence/datastore_sync_coordinator_test.ts:741-767 — The child program passed via stdin uses an untyped fn parameter in the mock lock's withLock(fn). This works because the child runs as a standalone Deno process without the project's strict tsconfig, but it means the mock doesn't enforce the lock interface contract at compile time. Purely theoretical since the child is a runtime-only fixture.

Verdict

PASS — Tests-only PR with solid regression coverage across POSIX-specific behaviors. The conditional assertion in the Docker interleaved test (Medium #1) is the most actionable finding — a one-line fix to make the assertion unconditional. The macOS xattr test (Medium #2) is acknowledged-weak coverage. No production code is modified, no security concerns, and no blocking issues.

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