Skip to content

test(core): fix the NetMonitorCore runner crash and DST-dependent expiry test (#330) - #368

Merged
jbcrane13 merged 1 commit into
mainfrom
fix/330-core-test-crash
Sep 29, 2026
Merged

jbcrane13 merged 1 commit into
mainfrom
fix/330-core-test-crash

Conversation

@jbcrane13

@jbcrane13 jbcrane13 commented Sep 29, 2026 •

Copy link
Copy Markdown
Owner

Problem

The full swift test in NetMonitorCore failed on main in two ways (reproduced on mini-pro-2 at 5f002e3):

  1. Runner crash (signal 5). The crash report (swiftpm-testing-helper-2026-09-28-233146.ips) traps inside Foundation's URLSession.data(for:) completion. Nine suites share MockURLProtocol's global requestHandler. Each is .serialized, but separate serialized suites still run in parallel, and every test's init() sets the handler to nil. A test in one suite cleared the handler another suite's request was using; the mock then finished the load with no response, and data(for:) trapped. Only 926 of about 1,464 tests had finished when the runner died.
  2. "Expiry calculation: days between two known dates" counted 59 days, not 60: 60 × 86400 s from Date() crosses the 1 Nov DST change in the local zone.

Fix (tests only; no app code changes)

  • GlobalMockURLProtocolSuites is a serialized parent suite, and the nine global-handler suites are nested under it in extensions, so they run one at a time. .serialized covers nested suites.
  • With no handler, MockURLProtocol now fails the request with URLError(.resourceUnavailable) instead of finishing without a response, so a future race fails one test rather than ending the run.
  • The two expiry-calculation tests use a fixed date (2026-10-15 UTC) and a UTC Gregorian calendar.

The six suite files are reindented only; review with git diff -w (48+/9−).

Verification (mini-pro-2, under lockf /tmp/nm-node-test.lock)

  • Before (main 5f002e3): 1 failure + exited with unexpected signal code 5
  • After (d32e2e9), two consecutive full runs: ✔ Test run with 1464 tests in 187 suites passed both times

Not part of 2.2.1 build 16. Only tests change, so no new build is needed.

Closes #330

🤖 Generated with Claude Code

https://claude.ai/code/session_012SGbgc2WtUFjD4SKcoa2bt


Devin Review

…endent expiry test (#330)

- Nest the nine suites that share MockURLProtocol's global requestHandler
  under one serialized parent (GlobalMockURLProtocolSuites). Separate
  .serialized suites ran in parallel, and each test's init() cleared the
  handler another suite was using mid-request.
- With no handler, MockURLProtocol now fails the request instead of
  finishing without a response, which made URLSession.data(for:) trap
  (SIGTRAP, signal 5) and end the whole run.
- The SSL expiry-calculation tests use a fixed date and a UTC calendar;
  60 x 86400 s from Date() counts 59 days across a DST change.

The six test files are reindented only; review with `git diff -w`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012SGbgc2WtUFjD4SKcoa2bt
@jbcrane13 jbcrane13 added the type:bug Something is broken label Sep 29, 2026
Copilot AI balanced review requested due to automatic review settings September 29, 2026 04:38
@jbcrane13 jbcrane13 added the type:bug Something is broken label Sep 29, 2026
@jbcrane13
jbcrane13 merged commit 0175f11 into main Sep 29, 2026
@jbcrane13
jbcrane13 deleted the fix/330-core-test-crash branch September 29, 2026 04:38

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔍 Devin Review: 1 flag

Not posted on this PR by your GitHub settings — view it in Devin Review. (Configure)

Devin Review

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

The change is a large, CI-critical reindentation of shared test infrastructure whose runtime correctness depends on Swift Testing serialization behavior that cannot be executed in this review environment, so a human should confirm before approval.

Review effort: Balanced
Findings: None

What changed in this PR

This test-only PR fixes two pre-existing failures in the NetMonitorCore package's full swift test run (issue #330): a signal 5 runner crash and a DST-sensitive SSL-expiry test. No application code changes.

The runner crash was caused by nine .serialized suites that share MockURLProtocol's global requestHandler: separate serialized suites still run in parallel, and each test's init() reset the handler while another suite's request was mid-flight, leaving a request with no handler that finished without a response and trapped inside URLSession.data(for:). The fix serializes all nine suites under a single @Suite(.serialized) parent and hardens the no-handler path.

Changes:

  • Introduce a @Suite(.serialized) enum GlobalMockURLProtocolSuites and nest all nine global-handler suites under it (via extensions) so they run one at a time.
  • Make MockURLProtocol fail a handler-less request with URLError(.resourceUnavailable) instead of finishing empty (which trapped the run).
  • Make the two expiry-calculation tests deterministic using a fixed 2026-10-15 00:00 UTC date and a UTC Gregorian calendar.
File Description
Helpers/​MockURLProtocol.swift Adds the GlobalMockURLProtocolSuites serialized parent; fails handler-less requests instead of trapping; updates doc comments.
ContractTests.swift Nests the suite (and its inner contract sub-suites) under GlobalMockURLProtocolSuites; reindent only.
GeoLocationServiceTests.swift Nests the suite under GlobalMockURLProtocolSuites; reindent only.
WorldPingServiceErrorTests.swift Nests the suite under GlobalMockURLProtocolSuites; reindent only.
WorldPingRegressionTests.swift Nests both suites under GlobalMockURLProtocolSuites; reindent only.
SpeedTestServiceSessionTests.swift Nests three suites under GlobalMockURLProtocolSuites; reindent only.
SpeedTestServiceErrorRecoveryTests.swift Nests the suite under GlobalMockURLProtocolSuites; reindent only.
SSLCertificateContractTests.swift Replaces Date()/Calendar.current with a fixed UTC date and calendar in the two expiry tests.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type:bug Something is broken

Projects

None yet

Development

Successfully merging this pull request may close these issues.

NetMonitorCore: full swift test has an off-by-one SSL expiry test and a signal-5 runner crash (pre-existing on main)

2 participants