From c13ca96fac2b33970b1ade6994704d7bc3f9ad6c Mon Sep 17 00:00:00 2001 From: illia-li Date: Thu, 21 Nov 2024 00:32:15 -0400 Subject: [PATCH] add `debounce` tests --- debounce/simple_debouncer_test.go | 134 ++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) diff --git a/debounce/simple_debouncer_test.go b/debounce/simple_debouncer_test.go index b11feddd4..fd9e55b4e 100644 --- a/debounce/simple_debouncer_test.go +++ b/debounce/simple_debouncer_test.go @@ -5,10 +5,143 @@ package debounce import ( "runtime" + "sync" "sync/atomic" "testing" + "time" ) +// TestSimpleDebouncerRace tests SimpleDebouncer for the fact that it does not allow concurrent writing, reading. +func TestSimpleDebouncerRace(t *testing.T) { + operations := 1000 + runs := 100 + count := 3 + + d := NewSimpleDebouncer() + for r := 0; r < runs; r++ { + var counter atomic.Int32 + var wg sync.WaitGroup + wg.Add(count) + + results := make([]bool, count) + fails := make([]bool, count) + for c := range results { + result := &results[c] + fail := &fails[c] + + go func() { + *result = d.Debounce(func() { + for i := 0; i < operations; i++ { + if counter.Add(1) != 1 { + *fail = true + } + time.Sleep(time.Microsecond) + counter.Add(-1) + } + }) + wg.Done() + }() + } + wg.Wait() + + // check results + + finished := 0 + for i, done := range results { + if done { + finished++ + } + if fails[i] { + t.Fatalf("Simultaneous execution detected") + } + } + if finished < 2 { + t.Fatalf("In one run should be finished more than 2 `Debounce` method calls, but finished %d", finished) + } + } +} + +// TestDebouncerExtreme tests SimpleDebouncer in the conditions fast multi `Debounce` method calls and fast execution of the `debounced function`. +func TestDebouncerExtreme(t *testing.T) { + type runResult struct { + executedN int32 + done bool + } + + runs := 10000 + count := 20 + + d := NewSimpleDebouncer() + var wg sync.WaitGroup + for r := 0; r < runs; r++ { + var executionsC atomic.Int32 + wg.Add(count) + + results := make([]runResult, count) + + for c := range results { + result := &results[c] + + go func() { + result.done = d.Debounce(func() { + result.executedN = executionsC.Add(1) + }) + wg.Done() + }() + } + wg.Wait() + + // check results + finished := 0 + for _, result := range results { + if result.done { + if result.executedN == 0 { + t.Fatalf("Wrong execution detected: \n%#v", result) + } + finished++ + } + } + if finished < 2 { + t.Fatalf("In one run should be finished more than 2 `Debounce` method calls, but finished %d", finished) + } + } +} + +// TestSimpleDebouncerCount tests SimpleDebouncer for the fact that it pended only one function call. +func TestSimpleDebouncerCount(t *testing.T) { + calls := 10 + + d := NewSimpleDebouncer() + var prepared, start, done sync.WaitGroup + prepared.Add(calls - 1) + start.Add(1) + done.Add(calls - 1) + + finished := 0 + for c := 0; c < calls-1; c++ { + go func() { + prepared.Done() + start.Wait() + d.Debounce(func() { + finished++ + }) + done.Done() + }() + } + d.Debounce(func() { + prepared.Wait() + start.Done() + finished++ + time.Sleep(time.Second) + }) + done.Wait() + + // check results + if finished != 2 { + t.Fatalf("Should be finished more than 2 `Debounce` method calls, but finished %d", finished) + } +} + // TestDebouncer tests that the debouncer allows only one function to execute at a time func TestSimpleDebouncer(t *testing.T) { t.Skip("This test sometimes ends vai panic. Issue https://github.com/scylladb/gocql/pull/344") @@ -16,6 +149,7 @@ func TestSimpleDebouncer(t *testing.T) { var executions int32 startedCh := make(chan struct{}, 1) doneCh := make(chan struct{}, 1) + // Function to increment executions fn := func() { <-startedCh // Simulate work