mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-27 13:45:19 +00:00
Merge remote-tracking branch 'origin/main' into harden/radio-metadata
This commit is contained in:
@@ -1374,3 +1374,37 @@ private func makeImageData() throws -> Data {
|
||||
return data
|
||||
#endif
|
||||
}
|
||||
|
||||
// MARK: - Tor Extension Tests
|
||||
|
||||
struct ChatViewModelTorExtensionTests {
|
||||
|
||||
/// Turning Tor off mid-bootstrap must not read as "the network is
|
||||
/// blocking tor": `torEnforced` is a compile-time constant, so the stall
|
||||
/// handler has to consult the runtime preference before announcing.
|
||||
@Test @MainActor
|
||||
func bootstrapStall_withTorPreferenceOff_announcesNothing() async {
|
||||
let key = NetworkActivationService.torPreferenceKey
|
||||
let previous = UserDefaults.standard.object(forKey: key)
|
||||
defer {
|
||||
if let previous {
|
||||
UserDefaults.standard.set(previous, forKey: key)
|
||||
} else {
|
||||
UserDefaults.standard.removeObject(forKey: key)
|
||||
}
|
||||
}
|
||||
let (viewModel, _) = makeTestableViewModel()
|
||||
|
||||
UserDefaults.standard.set(false, forKey: key)
|
||||
viewModel.handleTorBootstrapDidStall()
|
||||
try? await Task.sleep(nanoseconds: 50_000_000)
|
||||
#expect(viewModel.torStallAnnounced == false)
|
||||
|
||||
// The same stall with the preference on (the persisted default) is
|
||||
// exactly what must still be announced.
|
||||
UserDefaults.standard.set(true, forKey: key)
|
||||
viewModel.handleTorBootstrapDidStall()
|
||||
try? await Task.sleep(nanoseconds: 50_000_000)
|
||||
#expect(viewModel.torStallAnnounced == true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,46 @@ final class NostrRelayManagerTests: XCTestCase {
|
||||
XCTAssertTrue(context.sessionFactory.allConnections.allSatisfy { $0.cancelCallCount >= 1 })
|
||||
}
|
||||
|
||||
/// A relay removed while its connection is queued behind Tor bootstrap
|
||||
/// must stay removed: draining the pending set used to resurrect it,
|
||||
/// because `dropRelays` never touched `pendingTorConnectionURLs` and a
|
||||
/// custom relay is in neither the default set nor the allow-list filter.
|
||||
func test_relayRemovedWhileWaitingForTor_staysRemovedWhenTorBecomesReady() async {
|
||||
let customURL = "wss://custom-removed.example"
|
||||
let center = NotificationCenter()
|
||||
let customRelays = MutableRelayList(urls: [customURL])
|
||||
let context = makeContext(
|
||||
permission: .authorized,
|
||||
userTorEnabled: true,
|
||||
torEnforced: true,
|
||||
torIsReady: false,
|
||||
notificationCenter: center,
|
||||
customRelays: customRelays
|
||||
)
|
||||
|
||||
// Defaults plus the custom relay all queue while Tor bootstraps.
|
||||
context.manager.connect()
|
||||
XCTAssertTrue(context.sessionFactory.requestedURLs.isEmpty)
|
||||
XCTAssertEqual(context.torWaiter.awaitCallCount, 1)
|
||||
|
||||
// The relay is removed by hand before Tor is ready.
|
||||
customRelays.urls = []
|
||||
center.post(name: NostrRelaySettings.didChangeNotification, object: nil)
|
||||
// The settings sink hops through the main queue; let it land.
|
||||
try? await Task.sleep(nanoseconds: 20_000_000)
|
||||
|
||||
context.torWaiter.resolve(true)
|
||||
|
||||
let defaultsConnected = await waitUntil {
|
||||
context.sessionFactory.requestedURLs.count == self.expectedDefaultRelayCount
|
||||
}
|
||||
XCTAssertTrue(defaultsConnected)
|
||||
XCTAssertFalse(
|
||||
context.sessionFactory.requestedURLs.contains(customURL),
|
||||
"a relay removed while Tor was bootstrapping must not reconnect when the pending queue drains"
|
||||
)
|
||||
}
|
||||
|
||||
func test_connect_waitsForTorReadinessBeforeCreatingSessions() async {
|
||||
let context = makeContext(permission: .authorized, userTorEnabled: true, torEnforced: true, torIsReady: false)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user