// // AppLifecycleHandlingTests.swift // damus // // Created by Daniel D’Aquino on 2025-11-06. // import XCTest @testable import damus class AppLifecycleHandlingTests: XCTestCase { func getTestNotesJSONL() -> String { // Get the path for the test_notes.jsonl file in the same folder as this test file let testBundle = Bundle(for: type(of: self)) let fileURL = testBundle.url(forResource: "test_notes", withExtension: "jsonl")! // Load the contents of the file return try! String(contentsOf: fileURL, encoding: .utf8) } /// Tests for some race conditions between the app closing down and streams opening throughout the app /// See https://github.com/damus-io/damus/issues/3245 for more context. /// /// **Note:** Time delays are intentionally added because we actually want to provoke possible race conditions, /// so using proper waiting mechanisms would defeat the purpose of the test. func testAppLifecycleRaceConditions() async throws { let damusState = await generate_test_damus_state(mock_profile_info: nil) let notesJSONL = getTestNotesJSONL() for noteText in notesJSONL.split(separator: "\n") { let _ = damusState.ndb.processEvent("[\"EVENT\",\"subid\",\(String(noteText))]") } // Give some time ndb some time to fill up try? await Task.sleep(for: .milliseconds(2000)) // Start measuring the time elapsed for debugging let startTime = CFAbsoluteTimeGetCurrent() func getElapsedTimeMiliseconds() -> String { return "\((CFAbsoluteTimeGetCurrent() - startTime) * 1000) ms" } Task.detached { for i in 0...10000 { try await Task.sleep(for: .milliseconds(Int.random(in: 0...10))) print("APP_LIFECYCLE_TEST \(i): About to close Ndb. Elapsed time: \(getElapsedTimeMiliseconds())") damusState.ndb.close() print("APP_LIFECYCLE_TEST \(i): Closed Ndb. Elapsed time: \(getElapsedTimeMiliseconds())") print("APP_LIFECYCLE_TEST \(i): Reopening Ndb. Elapsed time: \(getElapsedTimeMiliseconds())") _ = damusState.ndb.reopen() print("APP_LIFECYCLE_TEST \(i): Reopened Ndb. Elapsed time: \(getElapsedTimeMiliseconds())") } } for i in 0...10000 { do { try await Task.sleep(for: .milliseconds(Int.random(in: 0...10))) print("APP_LIFECYCLE_TEST \(i): Starting new query. Elapsed time: \(getElapsedTimeMiliseconds())") _ = try damusState.ndb.query(filters: [try NdbFilter(from: NostrFilter(kinds: [.text], limit: 1000))], maxResults: 500) } catch { print("APP_LIFECYCLE_TEST \(i): Query error: \(error). Elapsed time: \(getElapsedTimeMiliseconds())") } print("APP_LIFECYCLE_TEST \(i): Finished query. Elapsed time: \(getElapsedTimeMiliseconds())") } } }