apple_kit

Apple-native services for Radroots iOS and macOS apps
git clone https://radroots.dev/git/apple_kit.git
Log | Files | Refs | README | LICENSE

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 }