- Introduce new Tai SDK tests in the GitHub workflows, requiring a Tai container with Docker socket mount for execution. - Update the Makefile to include a dedicated target for running Tai SDK tests, enhancing test coverage for the Tai integration. - Modify the Go module dependencies to include the pierrec/lz4 package, ensuring compatibility with the new tests. - Adjust test folder selection logic in the Makefile to exclude additional directories, streamlining the testing process.
696 lines
17 KiB
Go
696 lines
17 KiB
Go
package volume
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"net"
|
|
"os"
|
|
"testing"
|
|
|
|
pb "github.com/yaoapp/yao/tai/volume/pb"
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/grpc/credentials/insecure"
|
|
)
|
|
|
|
type mockVolumeServer struct {
|
|
pb.UnimplementedVolumeServer
|
|
statErr error
|
|
removeOK bool
|
|
removeError string
|
|
renameOK bool
|
|
renameError string
|
|
mkdirOK bool
|
|
mkdirError string
|
|
}
|
|
|
|
func (m *mockVolumeServer) Stat(_ context.Context, req *pb.FSRequest) (*pb.FileInfo, error) {
|
|
if m.statErr != nil {
|
|
return nil, m.statErr
|
|
}
|
|
return &pb.FileInfo{Path: req.Path, Size: 42, IsDir: false}, nil
|
|
}
|
|
|
|
func (m *mockVolumeServer) Remove(_ context.Context, req *pb.FSRemoveRequest) (*pb.FSOpResponse, error) {
|
|
return &pb.FSOpResponse{Ok: m.removeOK, Error: m.removeError}, nil
|
|
}
|
|
|
|
func (m *mockVolumeServer) Rename(_ context.Context, req *pb.FSRenameRequest) (*pb.FSOpResponse, error) {
|
|
return &pb.FSOpResponse{Ok: m.renameOK, Error: m.renameError}, nil
|
|
}
|
|
|
|
func (m *mockVolumeServer) MkdirAll(_ context.Context, req *pb.FSRequest) (*pb.FSOpResponse, error) {
|
|
return &pb.FSOpResponse{Ok: m.mkdirOK, Error: m.mkdirError}, nil
|
|
}
|
|
|
|
func (m *mockVolumeServer) ReadFile(req *pb.FSReadRequest, stream grpc.ServerStreamingServer[pb.FSDataChunk]) error {
|
|
return fmt.Errorf("file not found: %s", req.Path)
|
|
}
|
|
|
|
func (m *mockVolumeServer) WriteFile(stream grpc.ClientStreamingServer[pb.FSWriteChunk, pb.FSWriteResponse]) error {
|
|
for {
|
|
_, err := stream.Recv()
|
|
if err == io.EOF {
|
|
return stream.SendAndClose(&pb.FSWriteResponse{Size: 0})
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
func (m *mockVolumeServer) SyncPush(stream grpc.BidiStreamingServer[pb.SyncMessage, pb.SyncMessage]) error {
|
|
// Receive manifest
|
|
msg, err := stream.Recv()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
manifest := msg.GetManifest()
|
|
if manifest == nil {
|
|
return fmt.Errorf("expected manifest")
|
|
}
|
|
|
|
// Respond with diff: request all files + a ghost delete
|
|
var needFiles []string
|
|
for _, f := range manifest.Files {
|
|
if !f.IsDir {
|
|
needFiles = append(needFiles, f.Path)
|
|
}
|
|
}
|
|
if err := stream.Send(&pb.SyncMessage{
|
|
Payload: &pb.SyncMessage_Diff{
|
|
Diff: &pb.SyncDiff{
|
|
NeedFiles: needFiles,
|
|
DeleteFiles: []string{"old-deleted.txt"},
|
|
},
|
|
},
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Receive file chunks until CloseSend
|
|
var synced int32
|
|
var transferred int64
|
|
for {
|
|
msg, err := stream.Recv()
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if chunk := msg.GetChunk(); chunk != nil && chunk.Eof {
|
|
synced++
|
|
transferred += int64(len(chunk.Data))
|
|
}
|
|
}
|
|
|
|
// Send result
|
|
return stream.Send(&pb.SyncMessage{
|
|
Payload: &pb.SyncMessage_Result{
|
|
Result: &pb.SyncResult{
|
|
FilesSynced: synced,
|
|
BytesTransferred: transferred,
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func (m *mockVolumeServer) SyncPull(req *pb.SyncManifest, stream grpc.ServerStreamingServer[pb.SyncMessage]) error {
|
|
// Send MKDIR
|
|
if err := stream.Send(&pb.SyncMessage{
|
|
Payload: &pb.SyncMessage_Chunk{
|
|
Chunk: &pb.FileChunk{Path: "newdir", Type: pb.FileChunk_MKDIR},
|
|
},
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Send DELETE
|
|
if err := stream.Send(&pb.SyncMessage{
|
|
Payload: &pb.SyncMessage_Chunk{
|
|
Chunk: &pb.FileChunk{Path: "old-file.txt", Type: pb.FileChunk_DELETE},
|
|
},
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Send a file (FULL, multi-chunk)
|
|
data := []byte("mock pull content")
|
|
compressed, err := compress(data)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
half := len(compressed) / 2
|
|
if err := stream.Send(&pb.SyncMessage{
|
|
Payload: &pb.SyncMessage_Chunk{
|
|
Chunk: &pb.FileChunk{
|
|
Path: "pulled.txt",
|
|
Type: pb.FileChunk_FULL,
|
|
Data: compressed[:half],
|
|
Eof: false,
|
|
Mode: 0o644,
|
|
Mtime: 1234567890000000000,
|
|
},
|
|
},
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := stream.Send(&pb.SyncMessage{
|
|
Payload: &pb.SyncMessage_Chunk{
|
|
Chunk: &pb.FileChunk{
|
|
Path: "pulled.txt",
|
|
Type: pb.FileChunk_FULL,
|
|
Data: compressed[half:],
|
|
Eof: true,
|
|
},
|
|
},
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Send a file with no mode (tests default 0o644)
|
|
data2 := []byte("no mode")
|
|
c2, _ := compress(data2)
|
|
if err := stream.Send(&pb.SyncMessage{
|
|
Payload: &pb.SyncMessage_Chunk{
|
|
Chunk: &pb.FileChunk{
|
|
Path: "nomode.txt",
|
|
Type: pb.FileChunk_FULL,
|
|
Data: c2,
|
|
Eof: true,
|
|
},
|
|
},
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (m *mockVolumeServer) ListDir(_ context.Context, req *pb.FSRequest) (*pb.FSListResponse, error) {
|
|
return &pb.FSListResponse{Entries: []*pb.FileInfo{
|
|
{Path: "a.txt", Size: 10},
|
|
{Path: "b.txt", Size: 20, IsDir: true},
|
|
}}, nil
|
|
}
|
|
|
|
func startMockServer(t *testing.T, mock *mockVolumeServer) (*grpc.ClientConn, func()) {
|
|
t.Helper()
|
|
lis, err := net.Listen("tcp", "127.0.0.1:0")
|
|
if err != nil {
|
|
t.Fatalf("listen: %v", err)
|
|
}
|
|
srv := grpc.NewServer()
|
|
pb.RegisterVolumeServer(srv, mock)
|
|
|
|
go func() { _ = srv.Serve(lis) }()
|
|
|
|
conn, err := grpc.NewClient(lis.Addr().String(),
|
|
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
|
)
|
|
if err != nil {
|
|
srv.Stop()
|
|
t.Fatalf("dial: %v", err)
|
|
}
|
|
|
|
return conn, func() {
|
|
conn.Close()
|
|
srv.Stop()
|
|
}
|
|
}
|
|
|
|
func TestMockRemoteStat(t *testing.T) {
|
|
conn, cleanup := startMockServer(t, &mockVolumeServer{})
|
|
defer cleanup()
|
|
|
|
vol := NewRemote(conn)
|
|
info, err := vol.Stat(context.Background(), "s1", "test.txt")
|
|
if err != nil {
|
|
t.Fatalf("Stat: %v", err)
|
|
}
|
|
if info.Size != 42 {
|
|
t.Errorf("size = %d, want 42", info.Size)
|
|
}
|
|
}
|
|
|
|
func TestMockRemoteStatError(t *testing.T) {
|
|
conn, cleanup := startMockServer(t, &mockVolumeServer{statErr: fmt.Errorf("boom")})
|
|
defer cleanup()
|
|
|
|
vol := NewRemote(conn)
|
|
_, err := vol.Stat(context.Background(), "s1", "test.txt")
|
|
if err == nil {
|
|
t.Error("expected error")
|
|
}
|
|
}
|
|
|
|
func TestMockRemoteRemoveFail(t *testing.T) {
|
|
conn, cleanup := startMockServer(t, &mockVolumeServer{removeOK: false, removeError: "no such file"})
|
|
defer cleanup()
|
|
|
|
vol := NewRemote(conn)
|
|
err := vol.Remove(context.Background(), "s1", "bad.txt", false)
|
|
if err == nil {
|
|
t.Error("expected error")
|
|
}
|
|
}
|
|
|
|
func TestMockRemoteRemoveOK(t *testing.T) {
|
|
conn, cleanup := startMockServer(t, &mockVolumeServer{removeOK: true})
|
|
defer cleanup()
|
|
|
|
vol := NewRemote(conn)
|
|
err := vol.Remove(context.Background(), "s1", "good.txt", false)
|
|
if err != nil {
|
|
t.Errorf("Remove: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestMockRemoteRenameFail(t *testing.T) {
|
|
conn, cleanup := startMockServer(t, &mockVolumeServer{renameOK: false, renameError: "bad"})
|
|
defer cleanup()
|
|
|
|
vol := NewRemote(conn)
|
|
err := vol.Rename(context.Background(), "s1", "a", "b")
|
|
if err == nil {
|
|
t.Error("expected error")
|
|
}
|
|
}
|
|
|
|
func TestMockRemoteRenameOK(t *testing.T) {
|
|
conn, cleanup := startMockServer(t, &mockVolumeServer{renameOK: true})
|
|
defer cleanup()
|
|
|
|
vol := NewRemote(conn)
|
|
err := vol.Rename(context.Background(), "s1", "a", "b")
|
|
if err != nil {
|
|
t.Errorf("Rename: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestMockRemoteMkdirFail(t *testing.T) {
|
|
conn, cleanup := startMockServer(t, &mockVolumeServer{mkdirOK: false, mkdirError: "perm denied"})
|
|
defer cleanup()
|
|
|
|
vol := NewRemote(conn)
|
|
err := vol.MkdirAll(context.Background(), "s1", "dir")
|
|
if err == nil {
|
|
t.Error("expected error")
|
|
}
|
|
}
|
|
|
|
func TestMockRemoteMkdirOK(t *testing.T) {
|
|
conn, cleanup := startMockServer(t, &mockVolumeServer{mkdirOK: true})
|
|
defer cleanup()
|
|
|
|
vol := NewRemote(conn)
|
|
err := vol.MkdirAll(context.Background(), "s1", "dir")
|
|
if err != nil {
|
|
t.Errorf("MkdirAll: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestMockRemoteReadFileError(t *testing.T) {
|
|
conn, cleanup := startMockServer(t, &mockVolumeServer{})
|
|
defer cleanup()
|
|
|
|
vol := NewRemote(conn)
|
|
_, _, err := vol.ReadFile(context.Background(), "s1", "missing.txt")
|
|
if err == nil {
|
|
t.Error("expected error")
|
|
}
|
|
}
|
|
|
|
func TestMockRemoteWriteFile(t *testing.T) {
|
|
conn, cleanup := startMockServer(t, &mockVolumeServer{})
|
|
defer cleanup()
|
|
|
|
vol := NewRemote(conn)
|
|
err := vol.WriteFile(context.Background(), "s1", "test.txt", []byte("hello"), 0o644)
|
|
if err != nil {
|
|
t.Errorf("WriteFile: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestMockRemoteWriteFileLarge(t *testing.T) {
|
|
conn, cleanup := startMockServer(t, &mockVolumeServer{})
|
|
defer cleanup()
|
|
|
|
vol := NewRemote(conn)
|
|
data := make([]byte, 200*1024)
|
|
for i := range data {
|
|
data[i] = byte(i % 256)
|
|
}
|
|
err := vol.WriteFile(context.Background(), "s1", "large.bin", data, 0o644)
|
|
if err != nil {
|
|
t.Errorf("WriteFile large: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestMockRemoteWriteFileEmpty(t *testing.T) {
|
|
conn, cleanup := startMockServer(t, &mockVolumeServer{})
|
|
defer cleanup()
|
|
|
|
vol := NewRemote(conn)
|
|
err := vol.WriteFile(context.Background(), "s1", "empty.txt", []byte{}, 0o644)
|
|
if err != nil {
|
|
t.Errorf("WriteFile empty: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestMockRemoteListDir(t *testing.T) {
|
|
conn, cleanup := startMockServer(t, &mockVolumeServer{})
|
|
defer cleanup()
|
|
|
|
vol := NewRemote(conn)
|
|
entries, err := vol.ListDir(context.Background(), "s1", ".")
|
|
if err != nil {
|
|
t.Fatalf("ListDir: %v", err)
|
|
}
|
|
if len(entries) != 2 {
|
|
t.Errorf("entries = %d, want 2", len(entries))
|
|
}
|
|
}
|
|
|
|
func TestMockRemoteClose(t *testing.T) {
|
|
conn, cleanup := startMockServer(t, &mockVolumeServer{})
|
|
defer cleanup()
|
|
|
|
vol := NewRemote(conn)
|
|
if err := vol.Close(); err != nil {
|
|
t.Errorf("Close: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestMockRemoteSyncPush(t *testing.T) {
|
|
conn, cleanup := startMockServer(t, &mockVolumeServer{})
|
|
defer cleanup()
|
|
|
|
vol := NewRemote(conn)
|
|
srcDir := t.TempDir()
|
|
_ = os.WriteFile(srcDir+"/a.txt", []byte("aaa"), 0o644)
|
|
_ = os.Mkdir(srcDir+"/sub", 0o755)
|
|
_ = os.WriteFile(srcDir+"/sub/b.txt", []byte("bbb"), 0o644)
|
|
|
|
result, err := vol.SyncPush(context.Background(), "s1", srcDir)
|
|
if err != nil {
|
|
t.Fatalf("SyncPush: %v", err)
|
|
}
|
|
if result.FilesSynced < 1 {
|
|
t.Errorf("synced = %d", result.FilesSynced)
|
|
}
|
|
}
|
|
|
|
func TestMockRemoteSyncPushWithExcludes(t *testing.T) {
|
|
conn, cleanup := startMockServer(t, &mockVolumeServer{})
|
|
defer cleanup()
|
|
|
|
vol := NewRemote(conn)
|
|
srcDir := t.TempDir()
|
|
_ = os.WriteFile(srcDir+"/keep.txt", []byte("keep"), 0o644)
|
|
_ = os.WriteFile(srcDir+"/skip.log", []byte("skip"), 0o644)
|
|
|
|
result, err := vol.SyncPush(context.Background(), "s1", srcDir, WithExcludes("*.log"))
|
|
if err != nil {
|
|
t.Fatalf("SyncPush: %v", err)
|
|
}
|
|
if result.FilesSynced != 1 {
|
|
t.Errorf("synced = %d, want 1", result.FilesSynced)
|
|
}
|
|
}
|
|
|
|
func TestMockRemoteSyncPushForceFull(t *testing.T) {
|
|
conn, cleanup := startMockServer(t, &mockVolumeServer{})
|
|
defer cleanup()
|
|
|
|
vol := NewRemote(conn)
|
|
srcDir := t.TempDir()
|
|
_ = os.WriteFile(srcDir+"/a.txt", []byte("aaa"), 0o644)
|
|
|
|
result, err := vol.SyncPush(context.Background(), "s1", srcDir, WithForceFull())
|
|
if err != nil {
|
|
t.Fatalf("SyncPush: %v", err)
|
|
}
|
|
if result.FilesSynced < 1 {
|
|
t.Errorf("synced = %d", result.FilesSynced)
|
|
}
|
|
}
|
|
|
|
func TestMockRemoteSyncPull(t *testing.T) {
|
|
conn, cleanup := startMockServer(t, &mockVolumeServer{})
|
|
defer cleanup()
|
|
|
|
vol := NewRemote(conn)
|
|
dstDir := t.TempDir()
|
|
|
|
// Create a file that the mock will ask to DELETE
|
|
_ = os.WriteFile(dstDir+"/old-file.txt", []byte("old"), 0o644)
|
|
|
|
result, err := vol.SyncPull(context.Background(), "s1", dstDir)
|
|
if err != nil {
|
|
t.Fatalf("SyncPull: %v", err)
|
|
}
|
|
if result.FilesSynced < 1 {
|
|
t.Errorf("synced = %d", result.FilesSynced)
|
|
}
|
|
|
|
// Verify pulled file
|
|
data, err := os.ReadFile(dstDir + "/pulled.txt")
|
|
if err != nil {
|
|
t.Fatalf("ReadFile: %v", err)
|
|
}
|
|
if string(data) != "mock pull content" {
|
|
t.Errorf("content = %q", data)
|
|
}
|
|
|
|
// Verify MKDIR was created
|
|
info, err := os.Stat(dstDir + "/newdir")
|
|
if err != nil {
|
|
t.Fatalf("MKDIR dir: %v", err)
|
|
}
|
|
if !info.IsDir() {
|
|
t.Error("expected dir")
|
|
}
|
|
|
|
// Verify DELETE removed the file
|
|
if _, err := os.Stat(dstDir + "/old-file.txt"); err == nil {
|
|
t.Error("DELETE file should be removed")
|
|
}
|
|
|
|
// Verify nomode.txt was created
|
|
data, err = os.ReadFile(dstDir + "/nomode.txt")
|
|
if err != nil {
|
|
t.Fatalf("ReadFile nomode: %v", err)
|
|
}
|
|
if string(data) != "no mode" {
|
|
t.Errorf("nomode content = %q", data)
|
|
}
|
|
}
|
|
|
|
func TestMockRemoteSyncPullWithLocalFiles(t *testing.T) {
|
|
conn, cleanup := startMockServer(t, &mockVolumeServer{})
|
|
defer cleanup()
|
|
|
|
vol := NewRemote(conn)
|
|
dstDir := t.TempDir()
|
|
_ = os.WriteFile(dstDir+"/existing.txt", []byte("exist"), 0o644)
|
|
|
|
result, err := vol.SyncPull(context.Background(), "s1", dstDir)
|
|
if err != nil {
|
|
t.Fatalf("SyncPull: %v", err)
|
|
}
|
|
if result.FilesSynced < 1 {
|
|
t.Errorf("synced = %d", result.FilesSynced)
|
|
}
|
|
}
|
|
|
|
// errMockVolumeServer returns errors mid-stream for error-path testing.
|
|
type errMockVolumeServer struct {
|
|
pb.UnimplementedVolumeServer
|
|
}
|
|
|
|
func (m *errMockVolumeServer) SyncPush(stream grpc.BidiStreamingServer[pb.SyncMessage, pb.SyncMessage]) error {
|
|
_, _ = stream.Recv()
|
|
return fmt.Errorf("injected push error")
|
|
}
|
|
|
|
func (m *errMockVolumeServer) SyncPull(_ *pb.SyncManifest, stream grpc.ServerStreamingServer[pb.SyncMessage]) error {
|
|
return fmt.Errorf("injected pull error")
|
|
}
|
|
|
|
func (m *errMockVolumeServer) ReadFile(_ *pb.FSReadRequest, _ grpc.ServerStreamingServer[pb.FSDataChunk]) error {
|
|
return fmt.Errorf("injected read error")
|
|
}
|
|
|
|
func (m *errMockVolumeServer) WriteFile(stream grpc.ClientStreamingServer[pb.FSWriteChunk, pb.FSWriteResponse]) error {
|
|
return fmt.Errorf("injected write error")
|
|
}
|
|
|
|
func (m *errMockVolumeServer) Stat(_ context.Context, _ *pb.FSRequest) (*pb.FileInfo, error) {
|
|
return nil, fmt.Errorf("injected stat error")
|
|
}
|
|
|
|
func (m *errMockVolumeServer) ListDir(_ context.Context, _ *pb.FSRequest) (*pb.FSListResponse, error) {
|
|
return nil, fmt.Errorf("injected listdir error")
|
|
}
|
|
|
|
func (m *errMockVolumeServer) Remove(_ context.Context, _ *pb.FSRemoveRequest) (*pb.FSOpResponse, error) {
|
|
return nil, fmt.Errorf("injected remove error")
|
|
}
|
|
|
|
func (m *errMockVolumeServer) Rename(_ context.Context, _ *pb.FSRenameRequest) (*pb.FSOpResponse, error) {
|
|
return nil, fmt.Errorf("injected rename error")
|
|
}
|
|
|
|
func (m *errMockVolumeServer) MkdirAll(_ context.Context, _ *pb.FSRequest) (*pb.FSOpResponse, error) {
|
|
return nil, fmt.Errorf("injected mkdir error")
|
|
}
|
|
|
|
func startErrMockServer(t *testing.T) (*grpc.ClientConn, func()) {
|
|
t.Helper()
|
|
lis, err := net.Listen("tcp", "127.0.0.1:0")
|
|
if err != nil {
|
|
t.Fatalf("listen: %v", err)
|
|
}
|
|
srv := grpc.NewServer()
|
|
pb.RegisterVolumeServer(srv, &errMockVolumeServer{})
|
|
go func() { _ = srv.Serve(lis) }()
|
|
|
|
conn, err := grpc.NewClient(lis.Addr().String(),
|
|
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
|
)
|
|
if err != nil {
|
|
srv.Stop()
|
|
t.Fatalf("dial: %v", err)
|
|
}
|
|
return conn, func() { conn.Close(); srv.Stop() }
|
|
}
|
|
|
|
func TestErrRemoteSyncPush(t *testing.T) {
|
|
conn, cleanup := startErrMockServer(t)
|
|
defer cleanup()
|
|
|
|
vol := NewRemote(conn)
|
|
srcDir := t.TempDir()
|
|
_ = os.WriteFile(srcDir+"/a.txt", []byte("aaa"), 0o644)
|
|
|
|
_, err := vol.SyncPush(context.Background(), "s1", srcDir)
|
|
if err == nil {
|
|
t.Error("expected error")
|
|
}
|
|
}
|
|
|
|
func TestErrRemoteSyncPull(t *testing.T) {
|
|
conn, cleanup := startErrMockServer(t)
|
|
defer cleanup()
|
|
|
|
vol := NewRemote(conn)
|
|
dstDir := t.TempDir()
|
|
|
|
_, err := vol.SyncPull(context.Background(), "s1", dstDir)
|
|
if err == nil {
|
|
t.Error("expected error")
|
|
}
|
|
}
|
|
|
|
func TestErrRemoteWriteFile(t *testing.T) {
|
|
conn, cleanup := startErrMockServer(t)
|
|
defer cleanup()
|
|
|
|
vol := NewRemote(conn)
|
|
err := vol.WriteFile(context.Background(), "s1", "test.txt", []byte("x"), 0o644)
|
|
if err == nil {
|
|
t.Error("expected error")
|
|
}
|
|
}
|
|
|
|
func TestErrRemoteReadFile(t *testing.T) {
|
|
conn, cleanup := startErrMockServer(t)
|
|
defer cleanup()
|
|
|
|
vol := NewRemote(conn)
|
|
_, _, err := vol.ReadFile(context.Background(), "s1", "test.txt")
|
|
if err == nil {
|
|
t.Error("expected error")
|
|
}
|
|
}
|
|
|
|
func TestErrRemoteStat(t *testing.T) {
|
|
conn, cleanup := startErrMockServer(t)
|
|
defer cleanup()
|
|
|
|
vol := NewRemote(conn)
|
|
_, err := vol.Stat(context.Background(), "s1", "test.txt")
|
|
if err == nil {
|
|
t.Error("expected error")
|
|
}
|
|
}
|
|
|
|
func TestErrRemoteListDir(t *testing.T) {
|
|
conn, cleanup := startErrMockServer(t)
|
|
defer cleanup()
|
|
|
|
vol := NewRemote(conn)
|
|
_, err := vol.ListDir(context.Background(), "s1", ".")
|
|
if err == nil {
|
|
t.Error("expected error")
|
|
}
|
|
}
|
|
|
|
func TestErrRemoteRemove(t *testing.T) {
|
|
conn, cleanup := startErrMockServer(t)
|
|
defer cleanup()
|
|
|
|
vol := NewRemote(conn)
|
|
err := vol.Remove(context.Background(), "s1", "test.txt", false)
|
|
if err == nil {
|
|
t.Error("expected error")
|
|
}
|
|
}
|
|
|
|
func TestErrRemoteRename(t *testing.T) {
|
|
conn, cleanup := startErrMockServer(t)
|
|
defer cleanup()
|
|
|
|
vol := NewRemote(conn)
|
|
err := vol.Rename(context.Background(), "s1", "a", "b")
|
|
if err == nil {
|
|
t.Error("expected error")
|
|
}
|
|
}
|
|
|
|
func TestErrRemoteMkdirAll(t *testing.T) {
|
|
conn, cleanup := startErrMockServer(t)
|
|
defer cleanup()
|
|
|
|
vol := NewRemote(conn)
|
|
err := vol.MkdirAll(context.Background(), "s1", "dir")
|
|
if err == nil {
|
|
t.Error("expected error")
|
|
}
|
|
}
|
|
|
|
func TestPbToFileInfo(t *testing.T) {
|
|
fi := pbToFileInfo(&pb.FileInfo{
|
|
Path: "test.txt",
|
|
Size: 100,
|
|
Mtime: 1234567890000000000,
|
|
Mode: 0o644,
|
|
IsDir: false,
|
|
})
|
|
if fi.Path != "test.txt" {
|
|
t.Errorf("path = %q", fi.Path)
|
|
}
|
|
if fi.Size != 100 {
|
|
t.Errorf("size = %d", fi.Size)
|
|
}
|
|
if fi.IsDir {
|
|
t.Error("expected not dir")
|
|
}
|
|
if fi.Mode != os.FileMode(0o644) {
|
|
t.Errorf("mode = %v", fi.Mode)
|
|
}
|
|
}
|