github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/state/meterstatus_test.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package state_test 5 6 import ( 7 "time" 8 9 "github.com/juju/mgo/v3/bson" 10 jc "github.com/juju/testing/checkers" 11 gc "gopkg.in/check.v1" 12 13 "github.com/juju/juju/state" 14 statetesting "github.com/juju/juju/state/testing" 15 ) 16 17 type MeterStateSuite struct { 18 ConnSuite 19 unit *state.Unit 20 metricsManager *state.MetricsManager 21 } 22 23 var _ = gc.Suite(&MeterStateSuite{}) 24 25 func (s *MeterStateSuite) SetUpTest(c *gc.C) { 26 s.ConnSuite.SetUpTest(c) 27 s.unit = s.Factory.MakeUnit(c, nil) 28 c.Assert(s.unit.Base(), jc.DeepEquals, state.Base{OS: "ubuntu", Channel: "12.10/stable"}) 29 var err error 30 s.metricsManager, err = s.State.MetricsManager() 31 c.Assert(err, jc.ErrorIsNil) 32 // Before we get into the tests, ensure that all the creation events have flowed through the system. 33 s.WaitForModelWatchersIdle(c, s.Model.UUID()) 34 } 35 36 func (s *MeterStateSuite) TestMeterStatus(c *gc.C) { 37 status, err := s.unit.GetMeterStatus() 38 c.Assert(err, jc.ErrorIsNil) 39 c.Assert(status.Code, gc.Equals, state.MeterNotSet) 40 err = s.unit.SetMeterStatus("GREEN", "Additional information.") 41 c.Assert(err, jc.ErrorIsNil) 42 status, err = s.unit.GetMeterStatus() 43 c.Assert(err, jc.ErrorIsNil) 44 c.Assert(status.Code, gc.Equals, state.MeterGreen) 45 } 46 47 func (s *MeterStateSuite) TestMeterStatusIncludesModelUUID(c *gc.C) { 48 jujuDB := s.MgoSuite.Session.DB("juju") 49 meterStatus := jujuDB.C("meterStatus") 50 var docs []bson.M 51 err := meterStatus.Find(nil).All(&docs) 52 c.Assert(err, jc.ErrorIsNil) 53 // we now expect two meter status docs - one for the unit and one 54 // for the model - both should have the model-uuid filled in. 55 c.Assert(docs, gc.HasLen, 2) 56 c.Assert(docs[0]["model-uuid"], gc.Equals, s.State.ModelUUID()) 57 c.Assert(docs[1]["model-uuid"], gc.Equals, s.State.ModelUUID()) 58 } 59 60 func (s *MeterStateSuite) TestSetMeterStatusIncorrect(c *gc.C) { 61 err := s.unit.SetMeterStatus("NOT SET", "Additional information.") 62 c.Assert(err, gc.ErrorMatches, `meter status "NOT SET" not valid`) 63 status, err := s.unit.GetMeterStatus() 64 c.Assert(err, jc.ErrorIsNil) 65 c.Assert(status.Code, gc.Equals, state.MeterNotSet) 66 67 err = s.unit.SetMeterStatus("this-is-not-a-valid-status", "Additional information.") 68 c.Assert(err, gc.ErrorMatches, `meter status "this-is-not-a-valid-status" not valid`) 69 status, err = s.unit.GetMeterStatus() 70 c.Assert(err, jc.ErrorIsNil) 71 c.Assert(status.Code, gc.Equals, state.MeterNotSet) 72 } 73 74 func (s *MeterStateSuite) TestSetMeterStatusWhenDying(c *gc.C) { 75 preventUnitDestroyRemove(c, s.unit) 76 testWhenDying(c, s.unit, ".*"+contentionErr, contentionErr, func() error { 77 err := s.unit.SetMeterStatus("GREEN", "Additional information.") 78 if err != nil { 79 return err 80 } 81 status, err := s.unit.GetMeterStatus() 82 c.Assert(err, jc.ErrorIsNil) 83 c.Assert(status.Code, gc.Equals, state.MeterNotSet) 84 return nil 85 }) 86 } 87 88 func (s *MeterStateSuite) TestMeterStatusRemovedWithUnit(c *gc.C) { 89 err := s.unit.SetMeterStatus("GREEN", "Information.") 90 c.Assert(err, jc.ErrorIsNil) 91 err = s.unit.EnsureDead() 92 c.Assert(err, jc.ErrorIsNil) 93 err = s.unit.Remove() 94 c.Assert(err, jc.ErrorIsNil) 95 status, err := s.unit.GetMeterStatus() 96 c.Assert(err, gc.ErrorMatches, "cannot retrieve meter status for unit .*: not found") 97 c.Assert(status.Code, gc.Equals, state.MeterNotAvailable) 98 } 99 100 func (s *MeterStateSuite) TestMeterStatusWatcherRespondstoMeterStatus(c *gc.C) { 101 watcher := s.unit.WatchMeterStatus() 102 wc := statetesting.NewNotifyWatcherC(c, watcher) 103 wc.AssertOneChange() 104 err := s.unit.SetMeterStatus("GREEN", "Information.") 105 c.Assert(err, jc.ErrorIsNil) 106 wc.AssertOneChange() 107 } 108 109 func (s *MeterStateSuite) TestMeterStatusWatcherRespondsToMetricsManager(c *gc.C) { 110 mm, err := s.State.MetricsManager() 111 c.Assert(err, jc.ErrorIsNil) 112 watcher := s.unit.WatchMeterStatus() 113 wc := statetesting.NewNotifyWatcherC(c, watcher) 114 wc.AssertOneChange() 115 err = mm.SetLastSuccessfulSend(s.Clock.Now()) 116 c.Assert(err, jc.ErrorIsNil) 117 wc.AssertOneChange() 118 for i := 0; i < 3; i++ { 119 err := mm.IncrementConsecutiveErrors() 120 c.Assert(err, jc.ErrorIsNil) 121 } 122 status := mm.MeterStatus() 123 c.Assert(status.Code, gc.Equals, state.MeterAmber) 124 wc.AssertOneChange() 125 } 126 127 func (s *MeterStateSuite) TestMeterStatusWatcherRespondsToMetricsManagerAndStatus(c *gc.C) { 128 mm, err := s.State.MetricsManager() 129 c.Assert(err, jc.ErrorIsNil) 130 watcher := s.unit.WatchMeterStatus() 131 wc := statetesting.NewNotifyWatcherC(c, watcher) 132 wc.AssertOneChange() 133 err = mm.SetLastSuccessfulSend(s.Clock.Now()) 134 c.Assert(err, jc.ErrorIsNil) 135 wc.AssertOneChange() 136 for i := 0; i < 3; i++ { 137 err := mm.IncrementConsecutiveErrors() 138 c.Assert(err, jc.ErrorIsNil) 139 } 140 status := mm.MeterStatus() 141 c.Assert(status.Code, gc.Equals, state.MeterAmber) 142 wc.AssertOneChange() 143 err = s.unit.SetMeterStatus("GREEN", "Information.") 144 c.Assert(err, jc.ErrorIsNil) 145 wc.AssertOneChange() 146 } 147 148 func (s *MeterStateSuite) assertMetricsManagerAmberState(c *gc.C, metricsManager *state.MetricsManager) { 149 err := metricsManager.SetLastSuccessfulSend(s.Clock.Now()) 150 c.Assert(err, jc.ErrorIsNil) 151 for i := 0; i < 3; i++ { 152 err := metricsManager.IncrementConsecutiveErrors() 153 c.Assert(err, jc.ErrorIsNil) 154 } 155 status := metricsManager.MeterStatus() 156 c.Assert(status.Code, gc.Equals, state.MeterAmber, gc.Commentf("got meter status %#v", status)) 157 } 158 159 // TODO (mattyw) This function could be moved into a metricsmanager testing package. 160 func (s *MeterStateSuite) assertMetricsManagerRedState(c *gc.C, metricsManager *state.MetricsManager) { 161 // To enter the red state we need to set a last successful send as over 1 week ago 162 err := metricsManager.SetLastSuccessfulSend(s.Clock.Now().Add(-8 * 24 * time.Hour)) 163 c.Assert(err, jc.ErrorIsNil) 164 for i := 0; i < 3; i++ { 165 err := metricsManager.IncrementConsecutiveErrors() 166 c.Assert(err, jc.ErrorIsNil) 167 } 168 status := metricsManager.MeterStatus() 169 c.Assert(status.Code, gc.Equals, state.MeterRed, gc.Commentf("got meter status %#v", status)) 170 } 171 172 // TestMeterStatusMetricsManagerCombinations test every possible combination 173 // of meter status from the unit and the metrics manager. 174 func (s *MeterStateSuite) TestMeterStatusMetricsManagerCombinations(c *gc.C) { 175 greenMetricsMangager := func() {} 176 amberMetricsManager := func() { 177 s.assertMetricsManagerAmberState(c, s.metricsManager) 178 } 179 redMetricsManager := func() { 180 s.assertMetricsManagerRedState(c, s.metricsManager) 181 } 182 greenUnit := func() { 183 err := s.unit.SetMeterStatus("GREEN", "Unit") 184 c.Assert(err, jc.ErrorIsNil) 185 } 186 amberUnit := func() { 187 err := s.unit.SetMeterStatus("AMBER", "Unit") 188 c.Assert(err, jc.ErrorIsNil) 189 } 190 redUnit := func() { 191 err := s.unit.SetMeterStatus("RED", "Unit") 192 c.Assert(err, jc.ErrorIsNil) 193 } 194 195 tests := []struct { 196 about string 197 metricsManager func() 198 unit func() 199 expectedCode state.MeterStatusCode 200 expectedInfo string 201 }{{ 202 "green metrics manager and green unit returns green overall", 203 greenMetricsMangager, 204 greenUnit, 205 state.MeterGreen, 206 "Unit", 207 }, { 208 "amber metrics manager and amber unit returns amber overall", 209 amberMetricsManager, 210 amberUnit, 211 state.MeterAmber, 212 "Unit", 213 }, { 214 "red metrics manager and red unit returns red overall", 215 redMetricsManager, 216 redUnit, 217 state.MeterRed, 218 "failed to send metrics, exceeded grace period", 219 }, { 220 221 "red metrics manager and amber unit returns red overall", 222 redMetricsManager, 223 amberUnit, 224 state.MeterRed, 225 "failed to send metrics, exceeded grace period", 226 }, { 227 "red metrics manager and green unit returns red overall", 228 redMetricsManager, 229 greenUnit, 230 state.MeterRed, 231 "failed to send metrics, exceeded grace period", 232 }, { 233 "amber metrics manager and red unit returns red overall", 234 amberMetricsManager, 235 redUnit, 236 state.MeterRed, 237 "Unit", 238 }, { 239 "amber metrics manager and green unit returns amber overall", 240 amberMetricsManager, 241 greenUnit, 242 state.MeterAmber, 243 "failed to send metrics", 244 }, { 245 "green metrics manager and red unit returns red overall", 246 greenMetricsMangager, 247 redUnit, 248 state.MeterRed, 249 "Unit", 250 }, { 251 "green metrics manager and amber unit returns amber overall", 252 greenMetricsMangager, 253 amberUnit, 254 state.MeterAmber, 255 "Unit", 256 }} 257 258 for i, test := range tests { 259 c.Logf("running test %d %s", i, test.about) 260 test.metricsManager() 261 test.unit() 262 status, err := s.unit.GetMeterStatus() 263 c.Assert(err, jc.ErrorIsNil) 264 c.Check(status.Code, gc.Equals, test.expectedCode, gc.Commentf("got meter status %#v", status)) 265 } 266 } 267 268 func (s *MeterStateSuite) TestMeterStatusCombination(c *gc.C) { 269 var ( 270 Red = state.MeterStatus{state.MeterRed, ""} 271 Amber = state.MeterStatus{state.MeterAmber, ""} 272 Green = state.MeterStatus{state.MeterGreen, ""} 273 NotSet = state.MeterStatus{state.MeterNotSet, ""} 274 NotAvailable = state.MeterStatus{state.MeterNotAvailable, ""} 275 ) 276 c.Assert(state.CombineMeterStatus(Red, Red).Code, gc.Equals, Red.Code) 277 c.Assert(state.CombineMeterStatus(Red, Amber).Code, gc.Equals, Red.Code) 278 c.Assert(state.CombineMeterStatus(Red, Green).Code, gc.Equals, Red.Code) 279 c.Assert(state.CombineMeterStatus(Red, NotSet).Code, gc.Equals, Red.Code) 280 c.Assert(state.CombineMeterStatus(Red, NotAvailable).Code, gc.Equals, NotAvailable.Code) 281 282 c.Assert(state.CombineMeterStatus(Amber, Red).Code, gc.Equals, Red.Code) 283 c.Assert(state.CombineMeterStatus(Amber, Amber).Code, gc.Equals, Amber.Code) 284 c.Assert(state.CombineMeterStatus(Amber, Green).Code, gc.Equals, Amber.Code) 285 c.Assert(state.CombineMeterStatus(Amber, NotSet).Code, gc.Equals, Amber.Code) 286 c.Assert(state.CombineMeterStatus(Amber, NotAvailable).Code, gc.Equals, NotAvailable.Code) 287 288 c.Assert(state.CombineMeterStatus(Green, Red).Code, gc.Equals, Red.Code) 289 c.Assert(state.CombineMeterStatus(Green, Amber).Code, gc.Equals, Amber.Code) 290 c.Assert(state.CombineMeterStatus(Green, Green).Code, gc.Equals, Green.Code) 291 c.Assert(state.CombineMeterStatus(Green, NotSet).Code, gc.Equals, NotSet.Code) 292 c.Assert(state.CombineMeterStatus(Green, NotAvailable).Code, gc.Equals, NotAvailable.Code) 293 294 c.Assert(state.CombineMeterStatus(NotSet, Red).Code, gc.Equals, Red.Code) 295 c.Assert(state.CombineMeterStatus(NotSet, Amber).Code, gc.Equals, Amber.Code) 296 c.Assert(state.CombineMeterStatus(NotSet, Green).Code, gc.Equals, NotSet.Code) 297 c.Assert(state.CombineMeterStatus(NotSet, NotSet).Code, gc.Equals, NotSet.Code) 298 c.Assert(state.CombineMeterStatus(NotSet, NotAvailable).Code, gc.Equals, NotAvailable.Code) 299 300 c.Assert(state.CombineMeterStatus(NotAvailable, Red).Code, gc.Equals, NotAvailable.Code) 301 c.Assert(state.CombineMeterStatus(NotAvailable, Amber).Code, gc.Equals, NotAvailable.Code) 302 c.Assert(state.CombineMeterStatus(NotAvailable, Green).Code, gc.Equals, NotAvailable.Code) 303 c.Assert(state.CombineMeterStatus(NotAvailable, NotSet).Code, gc.Equals, NotAvailable.Code) 304 c.Assert(state.CombineMeterStatus(NotAvailable, NotAvailable).Code, gc.Equals, NotAvailable.Code) 305 }