github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/worker/meterstatus/isolated_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package meterstatus_test 5 6 import ( 7 "fmt" 8 "path" 9 "time" 10 11 "github.com/juju/clock/testclock" 12 "github.com/juju/errors" 13 "github.com/juju/loggo" 14 "github.com/juju/testing" 15 jc "github.com/juju/testing/checkers" 16 "github.com/juju/worker/v3" 17 "github.com/juju/worker/v3/workertest" 18 gc "gopkg.in/check.v1" 19 20 coretesting "github.com/juju/juju/testing" 21 "github.com/juju/juju/worker/common/charmrunner" 22 "github.com/juju/juju/worker/meterstatus" 23 ) 24 25 const ( 26 AmberGracePeriod = time.Minute 27 RedGracePeriod = time.Minute * 5 28 ) 29 30 type IsolatedWorkerConfigSuite struct { 31 coretesting.BaseSuite 32 33 config meterstatus.IsolatedConfig 34 } 35 36 var _ = gc.Suite(&IsolatedWorkerConfigSuite{}) 37 38 func (s *IsolatedWorkerConfigSuite) SetUpTest(c *gc.C) { 39 s.BaseSuite.SetUpTest(c) 40 s.config = meterstatus.IsolatedConfig{ 41 Runner: struct{ meterstatus.HookRunner }{}, 42 StateReadWriter: struct{ meterstatus.StateReadWriter }{}, 43 Clock: struct{ meterstatus.Clock }{}, 44 Logger: struct{ meterstatus.Logger }{}, 45 AmberGracePeriod: AmberGracePeriod, 46 RedGracePeriod: RedGracePeriod, 47 TriggerFactory: meterstatus.GetTriggers, 48 } 49 } 50 51 func (s *IsolatedWorkerConfigSuite) TestConfigValid(c *gc.C) { 52 c.Assert(s.config.Validate(), jc.ErrorIsNil) 53 } 54 55 func (s *IsolatedWorkerConfigSuite) TestMissingRunner(c *gc.C) { 56 s.config.Runner = nil 57 err := s.config.Validate() 58 c.Assert(err, jc.Satisfies, errors.IsNotValid) 59 c.Assert(err.Error(), gc.Equals, "missing Runner not valid") 60 } 61 62 func (s *IsolatedWorkerConfigSuite) TestMissingStateReadWriter(c *gc.C) { 63 s.config.StateReadWriter = nil 64 err := s.config.Validate() 65 c.Assert(err, jc.Satisfies, errors.IsNotValid) 66 c.Assert(err.Error(), gc.Equals, "missing StateReadWriter not valid") 67 } 68 69 func (s *IsolatedWorkerConfigSuite) TestMissingClock(c *gc.C) { 70 s.config.Clock = nil 71 err := s.config.Validate() 72 c.Assert(err, jc.Satisfies, errors.IsNotValid) 73 c.Assert(err.Error(), gc.Equals, "missing Clock not valid") 74 } 75 76 func (s *IsolatedWorkerConfigSuite) TestMissingLogger(c *gc.C) { 77 s.config.Logger = nil 78 err := s.config.Validate() 79 c.Assert(err, jc.Satisfies, errors.IsNotValid) 80 c.Assert(err.Error(), gc.Equals, "missing Logger not valid") 81 } 82 83 func (s *IsolatedWorkerConfigSuite) TestMissingAmberGracePeriod(c *gc.C) { 84 s.config.AmberGracePeriod = 0 85 err := s.config.Validate() 86 c.Assert(err, jc.Satisfies, errors.IsNotValid) 87 c.Assert(err.Error(), gc.Equals, "amber grace period not valid") 88 } 89 90 func (s *IsolatedWorkerConfigSuite) TestMissingRedGracePeriod(c *gc.C) { 91 s.config.RedGracePeriod = 0 92 err := s.config.Validate() 93 c.Assert(err, jc.Satisfies, errors.IsNotValid) 94 c.Assert(err.Error(), gc.Equals, "red grace period not valid") 95 } 96 97 func (s *IsolatedWorkerConfigSuite) TestMissingAmberEqualRed(c *gc.C) { 98 s.config.RedGracePeriod = s.config.AmberGracePeriod 99 err := s.config.Validate() 100 c.Assert(err.Error(), gc.Equals, "amber grace period must be shorter than the red grace period") 101 } 102 103 type IsolatedWorkerSuite struct { 104 coretesting.BaseSuite 105 106 stub *testing.Stub 107 108 dataDir string 109 clk *testclock.Clock 110 111 hookRan chan struct{} 112 triggersCreated chan struct{} 113 114 worker worker.Worker 115 } 116 117 var _ = gc.Suite(&IsolatedWorkerSuite{}) 118 119 func (s *IsolatedWorkerSuite) SetUpTest(c *gc.C) { 120 s.BaseSuite.SetUpTest(c) 121 s.stub = &testing.Stub{} 122 123 s.dataDir = c.MkDir() 124 125 s.hookRan = make(chan struct{}) 126 s.triggersCreated = make(chan struct{}) 127 128 triggerFactory := func(state meterstatus.WorkerState, status string, disconectedAt time.Time, clk meterstatus.Clock, amber time.Duration, red time.Duration) (<-chan time.Time, <-chan time.Time) { 129 select { 130 case s.triggersCreated <- struct{}{}: 131 case <-time.After(coretesting.LongWait): 132 c.Fatalf("failed to signal trigger creation") 133 } 134 return meterstatus.GetTriggers(state, status, disconectedAt, clk, amber, red) 135 } 136 137 s.clk = testclock.NewClock(time.Now()) 138 wrk, err := meterstatus.NewIsolatedStatusWorker( 139 meterstatus.IsolatedConfig{ 140 Runner: &stubRunner{stub: s.stub, ran: s.hookRan}, 141 StateReadWriter: meterstatus.NewDiskBackedState(path.Join(s.dataDir, "meter-status.yaml")), 142 Clock: s.clk, 143 Logger: loggo.GetLogger("test"), 144 AmberGracePeriod: AmberGracePeriod, 145 RedGracePeriod: RedGracePeriod, 146 TriggerFactory: triggerFactory, 147 }) 148 c.Assert(err, jc.ErrorIsNil) 149 c.Assert(wrk, gc.NotNil) 150 s.worker = wrk 151 } 152 153 func (s *IsolatedWorkerSuite) TearDownTest(c *gc.C) { 154 workertest.CleanKill(c, s.worker) 155 } 156 157 func (s *IsolatedWorkerSuite) TestTriggering(c *gc.C) { 158 assertSignal(c, s.triggersCreated) 159 160 // Wait on the red and amber timers. 161 c.Assert(s.clk.WaitAdvance(AmberGracePeriod+time.Second, testing.ShortWait, 2), jc.ErrorIsNil) 162 assertSignal(c, s.hookRan) 163 164 // Don't need to ensure the timers here, we did it for both above. 165 s.clk.Advance(RedGracePeriod + time.Second) 166 assertSignal(c, s.hookRan) 167 168 s.stub.CheckCallNames(c, "RunHook", "RunHook") 169 } 170 171 // TestMissingHookError tests that errors caused by missing hooks do not stop the worker. 172 func (s *IsolatedWorkerSuite) TestMissingHookError(c *gc.C) { 173 s.stub.SetErrors(charmrunner.NewMissingHookError("meter-status-changed")) 174 175 assertSignal(c, s.triggersCreated) 176 c.Assert(s.clk.WaitAdvance(AmberGracePeriod+time.Second, testing.ShortWait, 2), jc.ErrorIsNil) 177 assertSignal(c, s.hookRan) 178 179 s.stub.CheckCallNames(c, "RunHook") 180 } 181 182 // TestRandomHookError tests that errors returned by hooks do not stop the worker. 183 func (s *IsolatedWorkerSuite) TestRandomHookError(c *gc.C) { 184 s.stub.SetErrors(fmt.Errorf("blah")) 185 186 assertSignal(c, s.triggersCreated) 187 c.Assert(s.clk.WaitAdvance(AmberGracePeriod+time.Second, testing.ShortWait, 2), jc.ErrorIsNil) 188 assertSignal(c, s.hookRan) 189 190 s.stub.CheckCallNames(c, "RunHook") 191 }