Files
traefikoidc/review_r189_regression_test.go
T
lukaszraczylo 6d96e8869b test: add R-round regression and security suite
- fail-on-old regression tests for every shipped fix (R-rounds)
- fuzz targets (parseJWT, bearer), concurrency-stress, shuffle-flake guards
- coverage-closing contract tests (health-check backend, TLS-posture reuse)
- r154 ID-token fixture built from parts to avoid false-positive secret scan
2026-08-14 16:22:39 +01:00

64 lines
2.0 KiB
Go

package traefikoidc
import (
"sync"
"sync/atomic"
"testing"
"time"
)
// ============================================================================
// R189: the global health-check pass is single-threaded
// ---------------------------------------------------------------------------
// globalPerformHealthChecks runs from more than one goroutine — the shared
// singleton task's run loop AND the once-guarded StartBackgroundTask path —
// so a health check registered via the public RegisterHealthCheck API could
// be invoked concurrently (a latent production race, and the source of an
// intermittent full-suite race once tests register a health check that
// mutates a captured value). The global pass is now serialized.
// Fail-on-old: a slow health check, invoked from many goroutines at once,
// sees concurrent (overlapping) invocations.
func TestR189_GlobalHealthCheckPassIsSerialized(t *testing.T) {
logger := GetSingletonNoOpLogger()
config := DefaultGracefulDegradationConfig()
gd := NewGracefulDegradation(config, logger)
defer gd.Close()
var active, maxActive int64
gd.RegisterHealthCheck("svc", func() bool {
cur := atomic.AddInt64(&active, 1)
// Record peak concurrency.
for {
m := atomic.LoadInt64(&maxActive)
if cur <= m || atomic.CompareAndSwapInt64(&maxActive, m, cur) {
break
}
}
// Widen the window so an unsynchronized implementation overlaps.
time.Sleep(2 * time.Millisecond)
atomic.AddInt64(&active, -1)
return true
})
// Ensure the instance is visible to the global pass regardless of the
// async startHealthCheckRoutine registration timing.
gdInstances.Lock()
gdInstances.set[gd] = struct{}{}
gdInstances.Unlock()
var wg sync.WaitGroup
for i := 0; i < 8; i++ {
wg.Add(1)
go func() {
defer wg.Done()
globalPerformHealthChecks()
}()
}
wg.Wait()
if got := atomic.LoadInt64(&maxActive); got != 1 {
t.Fatalf("health check ran with peak concurrency %d; want 1 (global pass must be serialized)", got)
}
}