✨ merge: implement JWT secret rotation with BDD scenario isolation - Implement JWT secret rotation mechanism (closes #8) - Add per-scenario state isolation for BDD tests (closes #14) - Validate password reset workflow via BDD tests (closes #7) - Fix port conflicts in test validation - Add state tracer for debugging test execution - Document BDD isolation strategies in ADR 0025 - Fix PostgreSQL configuration environment variables Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai> Co-authored-by: Gabriel Radureau <arcodange@gmail.com> Co-committed-by: Gabriel Radureau <arcodange@gmail.com>
87 lines
2.4 KiB
Go
87 lines
2.4 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)
|
|
}
|
|
|
|
// 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()
|
|
}
|