Skip to content

Commit 0e8a3c1

Browse files
committed
Improve test stability
Run the continuation double-resume stress tests with DispatchQueue.concurrentPerform so each test waits for its 10,000 outer workers to reach the race window before returning. Extend their XCTest timeout to 20 seconds for slower CI workers. Verified the three stress tests passed serially in 7.5-8.3 seconds each. Temporarily restoring the historical unsynchronized Single bridge made testSingleContinuationIsNotResumedTwice abort, confirming the revised test still detects the original double-resume regression.
1 parent 66df31e commit 0e8a3c1

1 file changed

Lines changed: 48 additions & 54 deletions

File tree

‎Tests/RxSwiftTests/PrimitiveSequence+ConcurrencyTests.swift‎

Lines changed: 48 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -94,32 +94,30 @@ extension PrimitiveSequenceConcurrencyTests {
9494
func testSingleContinuationIsNotResumedTwice() {
9595
let expectation = XCTestExpectation()
9696
let iterations = 10000
97-
for i in 0 ..< iterations {
98-
DispatchQueue.global(qos: .userInitiated).async {
99-
let single = Single<Int>.create { observer in
100-
DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + 0.005) {
101-
observer(.success(42))
102-
}
103-
return Disposables.create()
97+
DispatchQueue.concurrentPerform(iterations: iterations) { i in
98+
let single = Single<Int>.create { observer in
99+
DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + 0.005) {
100+
observer(.success(42))
104101
}
102+
return Disposables.create()
103+
}
105104

106-
let task = Task {
107-
_ = try await single.value
108-
}
105+
let task = Task {
106+
_ = try await single.value
107+
}
109108

110-
DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + 0.005) {
111-
task.cancel()
112-
}
109+
DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + 0.005) {
110+
task.cancel()
111+
}
113112

114-
self.sleep(Double.random(in: 0.004 ... 0.006))
113+
self.sleep(Double.random(in: 0.004 ... 0.006))
115114

116-
if i == iterations - 1 {
117-
expectation.fulfill()
118-
}
115+
if i == iterations - 1 {
116+
expectation.fulfill()
119117
}
120118
}
121119

122-
wait(for: [expectation], timeout: 10)
120+
wait(for: [expectation], timeout: 20)
123121
}
124122
}
125123

@@ -210,32 +208,30 @@ extension PrimitiveSequenceConcurrencyTests {
210208
func testMaybeContinuationIsNotResumedTwice() {
211209
let expectation = XCTestExpectation()
212210
let iterations = 10000
213-
for i in 0 ..< iterations {
214-
DispatchQueue.global(qos: .userInitiated).async {
215-
let maybe = Maybe<Bool>.create { observer in
216-
DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + 0.005) {
217-
observer(.success(true))
218-
}
219-
return Disposables.create()
211+
DispatchQueue.concurrentPerform(iterations: iterations) { i in
212+
let maybe = Maybe<Bool>.create { observer in
213+
DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + 0.005) {
214+
observer(.success(true))
220215
}
216+
return Disposables.create()
217+
}
221218

222-
let task = Task {
223-
_ = try await maybe.value
224-
}
219+
let task = Task {
220+
_ = try await maybe.value
221+
}
225222

226-
DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + 0.005) {
227-
task.cancel()
228-
}
223+
DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + 0.005) {
224+
task.cancel()
225+
}
229226

230-
self.sleep(Double.random(in: 0.004 ... 0.006))
227+
self.sleep(Double.random(in: 0.004 ... 0.006))
231228

232-
if i == iterations - 1 {
233-
expectation.fulfill()
234-
}
229+
if i == iterations - 1 {
230+
expectation.fulfill()
235231
}
236232
}
237233

238-
wait(for: [expectation], timeout: 10)
234+
wait(for: [expectation], timeout: 20)
239235
}
240236
}
241237

@@ -298,32 +294,30 @@ extension PrimitiveSequenceConcurrencyTests {
298294
func testCompletableContinuationIsNotResumedTwice() {
299295
let expectation = XCTestExpectation()
300296
let iterations = 10000
301-
for i in 0 ..< iterations {
302-
DispatchQueue.global(qos: .userInitiated).async {
303-
let completable = Completable.create { observer in
304-
DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + 0.005) {
305-
observer(.completed)
306-
}
307-
return Disposables.create()
297+
DispatchQueue.concurrentPerform(iterations: iterations) { i in
298+
let completable = Completable.create { observer in
299+
DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + 0.005) {
300+
observer(.completed)
308301
}
302+
return Disposables.create()
303+
}
309304

310-
let task = Task {
311-
_ = try await completable.value
312-
}
305+
let task = Task {
306+
_ = try await completable.value
307+
}
313308

314-
DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + 0.005) {
315-
task.cancel()
316-
}
309+
DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + 0.005) {
310+
task.cancel()
311+
}
317312

318-
self.sleep(Double.random(in: 0.004 ... 0.006))
313+
self.sleep(Double.random(in: 0.004 ... 0.006))
319314

320-
if i == iterations - 1 {
321-
expectation.fulfill()
322-
}
315+
if i == iterations - 1 {
316+
expectation.fulfill()
323317
}
324318
}
325319

326-
wait(for: [expectation], timeout: 10)
320+
wait(for: [expectation], timeout: 20)
327321
}
328322
}
329323
#endif

0 commit comments

Comments
 (0)