🧪 test: add BDD exclusion tags and mark JWT scenarios as todo

- Add @flaky, @todo, @skip tags to BDD_TAGS.md
- Modify all feature test suites to exclude these tags
- Update test scripts to exclude tagged scenarios
- Mark all JWT scenarios with pending steps as @todo

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
2026-04-10 09:09:34 +02:00
parent 520da07bfe
commit a75f87777b
11 changed files with 51 additions and 11 deletions

View File

@@ -26,6 +26,12 @@ Used to categorize tests by system component:
- `@database` - Database interaction tests - `@database` - Database interaction tests
- `@security` - Security-related tests - `@security` - Security-related tests
### Exclusion Tags
Used to exclude tests from execution:
- `@flaky` - Tests that are unstable or intermittently fail
- `@todo` - Tests with pending step implementations
- `@skip` - Tests that should be skipped entirely
## Usage Examples ## Usage Examples
### Running Smoke Tests ### Running Smoke Tests
@@ -150,6 +156,9 @@ Feature: Health Endpoint
| `@config` | Configuration | `@config` on config scenarios | | `@config` | Configuration | `@config` on config scenarios |
| `@api` | API endpoints | `@api` on endpoint tests | | `@api` | API endpoints | `@api` on endpoint tests |
| `@v2` | V2 API | `@v2` on version 2 tests | | `@v2` | V2 API | `@v2` on version 2 tests |
| `@flaky` | Exclude flaky tests | `@flaky` on unstable scenarios |
| `@todo` | Exclude pending tests | `@todo` on unimplemented scenarios |
| `@skip` | Exclude tests entirely | `@skip` on disabled scenarios |
## Future Enhancements ## Future Enhancements

View File

@@ -24,6 +24,7 @@ func TestAuthBDD(t *testing.T) {
Strict: true, Strict: true,
Randomize: -1, Randomize: -1,
StopOnFailure: true, StopOnFailure: true,
Tags: "~@flaky && ~@todo && ~@skip",
}, },
} }

View File

@@ -24,6 +24,7 @@ func TestConfigBDD(t *testing.T) {
Strict: true, Strict: true,
Randomize: -1, Randomize: -1,
StopOnFailure: false, StopOnFailure: false,
Tags: "~@flaky && ~@todo && ~@skip",
}, },
} }

View File

@@ -24,6 +24,7 @@ func TestGreetBDD(t *testing.T) {
Strict: true, Strict: true,
Randomize: -1, Randomize: -1,
StopOnFailure: true, StopOnFailure: true,
Tags: "~@flaky && ~@todo && ~@skip",
}, },
} }

View File

@@ -24,6 +24,7 @@ func TestHealthBDD(t *testing.T) {
Strict: true, Strict: true,
Randomize: -1, Randomize: -1,
StopOnFailure: true, StopOnFailure: true,
Tags: "~@flaky && ~@todo && ~@skip",
}, },
} }

View File

@@ -10,6 +10,7 @@ Feature: JWT Secret Retention Policy
And the retention factor is 2.0 And the retention factor is 2.0
And the maximum retention is 72 hours And the maximum retention is 72 hours
@todo
Scenario: Automatic cleanup of expired secrets Scenario: Automatic cleanup of expired secrets
Given a primary JWT secret exists Given a primary JWT secret exists
And I add a secondary JWT secret with 1 hour expiration And I add a secondary JWT secret with 1 hour expiration
@@ -18,6 +19,7 @@ Feature: JWT Secret Retention Policy
And the primary secret should remain active And the primary secret should remain active
And I should see cleanup event in logs And I should see cleanup event in logs
@todo
Scenario: Secret retention based on TTL factor Scenario: Secret retention based on TTL factor
Given the JWT TTL is set to 2 hours Given the JWT TTL is set to 2 hours
And the retention factor is 3.0 And the retention factor is 3.0
@@ -25,6 +27,7 @@ Feature: JWT Secret Retention Policy
Then the secret should expire after 6 hours Then the secret should expire after 6 hours
And the retention period should be 6 hours And the retention period should be 6 hours
@todo
Scenario: Maximum retention period enforcement Scenario: Maximum retention period enforcement
Given the JWT TTL is set to 72 hours Given the JWT TTL is set to 72 hours
And the retention factor is 3.0 And the retention factor is 3.0
@@ -33,6 +36,7 @@ Feature: JWT Secret Retention Policy
Then the retention period should be capped at 72 hours Then the retention period should be capped at 72 hours
And not exceed the maximum retention limit And not exceed the maximum retention limit
@todo
Scenario: Cleanup preserves primary secret Scenario: Cleanup preserves primary secret
Given a primary JWT secret exists Given a primary JWT secret exists
And the primary secret is older than retention period And the primary secret is older than retention period
@@ -40,6 +44,7 @@ Feature: JWT Secret Retention Policy
Then the primary secret should not be removed Then the primary secret should not be removed
And the primary secret should remain active And the primary secret should remain active
@todo
Scenario: Multiple secrets with different ages Scenario: Multiple secrets with different ages
Given I have 3 JWT secrets of different ages Given I have 3 JWT secrets of different ages
And secret A is 1 hour old (within retention) And secret A is 1 hour old (within retention)
@@ -50,12 +55,14 @@ Feature: JWT Secret Retention Policy
And secret B should be removed And secret B should be removed
And secret C should be retained as primary And secret C should be retained as primary
@todo
Scenario: Cleanup frequency configuration Scenario: Cleanup frequency configuration
Given the cleanup interval is set to 30 minutes Given the cleanup interval is set to 30 minutes
When I add an expired JWT secret When I add an expired JWT secret
Then it should be removed within 30 minutes Then it should be removed within 30 minutes
And I should see cleanup events every 30 minutes And I should see cleanup events every 30 minutes
@todo
Scenario: Token validation with expired secret Scenario: Token validation with expired secret
Given a user "retentionuser" exists with password "testpass123" Given a user "retentionuser" exists with password "testpass123"
And I authenticate with username "retentionuser" and password "testpass123" And I authenticate with username "retentionuser" and password "testpass123"
@@ -65,6 +72,7 @@ Feature: JWT Secret Retention Policy
Then the token validation should fail Then the token validation should fail
And I should receive "invalid_token" error And I should receive "invalid_token" error
@todo
Scenario: Graceful rotation during retention period Scenario: Graceful rotation during retention period
Given a user "gracefuluser" exists with password "testpass123" Given a user "gracefuluser" exists with password "testpass123"
And I authenticate with username "gracefuluser" and password "testpass123" And I authenticate with username "gracefuluser" and password "testpass123"
@@ -75,12 +83,14 @@ Feature: JWT Secret Retention Policy
And the old token should still be valid during retention period And the old token should still be valid during retention period
And both tokens should work until retention period expires And both tokens should work until retention period expires
@todo
Scenario: Configuration validation Scenario: Configuration validation
Given I set retention factor to 0.5 Given I set retention factor to 0.5
When I try to start the server When I try to start the server
Then I should receive configuration validation error Then I should receive configuration validation error
And the error should mention "retention_factor must be 1.0" And the error should mention "retention_factor must be 1.0"
@todo
Scenario: Metrics for secret retention Scenario: Metrics for secret retention
Given I have enabled Prometheus metrics Given I have enabled Prometheus metrics
When the cleanup job removes expired secrets When the cleanup job removes expired secrets
@@ -88,12 +98,14 @@ Feature: JWT Secret Retention Policy
And I should see "jwt_secrets_active_count" metric decrease And I should see "jwt_secrets_active_count" metric decrease
And I should see "jwt_secret_retention_duration_seconds" histogram update And I should see "jwt_secret_retention_duration_seconds" histogram update
@todo
Scenario: Log masking for security Scenario: Log masking for security
Given I add a new JWT secret "super-secret-key-123456" Given I add a new JWT secret "super-secret-key-123456"
When the cleanup job runs When the cleanup job runs
Then the logs should show masked secret "supe****123456" Then the logs should show masked secret "supe****123456"
And not expose the full secret in logs And not expose the full secret in logs
@todo
Scenario: Cleanup with high volume of secrets Scenario: Cleanup with high volume of secrets
Given I have 1000 JWT secrets Given I have 1000 JWT secrets
And 300 of them are expired And 300 of them are expired
@@ -102,12 +114,14 @@ Feature: JWT Secret Retention Policy
And remove all 300 expired secrets And remove all 300 expired secrets
And not impact server performance And not impact server performance
@todo
Scenario: Disabled cleanup via configuration Scenario: Disabled cleanup via configuration
Given I set cleanup interval to 8760 hours Given I set cleanup interval to 8760 hours
When I add expired JWT secrets When I add expired JWT secrets
Then they should not be automatically removed Then they should not be automatically removed
And manual cleanup should still be possible And manual cleanup should still be possible
@todo
Scenario: Retention period calculation edge cases Scenario: Retention period calculation edge cases
Given the JWT TTL is 1 hour Given the JWT TTL is 1 hour
And the retention factor is 1.0 And the retention factor is 1.0
@@ -115,12 +129,14 @@ Feature: JWT Secret Retention Policy
Then the retention period should be 1 hour Then the retention period should be 1 hour
And the secret should expire after 1 hour And the secret should expire after 1 hour
@todo
Scenario: Secret validation with retention policy Scenario: Secret validation with retention policy
Given I try to add an invalid JWT secret Given I try to add an invalid JWT secret
When the secret is less than 16 characters When the secret is less than 16 characters
Then I should receive validation error Then I should receive validation error
And the error should mention "must be at least 16 characters" And the error should mention "must be at least 16 characters"
@todo
Scenario: Cleanup job error handling Scenario: Cleanup job error handling
Given the cleanup job encounters an error Given the cleanup job encounters an error
When it tries to remove a secret When it tries to remove a secret
@@ -128,6 +144,7 @@ Feature: JWT Secret Retention Policy
And continue with remaining secrets And continue with remaining secrets
And not crash the cleanup process And not crash the cleanup process
@todo
Scenario: Configuration reload without restart Scenario: Configuration reload without restart
Given the server is running with default retention settings Given the server is running with default retention settings
When I update the retention factor via configuration When I update the retention factor via configuration
@@ -135,6 +152,7 @@ Feature: JWT Secret Retention Policy
And existing secrets should be reevaluated And existing secrets should be reevaluated
And cleanup should use new retention periods And cleanup should use new retention periods
@todo
Scenario: Audit trail for secret operations Scenario: Audit trail for secret operations
Given I enable audit logging Given I enable audit logging
When I add a new JWT secret When I add a new JWT secret
@@ -142,6 +160,7 @@ Feature: JWT Secret Retention Policy
And when the secret is removed by cleanup And when the secret is removed by cleanup
Then I should see audit log entry with event type "secret_removed" Then I should see audit log entry with event type "secret_removed"
@todo
Scenario: Retention policy with token refresh Scenario: Retention policy with token refresh
Given a user "refreshuser" exists with password "testpass123" Given a user "refreshuser" exists with password "testpass123"
And I authenticate and receive token A And I authenticate and receive token A
@@ -150,6 +169,7 @@ Feature: JWT Secret Retention Policy
And token A should still be valid until retention expires And token A should still be valid until retention expires
And both tokens should work concurrently And both tokens should work concurrently
@todo
Scenario: Emergency secret rotation Scenario: Emergency secret rotation
Given a security incident requires immediate rotation Given a security incident requires immediate rotation
When I rotate to a new primary secret When I rotate to a new primary secret
@@ -157,6 +177,7 @@ Feature: JWT Secret Retention Policy
And new tokens should use the emergency secret And new tokens should use the emergency secret
And cleanup should remove compromised secrets And cleanup should remove compromised secrets
@todo
Scenario: Monitoring and alerting Scenario: Monitoring and alerting
Given I have monitoring configured Given I have monitoring configured
When the cleanup job fails repeatedly When the cleanup job fails repeatedly

View File

@@ -4,6 +4,7 @@ Feature: JWT Secret Rotation
I want to rotate JWT secrets without disrupting users I want to rotate JWT secrets without disrupting users
So that we can maintain security while ensuring continuous service So that we can maintain security while ensuring continuous service
@todo
Scenario: Authentication with multiple valid JWT secrets Scenario: Authentication with multiple valid JWT secrets
Given the server is running with multiple JWT secrets Given the server is running with multiple JWT secrets
And a user "multiuser" exists with password "testpass123" And a user "multiuser" exists with password "testpass123"
@@ -11,6 +12,7 @@ Feature: JWT Secret Rotation
Then the authentication should be successful Then the authentication should be successful
And I should receive a valid JWT token signed with the primary secret And I should receive a valid JWT token signed with the primary secret
@todo
Scenario: Token validation with multiple valid secrets Scenario: Token validation with multiple valid secrets
Given the server is running with multiple JWT secrets Given the server is running with multiple JWT secrets
And a user "tokenuser" exists with password "testpass123" And a user "tokenuser" exists with password "testpass123"
@@ -21,6 +23,7 @@ Feature: JWT Secret Rotation
Then the token should be valid Then the token should be valid
And it should contain the correct user ID And it should contain the correct user ID
@todo
Scenario: Secret rotation - adding new secret while keeping old one valid Scenario: Secret rotation - adding new secret while keeping old one valid
Given the server is running with primary JWT secret Given the server is running with primary JWT secret
And a user "rotateuser" exists with password "testpass123" And a user "rotateuser" exists with password "testpass123"
@@ -34,12 +37,14 @@ Feature: JWT Secret Rotation
When I validate the old JWT token signed with primary secret When I validate the old JWT token signed with primary secret
Then the token should still be valid Then the token should still be valid
@todo
Scenario: Token rejection after secret expiration Scenario: Token rejection after secret expiration
Given the server is running with primary and expired secondary JWT secrets Given the server is running with primary and expired secondary JWT secrets
When I use a JWT token signed with the expired secondary secret for authentication When I use a JWT token signed with the expired secondary secret for authentication
Then the authentication should fail Then the authentication should fail
And the response should contain error "invalid_token" And the response should contain error "invalid_token"
@todo
Scenario: Graceful secret rotation with user continuity Scenario: Graceful secret rotation with user continuity
Given the server is running with primary JWT secret Given the server is running with primary JWT secret
And a user "gracefuluser" exists with password "testpass123" And a user "gracefuluser" exists with password "testpass123"

View File

@@ -24,6 +24,7 @@ func TestJWTBDD(t *testing.T) {
Strict: true, Strict: true,
Randomize: -1, Randomize: -1,
StopOnFailure: true, StopOnFailure: true,
Tags: "~@flaky && ~@todo && ~@skip",
}, },
} }

View File

@@ -122,17 +122,17 @@ run_tests_with_tags() {
echo "🏗️ CI environment detected, using service configuration" echo "🏗️ CI environment detected, using service configuration"
fi fi
# Run tests with proper coverage measurement # Run tests with proper coverage measurement and tag exclusion
set +e set +e
if [ -n "$tags" ]; then if [ -n "$tags" ]; then
# Use godog directly for tag filtering # Use godog directly for tag filtering with exclusion
echo "🚀 Running: godog $tags features/" echo "🚀 Running: godog $tags --tags=~@flaky --tags=~@todo --tags=~@skip features/"
test_output=$(godog $tags features/ 2>&1) test_output=$(godog $tags --tags=~@flaky --tags=~@todo --tags=~@skip features/ 2>&1)
else else
# Use go test for full test suite # Use go test for full test suite with tag exclusion
echo "🚀 Running: go test ./features/..." echo "🚀 Running: go test ./features/... -tags=~@flaky,~@todo,~@skip"
test_output=$(go test ./features/... -v -cover -coverpkg=./... -coverprofile=coverage.out 2>&1) test_output=$(go test ./features/... -tags=~@flaky,~@todo,~@skip -v -cover -coverpkg=./... -coverprofile=coverage.out 2>&1)
fi fi
test_exit_code=$? test_exit_code=$?

View File

@@ -43,9 +43,9 @@ run_feature_test() {
docker exec dance-lessons-coach-postgres createdb -U postgres "${DLC_DATABASE_NAME}" docker exec dance-lessons-coach-postgres createdb -U postgres "${DLC_DATABASE_NAME}"
fi fi
# Run the feature tests # Run the feature tests with tag exclusion
cd "features/${feature_name}" cd "features/${feature_name}"
FEATURE=${feature_name} DLC_DATABASE_NAME="${DLC_DATABASE_NAME}" go test -v . 2>&1 | grep -E "(PASS|FAIL|RUN)" || true FEATURE=${feature_name} DLC_DATABASE_NAME="${DLC_DATABASE_NAME}" go test -v . -tags="~@flaky && ~@todo && ~@skip" 2>&1 | grep -E "(PASS|FAIL|RUN)" || true
# Cleanup # Cleanup
cd ../.. cd ../..

View File

@@ -108,9 +108,9 @@ run_feature_tests() {
export DLC_DATABASE_SSL_MODE="disable" export DLC_DATABASE_SSL_MODE="disable"
export DLC_CONFIG_FILE="${CONFIG}" export DLC_CONFIG_FILE="${CONFIG}"
# Run tests with proper coverage measurement # Run tests with proper coverage measurement and tag exclusion
set +e set +e
test_output=$(go test ./features/${FEATURE}/... -v -cover -coverpkg=./... -coverprofile=coverage-${FEATURE}.out 2>&1) test_output=$(go test ./features/${FEATURE}/... -tags=~@flaky,~@todo,~@skip -v -cover -coverpkg=./... -coverprofile=coverage-${FEATURE}.out 2>&1)
test_exit_code=$? test_exit_code=$?
set -e set -e