github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/state/status_service_test.go (about) 1 // Copyright 2015 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 "github.com/juju/juju/status" 14 "github.com/juju/juju/testing" 15 ) 16 17 type ServiceStatusSuite struct { 18 ConnSuite 19 service *state.Application 20 } 21 22 var _ = gc.Suite(&ServiceStatusSuite{}) 23 24 func (s *ServiceStatusSuite) SetUpTest(c *gc.C) { 25 s.ConnSuite.SetUpTest(c) 26 s.service = s.Factory.MakeApplication(c, nil) 27 } 28 29 func (s *ServiceStatusSuite) TestInitialStatus(c *gc.C) { 30 s.checkInitialStatus(c) 31 } 32 33 func (s *ServiceStatusSuite) checkInitialStatus(c *gc.C) { 34 statusInfo, err := s.service.Status() 35 c.Check(err, jc.ErrorIsNil) 36 checkInitialWorkloadStatus(c, statusInfo) 37 } 38 39 func (s *ServiceStatusSuite) TestSetUnknownStatus(c *gc.C) { 40 now := testing.ZeroTime() 41 sInfo := status.StatusInfo{ 42 Status: status.Status("vliegkat"), 43 Message: "orville", 44 Since: &now, 45 } 46 err := s.service.SetStatus(sInfo) 47 c.Check(err, gc.ErrorMatches, `cannot set invalid status "vliegkat"`) 48 49 s.checkInitialStatus(c) 50 } 51 52 func (s *ServiceStatusSuite) TestSetOverwritesData(c *gc.C) { 53 now := testing.ZeroTime() 54 sInfo := status.StatusInfo{ 55 Status: status.Active, 56 Message: "healthy", 57 Data: map[string]interface{}{ 58 "pew.pew": "zap", 59 }, 60 Since: &now, 61 } 62 err := s.service.SetStatus(sInfo) 63 c.Check(err, jc.ErrorIsNil) 64 65 s.checkGetSetStatus(c) 66 } 67 68 func (s *ServiceStatusSuite) TestGetSetStatusAlive(c *gc.C) { 69 s.checkGetSetStatus(c) 70 } 71 72 func (s *ServiceStatusSuite) checkGetSetStatus(c *gc.C) { 73 now := testing.ZeroTime() 74 sInfo := status.StatusInfo{ 75 Status: status.Active, 76 Message: "healthy", 77 Data: map[string]interface{}{ 78 "$ping": map[string]interface{}{ 79 "foo.bar": 123, 80 }, 81 }, 82 Since: &now, 83 } 84 err := s.service.SetStatus(sInfo) 85 c.Check(err, jc.ErrorIsNil) 86 87 service, err := s.State.Application(s.service.Name()) 88 c.Assert(err, jc.ErrorIsNil) 89 90 statusInfo, err := service.Status() 91 c.Check(err, jc.ErrorIsNil) 92 c.Check(statusInfo.Status, gc.Equals, status.Active) 93 c.Check(statusInfo.Message, gc.Equals, "healthy") 94 c.Check(statusInfo.Data, jc.DeepEquals, map[string]interface{}{ 95 "$ping": map[string]interface{}{ 96 "foo.bar": 123, 97 }, 98 }) 99 c.Check(statusInfo.Since, gc.NotNil) 100 } 101 102 func (s *ServiceStatusSuite) TestGetSetStatusDying(c *gc.C) { 103 _, err := s.service.AddUnit() 104 c.Assert(err, jc.ErrorIsNil) 105 err = s.service.Destroy() 106 c.Assert(err, jc.ErrorIsNil) 107 108 s.checkGetSetStatus(c) 109 } 110 111 func (s *ServiceStatusSuite) TestGetSetStatusGone(c *gc.C) { 112 err := s.service.Destroy() 113 c.Assert(err, jc.ErrorIsNil) 114 115 now := testing.ZeroTime() 116 sInfo := status.StatusInfo{ 117 Status: status.Active, 118 Message: "not really", 119 Since: &now, 120 } 121 err = s.service.SetStatus(sInfo) 122 c.Check(err, gc.ErrorMatches, `cannot set status: application not found`) 123 124 statusInfo, err := s.service.Status() 125 c.Check(err, gc.ErrorMatches, `cannot get status: application not found`) 126 c.Check(statusInfo, gc.DeepEquals, status.StatusInfo{}) 127 } 128 129 func (s *ServiceStatusSuite) TestSetStatusSince(c *gc.C) { 130 now := testing.ZeroTime() 131 sInfo := status.StatusInfo{ 132 Status: status.Maintenance, 133 Message: "", 134 Since: &now, 135 } 136 err := s.service.SetStatus(sInfo) 137 c.Assert(err, jc.ErrorIsNil) 138 statusInfo, err := s.service.Status() 139 c.Assert(err, jc.ErrorIsNil) 140 firstTime := statusInfo.Since 141 c.Assert(firstTime, gc.NotNil) 142 c.Assert(timeBeforeOrEqual(now, *firstTime), jc.IsTrue) 143 144 // Setting the same status a second time also updates the timestamp. 145 now = now.Add(1 * time.Second) 146 sInfo = status.StatusInfo{ 147 Status: status.Maintenance, 148 Message: "", 149 Since: &now, 150 } 151 err = s.service.SetStatus(sInfo) 152 c.Assert(err, jc.ErrorIsNil) 153 statusInfo, err = s.service.Status() 154 c.Assert(err, jc.ErrorIsNil) 155 c.Assert(timeBeforeOrEqual(*firstTime, *statusInfo.Since), jc.IsTrue) 156 } 157 158 func (s *ServiceStatusSuite) TestDeriveStatus(c *gc.C) { 159 // NOTE(fwereade): as detailed in the code, this implementation is not sane. 160 // The specified behaviour is arguably sane, but the code is in the wrong 161 // place. 162 163 // Create a unit with each possible status. 164 addUnit := func(unitStatus status.Status) *state.Unit { 165 unit, err := s.service.AddUnit() 166 c.Assert(err, gc.IsNil) 167 now := testing.ZeroTime() 168 sInfo := status.StatusInfo{ 169 Status: unitStatus, 170 Message: "blam", 171 Since: &now, 172 } 173 err = unit.SetStatus(sInfo) 174 c.Assert(err, gc.IsNil) 175 return unit 176 } 177 blockedUnit := addUnit(status.Blocked) 178 waitingUnit := addUnit(status.Waiting) 179 maintenanceUnit := addUnit(status.Maintenance) 180 terminatedUnit := addUnit(status.Terminated) 181 activeUnit := addUnit(status.Active) 182 unknownUnit := addUnit(status.Unknown) 183 184 // ...and create one with error status by setting it on the agent :-/. 185 errorUnit, err := s.service.AddUnit() 186 c.Assert(err, gc.IsNil) 187 now := testing.ZeroTime() 188 sInfo := status.StatusInfo{ 189 Status: status.Error, 190 Message: "blam", 191 Since: &now, 192 } 193 err = errorUnit.Agent().SetStatus(sInfo) 194 c.Assert(err, gc.IsNil) 195 196 // For each status, in order of severity, check the service status is 197 // derived from that unit status; then remove that unit and proceed to 198 // the next severity. 199 checkAndRemove := func(unit *state.Unit, status status.Status) { 200 info, err := s.service.Status() 201 c.Check(err, jc.ErrorIsNil) 202 c.Check(info.Status, gc.Equals, status) 203 204 err = unit.Destroy() 205 c.Assert(err, jc.ErrorIsNil) 206 err = unit.EnsureDead() 207 c.Assert(err, jc.ErrorIsNil) 208 err = unit.Remove() 209 c.Assert(err, jc.ErrorIsNil) 210 } 211 checkAndRemove(errorUnit, status.Error) 212 checkAndRemove(blockedUnit, status.Blocked) 213 checkAndRemove(waitingUnit, status.Waiting) 214 checkAndRemove(maintenanceUnit, status.Maintenance) 215 checkAndRemove(terminatedUnit, status.Terminated) 216 checkAndRemove(activeUnit, status.Active) 217 checkAndRemove(unknownUnit, status.Unknown) 218 } 219 220 func (s *ServiceStatusSuite) TestServiceStatusOverridesDerivedStatus(c *gc.C) { 221 unit, err := s.service.AddUnit() 222 c.Assert(err, gc.IsNil) 223 now := testing.ZeroTime() 224 sInfo := status.StatusInfo{ 225 Status: status.Blocked, 226 Message: "pow", 227 Since: &now, 228 } 229 err = unit.SetStatus(sInfo) 230 c.Assert(err, gc.IsNil) 231 sInfo = status.StatusInfo{ 232 Status: status.Maintenance, 233 Message: "zot", 234 Since: &now, 235 } 236 err = s.service.SetStatus(sInfo) 237 c.Assert(err, gc.IsNil) 238 239 info, err := s.service.Status() 240 c.Check(err, jc.ErrorIsNil) 241 c.Check(info.Status, gc.Equals, status.Maintenance) 242 }