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