diff --git a/limit_test.go b/limit_test.go index 6cf8bcf..7845837 100644 --- a/limit_test.go +++ b/limit_test.go @@ -17,22 +17,60 @@ const ( sleep = time.Microsecond * 10 ) -func TestLimit(t *testing.T) { +func TestLimitSilent(t *testing.T) { + testLimit(t, false) +} + +func TestLimitVerbose(t *testing.T) { + testLimit(t, true) +} + +func testLimit(t *testing.T, withStuck bool) { t.Parallel() var running int32 var wg sync.WaitGroup limit := simultaneous.New[any](max) + var stuckCalled atomic.Int32 + var unstuckCalled atomic.Int32 + someUnstuck := make(chan struct{}) + + if withStuck { + limit = limit.SetForeverMessaging(time.Millisecond, + func() { + if stuckCalled.Add(1) == 1 { + close(someUnstuck) + } + }, + func() { + unstuckCalled.Add(1) + }, + ) + } + + var fail atomic.Int32 + var success atomic.Int32 + for i := 0; i < threadCount; i++ { i := i wg.Add(1) go func() { defer wg.Done() var done simultaneous.Limited[any] - if i%2 == 0 { + switch i % 3 { + case 0: done = limit.Forever() - } else { + case 1: + var err error + done, err = limit.Timeout(0) + if err != nil { + fail.Add(1) + return + } else { + success.Add(1) + } + case 2: var err error done, err = limit.Timeout(time.Second * 2) if !assert.NoError(t, err) { @@ -42,8 +80,20 @@ func TestLimit(t *testing.T) { assert.LessOrEqual(t, atomic.AddInt32(&running, 1), int32(max)) time.Sleep(sleep) assert.GreaterOrEqual(t, atomic.AddInt32(&running, -1), int32(0)) + if withStuck { + <-someUnstuck + } done.Done() }() } wg.Wait() + + if withStuck { + t.Logf("stuck called %d unstuck called %d", stuckCalled.Load(), unstuckCalled.Load()) + assert.NotZero(t, stuckCalled.Load(), "stuck reported") + assert.Equal(t, stuckCalled.Load(), unstuckCalled.Load(), "stuck == unstuck") + } + t.Logf("timeout 0 failed %d succeeded %d", fail.Load(), success.Load()) + assert.NotZero(t, fail.Load(), "fail") + assert.NotZero(t, success.Load(), "succeed") }