github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/worker/resumer/resumer_test.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package resumer_test
     5  
     6  import (
     7  	"errors"
     8  	"sync"
     9  	"time"
    10  
    11  	"github.com/juju/juju/worker"
    12  
    13  	"github.com/juju/testing"
    14  	jc "github.com/juju/testing/checkers"
    15  	gc "gopkg.in/check.v1"
    16  
    17  	"github.com/juju/juju/state"
    18  	coretesting "github.com/juju/juju/testing"
    19  	"github.com/juju/juju/worker/resumer"
    20  )
    21  
    22  type ResumerSuite struct {
    23  	coretesting.BaseSuite
    24  
    25  	mockState *transactionResumerMock
    26  }
    27  
    28  var _ = gc.Suite(&ResumerSuite{})
    29  
    30  // Ensure *state.State implements TransactionResumer
    31  var _ resumer.TransactionResumer = (*state.State)(nil)
    32  
    33  func (s *ResumerSuite) SetUpTest(c *gc.C) {
    34  	s.BaseSuite.SetUpTest(c)
    35  
    36  	s.mockState = &transactionResumerMock{
    37  		Stub: &testing.Stub{},
    38  	}
    39  }
    40  
    41  func (s *ResumerSuite) TestRunStopWithMockState(c *gc.C) {
    42  	w := resumer.NewResumer(s.mockState)
    43  	c.Assert(worker.Stop(w), gc.IsNil)
    44  }
    45  
    46  func (s *ResumerSuite) TestResumerCalls(c *gc.C) {
    47  	// Shorter interval and mock help to count
    48  	// the resumer calls in a given timespan.
    49  	testInterval := coretesting.ShortWait
    50  	resumer.SetInterval(testInterval)
    51  	defer resumer.RestoreInterval()
    52  
    53  	w := resumer.NewResumer(s.mockState)
    54  	defer func() {
    55  		c.Assert(worker.Stop(w), gc.IsNil)
    56  	}()
    57  
    58  	time.Sleep(10 * testInterval)
    59  
    60  	s.mockState.CheckTimestamps(c, testInterval)
    61  }
    62  
    63  func (s *ResumerSuite) TestResumeTransactionsFailure(c *gc.C) {
    64  	// Force the first call to ResumeTransactions() to fail, the
    65  	// remaining returning no error.
    66  	s.mockState.SetErrors(errors.New("boom!"))
    67  
    68  	// Shorter interval and mock help to count
    69  	// the resumer calls in a given timespan.
    70  	testInterval := coretesting.ShortWait
    71  	resumer.SetInterval(testInterval)
    72  	defer resumer.RestoreInterval()
    73  
    74  	w := resumer.NewResumer(s.mockState)
    75  	defer func() {
    76  		c.Assert(worker.Stop(w), gc.IsNil)
    77  	}()
    78  
    79  	// For 4 intervals between 2 and 3 calls should be made.
    80  	time.Sleep(4 * testInterval)
    81  	s.mockState.CheckNumCallsBetween(c, 2, 3)
    82  }
    83  
    84  // TODO(waigani) This could be a simpler and more robust if the resumer took a
    85  // Clock.
    86  
    87  // transactionResumerMock is used to check the
    88  // calls of ResumeTransactions().
    89  type transactionResumerMock struct {
    90  	*testing.Stub
    91  
    92  	mu         sync.Mutex
    93  	timestamps []time.Time
    94  }
    95  
    96  func (tr *transactionResumerMock) ResumeTransactions() error {
    97  	tr.mu.Lock()
    98  	defer tr.mu.Unlock()
    99  
   100  	tr.timestamps = append(tr.timestamps, time.Now())
   101  	tr.MethodCall(tr, "ResumeTransactions")
   102  	return tr.NextErr()
   103  }
   104  
   105  func (tr *transactionResumerMock) CheckNumCallsBetween(c *gc.C, minCalls, maxCalls int) {
   106  	tr.mu.Lock()
   107  	defer tr.mu.Unlock()
   108  
   109  	// To combat test flakyness (see bug #1462412) we're expecting up
   110  	// to maxCalls, but at least minCalls.
   111  	calls := tr.Stub.Calls()
   112  	c.Assert(len(calls), jc.GreaterThan, minCalls-1)
   113  	c.Assert(len(calls), jc.LessThan, maxCalls+1)
   114  	for _, call := range calls {
   115  		c.Check(call.FuncName, gc.Equals, "ResumeTransactions")
   116  	}
   117  }
   118  
   119  func (tr *transactionResumerMock) CheckTimestamps(c *gc.C, testInterval time.Duration) {
   120  	// Check that a number of calls has happened with a time
   121  	// difference somewhere between the interval and twice the
   122  	// interval. A more precise time behavior cannot be
   123  	// specified due to the load during the test.
   124  	tr.mu.Lock()
   125  	defer tr.mu.Unlock()
   126  
   127  	longestInterval := 4 * testInterval
   128  	c.Assert(len(tr.timestamps) > 0, jc.IsTrue)
   129  	for i := 1; i < len(tr.timestamps); i++ {
   130  		diff := tr.timestamps[i].Sub(tr.timestamps[i-1])
   131  
   132  		c.Assert(diff >= testInterval, jc.IsTrue)
   133  		c.Assert(diff <= longestInterval, jc.IsTrue)
   134  		tr.Stub.CheckCall(c, i-1, "ResumeTransactions")
   135  	}
   136  }
   137  
   138  var _ resumer.TransactionResumer = (*transactionResumerMock)(nil)