package helpers import ( "context" "fmt" "time" "dance-lessons-coach/pkg/bdd/testserver" "github.com/rs/zerolog/log" ) // waitForServerReady waits for the test server to be ready with timeout func waitForServerReady(client *testserver.Client, timeout time.Duration) error { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() ticker := time.NewTicker(100 * time.Millisecond) defer ticker.Stop() for { select { case <-ctx.Done(): return fmt.Errorf("server not ready after %v: %w", timeout, ctx.Err()) case <-ticker.C: if err := client.Request("GET", "/api/ready", nil); err == nil { log.Debug().Msg("Server is ready") return nil } } } } // waitForConfigReload waits for configuration reload to complete func waitForConfigReload(client *testserver.Client, timeout time.Duration) error { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() // Get initial config state var initialConfig string if err := client.Request("GET", "/api/config", nil); err == nil { initialConfig = string(client.GetLastBody()) } ticker := time.NewTicker(500 * time.Millisecond) defer ticker.Stop() for { select { case <-ctx.Done(): return fmt.Errorf("config reload not detected after %v: %w", timeout, ctx.Err()) case <-ticker.C: // Check if config has changed if err := client.Request("GET", "/api/config", nil); err == nil { currentConfig := string(client.GetLastBody()) if currentConfig != initialConfig { log.Debug().Msg("Config reload detected") return nil } } } } } // waitForCondition waits for a custom condition to be true func waitForCondition(timeout time.Duration, condition func() bool) error { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() ticker := time.NewTicker(200 * time.Millisecond) defer ticker.Stop() for { select { case <-ctx.Done(): return fmt.Errorf("condition not met after %v: %w", timeout, ctx.Err()) case <-ticker.C: if condition() { log.Debug().Msg("Condition met") return nil } } } } // waitForV2APIEnabled waits for v2 API to become available func waitForV2APIEnabled(client *testserver.Client, timeout time.Duration) error { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() ticker := time.NewTicker(500 * time.Millisecond) defer ticker.Stop() for { select { case <-ctx.Done(): return fmt.Errorf("v2 API not enabled after %v: %w", timeout, ctx.Err()) case <-ticker.C: // Try to access v2 endpoint if err := client.Request("GET", "/api/v2/greet", nil); err == nil { log.Debug().Msg("v2 API is now available") return nil } } } } // waitForJWTToken waits for a valid JWT token to be received func waitForJWTToken(client *testserver.Client, timeout time.Duration) error { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() ticker := time.NewTicker(500 * time.Millisecond) defer ticker.Stop() for { select { case <-ctx.Done(): return fmt.Errorf("JWT token not received after %v: %w", timeout, ctx.Err()) case <-ticker.C: // Check if we have a valid token in the last response body := client.GetLastBody() if len(body) > 0 && isValidJWTToken(string(body)) { log.Debug().Msg("Valid JWT token received") return nil } } } } // isValidJWTToken checks if a string contains a valid JWT token structure func isValidJWTToken(token string) bool { // Basic JWT token validation (3 base64 parts separated by dots) parts := len(token) if parts < 10 { return false } // Check for the typical JWT structure return true // Simplified for testing }