sftp/request_test.go

253 lines
6.4 KiB
Go
Raw Permalink Normal View History

2016-07-13 05:56:34 +08:00
package sftp
import (
"sync"
2016-07-13 05:56:34 +08:00
"github.com/stretchr/testify/assert"
"bytes"
"errors"
"io"
"os"
"testing"
)
type testHandler struct {
2016-07-30 06:57:06 +08:00
filecontents []byte // dummy contents
output io.WriterAt // dummy file out
err error // dummy error, should be file related
2016-07-13 05:56:34 +08:00
}
func (t *testHandler) Fileread(r *Request) (io.ReaderAt, error) {
2016-07-20 03:52:43 +08:00
if t.err != nil {
return nil, t.err
}
_ = r.WithContext(r.Context()) // initialize context for deadlock testing
2016-07-30 06:57:06 +08:00
return bytes.NewReader(t.filecontents), nil
2016-07-13 05:56:34 +08:00
}
func (t *testHandler) Filewrite(r *Request) (io.WriterAt, error) {
2016-07-20 03:52:43 +08:00
if t.err != nil {
return nil, t.err
}
_ = r.WithContext(r.Context()) // initialize context for deadlock testing
2016-07-30 06:57:06 +08:00
return io.WriterAt(t.output), nil
2016-07-13 05:56:34 +08:00
}
func (t *testHandler) Filecmd(r *Request) error {
_ = r.WithContext(r.Context()) // initialize context for deadlock testing
return t.err
2016-07-13 05:56:34 +08:00
}
func (t *testHandler) Filelist(r *Request) (ListerAt, error) {
2016-07-20 03:52:43 +08:00
if t.err != nil {
return nil, t.err
}
_ = r.WithContext(r.Context()) // initialize context for deadlock testing
2016-07-13 05:56:34 +08:00
f, err := os.Open(r.Filepath)
2016-07-20 03:52:43 +08:00
if err != nil {
return nil, err
}
2016-07-13 05:56:34 +08:00
fi, err := f.Stat()
2016-07-20 03:52:43 +08:00
if err != nil {
return nil, err
}
return listerat([]os.FileInfo{fi}), nil
2016-07-13 05:56:34 +08:00
}
2016-07-30 06:57:06 +08:00
// make sure len(fakefile) == len(filecontents)
type fakefile [10]byte
2016-08-04 02:30:14 +08:00
var filecontents = []byte("file-data.")
2016-07-30 06:57:06 +08:00
// XXX need new for creating test requests that supports Open-ing
func testRequest(method string) *Request {
var flags uint32
switch method {
case "Get":
flags = flags | sshFxfRead
case "Put":
flags = flags | sshFxfWrite
}
request := &Request{
Filepath: "./request_test.go",
Method: method,
Attrs: []byte("foo"),
Flags: flags,
Target: "foo",
state: state{RWMutex: new(sync.RWMutex)},
2016-07-13 05:56:34 +08:00
}
return request
2016-07-13 05:56:34 +08:00
}
2016-07-30 06:57:06 +08:00
func (ff *fakefile) WriteAt(p []byte, off int64) (int, error) {
n := copy(ff[off:], p)
return n, nil
}
func (ff fakefile) string() string {
b := make([]byte, len(ff))
copy(b, ff[:])
return string(b)
}
2016-07-13 05:56:34 +08:00
func newTestHandlers() Handlers {
handler := &testHandler{
2016-07-30 06:57:06 +08:00
filecontents: filecontents,
output: &fakefile{},
2016-07-13 05:56:34 +08:00
err: nil,
}
return Handlers{
FileGet: handler,
FilePut: handler,
FileCmd: handler,
FileList: handler,
2016-07-13 05:56:34 +08:00
}
}
2016-07-30 06:57:06 +08:00
func (h Handlers) getOutString() string {
2016-07-13 05:56:34 +08:00
handler := h.FilePut.(*testHandler)
2016-07-30 06:57:06 +08:00
return handler.output.(*fakefile).string()
2016-07-13 05:56:34 +08:00
}
2016-07-26 02:42:18 +08:00
var errTest = errors.New("test error")
2016-07-13 05:56:34 +08:00
2018-01-17 06:12:00 +08:00
func (h *Handlers) returnError(err error) {
2016-07-13 05:56:34 +08:00
handler := h.FilePut.(*testHandler)
2018-01-17 06:12:00 +08:00
handler.err = err
2016-07-13 05:56:34 +08:00
}
2018-03-11 04:51:41 +08:00
func getStatusMsg(p interface{}) string {
pkt := p.(*sshFxpStatusPacket)
2018-03-11 04:51:41 +08:00
return pkt.StatusError.msg
}
func checkOkStatus(t *testing.T, p interface{}) {
pkt := p.(*sshFxpStatusPacket)
assert.Equal(t, pkt.StatusError.Code, uint32(sshFxOk),
2018-01-17 06:12:00 +08:00
"sshFxpStatusPacket not OK\n", pkt.StatusError.msg)
2016-07-13 05:56:34 +08:00
}
// fake/test packet
type fakePacket struct {
myid uint32
handle string
}
func (f fakePacket) id() uint32 {
return f.myid
}
func (f fakePacket) getHandle() string {
return f.handle
}
func (fakePacket) UnmarshalBinary(d []byte) error { return nil }
// XXX can't just set method to Get, need to use Open to setup Get/Put
2016-07-20 03:52:43 +08:00
func TestRequestGet(t *testing.T) {
2016-07-13 05:56:34 +08:00
handlers := newTestHandlers()
request := testRequest("Get")
pkt := fakePacket{myid: 1}
request.open(handlers, pkt)
2016-07-30 06:57:06 +08:00
// req.length is 5, so we test reads in 5 byte chunks
for i, txt := range []string{"file-", "data."} {
pkt := &sshFxpReadPacket{ID: uint32(i), Handle: "a",
Offset: uint64(i * 5), Len: 5}
rpkt := request.call(handlers, pkt, nil, 0)
dpkt := rpkt.(*sshFxpDataPacket)
assert.Equal(t, dpkt.id(), uint32(i))
2016-07-13 07:50:59 +08:00
assert.Equal(t, string(dpkt.Data), txt)
2016-07-13 05:56:34 +08:00
}
}
2018-01-17 06:12:00 +08:00
func TestRequestCustomError(t *testing.T) {
handlers := newTestHandlers()
request := testRequest("Stat")
pkt := fakePacket{myid: 1}
cmdErr := errors.New("stat not supported")
handlers.returnError(cmdErr)
rpkt := request.call(handlers, pkt, nil, 0)
assert.Equal(t, rpkt, statusFromError(pkt.myid, cmdErr))
2018-01-17 06:12:00 +08:00
}
// XXX can't just set method to Get, need to use Open to setup Get/Put
2016-07-20 03:52:43 +08:00
func TestRequestPut(t *testing.T) {
2016-07-13 05:56:34 +08:00
handlers := newTestHandlers()
request := testRequest("Put")
request.state.writerAt, _ = handlers.FilePut.Filewrite(request)
pkt := &sshFxpWritePacket{ID: 0, Handle: "a", Offset: 0, Length: 5,
Data: []byte("file-")}
rpkt := request.call(handlers, pkt, nil, 0)
2018-03-11 04:51:41 +08:00
checkOkStatus(t, rpkt)
pkt = &sshFxpWritePacket{ID: 1, Handle: "a", Offset: 5, Length: 5,
Data: []byte("data.")}
rpkt = request.call(handlers, pkt, nil, 0)
2018-03-11 04:51:41 +08:00
checkOkStatus(t, rpkt)
2016-07-30 06:57:06 +08:00
assert.Equal(t, "file-data.", handlers.getOutString())
2016-07-13 05:56:34 +08:00
}
2016-07-20 03:52:43 +08:00
func TestRequestCmdr(t *testing.T) {
2016-07-13 05:56:34 +08:00
handlers := newTestHandlers()
request := testRequest("Mkdir")
pkt := fakePacket{myid: 1}
rpkt := request.call(handlers, pkt, nil, 0)
2018-03-11 04:51:41 +08:00
checkOkStatus(t, rpkt)
2016-07-13 05:56:34 +08:00
2018-01-17 06:12:00 +08:00
handlers.returnError(errTest)
rpkt = request.call(handlers, pkt, nil, 0)
assert.Equal(t, rpkt, statusFromError(pkt.myid, errTest))
2016-07-13 05:56:34 +08:00
}
2016-07-20 03:52:43 +08:00
func TestRequestInfoStat(t *testing.T) {
2016-07-13 05:56:34 +08:00
handlers := newTestHandlers()
request := testRequest("Stat")
pkt := fakePacket{myid: 1}
rpkt := request.call(handlers, pkt, nil, 0)
spkt, ok := rpkt.(*sshFxpStatResponse)
2016-08-04 02:30:14 +08:00
assert.True(t, ok)
2016-07-13 07:50:59 +08:00
assert.Equal(t, spkt.info.Name(), "request_test.go")
2016-07-13 05:56:34 +08:00
}
func TestRequestInfoList(t *testing.T) {
handlers := newTestHandlers()
request := testRequest("List")
request.handle = "1"
pkt := fakePacket{myid: 1}
rpkt := request.opendir(handlers, pkt)
hpkt, ok := rpkt.(*sshFxpHandlePacket)
if assert.True(t, ok) {
assert.Equal(t, hpkt.Handle, "1")
}
pkt = fakePacket{myid: 2}
request.call(handlers, pkt, nil, 0)
}
func TestRequestInfoReadlink(t *testing.T) {
2016-07-13 05:56:34 +08:00
handlers := newTestHandlers()
request := testRequest("Readlink")
pkt := fakePacket{myid: 1}
rpkt := request.call(handlers, pkt, nil, 0)
npkt, ok := rpkt.(*sshFxpNamePacket)
if assert.True(t, ok) {
assert.IsType(t, &sshFxpNameAttr{}, npkt.NameAttrs[0])
assert.Equal(t, npkt.NameAttrs[0].Name, "request_test.go")
}
2016-07-13 05:56:34 +08:00
}
func TestOpendirHandleReuse(t *testing.T) {
handlers := newTestHandlers()
request := testRequest("Stat")
request.handle = "1"
pkt := fakePacket{myid: 1}
rpkt := request.call(handlers, pkt, nil, 0)
assert.IsType(t, &sshFxpStatResponse{}, rpkt)
request.Method = "List"
pkt = fakePacket{myid: 2}
rpkt = request.opendir(handlers, pkt)
if assert.IsType(t, &sshFxpHandlePacket{}, rpkt) {
hpkt := rpkt.(*sshFxpHandlePacket)
assert.Equal(t, hpkt.Handle, "1")
}
rpkt = request.call(handlers, pkt, nil, 0)
assert.IsType(t, &sshFxpNamePacket{}, rpkt)
}