Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(6)

Side by Side Diff: worker/apiuniter/context_test.go

Issue 13401050: worker;cmd/jujud: Replace uniter with apiuniter (Closed)
Patch Set: worker;cmd/jujud: Replace uniter with apiuniter Created 11 years, 7 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « worker/apiuniter/context.go ('k') | worker/apiuniter/debug/client.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2012, 2013 Canonical Ltd.
2 // Licensed under the AGPLv3, see LICENCE file for details.
3
4 package apiuniter_test
5
6 import (
7 "fmt"
8 "io/ioutil"
9 "os"
10 "path/filepath"
11 "strings"
12 "time"
13
14 gc "launchpad.net/gocheck"
15
16 "launchpad.net/juju-core/charm"
17 "launchpad.net/juju-core/juju/testing"
18 "launchpad.net/juju-core/state"
19 "launchpad.net/juju-core/state/api"
20 "launchpad.net/juju-core/state/api/params"
21 "launchpad.net/juju-core/state/api/uniter"
22 "launchpad.net/juju-core/utils"
23 "launchpad.net/juju-core/worker/apiuniter"
24 "launchpad.net/juju-core/worker/apiuniter/jujuc"
25 )
26
27 type RunHookSuite struct {
28 HookContextSuite
29 }
30
31 var _ = gc.Suite(&RunHookSuite{})
32
33 type hookSpec struct {
34 // name is the name of the hook.
35 name string
36 // perm is the file permissions of the hook.
37 perm os.FileMode
38 // code is the exit status of the hook.
39 code int
40 // stdout holds a string to print to stdout
41 stdout string
42 // stderr holds a string to print to stderr
43 stderr string
44 // background holds a string to print in the background after 0.2s.
45 background string
46 }
47
48 // makeCharm constructs a fake charm dir containing a single named hook
49 // with permissions perm and exit code code. If output is non-empty,
50 // the charm will write it to stdout and stderr, with each one prefixed
51 // by name of the stream. It returns the charm directory and the path
52 // to which the hook script will write environment variables.
53 func makeCharm(c *gc.C, spec hookSpec) (charmDir, outPath string) {
54 charmDir = c.MkDir()
55 hooksDir := filepath.Join(charmDir, "hooks")
56 err := os.Mkdir(hooksDir, 0755)
57 c.Assert(err, gc.IsNil)
58 c.Logf("openfile perm %v", spec.perm)
59 hook, err := os.OpenFile(filepath.Join(hooksDir, spec.name), os.O_CREATE |os.O_WRONLY, spec.perm)
60 c.Assert(err, gc.IsNil)
61 defer hook.Close()
62 printf := func(f string, a ...interface{}) {
63 if _, err := fmt.Fprintf(hook, f+"\n", a...); err != nil {
64 panic(err)
65 }
66 }
67 outPath = filepath.Join(c.MkDir(), "hook.out")
68 printf("#!/bin/bash")
69 printf("env > " + outPath)
70 if spec.stdout != "" {
71 printf("echo %s", spec.stdout)
72 }
73 if spec.stderr != "" {
74 printf("echo %s >&2", spec.stderr)
75 }
76 if spec.background != "" {
77 // Print something fairly quickly, then sleep for
78 // quite a long time - if the hook execution is
79 // blocking because of the background process,
80 // the hook execution will take much longer than
81 // expected.
82 printf("(sleep 0.2; echo %s; sleep 10) &", spec.background)
83 }
84 printf("exit %d", spec.code)
85 return charmDir, outPath
86 }
87
88 func AssertEnvContains(c *gc.C, lines []string, env map[string]string) {
89 for k, v := range env {
90 sought := k + "=" + v
91 found := false
92 for _, line := range lines {
93 if line == sought {
94 found = true
95 continue
96 }
97 }
98 comment := gc.Commentf("expected to find %v among %v", sought, l ines)
99 c.Assert(found, gc.Equals, true, comment)
100 }
101 }
102
103 func AssertEnv(c *gc.C, outPath string, charmDir string, env map[string]string, uuid string) {
104 out, err := ioutil.ReadFile(outPath)
105 c.Assert(err, gc.IsNil)
106 lines := strings.Split(string(out), "\n")
107 AssertEnvContains(c, lines, env)
108 AssertEnvContains(c, lines, map[string]string{
109 "DEBIAN_FRONTEND": "noninteractive",
110 "APT_LISTCHANGES_FRONTEND": "none",
111 "CHARM_DIR": charmDir,
112 "JUJU_AGENT_SOCKET": "/path/to/socket",
113 "JUJU_ENV_UUID": uuid,
114 })
115 }
116
117 // LineBufferSize matches the constant used when creating
118 // the bufio line reader.
119 const lineBufferSize = 4096
120
121 var apiAddrs = []string{"a1:123", "a2:123"}
122 var expectedApiAddrs = strings.Join(apiAddrs, " ")
123
124 var runHookTests = []struct {
125 summary string
126 relid int
127 remote string
128 spec hookSpec
129 err string
130 env map[string]string
131 }{
132 {
133 summary: "missing hook is not an error",
134 relid: -1,
135 }, {
136 summary: "report failure to execute hook",
137 relid: -1,
138 spec: hookSpec{perm: 0600},
139 err: `exec: .*something-happened": permission denied`,
140 }, {
141 summary: "report error indicated by hook's exit status",
142 relid: -1,
143 spec: hookSpec{
144 perm: 0700,
145 code: 99,
146 },
147 err: "exit status 99",
148 }, {
149 summary: "output logging",
150 relid: -1,
151 spec: hookSpec{
152 perm: 0700,
153 stdout: "stdout",
154 stderr: "stderr",
155 },
156 }, {
157 summary: "output logging with background process",
158 relid: -1,
159 spec: hookSpec{
160 perm: 0700,
161 stdout: "stdout",
162 background: "not printed",
163 },
164 }, {
165 summary: "long line split",
166 relid: -1,
167 spec: hookSpec{
168 perm: 0700,
169 stdout: strings.Repeat("a", lineBufferSize+10),
170 },
171 }, {
172 summary: "check shell environment for non-relation hook context" ,
173 relid: -1,
174 spec: hookSpec{perm: 0700},
175 env: map[string]string{
176 "JUJU_UNIT_NAME": "u/0",
177 "JUJU_API_ADDRESSES": expectedApiAddrs,
178 },
179 }, {
180 summary: "check shell environment for relation-broken hook conte xt",
181 relid: 1,
182 spec: hookSpec{perm: 0700},
183 env: map[string]string{
184 "JUJU_UNIT_NAME": "u/0",
185 "JUJU_API_ADDRESSES": expectedApiAddrs,
186 "JUJU_RELATION": "db",
187 "JUJU_RELATION_ID": "db:1",
188 "JUJU_REMOTE_UNIT": "",
189 },
190 }, {
191 summary: "check shell environment for relation hook context",
192 relid: 1,
193 remote: "r/1",
194 spec: hookSpec{perm: 0700},
195 env: map[string]string{
196 "JUJU_UNIT_NAME": "u/0",
197 "JUJU_API_ADDRESSES": expectedApiAddrs,
198 "JUJU_RELATION": "db",
199 "JUJU_RELATION_ID": "db:1",
200 "JUJU_REMOTE_UNIT": "r/1",
201 },
202 },
203 }
204
205 func (s *RunHookSuite) TestRunHook(c *gc.C) {
206 uuid, err := utils.NewUUID()
207 c.Assert(err, gc.IsNil)
208 for i, t := range runHookTests {
209 c.Logf("test %d: %s; perm %v", i, t.summary, t.spec.perm)
210 ctx := s.GetHookContext(c, uuid.String(), t.relid, t.remote)
211 var charmDir, outPath string
212 if t.spec.perm == 0 {
213 charmDir = c.MkDir()
214 } else {
215 spec := t.spec
216 spec.name = "something-happened"
217 c.Logf("makeCharm %#v", spec)
218 charmDir, outPath = makeCharm(c, spec)
219 }
220 toolsDir := c.MkDir()
221 t0 := time.Now()
222 err := ctx.RunHook("something-happened", charmDir, toolsDir, "/p ath/to/socket")
223 if t.err == "" {
224 c.Assert(err, gc.IsNil)
225 } else {
226 c.Assert(err, gc.ErrorMatches, t.err)
227 }
228 if t.env != nil {
229 env := map[string]string{"PATH": toolsDir + ":" + os.Get env("PATH")}
230 for k, v := range t.env {
231 env[k] = v
232 }
233 AssertEnv(c, outPath, charmDir, env, uuid.String())
234 }
235 if t.spec.background != "" && time.Now().Sub(t0) > 5*time.Second {
236 c.Errorf("background process holding up hook execution")
237 }
238 }
239 }
240
241 // split the line into buffer-sized lengths.
242 func splitLine(s string) []string {
243 var ss []string
244 for len(s) > lineBufferSize {
245 ss = append(ss, s[0:lineBufferSize])
246 s = s[lineBufferSize:]
247 }
248 if len(s) > 0 {
249 ss = append(ss, s)
250 }
251 return ss
252 }
253
254 func (s *RunHookSuite) TestRunHookRelationFlushing(c *gc.C) {
255 // Create a charm with a breaking hook.
256 uuid, err := utils.NewUUID()
257 c.Assert(err, gc.IsNil)
258 ctx := s.GetHookContext(c, uuid.String(), -1, "")
259 charmDir, _ := makeCharm(c, hookSpec{
260 name: "something-happened",
261 perm: 0700,
262 code: 123,
263 })
264
265 // Mess with multiple relation settings.
266 node0, err := s.relctxs[0].Settings()
267 node0.Set("foo", "1")
268 node1, err := s.relctxs[1].Settings()
269 node1.Set("bar", "2")
270
271 // Run the failing hook.
272 err = ctx.RunHook("something-happened", charmDir, c.MkDir(), "/path/to/s ocket")
273 c.Assert(err, gc.ErrorMatches, "exit status 123")
274
275 // Check that the changes to the local settings nodes have been discarde d.
276 node0, err = s.relctxs[0].Settings()
277 c.Assert(err, gc.IsNil)
278 c.Assert(node0.Map(), gc.DeepEquals, params.Settings{"relation-name": "d b0"})
279 node1, err = s.relctxs[1].Settings()
280 c.Assert(err, gc.IsNil)
281 c.Assert(node1.Map(), gc.DeepEquals, params.Settings{"relation-name": "d b1"})
282
283 // Check that the changes have been written to state.
284 settings0, err := s.relunits[0].ReadSettings("u/0")
285 c.Assert(err, gc.IsNil)
286 c.Assert(settings0, gc.DeepEquals, map[string]interface{}{"relation-name ": "db0"})
287 settings1, err := s.relunits[1].ReadSettings("u/0")
288 c.Assert(err, gc.IsNil)
289 c.Assert(settings1, gc.DeepEquals, map[string]interface{}{"relation-name ": "db1"})
290
291 // Create a charm with a working hook, and mess with settings again.
292 charmDir, _ = makeCharm(c, hookSpec{
293 name: "something-happened",
294 perm: 0700,
295 })
296 node0.Set("baz", "3")
297 node1.Set("qux", "4")
298
299 // Run the hook.
300 err = ctx.RunHook("something-happened", charmDir, c.MkDir(), "/path/to/s ocket")
301 c.Assert(err, gc.IsNil)
302
303 // Check that the changes to the local settings nodes are still there.
304 node0, err = s.relctxs[0].Settings()
305 c.Assert(err, gc.IsNil)
306 c.Assert(node0.Map(), gc.DeepEquals, params.Settings{
307 "relation-name": "db0",
308 "baz": "3",
309 })
310 node1, err = s.relctxs[1].Settings()
311 c.Assert(err, gc.IsNil)
312 c.Assert(node1.Map(), gc.DeepEquals, params.Settings{
313 "relation-name": "db1",
314 "qux": "4",
315 })
316
317 // Check that the changes have been written to state.
318 settings0, err = s.relunits[0].ReadSettings("u/0")
319 c.Assert(err, gc.IsNil)
320 c.Assert(settings0, gc.DeepEquals, map[string]interface{}{
321 "relation-name": "db0",
322 "baz": "3",
323 })
324 settings1, err = s.relunits[1].ReadSettings("u/0")
325 c.Assert(err, gc.IsNil)
326 c.Assert(settings1, gc.DeepEquals, map[string]interface{}{
327 "relation-name": "db1",
328 "qux": "4",
329 })
330 }
331
332 type ContextRelationSuite struct {
333 testing.JujuConnSuite
334 svc *state.Service
335 rel *state.Relation
336 ru *state.RelationUnit
337
338 st *api.State
339 uniter *uniter.State
340 apiRelUnit *uniter.RelationUnit
341 }
342
343 var _ = gc.Suite(&ContextRelationSuite{})
344
345 func (s *ContextRelationSuite) SetUpTest(c *gc.C) {
346 s.JujuConnSuite.SetUpTest(c)
347 ch := s.AddTestingCharm(c, "riak")
348 var err error
349 s.svc, err = s.State.AddService("u", ch)
350 c.Assert(err, gc.IsNil)
351 rels, err := s.svc.Relations()
352 c.Assert(err, gc.IsNil)
353 c.Assert(rels, gc.HasLen, 1)
354 s.rel = rels[0]
355 unit, err := s.svc.AddUnit()
356 c.Assert(err, gc.IsNil)
357 s.ru, err = s.rel.Unit(unit)
358 c.Assert(err, gc.IsNil)
359 err = s.ru.EnterScope(nil)
360 c.Assert(err, gc.IsNil)
361
362 err = unit.SetPassword("password")
363 c.Assert(err, gc.IsNil)
364 s.st = s.OpenAPIAs(c, unit.Tag(), "password")
365 c.Assert(s.st, gc.NotNil)
366 s.uniter = s.st.Uniter()
367 c.Assert(s.uniter, gc.NotNil)
368
369 apiRel, err := s.uniter.Relation(s.rel.Tag())
370 c.Assert(err, gc.IsNil)
371 apiUnit, err := s.uniter.Unit(unit.Tag())
372 c.Assert(err, gc.IsNil)
373 s.apiRelUnit, err = apiRel.Unit(apiUnit)
374 c.Assert(err, gc.IsNil)
375 }
376
377 func (s *ContextRelationSuite) TearDownTest(c *gc.C) {
378 if s.st != nil {
379 err := s.st.Close()
380 c.Assert(err, gc.IsNil)
381 }
382 s.JujuConnSuite.TearDownTest(c)
383 }
384
385 func (s *ContextRelationSuite) TestChangeMembers(c *gc.C) {
386 ctx := apiuniter.NewContextRelation(s.apiRelUnit, nil)
387 c.Assert(ctx.UnitNames(), gc.HasLen, 0)
388
389 // Check the units and settings after a simple update.
390 ctx.UpdateMembers(apiuniter.SettingsMap{
391 "u/2": {"baz": "2"},
392 "u/4": {"qux": "4"},
393 })
394 c.Assert(ctx.UnitNames(), gc.DeepEquals, []string{"u/2", "u/4"})
395 assertSettings := func(unit string, expect params.Settings) {
396 actual, err := ctx.ReadSettings(unit)
397 c.Assert(err, gc.IsNil)
398 c.Assert(actual, gc.DeepEquals, expect)
399 }
400 assertSettings("u/2", params.Settings{"baz": "2"})
401 assertSettings("u/4", params.Settings{"qux": "4"})
402
403 // Send a second update; check that members are only added, not removed.
404 ctx.UpdateMembers(apiuniter.SettingsMap{
405 "u/1": {"foo": "1"},
406 "u/2": {"abc": "2"},
407 "u/3": {"bar": "3"},
408 })
409 c.Assert(ctx.UnitNames(), gc.DeepEquals, []string{"u/1", "u/2", "u/3", " u/4"})
410
411 // Check that all settings remain cached.
412 assertSettings("u/1", params.Settings{"foo": "1"})
413 assertSettings("u/2", params.Settings{"abc": "2"})
414 assertSettings("u/3", params.Settings{"bar": "3"})
415 assertSettings("u/4", params.Settings{"qux": "4"})
416
417 // Delete a member, and check that it is no longer a member...
418 ctx.DeleteMember("u/2")
419 c.Assert(ctx.UnitNames(), gc.DeepEquals, []string{"u/1", "u/3", "u/4"})
420
421 // ...and that its settings are no longer cached.
422 _, err := ctx.ReadSettings("u/2")
423 c.Assert(err, gc.ErrorMatches, "permission denied")
424 }
425
426 func (s *ContextRelationSuite) TestMemberCaching(c *gc.C) {
427 unit, err := s.svc.AddUnit()
428 c.Assert(err, gc.IsNil)
429 ru, err := s.rel.Unit(unit)
430 c.Assert(err, gc.IsNil)
431 err = ru.EnterScope(map[string]interface{}{"blib": "blob"})
432 c.Assert(err, gc.IsNil)
433 settings, err := ru.Settings()
434 c.Assert(err, gc.IsNil)
435 settings.Set("ping", "pong")
436 _, err = settings.Write()
437 c.Assert(err, gc.IsNil)
438 ctx := apiuniter.NewContextRelation(s.apiRelUnit, map[string]int64{"u/1" : 0})
439
440 // Check that uncached settings are read from state.
441 m, err := ctx.ReadSettings("u/1")
442 c.Assert(err, gc.IsNil)
443 expectMap := settings.Map()
444 expectSettings := convertMap(expectMap)
445 c.Assert(m, gc.DeepEquals, expectSettings)
446
447 // Check that changes to state do not affect the cached settings.
448 settings.Set("ping", "pow")
449 _, err = settings.Write()
450 c.Assert(err, gc.IsNil)
451 m, err = ctx.ReadSettings("u/1")
452 c.Assert(err, gc.IsNil)
453 c.Assert(m, gc.DeepEquals, expectSettings)
454
455 // Check that ClearCache spares the members cache.
456 ctx.ClearCache()
457 m, err = ctx.ReadSettings("u/1")
458 c.Assert(err, gc.IsNil)
459 c.Assert(m, gc.DeepEquals, expectSettings)
460
461 // Check that updating the context overwrites the cached settings, and
462 // that the contents of state are ignored.
463 ctx.UpdateMembers(apiuniter.SettingsMap{"u/1": {"entirely": "different"} })
464 m, err = ctx.ReadSettings("u/1")
465 c.Assert(err, gc.IsNil)
466 c.Assert(m, gc.DeepEquals, params.Settings{"entirely": "different"})
467 }
468
469 func (s *ContextRelationSuite) TestNonMemberCaching(c *gc.C) {
470 unit, err := s.svc.AddUnit()
471 c.Assert(err, gc.IsNil)
472 ru, err := s.rel.Unit(unit)
473 c.Assert(err, gc.IsNil)
474 err = ru.EnterScope(map[string]interface{}{"blib": "blob"})
475 c.Assert(err, gc.IsNil)
476 settings, err := ru.Settings()
477 c.Assert(err, gc.IsNil)
478 settings.Set("ping", "pong")
479 _, err = settings.Write()
480 c.Assert(err, gc.IsNil)
481 ctx := apiuniter.NewContextRelation(s.apiRelUnit, nil)
482
483 // Check that settings are read from state.
484 m, err := ctx.ReadSettings("u/1")
485 c.Assert(err, gc.IsNil)
486 expectMap := settings.Map()
487 expectSettings := convertMap(expectMap)
488 c.Assert(m, gc.DeepEquals, expectSettings)
489
490 // Check that changes to state do not affect the obtained settings...
491 settings.Set("ping", "pow")
492 _, err = settings.Write()
493 c.Assert(err, gc.IsNil)
494 m, err = ctx.ReadSettings("u/1")
495 c.Assert(err, gc.IsNil)
496 c.Assert(m, gc.DeepEquals, expectSettings)
497
498 // ...until the caches are cleared.
499 ctx.ClearCache()
500 c.Assert(err, gc.IsNil)
501 m, err = ctx.ReadSettings("u/1")
502 c.Assert(err, gc.IsNil)
503 c.Assert(m["ping"], gc.Equals, "pow")
504 }
505
506 func (s *ContextRelationSuite) TestSettings(c *gc.C) {
507 ctx := apiuniter.NewContextRelation(s.apiRelUnit, nil)
508
509 // Change Settings, then clear cache without writing.
510 node, err := ctx.Settings()
511 c.Assert(err, gc.IsNil)
512 expectSettings := node.Map()
513 expectMap := convertSettings(expectSettings)
514 node.Set("change", "exciting")
515 ctx.ClearCache()
516
517 // Check that the change is not cached...
518 node, err = ctx.Settings()
519 c.Assert(err, gc.IsNil)
520 c.Assert(node.Map(), gc.DeepEquals, expectSettings)
521
522 // ...and not written to state.
523 settings, err := s.ru.ReadSettings("u/0")
524 c.Assert(err, gc.IsNil)
525 c.Assert(settings, gc.DeepEquals, expectMap)
526
527 // Change again, write settings, and clear caches.
528 node.Set("change", "exciting")
529 err = ctx.WriteSettings()
530 c.Assert(err, gc.IsNil)
531 ctx.ClearCache()
532
533 // Check that the change is reflected in Settings...
534 expectSettings["change"] = "exciting"
535 expectMap["change"] = expectSettings["change"]
536 node, err = ctx.Settings()
537 c.Assert(err, gc.IsNil)
538 c.Assert(node.Map(), gc.DeepEquals, expectSettings)
539
540 // ...and was written to state.
541 settings, err = s.ru.ReadSettings("u/0")
542 c.Assert(err, gc.IsNil)
543 c.Assert(settings, gc.DeepEquals, expectMap)
544 }
545
546 type InterfaceSuite struct {
547 HookContextSuite
548 }
549
550 var _ = gc.Suite(&InterfaceSuite{})
551
552 func (s *InterfaceSuite) GetContext(c *gc.C, relId int,
553 remoteName string) jujuc.Context {
554 uuid, err := utils.NewUUID()
555 c.Assert(err, gc.IsNil)
556 return s.HookContextSuite.GetHookContext(c, uuid.String(), relId, remote Name)
557 }
558
559 func (s *InterfaceSuite) TestUtils(c *gc.C) {
560 ctx := s.GetContext(c, -1, "")
561 c.Assert(ctx.UnitName(), gc.Equals, "u/0")
562 r, found := ctx.HookRelation()
563 c.Assert(found, gc.Equals, false)
564 c.Assert(r, gc.IsNil)
565 name, found := ctx.RemoteUnitName()
566 c.Assert(found, gc.Equals, false)
567 c.Assert(name, gc.Equals, "")
568 c.Assert(ctx.RelationIds(), gc.HasLen, 2)
569 r, found = ctx.Relation(0)
570 c.Assert(found, gc.Equals, true)
571 c.Assert(r.Name(), gc.Equals, "db")
572 c.Assert(r.FakeId(), gc.Equals, "db:0")
573 r, found = ctx.Relation(123)
574 c.Assert(found, gc.Equals, false)
575 c.Assert(r, gc.IsNil)
576
577 ctx = s.GetContext(c, 1, "")
578 r, found = ctx.HookRelation()
579 c.Assert(found, gc.Equals, true)
580 c.Assert(r.Name(), gc.Equals, "db")
581 c.Assert(r.FakeId(), gc.Equals, "db:1")
582
583 ctx = s.GetContext(c, 1, "u/123")
584 name, found = ctx.RemoteUnitName()
585 c.Assert(found, gc.Equals, true)
586 c.Assert(name, gc.Equals, "u/123")
587 }
588
589 func (s *InterfaceSuite) TestUnitCaching(c *gc.C) {
590 ctx := s.GetContext(c, -1, "")
591 pr, ok := ctx.PrivateAddress()
592 c.Assert(ok, gc.Equals, true)
593 c.Assert(pr, gc.Equals, "u-0.testing.invalid")
594 _, ok = ctx.PublicAddress()
595 c.Assert(ok, gc.Equals, false)
596
597 // Change remote state.
598 u, err := s.State.Unit("u/0")
599 c.Assert(err, gc.IsNil)
600 err = u.SetPrivateAddress("")
601 c.Assert(err, gc.IsNil)
602 err = u.SetPublicAddress("blah.testing.invalid")
603 c.Assert(err, gc.IsNil)
604
605 // Local view is unchanged.
606 pr, ok = ctx.PrivateAddress()
607 c.Assert(ok, gc.Equals, true)
608 c.Assert(pr, gc.Equals, "u-0.testing.invalid")
609 _, ok = ctx.PublicAddress()
610 c.Assert(ok, gc.Equals, false)
611 }
612
613 func (s *InterfaceSuite) TestConfigCaching(c *gc.C) {
614 ctx := s.GetContext(c, -1, "")
615 settings, err := ctx.ConfigSettings()
616 c.Assert(err, gc.IsNil)
617 c.Assert(settings, gc.DeepEquals, charm.Settings{"blog-title": "My Title "})
618
619 // Change remote config.
620 err = s.service.UpdateConfigSettings(charm.Settings{
621 "blog-title": "Something Else",
622 })
623 c.Assert(err, gc.IsNil)
624
625 // Local view is not changed.
626 settings, err = ctx.ConfigSettings()
627 c.Assert(err, gc.IsNil)
628 c.Assert(settings, gc.DeepEquals, charm.Settings{"blog-title": "My Title "})
629 }
630
631 type HookContextSuite struct {
632 testing.JujuConnSuite
633 service *state.Service
634 unit *state.Unit
635 relch *state.Charm
636 relunits map[int]*state.RelationUnit
637 relctxs map[int]*apiuniter.ContextRelation
638
639 st *api.State
640 uniter *uniter.State
641 apiUnit *uniter.Unit
642 }
643
644 func (s *HookContextSuite) SetUpTest(c *gc.C) {
645 s.JujuConnSuite.SetUpTest(c)
646 var err error
647 sch := s.AddTestingCharm(c, "wordpress")
648 s.service, err = s.State.AddService("u", sch)
649 c.Assert(err, gc.IsNil)
650 s.unit = s.AddUnit(c, s.service)
651
652 err = s.unit.SetPassword("password")
653 c.Assert(err, gc.IsNil)
654 s.st = s.OpenAPIAs(c, s.unit.Tag(), "password")
655 c.Assert(s.st, gc.NotNil)
656 s.uniter = s.st.Uniter()
657 c.Assert(s.uniter, gc.NotNil)
658
659 // Note: The unit must always have a charm URL set, because this
660 // happens as part of the installation process (that happens
661 // before the initial install hook).
662 err = s.unit.SetCharmURL(sch.URL())
663 c.Assert(err, gc.IsNil)
664 s.relch = s.AddTestingCharm(c, "mysql")
665 s.relunits = map[int]*state.RelationUnit{}
666 s.relctxs = map[int]*apiuniter.ContextRelation{}
667 s.AddContextRelation(c, "db0")
668 s.AddContextRelation(c, "db1")
669 }
670
671 func (s *HookContextSuite) TearDownTest(c *gc.C) {
672 if s.st != nil {
673 err := s.st.Close()
674 c.Assert(err, gc.IsNil)
675 }
676 s.JujuConnSuite.TearDownTest(c)
677 }
678
679 func (s *HookContextSuite) AddUnit(c *gc.C, svc *state.Service) *state.Unit {
680 unit, err := svc.AddUnit()
681 c.Assert(err, gc.IsNil)
682 name := strings.Replace(unit.Name(), "/", "-", 1)
683 err = unit.SetPrivateAddress(name + ".testing.invalid")
684 c.Assert(err, gc.IsNil)
685 return unit
686 }
687
688 func (s *HookContextSuite) AddContextRelation(c *gc.C, name string) {
689 _, err := s.State.AddService(name, s.relch)
690 c.Assert(err, gc.IsNil)
691 eps, err := s.State.InferEndpoints([]string{"u", name})
692 c.Assert(err, gc.IsNil)
693 rel, err := s.State.AddRelation(eps...)
694 c.Assert(err, gc.IsNil)
695 ru, err := rel.Unit(s.unit)
696 c.Assert(err, gc.IsNil)
697 s.relunits[rel.Id()] = ru
698 err = ru.EnterScope(map[string]interface{}{"relation-name": name})
699 c.Assert(err, gc.IsNil)
700 s.apiUnit, err = s.uniter.Unit(s.unit.Tag())
701 c.Assert(err, gc.IsNil)
702 apiRel, err := s.uniter.Relation(rel.Tag())
703 c.Assert(err, gc.IsNil)
704 apiRelUnit, err := apiRel.Unit(s.apiUnit)
705 c.Assert(err, gc.IsNil)
706 s.relctxs[rel.Id()] = apiuniter.NewContextRelation(apiRelUnit, nil)
707 }
708
709 func (s *HookContextSuite) GetHookContext(c *gc.C, uuid string, relid int,
710 remote string) *apiuniter.HookContext {
711 if relid != -1 {
712 _, found := s.relctxs[relid]
713 c.Assert(found, gc.Equals, true)
714 }
715 context, err := apiuniter.NewHookContext(s.apiUnit, "TestCtx", uuid, rel id, remote,
716 s.relctxs, apiAddrs)
717 c.Assert(err, gc.IsNil)
718 return context
719 }
720
721 func convertSettings(settings params.Settings) map[string]interface{} {
722 result := make(map[string]interface{})
723 for k, v := range settings {
724 result[k] = v
725 }
726 return result
727 }
728
729 func convertMap(settingsMap map[string]interface{}) params.Settings {
730 result := make(params.Settings)
731 for k, v := range settingsMap {
732 result[k] = v.(string)
733 }
734 return result
735 }
OLDNEW
« no previous file with comments | « worker/apiuniter/context.go ('k') | worker/apiuniter/debug/client.go » ('j') | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b