2016-07-09 03:38:35 +08:00
|
|
|
package sftp
|
|
|
|
|
|
|
|
import (
|
2018-01-31 07:55:50 +08:00
|
|
|
"context"
|
2016-07-23 06:16:25 +08:00
|
|
|
"fmt"
|
2016-07-09 03:38:35 +08:00
|
|
|
"io"
|
2020-09-17 22:48:19 +08:00
|
|
|
"io/ioutil"
|
2016-08-02 05:07:03 +08:00
|
|
|
"net"
|
2016-07-23 06:16:25 +08:00
|
|
|
"os"
|
2021-02-11 02:13:19 +08:00
|
|
|
"runtime"
|
2016-07-09 03:38:35 +08:00
|
|
|
"testing"
|
2020-09-26 00:35:41 +08:00
|
|
|
"time"
|
2016-07-20 03:52:43 +08:00
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
2020-08-25 13:46:42 +08:00
|
|
|
"github.com/stretchr/testify/require"
|
2016-07-09 03:38:35 +08:00
|
|
|
)
|
|
|
|
|
2016-07-23 06:16:25 +08:00
|
|
|
var _ = fmt.Print
|
|
|
|
|
2016-07-21 07:49:00 +08:00
|
|
|
type csPair struct {
|
2020-11-06 01:16:32 +08:00
|
|
|
cli *Client
|
|
|
|
svr *RequestServer
|
|
|
|
svrResult chan error
|
2016-07-21 07:49:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// these must be closed in order, else client.Close will hang
|
|
|
|
func (cs csPair) Close() {
|
|
|
|
cs.svr.Close()
|
|
|
|
cs.cli.Close()
|
2016-08-02 05:07:03 +08:00
|
|
|
os.Remove(sock)
|
2016-07-21 07:49:00 +08:00
|
|
|
}
|
|
|
|
|
2016-07-23 06:16:25 +08:00
|
|
|
func (cs csPair) testHandler() *root {
|
|
|
|
return cs.svr.Handlers.FileGet.(*root)
|
|
|
|
}
|
|
|
|
|
2016-08-04 02:30:14 +08:00
|
|
|
const sock = "/tmp/rstest.sock"
|
2016-08-02 05:07:03 +08:00
|
|
|
|
2016-07-21 07:49:00 +08:00
|
|
|
func clientRequestServerPair(t *testing.T) *csPair {
|
2019-01-19 07:59:30 +08:00
|
|
|
skipIfWindows(t)
|
2020-09-11 00:11:47 +08:00
|
|
|
skipIfPlan9(t)
|
2016-08-02 05:07:03 +08:00
|
|
|
ready := make(chan bool)
|
|
|
|
os.Remove(sock) // either this or signal handling
|
2020-11-06 01:16:32 +08:00
|
|
|
pair := &csPair{
|
2020-11-18 15:57:15 +08:00
|
|
|
svrResult: make(chan error, 1),
|
2020-11-06 01:16:32 +08:00
|
|
|
}
|
2016-08-02 05:07:03 +08:00
|
|
|
var server *RequestServer
|
|
|
|
go func() {
|
|
|
|
l, err := net.Listen("unix", sock)
|
|
|
|
if err != nil {
|
|
|
|
// neither assert nor t.Fatal reliably exit before Accept errors
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
ready <- true
|
|
|
|
fd, err := l.Accept()
|
2020-09-17 20:52:54 +08:00
|
|
|
require.NoError(t, err)
|
2016-08-02 05:07:03 +08:00
|
|
|
handlers := InMemHandler()
|
2020-03-19 20:20:22 +08:00
|
|
|
var options []RequestServerOption
|
2020-03-18 16:36:07 +08:00
|
|
|
if *testAllocator {
|
2020-03-19 20:20:22 +08:00
|
|
|
options = append(options, WithRSAllocator())
|
2020-03-18 16:36:07 +08:00
|
|
|
}
|
2020-03-19 20:20:22 +08:00
|
|
|
server = NewRequestServer(fd, handlers, options...)
|
2020-11-06 01:16:32 +08:00
|
|
|
err = server.Serve()
|
|
|
|
pair.svrResult <- err
|
2016-08-02 05:07:03 +08:00
|
|
|
}()
|
|
|
|
<-ready
|
|
|
|
defer os.Remove(sock)
|
|
|
|
c, err := net.Dial("unix", sock)
|
2020-09-17 20:52:54 +08:00
|
|
|
require.NoError(t, err)
|
2016-08-02 05:07:03 +08:00
|
|
|
client, err := NewClientPipe(c, c)
|
2016-07-23 11:34:35 +08:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("%+v\n", err)
|
|
|
|
}
|
2020-11-06 01:16:32 +08:00
|
|
|
pair.svr = server
|
|
|
|
pair.cli = client
|
|
|
|
return pair
|
2016-07-09 03:38:35 +08:00
|
|
|
}
|
|
|
|
|
2020-03-15 02:42:19 +08:00
|
|
|
func checkRequestServerAllocator(t *testing.T, p *csPair) {
|
|
|
|
if p.svr.pktMgr.alloc == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
checkAllocatorBeforeServerClose(t, p.svr.pktMgr.alloc)
|
|
|
|
p.Close()
|
|
|
|
checkAllocatorAfterServerClose(t, p.svr.pktMgr.alloc)
|
|
|
|
}
|
|
|
|
|
2016-08-02 05:07:03 +08:00
|
|
|
// after adding logging, maybe check log to make sure packet handling
|
|
|
|
// was split over more than one worker
|
|
|
|
func TestRequestSplitWrite(t *testing.T) {
|
|
|
|
p := clientRequestServerPair(t)
|
|
|
|
defer p.Close()
|
|
|
|
w, err := p.cli.Create("/foo")
|
2020-09-03 22:40:14 +08:00
|
|
|
require.NoError(t, err)
|
2016-08-02 05:07:03 +08:00
|
|
|
p.cli.maxPacket = 3 // force it to send in small chunks
|
|
|
|
contents := "one two three four five six seven eight nine ten"
|
|
|
|
w.Write([]byte(contents))
|
|
|
|
w.Close()
|
|
|
|
r := p.testHandler()
|
2020-09-21 22:29:50 +08:00
|
|
|
f, err := r.fetch("/foo")
|
|
|
|
require.NoError(t, err)
|
2016-08-02 05:07:03 +08:00
|
|
|
assert.Equal(t, contents, string(f.content))
|
2020-03-15 02:42:19 +08:00
|
|
|
checkRequestServerAllocator(t, p)
|
2016-08-02 05:07:03 +08:00
|
|
|
}
|
|
|
|
|
2016-07-20 03:52:43 +08:00
|
|
|
func TestRequestCache(t *testing.T) {
|
2016-07-21 07:49:00 +08:00
|
|
|
p := clientRequestServerPair(t)
|
|
|
|
defer p.Close()
|
2016-10-21 09:42:47 +08:00
|
|
|
foo := NewRequest("", "foo")
|
2018-02-02 03:32:59 +08:00
|
|
|
foo.ctx, foo.cancelCtx = context.WithCancel(context.Background())
|
2016-10-21 09:42:47 +08:00
|
|
|
bar := NewRequest("", "bar")
|
2016-07-27 02:32:37 +08:00
|
|
|
fh := p.svr.nextRequest(foo)
|
|
|
|
bh := p.svr.nextRequest(bar)
|
2016-07-21 07:49:00 +08:00
|
|
|
assert.Len(t, p.svr.openRequests, 2)
|
2019-01-29 10:23:54 +08:00
|
|
|
_foo, ok := p.svr.getRequest(fh)
|
2018-01-31 07:55:50 +08:00
|
|
|
assert.Equal(t, foo.Method, _foo.Method)
|
|
|
|
assert.Equal(t, foo.Filepath, _foo.Filepath)
|
|
|
|
assert.Equal(t, foo.Target, _foo.Target)
|
|
|
|
assert.Equal(t, foo.Flags, _foo.Flags)
|
|
|
|
assert.Equal(t, foo.Attrs, _foo.Attrs)
|
|
|
|
assert.Equal(t, foo.state, _foo.state)
|
|
|
|
assert.NotNil(t, _foo.ctx)
|
|
|
|
assert.Equal(t, _foo.Context().Err(), nil, "context is still valid")
|
2016-07-09 03:38:35 +08:00
|
|
|
assert.True(t, ok)
|
2019-01-29 10:23:54 +08:00
|
|
|
_, ok = p.svr.getRequest("zed")
|
2016-07-09 03:38:35 +08:00
|
|
|
assert.False(t, ok)
|
2016-07-27 02:32:37 +08:00
|
|
|
p.svr.closeRequest(fh)
|
2018-01-31 07:55:50 +08:00
|
|
|
assert.Equal(t, _foo.Context().Err(), context.Canceled, "context is now canceled")
|
2016-07-27 02:32:37 +08:00
|
|
|
p.svr.closeRequest(bh)
|
2016-07-21 07:49:00 +08:00
|
|
|
assert.Len(t, p.svr.openRequests, 0)
|
2020-03-15 02:42:19 +08:00
|
|
|
checkRequestServerAllocator(t, p)
|
2016-07-21 07:49:00 +08:00
|
|
|
}
|
|
|
|
|
2016-07-30 02:22:07 +08:00
|
|
|
func TestRequestCacheState(t *testing.T) {
|
|
|
|
// test operation that uses open/close
|
|
|
|
p := clientRequestServerPair(t)
|
|
|
|
defer p.Close()
|
|
|
|
_, err := putTestFile(p.cli, "/foo", "hello")
|
2020-09-17 20:52:54 +08:00
|
|
|
require.NoError(t, err)
|
2016-07-30 02:22:07 +08:00
|
|
|
assert.Len(t, p.svr.openRequests, 0)
|
|
|
|
// test operation that doesn't open/close
|
|
|
|
err = p.cli.Remove("/foo")
|
2020-09-17 20:52:54 +08:00
|
|
|
assert.NoError(t, err)
|
2016-07-30 02:22:07 +08:00
|
|
|
assert.Len(t, p.svr.openRequests, 0)
|
2020-03-15 02:42:19 +08:00
|
|
|
checkRequestServerAllocator(t, p)
|
2016-07-30 02:22:07 +08:00
|
|
|
}
|
|
|
|
|
2016-07-21 07:49:00 +08:00
|
|
|
func putTestFile(cli *Client, path, content string) (int, error) {
|
|
|
|
w, err := cli.Create(path)
|
|
|
|
if err == nil {
|
|
|
|
defer w.Close()
|
|
|
|
return w.Write([]byte(content))
|
|
|
|
}
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
|
2020-09-17 22:48:19 +08:00
|
|
|
func getTestFile(cli *Client, path string) ([]byte, error) {
|
|
|
|
r, err := cli.Open(path)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer r.Close()
|
|
|
|
|
|
|
|
return ioutil.ReadAll(r)
|
|
|
|
}
|
|
|
|
|
2016-07-21 07:49:00 +08:00
|
|
|
func TestRequestWrite(t *testing.T) {
|
|
|
|
p := clientRequestServerPair(t)
|
|
|
|
defer p.Close()
|
|
|
|
n, err := putTestFile(p.cli, "/foo", "hello")
|
2020-09-17 20:52:54 +08:00
|
|
|
require.NoError(t, err)
|
2016-07-21 07:49:00 +08:00
|
|
|
assert.Equal(t, 5, n)
|
2016-07-23 06:16:25 +08:00
|
|
|
r := p.testHandler()
|
|
|
|
f, err := r.fetch("/foo")
|
2020-09-17 20:52:54 +08:00
|
|
|
require.NoError(t, err)
|
2016-07-23 06:16:25 +08:00
|
|
|
assert.False(t, f.isdir)
|
|
|
|
assert.Equal(t, f.content, []byte("hello"))
|
2020-03-15 02:42:19 +08:00
|
|
|
checkRequestServerAllocator(t, p)
|
2016-07-23 06:16:25 +08:00
|
|
|
}
|
|
|
|
|
2017-12-25 05:43:57 +08:00
|
|
|
func TestRequestWriteEmpty(t *testing.T) {
|
|
|
|
p := clientRequestServerPair(t)
|
|
|
|
defer p.Close()
|
|
|
|
n, err := putTestFile(p.cli, "/foo", "")
|
2020-09-17 20:52:54 +08:00
|
|
|
require.NoError(t, err)
|
2017-12-25 05:43:57 +08:00
|
|
|
assert.Equal(t, 0, n)
|
|
|
|
r := p.testHandler()
|
|
|
|
f, err := r.fetch("/foo")
|
2020-09-17 20:52:54 +08:00
|
|
|
require.NoError(t, err)
|
|
|
|
assert.False(t, f.isdir)
|
|
|
|
assert.Len(t, f.content, 0)
|
2018-01-08 10:30:26 +08:00
|
|
|
// lets test with an error
|
2018-01-17 06:18:45 +08:00
|
|
|
r.returnErr(os.ErrInvalid)
|
2018-01-08 10:30:26 +08:00
|
|
|
n, err = putTestFile(p.cli, "/bar", "")
|
2020-09-17 20:52:54 +08:00
|
|
|
require.Error(t, err)
|
2018-01-17 06:18:45 +08:00
|
|
|
r.returnErr(nil)
|
2018-02-16 02:28:06 +08:00
|
|
|
assert.Equal(t, 0, n)
|
2020-03-15 02:42:19 +08:00
|
|
|
checkRequestServerAllocator(t, p)
|
2017-12-25 05:43:57 +08:00
|
|
|
}
|
|
|
|
|
2016-07-23 06:16:25 +08:00
|
|
|
func TestRequestFilename(t *testing.T) {
|
|
|
|
p := clientRequestServerPair(t)
|
|
|
|
defer p.Close()
|
|
|
|
_, err := putTestFile(p.cli, "/foo", "hello")
|
2020-09-17 20:52:54 +08:00
|
|
|
require.NoError(t, err)
|
2016-07-23 06:16:25 +08:00
|
|
|
r := p.testHandler()
|
|
|
|
f, err := r.fetch("/foo")
|
2020-09-17 20:52:54 +08:00
|
|
|
require.NoError(t, err)
|
2016-07-23 06:16:25 +08:00
|
|
|
assert.Equal(t, f.Name(), "foo")
|
2018-02-16 02:28:06 +08:00
|
|
|
_, err = r.fetch("/bar")
|
2018-01-08 10:05:50 +08:00
|
|
|
assert.Error(t, err)
|
2020-03-15 02:42:19 +08:00
|
|
|
checkRequestServerAllocator(t, p)
|
2016-07-21 07:49:00 +08:00
|
|
|
}
|
|
|
|
|
2018-11-21 08:34:41 +08:00
|
|
|
func TestRequestJustRead(t *testing.T) {
|
2016-07-21 07:49:00 +08:00
|
|
|
p := clientRequestServerPair(t)
|
|
|
|
defer p.Close()
|
|
|
|
_, err := putTestFile(p.cli, "/foo", "hello")
|
2020-09-17 20:52:54 +08:00
|
|
|
require.NoError(t, err)
|
2016-07-21 07:49:00 +08:00
|
|
|
rf, err := p.cli.Open("/foo")
|
2020-09-17 20:52:54 +08:00
|
|
|
require.NoError(t, err)
|
2016-07-21 07:49:00 +08:00
|
|
|
defer rf.Close()
|
|
|
|
contents := make([]byte, 5)
|
|
|
|
n, err := rf.Read(contents)
|
2016-07-23 11:34:35 +08:00
|
|
|
if err != nil && err != io.EOF {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
2016-07-21 07:49:00 +08:00
|
|
|
assert.Equal(t, 5, n)
|
|
|
|
assert.Equal(t, "hello", string(contents[0:5]))
|
2020-03-15 02:42:19 +08:00
|
|
|
checkRequestServerAllocator(t, p)
|
2016-07-09 03:38:35 +08:00
|
|
|
}
|
2016-07-23 06:16:25 +08:00
|
|
|
|
2018-11-21 08:34:41 +08:00
|
|
|
func TestRequestOpenFail(t *testing.T) {
|
2016-07-23 11:34:35 +08:00
|
|
|
p := clientRequestServerPair(t)
|
|
|
|
defer p.Close()
|
|
|
|
rf, err := p.cli.Open("/foo")
|
2017-03-01 02:44:56 +08:00
|
|
|
assert.Exactly(t, os.ErrNotExist, err)
|
2018-11-21 08:34:41 +08:00
|
|
|
assert.Nil(t, rf)
|
2020-11-16 21:34:09 +08:00
|
|
|
// if we return an error the sftp client will not close the handle
|
|
|
|
// ensure that we close it ourself
|
|
|
|
assert.Len(t, p.svr.openRequests, 0)
|
2020-03-15 02:42:19 +08:00
|
|
|
checkRequestServerAllocator(t, p)
|
2016-07-23 11:34:35 +08:00
|
|
|
}
|
|
|
|
|
2018-11-21 08:34:41 +08:00
|
|
|
func TestRequestCreate(t *testing.T) {
|
2016-07-23 06:16:25 +08:00
|
|
|
p := clientRequestServerPair(t)
|
|
|
|
defer p.Close()
|
2018-11-21 08:34:41 +08:00
|
|
|
fh, err := p.cli.Create("foo")
|
2020-09-17 20:52:54 +08:00
|
|
|
require.NoError(t, err)
|
2016-07-23 06:16:25 +08:00
|
|
|
err = fh.Close()
|
2020-09-17 20:52:54 +08:00
|
|
|
assert.NoError(t, err)
|
2020-03-15 02:42:19 +08:00
|
|
|
checkRequestServerAllocator(t, p)
|
2016-07-23 06:16:25 +08:00
|
|
|
}
|
|
|
|
|
2020-08-30 16:40:22 +08:00
|
|
|
func TestRequestReadAndWrite(t *testing.T) {
|
|
|
|
p := clientRequestServerPair(t)
|
|
|
|
defer p.Close()
|
2020-09-17 21:46:13 +08:00
|
|
|
|
2020-09-17 20:56:04 +08:00
|
|
|
file, err := p.cli.OpenFile("/foo", os.O_RDWR|os.O_CREATE)
|
2020-08-30 16:40:22 +08:00
|
|
|
require.NoError(t, err)
|
|
|
|
defer file.Close()
|
|
|
|
|
|
|
|
n, err := file.Write([]byte("hello"))
|
|
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, 5, n)
|
2020-09-17 21:46:13 +08:00
|
|
|
|
2020-08-30 16:40:22 +08:00
|
|
|
buf := make([]byte, 4)
|
|
|
|
n, err = file.ReadAt(buf, 1)
|
|
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, 4, n)
|
|
|
|
assert.Equal(t, []byte{'e', 'l', 'l', 'o'}, buf)
|
2020-09-17 20:58:38 +08:00
|
|
|
|
2020-09-17 21:46:13 +08:00
|
|
|
checkRequestServerAllocator(t, p)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestOpenFileExclusive(t *testing.T) {
|
|
|
|
p := clientRequestServerPair(t)
|
|
|
|
defer p.Close()
|
|
|
|
|
|
|
|
// first open should work
|
|
|
|
file, err := p.cli.OpenFile("/foo", os.O_RDWR|os.O_CREATE|os.O_EXCL)
|
|
|
|
require.NoError(t, err)
|
|
|
|
file.Close()
|
|
|
|
|
|
|
|
// second open should return error
|
2020-09-17 20:58:38 +08:00
|
|
|
_, err = p.cli.OpenFile("/foo", os.O_RDWR|os.O_CREATE|os.O_EXCL)
|
|
|
|
assert.Error(t, err)
|
|
|
|
|
2020-09-17 22:23:59 +08:00
|
|
|
checkRequestServerAllocator(t, p)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestOpenFileExclusiveNoSymlinkFollowing(t *testing.T) {
|
|
|
|
p := clientRequestServerPair(t)
|
|
|
|
defer p.Close()
|
|
|
|
|
2020-09-17 21:46:13 +08:00
|
|
|
// make a directory
|
2020-09-17 23:31:22 +08:00
|
|
|
err := p.cli.Mkdir("/foo")
|
2020-09-17 21:46:13 +08:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// make a symlink to that directory
|
2020-09-17 23:31:22 +08:00
|
|
|
err = p.cli.Symlink("/foo", "/foo2")
|
2020-09-17 21:46:13 +08:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2020-09-25 22:01:02 +08:00
|
|
|
// with O_EXCL, we can follow directory symlinks
|
2020-09-17 23:31:22 +08:00
|
|
|
file, err := p.cli.OpenFile("/foo2/bar", os.O_RDWR|os.O_CREATE|os.O_EXCL)
|
2020-09-25 22:01:02 +08:00
|
|
|
require.NoError(t, err)
|
|
|
|
err = file.Close()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// we should have created the file above; and this create should fail.
|
|
|
|
_, err = p.cli.OpenFile("/foo/bar", os.O_RDWR|os.O_CREATE|os.O_EXCL)
|
2020-09-17 21:46:13 +08:00
|
|
|
require.Error(t, err)
|
|
|
|
|
2020-09-25 22:01:02 +08:00
|
|
|
// create a dangling symlink
|
|
|
|
err = p.cli.Symlink("/notexist", "/bar")
|
2020-09-17 21:46:13 +08:00
|
|
|
require.NoError(t, err)
|
2020-09-25 22:01:02 +08:00
|
|
|
|
|
|
|
// opening a dangling symlink with O_CREATE and O_EXCL should fail, regardless of target not existing.
|
|
|
|
_, err = p.cli.OpenFile("/bar", os.O_RDWR|os.O_CREATE|os.O_EXCL)
|
|
|
|
require.Error(t, err)
|
2020-09-17 21:46:13 +08:00
|
|
|
|
2020-08-30 16:40:22 +08:00
|
|
|
checkRequestServerAllocator(t, p)
|
|
|
|
}
|
|
|
|
|
2016-07-23 06:16:25 +08:00
|
|
|
func TestRequestMkdir(t *testing.T) {
|
|
|
|
p := clientRequestServerPair(t)
|
|
|
|
defer p.Close()
|
|
|
|
err := p.cli.Mkdir("/foo")
|
2020-09-17 20:52:54 +08:00
|
|
|
require.NoError(t, err)
|
2016-07-23 06:16:25 +08:00
|
|
|
r := p.testHandler()
|
|
|
|
f, err := r.fetch("/foo")
|
2020-09-21 22:29:50 +08:00
|
|
|
require.NoError(t, err)
|
|
|
|
assert.True(t, f.IsDir())
|
2020-03-15 02:42:19 +08:00
|
|
|
checkRequestServerAllocator(t, p)
|
2016-07-23 06:16:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestRequestRemove(t *testing.T) {
|
|
|
|
p := clientRequestServerPair(t)
|
|
|
|
defer p.Close()
|
|
|
|
_, err := putTestFile(p.cli, "/foo", "hello")
|
2020-09-17 20:52:54 +08:00
|
|
|
require.NoError(t, err)
|
2016-07-23 06:16:25 +08:00
|
|
|
r := p.testHandler()
|
|
|
|
_, err = r.fetch("/foo")
|
2020-09-17 20:52:54 +08:00
|
|
|
assert.NoError(t, err)
|
2016-07-23 06:16:25 +08:00
|
|
|
err = p.cli.Remove("/foo")
|
2020-09-17 20:52:54 +08:00
|
|
|
assert.NoError(t, err)
|
2016-07-23 06:16:25 +08:00
|
|
|
_, err = r.fetch("/foo")
|
|
|
|
assert.Equal(t, err, os.ErrNotExist)
|
2020-03-15 02:42:19 +08:00
|
|
|
checkRequestServerAllocator(t, p)
|
2016-07-23 06:16:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestRequestRename(t *testing.T) {
|
|
|
|
p := clientRequestServerPair(t)
|
|
|
|
defer p.Close()
|
2020-09-26 00:13:45 +08:00
|
|
|
|
2016-07-23 06:16:25 +08:00
|
|
|
_, err := putTestFile(p.cli, "/foo", "hello")
|
2020-09-17 20:52:54 +08:00
|
|
|
require.NoError(t, err)
|
2020-09-26 00:13:45 +08:00
|
|
|
content, err := getTestFile(p.cli, "/foo")
|
2020-09-17 20:52:54 +08:00
|
|
|
require.NoError(t, err)
|
2020-09-26 00:13:45 +08:00
|
|
|
require.Equal(t, []byte("hello"), content)
|
|
|
|
|
2016-07-23 06:16:25 +08:00
|
|
|
err = p.cli.Rename("/foo", "/bar")
|
2020-09-17 20:52:54 +08:00
|
|
|
require.NoError(t, err)
|
2020-09-26 00:13:45 +08:00
|
|
|
|
|
|
|
// file contents are now at /bar
|
|
|
|
content, err = getTestFile(p.cli, "/bar")
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, []byte("hello"), content)
|
|
|
|
|
|
|
|
// /foo no longer exists
|
|
|
|
_, err = getTestFile(p.cli, "/foo")
|
|
|
|
require.Error(t, err)
|
|
|
|
|
|
|
|
_, err = putTestFile(p.cli, "/baz", "goodbye")
|
|
|
|
require.NoError(t, err)
|
|
|
|
content, err = getTestFile(p.cli, "/baz")
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, []byte("goodbye"), content)
|
|
|
|
|
|
|
|
// SFTP-v2: SSH_FXP_RENAME may not overwrite existing files.
|
|
|
|
err = p.cli.Rename("/bar", "/baz")
|
|
|
|
require.Error(t, err)
|
|
|
|
|
|
|
|
// /bar and /baz are unchanged
|
|
|
|
content, err = getTestFile(p.cli, "/bar")
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, []byte("hello"), content)
|
|
|
|
content, err = getTestFile(p.cli, "/baz")
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, []byte("goodbye"), content)
|
|
|
|
|
|
|
|
// posix-rename@openssh.com extension allows overwriting existing files.
|
2019-10-28 17:34:49 +08:00
|
|
|
err = p.cli.PosixRename("/bar", "/baz")
|
2020-09-17 20:52:54 +08:00
|
|
|
require.NoError(t, err)
|
2020-09-26 00:13:45 +08:00
|
|
|
|
|
|
|
// /baz now has the contents of /bar
|
|
|
|
content, err = getTestFile(p.cli, "/baz")
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, []byte("hello"), content)
|
|
|
|
|
|
|
|
// /bar no longer exists
|
|
|
|
_, err = getTestFile(p.cli, "/bar")
|
|
|
|
require.Error(t, err)
|
|
|
|
|
2020-03-15 02:42:19 +08:00
|
|
|
checkRequestServerAllocator(t, p)
|
2016-07-23 06:16:25 +08:00
|
|
|
}
|
|
|
|
|
2016-07-23 11:34:35 +08:00
|
|
|
func TestRequestRenameFail(t *testing.T) {
|
|
|
|
p := clientRequestServerPair(t)
|
|
|
|
defer p.Close()
|
|
|
|
_, err := putTestFile(p.cli, "/foo", "hello")
|
2020-09-17 20:52:54 +08:00
|
|
|
require.NoError(t, err)
|
2016-07-23 11:34:35 +08:00
|
|
|
_, err = putTestFile(p.cli, "/bar", "goodbye")
|
2020-09-17 20:52:54 +08:00
|
|
|
require.NoError(t, err)
|
2016-07-23 11:34:35 +08:00
|
|
|
err = p.cli.Rename("/foo", "/bar")
|
|
|
|
assert.IsType(t, &StatusError{}, err)
|
2020-03-15 02:42:19 +08:00
|
|
|
checkRequestServerAllocator(t, p)
|
2016-07-23 11:34:35 +08:00
|
|
|
}
|
|
|
|
|
2016-07-23 06:16:25 +08:00
|
|
|
func TestRequestStat(t *testing.T) {
|
|
|
|
p := clientRequestServerPair(t)
|
|
|
|
defer p.Close()
|
|
|
|
_, err := putTestFile(p.cli, "/foo", "hello")
|
2020-09-17 20:52:54 +08:00
|
|
|
require.NoError(t, err)
|
2016-07-23 06:16:25 +08:00
|
|
|
fi, err := p.cli.Stat("/foo")
|
2020-09-21 22:29:50 +08:00
|
|
|
require.NoError(t, err)
|
2016-07-23 06:16:25 +08:00
|
|
|
assert.Equal(t, fi.Name(), "foo")
|
|
|
|
assert.Equal(t, fi.Size(), int64(5))
|
|
|
|
assert.Equal(t, fi.Mode(), os.FileMode(0644))
|
2017-03-02 11:51:32 +08:00
|
|
|
assert.NoError(t, testOsSys(fi.Sys()))
|
2020-03-15 02:42:19 +08:00
|
|
|
checkRequestServerAllocator(t, p)
|
2016-07-23 06:16:25 +08:00
|
|
|
}
|
|
|
|
|
2017-04-25 12:36:09 +08:00
|
|
|
// NOTE: Setstat is a noop in the request server tests, but we want to test
|
|
|
|
// that is does nothing without crapping out.
|
|
|
|
func TestRequestSetstat(t *testing.T) {
|
|
|
|
p := clientRequestServerPair(t)
|
|
|
|
defer p.Close()
|
|
|
|
_, err := putTestFile(p.cli, "/foo", "hello")
|
2020-09-17 20:52:54 +08:00
|
|
|
require.NoError(t, err)
|
2017-04-25 12:36:09 +08:00
|
|
|
mode := os.FileMode(0644)
|
|
|
|
err = p.cli.Chmod("/foo", mode)
|
2020-09-17 20:52:54 +08:00
|
|
|
require.NoError(t, err)
|
2017-04-25 12:36:09 +08:00
|
|
|
fi, err := p.cli.Stat("/foo")
|
2020-09-17 20:52:54 +08:00
|
|
|
require.NoError(t, err)
|
2017-04-25 12:36:09 +08:00
|
|
|
assert.Equal(t, fi.Name(), "foo")
|
|
|
|
assert.Equal(t, fi.Size(), int64(5))
|
|
|
|
assert.Equal(t, fi.Mode(), os.FileMode(0644))
|
|
|
|
assert.NoError(t, testOsSys(fi.Sys()))
|
2020-03-15 02:42:19 +08:00
|
|
|
checkRequestServerAllocator(t, p)
|
2017-04-25 12:36:09 +08:00
|
|
|
}
|
|
|
|
|
2017-04-25 10:05:13 +08:00
|
|
|
func TestRequestFstat(t *testing.T) {
|
|
|
|
p := clientRequestServerPair(t)
|
|
|
|
defer p.Close()
|
|
|
|
_, err := putTestFile(p.cli, "/foo", "hello")
|
2020-09-17 20:52:54 +08:00
|
|
|
require.NoError(t, err)
|
2017-04-25 10:05:13 +08:00
|
|
|
fp, err := p.cli.Open("/foo")
|
2020-09-17 20:52:54 +08:00
|
|
|
require.NoError(t, err)
|
2017-04-25 10:05:13 +08:00
|
|
|
fi, err := fp.Stat()
|
2020-09-17 20:52:54 +08:00
|
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, fi.Name(), "foo")
|
|
|
|
assert.Equal(t, fi.Size(), int64(5))
|
|
|
|
assert.Equal(t, fi.Mode(), os.FileMode(0644))
|
|
|
|
assert.NoError(t, testOsSys(fi.Sys()))
|
2020-03-15 02:42:19 +08:00
|
|
|
checkRequestServerAllocator(t, p)
|
2017-04-25 10:05:13 +08:00
|
|
|
}
|
|
|
|
|
2020-08-22 15:51:12 +08:00
|
|
|
func TestRequestFsetstat(t *testing.T) {
|
|
|
|
p := clientRequestServerPair(t)
|
|
|
|
defer p.Close()
|
|
|
|
_, err := putTestFile(p.cli, "/foo", "hello")
|
2020-08-25 13:46:42 +08:00
|
|
|
require.NoError(t, err)
|
2020-08-22 15:51:12 +08:00
|
|
|
fp, err := p.cli.OpenFile("/foo", os.O_WRONLY)
|
2020-08-25 13:46:42 +08:00
|
|
|
require.NoError(t, err)
|
2020-08-22 15:51:12 +08:00
|
|
|
err = fp.Truncate(2)
|
2020-08-25 13:46:42 +08:00
|
|
|
fi, err := fp.Stat()
|
2020-08-25 20:39:22 +08:00
|
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, fi.Name(), "foo")
|
|
|
|
assert.Equal(t, fi.Size(), int64(2))
|
|
|
|
err = fp.Truncate(5)
|
|
|
|
require.NoError(t, err)
|
|
|
|
fi, err = fp.Stat()
|
|
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, fi.Name(), "foo")
|
|
|
|
assert.Equal(t, fi.Size(), int64(5))
|
2020-08-22 15:51:12 +08:00
|
|
|
err = fp.Close()
|
|
|
|
assert.NoError(t, err)
|
|
|
|
rf, err := p.cli.Open("/foo")
|
2020-08-25 13:46:42 +08:00
|
|
|
assert.NoError(t, err)
|
2020-08-22 15:51:12 +08:00
|
|
|
defer rf.Close()
|
|
|
|
contents := make([]byte, 20)
|
2020-08-25 20:39:22 +08:00
|
|
|
n, err := rf.Read(contents)
|
2020-08-25 13:46:42 +08:00
|
|
|
assert.EqualError(t, err, io.EOF.Error())
|
2020-08-25 20:39:22 +08:00
|
|
|
assert.Equal(t, 5, n)
|
|
|
|
assert.Equal(t, []byte{'h', 'e', 0, 0, 0}, contents[0:n])
|
2020-08-22 15:51:12 +08:00
|
|
|
checkRequestServerAllocator(t, p)
|
|
|
|
}
|
|
|
|
|
2016-07-23 06:16:25 +08:00
|
|
|
func TestRequestStatFail(t *testing.T) {
|
|
|
|
p := clientRequestServerPair(t)
|
|
|
|
defer p.Close()
|
|
|
|
fi, err := p.cli.Stat("/foo")
|
|
|
|
assert.Nil(t, fi)
|
|
|
|
assert.True(t, os.IsNotExist(err))
|
2020-03-15 02:42:19 +08:00
|
|
|
checkRequestServerAllocator(t, p)
|
2016-07-23 06:16:25 +08:00
|
|
|
}
|
|
|
|
|
2020-09-06 14:26:58 +08:00
|
|
|
func TestRequestLstat(t *testing.T) {
|
|
|
|
p := clientRequestServerPair(t)
|
|
|
|
defer p.Close()
|
|
|
|
_, err := putTestFile(p.cli, "/foo", "hello")
|
|
|
|
require.NoError(t, err)
|
|
|
|
err = p.cli.Symlink("/foo", "/bar")
|
|
|
|
require.NoError(t, err)
|
|
|
|
fi, err := p.cli.Lstat("/bar")
|
|
|
|
require.NoError(t, err)
|
|
|
|
assert.True(t, fi.Mode()&os.ModeSymlink == os.ModeSymlink)
|
|
|
|
checkRequestServerAllocator(t, p)
|
|
|
|
}
|
|
|
|
|
2019-05-25 03:23:18 +08:00
|
|
|
func TestRequestLink(t *testing.T) {
|
|
|
|
p := clientRequestServerPair(t)
|
|
|
|
defer p.Close()
|
2020-09-21 22:29:50 +08:00
|
|
|
|
2019-05-25 03:23:18 +08:00
|
|
|
_, err := putTestFile(p.cli, "/foo", "hello")
|
2020-09-17 20:52:54 +08:00
|
|
|
require.NoError(t, err)
|
2020-09-21 22:29:50 +08:00
|
|
|
|
2019-05-25 03:23:18 +08:00
|
|
|
err = p.cli.Link("/foo", "/bar")
|
2020-09-17 20:52:54 +08:00
|
|
|
require.NoError(t, err)
|
2020-09-21 22:29:50 +08:00
|
|
|
|
|
|
|
content, err := getTestFile(p.cli, "/bar")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, []byte("hello"), content)
|
|
|
|
|
2020-03-15 02:42:19 +08:00
|
|
|
checkRequestServerAllocator(t, p)
|
2019-05-25 03:23:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestRequestLinkFail(t *testing.T) {
|
|
|
|
p := clientRequestServerPair(t)
|
|
|
|
defer p.Close()
|
|
|
|
err := p.cli.Link("/foo", "/bar")
|
|
|
|
t.Log(err)
|
|
|
|
assert.True(t, os.IsNotExist(err))
|
2020-03-15 02:42:19 +08:00
|
|
|
checkRequestServerAllocator(t, p)
|
2019-05-25 03:23:18 +08:00
|
|
|
}
|
|
|
|
|
2016-07-23 11:34:35 +08:00
|
|
|
func TestRequestSymlink(t *testing.T) {
|
2016-07-23 06:16:25 +08:00
|
|
|
p := clientRequestServerPair(t)
|
|
|
|
defer p.Close()
|
2020-09-17 19:40:22 +08:00
|
|
|
|
2016-07-23 11:34:35 +08:00
|
|
|
_, err := putTestFile(p.cli, "/foo", "hello")
|
2020-09-17 19:40:22 +08:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2016-07-23 11:34:35 +08:00
|
|
|
err = p.cli.Symlink("/foo", "/bar")
|
2020-09-17 19:40:22 +08:00
|
|
|
require.NoError(t, err)
|
|
|
|
err = p.cli.Symlink("/bar", "/baz")
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2016-07-23 11:34:35 +08:00
|
|
|
r := p.testHandler()
|
2020-09-17 19:40:22 +08:00
|
|
|
|
2020-09-17 19:47:19 +08:00
|
|
|
fi, err := r.lfetch("/bar")
|
2020-09-21 22:29:50 +08:00
|
|
|
require.NoError(t, err)
|
2016-07-23 11:34:35 +08:00
|
|
|
assert.True(t, fi.Mode()&os.ModeSymlink == os.ModeSymlink)
|
2020-09-17 19:40:22 +08:00
|
|
|
|
2020-09-17 19:47:19 +08:00
|
|
|
fi, err = r.lfetch("/baz")
|
2020-09-21 22:29:50 +08:00
|
|
|
require.NoError(t, err)
|
2020-09-17 19:40:22 +08:00
|
|
|
assert.True(t, fi.Mode()&os.ModeSymlink == os.ModeSymlink)
|
|
|
|
|
2020-09-17 22:48:19 +08:00
|
|
|
content, err := getTestFile(p.cli, "/baz")
|
2020-09-17 19:40:22 +08:00
|
|
|
require.NoError(t, err)
|
2020-09-17 22:48:19 +08:00
|
|
|
assert.Equal(t, []byte("hello"), content)
|
2020-09-17 19:40:22 +08:00
|
|
|
|
2020-03-15 02:42:19 +08:00
|
|
|
checkRequestServerAllocator(t, p)
|
2016-07-23 11:34:35 +08:00
|
|
|
}
|
|
|
|
|
2020-09-26 00:35:41 +08:00
|
|
|
func TestRequestSymlinkLoop(t *testing.T) {
|
|
|
|
p := clientRequestServerPair(t)
|
|
|
|
defer p.Close()
|
|
|
|
|
|
|
|
err := p.cli.Symlink("/foo", "/bar")
|
|
|
|
require.NoError(t, err)
|
|
|
|
err = p.cli.Symlink("/bar", "/baz")
|
|
|
|
require.NoError(t, err)
|
|
|
|
err = p.cli.Symlink("/baz", "/foo")
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// test should fail if we reach this point
|
|
|
|
timer := time.NewTimer(1 * time.Second)
|
|
|
|
defer timer.Stop()
|
|
|
|
|
|
|
|
var content []byte
|
|
|
|
|
|
|
|
done := make(chan struct{})
|
|
|
|
go func() {
|
|
|
|
defer close(done)
|
|
|
|
|
|
|
|
content, err = getTestFile(p.cli, "/bar")
|
|
|
|
}()
|
|
|
|
|
|
|
|
select {
|
|
|
|
case <-timer.C:
|
|
|
|
t.Fatal("symlink loop following timed out")
|
|
|
|
return // just to let the compiler be absolutely sure
|
|
|
|
|
|
|
|
case <-done:
|
|
|
|
}
|
|
|
|
|
|
|
|
assert.Error(t, err)
|
|
|
|
assert.Len(t, content, 0)
|
|
|
|
|
|
|
|
checkRequestServerAllocator(t, p)
|
|
|
|
}
|
|
|
|
|
2020-09-17 22:48:19 +08:00
|
|
|
func TestRequestSymlinkDanglingFiles(t *testing.T) {
|
2016-07-23 11:34:35 +08:00
|
|
|
p := clientRequestServerPair(t)
|
|
|
|
defer p.Close()
|
2020-09-17 22:05:55 +08:00
|
|
|
|
2020-09-17 22:48:19 +08:00
|
|
|
// dangling links are ok. We will use "/foo" later.
|
2016-07-23 11:34:35 +08:00
|
|
|
err := p.cli.Symlink("/foo", "/bar")
|
2020-09-17 22:05:55 +08:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2020-09-17 22:48:19 +08:00
|
|
|
// creating a symlink in a non-existant directory should fail.
|
|
|
|
err = p.cli.Symlink("/dangle", "/foo/bar")
|
|
|
|
require.Error(t, err)
|
|
|
|
|
|
|
|
// creating a symlink under a dangling symlink should fail.
|
|
|
|
err = p.cli.Symlink("/dangle", "/bar/bar")
|
|
|
|
require.Error(t, err)
|
|
|
|
|
2020-09-17 22:23:59 +08:00
|
|
|
// opening a dangling link without O_CREATE should fail with os.IsNotExist == true
|
|
|
|
_, err = p.cli.OpenFile("/bar", os.O_RDONLY)
|
|
|
|
require.True(t, os.IsNotExist(err))
|
|
|
|
|
2020-09-17 22:48:19 +08:00
|
|
|
// overwriting a symlink is not allowed.
|
|
|
|
err = p.cli.Symlink("/dangle", "/bar")
|
2020-09-17 22:23:59 +08:00
|
|
|
require.Error(t, err)
|
2020-09-17 22:05:55 +08:00
|
|
|
|
2020-09-17 22:23:59 +08:00
|
|
|
// double symlink
|
|
|
|
err = p.cli.Symlink("/bar", "/baz")
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2020-09-17 22:48:19 +08:00
|
|
|
// opening a dangling link with O_CREATE should work.
|
|
|
|
_, err = putTestFile(p.cli, "/baz", "hello")
|
2020-09-17 22:23:59 +08:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2020-09-17 22:48:19 +08:00
|
|
|
// dangling link creation should create the target file itself.
|
|
|
|
content, err := getTestFile(p.cli, "/foo")
|
2020-09-17 22:23:59 +08:00
|
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, []byte("hello"), content)
|
2020-09-17 22:05:55 +08:00
|
|
|
|
2020-09-17 22:48:19 +08:00
|
|
|
// creating a symlink under a non-directory file should fail.
|
|
|
|
err = p.cli.Symlink("/dangle", "/foo/bar")
|
|
|
|
assert.Error(t, err)
|
|
|
|
|
2020-03-15 02:42:19 +08:00
|
|
|
checkRequestServerAllocator(t, p)
|
2016-07-23 11:34:35 +08:00
|
|
|
}
|
|
|
|
|
2020-09-17 23:31:22 +08:00
|
|
|
func TestRequestSymlinkDanglingDirectories(t *testing.T) {
|
|
|
|
p := clientRequestServerPair(t)
|
|
|
|
defer p.Close()
|
|
|
|
|
|
|
|
// dangling links are ok. We will use "/foo" later.
|
|
|
|
err := p.cli.Symlink("/foo", "/bar")
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// reading from a dangling symlink should fail.
|
|
|
|
_, err = p.cli.ReadDir("/bar")
|
|
|
|
require.True(t, os.IsNotExist(err))
|
|
|
|
|
2020-09-25 21:33:06 +08:00
|
|
|
// making a directory on a dangling symlink SHOULD NOT work.
|
2020-09-17 23:31:22 +08:00
|
|
|
err = p.cli.Mkdir("/bar")
|
2020-09-25 21:33:06 +08:00
|
|
|
require.Error(t, err)
|
|
|
|
|
|
|
|
// ok, now make directory, so we can test make files through the symlink.
|
|
|
|
err = p.cli.Mkdir("/foo")
|
2020-09-17 23:31:22 +08:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// should be able to make a file in that symlinked directory.
|
|
|
|
_, err = putTestFile(p.cli, "/bar/baz", "hello")
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// dangling directory creation should create the target directory itself.
|
|
|
|
content, err := getTestFile(p.cli, "/foo/baz")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, []byte("hello"), content)
|
|
|
|
|
|
|
|
checkRequestServerAllocator(t, p)
|
|
|
|
}
|
|
|
|
|
2016-07-23 11:34:35 +08:00
|
|
|
func TestRequestReadlink(t *testing.T) {
|
|
|
|
p := clientRequestServerPair(t)
|
|
|
|
defer p.Close()
|
|
|
|
_, err := putTestFile(p.cli, "/foo", "hello")
|
2020-09-17 20:52:54 +08:00
|
|
|
require.NoError(t, err)
|
2016-07-23 11:34:35 +08:00
|
|
|
err = p.cli.Symlink("/foo", "/bar")
|
2020-09-17 20:52:54 +08:00
|
|
|
require.NoError(t, err)
|
2016-07-23 11:34:35 +08:00
|
|
|
rl, err := p.cli.ReadLink("/bar")
|
2020-09-17 20:52:54 +08:00
|
|
|
assert.NoError(t, err)
|
2016-07-23 11:34:35 +08:00
|
|
|
assert.Equal(t, "foo", rl)
|
2020-03-15 02:42:19 +08:00
|
|
|
checkRequestServerAllocator(t, p)
|
2016-07-23 11:34:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestRequestReaddir(t *testing.T) {
|
|
|
|
p := clientRequestServerPair(t)
|
2017-07-28 09:22:11 +08:00
|
|
|
MaxFilelist = 22 // make not divisible by our test amount (100)
|
2016-07-23 11:34:35 +08:00
|
|
|
defer p.Close()
|
2017-07-11 07:43:58 +08:00
|
|
|
for i := 0; i < 100; i++ {
|
|
|
|
fname := fmt.Sprintf("/foo_%02d", i)
|
|
|
|
_, err := putTestFile(p.cli, fname, fname)
|
2019-02-05 05:20:01 +08:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal("expected no error, got:", err)
|
2019-01-29 10:20:55 +08:00
|
|
|
}
|
2017-07-11 07:43:58 +08:00
|
|
|
}
|
2018-05-26 12:47:30 +08:00
|
|
|
_, err := p.cli.ReadDir("/foo_01")
|
2019-08-30 23:04:37 +08:00
|
|
|
assert.Equal(t, &StatusError{Code: sshFxFailure,
|
2018-05-26 12:47:30 +08:00
|
|
|
msg: " /foo_01: not a directory"}, err)
|
|
|
|
_, err = p.cli.ReadDir("/does_not_exist")
|
|
|
|
assert.Equal(t, os.ErrNotExist, err)
|
2016-07-23 11:34:35 +08:00
|
|
|
di, err := p.cli.ReadDir("/")
|
2020-09-21 22:29:50 +08:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, di, 100)
|
2017-07-11 07:43:58 +08:00
|
|
|
names := []string{di[18].Name(), di[81].Name()}
|
|
|
|
assert.Equal(t, []string{"foo_18", "foo_81"}, names)
|
2020-11-16 21:34:09 +08:00
|
|
|
assert.Len(t, p.svr.openRequests, 0)
|
2020-03-15 02:42:19 +08:00
|
|
|
checkRequestServerAllocator(t, p)
|
2016-07-23 06:16:25 +08:00
|
|
|
}
|
2017-08-13 20:00:08 +08:00
|
|
|
|
2021-02-11 02:13:19 +08:00
|
|
|
func TestRequestStatVFS(t *testing.T) {
|
|
|
|
if runtime.GOOS != "linux" && runtime.GOOS != "darwin" {
|
|
|
|
t.Skip("StatVFS is implemented on linux and darwin")
|
|
|
|
}
|
|
|
|
|
|
|
|
p := clientRequestServerPair(t)
|
|
|
|
defer p.Close()
|
|
|
|
|
|
|
|
_, ok := p.cli.HasExtension("statvfs@openssh.com")
|
|
|
|
require.True(t, ok, "request server doesn't list statvfs extension")
|
|
|
|
vfs, err := p.cli.StatVFS("/")
|
|
|
|
require.NoError(t, err)
|
|
|
|
expected, err := getStatVFSForPath("/")
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotEqual(t, 0, expected.ID)
|
|
|
|
// check some stats
|
|
|
|
require.Equal(t, expected.Bavail, vfs.Bavail)
|
|
|
|
require.Equal(t, expected.Bfree, vfs.Bfree)
|
|
|
|
require.Equal(t, expected.Blocks, vfs.Blocks)
|
2021-02-11 02:35:30 +08:00
|
|
|
|
|
|
|
checkRequestServerAllocator(t, p)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestRequestStatVFSError(t *testing.T) {
|
|
|
|
if runtime.GOOS != "linux" && runtime.GOOS != "darwin" {
|
|
|
|
t.Skip("StatVFS is implemented on linux and darwin")
|
|
|
|
}
|
|
|
|
|
|
|
|
p := clientRequestServerPair(t)
|
|
|
|
defer p.Close()
|
|
|
|
|
|
|
|
_, err := p.cli.StatVFS("a missing path")
|
|
|
|
require.Error(t, err)
|
|
|
|
require.True(t, os.IsNotExist(err))
|
|
|
|
|
|
|
|
checkRequestServerAllocator(t, p)
|
2021-02-11 02:13:19 +08:00
|
|
|
}
|
|
|
|
|
2020-11-06 01:16:32 +08:00
|
|
|
func TestCleanDisconnect(t *testing.T) {
|
|
|
|
p := clientRequestServerPair(t)
|
|
|
|
defer p.Close()
|
|
|
|
|
|
|
|
err := p.cli.conn.Close()
|
|
|
|
require.NoError(t, err)
|
|
|
|
// server must return io.EOF after a clean client close
|
|
|
|
// with no pending open requests
|
|
|
|
err = <-p.svrResult
|
|
|
|
require.EqualError(t, err, io.EOF.Error())
|
|
|
|
checkRequestServerAllocator(t, p)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestUncleanDisconnect(t *testing.T) {
|
|
|
|
p := clientRequestServerPair(t)
|
|
|
|
defer p.Close()
|
|
|
|
|
|
|
|
foo := NewRequest("", "foo")
|
|
|
|
p.svr.nextRequest(foo)
|
|
|
|
err := p.cli.conn.Close()
|
|
|
|
require.NoError(t, err)
|
|
|
|
// the foo request above is still open after the client disconnects
|
|
|
|
// so the server will convert io.EOF to io.ErrUnexpectedEOF
|
|
|
|
err = <-p.svrResult
|
|
|
|
require.EqualError(t, err, io.ErrUnexpectedEOF.Error())
|
|
|
|
checkRequestServerAllocator(t, p)
|
|
|
|
}
|
|
|
|
|
2017-08-13 20:00:08 +08:00
|
|
|
func TestCleanPath(t *testing.T) {
|
|
|
|
assert.Equal(t, "/", cleanPath("/"))
|
2017-12-22 03:58:29 +08:00
|
|
|
assert.Equal(t, "/", cleanPath("."))
|
|
|
|
assert.Equal(t, "/", cleanPath("/."))
|
|
|
|
assert.Equal(t, "/", cleanPath("/a/.."))
|
|
|
|
assert.Equal(t, "/a/c", cleanPath("/a/b/../c"))
|
|
|
|
assert.Equal(t, "/a/c", cleanPath("/a/b/../c/"))
|
|
|
|
assert.Equal(t, "/a", cleanPath("/a/b/.."))
|
|
|
|
assert.Equal(t, "/a/b/c", cleanPath("/a/b/c"))
|
2017-08-13 20:00:08 +08:00
|
|
|
assert.Equal(t, "/", cleanPath("//"))
|
|
|
|
assert.Equal(t, "/a", cleanPath("/a/"))
|
|
|
|
assert.Equal(t, "/a", cleanPath("a/"))
|
|
|
|
assert.Equal(t, "/a/b/c", cleanPath("/a//b//c/"))
|
|
|
|
|
2017-12-22 03:58:29 +08:00
|
|
|
// filepath.ToSlash does not touch \ as char on unix systems
|
|
|
|
// so os.PathSeparator is used for windows compatible tests
|
2017-08-13 20:00:08 +08:00
|
|
|
bslash := string(os.PathSeparator)
|
|
|
|
assert.Equal(t, "/", cleanPath(bslash))
|
|
|
|
assert.Equal(t, "/", cleanPath(bslash+bslash))
|
|
|
|
assert.Equal(t, "/a", cleanPath(bslash+"a"+bslash))
|
|
|
|
assert.Equal(t, "/a", cleanPath("a"+bslash))
|
2017-12-22 03:58:29 +08:00
|
|
|
assert.Equal(t, "/a/b/c",
|
|
|
|
cleanPath(bslash+"a"+bslash+bslash+"b"+bslash+bslash+"c"+bslash))
|
2020-06-30 00:27:11 +08:00
|
|
|
assert.Equal(t, "/C:/a", cleanPath("C:"+bslash+"a"))
|
2017-08-13 20:00:08 +08:00
|
|
|
}
|