Commit 7c1b0842 authored by Bruce Flynn's avatar Bruce Flynn
Browse files

testing

parent d529dd6a
......@@ -10,6 +10,7 @@ import (
url_ "net/url"
"os"
"path/filepath"
"syscall"
"github.com/pkg/sftp"
"golang.org/x/crypto/ssh"
......@@ -38,7 +39,7 @@ type result struct {
type sftpClient interface {
Close() error
Create(string) (io.WriteCloser, error)
Getwd() (string, error)
Poke() bool
Open(string) (io.ReadCloser, error)
ReadDir(string) ([]os.FileInfo, error)
Remove(string) error
......@@ -72,8 +73,9 @@ func (c mySFTPClient) Create(path string) (io.WriteCloser, error) {
return sftpFile{f}, nil
}
func (c mySFTPClient) Getwd() (string, error) {
return c.SFTP.Getwd()
func (c mySFTPClient) Poke() bool {
_, err := c.SFTP.Getwd()
return err == nil
}
func (c mySFTPClient) Open(path string) (io.ReadCloser, error) {
......@@ -184,6 +186,7 @@ func textCommands(src io.Reader) <-chan command {
return ch
}
// generate a path on the remote
func (s sftpAPI) rempath(path string) string {
if !filepath.IsAbs(path) {
return filepath.Join(s.URL.Path, path)
......@@ -254,12 +257,18 @@ func (s sftpAPI) doListdir(path string) ([]stat, error) {
}
for _, st := range infos {
x := st.Sys().(*sftp.FileStat)
var m uint32
switch s := st.Sys().(type) {
case *sftp.FileStat:
m = s.Mode
case *syscall.Stat_t:
m = s.Mode
}
stats = append(stats, stat{
st.Name(),
st.Size(),
st.ModTime().Unix(),
int(x.Mode),
int(m),
})
}
......@@ -271,9 +280,10 @@ func (s sftpAPI) doDelete(path string) error {
return s.Client.Remove(s.rempath(path))
}
// make sure the client is connected by poking it
func (s *sftpAPI) ensureConnected() error {
if _, err := s.Client.Getwd(); err != nil {
debug("not connected, connecting: %s", err)
if !s.Client.Poke() {
debug("not connected, connecting")
return s.connect()
}
return nil
......
......@@ -3,13 +3,19 @@ package main
import (
"bytes"
"encoding/binary"
"io"
"io/ioutil"
"net/url"
"os"
"path/filepath"
"sort"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestBinaryCommands(t *testing.T) {
verbose = true
dat := make([]byte, 4)
binary.BigEndian.PutUint32(dat, 42)
......@@ -23,7 +29,6 @@ func TestBinaryCommands(t *testing.T) {
}
func TestTextCommands(t *testing.T) {
verbose = true
src := bytes.NewReader([]byte(`{"command": "PUT", "args": {"arg": "val"}}` + "\n"))
......@@ -32,3 +37,161 @@ func TestTextCommands(t *testing.T) {
assert.Equal(t, "PUT", cmd.Name)
assert.Equal(t, map[string]string{"arg": "val"}, cmd.Args)
}
/*
This is all fixture code for testing the API
There must be a less verbose way to do all this.
*/
type noOpCloseWriter struct {
w io.Writer
}
func (n noOpCloseWriter) Write(buf []byte) (int, error) {
return n.w.Write(buf)
}
func (n noOpCloseWriter) Close() error {
return nil
}
type stubClient struct {
putFile *bytes.Buffer
getFile io.ReadCloser
poke bool
workdir string
}
func (c stubClient) Cleanup() error {
return os.RemoveAll(c.workdir)
}
func (c stubClient) Close() error {
return nil
}
func (c stubClient) Create(path string) (io.WriteCloser, error) {
return noOpCloseWriter{c.putFile}, nil
}
func (c stubClient) Poke() bool {
return c.poke
}
func (c stubClient) Open(path string) (io.ReadCloser, error) {
return c.getFile, nil
}
func (c stubClient) ReadDir(p string) ([]os.FileInfo, error) {
f, err := os.Open(c.workdir)
if err != nil {
return []os.FileInfo{}, nil
}
return f.Readdir(-1)
}
func (c stubClient) Remove(fpath string) error {
return nil
}
func newStubAPI() (sftpAPI, error) {
req, resp, err := os.Pipe()
if err != nil {
return sftpAPI{}, nil
}
dir, err := tempDir()
r := bytes.NewReader([]byte("xyz"))
c := stubClient{
putFile: new(bytes.Buffer),
getFile: ioutil.NopCloser(r),
poke: true,
workdir: dir,
}
u, err := url.Parse("sftp://localhost")
if err != nil {
return sftpAPI{}, nil
}
return sftpAPI{
URL: u,
Client: c,
Req: req,
Resp: resp,
}, nil
}
func tempDir() (string, error) {
tmp := os.TempDir()
return ioutil.TempDir(tmp, "")
}
func TestAPIdoGet(t *testing.T) {
api, err := newStubAPI()
assert.Nil(t, err)
defer api.Client.(stubClient).Cleanup()
dest := filepath.Join(api.Client.(stubClient).workdir, "foo.dat")
err = api.doGet("ignored", dest)
assert.Nil(t, err)
dat, err := ioutil.ReadFile(dest)
assert.Nil(t, err)
assert.Equal(t, []byte("xyz"), dat)
}
func TestAPIdoPut(t *testing.T) {
api, err := newStubAPI()
assert.Nil(t, err)
defer api.Client.(stubClient).Cleanup()
// create file to put
dest := filepath.Join(api.Client.(stubClient).workdir, "foo.dat")
f, err := os.Create(dest)
assert.Nil(t, err)
_, err = f.Write([]byte("zyx"))
assert.Nil(t, err)
err = api.doPut(dest, "ignored")
assert.Nil(t, err)
assert.Nil(t, err)
assert.Equal(t, []byte("zyx"), api.Client.(stubClient).putFile.Bytes())
}
func TestAPIdoListdir(t *testing.T) {
api, err := newStubAPI()
assert.Nil(t, err)
defer api.Client.(stubClient).Cleanup()
// create file/dir to put
dir := api.Client.(stubClient).workdir
err = os.Mkdir(filepath.Join(dir, "00_dir"), 0755)
assert.Nil(t, err)
dest := filepath.Join(dir, "01_file")
f, err := os.Create(dest)
assert.Nil(t, err)
_, err = f.Write([]byte("zyx"))
assert.Nil(t, err)
matches, err := api.doListdir("ignored")
assert.Nil(t, err)
assert.Equal(t, 2, len(matches))
sort.Slice(matches, func(i, j int) bool {
return matches[i].Name < matches[j].Name
})
assert.Equal(t, "00_dir", matches[0].Name)
assert.Equal(t, 16877, matches[0].Mode)
// make sure the mtime is within 10s
assert.Greater(t, time.Now().Unix()+10, matches[0].MTime)
assert.Equal(t, "01_file", matches[1].Name)
assert.Equal(t, 33188, int(matches[1].Mode))
// make sure the mtime is within 10s
assert.Greater(t, time.Now().Unix()+10, matches[1].MTime)
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment