github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/state/statetracker_test.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package state_test 5 6 import ( 7 "time" 8 9 jc "github.com/juju/testing/checkers" 10 gc "gopkg.in/check.v1" 11 12 "github.com/juju/juju/state" 13 statetesting "github.com/juju/juju/state/testing" 14 "github.com/juju/juju/testing" 15 workerstate "github.com/juju/juju/worker/state" 16 ) 17 18 type StateTrackerSuite struct { 19 statetesting.StateSuite 20 pool *state.State 21 stateTracker workerstate.StateTracker 22 } 23 24 var _ = gc.Suite(&StateTrackerSuite{}) 25 26 func (s *StateTrackerSuite) SetUpTest(c *gc.C) { 27 s.StateSuite.SetUpTest(c) 28 s.stateTracker = workerstate.NewStateTracker(s.StatePool) 29 } 30 31 func (s *StateTrackerSuite) TestDoneWithNoUse(c *gc.C) { 32 err := s.stateTracker.Done() 33 c.Assert(err, jc.ErrorIsNil) 34 assertStatePoolClosed(c, s.StatePool) 35 } 36 37 func (s *StateTrackerSuite) TestTooManyDones(c *gc.C) { 38 err := s.stateTracker.Done() 39 c.Assert(err, jc.ErrorIsNil) 40 assertStatePoolClosed(c, s.StatePool) 41 42 err = s.stateTracker.Done() 43 c.Assert(err, gc.Equals, workerstate.ErrStateClosed) 44 assertStatePoolClosed(c, s.StatePool) 45 } 46 47 func (s *StateTrackerSuite) TestUse(c *gc.C) { 48 pool, err := s.stateTracker.Use() 49 c.Check(pool.SystemState(), gc.Equals, s.State) 50 c.Check(err, jc.ErrorIsNil) 51 52 pool, err = s.stateTracker.Use() 53 c.Check(pool.SystemState(), gc.Equals, s.State) 54 c.Check(err, jc.ErrorIsNil) 55 } 56 57 func (s *StateTrackerSuite) TestUseAndDone(c *gc.C) { 58 // Ref count starts at 1 (the creator/owner) 59 60 _, err := s.stateTracker.Use() 61 // 2 62 c.Check(err, jc.ErrorIsNil) 63 64 _, err = s.stateTracker.Use() 65 // 3 66 c.Check(err, jc.ErrorIsNil) 67 68 c.Check(s.stateTracker.Done(), jc.ErrorIsNil) 69 // 2 70 assertStatePoolNotClosed(c, s.StatePool) 71 72 _, err = s.stateTracker.Use() 73 // 3 74 c.Check(err, jc.ErrorIsNil) 75 76 c.Check(s.stateTracker.Done(), jc.ErrorIsNil) 77 // 2 78 assertStatePoolNotClosed(c, s.StatePool) 79 80 c.Check(s.stateTracker.Done(), jc.ErrorIsNil) 81 // 1 82 assertStatePoolNotClosed(c, s.StatePool) 83 84 c.Check(s.stateTracker.Done(), jc.ErrorIsNil) 85 // 0 86 assertStatePoolClosed(c, s.StatePool) 87 } 88 89 func (s *StateTrackerSuite) TestUseWhenClosed(c *gc.C) { 90 c.Assert(s.stateTracker.Done(), jc.ErrorIsNil) 91 92 pool, err := s.stateTracker.Use() 93 c.Check(pool, gc.IsNil) 94 c.Check(err, gc.Equals, workerstate.ErrStateClosed) 95 } 96 97 func assertStatePoolNotClosed(c *gc.C, pool *state.StatePool) { 98 c.Assert(pool.SystemState(), gc.NotNil) 99 err := pool.SystemState().Ping() 100 c.Assert(err, jc.ErrorIsNil) 101 } 102 103 func assertStatePoolClosed(c *gc.C, pool *state.StatePool) { 104 c.Assert(pool.SystemState(), gc.IsNil) 105 } 106 107 func isTxnLogStarted(report map[string]interface{}) bool { 108 // Sometimes when we call pool.Report() not all the workers have started yet, so we check 109 next := report 110 var ok bool 111 for _, p := range []string{"txn-watcher", "workers", "txnlog"} { 112 if child, ok := next[p]; !ok { 113 return false 114 } else { 115 next = child.(map[string]interface{}) 116 } 117 } 118 state, ok := next["state"] 119 return ok && state == "started" 120 } 121 122 func (s *StateTrackerSuite) TestReport(c *gc.C) { 123 pool, err := s.stateTracker.Use() 124 c.Assert(err, jc.ErrorIsNil) 125 start := time.Now() 126 report := pool.Report() 127 for !isTxnLogStarted(report) { 128 if time.Since(start) >= testing.LongWait { 129 c.Fatalf("txlog worker did not start after %v", testing.LongWait) 130 } 131 time.Sleep(time.Millisecond) 132 report = pool.Report() 133 } 134 c.Check(report, gc.NotNil) 135 // We don't have any State models in the pool, but we do have the 136 // txn-watcher report and the system state. 137 c.Check(report, gc.HasLen, 3) 138 c.Check(report["pool-size"], gc.Equals, 0) 139 140 // Calling Report increments the request count in the system 141 // state's hubwatcher stats, so zero that out before comparing. 142 removeRequestCount := func(report map[string]interface{}) map[string]interface{} { 143 next := report 144 for _, p := range []string{"system", "workers", "txnlog", "report"} { 145 child, ok := next[p] 146 if !ok { 147 c.Fatalf("couldn't find system.workers.txnlog.report") 148 } 149 next = child.(map[string]interface{}) 150 } 151 delete(next, "request-count") 152 return report 153 } 154 report = removeRequestCount(report) 155 c.Check(removeRequestCount(s.stateTracker.Report()), gc.DeepEquals, report) 156 c.Check(removeRequestCount(s.stateTracker.Report()), gc.DeepEquals, report) 157 c.Check(removeRequestCount(s.stateTracker.Report()), gc.DeepEquals, report) 158 }