//go:build integration package face import ( "context" "os" "testing" "time" ) // TestIntegration_DetectFaces tests face detection with real AWS Rekognition func TestIntegration_DetectFaces(t *testing.T) { if os.Getenv("AWS_REGION") == "" { t.Skip("AWS_REGION not set, skipping integration 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-test" } client := NewRekognitionClient(cfg, collectionID) ctx := context.Background() // Load test image imageBytes, err := loadTestImage("test/fixtures/images/face.jpg") if err != nil { t.Fatalf("failed to load test image: %v", err) } // Detect faces detections, err := client.DetectFaces(ctx, imageBytes) if err != nil { t.Fatalf("failed to detect faces: %v", err) } if len(detections) == 0 { t.Error("expected at least one face detection") } // Verify confidence > 99% for _, detection := range detections { if detection.Confidence < 99.0 { t.Errorf("expected confidence > 99%%, got %f", detection.Confidence) } } } // TestIntegration_IndexFace tests face indexing with real AWS Rekognition func TestIntegration_IndexFace(t *testing.T) { if os.Getenv("AWS_REGION") == "" { t.Skip("AWS_REGION not set, skipping integration 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-test" } 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) } // Index face photoID := "test-photo-" + time.Now().Format("20060102150405") detection, err := client.IndexFace(ctx, imageBytes, photoID) if err != nil { t.Fatalf("failed to index face: %v", err) } if detection == nil { t.Error("expected face detection, got nil") } if detection.Confidence < 99.0 { t.Errorf("expected confidence > 99%%, got %f", detection.Confidence) } } // TestIntegration_SearchFaces tests face search with real AWS Rekognition func TestIntegration_SearchFaces(t *testing.T) { if os.Getenv("AWS_REGION") == "" { t.Skip("AWS_REGION not set, skipping integration 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-test" } 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 and index test image imageBytes, err := loadTestImage("test/fixtures/images/face.jpg") if err != nil { t.Fatalf("failed to load test image: %v", err) } photoID := "test-photo-" + time.Now().Format("20060102150405") _, err = client.IndexFace(ctx, imageBytes, photoID) if err != nil { t.Fatalf("failed to index face: %v", err) } // Search for the indexed face matches, err := client.SearchFacesByImage(ctx, imageBytes, 10, 80.0) if err != nil { t.Fatalf("failed to search faces: %v", err) } if len(matches) == 0 { t.Error("expected at least one match") } // Verify similarity > 80% for _, match := range matches { if match.Similarity < 80.0 { t.Errorf("expected similarity > 80%%, got %f", match.Similarity) } } } // TestIntegration_EndToEnd tests complete face detection → index → search flow func TestIntegration_EndToEnd(t *testing.T) { if os.Getenv("AWS_REGION") == "" { t.Skip("AWS_REGION not set, skipping integration test") } startTime := time.Now() 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-test" } 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) } // Step 1: Detect faces detections, err := client.DetectFaces(ctx, imageBytes) if err != nil { t.Fatalf("failed to detect faces: %v", err) } if len(detections) == 0 { t.Fatal("no faces detected") } // Step 2: Index face photoID := "e2e-test-" + time.Now().Format("20060102150405") _, err = client.IndexFace(ctx, imageBytes, photoID) if err != nil { t.Fatalf("failed to index face: %v", err) } // Step 3: Search for the indexed face matches, err := client.SearchFacesByImage(ctx, imageBytes, 10, 80.0) if err != nil { t.Fatalf("failed to search faces: %v", err) } if len(matches) == 0 { t.Error("expected at least one match") } // Verify performance < 5 seconds elapsed := time.Since(startTime) if elapsed > 5*time.Second { t.Errorf("end-to-end latency exceeded 5 seconds: %v", elapsed) } t.Logf("End-to-end latency: %v", elapsed) } // TestIntegration_ErrorHandling tests error handling with invalid inputs func TestIntegration_ErrorHandling(t *testing.T) { if os.Getenv("AWS_REGION") == "" { t.Skip("AWS_REGION not set, skipping integration 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-test" } client := NewRekognitionClient(cfg, collectionID) ctx := context.Background() // Test with empty image data _, err = client.DetectFaces(ctx, []byte{}) if err == nil { t.Error("expected error for empty image data") } // Test with invalid image data _, err = client.DetectFaces(ctx, []byte("invalid image data")) if err == nil { t.Error("expected error for invalid image data") } } // Helper functions func loadAWSConfig() (aws.Config, error) { return config.LoadDefaultConfig(context.Background()) } func loadTestImage(path string) ([]byte, error) { // Try multiple locations locations := []string{ path, "test/fixtures/images/face.jpg", "testdata/face.jpg", "../test/fixtures/images/face.jpg", } for _, loc := range locations { data, err := os.ReadFile(loc) if err == nil { return data, nil } } return nil, fmt.Errorf("test image not found in any of the expected locations") }