test(ios): de-flake shutdown-IPC assertions via deterministic wait#147
Merged
Conversation
testStopSendsShutdownMessageOverIPC and testGracefulShutdownFlow asserted backend.receivedShutdown immediately after stop(), racing MockBackend's background read loop — and reading the bool with no cross-thread memory barrier. CI hit this intermittently (e.g. run 28023239180). Add a shutdownObserved semaphore signaled when the shutdown frame is read, plus waitForShutdown(timeout:), mirroring the existing handshakeComplete / waitForHandshake idiom. Both tests now await it (before signalling node exit, while the socket is still alive) instead of peeking the flag. Verified: full `swift test` suite green + the two tests passed 20/20 under a stress loop locally (Swift 6.3.2 / Xcode 26.5). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
gmaclennan
added a commit
that referenced
this pull request
Jun 23, 2026
## Optic Release Automation This **draft** PR is opened by Github action [optic-release-automation-action](https://github.com/nearform-actions/optic-release-automation-action). A new **draft** GitHub release [v1.0.0-pre.4](https://github.com/digidem/comapeo-core-react-native/releases/tag/untagged-884b8ff33e96eff7e06b) has been created. Release author: @gmaclennan #### If you want to go ahead with the release, please merge this PR. When you merge: - The GitHub release will be published - The npm package with tag pre will be published according to the publishing rules you have configured - No major or minor tags will be updated as configured #### If you close the PR - The new draft release will be deleted and nothing will change <!-- Release notes generated using configuration in .github/release.yml at 353e6e9 --> ## What's Changed ### 🚀 Features * feat(android): migrate rootkey from expo-secure-store on first boot by @gmaclennan in #107 ### 🐛 Bug Fixes * fix(backend): apply defaultOnlineStyleUrl to the standalone map server by @gmaclennan in #148 ### 🏗️ Maintenance * test(ios): de-flake shutdown-IPC assertions via deterministic wait by @gmaclennan in #147 **Full Changelog**: v1.0.0-pre.3...v1.0.0-pre.4 <!-- <release-meta>{"id":343614988,"version":"v1.0.0-pre.4","npmTag":"pre","opticUrl":"https://optic-zf3votdk5a-ew.a.run.app/api/generate/"}</release-meta> -->
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Swift Package Tests (macOS)flaked ontestStopSendsShutdownMessageOverIPC(and the same pattern intestGracefulShutdownFlow) — e.g. run 28023239180. Surfaced while CI ran it against PR #107, but it is independent of that PR: the failing run's Swift sources were byte-identical to a parent commit that passed, so it's a pre-existing test race, not a regression.Root cause
Both tests asserted
backend.receivedShutdownimmediately afterstop()returned.MockBackendsets that flag on a background read loop, so the assertion raced the loop — and read the plainBoolwith no cross-thread memory barrier. Waiting for theSTOPPINGtransition doesn't guarantee the backend has read the shutdown frame yet.Fix
MockBackendgains ashutdownObservedsemaphore (signaled when the shutdown frame is read) and awaitForShutdown(timeout:)method — mirroring the existinghandshakeComplete/waitForHandshakeidiom. Both tests nowwaitForShutdown(...)before signalling node exit (the frame is sent bystop()before it blocks, so the socket is still alive), instead of peeking the flag. The semaphore also provides the happens-before the bare bool read lacked.Verification
swift testsuite green.🤖 Generated with Claude Code