Make ServerStore instance-based so tests can't poison production servers.json#34
Merged
Conversation
This was referenced Apr 26, 2026
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.
Summary
ServerStorewas a static-method holder that always wrote to~/Library/Application Support/Brygga/servers.json. Any test that constructedAppState()and triggeredpersist()(e.g. viaclosePrivateMessage) overwrote the user's real server config with the test fixtures (ServerA @ a.example.org,ServerB @ b.example.org). Subsequent app launches restored the test fixtures, the user saw their real servers gone, and the scrollback for those servers became orphaned under their original UUIDs.ServerStorefromenumof static methods tofinal classwith instance methods +init(root:). Production code usesServerStore.shared; tests construct their ownServerStore(root: tempDir).AppState.init(store:)requires a store explicitly — no default. A test that forgets to inject a temp store is now a compile error rather than a silent prod overwrite.Changes
Sources/BryggaCore/Persistence/ServerStore.swift— converted fromenumtofinal class: Sendable. Removed staticfileURL(),load(),save(). Addedinit(root: URL? = nil), instanceload()andsave(_:), publicfileURL: URL. Addedstatic let shared = ServerStore()for the prod default.SnapshotandServerConfignested types are unchanged so existingServerStore.ServerConfigreferences inAppStatekeep working.Sources/BryggaCore/Models/AppState.swift— addedprivate let store: ServerStorefield. Removedinit(), replaced withinit(store: ServerStore).restoreFromStore()now callsstore.load();persist()callsstore.save(...).Sources/Brygga/BryggaApp.swift—AppState()→AppState(store: .shared). Sole production call site.Tests/AppStateNavigationTests.swift— addedmakeStore()helper that builds aServerStorerooted at a unique tempdir. AllAppState(...)constructors now use it. AddedtestPersistWritesToInjectedStoreNotProductionregression test that asserts apersist()-triggering mutation lands under the injected store's path, not the prod path.Test plan
swift build— passesswift test— 132 tests pass (+1 regression test)swiftformat --lint .— cleanswift testno longer touches the prod path:Risk / rollback
AppState.init()is removed. Only call site (BryggaApp.swift) is updated in this PR. Any external consumer ofAppState()would need to passServerStore.shared.init(root: nil)onServerStorekeeps prod behavior identical — same JSON file path, same schema, no migration needed.Follow-ups (separate PRs)
scrollback/<UUID>/orphans, print channels found in each, let user rebind one to a freshServerentry by editingservers.json'sidfield.ScrollbackStore.sharedandScrollbackIndex.shared— those also leaked into production fromIRCSessionTests, though the impact is tiny appended-row pollution rather than data overwrite.