sftp/client_integration_test.go

2401 lines
52 KiB
Go
Raw Normal View History

2013-11-06 12:40:35 +08:00
package sftp
// sftp integration tests
// enable with -integration
import (
2017-02-13 11:37:13 +08:00
"bytes"
2013-11-15 18:47:28 +08:00
"crypto/sha1"
"encoding"
"errors"
2013-11-08 19:11:02 +08:00
"io"
2013-11-06 12:40:35 +08:00
"io/ioutil"
"math/rand"
"net"
2013-11-06 12:40:35 +08:00
"os"
"os/exec"
"os/user"
2013-11-08 18:00:26 +08:00
"path"
2013-11-08 18:24:50 +08:00
"path/filepath"
"reflect"
"regexp"
"sort"
"strconv"
2013-11-06 12:40:35 +08:00
"testing"
"testing/quick"
"time"
2013-11-08 18:24:50 +08:00
"github.com/kr/fs"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
2013-11-06 12:40:35 +08:00
)
2013-11-06 16:29:59 +08:00
const (
Add integration tests that measure how throughput varies with latency. This clearly shows the impact high latency networks have on the throughput of sftp transfers. The current benchmark results on my machine are: $ go test -bench=. -integration PASS BenchmarkRead1k 20 93028268 ns/op 112.72 MB/s BenchmarkRead16k 100 14912438 ns/op 703.16 MB/s BenchmarkRead32k 100 12282661 ns/op 853.71 MB/s BenchmarkRead128k 100 10550935 ns/op 993.83 MB/s BenchmarkRead512k 100 12970518 ns/op 808.44 MB/s BenchmarkRead1MiB 100 11526693 ns/op 909.70 MB/s BenchmarkRead4MiB 100 15761135 ns/op 665.30 MB/s BenchmarkRead4MiBDelay10Msec 1 2662626928 ns/op 3.94 MB/s BenchmarkRead4MiBDelay50Msec 1 12977334971 ns/op 0.81 MB/s BenchmarkRead4MiBDelay150Msec 1 38777294968 ns/op 0.27 MB/s BenchmarkWrite1k 5 235318220 ns/op 44.56 MB/s BenchmarkWrite16k 50 57347520 ns/op 182.85 MB/s BenchmarkWrite32k 30 66151560 ns/op 158.51 MB/s BenchmarkWrite128k 20 86642733 ns/op 121.02 MB/s BenchmarkWrite512k 20 72648883 ns/op 144.34 MB/s BenchmarkWrite1MiB 20 87145317 ns/op 120.33 MB/s BenchmarkWrite4MiB 50 64098344 ns/op 163.59 MB/s BenchmarkWrite4MiBDelay10Msec 1 3360676836 ns/op 3.12 MB/s BenchmarkWrite4MiBDelay50Msec 1 16321294488 ns/op 0.64 MB/s BenchmarkWrite4MiBDelay150Msec 1 48731747397 ns/op 0.22 MB/s BenchmarkCopyDown10MiBDelay10Msec 1 3369680836 ns/op 3.11 MB/s BenchmarkCopyDown10MiBDelay50Msec 1 16228310257 ns/op 0.65 MB/s BenchmarkCopyDown10MiBDelay150Msec 1 48505306499 ns/op 0.22 MB/s BenchmarkCopyUp10MiBDelay10Msec 1 3393474907 ns/op 3.09 MB/s BenchmarkCopyUp10MiBDelay50Msec 1 16273951972 ns/op 0.64 MB/s BenchmarkCopyUp10MiBDelay150Msec 1 48461724780 ns/op 0.22 MB/s BenchmarkMarshalInit 2000000 779 ns/op BenchmarkMarshalOpen 2000000 645 ns/op BenchmarkMarshalWriteWorstCase 20000 70954 ns/op BenchmarkMarshalWrite1k 300000 5072 ns/op ok github.com/pkg/sftp 296.179s
2015-06-03 00:36:35 +08:00
READONLY = true
READWRITE = false
NODELAY time.Duration = 0
2013-11-08 18:00:26 +08:00
2013-11-08 18:24:50 +08:00
debuglevel = "ERROR" // set to "DEBUG" for debugging
2013-11-06 16:29:59 +08:00
)
Add integration tests that measure how throughput varies with latency. This clearly shows the impact high latency networks have on the throughput of sftp transfers. The current benchmark results on my machine are: $ go test -bench=. -integration PASS BenchmarkRead1k 20 93028268 ns/op 112.72 MB/s BenchmarkRead16k 100 14912438 ns/op 703.16 MB/s BenchmarkRead32k 100 12282661 ns/op 853.71 MB/s BenchmarkRead128k 100 10550935 ns/op 993.83 MB/s BenchmarkRead512k 100 12970518 ns/op 808.44 MB/s BenchmarkRead1MiB 100 11526693 ns/op 909.70 MB/s BenchmarkRead4MiB 100 15761135 ns/op 665.30 MB/s BenchmarkRead4MiBDelay10Msec 1 2662626928 ns/op 3.94 MB/s BenchmarkRead4MiBDelay50Msec 1 12977334971 ns/op 0.81 MB/s BenchmarkRead4MiBDelay150Msec 1 38777294968 ns/op 0.27 MB/s BenchmarkWrite1k 5 235318220 ns/op 44.56 MB/s BenchmarkWrite16k 50 57347520 ns/op 182.85 MB/s BenchmarkWrite32k 30 66151560 ns/op 158.51 MB/s BenchmarkWrite128k 20 86642733 ns/op 121.02 MB/s BenchmarkWrite512k 20 72648883 ns/op 144.34 MB/s BenchmarkWrite1MiB 20 87145317 ns/op 120.33 MB/s BenchmarkWrite4MiB 50 64098344 ns/op 163.59 MB/s BenchmarkWrite4MiBDelay10Msec 1 3360676836 ns/op 3.12 MB/s BenchmarkWrite4MiBDelay50Msec 1 16321294488 ns/op 0.64 MB/s BenchmarkWrite4MiBDelay150Msec 1 48731747397 ns/op 0.22 MB/s BenchmarkCopyDown10MiBDelay10Msec 1 3369680836 ns/op 3.11 MB/s BenchmarkCopyDown10MiBDelay50Msec 1 16228310257 ns/op 0.65 MB/s BenchmarkCopyDown10MiBDelay150Msec 1 48505306499 ns/op 0.22 MB/s BenchmarkCopyUp10MiBDelay10Msec 1 3393474907 ns/op 3.09 MB/s BenchmarkCopyUp10MiBDelay50Msec 1 16273951972 ns/op 0.64 MB/s BenchmarkCopyUp10MiBDelay150Msec 1 48461724780 ns/op 0.22 MB/s BenchmarkMarshalInit 2000000 779 ns/op BenchmarkMarshalOpen 2000000 645 ns/op BenchmarkMarshalWriteWorstCase 20000 70954 ns/op BenchmarkMarshalWrite1k 300000 5072 ns/op ok github.com/pkg/sftp 296.179s
2015-06-03 00:36:35 +08:00
type delayedWrite struct {
t time.Time
b []byte
}
// delayedWriter wraps a writer and artificially delays the write. This is
// meant to mimic connections with various latencies. Error's returned from the
// underlying writer will panic so this should only be used over reliable
// connections.
type delayedWriter struct {
w io.WriteCloser
ch chan delayedWrite
closed chan struct{}
}
func newDelayedWriter(w io.WriteCloser, delay time.Duration) io.WriteCloser {
ch := make(chan delayedWrite, 128)
closed := make(chan struct{})
go func() {
for writeMsg := range ch {
time.Sleep(time.Until(writeMsg.t.Add(delay)))
Add integration tests that measure how throughput varies with latency. This clearly shows the impact high latency networks have on the throughput of sftp transfers. The current benchmark results on my machine are: $ go test -bench=. -integration PASS BenchmarkRead1k 20 93028268 ns/op 112.72 MB/s BenchmarkRead16k 100 14912438 ns/op 703.16 MB/s BenchmarkRead32k 100 12282661 ns/op 853.71 MB/s BenchmarkRead128k 100 10550935 ns/op 993.83 MB/s BenchmarkRead512k 100 12970518 ns/op 808.44 MB/s BenchmarkRead1MiB 100 11526693 ns/op 909.70 MB/s BenchmarkRead4MiB 100 15761135 ns/op 665.30 MB/s BenchmarkRead4MiBDelay10Msec 1 2662626928 ns/op 3.94 MB/s BenchmarkRead4MiBDelay50Msec 1 12977334971 ns/op 0.81 MB/s BenchmarkRead4MiBDelay150Msec 1 38777294968 ns/op 0.27 MB/s BenchmarkWrite1k 5 235318220 ns/op 44.56 MB/s BenchmarkWrite16k 50 57347520 ns/op 182.85 MB/s BenchmarkWrite32k 30 66151560 ns/op 158.51 MB/s BenchmarkWrite128k 20 86642733 ns/op 121.02 MB/s BenchmarkWrite512k 20 72648883 ns/op 144.34 MB/s BenchmarkWrite1MiB 20 87145317 ns/op 120.33 MB/s BenchmarkWrite4MiB 50 64098344 ns/op 163.59 MB/s BenchmarkWrite4MiBDelay10Msec 1 3360676836 ns/op 3.12 MB/s BenchmarkWrite4MiBDelay50Msec 1 16321294488 ns/op 0.64 MB/s BenchmarkWrite4MiBDelay150Msec 1 48731747397 ns/op 0.22 MB/s BenchmarkCopyDown10MiBDelay10Msec 1 3369680836 ns/op 3.11 MB/s BenchmarkCopyDown10MiBDelay50Msec 1 16228310257 ns/op 0.65 MB/s BenchmarkCopyDown10MiBDelay150Msec 1 48505306499 ns/op 0.22 MB/s BenchmarkCopyUp10MiBDelay10Msec 1 3393474907 ns/op 3.09 MB/s BenchmarkCopyUp10MiBDelay50Msec 1 16273951972 ns/op 0.64 MB/s BenchmarkCopyUp10MiBDelay150Msec 1 48461724780 ns/op 0.22 MB/s BenchmarkMarshalInit 2000000 779 ns/op BenchmarkMarshalOpen 2000000 645 ns/op BenchmarkMarshalWriteWorstCase 20000 70954 ns/op BenchmarkMarshalWrite1k 300000 5072 ns/op ok github.com/pkg/sftp 296.179s
2015-06-03 00:36:35 +08:00
n, err := w.Write(writeMsg.b)
if err != nil {
panic("write error")
}
if n < len(writeMsg.b) {
panic("showrt write")
}
}
w.Close()
close(closed)
}()
return delayedWriter{w: w, ch: ch, closed: closed}
}
func (w delayedWriter) Write(b []byte) (int, error) {
bcopy := make([]byte, len(b))
copy(bcopy, b)
w.ch <- delayedWrite{t: time.Now(), b: bcopy}
return len(b), nil
}
func (w delayedWriter) Close() error {
close(w.ch)
<-w.closed
return nil
}
// netPipe provides a pair of io.ReadWriteClosers connected to each other.
// The functions is identical to os.Pipe with the exception that netPipe
2017-07-04 04:14:51 +08:00
// provides the Read/Close guarantees that os.File derrived pipes do not.
func netPipe(t testing.TB) (io.ReadWriteCloser, io.ReadWriteCloser) {
type result struct {
net.Conn
error
}
l, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatal(err)
}
ch := make(chan result, 1)
go func() {
conn, err := l.Accept()
ch <- result{conn, err}
err = l.Close()
if err != nil {
t.Error(err)
}
}()
c1, err := net.Dial("tcp", l.Addr().String())
if err != nil {
l.Close() // might cause another in the listening goroutine, but too bad
t.Fatal(err)
}
r := <-ch
if r.error != nil {
t.Fatal(err)
}
return c1, r.Conn
}
func testClientGoSvr(t testing.TB, readonly bool, delay time.Duration) (*Client, *exec.Cmd) {
c1, c2 := netPipe(t)
options := []ServerOption{WithDebug(os.Stderr)}
if readonly {
options = append(options, ReadOnly())
}
server, err := NewServer(c1, options...)
if err != nil {
t.Fatal(err)
}
go server.Serve()
var ctx io.WriteCloser = c2
if delay > NODELAY {
ctx = newDelayedWriter(ctx, delay)
}
client, err := NewClientPipe(c2, ctx)
if err != nil {
t.Fatal(err)
}
// dummy command...
return client, exec.Command("true")
}
2020-10-23 18:54:04 +08:00
// testClient returns a *Client connected to a locally running sftp-server
2013-11-06 12:40:35 +08:00
// the *exec.Cmd returned must be defer Wait'd.
Add integration tests that measure how throughput varies with latency. This clearly shows the impact high latency networks have on the throughput of sftp transfers. The current benchmark results on my machine are: $ go test -bench=. -integration PASS BenchmarkRead1k 20 93028268 ns/op 112.72 MB/s BenchmarkRead16k 100 14912438 ns/op 703.16 MB/s BenchmarkRead32k 100 12282661 ns/op 853.71 MB/s BenchmarkRead128k 100 10550935 ns/op 993.83 MB/s BenchmarkRead512k 100 12970518 ns/op 808.44 MB/s BenchmarkRead1MiB 100 11526693 ns/op 909.70 MB/s BenchmarkRead4MiB 100 15761135 ns/op 665.30 MB/s BenchmarkRead4MiBDelay10Msec 1 2662626928 ns/op 3.94 MB/s BenchmarkRead4MiBDelay50Msec 1 12977334971 ns/op 0.81 MB/s BenchmarkRead4MiBDelay150Msec 1 38777294968 ns/op 0.27 MB/s BenchmarkWrite1k 5 235318220 ns/op 44.56 MB/s BenchmarkWrite16k 50 57347520 ns/op 182.85 MB/s BenchmarkWrite32k 30 66151560 ns/op 158.51 MB/s BenchmarkWrite128k 20 86642733 ns/op 121.02 MB/s BenchmarkWrite512k 20 72648883 ns/op 144.34 MB/s BenchmarkWrite1MiB 20 87145317 ns/op 120.33 MB/s BenchmarkWrite4MiB 50 64098344 ns/op 163.59 MB/s BenchmarkWrite4MiBDelay10Msec 1 3360676836 ns/op 3.12 MB/s BenchmarkWrite4MiBDelay50Msec 1 16321294488 ns/op 0.64 MB/s BenchmarkWrite4MiBDelay150Msec 1 48731747397 ns/op 0.22 MB/s BenchmarkCopyDown10MiBDelay10Msec 1 3369680836 ns/op 3.11 MB/s BenchmarkCopyDown10MiBDelay50Msec 1 16228310257 ns/op 0.65 MB/s BenchmarkCopyDown10MiBDelay150Msec 1 48505306499 ns/op 0.22 MB/s BenchmarkCopyUp10MiBDelay10Msec 1 3393474907 ns/op 3.09 MB/s BenchmarkCopyUp10MiBDelay50Msec 1 16273951972 ns/op 0.64 MB/s BenchmarkCopyUp10MiBDelay150Msec 1 48461724780 ns/op 0.22 MB/s BenchmarkMarshalInit 2000000 779 ns/op BenchmarkMarshalOpen 2000000 645 ns/op BenchmarkMarshalWriteWorstCase 20000 70954 ns/op BenchmarkMarshalWrite1k 300000 5072 ns/op ok github.com/pkg/sftp 296.179s
2015-06-03 00:36:35 +08:00
func testClient(t testing.TB, readonly bool, delay time.Duration) (*Client, *exec.Cmd) {
2013-11-08 18:00:26 +08:00
if !*testIntegration {
2020-10-23 18:54:04 +08:00
t.Skip("skipping integration test")
2013-11-08 18:00:26 +08:00
}
if *testServerImpl {
return testClientGoSvr(t, readonly, delay)
}
cmd := exec.Command(*testSftp, "-e", "-R", "-l", debuglevel) // log to stderr, read only
2013-11-06 16:29:59 +08:00
if !readonly {
cmd = exec.Command(*testSftp, "-e", "-l", debuglevel) // log to stderr
2013-11-06 16:29:59 +08:00
}
2013-11-06 12:40:35 +08:00
cmd.Stderr = os.Stdout
pw, err := cmd.StdinPipe()
if err != nil {
t.Fatal(err)
}
if delay > NODELAY {
Add integration tests that measure how throughput varies with latency. This clearly shows the impact high latency networks have on the throughput of sftp transfers. The current benchmark results on my machine are: $ go test -bench=. -integration PASS BenchmarkRead1k 20 93028268 ns/op 112.72 MB/s BenchmarkRead16k 100 14912438 ns/op 703.16 MB/s BenchmarkRead32k 100 12282661 ns/op 853.71 MB/s BenchmarkRead128k 100 10550935 ns/op 993.83 MB/s BenchmarkRead512k 100 12970518 ns/op 808.44 MB/s BenchmarkRead1MiB 100 11526693 ns/op 909.70 MB/s BenchmarkRead4MiB 100 15761135 ns/op 665.30 MB/s BenchmarkRead4MiBDelay10Msec 1 2662626928 ns/op 3.94 MB/s BenchmarkRead4MiBDelay50Msec 1 12977334971 ns/op 0.81 MB/s BenchmarkRead4MiBDelay150Msec 1 38777294968 ns/op 0.27 MB/s BenchmarkWrite1k 5 235318220 ns/op 44.56 MB/s BenchmarkWrite16k 50 57347520 ns/op 182.85 MB/s BenchmarkWrite32k 30 66151560 ns/op 158.51 MB/s BenchmarkWrite128k 20 86642733 ns/op 121.02 MB/s BenchmarkWrite512k 20 72648883 ns/op 144.34 MB/s BenchmarkWrite1MiB 20 87145317 ns/op 120.33 MB/s BenchmarkWrite4MiB 50 64098344 ns/op 163.59 MB/s BenchmarkWrite4MiBDelay10Msec 1 3360676836 ns/op 3.12 MB/s BenchmarkWrite4MiBDelay50Msec 1 16321294488 ns/op 0.64 MB/s BenchmarkWrite4MiBDelay150Msec 1 48731747397 ns/op 0.22 MB/s BenchmarkCopyDown10MiBDelay10Msec 1 3369680836 ns/op 3.11 MB/s BenchmarkCopyDown10MiBDelay50Msec 1 16228310257 ns/op 0.65 MB/s BenchmarkCopyDown10MiBDelay150Msec 1 48505306499 ns/op 0.22 MB/s BenchmarkCopyUp10MiBDelay10Msec 1 3393474907 ns/op 3.09 MB/s BenchmarkCopyUp10MiBDelay50Msec 1 16273951972 ns/op 0.64 MB/s BenchmarkCopyUp10MiBDelay150Msec 1 48461724780 ns/op 0.22 MB/s BenchmarkMarshalInit 2000000 779 ns/op BenchmarkMarshalOpen 2000000 645 ns/op BenchmarkMarshalWriteWorstCase 20000 70954 ns/op BenchmarkMarshalWrite1k 300000 5072 ns/op ok github.com/pkg/sftp 296.179s
2015-06-03 00:36:35 +08:00
pw = newDelayedWriter(pw, delay)
}
2013-11-06 12:40:35 +08:00
pr, err := cmd.StdoutPipe()
if err != nil {
t.Fatal(err)
}
if err := cmd.Start(); err != nil {
t.Skipf("could not start sftp-server process: %v", err)
}
sftp, err := NewClientPipe(pr, pw)
if err != nil {
t.Fatal(err)
2013-11-06 12:40:35 +08:00
}
2013-11-06 12:40:35 +08:00
return sftp, cmd
}
func TestNewClient(t *testing.T) {
sftp, cmd := testClient(t, READONLY, NODELAY)
2013-11-06 12:40:35 +08:00
defer cmd.Wait()
if err := sftp.Close(); err != nil {
t.Fatal(err)
}
}
func TestClientLstat(t *testing.T) {
sftp, cmd := testClient(t, READONLY, NODELAY)
2013-11-06 12:40:35 +08:00
defer cmd.Wait()
defer sftp.Close()
f, err := ioutil.TempFile("", "sftptest-lstat")
2013-11-06 12:40:35 +08:00
if err != nil {
t.Fatal(err)
}
f.Close()
2013-11-06 12:40:35 +08:00
defer os.Remove(f.Name())
want, err := os.Lstat(f.Name())
if err != nil {
t.Fatal(err)
}
got, err := sftp.Lstat(f.Name())
if err != nil {
t.Fatal(err)
}
if !sameFile(want, got) {
t.Fatalf("Lstat(%q): want %#v, got %#v", f.Name(), want, got)
}
}
func TestClientLstatIsNotExist(t *testing.T) {
sftp, cmd := testClient(t, READONLY, NODELAY)
2013-11-06 16:29:59 +08:00
defer cmd.Wait()
defer sftp.Close()
f, err := ioutil.TempFile("", "sftptest-lstatisnotexist")
2013-11-06 16:29:59 +08:00
if err != nil {
t.Fatal(err)
}
f.Close()
2013-11-06 16:29:59 +08:00
os.Remove(f.Name())
if _, err := sftp.Lstat(f.Name()); !os.IsNotExist(err) {
t.Errorf("os.IsNotExist(%v) = false, want true", err)
2013-11-06 16:29:59 +08:00
}
}
2014-09-28 10:52:54 +08:00
func TestClientMkdir(t *testing.T) {
sftp, cmd := testClient(t, READWRITE, NODELAY)
defer cmd.Wait()
defer sftp.Close()
dir, err := ioutil.TempDir("", "sftptest-mkdir")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
2014-09-28 10:52:54 +08:00
sub := path.Join(dir, "mkdir1")
if err := sftp.Mkdir(sub); err != nil {
t.Fatal(err)
}
if _, err := os.Lstat(sub); err != nil {
t.Fatal(err)
}
2014-09-28 10:52:54 +08:00
}
2018-04-25 14:58:10 +08:00
func TestClientMkdirAll(t *testing.T) {
sftp, cmd := testClient(t, READWRITE, NODELAY)
2018-04-25 14:58:10 +08:00
defer cmd.Wait()
defer sftp.Close()
dir, err := ioutil.TempDir("", "sftptest-mkdirall")
2018-04-25 14:58:10 +08:00
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
2018-04-25 14:58:10 +08:00
sub := path.Join(dir, "mkdir1", "mkdir2", "mkdir3")
if err := sftp.MkdirAll(sub); err != nil {
t.Fatal(err)
}
info, err := os.Lstat(sub)
if err != nil {
2018-04-25 14:58:10 +08:00
t.Fatal(err)
}
if !info.IsDir() {
t.Fatalf("Expected mkdirall to create dir at: %s", sub)
}
2018-04-25 14:58:10 +08:00
}
2014-09-28 10:52:54 +08:00
2013-11-06 12:53:14 +08:00
func TestClientOpen(t *testing.T) {
sftp, cmd := testClient(t, READONLY, NODELAY)
2013-11-06 12:53:14 +08:00
defer cmd.Wait()
defer sftp.Close()
f, err := ioutil.TempFile("", "sftptest-open")
2013-11-06 12:53:14 +08:00
if err != nil {
t.Fatal(err)
}
f.Close()
2013-11-06 12:53:14 +08:00
defer os.Remove(f.Name())
got, err := sftp.Open(f.Name())
if err != nil {
t.Fatal(err)
}
if err := got.Close(); err != nil {
t.Fatal(err)
}
}
func TestClientOpenIsNotExist(t *testing.T) {
sftp, cmd := testClient(t, READONLY, NODELAY)
defer cmd.Wait()
defer sftp.Close()
if _, err := sftp.Open("/doesnt/exist/"); !os.IsNotExist(err) {
t.Errorf("os.IsNotExist(%v) = false, want true", err)
}
}
func TestClientStatIsNotExist(t *testing.T) {
sftp, cmd := testClient(t, READONLY, NODELAY)
defer cmd.Wait()
defer sftp.Close()
if _, err := sftp.Stat("/doesnt/exist/"); !os.IsNotExist(err) {
t.Errorf("os.IsNotExist(%v) = false, want true", err)
}
}
const seekBytes = 128 * 1024
type seek struct {
offset int64
}
func (s seek) Generate(r *rand.Rand, _ int) reflect.Value {
s.offset = int64(r.Int31n(seekBytes))
return reflect.ValueOf(s)
}
func (s seek) set(t *testing.T, r io.ReadSeeker) {
2018-02-16 02:27:33 +08:00
if _, err := r.Seek(s.offset, io.SeekStart); err != nil {
t.Fatalf("error while seeking with %+v: %v", s, err)
}
}
func (s seek) current(t *testing.T, r io.ReadSeeker) {
const mid = seekBytes / 2
skip := s.offset / 2
if s.offset > mid {
skip = -skip
}
2018-02-16 02:27:33 +08:00
if _, err := r.Seek(mid, io.SeekStart); err != nil {
t.Fatalf("error seeking to midpoint with %+v: %v", s, err)
}
2018-02-16 02:27:33 +08:00
if _, err := r.Seek(skip, io.SeekCurrent); err != nil {
t.Fatalf("error seeking from %d with %+v: %v", mid, s, err)
}
}
func (s seek) end(t *testing.T, r io.ReadSeeker) {
2018-02-16 02:27:33 +08:00
if _, err := r.Seek(-s.offset, io.SeekEnd); err != nil {
t.Fatalf("error seeking from end with %+v: %v", s, err)
}
}
func TestClientSeek(t *testing.T) {
sftp, cmd := testClient(t, READONLY, NODELAY)
defer cmd.Wait()
defer sftp.Close()
fOS, err := ioutil.TempFile("", "sftptest-seek")
if err != nil {
t.Fatal(err)
}
defer os.Remove(fOS.Name())
defer fOS.Close()
fSFTP, err := sftp.Open(fOS.Name())
if err != nil {
t.Fatal(err)
}
defer fSFTP.Close()
writeN(t, fOS, seekBytes)
if err := quick.CheckEqual(
func(s seek) (string, int64) { s.set(t, fOS); return readHash(t, fOS) },
func(s seek) (string, int64) { s.set(t, fSFTP); return readHash(t, fSFTP) },
nil,
); err != nil {
t.Errorf("Seek: expected equal absolute seeks: %v", err)
}
if err := quick.CheckEqual(
func(s seek) (string, int64) { s.current(t, fOS); return readHash(t, fOS) },
func(s seek) (string, int64) { s.current(t, fSFTP); return readHash(t, fSFTP) },
nil,
); err != nil {
t.Errorf("Seek: expected equal seeks from middle: %v", err)
}
if err := quick.CheckEqual(
func(s seek) (string, int64) { s.end(t, fOS); return readHash(t, fOS) },
func(s seek) (string, int64) { s.end(t, fSFTP); return readHash(t, fSFTP) },
nil,
); err != nil {
t.Errorf("Seek: expected equal seeks from end: %v", err)
}
2013-11-08 19:11:02 +08:00
}
2013-11-06 16:29:59 +08:00
func TestClientCreate(t *testing.T) {
sftp, cmd := testClient(t, READWRITE, NODELAY)
2013-11-06 16:29:59 +08:00
defer cmd.Wait()
defer sftp.Close()
f, err := ioutil.TempFile("", "sftptest-create")
2013-11-06 16:29:59 +08:00
if err != nil {
t.Fatal(err)
}
defer f.Close()
defer os.Remove(f.Name())
f2, err := sftp.Create(f.Name())
if err != nil {
t.Fatal(err)
}
defer f2.Close()
}
2013-11-14 12:32:21 +08:00
func TestClientAppend(t *testing.T) {
sftp, cmd := testClient(t, READWRITE, NODELAY)
2013-11-14 12:32:21 +08:00
defer cmd.Wait()
defer sftp.Close()
f, err := ioutil.TempFile("", "sftptest-append")
2013-11-14 12:32:21 +08:00
if err != nil {
t.Fatal(err)
}
defer f.Close()
defer os.Remove(f.Name())
f2, err := sftp.OpenFile(f.Name(), os.O_RDWR|os.O_APPEND)
if err != nil {
t.Fatal(err)
}
defer f2.Close()
}
2013-11-06 16:29:59 +08:00
func TestClientCreateFailed(t *testing.T) {
sftp, cmd := testClient(t, READONLY, NODELAY)
2013-11-06 16:29:59 +08:00
defer cmd.Wait()
defer sftp.Close()
f, err := ioutil.TempFile("", "sftptest-createfailed")
2013-11-06 16:29:59 +08:00
if err != nil {
t.Fatal(err)
}
defer f.Close()
defer os.Remove(f.Name())
f2, err := sftp.Create(f.Name())
if err1, ok := err.(*StatusError); !ok || err1.Code != sshFxPermissionDenied {
t.Fatalf("Create: want: %v, got %#v", sshFxPermissionDenied, err)
2013-11-06 16:29:59 +08:00
}
if err == nil {
f2.Close()
}
}
2015-09-25 16:05:59 +08:00
func TestClientFileName(t *testing.T) {
sftp, cmd := testClient(t, READONLY, NODELAY)
2015-09-25 16:05:59 +08:00
defer cmd.Wait()
defer sftp.Close()
f, err := ioutil.TempFile("", "sftptest-filename")
2015-09-25 16:05:59 +08:00
if err != nil {
t.Fatal(err)
}
defer os.Remove(f.Name())
f2, err := sftp.Open(f.Name())
if err != nil {
t.Fatal(err)
}
if got, want := f2.Name(), f.Name(); got != want {
2015-09-25 16:17:46 +08:00
t.Fatalf("Name: got %q want %q", want, got)
2015-09-25 16:05:59 +08:00
}
}
2013-11-06 13:03:08 +08:00
func TestClientFileStat(t *testing.T) {
sftp, cmd := testClient(t, READONLY, NODELAY)
2013-11-06 13:03:08 +08:00
defer cmd.Wait()
defer sftp.Close()
f, err := ioutil.TempFile("", "sftptest-filestat")
2013-11-06 13:03:08 +08:00
if err != nil {
t.Fatal(err)
}
defer os.Remove(f.Name())
want, err := os.Lstat(f.Name())
if err != nil {
t.Fatal(err)
}
f2, err := sftp.Open(f.Name())
if err != nil {
t.Fatal(err)
}
got, err := f2.Stat()
if err != nil {
t.Fatal(err)
}
if !sameFile(want, got) {
t.Fatalf("Lstat(%q): want %#v, got %#v", f.Name(), want, got)
}
}
func TestClientStatLink(t *testing.T) {
skipIfWindows(t) // Windows does not support links.
sftp, cmd := testClient(t, READONLY, NODELAY)
defer cmd.Wait()
defer sftp.Close()
f, err := ioutil.TempFile("", "sftptest-statlink")
if err != nil {
t.Fatal(err)
}
defer os.Remove(f.Name())
realName := f.Name()
linkName := f.Name() + ".softlink"
// create a symlink that points at sftptest
if err := os.Symlink(realName, linkName); err != nil {
t.Fatal(err)
}
defer os.Remove(linkName)
// compare Lstat of links
wantLstat, err := os.Lstat(linkName)
if err != nil {
t.Fatal(err)
}
wantStat, err := os.Stat(linkName)
if err != nil {
t.Fatal(err)
}
gotLstat, err := sftp.Lstat(linkName)
if err != nil {
t.Fatal(err)
}
gotStat, err := sftp.Stat(linkName)
if err != nil {
t.Fatal(err)
}
// check that stat is not lstat from os package
if sameFile(wantLstat, wantStat) {
t.Fatalf("Lstat / Stat(%q): both %#v %#v", f.Name(), wantLstat, wantStat)
}
// compare Lstat of links
if !sameFile(wantLstat, gotLstat) {
t.Fatalf("Lstat(%q): want %#v, got %#v", f.Name(), wantLstat, gotLstat)
}
// compare Stat of links
if !sameFile(wantStat, gotStat) {
t.Fatalf("Stat(%q): want %#v, got %#v", f.Name(), wantStat, gotStat)
}
// check that stat is not lstat
if sameFile(gotLstat, gotStat) {
t.Fatalf("Lstat / Stat(%q): both %#v %#v", f.Name(), gotLstat, gotStat)
}
}
func TestClientRemove(t *testing.T) {
sftp, cmd := testClient(t, READWRITE, NODELAY)
defer cmd.Wait()
defer sftp.Close()
f, err := ioutil.TempFile("", "sftptest-remove")
if err != nil {
t.Fatal(err)
}
defer os.Remove(f.Name())
f.Close()
if err := sftp.Remove(f.Name()); err != nil {
t.Fatal(err)
}
if _, err := os.Lstat(f.Name()); !os.IsNotExist(err) {
t.Fatal(err)
}
}
func TestClientRemoveDir(t *testing.T) {
sftp, cmd := testClient(t, READWRITE, NODELAY)
defer cmd.Wait()
defer sftp.Close()
dir, err := ioutil.TempDir("", "sftptest-removedir")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
if err := sftp.Remove(dir); err != nil {
t.Fatal(err)
}
if _, err := os.Lstat(dir); !os.IsNotExist(err) {
t.Fatal(err)
}
}
func TestClientRemoveFailed(t *testing.T) {
sftp, cmd := testClient(t, READONLY, NODELAY)
defer cmd.Wait()
defer sftp.Close()
f, err := ioutil.TempFile("", "sftptest-removefailed")
if err != nil {
t.Fatal(err)
}
defer os.Remove(f.Name())
if err := sftp.Remove(f.Name()); err == nil {
t.Fatalf("Remove(%v): want: permission denied, got %v", f.Name(), err)
}
if _, err := os.Lstat(f.Name()); err != nil {
t.Fatal(err)
}
}
2013-11-08 19:11:02 +08:00
func TestClientRename(t *testing.T) {
sftp, cmd := testClient(t, READWRITE, NODELAY)
2013-11-08 19:11:02 +08:00
defer cmd.Wait()
defer sftp.Close()
dir, err := ioutil.TempDir("", "sftptest-rename")
require.NoError(t, err)
defer os.RemoveAll(dir)
f, err := os.Create(filepath.Join(dir, "old"))
require.NoError(t, err)
f.Close()
f2 := filepath.Join(dir, "new")
2013-11-08 19:11:02 +08:00
if err := sftp.Rename(f.Name(), f2); err != nil {
t.Fatal(err)
}
if _, err := os.Lstat(f.Name()); !os.IsNotExist(err) {
t.Fatal(err)
}
if _, err := os.Lstat(f2); err != nil {
t.Fatal(err)
}
}
func TestClientPosixRename(t *testing.T) {
sftp, cmd := testClient(t, READWRITE, NODELAY)
defer cmd.Wait()
defer sftp.Close()
dir, err := ioutil.TempDir("", "sftptest-posixrename")
require.NoError(t, err)
defer os.RemoveAll(dir)
f, err := os.Create(filepath.Join(dir, "old"))
require.NoError(t, err)
f.Close()
f2 := filepath.Join(dir, "new")
if err := sftp.PosixRename(f.Name(), f2); err != nil {
t.Fatal(err)
}
if _, err := os.Lstat(f.Name()); !os.IsNotExist(err) {
t.Fatal(err)
}
if _, err := os.Lstat(f2); err != nil {
t.Fatal(err)
}
}
2015-12-22 05:45:40 +08:00
func TestClientGetwd(t *testing.T) {
sftp, cmd := testClient(t, READONLY, NODELAY)
2015-12-22 05:45:40 +08:00
defer cmd.Wait()
defer sftp.Close()
lwd, err := os.Getwd()
if err != nil {
t.Fatal(err)
}
rwd, err := sftp.Getwd()
if err != nil {
t.Fatal(err)
}
if !filepath.IsAbs(rwd) {
2015-12-22 05:45:40 +08:00
t.Fatalf("Getwd: wanted absolute path, got %q", rwd)
}
if filepath.ToSlash(lwd) != filepath.ToSlash(rwd) {
2015-12-22 05:45:40 +08:00
t.Fatalf("Getwd: want %q, got %q", lwd, rwd)
}
}
2015-08-01 06:46:13 +08:00
func TestClientReadLink(t *testing.T) {
sftp, cmd := testClient(t, READWRITE, NODELAY)
defer cmd.Wait()
defer sftp.Close()
dir, err := ioutil.TempDir("", "sftptest-readlink")
require.NoError(t, err)
defer os.RemoveAll(dir)
f, err := os.Create(filepath.Join(dir, "file"))
require.NoError(t, err)
f.Close()
f2 := filepath.Join(dir, "symlink")
if err := os.Symlink(f.Name(), f2); err != nil {
t.Fatal(err)
}
2015-09-07 16:05:16 +08:00
if rl, err := sftp.ReadLink(f2); err != nil {
t.Fatal(err)
2015-09-07 16:05:16 +08:00
} else if rl != f.Name() {
t.Fatalf("unexpected link target: %v, not %v", rl, f.Name())
}
}
func TestClientLink(t *testing.T) {
sftp, cmd := testClient(t, READWRITE, NODELAY)
defer cmd.Wait()
defer sftp.Close()
dir, err := ioutil.TempDir("", "sftptest-link")
require.NoError(t, err)
defer os.RemoveAll(dir)
f, err := os.Create(filepath.Join(dir, "file"))
require.NoError(t, err)
data := []byte("linktest")
_, err = f.Write(data)
f.Close()
if err != nil {
t.Fatal(err)
}
f2 := filepath.Join(dir, "link")
if err := sftp.Link(f.Name(), f2); err != nil {
t.Fatal(err)
}
if st2, err := sftp.Stat(f2); err != nil {
t.Fatal(err)
} else if int(st2.Size()) != len(data) {
t.Fatalf("unexpected link size: %v, not %v", st2.Size(), len(data))
}
}
2015-09-07 16:05:16 +08:00
func TestClientSymlink(t *testing.T) {
sftp, cmd := testClient(t, READWRITE, NODELAY)
2015-09-07 16:05:16 +08:00
defer cmd.Wait()
defer sftp.Close()
dir, err := ioutil.TempDir("", "sftptest-symlink")
require.NoError(t, err)
defer os.RemoveAll(dir)
f, err := os.Create(filepath.Join(dir, "file"))
require.NoError(t, err)
f.Close()
f2 := filepath.Join(dir, "symlink")
2015-09-07 16:05:16 +08:00
if err := sftp.Symlink(f.Name(), f2); err != nil {
t.Fatal(err)
}
if rl, err := sftp.ReadLink(f2); err != nil {
t.Fatal(err)
} else if rl != f.Name() {
t.Fatalf("unexpected link target: %v, not %v", rl, f.Name())
}
}
func TestClientChmod(t *testing.T) {
skipIfWindows(t) // No UNIX permissions.
sftp, cmd := testClient(t, READWRITE, NODELAY)
defer cmd.Wait()
defer sftp.Close()
f, err := ioutil.TempFile("", "sftptest")
if err != nil {
t.Fatal(err)
}
defer os.Remove(f.Name())
f.Close()
if err := sftp.Chmod(f.Name(), 0531); err != nil {
t.Fatal(err)
}
if stat, err := os.Stat(f.Name()); err != nil {
t.Fatal(err)
} else if stat.Mode()&os.ModePerm != 0531 {
t.Fatalf("invalid perm %o\n", stat.Mode())
}
}
func TestClientChmodReadonly(t *testing.T) {
skipIfWindows(t) // No UNIX permissions.
sftp, cmd := testClient(t, READONLY, NODELAY)
defer cmd.Wait()
defer sftp.Close()
f, err := ioutil.TempFile("", "sftptest")
if err != nil {
t.Fatal(err)
}
defer os.Remove(f.Name())
f.Close()
if err := sftp.Chmod(f.Name(), 0531); err == nil {
t.Fatal("expected error")
}
}
func TestClientChown(t *testing.T) {
skipIfWindows(t) // No UNIX permissions.
sftp, cmd := testClient(t, READWRITE, NODELAY)
defer cmd.Wait()
defer sftp.Close()
usr, err := user.Current()
if err != nil {
t.Fatal(err)
}
if usr.Uid != "0" {
t.Log("must be root to run chown tests")
t.Skip()
}
chownto, err := user.Lookup("daemon") // seems common-ish...
if err != nil {
t.Fatal(err)
}
2016-01-05 05:15:21 +08:00
toUID, err := strconv.Atoi(chownto.Uid)
if err != nil {
t.Fatal(err)
}
2016-01-05 05:15:21 +08:00
toGID, err := strconv.Atoi(chownto.Gid)
if err != nil {
t.Fatal(err)
}
f, err := ioutil.TempFile("", "sftptest-chown")
if err != nil {
t.Fatal(err)
}
defer os.Remove(f.Name())
f.Close()
before, err := exec.Command("ls", "-nl", f.Name()).Output()
if err != nil {
t.Fatal(err)
}
2016-01-05 05:15:21 +08:00
if err := sftp.Chown(f.Name(), toUID, toGID); err != nil {
t.Fatal(err)
}
after, err := exec.Command("ls", "-nl", f.Name()).Output()
if err != nil {
t.Fatal(err)
}
spaceRegex := regexp.MustCompile(`\s+`)
beforeWords := spaceRegex.Split(string(before), -1)
if beforeWords[2] != "0" {
t.Fatalf("bad previous user? should be root")
}
afterWords := spaceRegex.Split(string(after), -1)
if afterWords[2] != chownto.Uid || afterWords[3] != chownto.Gid {
t.Fatalf("bad chown: %#v", afterWords)
}
t.Logf("before: %v", string(before))
t.Logf(" after: %v", string(after))
}
func TestClientChownReadonly(t *testing.T) {
skipIfWindows(t) // No UNIX permissions.
sftp, cmd := testClient(t, READONLY, NODELAY)
defer cmd.Wait()
defer sftp.Close()
usr, err := user.Current()
if err != nil {
t.Fatal(err)
}
if usr.Uid != "0" {
t.Log("must be root to run chown tests")
t.Skip()
}
chownto, err := user.Lookup("daemon") // seems common-ish...
if err != nil {
t.Fatal(err)
}
2016-01-05 05:15:21 +08:00
toUID, err := strconv.Atoi(chownto.Uid)
if err != nil {
t.Fatal(err)
}
2016-01-05 05:15:21 +08:00
toGID, err := strconv.Atoi(chownto.Gid)
if err != nil {
t.Fatal(err)
}
f, err := ioutil.TempFile("", "sftptest-chownreadonly")
if err != nil {
t.Fatal(err)
}
defer os.Remove(f.Name())
f.Close()
2016-01-05 05:15:21 +08:00
if err := sftp.Chown(f.Name(), toUID, toGID); err == nil {
t.Fatal("expected error")
}
}
func TestClientChtimes(t *testing.T) {
sftp, cmd := testClient(t, READWRITE, NODELAY)
defer cmd.Wait()
defer sftp.Close()
f, err := ioutil.TempFile("", "sftptest-chtimes")
if err != nil {
t.Fatal(err)
}
defer os.Remove(f.Name())
f.Close()
atime := time.Date(2013, 2, 23, 13, 24, 35, 0, time.UTC)
mtime := time.Date(1985, 6, 12, 6, 6, 6, 0, time.UTC)
if err := sftp.Chtimes(f.Name(), atime, mtime); err != nil {
t.Fatal(err)
}
if stat, err := os.Stat(f.Name()); err != nil {
t.Fatal(err)
} else if stat.ModTime().Sub(mtime) != 0 {
t.Fatalf("incorrect mtime: %v vs %v", stat.ModTime(), mtime)
}
}
func TestClientChtimesReadonly(t *testing.T) {
sftp, cmd := testClient(t, READONLY, NODELAY)
defer cmd.Wait()
defer sftp.Close()
f, err := ioutil.TempFile("", "sftptest-chtimesreadonly")
if err != nil {
t.Fatal(err)
}
defer os.Remove(f.Name())
f.Close()
atime := time.Date(2013, 2, 23, 13, 24, 35, 0, time.UTC)
mtime := time.Date(1985, 6, 12, 6, 6, 6, 0, time.UTC)
if err := sftp.Chtimes(f.Name(), atime, mtime); err == nil {
t.Fatal("expected error")
}
}
2015-08-05 13:21:35 +08:00
func TestClientTruncate(t *testing.T) {
sftp, cmd := testClient(t, READWRITE, NODELAY)
defer cmd.Wait()
defer sftp.Close()
f, err := ioutil.TempFile("", "sftptest-truncate")
if err != nil {
t.Fatal(err)
}
defer os.Remove(f.Name())
2015-08-05 13:21:35 +08:00
fname := f.Name()
2015-08-05 13:21:35 +08:00
if n, err := f.Write([]byte("hello world")); n != 11 || err != nil {
t.Fatal(err)
}
f.Close()
if err := sftp.Truncate(fname, 5); err != nil {
t.Fatal(err)
}
if stat, err := os.Stat(fname); err != nil {
t.Fatal(err)
2015-08-05 13:21:35 +08:00
} else if stat.Size() != 5 {
t.Fatalf("unexpected size: %d", stat.Size())
}
}
2015-08-05 13:21:35 +08:00
func TestClientTruncateReadonly(t *testing.T) {
sftp, cmd := testClient(t, READONLY, NODELAY)
2015-08-05 13:21:35 +08:00
defer cmd.Wait()
defer sftp.Close()
f, err := ioutil.TempFile("", "sftptest")
if err != nil {
t.Fatal(err)
}
defer os.Remove(f.Name())
2015-08-05 13:21:35 +08:00
fname := f.Name()
if n, err := f.Write([]byte("hello world")); n != 11 || err != nil {
t.Fatal(err)
}
f.Close()
if err := sftp.Truncate(fname, 5); err == nil {
t.Fatal("expected error")
}
if stat, err := os.Stat(fname); err != nil {
t.Fatal(err)
} else if stat.Size() != 11 {
t.Fatalf("unexpected size: %d", stat.Size())
}
}
2013-11-06 12:40:35 +08:00
func sameFile(want, got os.FileInfo) bool {
_, wantName := filepath.Split(want.Name())
_, gotName := filepath.Split(got.Name())
return wantName == gotName &&
2013-11-06 12:40:35 +08:00
want.Size() == got.Size()
}
2013-11-08 18:00:26 +08:00
2015-07-30 08:24:24 +08:00
func TestClientReadSimple(t *testing.T) {
sftp, cmd := testClient(t, READONLY, NODELAY)
2015-07-30 08:24:24 +08:00
defer cmd.Wait()
defer sftp.Close()
d, err := ioutil.TempDir("", "sftptest")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(d)
f, err := ioutil.TempFile(d, "read-test")
if err != nil {
t.Fatal(err)
}
fname := f.Name()
f.Write([]byte("hello"))
f.Close()
f2, err := sftp.Open(fname)
if err != nil {
t.Fatal(err)
}
defer f2.Close()
stuff := make([]byte, 32)
n, err := f2.Read(stuff)
if err != nil && err != io.EOF {
t.Fatalf("err: %v", err)
}
if n != 5 {
t.Fatalf("n should be 5, is %v", n)
}
if string(stuff[0:5]) != "hello" {
t.Fatalf("invalid contents")
}
}
func TestClientReadDir(t *testing.T) {
sftp1, cmd1 := testClient(t, READONLY, NODELAY)
sftp2, cmd2 := testClientGoSvr(t, READONLY, NODELAY)
defer cmd1.Wait()
defer cmd2.Wait()
defer sftp1.Close()
defer sftp2.Close()
dir := os.TempDir()
d, err := os.Open(dir)
if err != nil {
t.Fatal(err)
}
defer d.Close()
osfiles, err := d.Readdir(4096)
if err != nil {
t.Fatal(err)
}
sftp1Files, err := sftp1.ReadDir(dir)
if err != nil {
t.Fatal(err)
}
sftp2Files, err := sftp2.ReadDir(dir)
if err != nil {
t.Fatal(err)
}
osFilesByName := map[string]os.FileInfo{}
for _, f := range osfiles {
osFilesByName[f.Name()] = f
}
sftp1FilesByName := map[string]os.FileInfo{}
for _, f := range sftp1Files {
sftp1FilesByName[f.Name()] = f
}
sftp2FilesByName := map[string]os.FileInfo{}
for _, f := range sftp2Files {
sftp2FilesByName[f.Name()] = f
}
if len(osFilesByName) != len(sftp1FilesByName) || len(sftp1FilesByName) != len(sftp2FilesByName) {
t.Fatalf("os gives %v, sftp1 gives %v, sftp2 gives %v", len(osFilesByName), len(sftp1FilesByName), len(sftp2FilesByName))
}
for name, osF := range osFilesByName {
sftp1F, ok := sftp1FilesByName[name]
if !ok {
t.Fatalf("%v present in os but not sftp1", name)
}
sftp2F, ok := sftp2FilesByName[name]
if !ok {
t.Fatalf("%v present in os but not sftp2", name)
}
//t.Logf("%v: %v %v %v", name, osF, sftp1F, sftp2F)
if osF.Size() != sftp1F.Size() || sftp1F.Size() != sftp2F.Size() {
t.Fatalf("size %v %v %v", osF.Size(), sftp1F.Size(), sftp2F.Size())
}
if osF.IsDir() != sftp1F.IsDir() || sftp1F.IsDir() != sftp2F.IsDir() {
t.Fatalf("isdir %v %v %v", osF.IsDir(), sftp1F.IsDir(), sftp2F.IsDir())
}
if osF.ModTime().Sub(sftp1F.ModTime()) > time.Second || sftp1F.ModTime() != sftp2F.ModTime() {
t.Fatalf("modtime %v %v %v", osF.ModTime(), sftp1F.ModTime(), sftp2F.ModTime())
}
if osF.Mode() != sftp1F.Mode() || sftp1F.Mode() != sftp2F.Mode() {
t.Fatalf("mode %x %x %x", osF.Mode(), sftp1F.Mode(), sftp2F.Mode())
}
}
}
2013-11-15 18:17:11 +08:00
var clientReadTests = []struct {
n int64
}{
{0},
{1},
{1000},
{1024},
{1025},
{2048},
{4096},
{1 << 12},
{1 << 13},
{1 << 14},
{1 << 15},
{1 << 16},
{1 << 17},
{1 << 18},
{1 << 19},
{1 << 20},
}
func TestClientRead(t *testing.T) {
sftp, cmd := testClient(t, READONLY, NODELAY)
2013-11-15 18:17:11 +08:00
defer cmd.Wait()
defer sftp.Close()
d, err := ioutil.TempDir("", "sftptest")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(d)
for _, tt := range clientReadTests {
f, err := ioutil.TempFile(d, "read-test")
if err != nil {
t.Fatal(err)
}
defer f.Close()
2013-11-15 18:47:28 +08:00
hash := writeN(t, f, tt.n)
2013-11-15 18:17:11 +08:00
f2, err := sftp.Open(f.Name())
if err != nil {
t.Fatal(err)
}
defer f2.Close()
2013-11-15 18:47:28 +08:00
hash2, n := readHash(t, f2)
if hash != hash2 || tt.n != n {
t.Errorf("Read: hash: want: %q, got %q, read: want: %v, got %v", hash, hash2, tt.n, n)
2013-11-15 18:17:11 +08:00
}
}
}
2013-11-15 18:47:28 +08:00
// readHash reads r until EOF returning the number of bytes read
// and the hash of the contents.
func readHash(t *testing.T, r io.Reader) (string, int64) {
h := sha1.New()
tr := io.TeeReader(r, h)
read, err := io.Copy(ioutil.Discard, tr)
if err != nil {
t.Fatal(err)
}
return string(h.Sum(nil)), read
}
// writeN writes n bytes of random data to w and returns the
// hash of that data.
func writeN(t *testing.T, w io.Writer, n int64) string {
r := rand.New(rand.NewSource(time.Now().UnixNano()))
2013-11-15 18:47:28 +08:00
h := sha1.New()
mw := io.MultiWriter(w, h)
written, err := io.CopyN(mw, r, n)
2013-11-15 18:47:28 +08:00
if err != nil {
t.Fatal(err)
}
if written != n {
t.Fatalf("CopyN(%v): wrote: %v", n, written)
}
return string(h.Sum(nil))
}
2013-11-08 18:00:26 +08:00
var clientWriteTests = []struct {
n int
total int64 // cumulative file size
}{
{0, 0},
{1, 1},
{0, 1},
{999, 1000},
{24, 1024},
{1023, 2047},
{2048, 4095},
{1 << 12, 8191},
{1 << 13, 16383},
{1 << 14, 32767},
{1 << 15, 65535},
{1 << 16, 131071},
{1 << 17, 262143},
2013-11-08 18:24:50 +08:00
{1 << 18, 524287},
{1 << 19, 1048575},
{1 << 20, 2097151},
{1 << 21, 4194303},
2013-11-08 18:00:26 +08:00
}
func TestClientWrite(t *testing.T) {
sftp, cmd := testClient(t, READWRITE, NODELAY)
2013-11-08 18:00:26 +08:00
defer cmd.Wait()
defer sftp.Close()
d, err := ioutil.TempDir("", "sftptest")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(d)
f := path.Join(d, "writeTest")
w, err := sftp.Create(f)
if err != nil {
t.Fatal(err)
}
defer w.Close()
for _, tt := range clientWriteTests {
got, err := w.Write(make([]byte, tt.n))
if err != nil {
t.Fatal(err)
}
if got != tt.n {
t.Errorf("Write(%v): wrote: want: %v, got %v", tt.n, tt.n, got)
}
fi, err := os.Stat(f)
if err != nil {
t.Fatal(err)
}
if total := fi.Size(); total != tt.total {
t.Errorf("Write(%v): size: want: %v, got %v", tt.n, tt.total, total)
}
}
}
2013-11-08 18:24:50 +08:00
2017-02-13 11:37:13 +08:00
// ReadFrom is basically Write with io.Reader as the arg
func TestClientReadFrom(t *testing.T) {
sftp, cmd := testClient(t, READWRITE, NODELAY)
2017-02-13 11:37:13 +08:00
defer cmd.Wait()
defer sftp.Close()
d, err := ioutil.TempDir("", "sftptest")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(d)
f := path.Join(d, "writeTest")
w, err := sftp.Create(f)
if err != nil {
t.Fatal(err)
}
defer w.Close()
for _, tt := range clientWriteTests {
got, err := w.ReadFrom(bytes.NewReader(make([]byte, tt.n)))
if err != nil {
t.Fatal(err)
}
if got != int64(tt.n) {
t.Errorf("Write(%v): wrote: want: %v, got %v", tt.n, tt.n, got)
}
fi, err := os.Stat(f)
if err != nil {
t.Fatal(err)
}
if total := fi.Size(); total != tt.total {
t.Errorf("Write(%v): size: want: %v, got %v", tt.n, tt.total, total)
}
}
}
// Issue #145 in github
// Deadlock in ReadFrom when network drops after 1 good packet.
// Deadlock would occur anytime desiredInFlight-inFlight==2 and 2 errors
// occured in a row. The channel to report the errors only had a buffer
// of 1 and 2 would be sent.
var errFakeNet = errors.New("Fake network issue")
func TestClientReadFromDeadlock(t *testing.T) {
clientWriteDeadlock(t, 1, func(f *File) {
b := make([]byte, 32768*4)
content := bytes.NewReader(b)
n, err := f.ReadFrom(content)
if n != 0 {
t.Fatal("Write should return 0", n)
}
if err != errFakeNet {
t.Fatal("Didn't recieve correct error", err)
}
})
}
// Write has exact same problem
func TestClientWriteDeadlock(t *testing.T) {
clientWriteDeadlock(t, 1, func(f *File) {
b := make([]byte, 32768*4)
n, err := f.Write(b)
if n != 0 {
t.Fatal("Write should return 0", n)
}
if err != errFakeNet {
t.Fatal("Didn't recieve correct error", err)
}
})
}
// shared body for both previous tests
func clientWriteDeadlock(t *testing.T, N int, badfunc func(*File)) {
if !*testServerImpl {
t.Skipf("skipping without -testserver")
}
sftp, cmd := testClient(t, READWRITE, NODELAY)
defer cmd.Wait()
defer sftp.Close()
d, err := ioutil.TempDir("", "sftptest")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(d)
f := path.Join(d, "writeTest")
w, err := sftp.Create(f)
if err != nil {
t.Fatal(err)
}
defer w.Close()
// Override sendPacket with failing version
// Replicates network error/drop part way through (after 1 good packet)
count := 0
sendPacketTest := func(w io.Writer, m encoding.BinaryMarshaler) error {
count++
if count > N {
return errFakeNet
}
return sendPacket(w, m)
}
sftp.clientConn.conn.sendPacketTest = sendPacketTest
defer func() {
sftp.clientConn.conn.sendPacketTest = nil
}()
// this locked (before the fix)
badfunc(w)
}
// Read/WriteTo has this issue as well
func TestClientReadDeadlock(t *testing.T) {
clientReadDeadlock(t, 1, func(f *File) {
b := make([]byte, 32768*4)
n, err := f.Read(b)
if n != 0 {
t.Fatal("Write should return 0", n)
}
if err != errFakeNet {
t.Fatal("Didn't recieve correct error", err)
}
})
}
func TestClientWriteToDeadlock(t *testing.T) {
clientReadDeadlock(t, 2, func(f *File) {
b := make([]byte, 32768*4)
buf := bytes.NewBuffer(b)
n, err := f.WriteTo(buf)
if n != 32768 {
t.Fatal("Write should return 0", n)
}
if err != errFakeNet {
t.Fatal("Didn't recieve correct error", err)
}
})
}
func clientReadDeadlock(t *testing.T, N int, badfunc func(*File)) {
if !*testServerImpl {
t.Skipf("skipping without -testserver")
}
sftp, cmd := testClient(t, READWRITE, NODELAY)
defer cmd.Wait()
defer sftp.Close()
d, err := ioutil.TempDir("", "sftptest")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(d)
f := path.Join(d, "writeTest")
w, err := sftp.Create(f)
if err != nil {
t.Fatal(err)
}
// write the data for the read tests
b := make([]byte, 32768*4)
w.Write(b)
defer w.Close()
// open new copy of file for read tests
r, err := sftp.Open(f)
if err != nil {
t.Fatal(err)
}
defer r.Close()
// Override sendPacket with failing version
// Replicates network error/drop part way through (after 1 good packet)
count := 0
sendPacketTest := func(w io.Writer, m encoding.BinaryMarshaler) error {
count++
if count > N {
return errFakeNet
}
return sendPacket(w, m)
}
sftp.clientConn.conn.sendPacketTest = sendPacketTest
defer func() {
sftp.clientConn.conn.sendPacketTest = nil
}()
// this locked (before the fix)
badfunc(r)
}
func TestClientSyncGo(t *testing.T) {
if !*testServerImpl {
t.Skipf("skipping without -testserver")
}
err := testClientSync(t)
// Since Server does not support the fsync extension, we can only
// check that we get the right error.
require.Error(t, err)
switch err := err.(type) {
case *StatusError:
assert.Equal(t, ErrSSHFxOpUnsupported, err.FxCode())
default:
t.Error(err)
}
}
func TestClientSyncSFTP(t *testing.T) {
if *testServerImpl {
t.Skipf("skipping with -testserver")
}
err := testClientSync(t)
assert.NoError(t, err)
}
func testClientSync(t *testing.T) error {
sftp, cmd := testClient(t, READWRITE, NODELAY)
defer cmd.Wait()
defer sftp.Close()
d, err := ioutil.TempDir("", "sftptest.sync")
require.NoError(t, err)
defer os.RemoveAll(d)
f := path.Join(d, "syncTest")
w, err := sftp.Create(f)
require.NoError(t, err)
defer w.Close()
return w.Sync()
}
2013-11-08 18:24:50 +08:00
// taken from github.com/kr/fs/walk_test.go
type Node struct {
name string
entries []*Node // nil if the entry is a file
mark int
}
var tree = &Node{
"testdata",
[]*Node{
{"a", nil, 0},
{"b", []*Node{}, 0},
{"c", nil, 0},
{
"d",
[]*Node{
{"x", nil, 0},
{"y", []*Node{}, 0},
{
"z",
[]*Node{
{"u", nil, 0},
{"v", nil, 0},
},
0,
},
},
0,
},
},
0,
}
func walkTree(n *Node, path string, f func(path string, n *Node)) {
f(path, n)
for _, e := range n.entries {
walkTree(e, filepath.Join(path, e.name), f)
}
}
func makeTree(t *testing.T) {
walkTree(tree, tree.name, func(path string, n *Node) {
if n.entries == nil {
fd, err := os.Create(path)
if err != nil {
t.Errorf("makeTree: %v", err)
return
}
fd.Close()
} else {
os.Mkdir(path, 0770)
}
})
}
func markTree(n *Node) { walkTree(n, "", func(path string, n *Node) { n.mark++ }) }
func checkMarks(t *testing.T, report bool) {
walkTree(tree, tree.name, func(path string, n *Node) {
if n.mark != 1 && report {
t.Errorf("node %s mark = %d; expected 1", path, n.mark)
}
n.mark = 0
})
}
// Assumes that each node name is unique. Good enough for a test.
// If clear is true, any incoming error is cleared before return. The errors
// are always accumulated, though.
func mark(path string, info os.FileInfo, err error, errors *[]error, clear bool) error {
if err != nil {
*errors = append(*errors, err)
if clear {
return nil
}
return err
}
name := info.Name()
walkTree(tree, tree.name, func(path string, n *Node) {
if n.name == name {
n.mark++
}
})
return nil
}
func TestClientWalk(t *testing.T) {
sftp, cmd := testClient(t, READONLY, NODELAY)
2013-11-08 18:24:50 +08:00
defer cmd.Wait()
defer sftp.Close()
makeTree(t)
errors := make([]error, 0, 10)
clear := true
2016-01-08 04:56:04 +08:00
markFn := func(walker *fs.Walker) error {
2013-11-08 18:24:50 +08:00
for walker.Step() {
2016-01-08 04:56:04 +08:00
err := mark(walker.Path(), walker.Stat(), walker.Err(), &errors, clear)
2013-11-08 18:24:50 +08:00
if err != nil {
2016-01-08 04:56:04 +08:00
return err
2013-11-08 18:24:50 +08:00
}
}
2016-01-08 04:56:04 +08:00
return nil
2013-11-08 18:24:50 +08:00
}
// Expect no errors.
err := markFn(sftp.Walk(tree.name))
if err != nil {
t.Fatalf("no error expected, found: %s", err)
}
if len(errors) != 0 {
t.Fatalf("unexpected errors: %s", errors)
}
checkMarks(t, true)
errors = errors[0:0]
// Test permission errors. Only possible if we're not root
// and only on some file systems (AFS, FAT). To avoid errors during
// all.bash on those file systems, skip during go test -short.
if os.Getuid() > 0 && !testing.Short() {
// introduce 2 errors: chmod top-level directories to 0
os.Chmod(filepath.Join(tree.name, tree.entries[1].name), 0)
os.Chmod(filepath.Join(tree.name, tree.entries[3].name), 0)
// 3) capture errors, expect two.
// mark respective subtrees manually
markTree(tree.entries[1])
markTree(tree.entries[3])
// correct double-marking of directory itself
tree.entries[1].mark--
tree.entries[3].mark--
err := markFn(sftp.Walk(tree.name))
if err != nil {
t.Fatalf("expected no error return from Walk, got %s", err)
}
if len(errors) != 2 {
t.Errorf("expected 2 errors, got %d: %s", len(errors), errors)
}
// the inaccessible subtrees were marked manually
checkMarks(t, true)
errors = errors[0:0]
// 4) capture errors, stop after first error.
// mark respective subtrees manually
markTree(tree.entries[1])
markTree(tree.entries[3])
// correct double-marking of directory itself
tree.entries[1].mark--
tree.entries[3].mark--
clear = false // error will stop processing
err = markFn(sftp.Walk(tree.name))
if err == nil {
t.Fatalf("expected error return from Walk")
}
if len(errors) != 1 {
t.Errorf("expected 1 error, got %d: %s", len(errors), errors)
}
// the inaccessible subtrees were marked manually
checkMarks(t, false)
errors = errors[0:0]
// restore permissions
os.Chmod(filepath.Join(tree.name, tree.entries[1].name), 0770)
os.Chmod(filepath.Join(tree.name, tree.entries[3].name), 0770)
}
// cleanup
if err := os.RemoveAll(tree.name); err != nil {
t.Errorf("removeTree: %v", err)
}
}
2014-10-09 05:41:54 +08:00
type MatchTest struct {
pattern, s string
match bool
err error
}
var matchTests = []MatchTest{
{"abc", "abc", true, nil},
{"*", "abc", true, nil},
{"*c", "abc", true, nil},
{"a*", "a", true, nil},
{"a*", "abc", true, nil},
{"a*", "ab/c", false, nil},
{"a*/b", "abc/b", true, nil},
{"a*/b", "a/c/b", false, nil},
{"a*b*c*d*e*/f", "axbxcxdxe/f", true, nil},
{"a*b*c*d*e*/f", "axbxcxdxexxx/f", true, nil},
{"a*b*c*d*e*/f", "axbxcxdxe/xxx/f", false, nil},
{"a*b*c*d*e*/f", "axbxcxdxexxx/fff", false, nil},
{"a*b?c*x", "abxbbxdbxebxczzx", true, nil},
{"a*b?c*x", "abxbbxdbxebxczzy", false, nil},
{"ab[c]", "abc", true, nil},
{"ab[b-d]", "abc", true, nil},
{"ab[e-g]", "abc", false, nil},
{"ab[^c]", "abc", false, nil},
{"ab[^b-d]", "abc", false, nil},
{"ab[^e-g]", "abc", true, nil},
{"a\\*b", "a*b", true, nil},
{"a\\*b", "ab", false, nil},
{"a?b", "a☺b", true, nil},
{"a[^a]b", "a☺b", true, nil},
{"a???b", "a☺b", false, nil},
{"a[^a][^a][^a]b", "a☺b", false, nil},
{"[a-ζ]*", "α", true, nil},
{"*[a-ζ]", "A", false, nil},
{"a?b", "a/b", false, nil},
{"a*b", "a/b", false, nil},
{"[\\]a]", "]", true, nil},
{"[\\-]", "-", true, nil},
{"[x\\-]", "x", true, nil},
{"[x\\-]", "-", true, nil},
{"[x\\-]", "z", false, nil},
{"[\\-x]", "x", true, nil},
{"[\\-x]", "-", true, nil},
{"[\\-x]", "a", false, nil},
{"[]a]", "]", false, ErrBadPattern},
{"[-]", "-", false, ErrBadPattern},
{"[x-]", "x", false, ErrBadPattern},
{"[x-]", "-", false, ErrBadPattern},
{"[x-]", "z", false, ErrBadPattern},
{"[-x]", "x", false, ErrBadPattern},
{"[-x]", "-", false, ErrBadPattern},
{"[-x]", "a", false, ErrBadPattern},
{"\\", "a", false, ErrBadPattern},
{"[a-b-c]", "a", false, ErrBadPattern},
{"[", "a", false, ErrBadPattern},
{"[^", "a", false, ErrBadPattern},
{"[^bc", "a", false, ErrBadPattern},
{"a[", "ab", false, ErrBadPattern},
{"*x", "xxx", true, nil},
// The following test behaves differently on Go 1.15.3 and Go tip as
// https://github.com/golang/go/commit/b5ddc42b465dd5b9532ee336d98343d81a6d35b2
// (pre-Go 1.16). TODO: reevaluate when Go 1.16 is released.
//{"a[", "a", false, nil},
}
func errp(e error) string {
if e == nil {
return "<nil>"
}
return e.Error()
}
// contains returns true if vector contains the string s.
func contains(vector []string, s string) bool {
for _, elem := range vector {
if elem == s {
return true
}
}
return false
}
var globTests = []struct {
pattern, result string
}{
{"match.go", "match.go"},
{"mat?h.go", "match.go"},
{"ma*ch.go", "match.go"},
{"../*/match.go", "../sftp/match.go"},
}
type globTest struct {
pattern string
matches []string
}
func (test *globTest) buildWant(root string) []string {
var want []string
for _, m := range test.matches {
want = append(want, root+filepath.FromSlash(m))
}
sort.Strings(want)
return want
}
func TestMatch(t *testing.T) {
for _, tt := range matchTests {
pattern := tt.pattern
s := tt.s
ok, err := Match(pattern, s)
if ok != tt.match || err != tt.err {
t.Errorf("Match(%#q, %#q) = %v, %q want %v, %q", pattern, s, ok, errp(err), tt.match, errp(tt.err))
}
}
}
func TestGlob(t *testing.T) {
sftp, cmd := testClient(t, READONLY, NODELAY)
defer cmd.Wait()
defer sftp.Close()
for _, tt := range globTests {
pattern := tt.pattern
result := tt.result
matches, err := sftp.Glob(pattern)
if err != nil {
t.Errorf("Glob error for %q: %s", pattern, err)
continue
}
if !contains(matches, result) {
t.Errorf("Glob(%#q) = %#v want %v", pattern, matches, result)
}
}
for _, pattern := range []string{"no_match", "../*/no_match"} {
matches, err := sftp.Glob(pattern)
if err != nil {
t.Errorf("Glob error for %q: %s", pattern, err)
continue
}
if len(matches) != 0 {
t.Errorf("Glob(%#q) = %#v want []", pattern, matches)
}
}
}
func TestGlobError(t *testing.T) {
sftp, cmd := testClient(t, READONLY, NODELAY)
defer cmd.Wait()
defer sftp.Close()
_, err := sftp.Glob("[7]")
if err != nil {
t.Error("expected error for bad pattern; got none")
}
}
func TestGlobUNC(t *testing.T) {
sftp, cmd := testClient(t, READONLY, NODELAY)
defer cmd.Wait()
defer sftp.Close()
// Just make sure this runs without crashing for now.
// See issue 15879.
sftp.Glob(`\\?\C:\*`)
}
2015-06-15 18:12:08 +08:00
// sftp/issue/42, abrupt server hangup would result in client hangs.
func TestServerRoughDisconnect(t *testing.T) {
skipIfWindows(t)
if *testServerImpl {
t.Skipf("skipping with -testserver")
}
sftp, cmd := testClient(t, READONLY, NODELAY)
defer cmd.Wait()
defer sftp.Close()
2015-06-15 18:12:08 +08:00
f, err := sftp.Open("/dev/zero")
if err != nil {
t.Fatal(err)
}
defer f.Close()
go func() {
time.Sleep(100 * time.Millisecond)
cmd.Process.Kill()
}()
io.Copy(ioutil.Discard, f)
}
// sftp/issue/181, abrupt server hangup would result in client hangs.
// due to broadcastErr filling up the request channel
// this reproduces it about 50% of the time
func TestServerRoughDisconnect2(t *testing.T) {
skipIfWindows(t)
if *testServerImpl {
t.Skipf("skipping with -testserver")
}
sftp, cmd := testClient(t, READONLY, NODELAY)
defer cmd.Wait()
defer sftp.Close()
f, err := sftp.Open("/dev/zero")
if err != nil {
t.Fatal(err)
}
defer f.Close()
b := make([]byte, 32768*100)
go func() {
time.Sleep(1 * time.Millisecond)
cmd.Process.Kill()
}()
for {
_, err = f.Read(b)
if err != nil {
break
}
}
}
// sftp/issue/234 - abrupt shutdown during ReadFrom hangs client
func TestServerRoughDisconnect3(t *testing.T) {
skipIfWindows(t)
if *testServerImpl {
t.Skipf("skipping with -testserver")
}
sftp, cmd := testClient(t, READWRITE, NODELAY)
defer cmd.Wait()
defer sftp.Close()
rf, err := sftp.OpenFile("/dev/null", os.O_RDWR)
if err != nil {
t.Fatal(err)
}
defer rf.Close()
lf, err := os.Open("/dev/zero")
if err != nil {
t.Fatal(err)
}
defer lf.Close()
go func() {
time.Sleep(10 * time.Millisecond)
cmd.Process.Kill()
}()
io.Copy(rf, lf)
}
// sftp/issue/234 - also affected Write
func TestServerRoughDisconnect4(t *testing.T) {
skipIfWindows(t)
if *testServerImpl {
t.Skipf("skipping with -testserver")
}
sftp, cmd := testClient(t, READWRITE, NODELAY)
defer cmd.Wait()
defer sftp.Close()
rf, err := sftp.OpenFile("/dev/null", os.O_RDWR)
if err != nil {
t.Fatal(err)
}
defer rf.Close()
lf, err := os.Open("/dev/zero")
if err != nil {
t.Fatal(err)
}
defer lf.Close()
go func() {
time.Sleep(10 * time.Millisecond)
cmd.Process.Kill()
}()
b := make([]byte, 32768*200)
lf.Read(b)
for {
_, err = rf.Write(b)
if err != nil {
break
}
}
io.Copy(rf, lf)
}
// sftp/issue/26 writing to a read only file caused client to loop.
func TestClientWriteToROFile(t *testing.T) {
skipIfWindows(t)
sftp, cmd := testClient(t, READWRITE, NODELAY)
defer cmd.Wait()
defer sftp.Close()
f, err := sftp.Open("/dev/zero")
if err != nil {
t.Fatal(err)
}
defer f.Close()
_, err = f.Write([]byte("hello"))
if err == nil {
t.Fatal("expected error, got", err)
}
}
Add integration tests that measure how throughput varies with latency. This clearly shows the impact high latency networks have on the throughput of sftp transfers. The current benchmark results on my machine are: $ go test -bench=. -integration PASS BenchmarkRead1k 20 93028268 ns/op 112.72 MB/s BenchmarkRead16k 100 14912438 ns/op 703.16 MB/s BenchmarkRead32k 100 12282661 ns/op 853.71 MB/s BenchmarkRead128k 100 10550935 ns/op 993.83 MB/s BenchmarkRead512k 100 12970518 ns/op 808.44 MB/s BenchmarkRead1MiB 100 11526693 ns/op 909.70 MB/s BenchmarkRead4MiB 100 15761135 ns/op 665.30 MB/s BenchmarkRead4MiBDelay10Msec 1 2662626928 ns/op 3.94 MB/s BenchmarkRead4MiBDelay50Msec 1 12977334971 ns/op 0.81 MB/s BenchmarkRead4MiBDelay150Msec 1 38777294968 ns/op 0.27 MB/s BenchmarkWrite1k 5 235318220 ns/op 44.56 MB/s BenchmarkWrite16k 50 57347520 ns/op 182.85 MB/s BenchmarkWrite32k 30 66151560 ns/op 158.51 MB/s BenchmarkWrite128k 20 86642733 ns/op 121.02 MB/s BenchmarkWrite512k 20 72648883 ns/op 144.34 MB/s BenchmarkWrite1MiB 20 87145317 ns/op 120.33 MB/s BenchmarkWrite4MiB 50 64098344 ns/op 163.59 MB/s BenchmarkWrite4MiBDelay10Msec 1 3360676836 ns/op 3.12 MB/s BenchmarkWrite4MiBDelay50Msec 1 16321294488 ns/op 0.64 MB/s BenchmarkWrite4MiBDelay150Msec 1 48731747397 ns/op 0.22 MB/s BenchmarkCopyDown10MiBDelay10Msec 1 3369680836 ns/op 3.11 MB/s BenchmarkCopyDown10MiBDelay50Msec 1 16228310257 ns/op 0.65 MB/s BenchmarkCopyDown10MiBDelay150Msec 1 48505306499 ns/op 0.22 MB/s BenchmarkCopyUp10MiBDelay10Msec 1 3393474907 ns/op 3.09 MB/s BenchmarkCopyUp10MiBDelay50Msec 1 16273951972 ns/op 0.64 MB/s BenchmarkCopyUp10MiBDelay150Msec 1 48461724780 ns/op 0.22 MB/s BenchmarkMarshalInit 2000000 779 ns/op BenchmarkMarshalOpen 2000000 645 ns/op BenchmarkMarshalWriteWorstCase 20000 70954 ns/op BenchmarkMarshalWrite1k 300000 5072 ns/op ok github.com/pkg/sftp 296.179s
2015-06-03 00:36:35 +08:00
func benchmarkRead(b *testing.B, bufsize int, delay time.Duration) {
skipIfWindows(b)
2014-10-09 05:41:54 +08:00
size := 10*1024*1024 + 123 // ~10MiB
// open sftp client
Add integration tests that measure how throughput varies with latency. This clearly shows the impact high latency networks have on the throughput of sftp transfers. The current benchmark results on my machine are: $ go test -bench=. -integration PASS BenchmarkRead1k 20 93028268 ns/op 112.72 MB/s BenchmarkRead16k 100 14912438 ns/op 703.16 MB/s BenchmarkRead32k 100 12282661 ns/op 853.71 MB/s BenchmarkRead128k 100 10550935 ns/op 993.83 MB/s BenchmarkRead512k 100 12970518 ns/op 808.44 MB/s BenchmarkRead1MiB 100 11526693 ns/op 909.70 MB/s BenchmarkRead4MiB 100 15761135 ns/op 665.30 MB/s BenchmarkRead4MiBDelay10Msec 1 2662626928 ns/op 3.94 MB/s BenchmarkRead4MiBDelay50Msec 1 12977334971 ns/op 0.81 MB/s BenchmarkRead4MiBDelay150Msec 1 38777294968 ns/op 0.27 MB/s BenchmarkWrite1k 5 235318220 ns/op 44.56 MB/s BenchmarkWrite16k 50 57347520 ns/op 182.85 MB/s BenchmarkWrite32k 30 66151560 ns/op 158.51 MB/s BenchmarkWrite128k 20 86642733 ns/op 121.02 MB/s BenchmarkWrite512k 20 72648883 ns/op 144.34 MB/s BenchmarkWrite1MiB 20 87145317 ns/op 120.33 MB/s BenchmarkWrite4MiB 50 64098344 ns/op 163.59 MB/s BenchmarkWrite4MiBDelay10Msec 1 3360676836 ns/op 3.12 MB/s BenchmarkWrite4MiBDelay50Msec 1 16321294488 ns/op 0.64 MB/s BenchmarkWrite4MiBDelay150Msec 1 48731747397 ns/op 0.22 MB/s BenchmarkCopyDown10MiBDelay10Msec 1 3369680836 ns/op 3.11 MB/s BenchmarkCopyDown10MiBDelay50Msec 1 16228310257 ns/op 0.65 MB/s BenchmarkCopyDown10MiBDelay150Msec 1 48505306499 ns/op 0.22 MB/s BenchmarkCopyUp10MiBDelay10Msec 1 3393474907 ns/op 3.09 MB/s BenchmarkCopyUp10MiBDelay50Msec 1 16273951972 ns/op 0.64 MB/s BenchmarkCopyUp10MiBDelay150Msec 1 48461724780 ns/op 0.22 MB/s BenchmarkMarshalInit 2000000 779 ns/op BenchmarkMarshalOpen 2000000 645 ns/op BenchmarkMarshalWriteWorstCase 20000 70954 ns/op BenchmarkMarshalWrite1k 300000 5072 ns/op ok github.com/pkg/sftp 296.179s
2015-06-03 00:36:35 +08:00
sftp, cmd := testClient(b, READONLY, delay)
2014-10-09 05:41:54 +08:00
defer cmd.Wait()
// defer sftp.Close()
2014-10-09 05:41:54 +08:00
buf := make([]byte, bufsize)
b.ResetTimer()
b.SetBytes(int64(size))
for i := 0; i < b.N; i++ {
offset := 0
f2, err := sftp.Open("/dev/zero")
if err != nil {
b.Fatal(err)
}
defer f2.Close()
for offset < size {
n, err := io.ReadFull(f2, buf)
offset += n
if err == io.ErrUnexpectedEOF && offset != size {
b.Fatalf("read too few bytes! want: %d, got: %d", size, n)
}
if err != nil {
b.Fatal(err)
}
offset += n
}
}
}
func BenchmarkRead1k(b *testing.B) {
benchmarkRead(b, 1*1024, NODELAY)
2014-10-09 05:41:54 +08:00
}
func BenchmarkRead16k(b *testing.B) {
benchmarkRead(b, 16*1024, NODELAY)
2014-10-09 05:41:54 +08:00
}
func BenchmarkRead32k(b *testing.B) {
benchmarkRead(b, 32*1024, NODELAY)
2014-10-09 05:41:54 +08:00
}
func BenchmarkRead128k(b *testing.B) {
benchmarkRead(b, 128*1024, NODELAY)
2014-10-09 05:41:54 +08:00
}
func BenchmarkRead512k(b *testing.B) {
benchmarkRead(b, 512*1024, NODELAY)
2014-10-09 05:41:54 +08:00
}
func BenchmarkRead1MiB(b *testing.B) {
benchmarkRead(b, 1024*1024, NODELAY)
2014-10-09 05:41:54 +08:00
}
func BenchmarkRead4MiB(b *testing.B) {
benchmarkRead(b, 4*1024*1024, NODELAY)
2014-10-09 05:41:54 +08:00
}
Add integration tests that measure how throughput varies with latency. This clearly shows the impact high latency networks have on the throughput of sftp transfers. The current benchmark results on my machine are: $ go test -bench=. -integration PASS BenchmarkRead1k 20 93028268 ns/op 112.72 MB/s BenchmarkRead16k 100 14912438 ns/op 703.16 MB/s BenchmarkRead32k 100 12282661 ns/op 853.71 MB/s BenchmarkRead128k 100 10550935 ns/op 993.83 MB/s BenchmarkRead512k 100 12970518 ns/op 808.44 MB/s BenchmarkRead1MiB 100 11526693 ns/op 909.70 MB/s BenchmarkRead4MiB 100 15761135 ns/op 665.30 MB/s BenchmarkRead4MiBDelay10Msec 1 2662626928 ns/op 3.94 MB/s BenchmarkRead4MiBDelay50Msec 1 12977334971 ns/op 0.81 MB/s BenchmarkRead4MiBDelay150Msec 1 38777294968 ns/op 0.27 MB/s BenchmarkWrite1k 5 235318220 ns/op 44.56 MB/s BenchmarkWrite16k 50 57347520 ns/op 182.85 MB/s BenchmarkWrite32k 30 66151560 ns/op 158.51 MB/s BenchmarkWrite128k 20 86642733 ns/op 121.02 MB/s BenchmarkWrite512k 20 72648883 ns/op 144.34 MB/s BenchmarkWrite1MiB 20 87145317 ns/op 120.33 MB/s BenchmarkWrite4MiB 50 64098344 ns/op 163.59 MB/s BenchmarkWrite4MiBDelay10Msec 1 3360676836 ns/op 3.12 MB/s BenchmarkWrite4MiBDelay50Msec 1 16321294488 ns/op 0.64 MB/s BenchmarkWrite4MiBDelay150Msec 1 48731747397 ns/op 0.22 MB/s BenchmarkCopyDown10MiBDelay10Msec 1 3369680836 ns/op 3.11 MB/s BenchmarkCopyDown10MiBDelay50Msec 1 16228310257 ns/op 0.65 MB/s BenchmarkCopyDown10MiBDelay150Msec 1 48505306499 ns/op 0.22 MB/s BenchmarkCopyUp10MiBDelay10Msec 1 3393474907 ns/op 3.09 MB/s BenchmarkCopyUp10MiBDelay50Msec 1 16273951972 ns/op 0.64 MB/s BenchmarkCopyUp10MiBDelay150Msec 1 48461724780 ns/op 0.22 MB/s BenchmarkMarshalInit 2000000 779 ns/op BenchmarkMarshalOpen 2000000 645 ns/op BenchmarkMarshalWriteWorstCase 20000 70954 ns/op BenchmarkMarshalWrite1k 300000 5072 ns/op ok github.com/pkg/sftp 296.179s
2015-06-03 00:36:35 +08:00
func BenchmarkRead4MiBDelay10Msec(b *testing.B) {
benchmarkRead(b, 4*1024*1024, 10*time.Millisecond)
2014-10-09 05:41:54 +08:00
}
Add integration tests that measure how throughput varies with latency. This clearly shows the impact high latency networks have on the throughput of sftp transfers. The current benchmark results on my machine are: $ go test -bench=. -integration PASS BenchmarkRead1k 20 93028268 ns/op 112.72 MB/s BenchmarkRead16k 100 14912438 ns/op 703.16 MB/s BenchmarkRead32k 100 12282661 ns/op 853.71 MB/s BenchmarkRead128k 100 10550935 ns/op 993.83 MB/s BenchmarkRead512k 100 12970518 ns/op 808.44 MB/s BenchmarkRead1MiB 100 11526693 ns/op 909.70 MB/s BenchmarkRead4MiB 100 15761135 ns/op 665.30 MB/s BenchmarkRead4MiBDelay10Msec 1 2662626928 ns/op 3.94 MB/s BenchmarkRead4MiBDelay50Msec 1 12977334971 ns/op 0.81 MB/s BenchmarkRead4MiBDelay150Msec 1 38777294968 ns/op 0.27 MB/s BenchmarkWrite1k 5 235318220 ns/op 44.56 MB/s BenchmarkWrite16k 50 57347520 ns/op 182.85 MB/s BenchmarkWrite32k 30 66151560 ns/op 158.51 MB/s BenchmarkWrite128k 20 86642733 ns/op 121.02 MB/s BenchmarkWrite512k 20 72648883 ns/op 144.34 MB/s BenchmarkWrite1MiB 20 87145317 ns/op 120.33 MB/s BenchmarkWrite4MiB 50 64098344 ns/op 163.59 MB/s BenchmarkWrite4MiBDelay10Msec 1 3360676836 ns/op 3.12 MB/s BenchmarkWrite4MiBDelay50Msec 1 16321294488 ns/op 0.64 MB/s BenchmarkWrite4MiBDelay150Msec 1 48731747397 ns/op 0.22 MB/s BenchmarkCopyDown10MiBDelay10Msec 1 3369680836 ns/op 3.11 MB/s BenchmarkCopyDown10MiBDelay50Msec 1 16228310257 ns/op 0.65 MB/s BenchmarkCopyDown10MiBDelay150Msec 1 48505306499 ns/op 0.22 MB/s BenchmarkCopyUp10MiBDelay10Msec 1 3393474907 ns/op 3.09 MB/s BenchmarkCopyUp10MiBDelay50Msec 1 16273951972 ns/op 0.64 MB/s BenchmarkCopyUp10MiBDelay150Msec 1 48461724780 ns/op 0.22 MB/s BenchmarkMarshalInit 2000000 779 ns/op BenchmarkMarshalOpen 2000000 645 ns/op BenchmarkMarshalWriteWorstCase 20000 70954 ns/op BenchmarkMarshalWrite1k 300000 5072 ns/op ok github.com/pkg/sftp 296.179s
2015-06-03 00:36:35 +08:00
func BenchmarkRead4MiBDelay50Msec(b *testing.B) {
benchmarkRead(b, 4*1024*1024, 50*time.Millisecond)
}
func BenchmarkRead4MiBDelay150Msec(b *testing.B) {
benchmarkRead(b, 4*1024*1024, 150*time.Millisecond)
}
func benchmarkWrite(b *testing.B, bufsize int, delay time.Duration) {
2014-10-09 05:41:54 +08:00
size := 10*1024*1024 + 123 // ~10MiB
// open sftp client
Add integration tests that measure how throughput varies with latency. This clearly shows the impact high latency networks have on the throughput of sftp transfers. The current benchmark results on my machine are: $ go test -bench=. -integration PASS BenchmarkRead1k 20 93028268 ns/op 112.72 MB/s BenchmarkRead16k 100 14912438 ns/op 703.16 MB/s BenchmarkRead32k 100 12282661 ns/op 853.71 MB/s BenchmarkRead128k 100 10550935 ns/op 993.83 MB/s BenchmarkRead512k 100 12970518 ns/op 808.44 MB/s BenchmarkRead1MiB 100 11526693 ns/op 909.70 MB/s BenchmarkRead4MiB 100 15761135 ns/op 665.30 MB/s BenchmarkRead4MiBDelay10Msec 1 2662626928 ns/op 3.94 MB/s BenchmarkRead4MiBDelay50Msec 1 12977334971 ns/op 0.81 MB/s BenchmarkRead4MiBDelay150Msec 1 38777294968 ns/op 0.27 MB/s BenchmarkWrite1k 5 235318220 ns/op 44.56 MB/s BenchmarkWrite16k 50 57347520 ns/op 182.85 MB/s BenchmarkWrite32k 30 66151560 ns/op 158.51 MB/s BenchmarkWrite128k 20 86642733 ns/op 121.02 MB/s BenchmarkWrite512k 20 72648883 ns/op 144.34 MB/s BenchmarkWrite1MiB 20 87145317 ns/op 120.33 MB/s BenchmarkWrite4MiB 50 64098344 ns/op 163.59 MB/s BenchmarkWrite4MiBDelay10Msec 1 3360676836 ns/op 3.12 MB/s BenchmarkWrite4MiBDelay50Msec 1 16321294488 ns/op 0.64 MB/s BenchmarkWrite4MiBDelay150Msec 1 48731747397 ns/op 0.22 MB/s BenchmarkCopyDown10MiBDelay10Msec 1 3369680836 ns/op 3.11 MB/s BenchmarkCopyDown10MiBDelay50Msec 1 16228310257 ns/op 0.65 MB/s BenchmarkCopyDown10MiBDelay150Msec 1 48505306499 ns/op 0.22 MB/s BenchmarkCopyUp10MiBDelay10Msec 1 3393474907 ns/op 3.09 MB/s BenchmarkCopyUp10MiBDelay50Msec 1 16273951972 ns/op 0.64 MB/s BenchmarkCopyUp10MiBDelay150Msec 1 48461724780 ns/op 0.22 MB/s BenchmarkMarshalInit 2000000 779 ns/op BenchmarkMarshalOpen 2000000 645 ns/op BenchmarkMarshalWriteWorstCase 20000 70954 ns/op BenchmarkMarshalWrite1k 300000 5072 ns/op ok github.com/pkg/sftp 296.179s
2015-06-03 00:36:35 +08:00
sftp, cmd := testClient(b, false, delay)
2014-10-09 05:41:54 +08:00
defer cmd.Wait()
// defer sftp.Close()
2014-10-09 05:41:54 +08:00
data := make([]byte, size)
b.ResetTimer()
b.SetBytes(int64(size))
for i := 0; i < b.N; i++ {
offset := 0
f, err := ioutil.TempFile("", "sftptest")
if err != nil {
b.Fatal(err)
}
defer os.Remove(f.Name())
f2, err := sftp.Create(f.Name())
if err != nil {
b.Fatal(err)
}
defer f2.Close()
for offset < size {
n, err := f2.Write(data[offset:min(len(data), offset+bufsize)])
if err != nil {
b.Fatal(err)
}
if offset+n < size && n != bufsize {
b.Fatalf("wrote too few bytes! want: %d, got: %d", size, n)
}
offset += n
}
f2.Close()
fi, err := os.Stat(f.Name())
if err != nil {
b.Fatal(err)
}
if fi.Size() != int64(size) {
b.Fatalf("wrong file size: want %d, got %d", size, fi.Size())
}
os.Remove(f.Name())
}
}
func BenchmarkWrite1k(b *testing.B) {
benchmarkWrite(b, 1*1024, NODELAY)
2014-10-09 05:41:54 +08:00
}
func BenchmarkWrite16k(b *testing.B) {
benchmarkWrite(b, 16*1024, NODELAY)
2014-10-09 05:41:54 +08:00
}
func BenchmarkWrite32k(b *testing.B) {
benchmarkWrite(b, 32*1024, NODELAY)
2014-10-09 05:41:54 +08:00
}
func BenchmarkWrite128k(b *testing.B) {
benchmarkWrite(b, 128*1024, NODELAY)
2014-10-09 05:41:54 +08:00
}
func BenchmarkWrite512k(b *testing.B) {
benchmarkWrite(b, 512*1024, NODELAY)
2014-10-09 05:41:54 +08:00
}
func BenchmarkWrite1MiB(b *testing.B) {
benchmarkWrite(b, 1024*1024, NODELAY)
2014-10-09 05:41:54 +08:00
}
func BenchmarkWrite4MiB(b *testing.B) {
benchmarkWrite(b, 4*1024*1024, NODELAY)
Add integration tests that measure how throughput varies with latency. This clearly shows the impact high latency networks have on the throughput of sftp transfers. The current benchmark results on my machine are: $ go test -bench=. -integration PASS BenchmarkRead1k 20 93028268 ns/op 112.72 MB/s BenchmarkRead16k 100 14912438 ns/op 703.16 MB/s BenchmarkRead32k 100 12282661 ns/op 853.71 MB/s BenchmarkRead128k 100 10550935 ns/op 993.83 MB/s BenchmarkRead512k 100 12970518 ns/op 808.44 MB/s BenchmarkRead1MiB 100 11526693 ns/op 909.70 MB/s BenchmarkRead4MiB 100 15761135 ns/op 665.30 MB/s BenchmarkRead4MiBDelay10Msec 1 2662626928 ns/op 3.94 MB/s BenchmarkRead4MiBDelay50Msec 1 12977334971 ns/op 0.81 MB/s BenchmarkRead4MiBDelay150Msec 1 38777294968 ns/op 0.27 MB/s BenchmarkWrite1k 5 235318220 ns/op 44.56 MB/s BenchmarkWrite16k 50 57347520 ns/op 182.85 MB/s BenchmarkWrite32k 30 66151560 ns/op 158.51 MB/s BenchmarkWrite128k 20 86642733 ns/op 121.02 MB/s BenchmarkWrite512k 20 72648883 ns/op 144.34 MB/s BenchmarkWrite1MiB 20 87145317 ns/op 120.33 MB/s BenchmarkWrite4MiB 50 64098344 ns/op 163.59 MB/s BenchmarkWrite4MiBDelay10Msec 1 3360676836 ns/op 3.12 MB/s BenchmarkWrite4MiBDelay50Msec 1 16321294488 ns/op 0.64 MB/s BenchmarkWrite4MiBDelay150Msec 1 48731747397 ns/op 0.22 MB/s BenchmarkCopyDown10MiBDelay10Msec 1 3369680836 ns/op 3.11 MB/s BenchmarkCopyDown10MiBDelay50Msec 1 16228310257 ns/op 0.65 MB/s BenchmarkCopyDown10MiBDelay150Msec 1 48505306499 ns/op 0.22 MB/s BenchmarkCopyUp10MiBDelay10Msec 1 3393474907 ns/op 3.09 MB/s BenchmarkCopyUp10MiBDelay50Msec 1 16273951972 ns/op 0.64 MB/s BenchmarkCopyUp10MiBDelay150Msec 1 48461724780 ns/op 0.22 MB/s BenchmarkMarshalInit 2000000 779 ns/op BenchmarkMarshalOpen 2000000 645 ns/op BenchmarkMarshalWriteWorstCase 20000 70954 ns/op BenchmarkMarshalWrite1k 300000 5072 ns/op ok github.com/pkg/sftp 296.179s
2015-06-03 00:36:35 +08:00
}
func BenchmarkWrite4MiBDelay10Msec(b *testing.B) {
benchmarkWrite(b, 4*1024*1024, 10*time.Millisecond)
}
func BenchmarkWrite4MiBDelay50Msec(b *testing.B) {
benchmarkWrite(b, 4*1024*1024, 50*time.Millisecond)
}
func BenchmarkWrite4MiBDelay150Msec(b *testing.B) {
benchmarkWrite(b, 4*1024*1024, 150*time.Millisecond)
2014-10-09 05:41:54 +08:00
}
2017-06-26 10:21:59 +08:00
func benchmarkReadFrom(b *testing.B, bufsize int, delay time.Duration) {
size := 10*1024*1024 + 123 // ~10MiB
// open sftp client
sftp, cmd := testClient(b, false, delay)
defer cmd.Wait()
// defer sftp.Close()
data := make([]byte, size)
b.ResetTimer()
b.SetBytes(int64(size))
for i := 0; i < b.N; i++ {
f, err := ioutil.TempFile("", "sftptest")
if err != nil {
b.Fatal(err)
}
defer os.Remove(f.Name())
f2, err := sftp.Create(f.Name())
if err != nil {
b.Fatal(err)
}
defer f2.Close()
f2.ReadFrom(bytes.NewReader(data))
f2.Close()
fi, err := os.Stat(f.Name())
if err != nil {
b.Fatal(err)
}
if fi.Size() != int64(size) {
b.Fatalf("wrong file size: want %d, got %d", size, fi.Size())
}
os.Remove(f.Name())
}
}
func BenchmarkReadFrom1k(b *testing.B) {
benchmarkReadFrom(b, 1*1024, NODELAY)
2017-06-26 10:21:59 +08:00
}
func BenchmarkReadFrom16k(b *testing.B) {
benchmarkReadFrom(b, 16*1024, NODELAY)
2017-06-26 10:21:59 +08:00
}
func BenchmarkReadFrom32k(b *testing.B) {
benchmarkReadFrom(b, 32*1024, NODELAY)
2017-06-26 10:21:59 +08:00
}
func BenchmarkReadFrom128k(b *testing.B) {
benchmarkReadFrom(b, 128*1024, NODELAY)
2017-06-26 10:21:59 +08:00
}
func BenchmarkReadFrom512k(b *testing.B) {
benchmarkReadFrom(b, 512*1024, NODELAY)
2017-06-26 10:21:59 +08:00
}
func BenchmarkReadFrom1MiB(b *testing.B) {
benchmarkReadFrom(b, 1024*1024, NODELAY)
2017-06-26 10:21:59 +08:00
}
func BenchmarkReadFrom4MiB(b *testing.B) {
benchmarkReadFrom(b, 4*1024*1024, NODELAY)
2017-06-26 10:21:59 +08:00
}
func BenchmarkReadFrom4MiBDelay10Msec(b *testing.B) {
benchmarkReadFrom(b, 4*1024*1024, 10*time.Millisecond)
}
func BenchmarkReadFrom4MiBDelay50Msec(b *testing.B) {
benchmarkReadFrom(b, 4*1024*1024, 50*time.Millisecond)
}
func BenchmarkReadFrom4MiBDelay150Msec(b *testing.B) {
benchmarkReadFrom(b, 4*1024*1024, 150*time.Millisecond)
}
Add integration tests that measure how throughput varies with latency. This clearly shows the impact high latency networks have on the throughput of sftp transfers. The current benchmark results on my machine are: $ go test -bench=. -integration PASS BenchmarkRead1k 20 93028268 ns/op 112.72 MB/s BenchmarkRead16k 100 14912438 ns/op 703.16 MB/s BenchmarkRead32k 100 12282661 ns/op 853.71 MB/s BenchmarkRead128k 100 10550935 ns/op 993.83 MB/s BenchmarkRead512k 100 12970518 ns/op 808.44 MB/s BenchmarkRead1MiB 100 11526693 ns/op 909.70 MB/s BenchmarkRead4MiB 100 15761135 ns/op 665.30 MB/s BenchmarkRead4MiBDelay10Msec 1 2662626928 ns/op 3.94 MB/s BenchmarkRead4MiBDelay50Msec 1 12977334971 ns/op 0.81 MB/s BenchmarkRead4MiBDelay150Msec 1 38777294968 ns/op 0.27 MB/s BenchmarkWrite1k 5 235318220 ns/op 44.56 MB/s BenchmarkWrite16k 50 57347520 ns/op 182.85 MB/s BenchmarkWrite32k 30 66151560 ns/op 158.51 MB/s BenchmarkWrite128k 20 86642733 ns/op 121.02 MB/s BenchmarkWrite512k 20 72648883 ns/op 144.34 MB/s BenchmarkWrite1MiB 20 87145317 ns/op 120.33 MB/s BenchmarkWrite4MiB 50 64098344 ns/op 163.59 MB/s BenchmarkWrite4MiBDelay10Msec 1 3360676836 ns/op 3.12 MB/s BenchmarkWrite4MiBDelay50Msec 1 16321294488 ns/op 0.64 MB/s BenchmarkWrite4MiBDelay150Msec 1 48731747397 ns/op 0.22 MB/s BenchmarkCopyDown10MiBDelay10Msec 1 3369680836 ns/op 3.11 MB/s BenchmarkCopyDown10MiBDelay50Msec 1 16228310257 ns/op 0.65 MB/s BenchmarkCopyDown10MiBDelay150Msec 1 48505306499 ns/op 0.22 MB/s BenchmarkCopyUp10MiBDelay10Msec 1 3393474907 ns/op 3.09 MB/s BenchmarkCopyUp10MiBDelay50Msec 1 16273951972 ns/op 0.64 MB/s BenchmarkCopyUp10MiBDelay150Msec 1 48461724780 ns/op 0.22 MB/s BenchmarkMarshalInit 2000000 779 ns/op BenchmarkMarshalOpen 2000000 645 ns/op BenchmarkMarshalWriteWorstCase 20000 70954 ns/op BenchmarkMarshalWrite1k 300000 5072 ns/op ok github.com/pkg/sftp 296.179s
2015-06-03 00:36:35 +08:00
func benchmarkCopyDown(b *testing.B, fileSize int64, delay time.Duration) {
skipIfWindows(b)
Add integration tests that measure how throughput varies with latency. This clearly shows the impact high latency networks have on the throughput of sftp transfers. The current benchmark results on my machine are: $ go test -bench=. -integration PASS BenchmarkRead1k 20 93028268 ns/op 112.72 MB/s BenchmarkRead16k 100 14912438 ns/op 703.16 MB/s BenchmarkRead32k 100 12282661 ns/op 853.71 MB/s BenchmarkRead128k 100 10550935 ns/op 993.83 MB/s BenchmarkRead512k 100 12970518 ns/op 808.44 MB/s BenchmarkRead1MiB 100 11526693 ns/op 909.70 MB/s BenchmarkRead4MiB 100 15761135 ns/op 665.30 MB/s BenchmarkRead4MiBDelay10Msec 1 2662626928 ns/op 3.94 MB/s BenchmarkRead4MiBDelay50Msec 1 12977334971 ns/op 0.81 MB/s BenchmarkRead4MiBDelay150Msec 1 38777294968 ns/op 0.27 MB/s BenchmarkWrite1k 5 235318220 ns/op 44.56 MB/s BenchmarkWrite16k 50 57347520 ns/op 182.85 MB/s BenchmarkWrite32k 30 66151560 ns/op 158.51 MB/s BenchmarkWrite128k 20 86642733 ns/op 121.02 MB/s BenchmarkWrite512k 20 72648883 ns/op 144.34 MB/s BenchmarkWrite1MiB 20 87145317 ns/op 120.33 MB/s BenchmarkWrite4MiB 50 64098344 ns/op 163.59 MB/s BenchmarkWrite4MiBDelay10Msec 1 3360676836 ns/op 3.12 MB/s BenchmarkWrite4MiBDelay50Msec 1 16321294488 ns/op 0.64 MB/s BenchmarkWrite4MiBDelay150Msec 1 48731747397 ns/op 0.22 MB/s BenchmarkCopyDown10MiBDelay10Msec 1 3369680836 ns/op 3.11 MB/s BenchmarkCopyDown10MiBDelay50Msec 1 16228310257 ns/op 0.65 MB/s BenchmarkCopyDown10MiBDelay150Msec 1 48505306499 ns/op 0.22 MB/s BenchmarkCopyUp10MiBDelay10Msec 1 3393474907 ns/op 3.09 MB/s BenchmarkCopyUp10MiBDelay50Msec 1 16273951972 ns/op 0.64 MB/s BenchmarkCopyUp10MiBDelay150Msec 1 48461724780 ns/op 0.22 MB/s BenchmarkMarshalInit 2000000 779 ns/op BenchmarkMarshalOpen 2000000 645 ns/op BenchmarkMarshalWriteWorstCase 20000 70954 ns/op BenchmarkMarshalWrite1k 300000 5072 ns/op ok github.com/pkg/sftp 296.179s
2015-06-03 00:36:35 +08:00
// Create a temp file and fill it with zero's.
src, err := ioutil.TempFile("", "sftptest")
if err != nil {
b.Fatal(err)
}
defer src.Close()
srcFilename := src.Name()
defer os.Remove(srcFilename)
zero, err := os.Open("/dev/zero")
if err != nil {
b.Fatal(err)
}
n, err := io.Copy(src, io.LimitReader(zero, fileSize))
if err != nil {
b.Fatal(err)
}
if n < fileSize {
b.Fatal("short copy")
}
zero.Close()
src.Close()
sftp, cmd := testClient(b, READONLY, delay)
defer cmd.Wait()
// defer sftp.Close()
Add integration tests that measure how throughput varies with latency. This clearly shows the impact high latency networks have on the throughput of sftp transfers. The current benchmark results on my machine are: $ go test -bench=. -integration PASS BenchmarkRead1k 20 93028268 ns/op 112.72 MB/s BenchmarkRead16k 100 14912438 ns/op 703.16 MB/s BenchmarkRead32k 100 12282661 ns/op 853.71 MB/s BenchmarkRead128k 100 10550935 ns/op 993.83 MB/s BenchmarkRead512k 100 12970518 ns/op 808.44 MB/s BenchmarkRead1MiB 100 11526693 ns/op 909.70 MB/s BenchmarkRead4MiB 100 15761135 ns/op 665.30 MB/s BenchmarkRead4MiBDelay10Msec 1 2662626928 ns/op 3.94 MB/s BenchmarkRead4MiBDelay50Msec 1 12977334971 ns/op 0.81 MB/s BenchmarkRead4MiBDelay150Msec 1 38777294968 ns/op 0.27 MB/s BenchmarkWrite1k 5 235318220 ns/op 44.56 MB/s BenchmarkWrite16k 50 57347520 ns/op 182.85 MB/s BenchmarkWrite32k 30 66151560 ns/op 158.51 MB/s BenchmarkWrite128k 20 86642733 ns/op 121.02 MB/s BenchmarkWrite512k 20 72648883 ns/op 144.34 MB/s BenchmarkWrite1MiB 20 87145317 ns/op 120.33 MB/s BenchmarkWrite4MiB 50 64098344 ns/op 163.59 MB/s BenchmarkWrite4MiBDelay10Msec 1 3360676836 ns/op 3.12 MB/s BenchmarkWrite4MiBDelay50Msec 1 16321294488 ns/op 0.64 MB/s BenchmarkWrite4MiBDelay150Msec 1 48731747397 ns/op 0.22 MB/s BenchmarkCopyDown10MiBDelay10Msec 1 3369680836 ns/op 3.11 MB/s BenchmarkCopyDown10MiBDelay50Msec 1 16228310257 ns/op 0.65 MB/s BenchmarkCopyDown10MiBDelay150Msec 1 48505306499 ns/op 0.22 MB/s BenchmarkCopyUp10MiBDelay10Msec 1 3393474907 ns/op 3.09 MB/s BenchmarkCopyUp10MiBDelay50Msec 1 16273951972 ns/op 0.64 MB/s BenchmarkCopyUp10MiBDelay150Msec 1 48461724780 ns/op 0.22 MB/s BenchmarkMarshalInit 2000000 779 ns/op BenchmarkMarshalOpen 2000000 645 ns/op BenchmarkMarshalWriteWorstCase 20000 70954 ns/op BenchmarkMarshalWrite1k 300000 5072 ns/op ok github.com/pkg/sftp 296.179s
2015-06-03 00:36:35 +08:00
b.ResetTimer()
b.SetBytes(fileSize)
for i := 0; i < b.N; i++ {
dst, err := ioutil.TempFile("", "sftptest")
if err != nil {
b.Fatal(err)
}
defer os.Remove(dst.Name())
src, err := sftp.Open(srcFilename)
if err != nil {
b.Fatal(err)
}
defer src.Close()
n, err := io.Copy(dst, src)
if err != nil {
b.Fatalf("copy error: %v", err)
}
if n < fileSize {
b.Fatal("unable to copy all bytes")
}
dst.Close()
fi, err := os.Stat(dst.Name())
if err != nil {
b.Fatal(err)
}
if fi.Size() != fileSize {
b.Fatalf("wrong file size: want %d, got %d", fileSize, fi.Size())
}
os.Remove(dst.Name())
}
}
func BenchmarkCopyDown10MiBDelay10Msec(b *testing.B) {
benchmarkCopyDown(b, 10*1024*1024, 10*time.Millisecond)
}
func BenchmarkCopyDown10MiBDelay50Msec(b *testing.B) {
benchmarkCopyDown(b, 10*1024*1024, 50*time.Millisecond)
}
func BenchmarkCopyDown10MiBDelay150Msec(b *testing.B) {
benchmarkCopyDown(b, 10*1024*1024, 150*time.Millisecond)
}
func benchmarkCopyUp(b *testing.B, fileSize int64, delay time.Duration) {
skipIfWindows(b)
Add integration tests that measure how throughput varies with latency. This clearly shows the impact high latency networks have on the throughput of sftp transfers. The current benchmark results on my machine are: $ go test -bench=. -integration PASS BenchmarkRead1k 20 93028268 ns/op 112.72 MB/s BenchmarkRead16k 100 14912438 ns/op 703.16 MB/s BenchmarkRead32k 100 12282661 ns/op 853.71 MB/s BenchmarkRead128k 100 10550935 ns/op 993.83 MB/s BenchmarkRead512k 100 12970518 ns/op 808.44 MB/s BenchmarkRead1MiB 100 11526693 ns/op 909.70 MB/s BenchmarkRead4MiB 100 15761135 ns/op 665.30 MB/s BenchmarkRead4MiBDelay10Msec 1 2662626928 ns/op 3.94 MB/s BenchmarkRead4MiBDelay50Msec 1 12977334971 ns/op 0.81 MB/s BenchmarkRead4MiBDelay150Msec 1 38777294968 ns/op 0.27 MB/s BenchmarkWrite1k 5 235318220 ns/op 44.56 MB/s BenchmarkWrite16k 50 57347520 ns/op 182.85 MB/s BenchmarkWrite32k 30 66151560 ns/op 158.51 MB/s BenchmarkWrite128k 20 86642733 ns/op 121.02 MB/s BenchmarkWrite512k 20 72648883 ns/op 144.34 MB/s BenchmarkWrite1MiB 20 87145317 ns/op 120.33 MB/s BenchmarkWrite4MiB 50 64098344 ns/op 163.59 MB/s BenchmarkWrite4MiBDelay10Msec 1 3360676836 ns/op 3.12 MB/s BenchmarkWrite4MiBDelay50Msec 1 16321294488 ns/op 0.64 MB/s BenchmarkWrite4MiBDelay150Msec 1 48731747397 ns/op 0.22 MB/s BenchmarkCopyDown10MiBDelay10Msec 1 3369680836 ns/op 3.11 MB/s BenchmarkCopyDown10MiBDelay50Msec 1 16228310257 ns/op 0.65 MB/s BenchmarkCopyDown10MiBDelay150Msec 1 48505306499 ns/op 0.22 MB/s BenchmarkCopyUp10MiBDelay10Msec 1 3393474907 ns/op 3.09 MB/s BenchmarkCopyUp10MiBDelay50Msec 1 16273951972 ns/op 0.64 MB/s BenchmarkCopyUp10MiBDelay150Msec 1 48461724780 ns/op 0.22 MB/s BenchmarkMarshalInit 2000000 779 ns/op BenchmarkMarshalOpen 2000000 645 ns/op BenchmarkMarshalWriteWorstCase 20000 70954 ns/op BenchmarkMarshalWrite1k 300000 5072 ns/op ok github.com/pkg/sftp 296.179s
2015-06-03 00:36:35 +08:00
// Create a temp file and fill it with zero's.
src, err := ioutil.TempFile("", "sftptest")
if err != nil {
b.Fatal(err)
}
defer src.Close()
srcFilename := src.Name()
defer os.Remove(srcFilename)
zero, err := os.Open("/dev/zero")
if err != nil {
b.Fatal(err)
}
n, err := io.Copy(src, io.LimitReader(zero, fileSize))
if err != nil {
b.Fatal(err)
}
if n < fileSize {
b.Fatal("short copy")
}
zero.Close()
src.Close()
sftp, cmd := testClient(b, false, delay)
defer cmd.Wait()
// defer sftp.Close()
Add integration tests that measure how throughput varies with latency. This clearly shows the impact high latency networks have on the throughput of sftp transfers. The current benchmark results on my machine are: $ go test -bench=. -integration PASS BenchmarkRead1k 20 93028268 ns/op 112.72 MB/s BenchmarkRead16k 100 14912438 ns/op 703.16 MB/s BenchmarkRead32k 100 12282661 ns/op 853.71 MB/s BenchmarkRead128k 100 10550935 ns/op 993.83 MB/s BenchmarkRead512k 100 12970518 ns/op 808.44 MB/s BenchmarkRead1MiB 100 11526693 ns/op 909.70 MB/s BenchmarkRead4MiB 100 15761135 ns/op 665.30 MB/s BenchmarkRead4MiBDelay10Msec 1 2662626928 ns/op 3.94 MB/s BenchmarkRead4MiBDelay50Msec 1 12977334971 ns/op 0.81 MB/s BenchmarkRead4MiBDelay150Msec 1 38777294968 ns/op 0.27 MB/s BenchmarkWrite1k 5 235318220 ns/op 44.56 MB/s BenchmarkWrite16k 50 57347520 ns/op 182.85 MB/s BenchmarkWrite32k 30 66151560 ns/op 158.51 MB/s BenchmarkWrite128k 20 86642733 ns/op 121.02 MB/s BenchmarkWrite512k 20 72648883 ns/op 144.34 MB/s BenchmarkWrite1MiB 20 87145317 ns/op 120.33 MB/s BenchmarkWrite4MiB 50 64098344 ns/op 163.59 MB/s BenchmarkWrite4MiBDelay10Msec 1 3360676836 ns/op 3.12 MB/s BenchmarkWrite4MiBDelay50Msec 1 16321294488 ns/op 0.64 MB/s BenchmarkWrite4MiBDelay150Msec 1 48731747397 ns/op 0.22 MB/s BenchmarkCopyDown10MiBDelay10Msec 1 3369680836 ns/op 3.11 MB/s BenchmarkCopyDown10MiBDelay50Msec 1 16228310257 ns/op 0.65 MB/s BenchmarkCopyDown10MiBDelay150Msec 1 48505306499 ns/op 0.22 MB/s BenchmarkCopyUp10MiBDelay10Msec 1 3393474907 ns/op 3.09 MB/s BenchmarkCopyUp10MiBDelay50Msec 1 16273951972 ns/op 0.64 MB/s BenchmarkCopyUp10MiBDelay150Msec 1 48461724780 ns/op 0.22 MB/s BenchmarkMarshalInit 2000000 779 ns/op BenchmarkMarshalOpen 2000000 645 ns/op BenchmarkMarshalWriteWorstCase 20000 70954 ns/op BenchmarkMarshalWrite1k 300000 5072 ns/op ok github.com/pkg/sftp 296.179s
2015-06-03 00:36:35 +08:00
b.ResetTimer()
b.SetBytes(fileSize)
for i := 0; i < b.N; i++ {
tmp, err := ioutil.TempFile("", "sftptest")
if err != nil {
b.Fatal(err)
}
tmp.Close()
defer os.Remove(tmp.Name())
dst, err := sftp.Create(tmp.Name())
if err != nil {
b.Fatal(err)
}
defer dst.Close()
src, err := os.Open(srcFilename)
if err != nil {
b.Fatal(err)
}
defer src.Close()
n, err := io.Copy(dst, src)
if err != nil {
b.Fatalf("copy error: %v", err)
}
if n < fileSize {
b.Fatal("unable to copy all bytes")
}
fi, err := os.Stat(tmp.Name())
if err != nil {
b.Fatal(err)
}
if fi.Size() != fileSize {
b.Fatalf("wrong file size: want %d, got %d", fileSize, fi.Size())
}
os.Remove(tmp.Name())
}
}
func BenchmarkCopyUp10MiBDelay10Msec(b *testing.B) {
benchmarkCopyUp(b, 10*1024*1024, 10*time.Millisecond)
}
func BenchmarkCopyUp10MiBDelay50Msec(b *testing.B) {
benchmarkCopyUp(b, 10*1024*1024, 50*time.Millisecond)
}
func BenchmarkCopyUp10MiBDelay150Msec(b *testing.B) {
benchmarkCopyUp(b, 10*1024*1024, 150*time.Millisecond)
2014-10-09 05:41:54 +08:00
}