Skip to content
Permalink
Browse files

Add an `always` method on EventLoopFuture (#981)

Add an `always` method on EventLoopFuture

Motivation:

#665

Modifications:

* Add `always` in EventLoopFuture.swift
* Add tests

Result:

NIO Users will be able to use `.always` to, well, always run an action
wether the future succeed or not.
  • Loading branch information...
Palleas authored and weissi committed May 15, 2019
1 parent 5513bb2 commit c59c193ea7fd2ac0f8819e7f1fc8c47a2e60eca7
@@ -1267,3 +1267,17 @@ func executeAndComplete<Value>(_ promise: EventLoopPromise<Value>?, _ body: () t
promise?.fail(e)
}
}


extension EventLoopFuture {
/// Adds an observer callback to this `EventLoopFuture` that is called when the
/// `EventLoopFuture` has any result.
///
/// - parameters:
/// - callback: the callback that is called when the `EventLoopFuture` is fulfilled.
/// - returns: the current `EventLoopFuture`
public func always(_ callback: @escaping (Result<Value, Error>) -> Void) -> EventLoopFuture<Value> {
self.whenComplete { result in callback(result) }
return self
}
}
@@ -70,6 +70,8 @@ extension EventLoopFutureTest {
("testWhenAllCompleteResultsWithFailuresStillSucceed", testWhenAllCompleteResultsWithFailuresStillSucceed),
("testWhenAllCompleteResults", testWhenAllCompleteResults),
("testWhenAllCompleteResolvesAfterFutures", testWhenAllCompleteResolvesAfterFutures),
("testAlways", testAlways),
("testAlwaysWithFailingPromise", testAlwaysWithFailingPromise),
]
}
}
@@ -1015,4 +1015,49 @@ class EventLoopFutureTest : XCTestCase {
let results = try assertNoThrowWithValue(mainFuture.wait().map { try $0.get() })
XCTAssertEqual(results, [0, 1, 2, 3, 4])
}

struct DatabaseError: Error {}
struct Database {
let query: () -> EventLoopFuture<[String]>

var closed = false

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

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

mutating func close() {
self.closed = true
}
}

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

XCTAssertFalse(db.closed)
let _ = try assertNoThrowWithValue(db.runQuery().always { result in
assertSuccess(result)
db.close()
}.map { $0.map { $0.uppercased() }}.wait())
XCTAssertTrue(db.closed)
}

func testAlwaysWithFailingPromise() throws {
let group = EmbeddedEventLoop()
let loop = group.next()
var db = Database { loop.makeFailedFuture(DatabaseError()) }

XCTAssertFalse(db.closed)
let _ = try XCTAssertThrowsError(db.runQuery().always { result in
assertFailure(result)
db.close()
}.map { $0.map { $0.uppercased() }}.wait()) { XCTAssertTrue($0 is DatabaseError) }
XCTAssertTrue(db.closed)
}
}
@@ -250,3 +250,11 @@ func getBoolSocketOption<IntType: SignedInteger>(channel: Channel, level: IntTyp
file: file,
line: line).wait() != 0
}

func assertSuccess<Value>(_ result: Result<Value, Error>, file: StaticString = #file, line: UInt = #line) {
guard case .success = result else { return XCTFail("Expected result to be successful", file: file, line: line) }
}

func assertFailure<Value>(_ result: Result<Value, Error>, file: StaticString = #file, line: UInt = #line) {
guard case .failure = result else { return XCTFail("Expected result to be a failure", file: file, line: line) }
}

0 comments on commit c59c193

Please sign in to comment.
You can’t perform that action at this time.