LEFT | RIGHT |
1 // launchpad.net/juju/go/state | |
2 // | |
3 // Copyright (c) 2011-2012 Canonical Ltd. | |
4 package state_test | |
5 | |
6 import ( | |
7 "fmt" | |
8 . "launchpad.net/gocheck" | |
9 "launchpad.net/gozk/zookeeper" | |
10 "launchpad.net/juju/go/charm" | |
11 "launchpad.net/juju/go/state" | |
12 "net/url" | |
13 "path/filepath" | |
14 "testing" | |
15 ) | |
16 | |
17 // TestPackage integrates the tests into gotest. | |
18 func TestPackage(t *testing.T) { | |
19 srv, dir := state.ZkSetUpEnvironment(t) | |
20 defer state.ZkTearDownEnvironment(t, srv, dir) | |
21 | |
22 TestingT(t) | |
23 } | |
24 | |
25 // charmDir returns a directory containing the given test charm. | |
26 func charmDir(name string) string { | |
27 return filepath.Join("..", "charm", "testrepo", "series", name) | |
28 } | |
29 | |
30 // readCharm returns a test charm by its name. | |
31 func readCharm(c *C, name string) charm.Charm { | |
32 ch, err := charm.ReadDir(charmDir(name)) | |
33 c.Assert(err, IsNil) | |
34 return ch | |
35 } | |
36 | |
37 // localCharmURL returns the local URL of a charm. | |
38 func localCharmURL(ch charm.Charm) *charm.URL { | |
39 url := fmt.Sprintf("local:series/%s-%d", ch.Meta().Name, ch.Revision()) | |
40 return charm.MustParseURL(url) | |
41 } | |
42 | |
43 // addDummyCharm adds the 'dummy' charm state to st. | |
44 func addDummyCharm(c *C, st *state.State) (*state.Charm, *charm.URL) { | |
45 ch := readCharm(c, "dummy") | |
46 curl := localCharmURL(ch) | |
47 bundleURL, err := url.Parse("http://bundle.url") | |
48 c.Assert(err, IsNil) | |
49 dummy, err := st.AddCharm(ch, curl, bundleURL) | |
50 c.Assert(err, IsNil) | |
51 return dummy, curl | |
52 } | |
53 | |
54 type StateSuite struct { | |
55 zkServer *zookeeper.Server | |
56 zkTestRoot string | |
57 zkTestPort int | |
58 zkAddr string | |
59 zkConn *zookeeper.Conn | |
60 st *state.State | |
61 } | |
62 | |
63 var _ = Suite(&StateSuite{}) | |
64 | |
65 func (s *StateSuite) SetUpTest(c *C) { | |
66 var err error | |
67 s.st, err = state.Open(&state.Info{ | |
68 Addrs: []string{state.ZkAddr}, | |
69 }) | |
70 c.Assert(err, IsNil) | |
71 err = s.st.Initialize() | |
72 c.Assert(err, IsNil) | |
73 s.zkConn = state.ZkConn(s.st) | |
74 } | |
75 | |
76 func (s *StateSuite) TearDownTest(c *C) { | |
77 // Delete possible nodes, ignore errors. | |
78 zkRemoveTree(s.zkConn, "/topology") | |
79 zkRemoveTree(s.zkConn, "/charms") | |
80 zkRemoveTree(s.zkConn, "/services") | |
81 zkRemoveTree(s.zkConn, "/machines") | |
82 zkRemoveTree(s.zkConn, "/units") | |
83 zkRemoveTree(s.zkConn, "/relations") | |
84 zkRemoveTree(s.zkConn, "/initialized") | |
85 s.zkConn.Close() | |
86 } | |
87 | |
88 func (s StateSuite) TestAddCharm(c *C) { | |
89 // Check that adding charms works correctly. | |
90 dummyCharm := readCharm(c, "dummy") | |
91 curl := localCharmURL(dummyCharm) | |
92 bundleURL, err := url.Parse("http://bundle.url") | |
93 c.Assert(err, IsNil) | |
94 dummy, err := s.st.AddCharm(dummyCharm, curl, bundleURL) | |
95 c.Assert(err, IsNil) | |
96 c.Assert(dummy.URL().String(), Equals, curl.String()) | |
97 _, _, err = s.zkConn.Children("/charms") | |
98 c.Assert(err, IsNil) | |
99 } | |
100 | |
101 func (s StateSuite) TestCharmAttributes(c *C) { | |
102 // Check that the basic (invariant) fields of the charm | |
103 // are correctly in place. | |
104 _, curl := addDummyCharm(c, s.st) | |
105 | |
106 dummy, err := s.st.Charm(curl) | |
107 c.Assert(err, IsNil) | |
108 c.Assert(dummy.URL().String(), Equals, curl.String()) | |
109 c.Assert(dummy.Revision(), Equals, 1) | |
110 bundleURL, err := url.Parse("http://bundle.url") | |
111 c.Assert(err, IsNil) | |
112 c.Assert(dummy.BundleURL(), DeepEquals, bundleURL) | |
113 meta := dummy.Meta() | |
114 c.Assert(meta.Name, Equals, "dummy") | |
115 config := dummy.Config() | |
116 c.Assert(config.Options["title"], Equals, | |
117 charm.Option{ | |
118 Default: "My Title", | |
119 Description: "A descriptive title used for the service."
, | |
120 Type: "string", | |
121 }, | |
122 ) | |
123 } | |
124 | |
125 func (s StateSuite) TestNonExistentCharmPriorToInitialization(c *C) { | |
126 // Check that getting a charm before any other charm has been added fail
s nicely. | |
127 curl, err := charm.ParseURL("local:series/dummy-1") | |
128 c.Assert(err, IsNil) | |
129 _, err = s.st.Charm(curl) | |
130 c.Assert(err, ErrorMatches, `charm not found: "local:series/dummy-1"`) | |
131 } | |
132 | |
133 func (s StateSuite) TestGetNonExistentCharm(c *C) { | |
134 // Check that getting a non-existent charm fails nicely. | |
135 addDummyCharm(c, s.st) | |
136 | |
137 curl := charm.MustParseURL("local:anotherseries/dummy-1") | |
138 _, err := s.st.Charm(curl) | |
139 c.Assert(err, ErrorMatches, `charm not found: "local:anotherseries/dummy
-1"`) | |
140 } | |
141 | |
142 func (s StateSuite) TestAddService(c *C) { | |
143 // Check that adding services works correctly. | |
144 dummy, curl := addDummyCharm(c, s.st) | |
145 wordpress, err := s.st.AddService("wordpress", dummy) | |
146 c.Assert(err, IsNil) | |
147 c.Assert(wordpress.Name(), Equals, "wordpress") | |
148 mysql, err := s.st.AddService("mysql", dummy) | |
149 c.Assert(err, IsNil) | |
150 c.Assert(mysql.Name(), Equals, "mysql") | |
151 | |
152 // Check that retrieving the new created services works correctly. | |
153 wordpress, err = s.st.Service("wordpress") | |
154 c.Assert(err, IsNil) | |
155 c.Assert(wordpress.Name(), Equals, "wordpress") | |
156 url, err := wordpress.CharmURL() | |
157 c.Assert(err, IsNil) | |
158 c.Assert(url.String(), Equals, curl.String()) | |
159 mysql, err = s.st.Service("mysql") | |
160 c.Assert(err, IsNil) | |
161 c.Assert(mysql.Name(), Equals, "mysql") | |
162 url, err = mysql.CharmURL() | |
163 c.Assert(err, IsNil) | |
164 c.Assert(url.String(), Equals, curl.String()) | |
165 } | |
166 | |
167 func (s StateSuite) TestRemoveService(c *C) { | |
168 dummy, _ := addDummyCharm(c, s.st) | |
169 service, err := s.st.AddService("wordpress", dummy) | |
170 c.Assert(err, IsNil) | |
171 | |
172 // Check that removing the service works correctly. | |
173 err = s.st.RemoveService(service) | |
174 c.Assert(err, IsNil) | |
175 service, err = s.st.Service("wordpress") | |
176 c.Assert(err, ErrorMatches, `service with name "wordpress" not found`) | |
177 } | |
178 | |
179 func (s StateSuite) TestReadNonExistentService(c *C) { | |
180 _, err := s.st.Service("pressword") | |
181 c.Assert(err, ErrorMatches, `service with name "pressword" not found`) | |
182 } | |
183 | |
184 func (s StateSuite) TestAllServices(c *C) { | |
185 // Check without existing services. | |
186 services, err := s.st.AllServices() | |
187 c.Assert(err, IsNil) | |
188 c.Assert(len(services), Equals, 0) | |
189 | |
190 // Check that after adding services the result is ok. | |
191 dummy, _ := addDummyCharm(c, s.st) | |
192 _, err = s.st.AddService("wordpress", dummy) | |
193 c.Assert(err, IsNil) | |
194 services, err = s.st.AllServices() | |
195 c.Assert(err, IsNil) | |
196 c.Assert(len(services), Equals, 1) | |
197 | |
198 _, err = s.st.AddService("mysql", dummy) | |
199 c.Assert(err, IsNil) | |
200 services, err = s.st.AllServices() | |
201 c.Assert(err, IsNil) | |
202 c.Assert(len(services), Equals, 2) | |
203 | |
204 // Check the returned service, order is defined by sorted keys. | |
205 c.Assert(services[0].Name(), Equals, "wordpress") | |
206 c.Assert(services[1].Name(), Equals, "mysql") | |
207 } | |
208 | |
209 func (s StateSuite) TestServiceCharm(c *C) { | |
210 dummy, curl := addDummyCharm(c, s.st) | |
211 wordpress, err := s.st.AddService("wordpress", dummy) | |
212 c.Assert(err, IsNil) | |
213 | |
214 // Check that getting and setting the service charm URL works correctly. | |
215 testcurl, err := wordpress.CharmURL() | |
216 c.Assert(err, IsNil) | |
217 c.Assert(testcurl.String(), Equals, curl.String()) | |
218 testcurl, err = charm.ParseURL("local:myseries/mydummy-1") | |
219 c.Assert(err, IsNil) | |
220 err = wordpress.SetCharmURL(testcurl) | |
221 c.Assert(err, IsNil) | |
222 testcurl, err = wordpress.CharmURL() | |
223 c.Assert(err, IsNil) | |
224 c.Assert(testcurl.String(), Equals, "local:myseries/mydummy-1") | |
225 } | |
226 | |
227 func (s StateSuite) TestServiceExposed(c *C) { | |
228 dummy, _ := addDummyCharm(c, s.st) | |
229 wordpress, err := s.st.AddService("wordpress", dummy) | |
230 c.Assert(err, IsNil) | |
231 | |
232 // Check that querying for the exposed flag works correctly. | |
233 exposed, err := wordpress.IsExposed() | |
234 c.Assert(err, IsNil) | |
235 c.Assert(exposed, Equals, false) | |
236 | |
237 // Check that setting and clearing the exposed flag works correctly. | |
238 err = wordpress.SetExposed() | |
239 c.Assert(err, IsNil) | |
240 exposed, err = wordpress.IsExposed() | |
241 c.Assert(err, IsNil) | |
242 c.Assert(exposed, Equals, true) | |
243 err = wordpress.ClearExposed() | |
244 c.Assert(err, IsNil) | |
245 exposed, err = wordpress.IsExposed() | |
246 c.Assert(err, IsNil) | |
247 c.Assert(exposed, Equals, false) | |
248 | |
249 // Check that setting and clearing the exposed flag multiple doesn't fai
l. | |
250 err = wordpress.SetExposed() | |
251 c.Assert(err, IsNil) | |
252 err = wordpress.SetExposed() | |
253 c.Assert(err, IsNil) | |
254 err = wordpress.ClearExposed() | |
255 c.Assert(err, IsNil) | |
256 err = wordpress.ClearExposed() | |
257 c.Assert(err, IsNil) | |
258 | |
259 // Check that setting and clearing the exposed flag on removed services
also doesn't fail. | |
260 err = s.st.RemoveService(wordpress) | |
261 c.Assert(err, IsNil) | |
262 err = wordpress.ClearExposed() | |
263 c.Assert(err, IsNil) | |
264 } | |
265 | |
266 func (s StateSuite) TestAddUnit(c *C) { | |
267 dummy, _ := addDummyCharm(c, s.st) | |
268 wordpress, err := s.st.AddService("wordpress", dummy) | |
269 c.Assert(err, IsNil) | |
270 | |
271 // Check that adding units works. | |
272 unitZero, err := wordpress.AddUnit() | |
273 c.Assert(err, IsNil) | |
274 c.Assert(unitZero.Name(), Equals, "wordpress/0") | |
275 unitOne, err := wordpress.AddUnit() | |
276 c.Assert(err, IsNil) | |
277 c.Assert(unitOne.Name(), Equals, "wordpress/1") | |
278 } | |
279 | |
280 func (s StateSuite) TestReadUnit(c *C) { | |
281 dummy, _ := addDummyCharm(c, s.st) | |
282 wordpress, err := s.st.AddService("wordpress", dummy) | |
283 c.Assert(err, IsNil) | |
284 _, err = wordpress.AddUnit() | |
285 c.Assert(err, IsNil) | |
286 _, err = wordpress.AddUnit() | |
287 c.Assert(err, IsNil) | |
288 mysql, err := s.st.AddService("mysql", dummy) | |
289 c.Assert(err, IsNil) | |
290 _, err = mysql.AddUnit() | |
291 c.Assert(err, IsNil) | |
292 | |
293 // Check that retrieving a unit works correctly. | |
294 unit, err := wordpress.Unit("wordpress/0") | |
295 c.Assert(err, IsNil) | |
296 c.Assert(unit.Name(), Equals, "wordpress/0") | |
297 | |
298 // Check that retrieving a non-existent or an invalidly | |
299 // named unit fail nicely. | |
300 unit, err = wordpress.Unit("wordpress") | |
301 c.Assert(err, ErrorMatches, `"wordpress" is not a valid unit name`) | |
302 unit, err = wordpress.Unit("wordpress/0/0") | |
303 c.Assert(err, ErrorMatches, `"wordpress/0/0" is not a valid unit name`) | |
304 unit, err = wordpress.Unit("pressword/0") | |
305 c.Assert(err, ErrorMatches, `can't find unit "pressword/0" on service "w
ordpress"`) | |
306 unit, err = wordpress.Unit("mysql/0") | |
307 c.Assert(err, ErrorMatches, `can't find unit "mysql/0" on service "wordp
ress"`) | |
308 | |
309 // Check that retrieving unit names works. | |
310 unitNames, err := wordpress.UnitNames() | |
311 c.Assert(err, IsNil) | |
312 c.Assert(unitNames, DeepEquals, []string{"wordpress/0", "wordpress/1"}) | |
313 | |
314 // Check that retrieving all units works. | |
315 units, err := wordpress.AllUnits() | |
316 c.Assert(err, IsNil) | |
317 c.Assert(len(units), Equals, 2) | |
318 c.Assert(units[0].Name(), Equals, "wordpress/0") | |
319 c.Assert(units[1].Name(), Equals, "wordpress/1") | |
320 } | |
321 | |
322 func (s StateSuite) TestReadUnitWithChangingState(c *C) { | |
323 dummy, _ := addDummyCharm(c, s.st) | |
324 wordpress, err := s.st.AddService("wordpress", dummy) | |
325 c.Assert(err, IsNil) | |
326 | |
327 // Check that reading a unit after removing the service | |
328 // fails nicely. | |
329 err = s.st.RemoveService(wordpress) | |
330 c.Assert(err, IsNil) | |
331 _, err = s.st.Unit("wordpress/0") | |
332 c.Assert(err, ErrorMatches, `service with name "wordpress" not found`) | |
333 } | |
334 | |
335 func (s StateSuite) TestRemoveUnit(c *C) { | |
336 dummy, _ := addDummyCharm(c, s.st) | |
337 wordpress, err := s.st.AddService("wordpress", dummy) | |
338 c.Assert(err, IsNil) | |
339 _, err = wordpress.AddUnit() | |
340 c.Assert(err, IsNil) | |
341 _, err = wordpress.AddUnit() | |
342 c.Assert(err, IsNil) | |
343 | |
344 // Check that removing a unit works. | |
345 unit, err := wordpress.Unit("wordpress/0") | |
346 c.Assert(err, IsNil) | |
347 err = wordpress.RemoveUnit(unit) | |
348 c.Assert(err, IsNil) | |
349 unitNames, err := wordpress.UnitNames() | |
350 c.Assert(err, IsNil) | |
351 c.Assert(unitNames, DeepEquals, []string{"wordpress/1"}) | |
352 | |
353 // Check that removing a non-existent unit fails nicely. | |
354 err = wordpress.RemoveUnit(unit) | |
355 c.Assert(err, ErrorMatches, "environment state has changed") | |
356 } | |
357 | |
358 func (s StateSuite) TestGetSetPublicAddress(c *C) { | |
359 dummy, _ := addDummyCharm(c, s.st) | |
360 wordpress, err := s.st.AddService("wordpress", dummy) | |
361 c.Assert(err, IsNil) | |
362 unit, err := wordpress.AddUnit() | |
363 c.Assert(err, IsNil) | |
364 | |
365 // Check that retrieving and setting of a public address works. | |
366 address, err := unit.PublicAddress() | |
367 c.Assert(err, ErrorMatches, "unit has no public address") | |
368 err = unit.SetPublicAddress("example.foobar.com") | |
369 c.Assert(err, IsNil) | |
370 address, err = unit.PublicAddress() | |
371 c.Assert(err, IsNil) | |
372 c.Assert(address, Equals, "example.foobar.com") | |
373 } | |
374 | |
375 func (s StateSuite) TestGetSetPrivateAddress(c *C) { | |
376 dummy, _ := addDummyCharm(c, s.st) | |
377 wordpress, err := s.st.AddService("wordpress", dummy) | |
378 c.Assert(err, IsNil) | |
379 unit, err := wordpress.AddUnit() | |
380 c.Assert(err, IsNil) | |
381 | |
382 // Check that retrieving and setting of a private address works. | |
383 address, err := unit.PrivateAddress() | |
384 c.Assert(err, ErrorMatches, "unit has no private address") | |
385 err = unit.SetPrivateAddress("example.local") | |
386 c.Assert(err, IsNil) | |
387 address, err = unit.PrivateAddress() | |
388 c.Assert(err, IsNil) | |
389 c.Assert(address, Equals, "example.local") | |
390 } | |
391 | |
392 func (s StateSuite) TestUnitCharm(c *C) { | |
393 dummy, curl := addDummyCharm(c, s.st) | |
394 wordpress, err := s.st.AddService("wordpress", dummy) | |
395 c.Assert(err, IsNil) | |
396 unit, err := wordpress.AddUnit() | |
397 c.Assert(err, IsNil) | |
398 | |
399 // Check that getting and setting the unit charm URL works correctly. | |
400 testcurl, err := unit.CharmURL() | |
401 c.Assert(err, IsNil) | |
402 c.Assert(testcurl.String(), Equals, curl.String()) | |
403 testcurl, err = charm.ParseURL("local:myseries/mydummy-1") | |
404 c.Assert(err, IsNil) | |
405 err = unit.SetCharmURL(testcurl) | |
406 c.Assert(err, IsNil) | |
407 testcurl, err = unit.CharmURL() | |
408 c.Assert(err, IsNil) | |
409 c.Assert(testcurl.String(), Equals, "local:myseries/mydummy-1") | |
410 } | |
411 | |
412 func (s StateSuite) TestUnassignUnitFromMachineWithoutBeingAssigned(c *C) { | |
413 // When unassigning a machine from a unit, it is possible that | |
414 // the machine has not been previously assigned, or that it | |
415 // was assigned but the state changed beneath us. In either | |
416 // case, the end state is the intended state, so we simply | |
417 // move forward without any errors here, to avoid having to | |
418 // handle the extra complexity of dealing with the concurrency | |
419 // problems. | |
420 dummy, _ := addDummyCharm(c, s.st) | |
421 wordpress, err := s.st.AddService("wordpress", dummy) | |
422 c.Assert(err, IsNil) | |
423 unit, err := wordpress.AddUnit() | |
424 c.Assert(err, IsNil) | |
425 | |
426 err = unit.UnassignFromMachine() | |
427 c.Assert(err, IsNil) | |
428 | |
429 // Check that the unit has no machine assigned. | |
430 wordpress, err = s.st.Service("wordpress") | |
431 c.Assert(err, IsNil) | |
432 units, err := wordpress.AllUnits() | |
433 c.Assert(err, IsNil) | |
434 unit = units[0] | |
435 _, err = unit.AssignedMachineId() | |
436 c.Assert(err, ErrorMatches, `unit not assigned to machine`) | |
437 } | |
438 | |
439 func (s StateSuite) TestAssignUnitToMachineAgainFails(c *C) { | |
440 // Check that assigning an already assigned unit to | |
441 // a machine fails if it isn't precisely the same | |
442 // machine.· | |
443 dummy, _ := addDummyCharm(c, s.st) | |
444 wordpress, err := s.st.AddService("wordpress", dummy) | |
445 c.Assert(err, IsNil) | |
446 unit, err := wordpress.AddUnit() | |
447 c.Assert(err, IsNil) | |
448 machineOne, err := s.st.AddMachine() | |
449 c.Assert(err, IsNil) | |
450 machineTwo, err := s.st.AddMachine() | |
451 c.Assert(err, IsNil) | |
452 | |
453 err = unit.AssignToMachine(machineOne) | |
454 c.Assert(err, IsNil) | |
455 | |
456 // Assigning the unit to the same machine should return no error. | |
457 err = unit.AssignToMachine(machineOne) | |
458 c.Assert(err, IsNil) | |
459 | |
460 // Assigning the unit to a different machine should fail. | |
461 err = unit.AssignToMachine(machineTwo) | |
462 c.Assert(err, ErrorMatches, `unit "wordpress/0" already assigned to mach
ine 0`) | |
463 | |
464 machineId, err := unit.AssignedMachineId() | |
465 c.Assert(err, IsNil) | |
466 c.Assert(machineId, Equals, 0) | |
467 } | |
468 | |
469 func (s StateSuite) TestUnassignUnitFromMachineWithChangingState(c *C) { | |
470 // Check that unassigning while the state changes fails nicely. | |
471 dummy, _ := addDummyCharm(c, s.st) | |
472 wordpress, err := s.st.AddService("wordpress", dummy) | |
473 c.Assert(err, IsNil) | |
474 unit, err := wordpress.AddUnit() | |
475 c.Assert(err, IsNil) | |
476 | |
477 // Remove the unit for the tests. | |
478 wordpress, err = s.st.Service("wordpress") | |
479 c.Assert(err, IsNil) | |
480 units, err := wordpress.AllUnits() | |
481 c.Assert(err, IsNil) | |
482 unit = units[0] | |
483 err = wordpress.RemoveUnit(unit) | |
484 c.Assert(err, IsNil) | |
485 | |
486 err = unit.UnassignFromMachine() | |
487 c.Assert(err, ErrorMatches, "environment state has changed") | |
488 _, err = unit.AssignedMachineId() | |
489 c.Assert(err, ErrorMatches, "environment state has changed") | |
490 | |
491 err = s.st.RemoveService(wordpress) | |
492 c.Assert(err, IsNil) | |
493 | |
494 err = unit.UnassignFromMachine() | |
495 c.Assert(err, ErrorMatches, "environment state has changed") | |
496 _, err = unit.AssignedMachineId() | |
497 c.Assert(err, ErrorMatches, "environment state has changed") | |
498 } | |
499 | |
500 func (s StateSuite) TestAssignUnitToUnusedMachine(c *C) { | |
501 // Create root machine that shouldn't be useds. | |
502 _, err := s.st.AddMachine() | |
503 c.Assert(err, IsNil) | |
504 // Check that a unit can be assigned to an unused machine. | |
505 dummy, _ := addDummyCharm(c, s.st) | |
506 mysqlService, err := s.st.AddService("mysql", dummy) | |
507 c.Assert(err, IsNil) | |
508 mysqlUnit, err := mysqlService.AddUnit() | |
509 c.Assert(err, IsNil) | |
510 mysqlMachine, err := s.st.AddMachine() | |
511 c.Assert(err, IsNil) | |
512 err = mysqlUnit.AssignToMachine(mysqlMachine) | |
513 c.Assert(err, IsNil) | |
514 err = s.st.RemoveService(mysqlService) | |
515 c.Assert(err, IsNil) | |
516 | |
517 wordpressService, err := s.st.AddService("wordpress", dummy) | |
518 c.Assert(err, IsNil) | |
519 wordpressUnit, err := wordpressService.AddUnit() | |
520 c.Assert(err, IsNil) | |
521 wordpressMachine, err := wordpressUnit.AssignToUnusedMachine() | |
522 c.Assert(err, IsNil) | |
523 | |
524 c.Assert(wordpressMachine.Id(), Equals, mysqlMachine.Id()) | |
525 } | |
526 | |
527 func (s StateSuite) TestAssignUnitToUnusedMachineWithChangingService(c *C) { | |
528 // Create root machine that shouldn't be useds. | |
529 _, err := s.st.AddMachine() | |
530 c.Assert(err, IsNil) | |
531 // Check for a 'state changed' error if a service is manipulated | |
532 // during reuse. | |
533 dummy, _ := addDummyCharm(c, s.st) | |
534 mysqlService, err := s.st.AddService("mysql", dummy) | |
535 c.Assert(err, IsNil) | |
536 mysqlUnit, err := mysqlService.AddUnit() | |
537 c.Assert(err, IsNil) | |
538 mysqlMachine, err := s.st.AddMachine() | |
539 c.Assert(err, IsNil) | |
540 err = mysqlUnit.AssignToMachine(mysqlMachine) | |
541 c.Assert(err, IsNil) | |
542 err = s.st.RemoveService(mysqlService) | |
543 c.Assert(err, IsNil) | |
544 | |
545 wordpressService, err := s.st.AddService("wordpress", dummy) | |
546 c.Assert(err, IsNil) | |
547 wordpressUnit, err := wordpressService.AddUnit() | |
548 c.Assert(err, IsNil) | |
549 err = s.st.RemoveService(wordpressService) | |
550 c.Assert(err, IsNil) | |
551 | |
552 _, err = wordpressUnit.AssignToUnusedMachine() | |
553 c.Assert(err, ErrorMatches, "environment state has changed") | |
554 } | |
555 | |
556 func (s StateSuite) TestAssignUnitToUnusedMachineWithChangingUnit(c *C) { | |
557 // Create root machine that shouldn't be useds. | |
558 _, err := s.st.AddMachine() | |
559 c.Assert(err, IsNil) | |
560 // Check for a 'state changed' error if a unit is manipulated | |
561 // during reuse. | |
562 dummy, _ := addDummyCharm(c, s.st) | |
563 mysqlService, err := s.st.AddService("mysql", dummy) | |
564 c.Assert(err, IsNil) | |
565 mysqlUnit, err := mysqlService.AddUnit() | |
566 c.Assert(err, IsNil) | |
567 mysqlMachine, err := s.st.AddMachine() | |
568 c.Assert(err, IsNil) | |
569 err = mysqlUnit.AssignToMachine(mysqlMachine) | |
570 c.Assert(err, IsNil) | |
571 err = s.st.RemoveService(mysqlService) | |
572 c.Assert(err, IsNil) | |
573 | |
574 wordpressService, err := s.st.AddService("wordpress", dummy) | |
575 c.Assert(err, IsNil) | |
576 wordpressUnit, err := wordpressService.AddUnit() | |
577 c.Assert(err, IsNil) | |
578 err = wordpressService.RemoveUnit(wordpressUnit) | |
579 c.Assert(err, IsNil) | |
580 | |
581 _, err = wordpressUnit.AssignToUnusedMachine() | |
582 c.Assert(err, ErrorMatches, "environment state has changed") | |
583 } | |
584 | |
585 func (s StateSuite) TestAssignUnitToUnusedMachineOnlyZero(c *C) { | |
586 // Create root machine that shouldn't be useds. | |
587 _, err := s.st.AddMachine() | |
588 c.Assert(err, IsNil) | |
589 // Check that the unit can't be assigned to machine zero. | |
590 dummy, _ := addDummyCharm(c, s.st) | |
591 wordpressService, err := s.st.AddService("wordpress", dummy) | |
592 c.Assert(err, IsNil) | |
593 wordpressUnit, err := wordpressService.AddUnit() | |
594 c.Assert(err, IsNil) | |
595 | |
596 _, err = wordpressUnit.AssignToUnusedMachine() | |
597 c.Assert(err, ErrorMatches, "no unused machine found") | 1 c.Assert(err, ErrorMatches, "no unused machine found") |
598 } | |
599 | |
600 func (s StateSuite) TestAssignUnitToUnusedMachineNoneAvailable(c *C) { | |
601 // Create machine 0, that shouldn't be used. | |
602 _, err := s.st.AddMachine() | |
603 c.Assert(err, IsNil) | |
604 // Check that assigning without unused machine fails.··· | |
605 dummy, _ := addDummyCharm(c, s.st) | |
606 mysqlService, err := s.st.AddService("mysql", dummy) | |
607 c.Assert(err, IsNil) | |
608 mysqlUnit, err := mysqlService.AddUnit() | |
609 c.Assert(err, IsNil) | |
610 mysqlMachine, err := s.st.AddMachine() | |
611 c.Assert(err, IsNil) | |
612 err = mysqlUnit.AssignToMachine(mysqlMachine) | |
613 c.Assert(err, IsNil) | |
614 | |
615 wordpressService, err := s.st.AddService("wordpress", dummy) | |
616 c.Assert(err, IsNil) | |
617 wordpressUnit, err := wordpressService.AddUnit() | |
618 c.Assert(err, IsNil) | |
619 | |
620 _, err = wordpressUnit.AssignToUnusedMachine() | |
621 c.Assert(err, ErrorMatches, "no unused machine found") | |
622 } | |
623 | |
624 func (s StateSuite) TestGetSetClearUnitUpgrate(c *C) { | |
625 // Check that setting and clearing an upgrade flag on a unit works. | |
626 dummy, _ := addDummyCharm(c, s.st) | |
627 wordpress, err := s.st.AddService("wordpress", dummy) | |
628 c.Assert(err, IsNil) | |
629 unit, err := wordpress.AddUnit() | |
630 c.Assert(err, IsNil) | |
631 | |
632 // Defaults to false. | |
633 upgrade, err := unit.Upgrade() | |
634 c.Assert(err, IsNil) | |
635 c.Assert(upgrade, Equals, false) | |
636 | |
637 // Can be set. | |
638 err = unit.SetUpgrade() | |
639 c.Assert(err, IsNil) | |
640 upgrade, err = unit.Upgrade() | |
641 c.Assert(err, IsNil) | |
642 c.Assert(upgrade, Equals, true) | |
643 | |
644 // Can be set multiple times. | |
645 err = unit.SetUpgrade() | |
646 c.Assert(err, IsNil) | |
647 upgrade, err = unit.Upgrade() | |
648 c.Assert(err, IsNil) | |
649 c.Assert(upgrade, Equals, true) | |
650 | |
651 // Can be cleared. | |
652 err = unit.ClearUpgrade() | |
653 c.Assert(err, IsNil) | |
654 upgrade, err = unit.Upgrade() | |
655 c.Assert(err, IsNil) | |
656 c.Assert(upgrade, Equals, false) | |
657 | |
658 // Can be cleared multiple times | |
659 err = unit.ClearUpgrade() | |
660 c.Assert(err, IsNil) | |
661 upgrade, err = unit.Upgrade() | |
662 c.Assert(err, IsNil) | |
663 c.Assert(upgrade, Equals, false) | |
664 } | |
665 | |
666 func (s StateSuite) TestGetSetClearResolved(c *C) { | |
667 // Check that setting and clearing the resolved setting on a unit works. | |
668 dummy, _ := addDummyCharm(c, s.st) | |
669 wordpress, err := s.st.AddService("wordpress", dummy) | |
670 c.Assert(err, IsNil) | |
671 unit, err := wordpress.AddUnit() | |
672 c.Assert(err, IsNil) | |
673 | |
674 setting, err := unit.Resolved() | |
675 c.Assert(err, IsNil) | |
676 c.Assert(setting, IsNil) | |
677 | |
678 err = unit.SetResolved(state.ResolvedNoHooks) | |
679 c.Assert(err, IsNil) | |
680 err = unit.SetResolved(state.ResolvedNoHooks) | |
681 c.Assert(err, ErrorMatches, `unit "wordpress/0" resolved already enabled
`) | |
682 setting, err = unit.Resolved() | |
683 c.Assert(err, IsNil) | |
684 c.Assert(setting, DeepEquals, map[string]interface{}{"retry": state.Reso
lvedNoHooks}) | |
685 | |
686 err = unit.ClearResolved() | |
687 c.Assert(err, IsNil) | |
688 setting, err = unit.Resolved() | |
689 c.Assert(err, IsNil) | |
690 c.Assert(setting, IsNil) | |
691 err = unit.ClearResolved() | |
692 c.Assert(err, IsNil) | |
693 | |
694 err = unit.SetResolved(-1) | |
695 c.Assert(err, ErrorMatches, `invalid retry value: -1`) | |
696 } | |
697 | |
698 func (s StateSuite) TestGetOpenPorts(c *C) { | |
699 // Check that changes to the open ports of units work porperly. | |
700 dummy, _ := addDummyCharm(c, s.st) | |
701 wordpress, err := s.st.AddService("wordpress", dummy) | |
702 c.Assert(err, IsNil) | |
703 unit, err := wordpress.AddUnit() | |
704 c.Assert(err, IsNil) | |
705 | |
706 // Verify no open ports before activity. | |
707 open, err := unit.OpenPorts() | |
708 c.Assert(err, IsNil) | |
709 c.Assert(open, HasLen, 0) | |
710 | |
711 // Now open and close port. | |
712 err = unit.OpenPort(80, "tcp") | |
713 c.Assert(err, IsNil) | |
714 open, err = unit.OpenPorts() | |
715 c.Assert(err, IsNil) | |
716 c.Assert(open, DeepEquals, []state.PortProto{ | |
717 {80, "tcp"}, | |
718 }) | |
719 | |
720 err = unit.OpenPort(53, "udp") | |
721 c.Assert(err, IsNil) | |
722 open, err = unit.OpenPorts() | |
723 c.Assert(err, IsNil) | |
724 c.Assert(open, DeepEquals, []state.PortProto{ | |
725 {80, "tcp"}, | |
726 {53, "udp"}, | |
727 }) | |
728 | |
729 err = unit.OpenPort(53, "tcp") | |
730 c.Assert(err, IsNil) | |
731 open, err = unit.OpenPorts() | |
732 c.Assert(err, IsNil) | |
733 c.Assert(open, DeepEquals, []state.PortProto{ | |
734 {80, "tcp"}, | |
735 {53, "udp"}, | |
736 {53, "tcp"}, | |
737 }) | |
738 | |
739 err = unit.OpenPort(443, "tcp") | |
740 c.Assert(err, IsNil) | |
741 open, err = unit.OpenPorts() | |
742 c.Assert(err, IsNil) | |
743 c.Assert(open, DeepEquals, []state.PortProto{ | |
744 {80, "tcp"}, | |
745 {53, "udp"}, | |
746 {53, "tcp"}, | |
747 {443, "tcp"}, | |
748 }) | |
749 | |
750 err = unit.ClosePort(80, "tcp") | |
751 c.Assert(err, IsNil) | |
752 open, err = unit.OpenPorts() | |
753 c.Assert(err, IsNil) | |
754 c.Assert(open, DeepEquals, []state.PortProto{ | |
755 {53, "udp"}, | |
756 {53, "tcp"}, | |
757 {443, "tcp"}, | |
758 }) | |
759 } | 2 } |
760 | 3 |
761 // zkRemoveTree recursively removes a tree. | 4 // zkRemoveTree recursively removes a tree. |
762 func zkRemoveTree(zk *zookeeper.Conn, path string) error { | 5 func zkRemoveTree(zk *zookeeper.Conn, path string) error { |
763 // First recursively delete the children. | 6 // First recursively delete the children. |
764 children, _, err := zk.Children(path) | |
765 if err != nil { | |
766 return err | |
767 } | |
768 for _, child := range children { | |
769 if err = zkRemoveTree(zk, fmt.Sprintf("%s/%s", path, child)); er
r != nil { | |
770 return err | |
771 } | |
772 } | |
773 // Now delete the path itself. | |
774 return zk.Delete(path, -1) | |
775 } | |
LEFT | RIGHT |