github.com/lmb/consul@v1.4.1/lib/semaphore/semaphore_test.go (about) 1 package semaphore 2 3 // Based on https://github.com/golang/sync/blob/master/semaphore/semaphore_test.go 4 5 import ( 6 "context" 7 "math/rand" 8 "runtime" 9 "sync" 10 "testing" 11 "time" 12 13 "github.com/stretchr/testify/require" 14 ) 15 16 const maxSleep = 1 * time.Millisecond 17 18 func HammerDynamic(sem *Dynamic, loops int) { 19 for i := 0; i < loops; i++ { 20 sem.Acquire(context.Background()) 21 time.Sleep(time.Duration(rand.Int63n(int64(maxSleep/time.Nanosecond))) * time.Nanosecond) 22 sem.Release() 23 } 24 } 25 26 // TestDynamic hammers the semaphore from all available cores to ensure we don't 27 // hit a panic or race detector notice something wonky. 28 func TestDynamic(t *testing.T) { 29 t.Parallel() 30 31 n := runtime.GOMAXPROCS(0) 32 loops := 10000 / n 33 sem := NewDynamic(int64(n)) 34 var wg sync.WaitGroup 35 wg.Add(n) 36 for i := 0; i < n; i++ { 37 go func() { 38 defer wg.Done() 39 HammerDynamic(sem, loops) 40 }() 41 } 42 wg.Wait() 43 } 44 45 func TestDynamicPanic(t *testing.T) { 46 t.Parallel() 47 48 defer func() { 49 if recover() == nil { 50 t.Fatal("release of an unacquired dynamic semaphore did not panic") 51 } 52 }() 53 w := NewDynamic(1) 54 w.Release() 55 } 56 57 func checkAcquire(t *testing.T, sem *Dynamic, wantAcquire bool) { 58 t.Helper() 59 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond) 60 defer cancel() 61 err := sem.Acquire(ctx) 62 if wantAcquire { 63 require.NoErrorf(t, err, "failed to acquire when we should have") 64 } else { 65 require.Error(t, err, "failed to block when should be full") 66 } 67 } 68 69 func TestDynamicAcquire(t *testing.T) { 70 t.Parallel() 71 72 ctx := context.Background() 73 sem := NewDynamic(2) 74 75 // Consume one slot [free: 1] 76 sem.Acquire(ctx) 77 // Should be able to consume another [free: 0] 78 checkAcquire(t, sem, true) 79 // Should fail to consume another [free: 0] 80 checkAcquire(t, sem, false) 81 82 // Release 2 83 sem.Release() 84 sem.Release() 85 86 // Should be able to consume another [free: 1] 87 checkAcquire(t, sem, true) 88 // Should be able to consume another [free: 0] 89 checkAcquire(t, sem, true) 90 // Should fail to consume another [free: 0] 91 checkAcquire(t, sem, false) 92 93 // Now expand the semaphore and we should be able to acquire again [free: 2] 94 sem.SetSize(4) 95 96 // Should be able to consume another [free: 1] 97 checkAcquire(t, sem, true) 98 // Should be able to consume another [free: 0] 99 checkAcquire(t, sem, true) 100 // Should fail to consume another [free: 0] 101 checkAcquire(t, sem, false) 102 103 // Shrinking it should work [free: 0] 104 sem.SetSize(3) 105 106 // Should fail to consume another [free: 0] 107 checkAcquire(t, sem, false) 108 109 // Release one [free: 0] (3 slots used are release, size only 3) 110 sem.Release() 111 112 // Should fail to consume another [free: 0] 113 checkAcquire(t, sem, false) 114 115 sem.Release() 116 117 // Should be able to consume another [free: 1] 118 checkAcquire(t, sem, true) 119 }