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)