ftp/client_test.go

401 lines
7.7 KiB
Go
Raw Normal View History

package ftp
import (
"bytes"
"io/ioutil"
"net/textproto"
2017-04-15 11:53:19 +02:00
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
const (
testData = "Just some text"
2013-02-17 10:31:56 +01:00
testDir = "mydir"
)
2015-08-20 01:46:22 +02:00
func TestConnPASV(t *testing.T) {
testConn(t, true)
}
func TestConnEPSV(t *testing.T) {
testConn(t, false)
}
func testConn(t *testing.T, disableEPSV bool) {
2015-08-18 18:39:31 +02:00
mock, c := openConn(t, "127.0.0.1", DialWithTimeout(5*time.Second), DialWithDisabledEPSV(disableEPSV))
2015-08-20 01:46:22 +02:00
2019-04-10 20:20:50 +02:00
err := c.Login("anonymous", "anonymous")
if err != nil {
t.Fatal(err)
}
err = c.NoOp()
if err != nil {
t.Error(err)
}
2015-08-18 19:34:22 +02:00
err = c.ChangeDir("incoming")
if err != nil {
t.Error(err)
}
2019-04-10 20:20:50 +02:00
dir, err := c.CurrentDir()
if err != nil {
t.Error(err)
} else {
if dir != "/incoming" {
t.Error("Wrong dir: " + dir)
}
}
data := bytes.NewBufferString(testData)
err = c.Stor("test", data)
if err != nil {
t.Error(err)
}
_, err = c.List(".")
if err != nil {
t.Error(err)
}
err = c.Rename("test", "tset")
if err != nil {
t.Error(err)
}
2017-04-15 11:53:19 +02:00
// Read without deadline
r, err := c.Retr("tset")
if err != nil {
t.Error(err)
} else {
2021-03-07 01:43:28 +01:00
buf, errRead := ioutil.ReadAll(r)
if err != nil {
2021-03-07 01:43:28 +01:00
t.Error(errRead)
}
if string(buf) != testData {
t.Errorf("'%s'", buf)
}
r.Close()
2017-05-05 02:46:29 +02:00
r.Close() // test we can close two times
}
2017-04-15 11:53:19 +02:00
// Read with deadline
r, err = c.Retr("tset")
if err != nil {
t.Error(err)
} else {
r.SetDeadline(time.Now())
2021-03-07 01:43:28 +01:00
_, err = ioutil.ReadAll(r)
2017-04-15 11:53:19 +02:00
if err == nil {
t.Error("deadline should have caused error")
} else if !strings.HasSuffix(err.Error(), "i/o timeout") {
t.Error(err)
}
r.Close()
}
// Read with offset
2015-08-20 22:47:09 +02:00
r, err = c.RetrFrom("tset", 5)
if err != nil {
t.Error(err)
} else {
2021-03-07 01:43:28 +01:00
buf, errRead := ioutil.ReadAll(r)
if errRead != nil {
t.Error(errRead)
2015-08-20 22:47:09 +02:00
}
expected := testData[5:]
if string(buf) != expected {
t.Errorf("read %q, expected %q", buf, expected)
}
r.Close()
}
2020-03-10 11:43:17 +01:00
data2 := bytes.NewBufferString(testData)
err = c.Append("tset", data2)
if err != nil {
t.Error(err)
}
// Read without deadline, after append
r, err = c.Retr("tset")
if err != nil {
t.Error(err)
} else {
2021-03-07 01:43:28 +01:00
buf, errRead := ioutil.ReadAll(r)
2020-03-10 11:43:17 +01:00
if err != nil {
2021-03-07 01:43:28 +01:00
t.Error(errRead)
2020-03-10 11:43:17 +01:00
}
if string(buf) != testData+testData {
t.Errorf("'%s'", buf)
}
r.Close()
}
2019-04-10 20:20:50 +02:00
fileSize, err := c.FileSize("magic-file")
if err != nil {
t.Error(err)
}
2019-04-10 20:20:50 +02:00
if fileSize != 42 {
t.Errorf("file size %q, expected %q", fileSize, 42)
2017-02-20 06:34:20 +01:00
}
2017-03-04 12:58:20 +01:00
_, err = c.FileSize("not-found")
if err == nil {
t.Fatal("expected error, got nil")
}
err = c.Delete("tset")
if err != nil {
t.Error(err)
}
err = c.MakeDir(testDir)
if err != nil {
t.Error(err)
}
err = c.ChangeDir(testDir)
if err != nil {
t.Error(err)
}
err = c.ChangeDirToParent()
if err != nil {
t.Error(err)
}
2015-08-20 10:32:28 +02:00
entries, err := c.NameList("/")
if err != nil {
t.Error(err)
}
if len(entries) != 1 || entries[0] != "/incoming" {
t.Errorf("Unexpected entries: %v", entries)
}
err = c.RemoveDir(testDir)
if err != nil {
t.Error(err)
}
2013-05-19 21:15:23 +02:00
err = c.Logout()
if err != nil {
if protoErr := err.(*textproto.Error); protoErr != nil {
if protoErr.Code != StatusNotImplemented {
t.Error(err)
}
} else {
t.Error(err)
}
2013-05-19 21:15:23 +02:00
}
2021-03-07 01:43:28 +01:00
if err = c.Quit(); err != nil {
2019-04-10 20:20:50 +02:00
t.Fatal(err)
}
// Wait for the connection to close
mock.Wait()
err = c.NoOp()
if err == nil {
t.Error("Expected error")
}
}
2013-07-08 07:48:11 +02:00
2019-04-10 20:20:50 +02:00
// TestConnect tests the legacy Connect function
func TestConnect(t *testing.T) {
mock, err := newFtpMock(t, "127.0.0.1")
if err != nil {
t.Fatal(err)
}
2019-04-10 20:20:50 +02:00
defer mock.Close()
2019-04-10 20:20:50 +02:00
c, err := Connect(mock.Addr())
if err != nil {
t.Fatal(err)
}
2019-04-10 20:20:50 +02:00
if err := c.Quit(); err != nil {
t.Fatal(err)
}
2019-04-10 20:20:50 +02:00
mock.Wait()
}
2015-08-21 18:36:56 +02:00
func TestTimeout(t *testing.T) {
if testing.Short() {
t.Skip("skipping test in short mode.")
}
2020-10-21 22:10:46 +02:00
if c, err := DialTimeout("localhost:2121", 1*time.Second); err == nil {
2015-08-21 18:36:56 +02:00
c.Quit()
2020-10-21 22:10:46 +02:00
t.Fatal("expected timeout, got nil error")
2015-08-21 18:36:56 +02:00
}
}
func TestWrongLogin(t *testing.T) {
2019-04-10 20:20:50 +02:00
mock, err := newFtpMock(t, "127.0.0.1")
if err != nil {
t.Fatal(err)
2015-08-21 18:36:56 +02:00
}
2019-04-10 20:20:50 +02:00
defer mock.Close()
2015-08-21 18:36:56 +02:00
2019-04-10 20:20:50 +02:00
c, err := DialTimeout(mock.Addr(), 5*time.Second)
2015-08-21 18:36:56 +02:00
if err != nil {
t.Fatal(err)
}
defer c.Quit()
err = c.Login("zoo2Shia", "fei5Yix9")
if err == nil {
t.Fatal("expected error, got nil")
}
}
func TestDeleteDirRecur(t *testing.T) {
2019-04-10 20:20:50 +02:00
mock, c := openConn(t, "127.0.0.1")
2019-04-10 20:20:50 +02:00
err := c.RemoveDirRecur("testDir")
if err != nil {
t.Error(err)
}
2019-04-10 20:20:50 +02:00
if err := c.Quit(); err != nil {
t.Fatal(err)
}
2019-04-10 20:20:50 +02:00
// Wait for the connection to close
mock.Wait()
}
2019-04-10 20:20:50 +02:00
// func TestFileDeleteDirRecur(t *testing.T) {
// mock, c := openConn(t, "127.0.0.1")
2019-04-10 20:20:50 +02:00
// err := c.RemoveDirRecur("testFile")
// if err == nil {
// t.Fatal("expected error got nil")
// }
2019-04-10 20:20:50 +02:00
// if err := c.Quit(); err != nil {
// t.Fatal(err)
// }
2019-04-10 20:20:50 +02:00
// // Wait for the connection to close
// mock.Wait()
// }
func TestMissingFolderDeleteDirRecur(t *testing.T) {
2019-04-10 20:20:50 +02:00
mock, c := openConn(t, "127.0.0.1")
2019-04-10 20:20:50 +02:00
err := c.RemoveDirRecur("missing-dir")
if err == nil {
2019-04-10 20:20:50 +02:00
t.Fatal("expected error got nil")
}
2019-04-10 20:20:50 +02:00
if err := c.Quit(); err != nil {
t.Fatal(err)
}
2019-04-10 20:20:50 +02:00
// Wait for the connection to close
mock.Wait()
}
func TestListCurrentDir(t *testing.T) {
mock, c := openConn(t, "127.0.0.1")
_, err := c.List("")
assert.NoError(t, err)
assert.Equal(t, "LIST", mock.lastFull, "LIST must not have a trailing whitespace")
_, err = c.NameList("")
assert.NoError(t, err)
assert.Equal(t, "NLST", mock.lastFull, "NLST must not have a trailing whitespace")
err = c.Quit()
assert.NoError(t, err)
mock.Wait()
}
func TestTimeUnsupported(t *testing.T) {
mock, c := openConnExt(t, "127.0.0.1", "no-time")
assert.False(t, c.mdtmSupported, "MDTM must NOT be supported")
assert.False(t, c.mfmtSupported, "MFMT must NOT be supported")
assert.False(t, c.IsGetTimeSupported(), "GetTime must NOT be supported")
assert.False(t, c.IsSetTimeSupported(), "SetTime must NOT be supported")
_, err := c.GetTime("file1")
assert.NotNil(t, err)
err = c.SetTime("file1", time.Now())
assert.NotNil(t, err)
assert.NoError(t, c.Quit())
mock.Wait()
}
func TestTimeStandard(t *testing.T) {
mock, c := openConnExt(t, "127.0.0.1", "std-time")
assert.True(t, c.mdtmSupported, "MDTM must be supported")
assert.True(t, c.mfmtSupported, "MFMT must be supported")
assert.True(t, c.IsGetTimeSupported(), "GetTime must be supported")
assert.True(t, c.IsSetTimeSupported(), "SetTime must be supported")
tm, err := c.GetTime("file1")
assert.NoError(t, err)
assert.False(t, tm.IsZero(), "GetTime must return valid time")
err = c.SetTime("file1", time.Now())
assert.NoError(t, err)
assert.NoError(t, c.Quit())
mock.Wait()
}
func TestTimeVsftpdPartial(t *testing.T) {
mock, c := openConnExt(t, "127.0.0.1", "vsftpd")
assert.True(t, c.mdtmSupported, "MDTM must be supported")
assert.False(t, c.mfmtSupported, "MFMT must NOT be supported")
assert.True(t, c.IsGetTimeSupported(), "GetTime must be supported")
assert.False(t, c.IsSetTimeSupported(), "SetTime must NOT be supported")
tm, err := c.GetTime("file1")
assert.NoError(t, err)
assert.False(t, tm.IsZero(), "GetTime must return valid time")
err = c.SetTime("file1", time.Now())
assert.NotNil(t, err)
assert.NoError(t, c.Quit())
mock.Wait()
}
func TestTimeVsftpdFull(t *testing.T) {
mock, c := openConnExt(t, "127.0.0.1", "vsftpd", DialWithWritingMDTM(true))
assert.True(t, c.mdtmSupported, "MDTM must be supported")
assert.False(t, c.mfmtSupported, "MFMT must NOT be supported")
assert.True(t, c.IsGetTimeSupported(), "GetTime must be supported")
assert.True(t, c.IsSetTimeSupported(), "SetTime must be supported")
tm, err := c.GetTime("file1")
assert.NoError(t, err)
assert.False(t, tm.IsZero(), "GetTime must return valid time")
err = c.SetTime("file1", time.Now())
assert.NoError(t, err)
assert.NoError(t, c.Quit())
mock.Wait()
}