package shell import ( "bytes" "context" "fmt" "net" "os" "path/filepath" "testing" "github.com/seaweedfs/seaweedfs/weed/pb" "github.com/seaweedfs/seaweedfs/weed/pb/filer_pb" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/status" ) type fsMvTestFilerServer struct { filer_pb.UnimplementedSeaweedFilerServer lookupReq *filer_pb.LookupDirectoryEntryRequest renameReq *filer_pb.AtomicRenameEntryRequest } func (s *fsMvTestFilerServer) LookupDirectoryEntry(_ context.Context, req *filer_pb.LookupDirectoryEntryRequest) (*filer_pb.LookupDirectoryEntryResponse, error) { s.lookupReq = req if req.Directory == "/dst" && req.Name == "dir" { return &filer_pb.LookupDirectoryEntryResponse{ Entry: &filer_pb.Entry{ Name: "dir", IsDirectory: true, Attributes: &filer_pb.FuseAttributes{}, }, }, nil } return nil, status.Error(codes.NotFound, "not found") } func (s *fsMvTestFilerServer) AtomicRenameEntry(_ context.Context, req *filer_pb.AtomicRenameEntryRequest) (*filer_pb.AtomicRenameEntryResponse, error) { s.renameReq = req return &filer_pb.AtomicRenameEntryResponse{}, nil } func TestFsMvMovesIntoExistingDestinationDirectory(t *testing.T) { filerServer := &fsMvTestFilerServer{} commandEnv, cleanup := newFsMvTestCommandEnv(t, filerServer) defer cleanup() var output bytes.Buffer err := (&commandFsMv{}).Do([]string{"/src/file", "/dst/dir"}, commandEnv, &output) if err != nil { t.Fatalf("fs.mv returned error: %v", err) } if filerServer.lookupReq == nil { t.Fatal("expected fs.mv to look up destination entry") } if filerServer.lookupReq.Directory != "/dst" || filerServer.lookupReq.Name != "dir" { t.Fatalf("destination lookup = directory %q name %q, want /dst dir", filerServer.lookupReq.Directory, filerServer.lookupReq.Name) } if filerServer.renameReq == nil { t.Fatal("expected fs.mv to issue rename") } if filerServer.renameReq.NewDirectory != "/dst/dir" || filerServer.renameReq.NewName != "file" { t.Fatalf("rename target = directory %q name %q, want /dst/dir file", filerServer.renameReq.NewDirectory, filerServer.renameReq.NewName) } } func newFsMvTestCommandEnv(t *testing.T, filerServer filer_pb.SeaweedFilerServer) (*CommandEnv, func()) { t.Helper() socketDir, err := os.MkdirTemp("", "swmv-") if err != nil { t.Fatalf("create socket dir: %v", err) } t.Cleanup(func() { _ = os.RemoveAll(socketDir) }) socketPath := filepath.Join(socketDir, "filer.sock") listener, err := net.Listen("unix", socketPath) if err != nil { t.Fatalf("listen unix socket: %v", err) } grpcServer := grpc.NewServer() filer_pb.RegisterSeaweedFilerServer(grpcServer, filerServer) go func() { _ = grpcServer.Serve(listener) }() grpcPort := 47000 + os.Getpid()%1000 pb.RegisterLocalGrpcSocket("127.0.0.1", grpcPort, socketPath) cleanup := func() { grpcServer.Stop() _ = listener.Close() } return &CommandEnv{ option: &ShellOptions{ FilerAddress: pb.ServerAddress(fmt.Sprintf("127.0.0.1:8888.%d", grpcPort)), GrpcDialOption: grpc.WithTransportCredentials(insecure.NewCredentials()), Directory: "/", }, }, cleanup }