github.com/mailgun/holster/v4@v4.20.0/clock/frozen_test.go (about)

     1  package clock
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/stretchr/testify/suite"
     9  )
    10  
    11  func TestFreezeUnfreeze(t *testing.T) {
    12  	Freeze(Now()).Unfreeze()
    13  }
    14  
    15  type FrozenSuite struct {
    16  	suite.Suite
    17  	epoch time.Time
    18  }
    19  
    20  func TestFrozenSuite(t *testing.T) {
    21  	suite.Run(t, new(FrozenSuite))
    22  }
    23  
    24  func (s *FrozenSuite) SetupSuite() {
    25  	var err error
    26  	s.epoch, err = time.Parse(time.RFC3339, "2009-02-19T00:00:00Z")
    27  	s.Require().NoError(err)
    28  }
    29  
    30  func (s *FrozenSuite) SetupTest() {
    31  	Freeze(s.epoch)
    32  }
    33  
    34  func (s *FrozenSuite) TearDownTest() {
    35  	Unfreeze()
    36  }
    37  
    38  func (s *FrozenSuite) TestAdvanceNow() {
    39  	s.Require().Equal(s.epoch, Now())
    40  	s.Require().Equal(42*time.Millisecond, Advance(42*time.Millisecond))
    41  	s.Require().Equal(s.epoch.Add(42*time.Millisecond), Now())
    42  	s.Require().Equal(55*time.Millisecond, Advance(13*time.Millisecond))
    43  	s.Require().Equal(74*time.Millisecond, Advance(19*time.Millisecond))
    44  	s.Require().Equal(s.epoch.Add(74*time.Millisecond), Now())
    45  }
    46  
    47  func (s *FrozenSuite) TestSleep() {
    48  	s.T().Skip("TODO: fix DATA RACE and enable(https://github.com/mailgun/holster/issues/147)")
    49  
    50  	hits := make(chan int, 100)
    51  
    52  	delays := []int{60, 100, 90, 131, 999, 5}
    53  	for i, tc := range []struct {
    54  		desc string
    55  		fn   func(delayMs int)
    56  	}{{
    57  		desc: "Sleep",
    58  		fn: func(delay int) {
    59  			Sleep(time.Duration(delay) * time.Millisecond)
    60  			hits <- delay
    61  		},
    62  	}, {
    63  		desc: "After",
    64  		fn: func(delay int) {
    65  			<-After(time.Duration(delay) * time.Millisecond)
    66  			hits <- delay
    67  		},
    68  	}, {
    69  		desc: "AfterFunc",
    70  		fn: func(delay int) {
    71  			AfterFunc(time.Duration(delay)*time.Millisecond,
    72  				func() {
    73  					hits <- delay
    74  				})
    75  		},
    76  	}, {
    77  		desc: "NewTimer",
    78  		fn: func(delay int) {
    79  			t := NewTimer(time.Duration(delay) * time.Millisecond)
    80  			<-t.C()
    81  			hits <- delay
    82  		},
    83  	}} {
    84  		fmt.Printf("Test case #%d: %s", i, tc.desc)
    85  		for _, delay := range delays {
    86  			go tc.fn(delay)
    87  		}
    88  		// Spin-wait for all goroutines to fall asleep.
    89  		ft := provider.(*frozenTime)
    90  		for {
    91  			if len(ft.timers) == len(delays) {
    92  				break
    93  			}
    94  			time.Sleep(10 * time.Millisecond)
    95  		}
    96  
    97  		runningMs := 0
    98  		for i, delayMs := range []int{5, 60, 90, 100, 131, 999} {
    99  			fmt.Printf("Checking timer #%d, delay=%d\n", i, delayMs)
   100  			delta := delayMs - runningMs - 1
   101  			Advance(time.Duration(delta) * time.Millisecond)
   102  			// Check before each timer deadline that it is not triggered yet.
   103  			s.assertHits(hits, []int{})
   104  
   105  			// When
   106  			Advance(1 * time.Millisecond)
   107  
   108  			// Then
   109  			s.assertHits(hits, []int{delayMs})
   110  
   111  			runningMs += delta + 1
   112  		}
   113  
   114  		Advance(1000 * time.Millisecond)
   115  		s.assertHits(hits, []int{})
   116  	}
   117  }
   118  
   119  // Timers scheduled to trigger at the same time do that in the order they were
   120  // created.
   121  func (s *FrozenSuite) TestSameTime() {
   122  	var hits []int
   123  
   124  	AfterFunc(100, func() { hits = append(hits, 3) })
   125  	AfterFunc(100, func() { hits = append(hits, 1) })
   126  	AfterFunc(99, func() { hits = append(hits, 2) })
   127  	AfterFunc(100, func() { hits = append(hits, 5) })
   128  	AfterFunc(101, func() { hits = append(hits, 4) })
   129  	AfterFunc(101, func() { hits = append(hits, 6) })
   130  
   131  	// When
   132  	Advance(100)
   133  
   134  	// Then
   135  	s.Require().Equal([]int{2, 3, 1, 5}, hits)
   136  }
   137  
   138  func (s *FrozenSuite) TestTimerStop() {
   139  	hits := []int{}
   140  
   141  	AfterFunc(100, func() { hits = append(hits, 1) })
   142  	t := AfterFunc(100, func() { hits = append(hits, 2) })
   143  	AfterFunc(100, func() { hits = append(hits, 3) })
   144  	Advance(99)
   145  	s.Require().Equal([]int{}, hits)
   146  
   147  	// When
   148  	active1 := t.Stop()
   149  	active2 := t.Stop()
   150  
   151  	// Then
   152  	s.Require().Equal(true, active1)
   153  	s.Require().Equal(false, active2)
   154  	Advance(1)
   155  	s.Require().Equal([]int{1, 3}, hits)
   156  }
   157  
   158  func (s *FrozenSuite) TestReset() {
   159  	hits := []int{}
   160  
   161  	t1 := AfterFunc(100, func() { hits = append(hits, 1) })
   162  	t2 := AfterFunc(100, func() { hits = append(hits, 2) })
   163  	AfterFunc(100, func() { hits = append(hits, 3) })
   164  	Advance(99)
   165  	s.Require().Equal([]int{}, hits)
   166  
   167  	// When
   168  	active1 := t1.Reset(1) // Reset to the same time
   169  	active2 := t2.Reset(7)
   170  
   171  	// Then
   172  	s.Require().Equal(true, active1)
   173  	s.Require().Equal(true, active2)
   174  
   175  	Advance(1)
   176  	s.Require().Equal([]int{3, 1}, hits)
   177  	Advance(5)
   178  	s.Require().Equal([]int{3, 1}, hits)
   179  	Advance(1)
   180  	s.Require().Equal([]int{3, 1, 2}, hits)
   181  }
   182  
   183  // Reset to the same time just puts the timer at the end of the trigger list
   184  // for the date.
   185  func (s *FrozenSuite) TestResetSame() {
   186  	hits := []int{}
   187  
   188  	t := AfterFunc(100, func() { hits = append(hits, 1) })
   189  	AfterFunc(100, func() { hits = append(hits, 2) })
   190  	AfterFunc(100, func() { hits = append(hits, 3) })
   191  	AfterFunc(101, func() { hits = append(hits, 4) })
   192  	Advance(9)
   193  
   194  	// When
   195  	active := t.Reset(91)
   196  
   197  	// Then
   198  	s.Require().Equal(true, active)
   199  
   200  	Advance(90)
   201  	s.Require().Equal([]int{}, hits)
   202  	Advance(1)
   203  	s.Require().Equal([]int{2, 3, 1}, hits)
   204  }
   205  
   206  func (s *FrozenSuite) TestTicker() {
   207  	t := NewTicker(100)
   208  
   209  	Advance(99)
   210  	s.assertNotFired(t.C())
   211  	Advance(1)
   212  	s.Require().Equal(<-t.C(), s.epoch.Add(100))
   213  	Advance(750)
   214  	s.Require().Equal(<-t.C(), s.epoch.Add(200))
   215  	Advance(49)
   216  	s.assertNotFired(t.C())
   217  	Advance(1)
   218  	s.Require().Equal(<-t.C(), s.epoch.Add(900))
   219  
   220  	t.Stop()
   221  	Advance(300)
   222  	s.assertNotFired(t.C())
   223  }
   224  
   225  func (s *FrozenSuite) TestTickerZero() {
   226  	defer func() {
   227  		_ = recover()
   228  	}()
   229  
   230  	NewTicker(0)
   231  	s.Fail("Should panic")
   232  }
   233  
   234  func (s *FrozenSuite) TestTick() {
   235  	ch := Tick(100)
   236  
   237  	Advance(99)
   238  	s.assertNotFired(ch)
   239  	Advance(1)
   240  	s.Require().Equal(<-ch, s.epoch.Add(100))
   241  	Advance(750)
   242  	s.Require().Equal(<-ch, s.epoch.Add(200))
   243  	Advance(49)
   244  	s.assertNotFired(ch)
   245  	Advance(1)
   246  	s.Require().Equal(<-ch, s.epoch.Add(900))
   247  }
   248  
   249  func (s *FrozenSuite) TestTickZero() {
   250  	ch := Tick(0)
   251  	s.Require().Nil(ch)
   252  }
   253  
   254  func (s *FrozenSuite) TestNewStoppedTimer() {
   255  	t := NewStoppedTimer()
   256  
   257  	// When/Then
   258  	select {
   259  	case <-t.C():
   260  		s.Fail("Timer should not have fired")
   261  	default:
   262  	}
   263  	s.Require().Equal(false, t.Stop())
   264  }
   265  
   266  func (s *FrozenSuite) TestWait4Scheduled() {
   267  	After(100 * Millisecond)
   268  	After(100 * Millisecond)
   269  	s.Require().Equal(false, Wait4Scheduled(3, 0))
   270  
   271  	startedCh := make(chan struct{})
   272  	resultCh := make(chan bool)
   273  	go func() {
   274  		close(startedCh)
   275  		resultCh <- Wait4Scheduled(3, 5*Second)
   276  	}()
   277  	// Allow some time for waiter to be set and start waiting for a signal.
   278  	<-startedCh
   279  	time.Sleep(50 * Millisecond)
   280  
   281  	// When
   282  	After(100 * Millisecond)
   283  
   284  	// Then
   285  	s.Require().Equal(true, <-resultCh)
   286  }
   287  
   288  // If there is enough timers scheduled already, then a shortcut execution path
   289  // is taken and Wait4Scheduled returns immediately.
   290  func (s *FrozenSuite) TestWait4ScheduledImmediate() {
   291  	After(100 * Millisecond)
   292  	After(100 * Millisecond)
   293  	// When/Then
   294  	s.Require().Equal(true, Wait4Scheduled(2, 0))
   295  }
   296  
   297  func (s *FrozenSuite) TestSince() {
   298  	s.Require().Equal(Duration(0), Since(Now()))
   299  	s.Require().Equal(-Millisecond, Since(Now().Add(Millisecond)))
   300  	s.Require().Equal(Millisecond, Since(Now().Add(-Millisecond)))
   301  }
   302  
   303  func (s *FrozenSuite) TestUntil() {
   304  	s.Require().Equal(Duration(0), Until(Now()))
   305  	s.Require().Equal(Millisecond, Until(Now().Add(Millisecond)))
   306  	s.Require().Equal(-Millisecond, Until(Now().Add(-Millisecond)))
   307  }
   308  
   309  func (s *FrozenSuite) assertHits(got <-chan int, want []int) {
   310  	for i, w := range want {
   311  		var g int
   312  		select {
   313  		case g = <-got:
   314  		case <-time.After(100 * time.Millisecond):
   315  			s.Failf("Missing hit", "want=%v", w)
   316  			return
   317  		}
   318  		s.Require().Equal(w, g, "Hit #%d", i)
   319  	}
   320  	for {
   321  		select {
   322  		case g := <-got:
   323  			s.Failf("Unexpected hit", "got=%v", g)
   324  		default:
   325  			return
   326  		}
   327  	}
   328  }
   329  
   330  func (s *FrozenSuite) assertNotFired(ch <-chan time.Time) {
   331  	select {
   332  	case <-ch:
   333  		s.Fail("Premature fire")
   334  	default:
   335  	}
   336  }