Skip to content

Commit 3fc7447

Browse files
authored
Add test for network listener (#411)
1 parent c75282d commit 3fc7447

File tree

2 files changed

+94
-22
lines changed

2 files changed

+94
-22
lines changed

Sources/SwiftQueue/Constraint+Network.swift

Lines changed: 52 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -33,37 +33,28 @@ public enum NetworkType: Int, Codable {
3333
case wifi = 2
3434
}
3535

36-
internal final class NetworkConstraint: SimpleConstraint, CodableConstraint {
36+
internal protocol NetworkMonitor {
3737

38-
/// Require a certain connectivity type
39-
internal let networkType: NetworkType
38+
func hasCorrectNetworkType(require: NetworkType) -> Bool
4039

41-
private var monitor: NWPathMonitor?
40+
func startMonitoring(networkType: NetworkType, operation: SqOperation)
4241

43-
required init(networkType: NetworkType) {
44-
assert(networkType != .any)
45-
self.networkType = networkType
46-
}
42+
}
4743

48-
convenience init?(from decoder: Decoder) throws {
49-
let container = try decoder.container(keyedBy: NetworkConstraintKey.self)
50-
if container.contains(.requireNetwork) {
51-
try self.init(networkType: container.decode(NetworkType.self, forKey: .requireNetwork))
52-
} else { return nil }
53-
}
44+
internal class NWPathMonitorNetworkMonitor: NetworkMonitor {
5445

55-
override func willSchedule(queue: SqOperationQueue, operation: SqOperation) throws {
56-
assert(operation.dispatchQueue != .main)
57-
self.monitor = NWPathMonitor()
58-
}
59-
60-
override func run(operation: SqOperation) -> Bool {
61-
guard let monitor = monitor else { return true }
46+
private let monitor = NWPathMonitor()
6247

48+
func hasCorrectNetworkType(require: NetworkType) -> Bool {
6349
if monitor.currentPath.status == .satisfied {
50+
monitor.pathUpdateHandler = nil
6451
return true
52+
} else {
53+
return false
6554
}
55+
}
6656

57+
func startMonitoring(networkType: NetworkType, operation: SqOperation) {
6758
monitor.pathUpdateHandler = { [monitor, operation, networkType] path in
6859
guard path.status == .satisfied else {
6960
operation.logger.log(.verbose, jobId: operation.name, message: "Unsatisfied network requirement")
@@ -81,8 +72,47 @@ internal final class NetworkConstraint: SimpleConstraint, CodableConstraint {
8172
monitor.pathUpdateHandler = nil
8273
operation.run()
8374
}
84-
8575
monitor.start(queue: operation.dispatchQueue)
76+
}
77+
78+
79+
}
80+
81+
82+
internal final class NetworkConstraint: SimpleConstraint, CodableConstraint {
83+
84+
/// Require a certain connectivity type
85+
internal let networkType: NetworkType
86+
87+
private let monitor: NetworkMonitor
88+
89+
required init(networkType: NetworkType, monitor: NetworkMonitor) {
90+
assert(networkType != .any)
91+
self.networkType = networkType
92+
self.monitor = monitor
93+
}
94+
95+
convenience init(networkType: NetworkType) {
96+
self.init(networkType: networkType, monitor: NWPathMonitorNetworkMonitor())
97+
}
98+
99+
convenience init?(from decoder: Decoder) throws {
100+
let container = try decoder.container(keyedBy: NetworkConstraintKey.self)
101+
if container.contains(.requireNetwork) {
102+
try self.init(networkType: container.decode(NetworkType.self, forKey: .requireNetwork))
103+
} else { return nil }
104+
}
105+
106+
override func willSchedule(queue: SqOperationQueue, operation: SqOperation) throws {
107+
assert(operation.dispatchQueue != .main)
108+
}
109+
110+
override func run(operation: SqOperation) -> Bool {
111+
if monitor.hasCorrectNetworkType(require: networkType) {
112+
return true
113+
}
114+
115+
monitor.startMonitoring(networkType: networkType, operation: operation)
86116
return false
87117
}
88118

Tests/SwiftQueueTests/ConstraintTest+Network.swift

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,46 @@ class ConstraintTestNetwork: XCTestCase {
5454
job.assertSingleCompletion()
5555
}
5656

57+
func testNetworkWaitUntilAvailable() {
58+
let (type, job) = (UUID().uuidString, TestJob())
59+
60+
let creator = TestCreator([type: job])
61+
let semaphore = DispatchSemaphore(value: 0)
62+
63+
let manager = SwiftQueueManagerBuilder(creator: creator).set(persister: NoPersister.shared).build()
64+
JobBuilder(type: type)
65+
.add(constraint: NetworkConstraint(networkType: .wifi, monitor: TestNetworkMonitor(semaphore: semaphore)))
66+
.schedule(manager: manager)
67+
68+
job.assertNoRun()
69+
70+
semaphore.signal()
71+
72+
job.awaitForRemoval()
73+
job.assertSingleCompletion()
74+
}
75+
76+
}
77+
78+
internal class TestNetworkMonitor: NetworkMonitor {
79+
80+
private let semaphore: DispatchSemaphore
81+
82+
private var hasNetworkChanged = false
83+
84+
required init(semaphore: DispatchSemaphore) {
85+
self.semaphore = semaphore
86+
}
87+
88+
func hasCorrectNetworkType(require: NetworkType) -> Bool {
89+
hasNetworkChanged
90+
}
91+
92+
func startMonitoring(networkType: NetworkType, operation: SqOperation) {
93+
operation.dispatchQueue.async { [weak self] in
94+
self?.semaphore.wait()
95+
self?.hasNetworkChanged = true
96+
operation.run()
97+
}
98+
}
5799
}

0 commit comments

Comments
 (0)