github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/state/status_unitagent_test.go (about) 1 // Copyright 2012-2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package state_test 5 6 import ( 7 "fmt" 8 "time" // Only used for time types. 9 10 jc "github.com/juju/testing/checkers" 11 gc "gopkg.in/check.v1" 12 13 "github.com/juju/juju/core/status" 14 "github.com/juju/juju/state" 15 "github.com/juju/juju/testing" 16 "github.com/juju/juju/testing/factory" 17 ) 18 19 type StatusUnitAgentSuite struct { 20 ConnSuite 21 unit *state.Unit 22 agent *state.UnitAgent 23 } 24 25 var _ = gc.Suite(&StatusUnitAgentSuite{}) 26 27 func (s *StatusUnitAgentSuite) SetUpTest(c *gc.C) { 28 s.ConnSuite.SetUpTest(c) 29 s.unit = s.Factory.MakeUnit(c, nil) 30 s.agent = s.unit.Agent() 31 } 32 33 func (s *StatusUnitAgentSuite) TestInitialStatus(c *gc.C) { 34 s.checkInitialStatus(c) 35 } 36 37 func (s *StatusUnitAgentSuite) checkInitialStatus(c *gc.C) { 38 statusInfo, err := s.agent.Status() 39 c.Check(err, jc.ErrorIsNil) 40 checkInitialUnitAgentStatus(c, statusInfo) 41 } 42 43 func (s *StatusUnitAgentSuite) TestSetUnknownStatus(c *gc.C) { 44 now := testing.ZeroTime() 45 sInfo := status.StatusInfo{ 46 Status: status.Status("vliegkat"), 47 Message: "orville", 48 Since: &now, 49 } 50 err := s.agent.SetStatus(sInfo) 51 c.Check(err, gc.ErrorMatches, `cannot set invalid status "vliegkat"`) 52 53 s.checkInitialStatus(c) 54 } 55 56 func (s *StatusUnitAgentSuite) TestSetErrorStatusWithoutInfo(c *gc.C) { 57 now := testing.ZeroTime() 58 sInfo := status.StatusInfo{ 59 Status: status.Error, 60 Message: "", 61 Since: &now, 62 } 63 err := s.agent.SetStatus(sInfo) 64 c.Check(err, gc.ErrorMatches, `cannot set status "error" without info`) 65 66 s.checkInitialStatus(c) 67 } 68 69 func (s *StatusUnitAgentSuite) TestSetAllocatingStatusAlreadyAssigned(c *gc.C) { 70 now := testing.ZeroTime() 71 sInfo := status.StatusInfo{ 72 Status: status.Allocating, 73 Message: "", 74 Since: &now, 75 } 76 err := s.agent.SetStatus(sInfo) 77 c.Check(err, gc.ErrorMatches, `cannot set status "allocating" as unit is already assigned`) 78 79 s.checkInitialStatus(c) 80 } 81 82 func (s *StatusUnitAgentSuite) TestSetStatusUnassigned(c *gc.C) { 83 app := s.Factory.MakeApplication(c, &factory.ApplicationParams{Name: "foo"}) 84 u, err := app.AddUnit(state.AddUnitParams{}) 85 c.Assert(err, jc.ErrorIsNil) 86 agent := u.Agent() 87 for _, value := range []status.Status{status.Idle, status.Executing, status.Rebooting, status.Failed} { 88 now := testing.ZeroTime() 89 sInfo := status.StatusInfo{ 90 Status: value, 91 Message: "", 92 Since: &now, 93 } 94 err := agent.SetStatus(sInfo) 95 c.Check(err, gc.ErrorMatches, fmt.Sprintf(`cannot set status %q until unit is assigned`, value)) 96 97 s.checkInitialStatus(c) 98 } 99 } 100 101 func (s *StatusUnitAgentSuite) TestSetStatusRunningNonCAAS(c *gc.C) { 102 app := s.Factory.MakeApplication(c, &factory.ApplicationParams{Name: "foo"}) 103 u, err := app.AddUnit(state.AddUnitParams{}) 104 c.Assert(err, jc.ErrorIsNil) 105 agent := u.Agent() 106 now := testing.ZeroTime() 107 sInfo := status.StatusInfo{ 108 Status: status.Running, 109 Message: "", 110 Since: &now, 111 } 112 err = agent.SetStatus(sInfo) 113 c.Check(err, gc.ErrorMatches, `cannot set invalid status "running"`) 114 s.checkInitialStatus(c) 115 } 116 117 func (s *StatusUnitAgentSuite) TestSetOverwritesData(c *gc.C) { 118 now := testing.ZeroTime() 119 sInfo := status.StatusInfo{ 120 Status: status.Idle, 121 Message: "something", 122 Data: map[string]interface{}{ 123 "pew.pew": "zap", 124 }, 125 Since: &now, 126 } 127 err := s.agent.SetStatus(sInfo) 128 c.Check(err, jc.ErrorIsNil) 129 130 s.checkGetSetStatus(c) 131 } 132 133 func (s *StatusUnitAgentSuite) TestGetSetStatusAlive(c *gc.C) { 134 s.checkGetSetStatus(c) 135 } 136 137 func (s *StatusUnitAgentSuite) checkGetSetStatus(c *gc.C) { 138 now := testing.ZeroTime() 139 sInfo := status.StatusInfo{ 140 Status: status.Idle, 141 Message: "something", 142 Data: map[string]interface{}{ 143 "$foo": "bar", 144 "baz.qux": "ping", 145 "pong": map[string]interface{}{ 146 "$unset": "txn-revno", 147 }, 148 }, 149 Since: &now, 150 } 151 err := s.agent.SetStatus(sInfo) 152 c.Check(err, jc.ErrorIsNil) 153 154 unit, err := s.State.Unit(s.unit.Name()) 155 c.Assert(err, jc.ErrorIsNil) 156 agent := unit.Agent() 157 158 statusInfo, err := agent.Status() 159 c.Check(err, jc.ErrorIsNil) 160 c.Check(statusInfo.Status, gc.Equals, status.Idle) 161 c.Check(statusInfo.Message, gc.Equals, "something") 162 c.Check(statusInfo.Data, jc.DeepEquals, map[string]interface{}{ 163 "$foo": "bar", 164 "baz.qux": "ping", 165 "pong": map[string]interface{}{ 166 "$unset": "txn-revno", 167 }, 168 }) 169 c.Check(statusInfo.Since, gc.NotNil) 170 } 171 172 func (s *StatusUnitAgentSuite) TestGetSetStatusDying(c *gc.C) { 173 preventUnitDestroyRemove(c, s.unit) 174 err := s.unit.Destroy() 175 c.Assert(err, jc.ErrorIsNil) 176 177 s.checkGetSetStatus(c) 178 } 179 180 func (s *StatusUnitAgentSuite) TestGetSetStatusDead(c *gc.C) { 181 preventUnitDestroyRemove(c, s.unit) 182 err := s.unit.Destroy() 183 c.Assert(err, jc.ErrorIsNil) 184 err = s.unit.EnsureDead() 185 c.Assert(err, jc.ErrorIsNil) 186 187 // NOTE: it would be more technically correct to reject status updates 188 // while Dead, but it's easier and clearer, not to mention more efficient, 189 // to just depend on status doc existence. 190 s.checkGetSetStatus(c) 191 } 192 193 func (s *StatusUnitAgentSuite) TestGetSetStatusGone(c *gc.C) { 194 err := s.unit.Destroy() 195 c.Assert(err, jc.ErrorIsNil) 196 197 now := testing.ZeroTime() 198 sInfo := status.StatusInfo{ 199 Status: status.Idle, 200 Message: "not really", 201 Since: &now, 202 } 203 err = s.agent.SetStatus(sInfo) 204 c.Check(err, gc.ErrorMatches, `cannot set status: agent not found`) 205 206 statusInfo, err := s.agent.Status() 207 c.Check(err, gc.ErrorMatches, `cannot get status: agent not found`) 208 c.Check(statusInfo, gc.DeepEquals, status.StatusInfo{}) 209 } 210 211 func (s *StatusUnitAgentSuite) TestGetSetErrorStatus(c *gc.C) { 212 now := testing.ZeroTime() 213 sInfo := status.StatusInfo{ 214 Status: status.Error, 215 Message: "test-hook failed", 216 Data: map[string]interface{}{ 217 "foo": "bar", 218 }, 219 Since: &now, 220 } 221 err := s.agent.SetStatus(sInfo) 222 c.Assert(err, jc.ErrorIsNil) 223 224 // Agent error is reported as unit error. 225 statusInfo, err := s.unit.Status() 226 c.Check(err, jc.ErrorIsNil) 227 c.Check(statusInfo.Status, gc.Equals, status.Error) 228 c.Check(statusInfo.Message, gc.Equals, "test-hook failed") 229 c.Check(statusInfo.Data, gc.DeepEquals, map[string]interface{}{ 230 "foo": "bar", 231 }) 232 233 // For agents, error is reported as idle. 234 statusInfo, err = s.agent.Status() 235 c.Check(err, jc.ErrorIsNil) 236 c.Check(statusInfo.Status, gc.Equals, status.Idle) 237 c.Check(statusInfo.Message, gc.Equals, "") 238 c.Check(statusInfo.Data, gc.HasLen, 0) 239 } 240 241 func timeBeforeOrEqual(timeBefore, timeOther time.Time) bool { 242 return timeBefore.Before(timeOther) || timeBefore.Equal(timeOther) 243 } 244 245 func (s *StatusUnitAgentSuite) TestSetAgentStatusSince(c *gc.C) { 246 now := testing.ZeroTime() 247 sInfo := status.StatusInfo{ 248 Status: status.Idle, 249 Message: "", 250 Since: &now, 251 } 252 err := s.agent.SetStatus(sInfo) 253 c.Assert(err, jc.ErrorIsNil) 254 statusInfo, err := s.agent.Status() 255 c.Assert(err, jc.ErrorIsNil) 256 firstTime := statusInfo.Since 257 c.Assert(firstTime, gc.NotNil) 258 c.Assert(timeBeforeOrEqual(now, *firstTime), jc.IsTrue) 259 260 // Setting the same status a second time also updates the timestamp. 261 now = now.Add(1 * time.Second) 262 sInfo = status.StatusInfo{ 263 Status: status.Idle, 264 Message: "", 265 Since: &now, 266 } 267 err = s.agent.SetStatus(sInfo) 268 c.Assert(err, jc.ErrorIsNil) 269 statusInfo, err = s.agent.Status() 270 c.Assert(err, jc.ErrorIsNil) 271 c.Assert(timeBeforeOrEqual(*firstTime, *statusInfo.Since), jc.IsTrue) 272 } 273 274 func (s *StatusUnitAgentSuite) TestStatusHistoryInitial(c *gc.C) { 275 history, err := s.agent.StatusHistory(status.StatusHistoryFilter{Size: 1}) 276 c.Check(err, jc.ErrorIsNil) 277 c.Assert(history, gc.HasLen, 1) 278 279 checkInitialUnitAgentStatus(c, history[0]) 280 } 281 282 func (s *StatusUnitAgentSuite) TestStatusHistoryShort(c *gc.C) { 283 primeUnitAgentStatusHistory(c, s.Clock, s.agent, 5, 0, "") 284 285 history, err := s.agent.StatusHistory(status.StatusHistoryFilter{Size: 10}) 286 c.Check(err, jc.ErrorIsNil) 287 c.Assert(history, gc.HasLen, 6) 288 289 checkInitialUnitAgentStatus(c, history[5]) 290 history = history[:5] 291 for i, statusInfo := range history { 292 checkPrimedUnitAgentStatus(c, statusInfo, 4-i, 0) 293 } 294 } 295 296 func (s *StatusUnitAgentSuite) TestStatusHistoryLong(c *gc.C) { 297 primeUnitAgentStatusHistory(c, s.Clock, s.agent, 25, 0, "") 298 299 history, err := s.agent.StatusHistory(status.StatusHistoryFilter{Size: 15}) 300 c.Check(err, jc.ErrorIsNil) 301 c.Check(history, gc.HasLen, 15) 302 for i, statusInfo := range history { 303 checkPrimedUnitAgentStatus(c, statusInfo, 24-i, 0) 304 } 305 }