github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/uniter/timer_test.go (about)

     1  // Copyright 2017 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package uniter_test
     5  
     6  import (
     7  	"reflect"
     8  	"time"
     9  
    10  	jc "github.com/juju/testing/checkers"
    11  	gc "gopkg.in/check.v1"
    12  
    13  	"github.com/juju/juju/worker/uniter"
    14  )
    15  
    16  type timerSuite struct{}
    17  
    18  var _ = gc.Suite(&timerSuite{})
    19  
    20  func (s *timerSuite) TestTimer(c *gc.C) {
    21  	nominal := 100 * time.Second
    22  	minTime := 80*time.Second - time.Millisecond
    23  	maxTime := 120*time.Second + time.Millisecond
    24  
    25  	timer := uniter.NewUpdateStatusTimer()
    26  	var lastTime time.Duration
    27  	var measuredMinTime time.Duration
    28  	var measuredMaxTime time.Duration
    29  
    30  	for i := 0; i < 1000; i++ {
    31  		wait := timer(nominal)
    32  		waitDuration := time.Duration(reflect.ValueOf(wait).Int())
    33  		// We use Assert rather than Check because we don't want 100s of failures
    34  		c.Assert(wait, jc.GreaterThan, minTime)
    35  		c.Assert(wait, jc.LessThan, maxTime)
    36  		if lastTime == 0 {
    37  			measuredMinTime = waitDuration
    38  			measuredMaxTime = waitDuration
    39  		} else {
    40  			// We are using a range in 100s of milliseconds at a
    41  			// resolution of nanoseconds. The chance of getting the
    42  			// same random value 2x in a row is sufficiently low that
    43  			// we can just assert the value is changing.
    44  			// (Chance of collision is roughly 1 in 100 Million)
    45  			c.Assert(wait, gc.Not(gc.Equals), lastTime)
    46  			if waitDuration < measuredMinTime {
    47  				measuredMinTime = waitDuration
    48  			}
    49  			if waitDuration > measuredMaxTime {
    50  				measuredMaxTime = waitDuration
    51  			}
    52  		}
    53  		lastTime = waitDuration
    54  	}
    55  	// Check that we're actually using the full range that was requested.
    56  	// Assert that after 1000 tries we've used a good portion of the range
    57  	// If we sampled perfectly, then we would have fully sampled the range,
    58  	// spread very 1/1000 of the range.
    59  	// If we set the required range to 1/100, then a given sample would fail 99%
    60  	// of the time, 1000 samples would fail 0.99^1000=4e-5 or ~1-in-20,000 times.
    61  	// (actual measurements showed 18 in 20,000, probably due to double ended range vs single ended)
    62  	// However, at 1/10 its 0.9^1000=1.7e-46, or 10^41 times less likely to fail.
    63  	// In 100,000 runs, a range of 1/10 never failed
    64  	expectedCloseness := (maxTime - minTime) / 10
    65  	c.Check(measuredMinTime, jc.LessThan, minTime+expectedCloseness)
    66  	c.Check(measuredMaxTime, jc.GreaterThan, maxTime-expectedCloseness)
    67  }