-
Notifications
You must be signed in to change notification settings - Fork 84
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Don't fail closeFuture when an error occurs on closing #487
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -71,7 +71,10 @@ class ConfiguringPipelineInlineMultiplexerTests: XCTestCase { | |
) | ||
) | ||
|
||
clientMultiplexer.createStreamChannel(promise: nil) { channel in | ||
let errorHandler = ErrorEncounteredHandler() | ||
let streamChannelPromise = self.clientChannel.eventLoop.makePromise(of: Channel.self) | ||
clientMultiplexer.createStreamChannel(promise: streamChannelPromise) { channel in | ||
try? channel.pipeline.addHandler(errorHandler).wait() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This stream channel initializer will be executed on the event-loop; you can't There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This one got marked as resolved but wasn't actually resolved. FWIW I also don't think it's necessary for all of these tests to check this behaviour (i.e. the stream closed error gets fired down the pipeline); we end up with a much larger diff than necessary and harder to maintain tests. I'd prefer we had a separate test which asserts the specific behaviour. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Ah, sorry I fixed it in a bunch of places but missed a few others.
We were already performing assertions on the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No worries, I saw the first one and assumed they'd all been missed. I'm okay not reverting it, the work's been done now. I get the following the existing pattern argument; I just think we should be mindful when we make changes like this to keep tests maintainable. This package is bad enough as it is as most tests have about three different versions because of the different multiplexing APIs... |
||
channel.writeAndFlush(reqFrame.payload).whenComplete { _ in channel.close(promise: requestPromise) } | ||
return channel.eventLoop.makeSucceededFuture(()) | ||
} | ||
|
@@ -82,9 +85,10 @@ class ConfiguringPipelineInlineMultiplexerTests: XCTestCase { | |
self.interactInMemory(self.clientChannel, self.serverChannel) | ||
(self.clientChannel.eventLoop as! EmbeddedEventLoop).run() | ||
|
||
XCTAssertThrowsError(try requestPromise.futureResult.wait()) { error in | ||
XCTAssertTrue(error is NIOHTTP2Errors.StreamClosed) | ||
} | ||
let streamChannel = try XCTUnwrap(streamChannelPromise.futureResult.wait()) | ||
XCTAssertNoThrow(try streamChannel.closeFuture.wait()) | ||
XCTAssertNoThrow(try requestPromise.futureResult.wait()) | ||
XCTAssertTrue(errorHandler.encounteredError is NIOHTTP2Errors.StreamClosed) | ||
|
||
// We should have received a HEADERS and a RST_STREAM frame. | ||
// The RST_STREAM frame is from closing an incomplete stream on the client side. | ||
|
@@ -133,7 +137,10 @@ class ConfiguringPipelineInlineMultiplexerTests: XCTestCase { | |
) | ||
) | ||
|
||
clientMultiplexer.createStreamChannel(promise: nil) { channel in | ||
let errorHandler = ErrorEncounteredHandler() | ||
let streamChannelPromise = self.clientChannel.eventLoop.makePromise(of: Channel.self) | ||
clientMultiplexer.createStreamChannel(promise: streamChannelPromise) { channel in | ||
try? channel.pipeline.addHandler(errorHandler).wait() | ||
channel.writeAndFlush(reqFrame.payload).whenComplete { _ in channel.close(promise: requestPromise) } | ||
return channel.eventLoop.makeSucceededFuture(()) | ||
} | ||
|
@@ -144,9 +151,10 @@ class ConfiguringPipelineInlineMultiplexerTests: XCTestCase { | |
self.interactInMemory(self.clientChannel, self.serverChannel) | ||
(self.clientChannel.eventLoop as! EmbeddedEventLoop).run() | ||
|
||
XCTAssertThrowsError(try requestPromise.futureResult.wait()) { error in | ||
XCTAssertTrue(error is NIOHTTP2Errors.StreamClosed) | ||
} | ||
let streamChannel = try XCTUnwrap(streamChannelPromise.futureResult.wait()) | ||
XCTAssertNoThrow(try streamChannel.closeFuture.wait()) | ||
XCTAssertNoThrow(try requestPromise.futureResult.wait()) | ||
XCTAssertTrue(errorHandler.encounteredError is NIOHTTP2Errors.StreamClosed) | ||
|
||
// We should have received a HEADERS and a RST_STREAM frame. | ||
// The RST_STREAM frame is from closing an incomplete stream on the client side. | ||
|
@@ -466,7 +474,10 @@ class ConfiguringPipelineInlineMultiplexerTests: XCTestCase { | |
) | ||
) | ||
|
||
clientMultiplexer.createStreamChannel(promise: nil) { channel in | ||
let errorHandler = ErrorEncounteredHandler() | ||
let streamChannelPromise = self.clientChannel.eventLoop.makePromise(of: Channel.self) | ||
clientMultiplexer.createStreamChannel(promise: streamChannelPromise) { channel in | ||
try? channel.pipeline.addHandler(errorHandler).wait() | ||
channel.writeAndFlush(reqFrame.payload).whenComplete { _ in channel.close(promise: requestPromise) } | ||
return channel.eventLoop.makeSucceededFuture(()) | ||
} | ||
|
@@ -476,9 +487,11 @@ class ConfiguringPipelineInlineMultiplexerTests: XCTestCase { | |
(self.clientChannel.eventLoop as! EmbeddedEventLoop).run() | ||
self.interactInMemory(self.clientChannel, self.serverChannel) | ||
(self.clientChannel.eventLoop as! EmbeddedEventLoop).run() | ||
XCTAssertThrowsError(try requestPromise.futureResult.wait()) { error in | ||
XCTAssertTrue(error is NIOHTTP2Errors.StreamClosed) | ||
} | ||
|
||
let streamChannel = try XCTUnwrap(streamChannelPromise.futureResult.wait()) | ||
XCTAssertNoThrow(try streamChannel.closeFuture.wait()) | ||
XCTAssertNoThrow(try requestPromise.futureResult.wait()) | ||
XCTAssertTrue(errorHandler.encounteredError is NIOHTTP2Errors.StreamClosed) | ||
|
||
// Assert that the user-provided handler received the | ||
// HTTP1 parts corresponding to the H2 message sent | ||
|
@@ -556,7 +569,10 @@ class ConfiguringPipelineInlineMultiplexerTests: XCTestCase { | |
) | ||
) | ||
|
||
clientMultiplexer.createStreamChannel(promise: nil) { channel in | ||
let errorHandler = ErrorEncounteredHandler() | ||
let streamChannelPromise = self.clientChannel.eventLoop.makePromise(of: Channel.self) | ||
clientMultiplexer.createStreamChannel(promise: streamChannelPromise) { channel in | ||
try? channel.pipeline.addHandler(errorHandler).wait() | ||
channel.writeAndFlush(reqFrame.payload).whenComplete { _ in channel.close(promise: requestPromise) } | ||
return channel.eventLoop.makeSucceededFuture(()) | ||
} | ||
|
@@ -566,9 +582,11 @@ class ConfiguringPipelineInlineMultiplexerTests: XCTestCase { | |
(self.clientChannel.eventLoop as! EmbeddedEventLoop).run() | ||
self.interactInMemory(self.clientChannel, self.serverChannel) | ||
(self.clientChannel.eventLoop as! EmbeddedEventLoop).run() | ||
XCTAssertThrowsError(try requestPromise.futureResult.wait()) { error in | ||
XCTAssertTrue(error is NIOHTTP2Errors.StreamClosed) | ||
} | ||
|
||
let streamChannel = try XCTUnwrap(streamChannelPromise.futureResult.wait()) | ||
XCTAssertNoThrow(try streamChannel.closeFuture.wait()) | ||
XCTAssertNoThrow(try requestPromise.futureResult.wait()) | ||
XCTAssertTrue(errorHandler.encounteredError is NIOHTTP2Errors.StreamClosed) | ||
|
||
// Assert that the user-provided handler received the | ||
// HTTP1 parts corresponding to the H2 message sent | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is what was agreed: IIRC the promise from
close(mode:promise:)
(i.e.pendingClosePromise
) can fail to provide diagnostic information. It's thecloseFuture
(i.e. part of theChannel
API) which mustn't fail.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree with what @glbrntt said here. This means we need to change the implementation of
executeThenClose
to discard the error fromclose
and instead add a call tocloseFuture.get()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And update the docs for
Channel.closeFuture
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh okay, I misunderstood this. The one thing I found weird when implementing this (and why I decided to not fail this promise either) is that calling
channel.close()
will return a failed promise (since it creates one and passes it tochannel.close(promise: newPromise)
under the hood), which I personally find slightly confusing. But if you're okay with this behaviour I can just be clear in the docs about it.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's expected. Roughly speaking:
channel.close(promise:)
(and variants of, i.e.channel.close()
) are "close the channel and tell me how it closed" (cleanly/uncleanly)channel.closeFuture
is "tell me when the channel is closed"