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") } }