This commit introduces test cases for the API, archive, store, and filesystem functionalities, as well as a functional test for a full workflow. It ensures robust testing for snapshot operations, archiving, and blob management, significantly improving reliability.
354 lines
9.5 KiB
Go
354 lines
9.5 KiB
Go
package agate
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// BenchmarkCreateSnapshot benchmarks the performance of creating snapshots with different numbers of files
|
|
func BenchmarkCreateSnapshot(b *testing.B) {
|
|
// Skip in short mode
|
|
if testing.Short() {
|
|
b.Skip("Skipping benchmark in short mode")
|
|
}
|
|
|
|
// Test with different numbers of files
|
|
fileCounts := []int{10, 100, 1000}
|
|
for _, fileCount := range fileCounts {
|
|
b.Run(fmt.Sprintf("Files-%d", fileCount), func(b *testing.B) {
|
|
// Create a temporary directory for tests
|
|
tempDir, err := os.MkdirTemp("", "agate-bench-*")
|
|
if err != nil {
|
|
b.Fatalf("Failed to create temp directory: %v", err)
|
|
}
|
|
defer os.RemoveAll(tempDir)
|
|
|
|
// Create a data directory
|
|
dataDir := filepath.Join(tempDir, "data")
|
|
if err := os.MkdirAll(dataDir, 0755); err != nil {
|
|
b.Fatalf("Failed to create data directory: %v", err)
|
|
}
|
|
|
|
// Create test files
|
|
createBenchmarkFiles(b, dataDir, fileCount, 1024) // 1 KB per file
|
|
|
|
// Create Agate options
|
|
options := AgateOptions{
|
|
WorkDir: dataDir,
|
|
OpenFunc: func(dir string) error {
|
|
return nil
|
|
},
|
|
CloseFunc: func() error {
|
|
return nil
|
|
},
|
|
}
|
|
|
|
// Create Agate instance
|
|
ag, err := New(options)
|
|
if err != nil {
|
|
b.Fatalf("Failed to create Agate instance: %v", err)
|
|
}
|
|
defer ag.Close()
|
|
|
|
// Reset the timer before the benchmark loop
|
|
b.ResetTimer()
|
|
|
|
// Run the benchmark
|
|
for i := 0; i < b.N; i++ {
|
|
ctx := context.Background()
|
|
_, err := ag.SaveSnapshot(ctx, fmt.Sprintf("Benchmark Snapshot %d", i), "")
|
|
if err != nil {
|
|
b.Fatalf("Failed to create snapshot: %v", err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// BenchmarkRestoreSnapshot benchmarks the performance of restoring snapshots with different numbers of files
|
|
func BenchmarkRestoreSnapshot(b *testing.B) {
|
|
// Skip in short mode
|
|
if testing.Short() {
|
|
b.Skip("Skipping benchmark in short mode")
|
|
}
|
|
|
|
// Test with different numbers of files
|
|
fileCounts := []int{10, 100, 1000}
|
|
for _, fileCount := range fileCounts {
|
|
b.Run(fmt.Sprintf("Files-%d", fileCount), func(b *testing.B) {
|
|
// Create a temporary directory for tests
|
|
tempDir, err := os.MkdirTemp("", "agate-bench-*")
|
|
if err != nil {
|
|
b.Fatalf("Failed to create temp directory: %v", err)
|
|
}
|
|
defer os.RemoveAll(tempDir)
|
|
|
|
// Create a data directory
|
|
dataDir := filepath.Join(tempDir, "data")
|
|
if err := os.MkdirAll(dataDir, 0755); err != nil {
|
|
b.Fatalf("Failed to create data directory: %v", err)
|
|
}
|
|
|
|
// Create test files
|
|
createBenchmarkFiles(b, dataDir, fileCount, 1024) // 1 KB per file
|
|
|
|
// Create Agate options
|
|
options := AgateOptions{
|
|
WorkDir: dataDir,
|
|
OpenFunc: func(dir string) error {
|
|
return nil
|
|
},
|
|
CloseFunc: func() error {
|
|
return nil
|
|
},
|
|
}
|
|
|
|
// Create Agate instance
|
|
ag, err := New(options)
|
|
if err != nil {
|
|
b.Fatalf("Failed to create Agate instance: %v", err)
|
|
}
|
|
defer ag.Close()
|
|
|
|
// Create a snapshot
|
|
ctx := context.Background()
|
|
snapshotID, err := ag.SaveSnapshot(ctx, "Benchmark Snapshot", "")
|
|
if err != nil {
|
|
b.Fatalf("Failed to create snapshot: %v", err)
|
|
}
|
|
|
|
// Modify some files
|
|
for i := 0; i < fileCount/2; i++ {
|
|
filePath := filepath.Join(dataDir, fmt.Sprintf("file_%d.txt", i))
|
|
if err := os.WriteFile(filePath, []byte(fmt.Sprintf("Modified content %d", i)), 0644); err != nil {
|
|
b.Fatalf("Failed to modify file: %v", err)
|
|
}
|
|
}
|
|
|
|
// Reset the timer before the benchmark loop
|
|
b.ResetTimer()
|
|
|
|
// Run the benchmark
|
|
for i := 0; i < b.N; i++ {
|
|
err := ag.RestoreSnapshot(ctx, snapshotID)
|
|
if err != nil {
|
|
b.Fatalf("Failed to restore snapshot: %v", err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// BenchmarkLargeFiles benchmarks the performance of creating and restoring snapshots with large files
|
|
func BenchmarkLargeFiles(b *testing.B) {
|
|
// Skip in short mode
|
|
if testing.Short() {
|
|
b.Skip("Skipping benchmark in short mode")
|
|
}
|
|
|
|
// Test with different file sizes
|
|
fileSizes := []int{1 * 1024 * 1024, 10 * 1024 * 1024, 100 * 1024 * 1024} // 1 MB, 10 MB, 100 MB
|
|
for _, fileSize := range fileSizes {
|
|
b.Run(fmt.Sprintf("Size-%dMB", fileSize/(1024*1024)), func(b *testing.B) {
|
|
// Create a temporary directory for tests
|
|
tempDir, err := os.MkdirTemp("", "agate-bench-*")
|
|
if err != nil {
|
|
b.Fatalf("Failed to create temp directory: %v", err)
|
|
}
|
|
defer os.RemoveAll(tempDir)
|
|
|
|
// Create a data directory
|
|
dataDir := filepath.Join(tempDir, "data")
|
|
if err := os.MkdirAll(dataDir, 0755); err != nil {
|
|
b.Fatalf("Failed to create data directory: %v", err)
|
|
}
|
|
|
|
// Create a large file
|
|
largeFilePath := filepath.Join(dataDir, "large_file.bin")
|
|
createLargeFile(b, largeFilePath, fileSize)
|
|
|
|
// Create Agate options
|
|
options := AgateOptions{
|
|
WorkDir: dataDir,
|
|
OpenFunc: func(dir string) error {
|
|
return nil
|
|
},
|
|
CloseFunc: func() error {
|
|
return nil
|
|
},
|
|
}
|
|
|
|
// Create Agate instance
|
|
ag, err := New(options)
|
|
if err != nil {
|
|
b.Fatalf("Failed to create Agate instance: %v", err)
|
|
}
|
|
defer ag.Close()
|
|
|
|
// Create a snapshot
|
|
ctx := context.Background()
|
|
|
|
// Measure snapshot creation time
|
|
b.Run("Create", func(b *testing.B) {
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
_, err := ag.SaveSnapshot(ctx, fmt.Sprintf("Large File Snapshot %d", i), "")
|
|
if err != nil {
|
|
b.Fatalf("Failed to create snapshot: %v", err)
|
|
}
|
|
}
|
|
})
|
|
|
|
// Create a snapshot for restoration benchmark
|
|
snapshotID, err := ag.SaveSnapshot(ctx, "Large File Snapshot", "")
|
|
if err != nil {
|
|
b.Fatalf("Failed to create snapshot: %v", err)
|
|
}
|
|
|
|
// Modify the large file
|
|
if err := os.WriteFile(largeFilePath, []byte("Modified content"), 0644); err != nil {
|
|
b.Fatalf("Failed to modify large file: %v", err)
|
|
}
|
|
|
|
// Measure snapshot restoration time
|
|
b.Run("Restore", func(b *testing.B) {
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
err := ag.RestoreSnapshot(ctx, snapshotID)
|
|
if err != nil {
|
|
b.Fatalf("Failed to restore snapshot: %v", err)
|
|
}
|
|
}
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestPerformanceMetrics runs performance tests and reports metrics
|
|
func TestPerformanceMetrics(t *testing.T) {
|
|
// Skip in short mode
|
|
if testing.Short() {
|
|
t.Skip("Skipping performance metrics test in short mode")
|
|
}
|
|
|
|
// Create a temporary directory for tests
|
|
tempDir, err := os.MkdirTemp("", "agate-perf-*")
|
|
if err != nil {
|
|
t.Fatalf("Failed to create temp directory: %v", err)
|
|
}
|
|
defer os.RemoveAll(tempDir)
|
|
|
|
// Create a data directory
|
|
dataDir := filepath.Join(tempDir, "data")
|
|
if err := os.MkdirAll(dataDir, 0755); err != nil {
|
|
t.Fatalf("Failed to create data directory: %v", err)
|
|
}
|
|
|
|
// Test with different numbers of files
|
|
fileCounts := []int{10, 100, 1000}
|
|
for _, fileCount := range fileCounts {
|
|
t.Run(fmt.Sprintf("Files-%d", fileCount), func(t *testing.T) {
|
|
// Create test files
|
|
createBenchmarkFiles(t, dataDir, fileCount, 1024) // 1 KB per file
|
|
|
|
// Create Agate options
|
|
options := AgateOptions{
|
|
WorkDir: dataDir,
|
|
OpenFunc: func(dir string) error {
|
|
return nil
|
|
},
|
|
CloseFunc: func() error {
|
|
return nil
|
|
},
|
|
}
|
|
|
|
// Create Agate instance
|
|
ag, err := New(options)
|
|
if err != nil {
|
|
t.Fatalf("Failed to create Agate instance: %v", err)
|
|
}
|
|
defer ag.Close()
|
|
|
|
// Measure snapshot creation time
|
|
ctx := context.Background()
|
|
startTime := time.Now()
|
|
snapshotID, err := ag.SaveSnapshot(ctx, "Performance Test Snapshot", "")
|
|
if err != nil {
|
|
t.Fatalf("Failed to create snapshot: %v", err)
|
|
}
|
|
createDuration := time.Since(startTime)
|
|
t.Logf("Created snapshot with %d files in %v (%.2f files/sec)", fileCount, createDuration, float64(fileCount)/createDuration.Seconds())
|
|
|
|
// Modify some files
|
|
for i := 0; i < fileCount/2; i++ {
|
|
filePath := filepath.Join(dataDir, fmt.Sprintf("file_%d.txt", i))
|
|
if err := os.WriteFile(filePath, []byte(fmt.Sprintf("Modified content %d", i)), 0644); err != nil {
|
|
t.Fatalf("Failed to modify file: %v", err)
|
|
}
|
|
}
|
|
|
|
// Measure snapshot restoration time
|
|
startTime = time.Now()
|
|
err = ag.RestoreSnapshot(ctx, snapshotID)
|
|
if err != nil {
|
|
t.Fatalf("Failed to restore snapshot: %v", err)
|
|
}
|
|
restoreDuration := time.Since(startTime)
|
|
t.Logf("Restored snapshot with %d files in %v (%.2f files/sec)", fileCount, restoreDuration, float64(fileCount)/restoreDuration.Seconds())
|
|
})
|
|
}
|
|
}
|
|
|
|
// Helper function to create benchmark files
|
|
func createBenchmarkFiles(tb testing.TB, dir string, count, size int) {
|
|
tb.Helper()
|
|
|
|
// Create files with sequential names
|
|
for i := 0; i < count; i++ {
|
|
filePath := filepath.Join(dir, fmt.Sprintf("file_%d.txt", i))
|
|
|
|
// Create content of specified size
|
|
content := make([]byte, size)
|
|
for j := 0; j < size; j++ {
|
|
content[j] = byte(j % 256)
|
|
}
|
|
|
|
if err := os.WriteFile(filePath, content, 0644); err != nil {
|
|
tb.Fatalf("Failed to create benchmark file %s: %v", filePath, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Helper function to create a large file
|
|
func createLargeFile(tb testing.TB, path string, size int) {
|
|
tb.Helper()
|
|
|
|
// Create the file
|
|
file, err := os.Create(path)
|
|
if err != nil {
|
|
tb.Fatalf("Failed to create large file: %v", err)
|
|
}
|
|
defer file.Close()
|
|
|
|
// Create a buffer with a pattern
|
|
bufferSize := 8192 // 8 KB buffer
|
|
buffer := make([]byte, bufferSize)
|
|
for i := 0; i < bufferSize; i++ {
|
|
buffer[i] = byte(i % 256)
|
|
}
|
|
|
|
// Write the buffer multiple times to reach the desired size
|
|
bytesWritten := 0
|
|
for bytesWritten < size {
|
|
n, err := file.Write(buffer)
|
|
if err != nil {
|
|
tb.Fatalf("Failed to write to large file: %v", err)
|
|
}
|
|
bytesWritten += n
|
|
}
|
|
}
|