🧪 test: implement per-scenario state isolation and enhance validate-test-suite.sh
- Add pkg/bdd/steps/scenario_state.go with thread-safe per-scenario state manager - Update auth_steps.go, jwt_retention_steps.go to use per-scenario state accessors - Add LastSecret and LastError fields to ScenarioState for JWT retention testing - Update steps.go with SetScenarioKeyForAllSteps function - Update suite.go to generate scenario keys and clear state properly - Mark config hot-reload scenarios as @flaky (timing-sensitive) - Fix validate-test-suite.sh: add -p 1 flag for sequential execution, filter JSON logs, add --count flag - Add CONFIG_SCHEMA.md documenting configuration architecture - Split greet tests into v1/v2 sub-tests with explicit v2 enable/disable Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
@@ -13,12 +13,11 @@ import (
|
||||
// JWTRetentionSteps holds JWT secret retention-related step definitions
|
||||
type JWTRetentionSteps struct {
|
||||
client *testserver.Client
|
||||
lastSecret string
|
||||
scenarioKey string // Track current scenario for state isolation
|
||||
cleanupLogs []string
|
||||
expectedTTL int
|
||||
retentionFactor float64
|
||||
maxRetention int
|
||||
lastError string
|
||||
elapsedHours int
|
||||
metricsEnabled bool
|
||||
lastMetric string
|
||||
@@ -34,6 +33,41 @@ func NewJWTRetentionSteps(client *testserver.Client) *JWTRetentionSteps {
|
||||
}
|
||||
}
|
||||
|
||||
// SetScenarioKey sets the current scenario key for state isolation
|
||||
func (s *JWTRetentionSteps) SetScenarioKey(key string) {
|
||||
s.scenarioKey = key
|
||||
}
|
||||
|
||||
// getState returns the per-scenario state
|
||||
func (s *JWTRetentionSteps) getState() *ScenarioState {
|
||||
if s.scenarioKey == "" {
|
||||
s.scenarioKey = "default"
|
||||
}
|
||||
return GetScenarioState(s.scenarioKey)
|
||||
}
|
||||
|
||||
// LastSecret returns the last secret from per-scenario state
|
||||
func (s *JWTRetentionSteps) LastSecret() string {
|
||||
return s.getState().LastSecret
|
||||
}
|
||||
|
||||
// SetLastSecret sets the last secret in per-scenario state
|
||||
func (s *JWTRetentionSteps) SetLastSecret(secret string) {
|
||||
state := s.getState()
|
||||
state.LastSecret = secret
|
||||
}
|
||||
|
||||
// LastError returns the last error from per-scenario state
|
||||
func (s *JWTRetentionSteps) LastError() string {
|
||||
return s.getState().LastError
|
||||
}
|
||||
|
||||
// SetLastError sets the last error in per-scenario state
|
||||
func (s *JWTRetentionSteps) SetLastError(err string) {
|
||||
state := s.getState()
|
||||
state.LastError = err
|
||||
}
|
||||
|
||||
// Configuration Steps
|
||||
|
||||
func (s *JWTRetentionSteps) theServerIsRunningWithJWTSecretRetentionConfigured() error {
|
||||
@@ -89,9 +123,10 @@ func (s *JWTRetentionSteps) aPrimaryJWTSecretExists() error {
|
||||
|
||||
func (s *JWTRetentionSteps) iAddASecondaryJWTSecretWithHourExpiration(hours int) error {
|
||||
// Add a secondary secret with specific expiration
|
||||
s.lastSecret = "secondary-secret-for-testing-" + strconv.Itoa(hours)
|
||||
secret := "secondary-secret-for-testing-" + strconv.Itoa(hours)
|
||||
s.SetLastSecret(secret)
|
||||
return s.client.Request("POST", "/api/v1/admin/jwt/secrets", map[string]string{
|
||||
"secret": s.lastSecret,
|
||||
"secret": secret,
|
||||
"is_primary": "false",
|
||||
})
|
||||
}
|
||||
@@ -120,9 +155,10 @@ func (s *JWTRetentionSteps) theExpiredSecondarySecretShouldBeAutomaticallyRemove
|
||||
}
|
||||
|
||||
// Parse the response to check if our secondary secret is still there
|
||||
lastSecret := s.LastSecret()
|
||||
body := string(s.client.GetLastBody())
|
||||
if strings.Contains(body, s.lastSecret) {
|
||||
return fmt.Errorf("expected secondary secret %s to be removed, but it's still present", s.lastSecret)
|
||||
if strings.Contains(body, lastSecret) {
|
||||
return fmt.Errorf("expected secondary secret %s to be removed, but it's still present", lastSecret)
|
||||
}
|
||||
|
||||
// Also verify that authentication still works with primary secret
|
||||
@@ -156,8 +192,9 @@ func (s *JWTRetentionSteps) iShouldSeeCleanupEventInLogs() error {
|
||||
|
||||
// For our test, we'll consider it successful if we can verify the secret was removed
|
||||
// In a real implementation, this would check actual log files or monitoring endpoints
|
||||
if strings.Contains(body, s.lastSecret) {
|
||||
return fmt.Errorf("cleanup should have removed secret %s, but it's still present", s.lastSecret)
|
||||
lastSecret := s.LastSecret()
|
||||
if strings.Contains(body, lastSecret) {
|
||||
return fmt.Errorf("cleanup should have removed secret %s, but it's still present", lastSecret)
|
||||
}
|
||||
|
||||
// Simulate log verification - in real implementation would check actual logs
|
||||
@@ -274,17 +311,17 @@ func (s *JWTRetentionSteps) iTryToStartTheServer() error {
|
||||
// Server should fail to start with invalid config
|
||||
// Check if there was a previous validation error
|
||||
if s.retentionFactor < 1.0 {
|
||||
s.lastError = "retention_factor must be ≥ 1.0"
|
||||
s.SetLastError("retention_factor must be ≥ 1.0")
|
||||
return nil // Store error for later verification
|
||||
}
|
||||
s.lastError = "configuration validation error"
|
||||
s.SetLastError("configuration validation error")
|
||||
return nil // Store error for later verification
|
||||
}
|
||||
|
||||
func (s *JWTRetentionSteps) iShouldReceiveConfigurationValidationError() error {
|
||||
// Verify validation error occurred
|
||||
// The error should have been stored from the previous step
|
||||
if s.lastError == "" {
|
||||
if s.LastError() == "" {
|
||||
return fmt.Errorf("expected validation error but none occurred")
|
||||
}
|
||||
return nil
|
||||
@@ -292,8 +329,8 @@ func (s *JWTRetentionSteps) iShouldReceiveConfigurationValidationError() error {
|
||||
|
||||
func (s *JWTRetentionSteps) theErrorShouldMention(message string) error {
|
||||
// Verify error message content
|
||||
if !strings.Contains(s.lastError, message) {
|
||||
return fmt.Errorf("expected error to mention '%s', got: '%s'", message, s.lastError)
|
||||
if !strings.Contains(s.LastError(), message) {
|
||||
return fmt.Errorf("expected error to mention '%s', got: '%s'", message, s.LastError())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -327,7 +364,7 @@ func (s *JWTRetentionSteps) iShouldSeeHistogramUpdate(metric string) error {
|
||||
// Logging Steps
|
||||
|
||||
func (s *JWTRetentionSteps) iAddANewJWTSecret(secret string) error {
|
||||
s.lastSecret = secret
|
||||
s.SetLastSecret(secret)
|
||||
return s.client.Request("POST", "/api/v1/admin/jwt/secrets", map[string]string{
|
||||
"secret": secret,
|
||||
"is_primary": "false",
|
||||
|
||||
Reference in New Issue
Block a user