RadrootsAppleBackgroundTaskSchedulerTests.swift (6327B)
1 import Foundation 2 import Testing 3 4 @testable import RadrootsKit 5 6 @Test func appleBackgroundTaskSchedulerRegistersAndSubmitsThroughAdapters() async throws { 7 let probe = RadrootsAppleBackgroundTaskSchedulerProbe(now: Date(timeIntervalSince1970: 100)) 8 let scheduler = RadrootsAppleBackgroundTaskScheduler(adapters: probe.adapters()) 9 let identifier = try RadrootsBackgroundTaskIdentifier("org.radroots.field-ios.background.refresh") 10 let registration = RadrootsAppleBackgroundTaskRegistration( 11 identifier: identifier, 12 kind: .appRefresh, 13 handler: { true } 14 ) 15 let request = try RadrootsBackgroundTaskRequest( 16 identifier: identifier, 17 kind: .appRefresh, 18 earliestBeginDate: Date(timeIntervalSince1970: 120) 19 ) 20 21 #expect(try await scheduler.register(registration)) 22 let snapshot = try await scheduler.submit(request) 23 24 #expect(snapshot.identifier == identifier) 25 #expect(snapshot.submittedAt == Date(timeIntervalSince1970: 100)) 26 #expect(await probe.registeredIdentifiers == [identifier]) 27 #expect(await probe.submittedRequests == [request]) 28 } 29 30 @Test func appleBackgroundTaskSchedulerCancelsAndListsPendingTasksThroughAdapters() async throws { 31 let identifier = try RadrootsBackgroundTaskIdentifier( 32 "org.radroots.field-ios.background.processing") 33 let request = try RadrootsBackgroundTaskRequest( 34 identifier: identifier, 35 kind: .processing, 36 requiresNetworkConnectivity: true 37 ) 38 let pendingSnapshot = try RadrootsBackgroundTaskSnapshot( 39 request: request, 40 submittedAt: Date(timeIntervalSince1970: 5) 41 ) 42 let probe = RadrootsAppleBackgroundTaskSchedulerProbe(pendingSnapshots: [pendingSnapshot]) 43 let scheduler = RadrootsAppleBackgroundTaskScheduler(adapters: probe.adapters()) 44 45 try await scheduler.cancel(identifier) 46 try await scheduler.cancelAll() 47 48 #expect(await probe.cancelledIdentifiers == [identifier]) 49 #expect(await probe.cancelAllCount == 1) 50 #expect(try await scheduler.pendingTasks() == [pendingSnapshot]) 51 } 52 53 @Test func appleBackgroundTaskSchedulerMapsAdapterSubmitFailures() async throws { 54 let probe = RadrootsAppleBackgroundTaskSchedulerProbe( 55 submitOutcome: .failure(.schedulerFailure) 56 ) 57 let scheduler = RadrootsAppleBackgroundTaskScheduler(adapters: probe.adapters()) 58 let request = try RadrootsBackgroundTaskRequest( 59 identifier: "org.radroots.field-ios.background.refresh", 60 kind: .appRefresh 61 ) 62 63 await #expect(throws: RadrootsBackgroundTaskError.schedulerFailure) { 64 _ = try await scheduler.submit(request) 65 } 66 } 67 68 @Test func appleBackgroundTaskSchedulerMapsRegistrationRejectionToTypedFailure() async throws { 69 let probe = RadrootsAppleBackgroundTaskSchedulerProbe(registerResult: false) 70 let scheduler = RadrootsAppleBackgroundTaskScheduler(adapters: probe.adapters()) 71 let identifier = try RadrootsBackgroundTaskIdentifier("org.radroots.field-ios.background.refresh") 72 let registration = RadrootsAppleBackgroundTaskRegistration( 73 identifier: identifier, 74 kind: .appRefresh, 75 handler: { true } 76 ) 77 78 await #expect(throws: RadrootsBackgroundTaskError.schedulerFailure) { 79 _ = try await scheduler.register(registration) 80 } 81 #expect(await probe.registeredIdentifiers == [identifier]) 82 } 83 84 private actor RadrootsAppleBackgroundTaskSchedulerProbe { 85 private let nowValue: Date 86 private let registerResult: Bool 87 private let submitOutcome: Result<Void, RadrootsBackgroundTaskError> 88 private var pendingSnapshotsValue: [RadrootsBackgroundTaskSnapshot] 89 private var registeredIdentifiersValue: [RadrootsBackgroundTaskIdentifier] 90 private var submittedRequestsValue: [RadrootsBackgroundTaskRequest] 91 private var cancelledIdentifiersValue: [RadrootsBackgroundTaskIdentifier] 92 private var cancelAllCountValue: Int 93 94 init( 95 now: Date = Date(timeIntervalSince1970: 0), 96 registerResult: Bool = true, 97 submitOutcome: Result<Void, RadrootsBackgroundTaskError> = .success(()), 98 pendingSnapshots: [RadrootsBackgroundTaskSnapshot] = [] 99 ) { 100 nowValue = now 101 self.registerResult = registerResult 102 self.submitOutcome = submitOutcome 103 pendingSnapshotsValue = pendingSnapshots 104 registeredIdentifiersValue = [] 105 submittedRequestsValue = [] 106 cancelledIdentifiersValue = [] 107 cancelAllCountValue = 0 108 } 109 110 nonisolated func adapters() -> RadrootsAppleBackgroundTaskSchedulerAdapters { 111 RadrootsAppleBackgroundTaskSchedulerAdapters( 112 now: { 113 self.nowValue 114 }, 115 register: { registration in 116 await self.register(registration) 117 }, 118 submit: { request in 119 try await self.submit(request) 120 }, 121 cancel: { identifier in 122 await self.cancel(identifier) 123 }, 124 cancelAll: { 125 await self.cancelAll() 126 }, 127 pendingTasks: { 128 await self.pendingSnapshots() 129 } 130 ) 131 } 132 133 private func register(_ registration: RadrootsAppleBackgroundTaskRegistration) -> Bool { 134 registeredIdentifiersValue.append(registration.identifier) 135 return registerResult 136 } 137 138 private func submit(_ request: RadrootsBackgroundTaskRequest) throws { 139 submittedRequestsValue.append(request) 140 switch submitOutcome { 141 case .success: 142 return 143 case .failure(let error): 144 throw error 145 } 146 } 147 148 private func cancel(_ identifier: RadrootsBackgroundTaskIdentifier) { 149 cancelledIdentifiersValue.append(identifier) 150 } 151 152 private func cancelAll() { 153 cancelAllCountValue += 1 154 } 155 156 private func pendingSnapshots() -> [RadrootsBackgroundTaskSnapshot] { 157 pendingSnapshotsValue 158 } 159 160 var registeredIdentifiers: [RadrootsBackgroundTaskIdentifier] { 161 registeredIdentifiersValue 162 } 163 164 var submittedRequests: [RadrootsBackgroundTaskRequest] { 165 submittedRequestsValue 166 } 167 168 var cancelledIdentifiers: [RadrootsBackgroundTaskIdentifier] { 169 cancelledIdentifiersValue 170 } 171 172 var cancelAllCount: Int { 173 cancelAllCountValue 174 } 175 }