github.com/rogpeppe/clock@v0.0.0-20190514195947-2896927a307a/testclock/clock_test.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the LGPLv3, see LICENCE file for details.
     3  
     4  package testclock_test
     5  
     6  import (
     7  	"bytes"
     8  	"fmt"
     9  	"sync"
    10  	"testing"
    11  	"time"
    12  
    13  	qt "github.com/frankban/quicktest"
    14  
    15  	"github.com/rogpeppe/clock/testclock"
    16  )
    17  
    18  func TestNow(t *testing.T) {
    19  	c := qt.New(t)
    20  	t0 := time.Now()
    21  	cl := testclock.NewClock(t0)
    22  	c.Assert(cl.Now(), qt.Equals, t0)
    23  }
    24  
    25  var (
    26  	shortWait = 50 * time.Millisecond
    27  	longWait  = time.Second
    28  )
    29  
    30  func TestAdvanceLogs(t *testing.T) {
    31  	c := qt.New(t)
    32  	t0 := time.Now()
    33  	cl := testclock.NewClock(t0)
    34  	var logBuf bytes.Buffer
    35  	cl.SetLog(func(msg string) {
    36  		fmt.Fprintln(&logBuf, msg)
    37  	})
    38  
    39  	// Shouldn't log anything.
    40  	tc := cl.After(time.Second)
    41  	cl.Advance(time.Minute)
    42  	<-tc
    43  	c.Check(logBuf.Bytes(), qt.HasLen, 0)
    44  
    45  	// Should log since nothing's waiting.
    46  	cl.Advance(time.Hour)
    47  	c.Check(logBuf.String(), qt.Equals, "advancing a clock that has nothing waiting: cf. https://github.com/juju/juju/wiki/Intermittent-failures\n")
    48  }
    49  
    50  func TestWaitAdvance(t *testing.T) {
    51  	c := qt.New(t)
    52  	t0 := time.Now()
    53  	cl := testclock.NewClock(t0)
    54  
    55  	// It is legal to just say 'nothing is waiting'
    56  	err := cl.WaitAdvance(0, 0, 0)
    57  	c.Check(err, qt.Equals, nil)
    58  
    59  	// Test that no timers errors out.
    60  	err = cl.WaitAdvance(time.Millisecond, 10*time.Millisecond, 1)
    61  	c.Check(err, qt.ErrorMatches, "got 0 timers added after waiting 10ms: wanted 1, stacks:\n")
    62  
    63  	// Test that a timer doesn't error.
    64  	_ = cl.After(time.Nanosecond)
    65  	err = cl.WaitAdvance(time.Millisecond, 10*time.Millisecond, 1)
    66  	c.Check(err, qt.Equals, nil)
    67  }
    68  
    69  func TestAdvanceWithAfter(t *testing.T) {
    70  	c := qt.New(t)
    71  	t0 := time.Now()
    72  	cl := testclock.NewClock(t0)
    73  	ch := cl.After(time.Second)
    74  	select {
    75  	case <-ch:
    76  		c.Fatalf("received unexpected event")
    77  	case <-time.After(shortWait):
    78  	}
    79  
    80  	cl.Advance(time.Second - 1)
    81  
    82  	select {
    83  	case <-ch:
    84  		c.Fatalf("received unexpected event")
    85  	case <-time.After(shortWait):
    86  	}
    87  
    88  	cl.Advance(1)
    89  
    90  	select {
    91  	case <-ch:
    92  	case <-time.After(longWait):
    93  		c.Fatalf("expected event to be triggered")
    94  	}
    95  
    96  	cl.Advance(time.Second)
    97  	select {
    98  	case <-ch:
    99  		c.Fatalf("received unexpected event")
   100  	case <-time.After(shortWait):
   101  	}
   102  
   103  	// Test that we can do it again
   104  	ch = cl.After(time.Second)
   105  	cl.Advance(2 * time.Second)
   106  	select {
   107  	case <-ch:
   108  	case <-time.After(longWait):
   109  		c.Fatalf("expected event to be triggered")
   110  	}
   111  	c.Assert(cl.Now().UTC(), qt.Equals, t0.Add(4*time.Second).UTC())
   112  }
   113  
   114  func TestAdvanceWithAfterFunc(t *testing.T) {
   115  	c := qt.New(t)
   116  	// Most of the details have been checked in TestAdvanceWithAfter,
   117  	// so just check that AfterFunc is wired up correctly.
   118  	t0 := time.Now()
   119  	cl := testclock.NewClock(t0)
   120  	fired := make(chan struct{})
   121  	cl.AfterFunc(time.Second, func() {
   122  		close(fired)
   123  	})
   124  	cl.Advance(2 * time.Second)
   125  	select {
   126  	case <-fired:
   127  	case <-time.After(longWait):
   128  		c.Fatalf("expected event to be triggered")
   129  	}
   130  }
   131  
   132  func TestAfterFuncStop(t *testing.T) {
   133  	c := qt.New(t)
   134  	t0 := time.Now()
   135  	cl := testclock.NewClock(t0)
   136  	fired := make(chan struct{})
   137  	timer := cl.AfterFunc(time.Second, func() {
   138  		close(fired)
   139  	})
   140  	cl.Advance(50 * time.Millisecond)
   141  	timer.Stop()
   142  	select {
   143  	case <-fired:
   144  		c.Fatalf("received unexpected event")
   145  	case <-time.After(shortWait):
   146  	}
   147  }
   148  
   149  func TestNewTimerReset(t *testing.T) {
   150  	c := qt.New(t)
   151  	t0 := time.Now()
   152  	cl := testclock.NewClock(t0)
   153  	timer := cl.NewTimer(time.Second)
   154  	cl.Advance(time.Second)
   155  	select {
   156  	case t := <-timer.Chan():
   157  		c.Assert(t.UTC(), qt.Equals, t0.Add(time.Second).UTC())
   158  	case <-time.After(longWait):
   159  		c.Fatalf("expected event to be triggered")
   160  	}
   161  
   162  	timer.Reset(50 * time.Millisecond)
   163  	cl.Advance(100 * time.Millisecond)
   164  	select {
   165  	case t := <-timer.Chan():
   166  		c.Assert(t.UTC(), qt.Equals, t0.Add(time.Second+100*time.Millisecond).UTC())
   167  	case <-time.After(longWait):
   168  		c.Fatalf("expected event to be triggered")
   169  	}
   170  }
   171  
   172  func TestNewTimerAsyncReset(t *testing.T) {
   173  	c := qt.New(t)
   174  	t0 := time.Now()
   175  	clock := testclock.NewClock(t0)
   176  	timer := clock.NewTimer(time.Hour)
   177  	stop := make(chan struct{})
   178  	stopped := make(chan struct{})
   179  	var wg sync.WaitGroup
   180  	wg.Add(1)
   181  	go func() {
   182  		defer wg.Done()
   183  		select {
   184  		case <-stop:
   185  		case t := <-timer.Chan():
   186  			c.Errorf("timer accidentally ticked at: %v", t)
   187  		case <-time.After(longWait):
   188  			c.Errorf("test took too long")
   189  		}
   190  		close(stopped)
   191  	}()
   192  	// Just our goroutine, but we don't go so far as to trigger the wakeup.
   193  	clock.WaitAdvance(1*time.Minute, 10*time.Millisecond, 1)
   194  	// Reset shouldn't trigger a wakeup, just move when it thinks it will wake up.
   195  	timer.Reset(time.Hour)
   196  	clock.WaitAdvance(1*time.Minute, 10*time.Millisecond, 1)
   197  	timer.Reset(time.Minute)
   198  	clock.WaitAdvance(30*time.Second, 10*time.Millisecond, 1)
   199  	// Now tell the goroutine to stop and start another one that *does* want to
   200  	// wake up
   201  	close(stop)
   202  	select {
   203  	case <-stopped:
   204  	case <-time.After(longWait):
   205  		c.Errorf("goroutine failed to stop")
   206  	}
   207  	wg.Add(1)
   208  	go func() {
   209  		defer wg.Done()
   210  		select {
   211  		case t := <-timer.Chan():
   212  			c.Logf("timer successfully ticked: %v", t)
   213  		case <-time.After(longWait):
   214  			c.Errorf("timer took too long")
   215  		}
   216  	}()
   217  	// And advance the clock long enough to cause it to notice
   218  	clock.WaitAdvance(30*time.Second, 10*time.Millisecond, 1)
   219  	wg.Wait()
   220  }
   221  
   222  func TestNewTimerResetCausesWakeup(t *testing.T) {
   223  	c := qt.New(t)
   224  	t0 := time.Now()
   225  	clock := testclock.NewClock(t0)
   226  	timer1 := clock.NewTimer(time.Hour)
   227  	timer2 := clock.NewTimer(time.Hour)
   228  	timer3 := clock.NewTimer(time.Hour)
   229  	var wg sync.WaitGroup
   230  	wg.Add(1)
   231  	go func() {
   232  		defer wg.Done()
   233  		select {
   234  		case t := <-timer1.Chan():
   235  			c.Check(t0, qt.Equals, t)
   236  		case <-time.After(longWait):
   237  			c.Errorf("timer1 took too long to wake up")
   238  		}
   239  	}()
   240  	wg.Add(1)
   241  	go func() {
   242  		defer wg.Done()
   243  		select {
   244  		case <-timer2.Chan():
   245  			c.Errorf("timer2 should not wake up")
   246  		case <-time.After(shortWait):
   247  			c.Logf("timer2 succesfully slept for 50ms")
   248  		}
   249  	}()
   250  	wg.Add(1)
   251  	go func() {
   252  		defer wg.Done()
   253  		select {
   254  		case t := <-timer3.Chan():
   255  			// Even though the reset was negative, it triggers at 'now'
   256  			c.Check(t0, qt.Equals, t)
   257  		case <-time.After(longWait):
   258  			c.Errorf("timer3 took too long to wake up")
   259  		}
   260  	}()
   261  	// Reseting the timer to a time <= 0 should cause it to wake up on its
   262  	// own, without needing an Advance or WaitAdvance to be done
   263  	timer1.Reset(0)
   264  	timer3.Reset(-1 * time.Second)
   265  	wg.Wait()
   266  }
   267  
   268  func TestMultipleWaiters(t *testing.T) {
   269  	c := qt.New(t)
   270  	var wg sync.WaitGroup
   271  	t0 := time.Date(2000, 01, 01, 01, 0, 0, 0, time.UTC)
   272  	cl := testclock.NewClock(t0)
   273  
   274  	total := 0
   275  	start := func(f func()) {
   276  		total++
   277  		wg.Add(1)
   278  		go func() {
   279  			defer wg.Done()
   280  			f()
   281  		}()
   282  	}
   283  	start(func() {
   284  		<-cl.After(50 * time.Millisecond)
   285  	})
   286  	start(func() {
   287  		ch := make(chan struct{})
   288  		cl.AfterFunc(100*time.Millisecond, func() {
   289  			close(ch)
   290  		})
   291  		<-ch
   292  	})
   293  	start(func() {
   294  		timer := cl.NewTimer(150 * time.Millisecond)
   295  		<-timer.Chan()
   296  		timer.Reset(50 * time.Millisecond)
   297  		<-timer.Chan()
   298  	})
   299  
   300  	done := make(chan struct{})
   301  	go func() {
   302  		wg.Wait()
   303  		close(done)
   304  	}()
   305  
   306  	// Wait for all the alarms to be waited on.
   307  	for i := 0; i < total; i++ {
   308  		select {
   309  		case <-cl.Alarms():
   310  		case <-time.After(longWait):
   311  			c.Fatalf("expected a notification on the alarms channel")
   312  		}
   313  	}
   314  	select {
   315  	case <-cl.Alarms():
   316  		c.Fatalf("unexpected extra notification on alarms channel")
   317  	case <-time.After(shortWait):
   318  	}
   319  
   320  	cl.Advance(150 * time.Millisecond)
   321  
   322  	// Wait for the extra notification after reset.
   323  	select {
   324  	case <-cl.Alarms():
   325  	case <-time.After(longWait):
   326  		c.Fatalf("expected a notification on the alarms channel")
   327  	}
   328  
   329  	cl.Advance(50 * time.Millisecond)
   330  
   331  	select {
   332  	case <-done:
   333  	case <-time.After(longWait):
   334  		c.Fatalf("expected all waits to complete")
   335  	}
   336  
   337  }