github.com/prysmaticlabs/prysm@v1.4.4/shared/asyncutil/debounce_test.go (about)

     1  package asyncutil
     2  
     3  import (
     4  	"context"
     5  	"sync"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/prysmaticlabs/prysm/shared/testutil"
    10  	"github.com/prysmaticlabs/prysm/shared/testutil/assert"
    11  	"github.com/prysmaticlabs/prysm/shared/testutil/require"
    12  )
    13  
    14  func TestDebounce_NoEvents(t *testing.T) {
    15  	eventsChan := make(chan interface{}, 100)
    16  	ctx, cancel := context.WithCancel(context.Background())
    17  	interval := time.Second
    18  	timesHandled := 0
    19  	wg := &sync.WaitGroup{}
    20  	wg.Add(1)
    21  	go func() {
    22  		time.AfterFunc(interval, func() {
    23  			cancel()
    24  		})
    25  	}()
    26  	go func() {
    27  		Debounce(ctx, interval, eventsChan, func(event interface{}) {
    28  			timesHandled++
    29  		})
    30  		wg.Done()
    31  	}()
    32  	if testutil.WaitTimeout(wg, interval*2) {
    33  		t.Fatalf("Test should have exited by now, timed out")
    34  	}
    35  	assert.Equal(t, 0, timesHandled, "Wrong number of handled calls")
    36  }
    37  
    38  func TestDebounce_CtxClosing(t *testing.T) {
    39  	eventsChan := make(chan interface{}, 100)
    40  	ctx, cancel := context.WithCancel(context.Background())
    41  	interval := time.Second
    42  	timesHandled := 0
    43  	wg := &sync.WaitGroup{}
    44  	wg.Add(1)
    45  	go func() {
    46  		ticker := time.NewTicker(time.Millisecond * 100)
    47  		defer ticker.Stop()
    48  		for {
    49  			select {
    50  			case <-ctx.Done():
    51  				return
    52  			case <-ticker.C:
    53  				eventsChan <- struct{}{}
    54  			}
    55  		}
    56  	}()
    57  	go func() {
    58  		time.AfterFunc(interval, func() {
    59  			cancel()
    60  		})
    61  	}()
    62  	go func() {
    63  		Debounce(ctx, interval, eventsChan, func(event interface{}) {
    64  			timesHandled++
    65  		})
    66  		wg.Done()
    67  	}()
    68  	if testutil.WaitTimeout(wg, interval*2) {
    69  		t.Fatalf("Test should have exited by now, timed out")
    70  	}
    71  	assert.Equal(t, 0, timesHandled, "Wrong number of handled calls")
    72  }
    73  
    74  func TestDebounce_SingleHandlerInvocation(t *testing.T) {
    75  	eventsChan := make(chan interface{}, 100)
    76  	ctx, cancel := context.WithCancel(context.Background())
    77  	interval := time.Second
    78  	timesHandled := 0
    79  	go Debounce(ctx, interval, eventsChan, func(event interface{}) {
    80  		timesHandled++
    81  	})
    82  	for i := 0; i < 100; i++ {
    83  		eventsChan <- struct{}{}
    84  	}
    85  	// We should expect 100 rapid fire changes to only have caused
    86  	// 1 handler to trigger after the debouncing period.
    87  	time.Sleep(interval * 2)
    88  	assert.Equal(t, 1, timesHandled, "Wrong number of handled calls")
    89  	cancel()
    90  }
    91  
    92  func TestDebounce_MultipleHandlerInvocation(t *testing.T) {
    93  	eventsChan := make(chan interface{}, 100)
    94  	ctx, cancel := context.WithCancel(context.Background())
    95  	interval := time.Second
    96  	timesHandled := 0
    97  	go Debounce(ctx, interval, eventsChan, func(event interface{}) {
    98  		timesHandled++
    99  	})
   100  	for i := 0; i < 100; i++ {
   101  		eventsChan <- struct{}{}
   102  	}
   103  	require.Equal(t, 0, timesHandled, "Events must prevent from handler execution")
   104  
   105  	// By this time the first event should be triggered.
   106  	time.Sleep(2 * time.Second)
   107  	assert.Equal(t, 1, timesHandled, "Wrong number of handled calls")
   108  
   109  	// Second event.
   110  	eventsChan <- struct{}{}
   111  	time.Sleep(2 * time.Second)
   112  	assert.Equal(t, 2, timesHandled, "Wrong number of handled calls")
   113  
   114  	cancel()
   115  }