Skip to content

Commit 0052995

Browse files
authored
small refactoring (#31)
motivation: prepare for OSS changes: * rename the internal _shutdown function to shutdownItem * add and improve few tests
1 parent a9ec308 commit 0052995

File tree

3 files changed

+73
-30
lines changed

3 files changed

+73
-30
lines changed

Sources/ServiceLauncher/Lifecycle.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ public class Lifecycle {
131131
}
132132
self.state = .starting(configuration.callbackQueue)
133133
}
134-
self._start(on: configuration.callbackQueue, items: items, index: 0) { started, error in
134+
self.startItem(on: configuration.callbackQueue, items: items, index: 0) { started, error in
135135
self.stateLock.lock()
136136
if error != nil {
137137
self.state = .shuttingDown(configuration.callbackQueue)
@@ -165,7 +165,7 @@ public class Lifecycle {
165165
}
166166
}
167167

168-
private func _start(on queue: DispatchQueue, items: [LifecycleItem], index: Int, callback: @escaping (Int, Error?) -> Void) {
168+
private func startItem(on queue: DispatchQueue, items: [LifecycleItem], index: Int, callback: @escaping (Int, Error?) -> Void) {
169169
// async barrier
170170
let start = { (callback) -> Void in queue.async { items[index].start(callback: callback) } }
171171
let callback = { (index, error) -> Void in queue.async { callback(index, error) } }
@@ -183,7 +183,7 @@ public class Lifecycle {
183183
if case .shuttingDown = self.stateLock.withLock({ self.state }) {
184184
return callback(index, nil)
185185
}
186-
self._start(on: queue, items: items, index: index + 1, callback: callback)
186+
self.startItem(on: queue, items: items, index: index + 1, callback: callback)
187187
}
188188
}
189189

@@ -192,7 +192,7 @@ public class Lifecycle {
192192
self.logger.info("shutting down lifecycle")
193193
self.state = .shuttingDown(queue)
194194
}
195-
self._shutdown(on: queue, items: items.reversed(), index: 0, errors: nil) { errors in
195+
self.shutdownItem(on: queue, items: items.reversed(), index: 0, errors: nil) { errors in
196196
self.stateLock.withLock {
197197
guard case .shuttingDown = self.state else {
198198
preconditionFailure("invalid state, \(self.state)")
@@ -204,7 +204,7 @@ public class Lifecycle {
204204
}
205205
}
206206

207-
private func _shutdown(on queue: DispatchQueue, items: [LifecycleItem], index: Int, errors: [String: Error]?, callback: @escaping ([String: Error]?) -> Void) {
207+
private func shutdownItem(on queue: DispatchQueue, items: [LifecycleItem], index: Int, errors: [String: Error]?, callback: @escaping ([String: Error]?) -> Void) {
208208
// async barrier
209209
let shutdown = { (callback) -> Void in queue.async { items[index].shutdown(callback: callback) } }
210210
let callback = { (errors) -> Void in queue.async { callback(errors) } }
@@ -222,7 +222,7 @@ public class Lifecycle {
222222
errors![items[index].label] = error
223223
self.logger.error("failed to stop [\(items[index].label)]: \(error)")
224224
}
225-
self._shutdown(on: queue, items: items, index: index + 1, errors: errors, callback: callback)
225+
self.shutdownItem(on: queue, items: items, index: index + 1, errors: errors, callback: callback)
226226
}
227227
}
228228

Tests/ServiceLauncherTests/LifecycleTests+XCTest.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ extension Tests {
2626
static var allTests: [(String, (Tests) -> () throws -> Void)] {
2727
return [
2828
("testStartThenShutdown", testStartThenShutdown),
29-
("testDispatchQueues", testDispatchQueues),
29+
("testDefaultCallbackQueue", testDefaultCallbackQueue),
30+
("testUserDefinedCallbackQueue", testUserDefinedCallbackQueue),
3031
("testShutdownWhileStarting", testShutdownWhileStarting),
3132
("testShutdownWhenIdle", testShutdownWhenIdle),
3233
("testShutdownWhenShutdown", testShutdownWhenShutdown),

Tests/ServiceLauncherTests/LifecycleTests.swift

Lines changed: 65 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import XCTest
1919

2020
final class Tests: XCTestCase {
2121
func testStartThenShutdown() {
22-
let items = (0 ... Int.random(in: 10 ... 20)).map { _ in GoodItem() }
22+
let items = (5 ... Int.random(in: 10 ... 20)).map { _ in GoodItem() }
2323
let lifecycle = Lifecycle()
2424
lifecycle.register(items)
2525
lifecycle.start(configuration: .init(shutdownSignal: nil)) { startError in
@@ -35,7 +35,7 @@ final class Tests: XCTestCase {
3535
// FIXME: this test does not work in rio
3636
func _testShutdownWithSignal() {
3737
let signal = Lifecycle.Signal.ALRM
38-
let items = (0 ... Int.random(in: 10 ... 20)).map { _ in GoodItem() }
38+
let items = (5 ... Int.random(in: 10 ... 20)).map { _ in GoodItem() }
3939
let lifecycle = Lifecycle()
4040
lifecycle.register(items)
4141
let configuration = Lifecycle.Configuration(shutdownSignal: [signal])
@@ -47,29 +47,71 @@ final class Tests: XCTestCase {
4747
items.forEach { XCTAssertEqual($0.state, .shutdown, "expected item to be shutdown, but \($0.state)") }
4848
}
4949

50-
func testDispatchQueues() {
50+
func testDefaultCallbackQueue() {
51+
let lifecycle = Lifecycle()
52+
var startCalls = [String]()
53+
var stopCalls = [String]()
54+
55+
let items = (1 ... Int.random(in: 10 ... 20)).map { index -> LifecycleItem in
56+
let id = "item-\(index)"
57+
return Lifecycle.Item(label: id,
58+
start: .sync {
59+
dispatchPrecondition(condition: .onQueue(.global()))
60+
startCalls.append(id)
61+
},
62+
shutdown: .sync {
63+
dispatchPrecondition(condition: .onQueue(.global()))
64+
XCTAssertTrue(startCalls.contains(id))
65+
stopCalls.append(id)
66+
})
67+
}
68+
lifecycle.register(items)
69+
70+
lifecycle.start(configuration: .init(shutdownSignal: nil)) { startError in
71+
dispatchPrecondition(condition: .onQueue(.global()))
72+
XCTAssertNil(startError, "not expecting error")
73+
lifecycle.shutdown { shutdownErrors in
74+
dispatchPrecondition(condition: .onQueue(.global()))
75+
XCTAssertNil(shutdownErrors, "not expecting error")
76+
}
77+
}
78+
lifecycle.wait()
79+
items.forEach { item in XCTAssertTrue(startCalls.contains(item.label), "expected \(item.label) to be started") }
80+
items.forEach { item in XCTAssertTrue(stopCalls.contains(item.label), "expected \(item.label) to be stopped") }
81+
}
82+
83+
func testUserDefinedCallbackQueue() {
5184
let lifecycle = Lifecycle()
5285
let testQueue = DispatchQueue(label: UUID().uuidString)
86+
var startCalls = [String]()
87+
var stopCalls = [String]()
5388

54-
lifecycle.register(label: UUID().uuidString,
55-
start: {
56-
dispatchPrecondition(condition: DispatchPredicate.onQueue(testQueue))
57-
},
58-
shutdown: {
59-
dispatchPrecondition(condition: DispatchPredicate.onQueue(testQueue))
60-
})
61-
lifecycle.register(label: UUID().uuidString,
62-
start: {
63-
dispatchPrecondition(condition: DispatchPredicate.onQueue(testQueue))
64-
},
65-
shutdown: {
66-
dispatchPrecondition(condition: DispatchPredicate.onQueue(testQueue))
67-
})
68-
lifecycle.start(configuration: .init(callbackQueue: testQueue, shutdownSignal: nil)) { error in
69-
XCTAssertNil(error)
70-
lifecycle.shutdown()
89+
let items = (1 ... Int.random(in: 10 ... 20)).map { index -> LifecycleItem in
90+
let id = "item-\(index)"
91+
return Lifecycle.Item(label: id,
92+
start: .sync {
93+
dispatchPrecondition(condition: .onQueue(testQueue))
94+
startCalls.append(id)
95+
},
96+
shutdown: .sync {
97+
dispatchPrecondition(condition: .onQueue(testQueue))
98+
XCTAssertTrue(startCalls.contains(id))
99+
stopCalls.append(id)
100+
})
101+
}
102+
lifecycle.register(items)
103+
104+
lifecycle.start(configuration: .init(callbackQueue: testQueue, shutdownSignal: nil)) { startError in
105+
dispatchPrecondition(condition: .onQueue(testQueue))
106+
XCTAssertNil(startError, "not expecting error")
107+
lifecycle.shutdown { shutdownErrors in
108+
dispatchPrecondition(condition: .onQueue(testQueue))
109+
XCTAssertNil(shutdownErrors, "not expecting error")
110+
}
71111
}
72112
lifecycle.wait()
113+
items.forEach { item in XCTAssertTrue(startCalls.contains(item.label), "expected \(item.label) to be started") }
114+
items.forEach { item in XCTAssertTrue(stopCalls.contains(item.label), "expected \(item.label) to be stopped") }
73115
}
74116

75117
func testShutdownWhileStarting() {
@@ -104,7 +146,7 @@ final class Tests: XCTestCase {
104146
}
105147
var started = 0
106148
let startSempahore = DispatchSemaphore(value: 0)
107-
let items = (0 ... Int.random(in: 10 ... 20)).map { _ in Item {
149+
let items = (5 ... Int.random(in: 10 ... 20)).map { _ in Item {
108150
started += 1
109151
startSempahore.signal()
110152
} }
@@ -387,7 +429,7 @@ final class Tests: XCTestCase {
387429
}
388430

389431
let lifecycle = Lifecycle()
390-
let items = (0 ... Int.random(in: 10 ... 20)).map { _ in Sync() }
432+
let items = (5 ... Int.random(in: 10 ... 20)).map { _ in Sync() }
391433
items.forEach { item in
392434
lifecycle.register(label: item.id, start: item.start, shutdown: item.shutdown)
393435
}
@@ -424,7 +466,7 @@ final class Tests: XCTestCase {
424466

425467
func testConcurrency() {
426468
let lifecycle = Lifecycle()
427-
let items = (0 ... 50000).map { _ in GoodItem(startDelay: 0, shutdownDelay: 0) }
469+
let items = (5000 ... 10000).map { _ in GoodItem(startDelay: 0, shutdownDelay: 0) }
428470
let group = DispatchGroup()
429471
items.forEach { item in
430472
group.enter()

0 commit comments

Comments
 (0)