veza/veza-backend-api/internal/testutils/parallel.go

108 lines
2.4 KiB
Go
Raw Normal View History

2025-12-03 19:29:37 +00:00
package testutils
import (
"sync"
"testing"
)
var (
parallelLock sync.Mutex
)
// SetupParallelTest configure un test pour exécution parallèle (T0048)
func SetupParallelTest(t *testing.T) {
t.Parallel()
// Acquérir un lock si ressources partagées
// parallelLock.Lock()
// t.Cleanup(func() { parallelLock.Unlock() })
}
// RunParallelTests exécute plusieurs tests en parallèle (T0048)
2025-12-16 16:23:49 +00:00
// Note: The sub-tests created by t.Run() already call t.Parallel(), so testFuncs
// should NOT call SetupParallelTest() or t.Parallel() themselves to avoid "t.Parallel called multiple times" panic
// The parent test must wait for all sub-tests to complete
2025-12-03 19:29:37 +00:00
func RunParallelTests(t *testing.T, testFuncs map[string]func(*testing.T)) {
2025-12-16 16:23:49 +00:00
// Use t.Run() which automatically waits for all sub-tests to complete
// Each sub-test calls t.Parallel() to run in parallel
2025-12-03 19:29:37 +00:00
for name, fn := range testFuncs {
2025-12-16 16:23:49 +00:00
t.Run(name, func(t *testing.T) {
t.Parallel()
fn(t)
})
2025-12-03 19:29:37 +00:00
}
2025-12-16 16:23:49 +00:00
// t.Run() blocks until all sub-tests complete, so we don't need WaitGroup
2025-12-03 19:29:37 +00:00
}
// WithLock exécute une fonction avec un lock partagé (T0048)
func WithLock(fn func()) {
parallelLock.Lock()
defer parallelLock.Unlock()
fn()
}
// TestLockManager gère les locks pour les tests parallèles (T0048)
type TestLockManager struct {
locks map[string]*sync.Mutex
mu sync.RWMutex
}
// NewTestLockManager crée un nouveau gestionnaire de locks (T0048)
func NewTestLockManager() *TestLockManager {
return &TestLockManager{
locks: make(map[string]*sync.Mutex),
}
}
// Lock acquiert un lock nommé (T0048)
func (tm *TestLockManager) Lock(name string) func() {
tm.mu.Lock()
lock, exists := tm.locks[name]
if !exists {
lock = &sync.Mutex{}
tm.locks[name] = lock
}
tm.mu.Unlock()
lock.Lock()
return func() {
lock.Unlock()
}
}
// Example usage:
/*
func TestParallel(t *testing.T) {
testFuncs := map[string]func(*testing.T){
"test1": func(t *testing.T) {
SetupParallelTest(t)
// Test code
},
"test2": func(t *testing.T) {
SetupParallelTest(t)
// Test code
},
}
RunParallelTests(t, testFuncs)
}
func TestWithSharedResource(t *testing.T) {
t.Parallel()
WithLock(func() {
// Code qui nécessite un lock
})
}
func TestWithNamedLock(t *testing.T) {
t.Parallel()
lockManager := NewTestLockManager()
unlock := lockManager.Lock("resource1")
defer unlock()
// Code qui nécessite un lock nommé
}
*/