github.com/mattyw/juju@v0.0.0-20140610034352-732aecd63861/state/api/uniter/unit_test.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package uniter_test 5 6 import ( 7 "sort" 8 9 "github.com/juju/errors" 10 jc "github.com/juju/testing/checkers" 11 gc "launchpad.net/gocheck" 12 13 "github.com/juju/juju/charm" 14 "github.com/juju/juju/instance" 15 "github.com/juju/juju/state" 16 "github.com/juju/juju/state/api/params" 17 "github.com/juju/juju/state/api/uniter" 18 statetesting "github.com/juju/juju/state/testing" 19 ) 20 21 type unitSuite struct { 22 uniterSuite 23 24 apiUnit *uniter.Unit 25 } 26 27 var _ = gc.Suite(&unitSuite{}) 28 29 func (s *unitSuite) SetUpTest(c *gc.C) { 30 s.uniterSuite.SetUpTest(c) 31 32 var err error 33 s.apiUnit, err = s.uniter.Unit(s.wordpressUnit.Tag()) 34 c.Assert(err, gc.IsNil) 35 } 36 37 func (s *unitSuite) TearDownTest(c *gc.C) { 38 s.uniterSuite.TearDownTest(c) 39 } 40 41 func (s *unitSuite) TestUnitAndUnitTag(c *gc.C) { 42 apiUnitFoo, err := s.uniter.Unit("unit-foo-42") 43 c.Assert(err, gc.ErrorMatches, "permission denied") 44 c.Assert(err, jc.Satisfies, params.IsCodeUnauthorized) 45 c.Assert(apiUnitFoo, gc.IsNil) 46 47 c.Assert(s.apiUnit.Tag(), gc.Equals, "unit-wordpress-0") 48 } 49 50 func (s *unitSuite) TestSetStatus(c *gc.C) { 51 status, info, data, err := s.wordpressUnit.Status() 52 c.Assert(err, gc.IsNil) 53 c.Assert(status, gc.Equals, params.StatusPending) 54 c.Assert(info, gc.Equals, "") 55 c.Assert(data, gc.HasLen, 0) 56 57 err = s.apiUnit.SetStatus(params.StatusStarted, "blah", nil) 58 c.Assert(err, gc.IsNil) 59 60 status, info, data, err = s.wordpressUnit.Status() 61 c.Assert(err, gc.IsNil) 62 c.Assert(status, gc.Equals, params.StatusStarted) 63 c.Assert(info, gc.Equals, "blah") 64 c.Assert(data, gc.HasLen, 0) 65 } 66 67 func (s *unitSuite) TestEnsureDead(c *gc.C) { 68 c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Alive) 69 70 err := s.apiUnit.EnsureDead() 71 c.Assert(err, gc.IsNil) 72 73 err = s.wordpressUnit.Refresh() 74 c.Assert(err, gc.IsNil) 75 c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Dead) 76 77 err = s.apiUnit.EnsureDead() 78 c.Assert(err, gc.IsNil) 79 err = s.wordpressUnit.Refresh() 80 c.Assert(err, gc.IsNil) 81 c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Dead) 82 83 err = s.wordpressUnit.Remove() 84 c.Assert(err, gc.IsNil) 85 err = s.wordpressUnit.Refresh() 86 c.Assert(err, jc.Satisfies, errors.IsNotFound) 87 88 err = s.apiUnit.EnsureDead() 89 c.Assert(err, gc.ErrorMatches, `unit "wordpress/0" not found`) 90 c.Assert(err, jc.Satisfies, params.IsCodeNotFound) 91 } 92 93 func (s *unitSuite) TestDestroy(c *gc.C) { 94 c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Alive) 95 96 err := s.apiUnit.Destroy() 97 c.Assert(err, gc.IsNil) 98 99 err = s.wordpressUnit.Refresh() 100 c.Assert(err, gc.ErrorMatches, `unit "wordpress/0" not found`) 101 } 102 103 func (s *unitSuite) TestDestroyAllSubordinates(c *gc.C) { 104 c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Alive) 105 106 // Call without subordinates - no change. 107 err := s.apiUnit.DestroyAllSubordinates() 108 c.Assert(err, gc.IsNil) 109 110 // Add a couple of subordinates and try again. 111 _, _, loggingSub := s.addRelatedService(c, "wordpress", "logging", s.wordpressUnit) 112 _, _, monitoringSub := s.addRelatedService(c, "wordpress", "monitoring", s.wordpressUnit) 113 c.Assert(loggingSub.Life(), gc.Equals, state.Alive) 114 c.Assert(monitoringSub.Life(), gc.Equals, state.Alive) 115 116 err = s.apiUnit.DestroyAllSubordinates() 117 c.Assert(err, gc.IsNil) 118 119 // Verify they got destroyed. 120 err = loggingSub.Refresh() 121 c.Assert(err, gc.IsNil) 122 c.Assert(loggingSub.Life(), gc.Equals, state.Dying) 123 err = monitoringSub.Refresh() 124 c.Assert(err, gc.IsNil) 125 c.Assert(monitoringSub.Life(), gc.Equals, state.Dying) 126 } 127 128 func (s *unitSuite) TestRefresh(c *gc.C) { 129 c.Assert(s.apiUnit.Life(), gc.Equals, params.Alive) 130 131 err := s.apiUnit.EnsureDead() 132 c.Assert(err, gc.IsNil) 133 c.Assert(s.apiUnit.Life(), gc.Equals, params.Alive) 134 135 err = s.apiUnit.Refresh() 136 c.Assert(err, gc.IsNil) 137 c.Assert(s.apiUnit.Life(), gc.Equals, params.Dead) 138 } 139 140 func (s *unitSuite) TestWatch(c *gc.C) { 141 c.Assert(s.apiUnit.Life(), gc.Equals, params.Alive) 142 143 w, err := s.apiUnit.Watch() 144 c.Assert(err, gc.IsNil) 145 defer statetesting.AssertStop(c, w) 146 wc := statetesting.NewNotifyWatcherC(c, s.BackingState, w) 147 148 // Initial event. 149 wc.AssertOneChange() 150 151 // Change something other than the lifecycle and make sure it's 152 // not detected. 153 err = s.apiUnit.SetStatus(params.StatusStarted, "not really", nil) 154 c.Assert(err, gc.IsNil) 155 wc.AssertNoChange() 156 157 // Make the unit dead and check it's detected. 158 err = s.apiUnit.EnsureDead() 159 c.Assert(err, gc.IsNil) 160 wc.AssertOneChange() 161 162 statetesting.AssertStop(c, w) 163 wc.AssertClosed() 164 } 165 166 func (s *unitSuite) TestResolve(c *gc.C) { 167 err := s.wordpressUnit.SetResolved(state.ResolvedRetryHooks) 168 c.Assert(err, gc.IsNil) 169 170 mode, err := s.apiUnit.Resolved() 171 c.Assert(err, gc.IsNil) 172 c.Assert(mode, gc.Equals, params.ResolvedRetryHooks) 173 174 err = s.apiUnit.ClearResolved() 175 c.Assert(err, gc.IsNil) 176 177 mode, err = s.apiUnit.Resolved() 178 c.Assert(err, gc.IsNil) 179 c.Assert(mode, gc.Equals, params.ResolvedNone) 180 } 181 182 func (s *unitSuite) TestIsPrincipal(c *gc.C) { 183 ok, err := s.apiUnit.IsPrincipal() 184 c.Assert(err, gc.IsNil) 185 c.Assert(ok, jc.IsTrue) 186 } 187 188 func (s *unitSuite) TestHasSubordinates(c *gc.C) { 189 found, err := s.apiUnit.HasSubordinates() 190 c.Assert(err, gc.IsNil) 191 c.Assert(found, jc.IsFalse) 192 193 // Add a couple of subordinates and try again. 194 s.addRelatedService(c, "wordpress", "logging", s.wordpressUnit) 195 s.addRelatedService(c, "wordpress", "monitoring", s.wordpressUnit) 196 197 found, err = s.apiUnit.HasSubordinates() 198 c.Assert(err, gc.IsNil) 199 c.Assert(found, jc.IsTrue) 200 } 201 202 func (s *unitSuite) TestPublicAddress(c *gc.C) { 203 address, err := s.apiUnit.PublicAddress() 204 c.Assert(err, gc.ErrorMatches, `"unit-wordpress-0" has no public address set`) 205 206 err = s.wordpressMachine.SetAddresses(instance.NewAddress("1.2.3.4", instance.NetworkPublic)) 207 c.Assert(err, gc.IsNil) 208 209 address, err = s.apiUnit.PublicAddress() 210 c.Assert(err, gc.IsNil) 211 c.Assert(address, gc.Equals, "1.2.3.4") 212 } 213 214 func (s *unitSuite) TestPrivateAddress(c *gc.C) { 215 address, err := s.apiUnit.PrivateAddress() 216 c.Assert(err, gc.ErrorMatches, `"unit-wordpress-0" has no private address set`) 217 218 err = s.wordpressMachine.SetAddresses(instance.NewAddress("1.2.3.4", instance.NetworkCloudLocal)) 219 c.Assert(err, gc.IsNil) 220 221 address, err = s.apiUnit.PrivateAddress() 222 c.Assert(err, gc.IsNil) 223 c.Assert(address, gc.Equals, "1.2.3.4") 224 } 225 226 func (s *unitSuite) TestOpenClosePort(c *gc.C) { 227 ports := s.wordpressUnit.OpenedPorts() 228 c.Assert(ports, gc.HasLen, 0) 229 230 err := s.apiUnit.OpenPort("foo", 1234) 231 c.Assert(err, gc.IsNil) 232 err = s.apiUnit.OpenPort("bar", 4321) 233 c.Assert(err, gc.IsNil) 234 235 err = s.wordpressUnit.Refresh() 236 c.Assert(err, gc.IsNil) 237 ports = s.wordpressUnit.OpenedPorts() 238 // OpenedPorts returns a sorted slice. 239 c.Assert(ports, gc.DeepEquals, []instance.Port{ 240 {Protocol: "bar", Number: 4321}, 241 {Protocol: "foo", Number: 1234}, 242 }) 243 244 err = s.apiUnit.ClosePort("bar", 4321) 245 c.Assert(err, gc.IsNil) 246 247 err = s.wordpressUnit.Refresh() 248 c.Assert(err, gc.IsNil) 249 ports = s.wordpressUnit.OpenedPorts() 250 // OpenedPorts returns a sorted slice. 251 c.Assert(ports, gc.DeepEquals, []instance.Port{ 252 {Protocol: "foo", Number: 1234}, 253 }) 254 255 err = s.apiUnit.ClosePort("foo", 1234) 256 c.Assert(err, gc.IsNil) 257 258 err = s.wordpressUnit.Refresh() 259 c.Assert(err, gc.IsNil) 260 ports = s.wordpressUnit.OpenedPorts() 261 c.Assert(ports, gc.HasLen, 0) 262 } 263 264 func (s *unitSuite) TestGetSetCharmURL(c *gc.C) { 265 // No charm URL set yet. 266 curl, ok := s.wordpressUnit.CharmURL() 267 c.Assert(curl, gc.IsNil) 268 c.Assert(ok, jc.IsFalse) 269 270 // Now check the same through the API. 271 _, err := s.apiUnit.CharmURL() 272 c.Assert(err, gc.Equals, uniter.ErrNoCharmURLSet) 273 274 err = s.apiUnit.SetCharmURL(s.wordpressCharm.URL()) 275 c.Assert(err, gc.IsNil) 276 277 curl, err = s.apiUnit.CharmURL() 278 c.Assert(err, gc.IsNil) 279 c.Assert(curl, gc.NotNil) 280 c.Assert(curl.String(), gc.Equals, s.wordpressCharm.String()) 281 } 282 283 func (s *unitSuite) TestConfigSettings(c *gc.C) { 284 // Make sure ConfigSettings returns an error when 285 // no charm URL is set, as its state counterpart does. 286 settings, err := s.apiUnit.ConfigSettings() 287 c.Assert(err, gc.ErrorMatches, "unit charm not set") 288 289 // Now set the charm and try again. 290 err = s.apiUnit.SetCharmURL(s.wordpressCharm.URL()) 291 c.Assert(err, gc.IsNil) 292 293 settings, err = s.apiUnit.ConfigSettings() 294 c.Assert(err, gc.IsNil) 295 c.Assert(settings, gc.DeepEquals, charm.Settings{ 296 "blog-title": "My Title", 297 }) 298 299 // Update the config and check we get the changes on the next call. 300 err = s.wordpressService.UpdateConfigSettings(charm.Settings{ 301 "blog-title": "superhero paparazzi", 302 }) 303 c.Assert(err, gc.IsNil) 304 305 settings, err = s.apiUnit.ConfigSettings() 306 c.Assert(err, gc.IsNil) 307 c.Assert(settings, gc.DeepEquals, charm.Settings{ 308 "blog-title": "superhero paparazzi", 309 }) 310 } 311 312 func (s *unitSuite) TestWatchConfigSettings(c *gc.C) { 313 // Make sure WatchConfigSettings returns an error when 314 // no charm URL is set, as its state counterpart does. 315 w, err := s.apiUnit.WatchConfigSettings() 316 c.Assert(err, gc.ErrorMatches, "unit charm not set") 317 318 // Now set the charm and try again. 319 err = s.apiUnit.SetCharmURL(s.wordpressCharm.URL()) 320 c.Assert(err, gc.IsNil) 321 322 w, err = s.apiUnit.WatchConfigSettings() 323 defer statetesting.AssertStop(c, w) 324 wc := statetesting.NewNotifyWatcherC(c, s.BackingState, w) 325 326 // Initial event. 327 wc.AssertOneChange() 328 329 // Update config a couple of times, check a single event. 330 err = s.wordpressService.UpdateConfigSettings(charm.Settings{ 331 "blog-title": "superhero paparazzi", 332 }) 333 c.Assert(err, gc.IsNil) 334 err = s.wordpressService.UpdateConfigSettings(charm.Settings{ 335 "blog-title": "sauceror central", 336 }) 337 c.Assert(err, gc.IsNil) 338 wc.AssertOneChange() 339 340 // Non-change is not reported. 341 err = s.wordpressService.UpdateConfigSettings(charm.Settings{ 342 "blog-title": "sauceror central", 343 }) 344 c.Assert(err, gc.IsNil) 345 wc.AssertNoChange() 346 347 // NOTE: This test is not as exhaustive as the one in state, 348 // because the watcher is already tested there. Here we just 349 // ensure we get the events when we expect them and don't get 350 // them when they're not expected. 351 352 statetesting.AssertStop(c, w) 353 wc.AssertClosed() 354 } 355 356 func (s *unitSuite) TestServiceNameAndTag(c *gc.C) { 357 c.Assert(s.apiUnit.ServiceName(), gc.Equals, "wordpress") 358 c.Assert(s.apiUnit.ServiceTag(), gc.Equals, "service-wordpress") 359 } 360 361 func (s *unitSuite) TestJoinedRelations(c *gc.C) { 362 joinedRelations, err := s.apiUnit.JoinedRelations() 363 c.Assert(err, gc.IsNil) 364 c.Assert(joinedRelations, gc.HasLen, 0) 365 366 rel1, _, _ := s.addRelatedService(c, "wordpress", "monitoring", s.wordpressUnit) 367 joinedRelations, err = s.apiUnit.JoinedRelations() 368 c.Assert(err, gc.IsNil) 369 c.Assert(joinedRelations, gc.DeepEquals, []string{rel1.Tag()}) 370 371 rel2, _, _ := s.addRelatedService(c, "wordpress", "logging", s.wordpressUnit) 372 joinedRelations, err = s.apiUnit.JoinedRelations() 373 c.Assert(err, gc.IsNil) 374 sort.Strings(joinedRelations) 375 c.Assert(joinedRelations, gc.DeepEquals, []string{rel2.Tag(), rel1.Tag()}) 376 }