field_ios

In-the-field app for Radroots on iOS
git clone https://radroots.dev/git/field_ios.git
Log | Files | Refs | README | LICENSE

TeraRuntimeShutdownTests.swift (7593B)


      1 @testable import TeraApp
      2 import XCTest
      3 
      4 final class TeraRuntimeShutdownTests: XCTestCase {
      5   func testTimeoutRetainsActualOperationAndRepeatedCloseDrainsIt() async throws {
      6     let configuration = TeraRuntimeClientTests().makeConfiguration(generation: "70")
      7     let backend = ResourceTestBackend(publicKeyHex: configuration.publicKeyHex)
      8     let pause = ResourceTestPause()
      9     let client = TeraRuntimeClient(
     10       factory: { _ in await backend.start() },
     11       deadlines: TeraRuntimeDeadlinePolicy(shutdownNanoseconds: 1_000_000)
     12     )
     13     _ = try await client.start(configuration: configuration)
     14     await backend.pauseSnapshot(pause)
     15     let operation = Task { try await client.snapshot() }
     16     await pause.entered.wait()
     17     await assertShutdownDeadline(client)
     18     let prematureCloses = await backend.shutdownCount
     19     XCTAssertEqual(prematureCloses, 0)
     20     await assertAdmissionClosed(client)
     21     await assertShutdownDeadline(client)
     22     let duplicateCloses = await backend.shutdownCount
     23     XCTAssertEqual(duplicateCloses, 0)
     24     await pause.resume.open()
     25     _ = await operation.result
     26     await awaitClosed(backend)
     27     _ = try await client.stop()
     28     let closes = await backend.shutdownCount
     29     XCTAssertEqual(closes, 1)
     30   }
     31 
     32   func testCancellingCloseWaiterKeepsOneSharedNativeClose() async throws {
     33     let configuration = TeraRuntimeClientTests().makeConfiguration(generation: "71")
     34     let backend = ResourceTestBackend(publicKeyHex: configuration.publicKeyHex)
     35     let pause = ResourceTestPause()
     36     let client = TeraRuntimeClient(factory: { _ in await backend.start() })
     37     _ = try await client.start(configuration: configuration)
     38     await backend.pauseShutdown(pause)
     39     let cancelled = Task { try await client.stop() }
     40     await pause.entered.wait()
     41     cancelled.cancel()
     42     do {
     43       _ = try await cancelled.value
     44       XCTFail("The caller should stop waiting")
     45     } catch let TeraRuntimeClientError.shutdown(failure) {
     46       XCTAssertEqual(failure.code, "ios.runtime.cancelled")
     47     }
     48     await assertAdmissionClosed(client)
     49     let survivor = Task { try await client.stop() }
     50     await pause.resume.open()
     51     let receipt = try await survivor.value
     52     XCTAssertEqual(receipt.state, "closed")
     53     _ = try await client.stop()
     54     let closes = await backend.shutdownCount
     55     XCTAssertEqual(closes, 1)
     56   }
     57 
     58   func testProtectedStorageFailureRetainsBackendForExplicitRetry() async throws {
     59     let configuration = TeraRuntimeClientTests().makeConfiguration(generation: "72")
     60     let backend = ResourceTestBackend(publicKeyHex: configuration.publicKeyHex)
     61     let failure = TeraRuntimeFailure.local(
     62       operation: "test.close", code: "protected_data_unavailable", safeMessage: "Protected data unavailable"
     63     )
     64     let client = TeraRuntimeClient(factory: { _ in await backend.start() })
     65     _ = try await client.start(configuration: configuration)
     66     await backend.failShutdownOnce(failure)
     67     do {
     68       _ = try await client.stop()
     69       XCTFail("Close failure must survive")
     70     } catch let TeraRuntimeClientError.shutdown(observed) { XCTAssertEqual(observed, failure) }
     71     await assertAdmissionClosed(client)
     72     let receipt = try await client.stop()
     73     XCTAssertFalse(receipt.alreadyClosed)
     74     let closes = await backend.shutdownCount
     75     XCTAssertEqual(closes, 2)
     76   }
     77 
     78   func testShutdownWaitsForLateStartupAndItsNativeCleanup() async throws {
     79     let configuration = TeraRuntimeClientTests().makeConfiguration(generation: "73")
     80     let backend = ResourceTestBackend(publicKeyHex: configuration.publicKeyHex)
     81     let creation = ResourceTestPause()
     82     let cleanup = ResourceTestPause()
     83     await backend.pauseShutdown(cleanup)
     84     let client = TeraRuntimeClient(
     85       factory: { _ in await creation.wait(); return await backend.start() },
     86       deadlines: TeraRuntimeDeadlinePolicy(shutdownNanoseconds: 1_000_000)
     87     )
     88     let start = Task { try await client.start(configuration: configuration) }
     89     await creation.entered.wait()
     90     await assertShutdownDeadline(client)
     91     _ = await start.result
     92     do {
     93       _ = try await client.start(configuration: configuration)
     94       XCTFail("A new startup cannot pass outstanding cleanup")
     95     } catch let TeraRuntimeClientError.shutdown(failure) {
     96       XCTAssertEqual(failure.code, "ios.runtime.deadline_exceeded")
     97     }
     98     await creation.resume.open()
     99     await cleanup.entered.wait()
    100     await assertShutdownDeadline(client)
    101     await cleanup.resume.open()
    102     await awaitClosed(backend)
    103     _ = try await client.stop()
    104     let closes = await backend.shutdownCount
    105     XCTAssertEqual(closes, 1)
    106   }
    107 
    108   func testFailedLateStartupCleanupIsRetainedAndRetried() async throws {
    109     let pause = ResourceTestPause()
    110     let configuration = TeraRuntimeClientTests().makeConfiguration(generation: "74")
    111     let backend = ResourceTestBackend(publicKeyHex: configuration.publicKeyHex)
    112     await backend.failShutdownOnce(.local(operation: "test.close", code: "protected_data_unavailable", safeMessage: "Locked"))
    113     let client = TeraRuntimeClient(factory: { _ in await pause.wait(); return await backend.start() })
    114     let start = Task { try await client.start(configuration: configuration) }
    115     await pause.entered.wait()
    116     start.cancel()
    117     _ = await start.result
    118     await pause.resume.open()
    119     // The cleanup owner may already have observed the first failure. Either
    120     // close reports it, or this explicit request resumes that failed cleanup.
    121     do {
    122       _ = try await client.stop()
    123     } catch let TeraRuntimeClientError.shutdown(failure) {
    124       XCTAssertEqual(failure.code, "protected_data_unavailable")
    125       _ = try await client.stop()
    126     }
    127     let closes = await backend.shutdownCount
    128     XCTAssertEqual(closes, 2)
    129     let lifecycle = await client.lifecycle()
    130     XCTAssertEqual(lifecycle, .stopped)
    131   }
    132 
    133   func testLifecycleBridgeSharesCloseAndRetainsFailedRegistration() async {
    134     let bridge = TeraLifecycleBridge()
    135     let attempt = ShutdownAttemptFixture()
    136     await bridge.register { await attempt.close() }
    137     let first = Task { await bridge.requestShutdown() }
    138     await attempt.pause.entered.wait()
    139     first.cancel()
    140     let second = Task { await bridge.requestShutdown() }
    141     await attempt.pause.resume.open()
    142     await first.value
    143     await second.value
    144     await bridge.requestShutdown()
    145     await bridge.requestShutdown()
    146     let count = await attempt.calls
    147     XCTAssertEqual(count, 2)
    148   }
    149 
    150   private func assertAdmissionClosed(_ client: TeraRuntimeClient) async {
    151     do {
    152       _ = try await client.snapshot()
    153       XCTFail("Closing runtime admitted a command")
    154     } catch { XCTAssertEqual(error as? TeraRuntimeClientError, .notRunning) }
    155   }
    156 
    157   private func assertShutdownDeadline(_ client: TeraRuntimeClient) async {
    158     do {
    159       _ = try await client.stop()
    160       XCTFail("Outstanding work cannot report closed")
    161     } catch let TeraRuntimeClientError.shutdown(failure) {
    162       XCTAssertEqual(failure.code, "ios.runtime.deadline_exceeded")
    163     } catch { XCTFail("Unexpected close failure: \(error)") }
    164   }
    165 
    166   private func awaitClosed(_ backend: ResourceTestBackend) async {
    167     let completed = expectation(description: "Native close completed")
    168     let wait = Task { await backend.closed.wait(); completed.fulfill() }
    169     await fulfillment(of: [completed], timeout: 2)
    170     await backend.closed.open()
    171     await wait.value
    172   }
    173 }
    174 
    175 private actor ShutdownAttemptFixture {
    176   let pause = ResourceTestPause()
    177   private(set) var calls = 0
    178   func close() async -> Bool {
    179     calls += 1
    180     if calls == 1 {
    181       await pause.wait(); return false
    182     }
    183     return true
    184   }
    185 }