Files
dance-lessons-coach/pkg/bdd/testserver/state_tracer.go
Gabriel Radureau 63d27cc35e
All checks were successful
CI/CD Pipeline / Build Docker Cache (push) Successful in 12s
CI/CD Pipeline / CI Pipeline (push) Successful in 8m44s
CI/CD Pipeline / Trigger Docker Push (push) Has been skipped
🐛 fix(bdd): revert PR #26 schema isolation, add cache flush + sequential test execution
PR #26 added BDD_SCHEMA_ISOLATION=true to CI but this creates per-scenario schemas
WITHOUT running migrations on them, causing 500 errors on user registration. This
PR reverts that and instead relies on:

1. The existing CleanupDatabase hook (truncates all tables AfterScenario)
2. Sequential test package execution (-p 1) to avoid contention between feature
   packages sharing the same Postgres DB

Plus defensive additions for future-proofing:
- pkg/server/server.go: GetCacheService() exposed for test cleanup
- pkg/bdd/testserver/server.go: cacheService field + FlushCache() method
- pkg/bdd/testserver/state_tracer.go: TraceStateCacheOperation
- pkg/bdd/suite.go: AfterScenario hook calls FlushCache()
- scripts/run-bdd-tests.sh: -p 1 added (sequential package execution)

Validation:
- AuthBDD alone: 5/5 PASS (was 0/5 with broken schema isolation)
- Full features/ via run-bdd-tests.sh: ALL PASS (auth, config, greet, health, jwt)

Out of scope (follow-up T12):
- Proper parallel BDD with schema migrations per scenario + dedicated connection
  pools. Required for scaling tests but architecturally significant. Tracked.

Co-Authored-By: Mistral Vibe (devstral-2 / mistral-medium-3.5) - cache flush diagnosis
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> - root cause + revert
2026-05-03 16:28:21 +02:00

92 lines
2.6 KiB
Go

package testserver
import (
"fmt"
"os"
"path/filepath"
"time"
)
// TraceStateScenarioStart logs the start of a scenario
func TraceStateScenarioStart(feature, scenario string) {
writeTraceLine(feature, scenario, "SCENARIO_START", "")
}
// TraceStateScenarioEnd logs the end of a scenario
func TraceStateScenarioEnd(feature, scenario string, err error) {
status := "PASSED"
if err != nil {
status = fmt.Sprintf("FAILED: %v", err)
}
writeTraceLine(feature, scenario, "SCENARIO_END", status)
}
// TraceStateDBCleanup logs a database cleanup operation
func TraceStateDBCleanup(feature, scenario, table string) {
writeTraceLine(feature, scenario, "DB_CLEANUP", table)
}
// TraceStateJWTSecretOperation logs a JWT secret operation
func TraceStateJWTSecretOperation(feature, scenario, operation, details string) {
writeTraceLine(feature, scenario, "JWT_"+operation, details)
}
// TraceStateCacheOperation logs a cache operation
func TraceStateCacheOperation(feature, scenario, operation, details string) {
writeTraceLine(feature, scenario, "CACHE_"+operation, details)
}
// TraceStateSchemaIsolation logs a schema isolation operation
func TraceStateSchemaIsolation(feature, scenario, operation, details string) {
writeTraceLine(feature, scenario, "SCHEMA_"+operation, details)
}
// TraceStateTransaction logs a transaction boundary
func TraceStateTransaction(feature, scenario, action, details string) {
writeTraceLine(feature, scenario, "TX_"+action, details)
}
// TraceStateDBRead logs a database read operation
func TraceStateDBRead(feature, scenario, table, details string) {
writeTraceLine(feature, scenario, "DB_SELECT", fmt.Sprintf("table=%s %s", table, details))
}
// StateTracingEnabled returns true if BDD_TRACE_STATE environment variable is set to "1"
func StateTracingEnabled() bool {
return os.Getenv("BDD_TRACE_STATE") == "1"
}
// writeTraceLine writes a trace line to the state trace file in $TMPDIR
func writeTraceLine(feature, scenario, action, details string) {
if !StateTracingEnabled() {
return
}
tmpDir := os.Getenv("TMPDIR")
if tmpDir == "" {
tmpDir = "/tmp"
}
timestamp := time.Now().Format("20060102-150405")
pid := os.Getpid()
filename := fmt.Sprintf("bdd-state-trace-%s-%d.log", timestamp, pid)
filePath := filepath.Join(tmpDir, filename)
line := fmt.Sprintf("%s | %-15s | %-40s | %-16s | %s\n",
time.Now().Format("2006-01-02T15:04:05.000000"),
feature,
scenario,
action,
details,
)
file, err := os.OpenFile(filePath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
return
}
defer file.Close()
if _, err := file.WriteString(line); err != nil {
return
}
file.Sync()
}