github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/api/uniter/relationunit_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 "github.com/juju/names" 8 jc "github.com/juju/testing/checkers" 9 gc "gopkg.in/check.v1" 10 "gopkg.in/juju/charm.v4" 11 12 "github.com/juju/juju/api/uniter" 13 "github.com/juju/juju/apiserver/params" 14 "github.com/juju/juju/network" 15 "github.com/juju/juju/state" 16 statetesting "github.com/juju/juju/state/testing" 17 ) 18 19 // commonRelationSuiteMixin contains fields used by both relationSuite 20 // and relationUnitSuite. We're not just embeddnig relationUnitSuite 21 // into relationSuite to avoid running the former's tests twice. 22 type commonRelationSuiteMixin struct { 23 mysqlMachine *state.Machine 24 mysqlService *state.Service 25 mysqlCharm *state.Charm 26 mysqlUnit *state.Unit 27 28 stateRelation *state.Relation 29 } 30 31 type relationUnitSuite struct { 32 uniterSuite 33 commonRelationSuiteMixin 34 } 35 36 var _ = gc.Suite(&relationUnitSuite{}) 37 38 func (m *commonRelationSuiteMixin) SetUpTest(c *gc.C, s uniterSuite) { 39 // Create another machine, service and unit, so we can 40 // test relations and relation units. 41 m.mysqlMachine, m.mysqlService, m.mysqlCharm, m.mysqlUnit = s.addMachineServiceCharmAndUnit(c, "mysql") 42 43 // Add a relation, used by both this suite and relationSuite. 44 m.stateRelation = s.addRelation(c, "wordpress", "mysql") 45 } 46 47 func (s *relationUnitSuite) SetUpTest(c *gc.C) { 48 s.uniterSuite.SetUpTest(c) 49 s.commonRelationSuiteMixin.SetUpTest(c, s.uniterSuite) 50 } 51 52 func (s *relationUnitSuite) TearDownTest(c *gc.C) { 53 s.uniterSuite.TearDownTest(c) 54 } 55 56 func (s *relationUnitSuite) getRelationUnits(c *gc.C) (*state.RelationUnit, *uniter.RelationUnit) { 57 wpRelUnit, err := s.stateRelation.Unit(s.wordpressUnit) 58 c.Assert(err, jc.ErrorIsNil) 59 apiRelation, err := s.uniter.Relation(s.stateRelation.Tag().(names.RelationTag)) 60 c.Assert(err, jc.ErrorIsNil) 61 // TODO(dfc) 62 apiUnit, err := s.uniter.Unit(s.wordpressUnit.Tag().(names.UnitTag)) 63 c.Assert(err, jc.ErrorIsNil) 64 apiRelUnit, err := apiRelation.Unit(apiUnit) 65 c.Assert(err, jc.ErrorIsNil) 66 return wpRelUnit, apiRelUnit 67 } 68 69 func (s *relationUnitSuite) TestRelation(c *gc.C) { 70 _, apiRelUnit := s.getRelationUnits(c) 71 72 apiRel := apiRelUnit.Relation() 73 c.Assert(apiRel, gc.NotNil) 74 c.Assert(apiRel.String(), gc.Equals, "wordpress:db mysql:server") 75 } 76 77 func (s *relationUnitSuite) TestEndpoint(c *gc.C) { 78 _, apiRelUnit := s.getRelationUnits(c) 79 80 apiEndpoint := apiRelUnit.Endpoint() 81 c.Assert(apiEndpoint, gc.DeepEquals, uniter.Endpoint{ 82 charm.Relation{ 83 Name: "db", 84 Role: "requirer", 85 Interface: "mysql", 86 Optional: false, 87 Limit: 1, 88 Scope: "global", 89 }, 90 }) 91 } 92 93 func (s *relationUnitSuite) TestPrivateAddress(c *gc.C) { 94 _, apiRelUnit := s.getRelationUnits(c) 95 96 // Try getting it first without an address set. 97 address, err := apiRelUnit.PrivateAddress() 98 c.Assert(err, gc.ErrorMatches, `"unit-wordpress-0" has no private address set`) 99 100 // Set an address and try again. 101 err = s.wordpressMachine.SetAddresses(network.NewAddress("1.2.3.4", network.ScopeCloudLocal)) 102 c.Assert(err, jc.ErrorIsNil) 103 address, err = apiRelUnit.PrivateAddress() 104 c.Assert(err, jc.ErrorIsNil) 105 c.Assert(address, gc.Equals, "1.2.3.4") 106 } 107 108 func (s *relationUnitSuite) TestEnterScopeSuccessfully(c *gc.C) { 109 // NOTE: This test is not as exhaustive as the ones in state. 110 // Here, we just check the success case, while the two error 111 // cases are tested separately. 112 wpRelUnit, apiRelUnit := s.getRelationUnits(c) 113 s.assertInScope(c, wpRelUnit, false) 114 115 err := apiRelUnit.EnterScope() 116 c.Assert(err, jc.ErrorIsNil) 117 s.assertInScope(c, wpRelUnit, true) 118 } 119 120 func (s *relationUnitSuite) TestEnterScopeErrCannotEnterScope(c *gc.C) { 121 // Test the ErrCannotEnterScope gets forwarded correctly. 122 // We need to enter the scope wit the other unit first. 123 myRelUnit, err := s.stateRelation.Unit(s.mysqlUnit) 124 c.Assert(err, jc.ErrorIsNil) 125 err = myRelUnit.EnterScope(nil) 126 c.Assert(err, jc.ErrorIsNil) 127 s.assertInScope(c, myRelUnit, true) 128 129 // Now we destroy mysqlService, so the relation is be set to 130 // dying. 131 err = s.mysqlService.Destroy() 132 c.Assert(err, jc.ErrorIsNil) 133 err = s.stateRelation.Refresh() 134 c.Assert(err, jc.ErrorIsNil) 135 c.Assert(s.stateRelation.Life(), gc.Equals, state.Dying) 136 137 // Enter the scope with wordpressUnit. 138 wpRelUnit, apiRelUnit := s.getRelationUnits(c) 139 s.assertInScope(c, wpRelUnit, false) 140 err = apiRelUnit.EnterScope() 141 c.Assert(err, gc.NotNil) 142 c.Check(err, jc.Satisfies, params.IsCodeCannotEnterScope) 143 c.Check(err, gc.ErrorMatches, "cannot enter scope: unit or relation is not alive") 144 } 145 146 func (s *relationUnitSuite) TestEnterScopeErrCannotEnterScopeYet(c *gc.C) { 147 // Test the ErrCannotEnterScopeYet gets forwarded correctly. 148 // First we need to destroy the stateRelation. 149 err := s.stateRelation.Destroy() 150 c.Assert(err, jc.ErrorIsNil) 151 152 // Now we create a subordinate of wordpressUnit and enter scope. 153 subRel, _, loggingSub := s.addRelatedService(c, "wordpress", "logging", s.wordpressUnit) 154 wpRelUnit, err := subRel.Unit(s.wordpressUnit) 155 c.Assert(err, jc.ErrorIsNil) 156 s.assertInScope(c, wpRelUnit, true) 157 158 // Leave scope, destroy the subordinate and try entering again. 159 err = wpRelUnit.LeaveScope() 160 c.Assert(err, jc.ErrorIsNil) 161 s.assertInScope(c, wpRelUnit, false) 162 err = loggingSub.Destroy() 163 c.Assert(err, jc.ErrorIsNil) 164 165 apiUnit, err := s.uniter.Unit(s.wordpressUnit.Tag().(names.UnitTag)) 166 c.Assert(err, jc.ErrorIsNil) 167 apiRel, err := s.uniter.Relation(subRel.Tag().(names.RelationTag)) 168 c.Assert(err, jc.ErrorIsNil) 169 apiRelUnit, err := apiRel.Unit(apiUnit) 170 c.Assert(err, jc.ErrorIsNil) 171 err = apiRelUnit.EnterScope() 172 c.Assert(err, gc.NotNil) 173 c.Check(err, jc.Satisfies, params.IsCodeCannotEnterScopeYet) 174 c.Check(err, gc.ErrorMatches, "cannot enter scope yet: non-alive subordinate unit has not been removed") 175 } 176 177 func (s *relationUnitSuite) TestLeaveScope(c *gc.C) { 178 wpRelUnit, apiRelUnit := s.getRelationUnits(c) 179 s.assertInScope(c, wpRelUnit, false) 180 181 err := wpRelUnit.EnterScope(nil) 182 c.Assert(err, jc.ErrorIsNil) 183 s.assertInScope(c, wpRelUnit, true) 184 185 err = apiRelUnit.LeaveScope() 186 c.Assert(err, jc.ErrorIsNil) 187 s.assertInScope(c, wpRelUnit, false) 188 } 189 190 func (s *relationUnitSuite) TestSettings(c *gc.C) { 191 wpRelUnit, apiRelUnit := s.getRelationUnits(c) 192 settings := map[string]interface{}{ 193 "some": "settings", 194 "other": "things", 195 } 196 err := wpRelUnit.EnterScope(settings) 197 c.Assert(err, jc.ErrorIsNil) 198 s.assertInScope(c, wpRelUnit, true) 199 200 gotSettings, err := apiRelUnit.Settings() 201 c.Assert(err, jc.ErrorIsNil) 202 c.Assert(gotSettings.Map(), gc.DeepEquals, params.Settings{ 203 "some": "settings", 204 "other": "things", 205 }) 206 } 207 208 func (s *relationUnitSuite) TestReadSettings(c *gc.C) { 209 // First try to read the settings which are not set. 210 myRelUnit, err := s.stateRelation.Unit(s.mysqlUnit) 211 c.Assert(err, jc.ErrorIsNil) 212 err = myRelUnit.EnterScope(nil) 213 c.Assert(err, jc.ErrorIsNil) 214 s.assertInScope(c, myRelUnit, true) 215 216 // Try reading - should be ok. 217 wpRelUnit, apiRelUnit := s.getRelationUnits(c) 218 s.assertInScope(c, wpRelUnit, false) 219 gotSettings, err := apiRelUnit.ReadSettings("mysql/0") 220 c.Assert(err, jc.ErrorIsNil) 221 c.Assert(gotSettings, gc.HasLen, 0) 222 223 // Now leave and re-enter scope with some settings. 224 settings := map[string]interface{}{ 225 "some": "settings", 226 "other": "things", 227 } 228 err = myRelUnit.LeaveScope() 229 c.Assert(err, jc.ErrorIsNil) 230 s.assertInScope(c, myRelUnit, false) 231 err = myRelUnit.EnterScope(settings) 232 c.Assert(err, jc.ErrorIsNil) 233 s.assertInScope(c, myRelUnit, true) 234 gotSettings, err = apiRelUnit.ReadSettings("mysql/0") 235 c.Assert(err, jc.ErrorIsNil) 236 c.Assert(gotSettings, gc.DeepEquals, params.Settings{ 237 "some": "settings", 238 "other": "things", 239 }) 240 } 241 242 func (s *relationUnitSuite) TestReadSettingsInvalidUnitTag(c *gc.C) { 243 // First try to read the settings which are not set. 244 myRelUnit, err := s.stateRelation.Unit(s.mysqlUnit) 245 c.Assert(err, jc.ErrorIsNil) 246 err = myRelUnit.EnterScope(nil) 247 c.Assert(err, jc.ErrorIsNil) 248 s.assertInScope(c, myRelUnit, true) 249 250 // Try reading - should be ok. 251 wpRelUnit, apiRelUnit := s.getRelationUnits(c) 252 s.assertInScope(c, wpRelUnit, false) 253 _, err = apiRelUnit.ReadSettings("mysql") 254 c.Assert(err, gc.ErrorMatches, "\"mysql\" is not a valid unit") 255 } 256 257 func (s *relationUnitSuite) TestWatchRelationUnits(c *gc.C) { 258 // Enter scope with mysqlUnit. 259 myRelUnit, err := s.stateRelation.Unit(s.mysqlUnit) 260 c.Assert(err, jc.ErrorIsNil) 261 err = myRelUnit.EnterScope(nil) 262 c.Assert(err, jc.ErrorIsNil) 263 s.assertInScope(c, myRelUnit, true) 264 265 apiRel, err := s.uniter.Relation(s.stateRelation.Tag().(names.RelationTag)) 266 c.Assert(err, jc.ErrorIsNil) 267 apiUnit, err := s.uniter.Unit(names.NewUnitTag("wordpress/0")) 268 c.Assert(err, jc.ErrorIsNil) 269 apiRelUnit, err := apiRel.Unit(apiUnit) 270 c.Assert(err, jc.ErrorIsNil) 271 272 w, err := apiRelUnit.Watch() 273 defer statetesting.AssertStop(c, w) 274 wc := statetesting.NewRelationUnitsWatcherC(c, s.BackingState, w) 275 276 // Initial event. 277 wc.AssertChange([]string{"mysql/0"}, nil) 278 279 // Leave scope with mysqlUnit, check it's detected. 280 err = myRelUnit.LeaveScope() 281 c.Assert(err, jc.ErrorIsNil) 282 s.assertInScope(c, myRelUnit, false) 283 wc.AssertChange(nil, []string{"mysql/0"}) 284 285 // Non-change is not reported. 286 err = myRelUnit.LeaveScope() 287 c.Assert(err, jc.ErrorIsNil) 288 wc.AssertNoChange() 289 290 // NOTE: This test is not as exhaustive as the one in state, 291 // because the watcher is already tested there. Here we just 292 // ensure we get the events when we expect them and don't get 293 // them when they're not expected. 294 295 statetesting.AssertStop(c, w) 296 wc.AssertClosed() 297 }