Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 53 additions & 50 deletions Tests/NIOPosixTests/EventLoopFutureTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -851,8 +851,8 @@ class EventLoopFutureTest: XCTestCase {
let promises = (0..<5).map { _ in group.next().makePromise(of: Int.self) }
let futures = promises.map { $0.futureResult }

var succeeded = false
var completedPromises = false
let succeeded = NIOLockedValueBox(false)
let completedPromises = NIOLockedValueBox(false)

let mainFuture: EventLoopFuture<[Int]>

Expand All @@ -864,24 +864,24 @@ class EventLoopFutureTest: XCTestCase {
}

mainFuture.whenSuccess { _ in
XCTAssertTrue(completedPromises)
XCTAssertFalse(succeeded)
succeeded = true
XCTAssertTrue(completedPromises.withLockedValue { $0 })
XCTAssertFalse(succeeded.withLockedValue { $0 })
succeeded.withLockedValue { $0 = true }
}

// Should be false, as none of the promises have completed yet
XCTAssertFalse(succeeded)
XCTAssertFalse(succeeded.withLockedValue { $0 })

// complete the first four promises
for (index, promise) in promises.dropLast().enumerated() {
promise.succeed(index)
}

// Should still be false, as one promise hasn't completed yet
XCTAssertFalse(succeeded)
XCTAssertFalse(succeeded.withLockedValue { $0 })

// Complete the last promise
completedPromises = true
completedPromises.withLockedValue { $0 = true }
promises.last!.succeed(4)

let results = try assertNoThrowWithValue(mainFuture.wait())
Expand All @@ -903,8 +903,8 @@ class EventLoopFutureTest: XCTestCase {
let promises = expected.map { _ in group.next().makePromise(of: Int.self) }
let futures = promises.map { $0.futureResult }

var succeeded = false
var completedPromises = false
let succeeded = NIOLockedValueBox(false)
let completedPromises = NIOLockedValueBox(false)

let mainFuture: EventLoopFuture<[Int]>

Expand All @@ -916,14 +916,14 @@ class EventLoopFutureTest: XCTestCase {
}

mainFuture.whenSuccess { _ in
XCTAssertTrue(completedPromises)
XCTAssertFalse(succeeded)
succeeded = true
XCTAssertTrue(completedPromises.withLockedValue { $0 })
XCTAssertFalse(succeeded.withLockedValue { $0 })
succeeded.withLockedValue { $0 = true }
}

for index in expected.reversed() {
if index == 0 {
completedPromises = true
completedPromises.withLockedValue { $0 = true }
}
promises[index].succeed(index)
}
Expand Down Expand Up @@ -1009,8 +1009,8 @@ class EventLoopFutureTest: XCTestCase {
let promises = (0..<5).map { _ in group.next().makePromise(of: Int.self) }
let futures = promises.map { $0.futureResult }

var succeeded = false
var completedPromises = false
let succeeded = NIOLockedValueBox(false)
let completedPromises = NIOLockedValueBox(false)

let mainFuture: EventLoopFuture<[Result<Int, Error>]>

Expand All @@ -1022,24 +1022,24 @@ class EventLoopFutureTest: XCTestCase {
}

mainFuture.whenSuccess { _ in
XCTAssertTrue(completedPromises)
XCTAssertFalse(succeeded)
succeeded = true
XCTAssertTrue(completedPromises.withLockedValue { $0 })
XCTAssertFalse(succeeded.withLockedValue { $0 })
succeeded.withLockedValue { $0 = true }
}

// Should be false, as none of the promises have completed yet
XCTAssertFalse(succeeded)
XCTAssertFalse(succeeded.withLockedValue { $0 })

// complete the first four promises
for (index, promise) in promises.dropLast().enumerated() {
promise.succeed(index)
}

// Should still be false, as one promise hasn't completed yet
XCTAssertFalse(succeeded)
XCTAssertFalse(succeeded.withLockedValue { $0 })

// Complete the last promise
completedPromises = true
completedPromises.withLockedValue { $0 = true }
promises.last!.succeed(4)

let results = try assertNoThrowWithValue(mainFuture.wait().map { try $0.get() })
Expand All @@ -1051,28 +1051,31 @@ class EventLoopFutureTest: XCTestCase {
}

struct DatabaseError: Error {}
struct Database {
let query: () -> EventLoopFuture<[String]>
final class Database: Sendable {
private let query: @Sendable () -> EventLoopFuture<[String]>
private let _closed = NIOLockedValueBox(false)

var closed = false
var closed: Bool {
self._closed.withLockedValue { $0 }
}

init(query: @escaping () -> EventLoopFuture<[String]>) {
init(query: @escaping @Sendable () -> EventLoopFuture<[String]>) {
self.query = query
}

func runQuery() -> EventLoopFuture<[String]> {
query()
self.query()
}

mutating func close() {
self.closed = true
func close() {
self._closed.withLockedValue { $0 = true }
}
}

func testAlways() throws {
let group = EmbeddedEventLoop()
let loop = group.next()
var db = Database { loop.makeSucceededFuture(["Item 1", "Item 2", "Item 3"]) }
let db = Database { loop.makeSucceededFuture(["Item 1", "Item 2", "Item 3"]) }

XCTAssertFalse(db.closed)
let _ = try assertNoThrowWithValue(
Expand All @@ -1087,7 +1090,7 @@ class EventLoopFutureTest: XCTestCase {
func testAlwaysWithFailingPromise() throws {
let group = EmbeddedEventLoop()
let loop = group.next()
var db = Database { loop.makeFailedFuture(DatabaseError()) }
let db = Database { loop.makeFailedFuture(DatabaseError()) }

XCTAssertFalse(db.closed)
let _ = try XCTAssertThrowsError(
Expand Down Expand Up @@ -1173,26 +1176,26 @@ class EventLoopFutureTest: XCTestCase {

func testAndAllCompleteWithZeroFutures() {
let eventLoop = EmbeddedEventLoop()
let done = DispatchWorkItem {}
let done = DispatchSemaphore(value: 0)
EventLoopFuture<Void>.andAllComplete([], on: eventLoop).whenComplete { (result: Result<Void, Error>) in
_ = result.mapError { error -> Error in
XCTFail("unexpected error \(error)")
return error
}
done.perform()
done.signal()
}
done.wait()
}

func testAndAllSucceedWithZeroFutures() {
let eventLoop = EmbeddedEventLoop()
let done = DispatchWorkItem {}
let done = DispatchSemaphore(value: 0)
EventLoopFuture<Void>.andAllSucceed([], on: eventLoop).whenComplete { result in
_ = result.mapError { error -> Error in
XCTFail("unexpected error \(error)")
return error
}
done.perform()
done.signal()
}
done.wait()
}
Expand Down Expand Up @@ -1325,12 +1328,12 @@ class EventLoopFutureTest: XCTestCase {
}

let exitPromise: EventLoopPromise<Void> = elg1.next().makePromise()
var callNumber = 0
let callNumber = NIOLockedValueBox(0)
_ = elg1.next().scheduleRepeatedAsyncTask(initialDelay: .nanoseconds(0), delay: .nanoseconds(0)) { task in
struct Dummy: Error {}

callNumber += 1
switch callNumber {
callNumber.withLockedValue { $0 += 1 }
switch callNumber.withLockedValue({ $0 }) {
case 1:
return elg2.next().makeSucceededFuture(())
case 2:
Expand Down Expand Up @@ -1460,18 +1463,18 @@ class EventLoopFutureTest: XCTestCase {
func testWhenFailureBlocking() {
let eventLoop = EmbeddedEventLoop()
let sem = DispatchSemaphore(value: 0)
var nonBlockingRan = false
let nonBlockingRan = NIOLockedValueBox(false)
let p = eventLoop.makePromise(of: String.self)
p.futureResult.whenFailureBlocking(onto: DispatchQueue.global()) { err in
sem.wait() // Block in callback
XCTAssertEqual(err as! EventLoopFutureTestError, EventLoopFutureTestError.example)
XCTAssertTrue(nonBlockingRan)
XCTAssertTrue(nonBlockingRan.withLockedValue { $0 })
}
p.fail(EventLoopFutureTestError.example)

let p2 = eventLoop.makePromise(of: Bool.self)
p2.futureResult.whenSuccess { _ in
nonBlockingRan = true
nonBlockingRan.withLockedValue { $0 = true }
}
p2.succeed(true)

Expand All @@ -1481,17 +1484,17 @@ class EventLoopFutureTest: XCTestCase {
func testWhenCompleteBlockingSuccess() {
let eventLoop = EmbeddedEventLoop()
let sem = DispatchSemaphore(value: 0)
var nonBlockingRan = false
let nonBlockingRan = NIOLockedValueBox(false)
let p = eventLoop.makePromise(of: String.self)
p.futureResult.whenCompleteBlocking(onto: DispatchQueue.global()) { _ in
sem.wait() // Block in callback
XCTAssertTrue(nonBlockingRan)
XCTAssertTrue(nonBlockingRan.withLockedValue { $0 })
}
p.succeed("hello")

let p2 = eventLoop.makePromise(of: Bool.self)
p2.futureResult.whenSuccess { _ in
nonBlockingRan = true
nonBlockingRan.withLockedValue { $0 = true }
}
p2.succeed(true)

Expand All @@ -1501,17 +1504,17 @@ class EventLoopFutureTest: XCTestCase {
func testWhenCompleteBlockingFailure() {
let eventLoop = EmbeddedEventLoop()
let sem = DispatchSemaphore(value: 0)
var nonBlockingRan = false
let nonBlockingRan = NIOLockedValueBox(false)
let p = eventLoop.makePromise(of: String.self)
p.futureResult.whenCompleteBlocking(onto: DispatchQueue.global()) { _ in
sem.wait() // Block in callback
XCTAssertTrue(nonBlockingRan)
XCTAssertTrue(nonBlockingRan.withLockedValue { $0 })
}
p.fail(EventLoopFutureTestError.example)

let p2 = eventLoop.makePromise(of: Bool.self)
p2.futureResult.whenSuccess { _ in
nonBlockingRan = true
nonBlockingRan.withLockedValue { $0 = true }
}
p2.succeed(true)

Expand Down Expand Up @@ -1548,11 +1551,11 @@ class EventLoopFutureTest: XCTestCase {

let futures = (1...10).map { el.makeSucceededFuture($0) }

var calls = 0
let calls = NIOLockedValueBox(0)
let all = el.makeSucceededFuture(0).foldWithEventLoop(futures) { l, r, el2 in
calls += 1
calls.withLockedValue { $0 += 1 }
XCTAssert(el === el2)
XCTAssertEqual(calls, r)
XCTAssertEqual(calls.withLockedValue { $0 }, r)
return el2.makeSucceededFuture(l + r)
}

Expand Down
Loading
Loading