-
Notifications
You must be signed in to change notification settings - Fork 235
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
Allow half-closed reads and test against TCP/TLS connections #131
Conversation
Specifically to debug hashicorp/nomad#23305 but tests should probably run against multiple net.Conn implementations as yamux is sensitive to net.Conn behaviors such as concurrent Read|Write|Close and what errors are returned.
Effectively reverts 912e296 Reasons to revert to locally closed streams being readable: Matches libp2p's yamux fork: https://github.com/libp2p/go-yamux/blob/master/stream.go#L95-L96 Both yamux and SPDY make it clear that a locally closed stream cannot send more data. SPDY explicitly supports unidirectional streams where one peer is closed (readonly) from the beginning: https://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3-1/#46-unidirectional-streams
0 functional changes.
TestSession_PartialReadWindowUpdate asserts that large sends can cause window updates. When using io.Pipes the server recieves the window update nearly synchronously during the client's Read call. Using tcp sockets adds just enough latency to reliably lose the race for observing the window update on the server. Added a sleep to ensure the server has time to read and apply the window update from the client. I also added a number of comments and non-functional cleanups. The time.Sleep() is the only functional change.
Expanded tests to use TCP and TLS. Sorry for the huge diff, but I think this makes yamux's test suite much more realistic. There are quite a few new tools: - testConnPipe is the original io.Pipe based testing tool. Some tests still require it due to the ability to easily pause the data flow. - testConnTCP and testConnTLS create TCP and TLS connections for yamux to use. This introduces more realistic timing issues, buffering, and subtle differences in error messages. - testConnTypes is a helper to run subtests against *all* the above connection types as well as ensuring reversing the client/server sockets doesn't impact yamux (it didn't!). I didn't convert every test to it since it adds some time and noise to test runs. I also tried to formalize (client, server) as a pattern. There was a mix of orderings. Those roles are rarely meaningful to yamux, but meaningful names makes debugging easier than numbering variables.
Since switching this to test against TLS made it fail until d96c90e was applied it should be tested against all conn types. Curiously io.Pipe is unaffected by the change in half close behavior.
session_test.go
Outdated
} | ||
t.Cleanup(func() { _ = l.Close() }) | ||
|
||
var srv net.Conn |
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.
This feels slightly racy. Probably better to send this net.Conn
back out of the goroutine using another channel?
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.
Same as above, errCh synchronizes access to srv... although switching naming schemes is a bit annoying. I'll fix that up.
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.
LGTM! 👍
// See testConnType | ||
type connTypeTest struct { | ||
Name string | ||
Conns connTypeFunc | ||
} |
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.
This could probably be an anonymous struct in testConnTypes
, which would leave one fewer top-level object for developers to figure out when reading an inherently complex test file.
Summary
Details
In an attempt to debug hashicorp/nomad#23305 I switched tests from using
io.Pipe
totls.Conn
for transports.While this did not uncover the root cause of 23305, it did catch a case where the implementation did not follow the yamux or SPDY specs: after calling Stream.Close, you can still call Stream.Read. Reads on half-closed streams had been explicitly disallowed in 912e296 for unclear reasons. Even at the time
TestHalfClose
was unaffected by this change. Switching the test from io.Pipe to tls.Conn uncovered the bug. See https://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3-1/#236-stream-half-close for details.Individual commits have more details and are hopefully grouped reasonably. In particular 5bda672 describes the new test helpers.
#127
Sadly no test results changed before or after #127 was applied. This is not entirely surprising as we already suspected tests did not cover the changes being made.