github.com/juju/clock@v1.0.3/testclock/dilated_test.go (about)

     1  // Copyright 2022 Canonical Ltd.
     2  // Licensed under the LGPLv3, see LICENCE file for details.
     3  
     4  package testclock_test
     5  
     6  import (
     7  	"math/rand"
     8  	"runtime"
     9  	"sync"
    10  	"time"
    11  
    12  	"github.com/juju/clock"
    13  	"github.com/juju/testing"
    14  	jc "github.com/juju/testing/checkers"
    15  	gc "gopkg.in/check.v1"
    16  
    17  	"github.com/juju/clock/testclock"
    18  )
    19  
    20  const (
    21  	halfSecond   = 500 * time.Millisecond
    22  	doubleSecond = 2 * time.Second
    23  )
    24  
    25  type dilatedClockSuite struct {
    26  	testing.LoggingSuite
    27  }
    28  
    29  var _ = gc.Suite(&dilatedClockSuite{})
    30  
    31  func (*dilatedClockSuite) TestSlowedAfter(c *gc.C) {
    32  	cl := testclock.NewDilatedWallClock(doubleSecond)
    33  	t0 := time.Now()
    34  	d0 := cl.Now()
    35  	d1 := <-cl.After(time.Second)
    36  	t1 := time.Now()
    37  	c.Assert(t1.Sub(t0).Seconds(), jc.GreaterThan, 1.9)
    38  	c.Assert(d1.Sub(d0).Seconds(), jc.GreaterThan, 0.9)
    39  	c.Assert(d1.Sub(d0).Seconds(), jc.LessThan, 1.1)
    40  }
    41  
    42  func (*dilatedClockSuite) TestFastAfter(c *gc.C) {
    43  	cl := testclock.NewDilatedWallClock(halfSecond)
    44  	t0 := time.Now()
    45  	d0 := cl.Now()
    46  	d1 := <-cl.After(time.Second)
    47  	t1 := time.Now()
    48  	c.Assert(t1.Sub(t0).Milliseconds(), jc.LessThan, 600)
    49  	c.Assert(d1.Sub(d0).Milliseconds(), jc.GreaterThan, 990)
    50  	c.Assert(d1.Sub(d0).Milliseconds(), jc.LessThan, 1010)
    51  }
    52  
    53  func (*dilatedClockSuite) TestSlowedAfterFunc(c *gc.C) {
    54  	t0 := time.Now()
    55  	cl := testclock.NewDilatedWallClock(doubleSecond)
    56  	mut := sync.Mutex{}
    57  	mut.Lock()
    58  	cl.AfterFunc(time.Second, func() {
    59  		defer mut.Unlock()
    60  		c.Check(time.Since(t0).Seconds(), jc.GreaterThan, 1.9)
    61  	})
    62  	mut.Lock()
    63  }
    64  
    65  func (*dilatedClockSuite) TestFastAfterFunc(c *gc.C) {
    66  	t0 := time.Now()
    67  	cl := testclock.NewDilatedWallClock(halfSecond)
    68  	mut := sync.Mutex{}
    69  	mut.Lock()
    70  	cl.AfterFunc(time.Second, func() {
    71  		defer mut.Unlock()
    72  		c.Check(time.Since(t0).Milliseconds(), jc.LessThan, 600)
    73  	})
    74  	mut.Lock()
    75  }
    76  
    77  func (*dilatedClockSuite) TestSlowedNow(c *gc.C) {
    78  	t0 := time.Now()
    79  	cl := testclock.NewDilatedWallClock(doubleSecond)
    80  	<-time.After(time.Second)
    81  	t2 := cl.Now()
    82  	c.Assert(t2.Sub(t0).Milliseconds(), jc.GreaterThan, 400)
    83  	c.Assert(t2.Sub(t0).Milliseconds(), jc.LessThan, 600)
    84  	<-time.After(time.Second)
    85  	t3 := cl.Now()
    86  	c.Assert(t3.Sub(t0).Milliseconds(), jc.GreaterThan, 900)
    87  	c.Assert(t3.Sub(t0).Milliseconds(), jc.LessThan, 1100)
    88  }
    89  
    90  func (*dilatedClockSuite) TestFastNow(c *gc.C) {
    91  	t0 := time.Now()
    92  	cl := testclock.NewDilatedWallClock(halfSecond)
    93  	<-time.After(time.Second)
    94  	t2 := cl.Now()
    95  	c.Assert(t2.Sub(t0).Milliseconds(), jc.GreaterThan, 1900)
    96  	c.Assert(t2.Sub(t0).Milliseconds(), jc.LessThan, 2100)
    97  	<-time.After(time.Second)
    98  	t3 := cl.Now()
    99  	c.Assert(t3.Sub(t0).Milliseconds(), jc.GreaterThan, 3900)
   100  	c.Assert(t3.Sub(t0).Milliseconds(), jc.LessThan, 4100)
   101  }
   102  
   103  func (*dilatedClockSuite) TestAdvance(c *gc.C) {
   104  	t0 := time.Now()
   105  	cl := testclock.NewDilatedWallClock(halfSecond)
   106  	first := cl.After(time.Second)
   107  	cl.Advance(halfSecond)
   108  	<-time.After(250 * time.Millisecond)
   109  	select {
   110  	case t := <-first:
   111  		c.Assert(t.Sub(t0).Milliseconds(), jc.GreaterThan, 249)
   112  	case <-time.After(shortWait):
   113  		c.Fatal("timer failed to trigger early")
   114  	}
   115  }
   116  
   117  func (*dilatedClockSuite) TestAdvanceMulti(c *gc.C) {
   118  	cl := testclock.NewDilatedWallClock(halfSecond)
   119  	first := cl.After(time.Second)
   120  	second := cl.After(2 * time.Second)
   121  	third := cl.After(1 * time.Hour)
   122  
   123  	done := time.After(longWait)
   124  	fourth := cl.After(12*time.Hour + longWait*2 + time.Second)
   125  
   126  	cl.Advance(12 * time.Hour)
   127  
   128  	n := 0
   129  out:
   130  	for {
   131  		select {
   132  		case <-first:
   133  			n++
   134  		case <-second:
   135  			n++
   136  		case <-third:
   137  			n++
   138  		case <-fourth:
   139  			c.Fatal("timer that fired that should not have")
   140  		case <-done:
   141  			break out
   142  		}
   143  	}
   144  	c.Assert(n, gc.Equals, 3)
   145  }
   146  
   147  func (*dilatedClockSuite) TestStop(c *gc.C) {
   148  	numGo := runtime.NumGoroutine()
   149  	cl := testclock.NewDilatedWallClock(halfSecond)
   150  	a := cl.NewTimer(time.Second)
   151  	time.Sleep(shortWait)
   152  	ok := a.Stop()
   153  	c.Assert(ok, jc.IsTrue)
   154  	ok = a.Stop()
   155  	c.Assert(ok, jc.IsFalse)
   156  	select {
   157  	case <-a.Chan():
   158  		c.Fatal("stopped clock fired")
   159  	case <-time.After(time.Second):
   160  	}
   161  	for i := 0; i < 3; i++ {
   162  		if runtime.NumGoroutine() == numGo {
   163  			break
   164  		}
   165  		time.Sleep(shortWait)
   166  	}
   167  	c.Assert(runtime.NumGoroutine(), gc.Equals, numGo, gc.Commentf("clock goroutine still running"))
   168  }
   169  
   170  func (*dilatedClockSuite) TestReset(c *gc.C) {
   171  	numGo := runtime.NumGoroutine()
   172  	cl := testclock.NewDilatedWallClock(halfSecond)
   173  	a := cl.NewTimer(time.Second)
   174  	time.Sleep(250 * time.Millisecond)
   175  	ok := a.Reset(time.Second)
   176  	c.Assert(ok, jc.IsTrue)
   177  	<-time.After(halfSecond)
   178  	select {
   179  	case <-a.Chan():
   180  	case <-time.After(shortWait):
   181  		c.Fatal("timer did not fire")
   182  	}
   183  	for i := 0; i < 3; i++ {
   184  		if runtime.NumGoroutine() == numGo {
   185  			break
   186  		}
   187  		time.Sleep(shortWait)
   188  	}
   189  	c.Assert(runtime.NumGoroutine(), gc.Equals, numGo, gc.Commentf("clock goroutine still running"))
   190  }
   191  
   192  func (*dilatedClockSuite) TestStopReset(c *gc.C) {
   193  	numGo := runtime.NumGoroutine()
   194  	cl := testclock.NewDilatedWallClock(halfSecond)
   195  	a := cl.NewTimer(time.Second)
   196  	time.Sleep(250 * time.Millisecond)
   197  	ok := a.Stop()
   198  	c.Assert(ok, jc.IsTrue)
   199  	ok = a.Reset(time.Second)
   200  	c.Assert(ok, jc.IsTrue)
   201  	<-time.After(halfSecond)
   202  	select {
   203  	case <-a.Chan():
   204  	case <-time.After(shortWait):
   205  		c.Fatal("timer did not fire")
   206  	}
   207  	for i := 0; i < 3; i++ {
   208  		if runtime.NumGoroutine() == numGo {
   209  			break
   210  		}
   211  		time.Sleep(shortWait)
   212  	}
   213  	c.Assert(runtime.NumGoroutine(), gc.Equals, numGo, gc.Commentf("clock goroutine still running"))
   214  }
   215  
   216  func (*dilatedClockSuite) TestAdvanceAlreadyFired(c *gc.C) {
   217  	numGo := runtime.NumGoroutine()
   218  	cl := testclock.NewDilatedWallClock(time.Second)
   219  	t := cl.NewTimer(time.Millisecond)
   220  	time.Sleep(shortWait)
   221  	cl.Advance(time.Second)
   222  	select {
   223  	case <-t.Chan():
   224  	case <-time.After(shortWait):
   225  		c.Fatal("timer did not fire")
   226  	}
   227  	for i := 0; i < 3; i++ {
   228  		if runtime.NumGoroutine() == numGo {
   229  			break
   230  		}
   231  		time.Sleep(shortWait)
   232  	}
   233  	c.Assert(runtime.NumGoroutine(), gc.Equals, numGo, gc.Commentf("clock goroutine still running"))
   234  }
   235  
   236  func (*dilatedClockSuite) TestAdvanceFast(c *gc.C) {
   237  	cl := testclock.NewDilatedWallClock(time.Minute)
   238  	timers := make([]clock.Timer, 0, 1000)
   239  	for i := time.Millisecond; i <= time.Second; i += time.Millisecond {
   240  		timers = append(timers, cl.NewTimer(i))
   241  	}
   242  	for i := 0; i < 10000; i++ {
   243  		cl.Advance(100 * time.Microsecond)
   244  	}
   245  	deadline := time.After(10 * time.Second)
   246  	for _, timer := range timers {
   247  		select {
   248  		case <-timer.Chan():
   249  		case <-deadline:
   250  			c.Fatal("timer did not fire by deadline")
   251  		}
   252  	}
   253  }
   254  
   255  func (*dilatedClockSuite) TestAdvanceReset(c *gc.C) {
   256  	cl := testclock.NewDilatedWallClock(time.Minute)
   257  	timers := make([]clock.Timer, 0, 10)
   258  	for i := 0; i < 10; i++ {
   259  		timers = append(timers, cl.NewTimer(time.Millisecond))
   260  	}
   261  	deadline := time.After(10 * time.Second)
   262  	for i := 0; i < 1000; i++ {
   263  		cl.Advance(time.Millisecond)
   264  		for _, timer := range timers {
   265  			select {
   266  			case <-timer.Chan():
   267  			case <-deadline:
   268  				c.Fatal("timer did not fire by deadline")
   269  			}
   270  			timer.Reset(time.Millisecond)
   271  		}
   272  	}
   273  }
   274  
   275  func (*dilatedClockSuite) TestAdvanceResetRacey(c *gc.C) {
   276  	cl := testclock.NewDilatedWallClock(time.Second)
   277  	timers := make([]clock.Timer, 0, 10)
   278  	for i := 0; i < 10; i++ {
   279  		timers = append(timers, cl.NewTimer(time.Millisecond))
   280  	}
   281  	deadline := time.After(2 * time.Second)
   282  	for i := 0; i < 1000; i++ {
   283  		time.Sleep(999 * time.Microsecond)
   284  		cl.Advance(time.Microsecond * time.Duration(rand.Intn(2)))
   285  		for _, timer := range timers {
   286  			select {
   287  			case <-timer.Chan():
   288  			case <-deadline:
   289  				c.Fatal("timer did not fire by deadline")
   290  			}
   291  			timer.Reset(time.Millisecond)
   292  		}
   293  	}
   294  }