Skip to content

Commit

Permalink
Add File.ReadFrom test with a Sized Reader
Browse files Browse the repository at this point in the history
This tests ReadFrom's determining concurrency from the estimated input
size. go test -cover -integration, before:

coverage: 77.3% of statements

After:

coverage: 79.2% of statements
  • Loading branch information
greatroar committed Dec 24, 2021
1 parent 42e9800 commit 1fffa62
Showing 1 changed file with 59 additions and 5 deletions.
64 changes: 59 additions & 5 deletions client_integration_test.go
Expand Up @@ -7,6 +7,7 @@ import (
"bytes"
"crypto/sha1"
"errors"
"fmt"
"io"
"io/ioutil"
"math/rand"
Expand Down Expand Up @@ -164,7 +165,7 @@ func netPipe(t testing.TB) (io.ReadWriteCloser, io.ReadWriteCloser) {
return c1, r.Conn
}

func testClientGoSvr(t testing.TB, readonly bool, delay time.Duration) (*Client, *exec.Cmd) {
func testClientGoSvr(t testing.TB, readonly bool, delay time.Duration, opts ...ClientOption) (*Client, *exec.Cmd) {
c1, c2 := netPipe(t)

options := []ServerOption{WithDebug(os.Stderr)}
Expand All @@ -183,7 +184,7 @@ func testClientGoSvr(t testing.TB, readonly bool, delay time.Duration) (*Client,
wr = newDelayedWriter(wr, delay)
}

client, err := NewClientPipe(c2, wr)
client, err := NewClientPipe(c2, wr, opts...)
if err != nil {
t.Fatal(err)
}
Expand All @@ -194,13 +195,13 @@ func testClientGoSvr(t testing.TB, readonly bool, delay time.Duration) (*Client,

// testClient returns a *Client connected to a locally running sftp-server
// the *exec.Cmd returned must be defer Wait'd.
func testClient(t testing.TB, readonly bool, delay time.Duration) (*Client, *exec.Cmd) {
func testClient(t testing.TB, readonly bool, delay time.Duration, opts ...ClientOption) (*Client, *exec.Cmd) {
if !*testIntegration {
t.Skip("skipping integration test")
}

if *testServerImpl {
return testClientGoSvr(t, readonly, delay)
return testClientGoSvr(t, readonly, delay, opts...)
}

cmd := exec.Command(*testSftp, "-e", "-R", "-l", debuglevel) // log to stderr, read only
Expand Down Expand Up @@ -228,7 +229,7 @@ func testClient(t testing.TB, readonly bool, delay time.Duration) (*Client, *exe
t.Skipf("could not start sftp-server process: %v", err)
}

sftp, err := NewClientPipe(pr, pw)
sftp, err := NewClientPipe(pr, pw, opts...)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -1489,6 +1490,59 @@ func TestClientReadFrom(t *testing.T) {
}
}

// A sizedReader is a Reader with a completely arbitrary Size.
type sizedReader struct {
io.Reader
size int
}

func (r *sizedReader) Size() int { return r.size }

// Test File.ReadFrom's handling of a Reader's Size:
// it should be used as a heuristic for determining concurrency only.
func TestClientReadFromSizeMismatch(t *testing.T) {
const (
packetSize = 1024
filesize = 4 * packetSize
)

sftp, cmd := testClient(t, READWRITE, NODELAY, MaxPacketChecked(packetSize), UseConcurrentWrites(true))
defer cmd.Wait()
defer sftp.Close()

d, err := ioutil.TempDir("", "sftptest-readfrom-size-mismatch")
if err != nil {
t.Fatal("cannot create temp dir:", err)
}
defer os.RemoveAll(d)

buf := make([]byte, filesize)

for i, reportedSize := range []int{
-1, filesize - 100, filesize, filesize + 100,
} {
t.Run(fmt.Sprint(i), func(t *testing.T) {
r := &sizedReader{Reader: bytes.NewReader(buf), size: reportedSize}

f := path.Join(d, fmt.Sprint(i))
w, err := sftp.Create(f)
if err != nil {
t.Fatal("unexpected error:", err)
}
defer w.Close()

n, err := w.ReadFrom(r)
assert.EqualValues(t, filesize, n)

fi, err := os.Stat(f)
if err != nil {
t.Fatal("unexpected error:", err)
}
assert.EqualValues(t, filesize, fi.Size())
})
}
}

// Issue #145 in github
// Deadlock in ReadFrom when network drops after 1 good packet.
// Deadlock would occur anytime desiredInFlight-inFlight==2 and 2 errors
Expand Down

0 comments on commit 1fffa62

Please sign in to comment.