-
Notifications
You must be signed in to change notification settings - Fork 380
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
[bug] Write error not returned if reader already signals EOF #494
Changes from all 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 |
---|---|---|
|
@@ -1249,6 +1249,57 @@ func TestClientReadSequential(t *testing.T) { | |
} | ||
} | ||
|
||
type lastChunkErrSequentialWriter struct { | ||
expected int | ||
written int | ||
writtenReturn int | ||
} | ||
|
||
func (w *lastChunkErrSequentialWriter) Write(b []byte) (int, error) { | ||
chunkSize := len(b) | ||
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 alias ends up adding more characters of code than it saves. Sometimes, repetition isn’t a bad thing. |
||
w.written += chunkSize | ||
if w.written == w.expected { | ||
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 test is too strict. If we shoot past |
||
return w.writtenReturn, errors.New("test error") | ||
} | ||
return chunkSize, nil | ||
} | ||
|
||
func TestClientWriteSequential_WriterErr(t *testing.T) { | ||
sftp, cmd := testClient(t, READONLY, NODELAY) | ||
defer cmd.Wait() | ||
defer sftp.Close() | ||
|
||
d, err := ioutil.TempDir("", "sftptest-writesequential-writeerr") | ||
require.NoError(t, err) | ||
|
||
defer os.RemoveAll(d) | ||
|
||
var ( | ||
content = []byte("hello world") | ||
shortWrite = 2 | ||
) | ||
w := lastChunkErrSequentialWriter{ | ||
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.
Unfortunately, this test still does not ensure that the same bug mentioned before could still slip through. We’re still only ever making one call to In the face of all of this, I think special casing all of the functionality of the writer is appropriate. First run returns |
||
expected: len(content), | ||
writtenReturn: shortWrite, | ||
} | ||
|
||
f, err := ioutil.TempFile(d, "write-sequential-writeerr-test") | ||
require.NoError(t, err) | ||
fname := f.Name() | ||
n, err := f.Write(content) | ||
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. Speaking of which, let’s use |
||
require.NoError(t, err) | ||
require.Equal(t, n, len(content)) | ||
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.
If we already passed the |
||
require.NoError(t, f.Close()) | ||
|
||
sftpFile, err := sftp.Open(fname) | ||
require.NoError(t, err) | ||
defer sftpFile.Close() | ||
|
||
gotWritten, gotErr := sftpFile.writeToSequential(&w) | ||
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. We know logically that we could not have reached this code unless Likewise, there will now be no other |
||
require.NotErrorIs(t, io.EOF, gotErr) | ||
require.Equal(t, int64(shortWrite), gotWritten) | ||
Comment on lines
+1299
to
+1300
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. The API is confusing on this matter: This is one of the central reasons why I tell people to avoid using This is especially true, when one is coming from a language that incentivizes writing equality tests as Instead, something like this (without the comments which are here for study, rather than for good code practice):
Also, we don’t want to |
||
} | ||
|
||
func TestClientReadDir(t *testing.T) { | ||
sftp1, cmd1 := testClient(t, READONLY, NODELAY) | ||
sftp2, cmd2 := testClientGoSvr(t, READONLY, NODELAY) | ||
|
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.
there’s no need to rename
err
error. Since we now have an early return, there is no need to access the twoerr
variables at the same time, so shadowing is no longer a problem.