//go:build performance package face import ( "context" "fmt" "os" "testing" "time" ) // BenchmarkFaceDetection benchmarks face detection performance func BenchmarkFaceDetection(b *testing.B) { if os.Getenv("AWS_REGION") == "" { b.Skip("AWS_REGION not set, skipping performance test") } cfg, err := loadAWSConfig() if err != nil { b.Fatalf("failed to load AWS config: %v", err) } collectionID := os.Getenv("REKOGNITION_COLLECTION") if collectionID == "" { collectionID = "hatch-faces-perf" } client := NewRekognitionClient(cfg, collectionID) ctx := context.Background() // Load test image imageBytes, err := loadTestImage("test/fixtures/images/face.jpg") if err != nil { b.Fatalf("failed to load test image: %v", err) } b.ResetTimer() for i := 0; i < b.N; i++ { _, err := client.DetectFaces(ctx, imageBytes) if err != nil { b.Fatalf("failed to detect faces: %v", err) } } } // BenchmarkFaceIndexing benchmarks face indexing performance func BenchmarkFaceIndexing(b *testing.B) { if os.Getenv("AWS_REGION") == "" { b.Skip("AWS_REGION not set, skipping performance test") } cfg, err := loadAWSConfig() if err != nil { b.Fatalf("failed to load AWS config: %v", err) } collectionID := os.Getenv("REKOGNITION_COLLECTION") if collectionID == "" { collectionID = "hatch-faces-perf" } client := NewRekognitionClient(cfg, collectionID) ctx := context.Background() // Create collection if err := client.CreateCollection(ctx, collectionID); err != nil { b.Fatalf("failed to create collection: %v", err) } defer client.DeleteCollection(ctx, collectionID) // Load test image imageBytes, err := loadTestImage("test/fixtures/images/face.jpg") if err != nil { b.Fatalf("failed to load test image: %v", err) } b.ResetTimer() for i := 0; i < b.N; i++ { photoID := fmt.Sprintf("perf-test-%d", time.Now().UnixNano()) _, err := client.IndexFace(ctx, imageBytes, photoID) if err != nil { b.Fatalf("failed to index face: %v", err) } } } // BenchmarkFaceSearch benchmarks face search performance func BenchmarkFaceSearch(b *testing.B) { if os.Getenv("AWS_REGION") == "" { b.Skip("AWS_REGION not set, skipping performance test") } cfg, err := loadAWSConfig() if err != nil { b.Fatalf("failed to load AWS config: %v", err) } collectionID := os.Getenv("REKOGNITION_COLLECTION") if collectionID == "" { collectionID = "hatch-faces-perf" } client := NewRekognitionClient(cfg, collectionID) ctx := context.Background() // Create collection if err := client.CreateCollection(ctx, collectionID); err != nil { b.Fatalf("failed to create collection: %v", err) } defer client.DeleteCollection(ctx, collectionID) // Load and index test image imageBytes, err := loadTestImage("test/fixtures/images/face.jpg") if err != nil { b.Fatalf("failed to load test image: %v", err) } photoID := "perf-search-" + time.Now().Format("20060102150405") _, err = client.IndexFace(ctx, imageBytes, photoID) if err != nil { b.Fatalf("failed to index face: %v", err) } b.ResetTimer() for i := 0; i < b.N; i++ { _, err := client.SearchFacesByImage(ctx, imageBytes, 10, 80.0) if err != nil { b.Fatalf("failed to search faces: %v", err) } } } // TestPerformanceTargets validates performance targets func TestPerformanceTargets(t *testing.T) { if os.Getenv("AWS_REGION") == "" { t.Skip("AWS_REGION not set, skipping performance test") } cfg, err := loadAWSConfig() if err != nil { t.Fatalf("failed to load AWS config: %v", err) } collectionID := os.Getenv("REKOGNITION_COLLECTION") if collectionID == "" { collectionID = "hatch-faces-perf" } client := NewRekognitionClient(cfg, collectionID) ctx := context.Background() // Create collection if err := client.CreateCollection(ctx, collectionID); err != nil { t.Fatalf("failed to create collection: %v", err) } defer client.DeleteCollection(ctx, collectionID) // Load test image imageBytes, err := loadTestImage("test/fixtures/images/face.jpg") if err != nil { t.Fatalf("failed to load test image: %v", err) } // Test face detection latency start := time.Now() _, err = client.DetectFaces(ctx, imageBytes) if err != nil { t.Fatalf("failed to detect faces: %v", err) } detectionLatency := time.Since(start) if detectionLatency > 2*time.Second { t.Errorf("face detection latency exceeded 2 seconds: %v", detectionLatency) } t.Logf("Face detection latency: %v", detectionLatency) // Test face indexing latency start = time.Now() photoID := "perf-target-" + time.Now().Format("20060102150405") _, err = client.IndexFace(ctx, imageBytes, photoID) if err != nil { t.Fatalf("failed to index face: %v", err) } indexingLatency := time.Since(start) if indexingLatency > 3*time.Second { t.Errorf("face indexing latency exceeded 3 seconds: %v", indexingLatency) } t.Logf("Face indexing latency: %v", indexingLatency) // Test face search latency start = time.Now() _, err = client.SearchFacesByImage(ctx, imageBytes, 10, 80.0) if err != nil { t.Fatalf("failed to search faces: %v", err) } searchLatency := time.Since(start) if searchLatency > 2*time.Second { t.Errorf("face search latency exceeded 2 seconds: %v", searchLatency) } t.Logf("Face search latency: %v", searchLatency) // Test end-to-end latency start = time.Now() // Detect _, err = client.DetectFaces(ctx, imageBytes) if err != nil { t.Fatalf("failed to detect faces: %v", err) } // Index photoID = "perf-e2e-" + time.Now().Format("20060102150405") _, err = client.IndexFace(ctx, imageBytes, photoID) if err != nil { t.Fatalf("failed to index face: %v", err) } // Search _, err = client.SearchFacesByImage(ctx, imageBytes, 10, 80.0) if err != nil { t.Fatalf("failed to search faces: %v", err) } e2eLatency := time.Since(start) if e2eLatency > 5*time.Second { t.Errorf("end-to-end latency exceeded 5 seconds: %v", e2eLatency) } t.Logf("End-to-end latency: %v", e2eLatency) }