package test import ( "net/http" "net/http/httptest" "testing" "time" "github.com/stretchr/testify/assert" ) func TestGetHTTPTimeout(t *testing.T) { // Test default value timeout := GetHTTPTimeout() assert.Equal(t, 30*time.Second, timeout, "default HTTP timeout should be 30 seconds") // Test with environment variable t.Setenv("E2E_HTTP_TIMEOUT", "45s") timeout = GetHTTPTimeout() assert.Equal(t, 45*time.Second, timeout, "HTTP timeout should respect E2E_HTTP_TIMEOUT env var") // Test with invalid environment variable (should fall back to default) t.Setenv("E2E_HTTP_TIMEOUT", "invalid") timeout = GetHTTPTimeout() assert.Equal(t, 30*time.Second, timeout, "invalid E2E_HTTP_TIMEOUT should fall back to default") } func TestGetPollingTimeout(t *testing.T) { // Clear CI env vars to ensure we test non-CI default first t.Setenv("CI", "") t.Setenv("BITBUCKET_PIPELINE_UUID", "") // Test default value (non-CI) timeout := GetPollingTimeout() assert.Equal(t, 60*time.Second, timeout, "default polling timeout should be 60 seconds") // Test with environment variable override t.Setenv("E2E_WAIT_TIMEOUT", "120s") timeout = GetPollingTimeout() assert.Equal(t, 120*time.Second, timeout, "polling timeout should respect E2E_WAIT_TIMEOUT env var") // Test CI detection t.Setenv("E2E_WAIT_TIMEOUT", "") t.Setenv("CI", "true") timeout = GetPollingTimeout() assert.Equal(t, 180*time.Second, timeout, "polling timeout in CI should be 180 seconds") // Test BITBUCKET_PIPELINE_UUID detection t.Setenv("CI", "") t.Setenv("BITBUCKET_PIPELINE_UUID", "some-uuid") timeout = GetPollingTimeout() assert.Equal(t, 180*time.Second, timeout, "polling timeout with BITBUCKET_PIPELINE_UUID should be 180 seconds") } func TestGetPollInterval(t *testing.T) { // Test default value interval := GetPollInterval() assert.Equal(t, 500*time.Millisecond, interval, "default poll interval should be 500ms") // Test with environment variable t.Setenv("E2E_POLL_INTERVAL", "1s") interval = GetPollInterval() assert.Equal(t, 1*time.Second, interval, "poll interval should respect E2E_POLL_INTERVAL env var") // Test with invalid environment variable (should fall back to default) t.Setenv("E2E_POLL_INTERVAL", "invalid") interval = GetPollInterval() assert.Equal(t, 500*time.Millisecond, interval, "invalid E2E_POLL_INTERVAL should fall back to default") } func TestGetHTTPClient(t *testing.T) { client := GetHTTPClient() assert.NotNil(t, client, "GetHTTPClient should return a non-nil client") assert.Equal(t, GetHTTPTimeout(), client.Timeout, "HTTP client timeout should match GetHTTPTimeout()") } func TestIsCI(t *testing.T) { // Clear CI env vars to ensure consistent test behavior t.Setenv("CI", "") t.Setenv("BITBUCKET_PIPELINE_UUID", "") // Test non-CI environment assert.False(t, isCI(), "isCI should return false when CI env vars are not set") // Test with CI env var t.Setenv("CI", "true") assert.True(t, isCI(), "isCI should return true when CI is set") // Test with BITBUCKET_PIPELINE_UUID t.Setenv("CI", "") t.Setenv("BITBUCKET_PIPELINE_UUID", "some-uuid") assert.True(t, isCI(), "isCI should return true when BITBUCKET_PIPELINE_UUID is set") } func TestWaitForExternalReadiness(t *testing.T) { t.Run("success on first attempt", func(t *testing.T) { // Create a test server that returns 200 OK server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/health" { w.WriteHeader(http.StatusOK) return } w.WriteHeader(http.StatusNotFound) })) defer server.Close() err := WaitForExternalReadiness(server.URL, "/health", 5*time.Second) assert.NoError(t, err, "should succeed when server is immediately ready") }) t.Run("success after delay", func(t *testing.T) { attempts := 0 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/health" { attempts++ if attempts < 3 { w.WriteHeader(http.StatusServiceUnavailable) return } w.WriteHeader(http.StatusOK) return } w.WriteHeader(http.StatusNotFound) })) defer server.Close() err := WaitForExternalReadiness(server.URL, "/health", 5*time.Second) assert.NoError(t, err, "should succeed after retries") assert.GreaterOrEqual(t, attempts, 3, "should have made multiple attempts") }) t.Run("timeout on non-responsive server", func(t *testing.T) { // Create a server that always returns 503 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusServiceUnavailable) })) defer server.Close() err := WaitForExternalReadiness(server.URL, "/health", 2*time.Second) assert.Error(t, err, "should fail when server never becomes ready") assert.Contains(t, err.Error(), "not reachable", "error should indicate service not reachable") }) t.Run("timeout on unreachable server", func(t *testing.T) { // Use an invalid URL that will fail to connect err := WaitForExternalReadiness("http://127.0.0.1:1", "/health", 2*time.Second) assert.Error(t, err, "should fail when server is unreachable") assert.Contains(t, err.Error(), "not reachable", "error should indicate service not reachable") }) } func TestWaitForAPIRoutes(t *testing.T) { t.Run("success when routes return 200", func(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/clients" { w.WriteHeader(http.StatusOK) _, _ = w.Write([]byte("[]")) return } w.WriteHeader(http.StatusNotFound) })) defer server.Close() err := WaitForAPIRoutes(server.URL, 5*time.Second) assert.NoError(t, err, "should succeed when routes return 200") }) t.Run("success after routes become available", func(t *testing.T) { attempts := 0 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/clients" { attempts++ if attempts < 3 { // Simulate "404 page not found" before routes are registered w.WriteHeader(http.StatusNotFound) _, _ = w.Write([]byte("404 page not found")) return } w.WriteHeader(http.StatusOK) _, _ = w.Write([]byte("[]")) return } w.WriteHeader(http.StatusNotFound) })) defer server.Close() err := WaitForAPIRoutes(server.URL, 5*time.Second) assert.NoError(t, err, "should succeed after routes become available") assert.GreaterOrEqual(t, attempts, 3, "should have made multiple attempts") }) t.Run("success when routes return 401", func(t *testing.T) { // 401 means the route exists but requires auth - route is registered server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/clients" { w.WriteHeader(http.StatusUnauthorized) return } w.WriteHeader(http.StatusNotFound) })) defer server.Close() err := WaitForAPIRoutes(server.URL, 5*time.Second) assert.NoError(t, err, "should succeed when routes return 401 (route exists)") }) t.Run("timeout when routes never register", func(t *testing.T) { // Server always returns 404 - routes never registered server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNotFound) _, _ = w.Write([]byte("404 page not found")) })) defer server.Close() err := WaitForAPIRoutes(server.URL, 2*time.Second) assert.Error(t, err, "should fail when routes never register") assert.Contains(t, err.Error(), "not registered", "error should indicate routes not registered") }) }