diff --git a/grpc_test.go b/grpc_test.go new file mode 100644 index 0000000..c477c7f --- /dev/null +++ b/grpc_test.go @@ -0,0 +1,204 @@ +package agate + +import ( + "context" + "os" + "path/filepath" + "testing" + "time" + + "gitea.unprism.ru/KRBL/Agate/remote" + "gitea.unprism.ru/KRBL/Agate/store" +) + +// TestGRPCServerClient tests the interaction between a gRPC server and client. +// It creates multiple snapshots with different content on the server, +// connects a client to the server, downloads the latest snapshot, +// and verifies the contents of the files. +func TestGRPCServerClient(t *testing.T) { + // Skip this test in short mode + if testing.Short() { + t.Skip("Skipping gRPC server-client test in short mode") + } + + // Create a temporary directory for the server + serverDir, err := os.MkdirTemp("", "agate-server-*") + if err != nil { + t.Fatalf("Failed to create server temp directory: %v", err) + } + defer os.RemoveAll(serverDir) + + // Create a temporary directory for the client + clientDir, err := os.MkdirTemp("", "agate-client-*") + if err != nil { + t.Fatalf("Failed to create client temp directory: %v", err) + } + defer os.RemoveAll(clientDir) + + // Create Agate options for the server + serverOptions := AgateOptions{ + WorkDir: serverDir, + } + + // Create Agate instance for the server + serverAgate, err := New(serverOptions) + if err != nil { + t.Fatalf("Failed to create server Agate instance: %v", err) + } + defer serverAgate.Close() + + // Create a data directory + dataDir := serverAgate.options.BlobStore.GetActiveDir() + if err := os.MkdirAll(dataDir, 0755); err != nil { + t.Fatalf("Failed to create data directory: %v", err) + } + + // Create initial test files for the first snapshot + initialFiles := map[string]string{ + filepath.Join(dataDir, "file1.txt"): "Initial content of file 1", + filepath.Join(dataDir, "file2.txt"): "Initial content of file 2", + filepath.Join(dataDir, "subdir", "file3.txt"): "Initial content of file 3", + } + + // Create subdirectory + if err := os.MkdirAll(filepath.Join(dataDir, "subdir"), 0755); err != nil { + t.Fatalf("Failed to create subdirectory: %v", err) + } + + // Create the files + for path, content := range initialFiles { + if err := os.WriteFile(path, []byte(content), 0644); err != nil { + t.Fatalf("Failed to create test file %s: %v", path, err) + } + } + + // Create the first snapshot + ctx := context.Background() + snapshot1ID, err := serverAgate.SaveSnapshot(ctx, "Snapshot 1", "") + if err != nil { + t.Fatalf("Failed to create first snapshot: %v", err) + } + t.Logf("Created first snapshot with ID: %s", snapshot1ID) + + // Modify some files and add a new file for the second snapshot + modifiedFiles := map[string]string{ + filepath.Join(dataDir, "file1.txt"): "Modified content of file 1", + filepath.Join(dataDir, "file4.txt"): "Content of new file 4", + } + + for path, content := range modifiedFiles { + if err := os.WriteFile(path, []byte(content), 0644); err != nil { + t.Fatalf("Failed to modify/create test file %s: %v", path, err) + } + } + + // Create the second snapshot + snapshot2ID, err := serverAgate.SaveSnapshot(ctx, "Snapshot 2", snapshot1ID) + if err != nil { + t.Fatalf("Failed to create second snapshot: %v", err) + } + t.Logf("Created second snapshot with ID: %s", snapshot2ID) + + // Delete a file and modify another for the third snapshot + if err := os.Remove(filepath.Join(dataDir, "file2.txt")); err != nil { + t.Fatalf("Failed to delete test file: %v", err) + } + + if err := os.WriteFile(filepath.Join(dataDir, "subdir/file3.txt"), []byte("Modified content of file 3"), 0644); err != nil { + t.Fatalf("Failed to modify test file: %v", err) + } + + // Create the third snapshot + snapshot3ID, err := serverAgate.SaveSnapshot(ctx, "Snapshot 3", snapshot2ID) + if err != nil { + t.Fatalf("Failed to create third snapshot: %v", err) + } + t.Logf("Created third snapshot with ID: %s", snapshot3ID) + + // Start the gRPC server + serverAddress := "localhost:50051" + server, err := remote.RunServer(ctx, serverAgate.manager, serverAddress) + if err != nil { + t.Fatalf("Failed to start gRPC server: %v", err) + } + defer server.Stop(ctx) + + // Give the server a moment to start + time.Sleep(100 * time.Millisecond) + + // Connect a client to the server + client, err := remote.NewClient(serverAddress) + if err != nil { + t.Fatalf("Failed to connect client to server: %v", err) + } + defer client.Close() + + // List snapshots from the client + snapshots, err := client.ListSnapshots(ctx) + if err != nil { + t.Fatalf("Failed to list snapshots from client: %v", err) + } + + // Verify we have 3 snapshots + if len(snapshots) != 3 { + t.Errorf("Expected 3 snapshots, got %d", len(snapshots)) + } + + // Find the latest snapshot (should be snapshot3) + var latestSnapshot store.SnapshotInfo + for _, snapshot := range snapshots { + if latestSnapshot.CreationTime.Before(snapshot.CreationTime) { + latestSnapshot = snapshot + } + } + + // Verify the latest snapshot is snapshot3 + if latestSnapshot.ID != snapshot3ID { + t.Errorf("Latest snapshot ID is %s, expected %s", latestSnapshot.ID, snapshot3ID) + } + + // Get detailed information about the latest snapshot + snapshotDetails, err := client.FetchSnapshotDetails(ctx, latestSnapshot.ID) + if err != nil { + t.Fatalf("Failed to fetch snapshot details: %v", err) + } + + // Verify the snapshot details + if snapshotDetails.ID != snapshot3ID { + t.Errorf("Snapshot details ID is %s, expected %s", snapshotDetails.ID, snapshot3ID) + } + + // Create a directory to download the snapshot to + downloadDir := filepath.Join(clientDir, "download") + if err := os.MkdirAll(downloadDir, 0755); err != nil { + t.Fatalf("Failed to create download directory: %v", err) + } + + // Download the snapshot + err = client.DownloadSnapshot(ctx, latestSnapshot.ID, downloadDir, "") + if err != nil { + t.Fatalf("Failed to download snapshot: %v", err) + } + + // Verify the downloaded files match the expected content + expectedFiles := map[string]string{ + filepath.Join(downloadDir, "file1.txt"): "Modified content of file 1", + filepath.Join(downloadDir, "file4.txt"): "Content of new file 4", + filepath.Join(downloadDir, "subdir/file3.txt"): "Modified content of file 3", + } + + for path, expectedContent := range expectedFiles { + content, err := os.ReadFile(path) + if err != nil { + t.Fatalf("Failed to read downloaded file %s: %v", path, err) + } + if string(content) != expectedContent { + t.Errorf("Downloaded file %s has wrong content: got %s, want %s", path, string(content), expectedContent) + } + } + + // Verify that file2.txt doesn't exist in the downloaded snapshot + if _, err := os.Stat(filepath.Join(downloadDir, "file2.txt")); !os.IsNotExist(err) { + t.Errorf("file2.txt should not exist in the downloaded snapshot") + } +}