// +build integration package serviceadapter import ( "fmt" "io" "net/http" "os" "strconv" "strings" "testing" "time" ) // TestIntegration tests the real gateway deployment. // Run with: go test -tags integration -v ./internal/serviceadapter func TestIntegration(t *testing.T) { // Load config from .dev.test gatewayURL := os.Getenv("GATEWAY_URL") if gatewayURL == "" { gatewayURL = "http://localhost:8080" } testJWT := os.Getenv("TEST_JWT_TOKEN") skipAuth := os.Getenv("SKIP_AUTH_TESTS") == "true" timeoutStr := os.Getenv("TEST_TIMEOUT") timeout := 10 if t, err := strconv.Atoi(timeoutStr); err == nil { timeout = t } client := &http.Client{Timeout: time.Duration(timeout) * time.Second} t.Run("health check", func(t *testing.T) { resp, err := client.Get(gatewayURL + "/healthz") if err != nil { t.Fatalf("health check failed: %v", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { body, _ := io.ReadAll(resp.Body) t.Fatalf("health check returned %d: %s", resp.StatusCode, string(body)) } }) t.Run("public service - sqs", func(t *testing.T) { req, err := http.NewRequest("GET", gatewayURL+"/", nil) if err != nil { t.Fatalf("failed to create request: %v", err) } req.Header.Set("X-Service", "sqs") req.Header.Set("X-Resource", "list-queues") resp, err := client.Do(req) if err != nil { t.Fatalf("request failed: %v", err) } defer resp.Body.Close() if resp.StatusCode == http.StatusBadGateway { t.Logf("sqs service not reachable (expected in test env): %d", resp.StatusCode) return // Service might not be reachable from outside cluster } if resp.StatusCode < 200 || resp.StatusCode >= 300 { body, _ := io.ReadAll(resp.Body) t.Logf("sqs returned %d: %s", resp.StatusCode, string(body)) } }) t.Run("public service - s3", func(t *testing.T) { req, err := http.NewRequest("GET", gatewayURL+"/", nil) if err != nil { t.Fatalf("failed to create request: %v", err) } req.Header.Set("X-Service", "s3") req.Header.Set("X-Resource", "list-objects") resp, err := client.Do(req) if err != nil { t.Fatalf("request failed: %v", err) } defer resp.Body.Close() if resp.StatusCode == http.StatusBadGateway { t.Logf("s3 service not reachable (expected in test env): %d", resp.StatusCode) return } if resp.StatusCode < 200 || resp.StatusCode >= 300 { body, _ := io.ReadAll(resp.Body) t.Logf("s3 returned %d: %s", resp.StatusCode, string(body)) } }) t.Run("public service - memory", func(t *testing.T) { req, err := http.NewRequest("POST", gatewayURL+"/", nil) if err != nil { t.Fatalf("failed to create request: %v", err) } req.Header.Set("X-Service", "memory") req.Header.Set("X-Resource", "query") resp, err := client.Do(req) if err != nil { t.Fatalf("request failed: %v", err) } defer resp.Body.Close() if resp.StatusCode == http.StatusBadGateway { t.Logf("memory service not reachable (expected in test env): %d", resp.StatusCode) return } if resp.StatusCode < 200 || resp.StatusCode >= 300 { body, _ := io.ReadAll(resp.Body) t.Logf("memory returned %d: %s", resp.StatusCode, string(body)) } }) t.Run("service not found", func(t *testing.T) { req, err := http.NewRequest("GET", gatewayURL+"/", nil) if err != nil { t.Fatalf("failed to create request: %v", err) } req.Header.Set("X-Service", "nonexistent") req.Header.Set("X-Resource", "foo") resp, err := client.Do(req) if err != nil { t.Fatalf("request failed: %v", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusNotFound { t.Errorf("expected 404, got %d", resp.StatusCode) } body, _ := io.ReadAll(resp.Body) if !strings.Contains(string(body), "not found") { t.Errorf("expected 'not found' in response, got: %s", string(body)) } }) t.Run("resource not found", func(t *testing.T) { req, err := http.NewRequest("GET", gatewayURL+"/", nil) if err != nil { t.Fatalf("failed to create request: %v", err) } req.Header.Set("X-Service", "sqs") req.Header.Set("X-Resource", "invalid-resource") resp, err := client.Do(req) if err != nil { t.Fatalf("request failed: %v", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusNotFound { t.Errorf("expected 404, got %d", resp.StatusCode) } }) if !skipAuth && testJWT != "" { t.Run("iam service with valid JWT", func(t *testing.T) { req, err := http.NewRequest("GET", gatewayURL+"/", nil) if err != nil { t.Fatalf("failed to create request: %v", err) } req.Header.Set("X-Service", "iam") req.Header.Set("X-Resource", "list-roles") req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", testJWT)) resp, err := client.Do(req) if err != nil { t.Fatalf("request failed: %v", err) } defer resp.Body.Close() if resp.StatusCode == http.StatusBadGateway { t.Logf("iam service not reachable: %d", resp.StatusCode) return } if resp.StatusCode >= 400 { body, _ := io.ReadAll(resp.Body) t.Logf("iam returned %d: %s", resp.StatusCode, string(body)) } }) } else { t.Log("Skipping auth tests (set TEST_JWT_TOKEN to enable)") } t.Run("missing X-Service header", func(t *testing.T) { req, err := http.NewRequest("GET", gatewayURL+"/", nil) if err != nil { t.Fatalf("failed to create request: %v", err) } // No X-Service header resp, err := client.Do(req) if err != nil { t.Fatalf("request failed: %v", err) } defer resp.Body.Close() // Should route through other paths, not via X-Service dispatcher // This is expected - no error, just not dispatched t.Logf("Request without X-Service returned %d", resp.StatusCode) }) }