github.com/xmidt-org/webpa-common@v1.11.9/capacitor/capacitor_test.go (about)

     1  package capacitor
     2  
     3  import (
     4  	"fmt"
     5  	"sync"
     6  	"sync/atomic"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/mock"
    12  	"github.com/stretchr/testify/require"
    13  	"github.com/xmidt-org/webpa-common/clock/clocktest"
    14  )
    15  
    16  func ExampleBasicUsage() {
    17  	var (
    18  		c = New()
    19  		w = new(sync.WaitGroup)
    20  	)
    21  
    22  	w.Add(1)
    23  
    24  	// this may or may not be executed, depending on timing of the machine where this is run
    25  	c.Submit(func() {})
    26  
    27  	// we'll wait until this is executed
    28  	c.Submit(func() {
    29  		fmt.Println("Discharged")
    30  		w.Done()
    31  	})
    32  
    33  	w.Wait()
    34  
    35  	// Output:
    36  	// Discharged
    37  }
    38  
    39  func testWithDelayDefault(t *testing.T) {
    40  	var (
    41  		assert = assert.New(t)
    42  		c      = new(capacitor)
    43  	)
    44  
    45  	WithDelay(0)(c)
    46  	assert.Equal(DefaultDelay, c.delay)
    47  }
    48  
    49  func testWithDelayCustom(t *testing.T) {
    50  	var (
    51  		assert = assert.New(t)
    52  		c      = new(capacitor)
    53  	)
    54  
    55  	WithDelay(31 * time.Minute)(c)
    56  	assert.Equal(31*time.Minute, c.delay)
    57  }
    58  
    59  func TestWithDelay(t *testing.T) {
    60  	t.Run("Default", testWithDelayDefault)
    61  	t.Run("Custom", testWithDelayCustom)
    62  }
    63  
    64  func testWithClockDefault(t *testing.T) {
    65  	var (
    66  		assert = assert.New(t)
    67  		c      = new(capacitor)
    68  	)
    69  
    70  	WithClock(nil)(c)
    71  	assert.NotNil(c.c)
    72  }
    73  
    74  func testWithClockCustom(t *testing.T) {
    75  	var (
    76  		assert = assert.New(t)
    77  		cl     = new(clocktest.Mock)
    78  		c      = new(capacitor)
    79  	)
    80  
    81  	WithClock(cl)(c)
    82  	assert.Equal(cl, c.c)
    83  }
    84  
    85  func TestWithClock(t *testing.T) {
    86  	t.Run("Default", testWithClockDefault)
    87  	t.Run("Custom", testWithClockCustom)
    88  }
    89  
    90  func testCapacitorSubmit(t *testing.T) {
    91  	var (
    92  		assert  = assert.New(t)
    93  		require = require.New(t)
    94  
    95  		stopped = make(chan struct{})
    96  		calls   int32
    97  		f       = func() {
    98  			atomic.AddInt32(&calls, 1)
    99  		}
   100  
   101  		cl      = new(clocktest.Mock)
   102  		timer   = new(clocktest.MockTimer)
   103  		trigger = make(chan time.Time, 1)
   104  		c       = New(WithDelay(time.Minute), WithClock(cl))
   105  	)
   106  
   107  	require.NotNil(c)
   108  	cl.OnNewTimer(time.Minute, timer).Once()
   109  	timer.OnC(trigger).Once()
   110  	timer.OnStop(true).Once().Run(func(mock.Arguments) {
   111  		close(stopped)
   112  	})
   113  
   114  	for i := 0; i < 10; i++ {
   115  		c.Submit(f)
   116  	}
   117  
   118  	trigger <- time.Time{}
   119  
   120  	select {
   121  	case <-stopped:
   122  		// passing
   123  	case <-time.After(5 * time.Second):
   124  		assert.Fail("The capacitor did not discharge properly")
   125  	}
   126  
   127  	cl.AssertExpectations(t)
   128  	timer.AssertExpectations(t)
   129  	assert.Equal(int32(1), atomic.LoadInt32(&calls))
   130  }
   131  
   132  func testCapacitorDischarge(t *testing.T) {
   133  	var (
   134  		assert  = assert.New(t)
   135  		require = require.New(t)
   136  
   137  		stopped = make(chan struct{})
   138  		calls   int32
   139  		f       = func() {
   140  			atomic.AddInt32(&calls, 1)
   141  		}
   142  
   143  		cl      = new(clocktest.Mock)
   144  		timer   = new(clocktest.MockTimer)
   145  		trigger = make(chan time.Time)
   146  		c       = New(WithDelay(time.Minute), WithClock(cl))
   147  	)
   148  
   149  	require.NotNil(c)
   150  	cl.OnNewTimer(time.Minute, timer).Once()
   151  	timer.OnC(trigger).Once()
   152  	timer.OnStop(true).Once().Run(func(mock.Arguments) {
   153  		close(stopped)
   154  	})
   155  
   156  	for i := 0; i < 10; i++ {
   157  		c.Submit(f)
   158  	}
   159  
   160  	c.Discharge()
   161  	c.Discharge() // idempotent
   162  
   163  	select {
   164  	case <-stopped:
   165  		// passing
   166  	case <-time.After(5 * time.Second):
   167  		assert.Fail("The capacitor did not discharge properly")
   168  	}
   169  
   170  	cl.AssertExpectations(t)
   171  	timer.AssertExpectations(t)
   172  	assert.Equal(int32(1), atomic.LoadInt32(&calls))
   173  }
   174  
   175  func testCapacitorCancel(t *testing.T) {
   176  	var (
   177  		assert  = assert.New(t)
   178  		require = require.New(t)
   179  
   180  		stopped = make(chan struct{})
   181  		calls   int32
   182  		f       = func() {
   183  			atomic.AddInt32(&calls, 1)
   184  		}
   185  
   186  		cl      = new(clocktest.Mock)
   187  		timer   = new(clocktest.MockTimer)
   188  		trigger = make(chan time.Time)
   189  		c       = New(WithDelay(time.Minute), WithClock(cl))
   190  	)
   191  
   192  	require.NotNil(c)
   193  	cl.OnNewTimer(time.Minute, timer).Once()
   194  	timer.OnC(trigger).Once()
   195  	timer.OnStop(true).Once().Run(func(mock.Arguments) {
   196  		close(stopped)
   197  	})
   198  
   199  	for i := 0; i < 10; i++ {
   200  		c.Submit(f)
   201  	}
   202  
   203  	c.Cancel()
   204  	c.Cancel() // idempotent
   205  
   206  	select {
   207  	case <-stopped:
   208  		// passing
   209  	case <-time.After(5 * time.Second):
   210  		assert.Fail("The capacitor did not discharge properly")
   211  	}
   212  
   213  	cl.AssertExpectations(t)
   214  	timer.AssertExpectations(t)
   215  	assert.Zero(atomic.LoadInt32(&calls))
   216  }
   217  
   218  func TestCapacitor(t *testing.T) {
   219  	t.Run("Submit", testCapacitorSubmit)
   220  	t.Run("Discharge", testCapacitorDischarge)
   221  	t.Run("Cancel", testCapacitorCancel)
   222  }