-
-
Notifications
You must be signed in to change notification settings - Fork 78
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
[Fix] Query Hangs if Connection is Closed #487
[Fix] Query Hangs if Connection is Closed #487
Conversation
Cancelled the integration tests CI manually, since they wouldn't have finished. Side note @gwynne: probably good to have a time limit in CIs. |
The default timeout is 1 hour, IIRC. |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #487 +/- ##
==========================================
+ Coverage 54.98% 55.28% +0.30%
==========================================
Files 127 127
Lines 10155 10161 +6
==========================================
+ Hits 5584 5618 +34
+ Misses 4571 4543 -28
|
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.
Great catch! We really need to make sure we cover all cases by adding unit tests for each of them!
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.
Sorry used wrong button before :)
the test I added as an example hangs 100% of time for me. |
Hmm you're right. I thought i tested that properly and it turned out like i said, but apparently not. I was likely testing with my fixes in there, and not reverted. |
ahh hmm CI is failing with |
I reckon I didn't add a unit test for "each" modified function. Should I? |
Yes, please! |
} | ||
} | ||
|
||
func testListenFailsIfConnectionIsClosedMidway() async throws { |
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.
What connection state do you want to test here? In which connection state does this happen? Can we mock this explicitly and not by accident?
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.
The test is consistent, it only waits 3 seconds to make sure the listener has started listening.
It tests that if there is a listen in process, and then the connection is closed, the listener sequence needs to 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.
ah! in that case we should wait for the client messages on the channel instead of using a timer.
See here how it is done:
postgres-nio/Tests/PostgresNIOTests/New/PostgresConnectionTests.swift
Lines 83 to 96 in 7b621c1
func testSimpleListen() async throws { | |
let (connection, channel) = try await self.makeTestConnectionWithAsyncTestingChannel() | |
try await withThrowingTaskGroup(of: Void.self) { taskGroup in | |
taskGroup.addTask { | |
let events = try await connection.listen("foo") | |
for try await event in events { | |
XCTAssertEqual(event.payload, "wooohooo") | |
break | |
} | |
} | |
let listenMessage = try await channel.waitForUnpreparedRequest() | |
XCTAssertEqual(listenMessage.parse.query, #"LISTEN "foo";"#) |
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.
Thanks for the clues, I did this in the new test.
We no longer need to change that fatalError("Invalid state: \(self.state)")
, it appears that was triggered as a result of my bad test.
@fabianfett i think i no longer need to make another PR out of this?
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.
@fabianfett I think this PR's changes are good, but I noticed this results in a fatal error regardless of my changes:
func testAddListenerFailsIfConnectionIsClosed() async throws {
let (connection, channel) = try await self.makeTestConnectionWithAsyncTestingChannel()
connection.addListener(channel: "example") { context, notification in
XCTFail("Did not expect to receive")
}
try await connection.close()
XCTAssertEqual(channel.isActive, false)
}
|
||
try await channel.writeInbound(PostgresBackendMessage.notification(.init(backendPID: 12, channel: "foo", payload: "wooohooo"))) | ||
|
||
try await connection.close() |
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.
Using .close()
instead of .closeGracefully()
here because .closeGracefully()
will wait it out till infinity and beyond, apparently because it's "graceful" and the listener is still listening.
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.
Great patch! Thanks for pushing through!
This reverts commit f55caa7.
See the test for how to trigger this.