✨ feat: add schema-per-scenario isolation with BDD_SCHEMA_ISOLATION env var
- Add BDD_SCHEMA_ISOLATION env var to enable PostgreSQL schema-per-scenario isolation
- Generate unique schema names: test_{sha256(feature:scenario)[:8]}
- Implement SetupScenarioSchema() and TeardownScenarioSchema() with search_path handling
- Add CASCADE drop to clean up all scenario-created DB objects
- Add isSchemaIsolationEnabled() helpers to both suite.go and server.go
- Skip table clearing when schema isolation is active (schema drop replaces it)
- Update validate-test-suite.sh to set FIXED_TEST_PORT and BDD_SCHEMA_ISOLATION
- Add isCleanupLoggingEnabled() for optional CLEANUP: prefixed logs
- Add ADR 0025 documenting all isolation strategies and decision rationale
Activation:
BDD_SCHEMA_ISOLATION=true - Enable schema-per-scenario isolation
BDD_ENABLE_CLEANUP_LOGS=true - Enable verbose cleanup/isolation logging
Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
@@ -42,11 +42,10 @@ func InitializeTestSuite(ctx *godog.TestSuiteContext) {
|
|||||||
|
|
||||||
sc := ctx.ScenarioContext()
|
sc := ctx.ScenarioContext()
|
||||||
sc.BeforeScenario(func(s *godog.Scenario) {
|
sc.BeforeScenario(func(s *godog.Scenario) {
|
||||||
// Get feature name from context or environment
|
// Get feature name from environment - falls back to "bdd" for multi-feature tests
|
||||||
feature := os.Getenv("FEATURE")
|
feature := os.Getenv("FEATURE")
|
||||||
if feature == "" {
|
if feature == "" {
|
||||||
// Try to extract feature from scenario tags or path
|
feature = "bdd"
|
||||||
feature = "unknown"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if isCleanupLoggingEnabled() {
|
if isCleanupLoggingEnabled() {
|
||||||
@@ -55,9 +54,14 @@ func InitializeTestSuite(ctx *godog.TestSuiteContext) {
|
|||||||
|
|
||||||
// Setup schema isolation if enabled
|
// Setup schema isolation if enabled
|
||||||
if sharedServer != nil {
|
if sharedServer != nil {
|
||||||
if err := sharedServer.SetupScenarioSchema(feature, s.Name); err != nil {
|
// Include scenario Uri for disambiguation when multiple features run
|
||||||
|
scenarioKey := s.Name
|
||||||
|
if s.Uri != "" {
|
||||||
|
scenarioKey = fmt.Sprintf("%s:%s", s.Uri, s.Name)
|
||||||
|
}
|
||||||
|
if err := sharedServer.SetupScenarioSchema(feature, scenarioKey); err != nil {
|
||||||
if isCleanupLoggingEnabled() {
|
if isCleanupLoggingEnabled() {
|
||||||
log.Warn().Err(err).Msg("ISOLATION: Failed to setup scenario schema")
|
log.Warn().Err(err).Str("feature", feature).Str("scenario", scenarioKey).Msg("ISOLATION: Failed to setup scenario schema")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,6 +55,9 @@ for (( run=1; run<=$RUN_COUNT; run++ )); do
|
|||||||
echo " 🧪 Unit tests..."
|
echo " 🧪 Unit tests..."
|
||||||
go clean -testcache > /dev/null 2>&1
|
go clean -testcache > /dev/null 2>&1
|
||||||
|
|
||||||
|
# Set environment variables for consistent test behavior
|
||||||
|
export FIXED_TEST_PORT=true
|
||||||
|
|
||||||
set +e # Temporarily disable exit on error
|
set +e # Temporarily disable exit on error
|
||||||
UNIT_OUTPUT=$(go test ./cmd/... ./pkg/... -v 2>&1)
|
UNIT_OUTPUT=$(go test ./cmd/... ./pkg/... -v 2>&1)
|
||||||
UNIT_EXIT_CODE=$?
|
UNIT_EXIT_CODE=$?
|
||||||
@@ -77,6 +80,15 @@ for (( run=1; run<=$RUN_COUNT; run++ )); do
|
|||||||
echo " 🧪 BDD tests..."
|
echo " 🧪 BDD tests..."
|
||||||
go clean -testcache > /dev/null 2>&1
|
go clean -testcache > /dev/null 2>&1
|
||||||
|
|
||||||
|
# Set environment variables for consistent BDD test behavior
|
||||||
|
export FIXED_TEST_PORT=true
|
||||||
|
export BDD_SCHEMA_ISOLATION=true
|
||||||
|
export DLC_DATABASE_HOST=localhost
|
||||||
|
export DLC_DATABASE_PORT=5432
|
||||||
|
export DLC_DATABASE_USER=postgres
|
||||||
|
export DLC_DATABASE_PASSWORD=postgres
|
||||||
|
export DLC_DATABASE_NAME=dance_lessons_coach_test
|
||||||
|
|
||||||
set +e # Temporarily disable exit on error
|
set +e # Temporarily disable exit on error
|
||||||
BDD_OUTPUT=$(go test ./features/... -v 2>&1)
|
BDD_OUTPUT=$(go test ./features/... -v 2>&1)
|
||||||
BDD_EXIT_CODE=$?
|
BDD_EXIT_CODE=$?
|
||||||
@@ -142,7 +154,7 @@ else
|
|||||||
# Process BDD test failures
|
# Process BDD test failures
|
||||||
if [ -s "$BDD_FAILURE_LOG" ]; then
|
if [ -s "$BDD_FAILURE_LOG" ]; then
|
||||||
echo "BDD Test Failures:"
|
echo "BDD Test Failures:"
|
||||||
echo "================"
|
echo "==============="
|
||||||
|
|
||||||
# Count BDD test failures with granularity
|
# Count BDD test failures with granularity
|
||||||
BDD_FAILURES=$(grep "FAIL" "$BDD_FAILURE_LOG" | \
|
BDD_FAILURES=$(grep "FAIL" "$BDD_FAILURE_LOG" | \
|
||||||
@@ -155,7 +167,7 @@ else
|
|||||||
while IFS= read -r line; do
|
while IFS= read -r line; do
|
||||||
count=$(echo "$line" | awk '{print $1}')
|
count=$(echo "$line" | awk '{print $1}')
|
||||||
test=$(echo "$line" | sed 's/^[0-9]*[[:space:]]*//')
|
test=$(echo "$line" | sed 's/^[0-9]*[[:space:]]*//')
|
||||||
echo " $count × $test"
|
echo " $count x $test"
|
||||||
done <<< "$BDD_FAILURES"
|
done <<< "$BDD_FAILURES"
|
||||||
else
|
else
|
||||||
echo " None (check log for details)"
|
echo " None (check log for details)"
|
||||||
@@ -182,4 +194,4 @@ else
|
|||||||
echo " 5. Use ./scripts/run-bdd-tests.sh list-tags to see available tags"
|
echo " 5. Use ./scripts/run-bdd-tests.sh list-tags to see available tags"
|
||||||
|
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|||||||
Reference in New Issue
Block a user