Merge lp:~jimbaker/pyjuju/unit-rel-lifecycle-start-invoker into lp:pyjuju

Proposed by Jim Baker
Status: Merged
Merged at revision: 535
Proposed branch: lp:~jimbaker/pyjuju/unit-rel-lifecycle-start-invoker
Merge into: lp:pyjuju
Diff against target: 156 lines (+69/-6)
4 files modified
juju/hooks/invoker.py (+6/-1)
juju/hooks/tests/test_invoker.py (+3/-3)
juju/unit/lifecycle.py (+1/-0)
juju/unit/tests/test_lifecycle.py (+59/-2)
To merge this branch: bzr merge lp:~jimbaker/pyjuju/unit-rel-lifecycle-start-invoker
Reviewer Review Type Date Requested Status
Juju Engineering Pending
Review via email: mp+104195@code.launchpad.net

Description of the change

Ensure Invoker.start is called from UnitRelationLifecycle usage.

UnitRelationLifecycle did not properly call Invoker.start (a one-line fix), which prevented relation hook contexts from being cached for the corresponding hook call. Because caching of the hook contexts is logged, this can be verified to ensure this method is properly called for both UnitRelationLifecycle and UnitLifecycle usages.

https://codereview.appspot.com/6131061/

To post a comment you must log in.
Revision history for this message
Jim Baker (jimbaker) wrote :
Download full text (6.4 KiB)

Reviewers: mp+104195_code.launchpad.net,

Message:
Please take a look.

Description:
Ensure Invoker.start is called from UnitRelationLifecycle usage.

UnitRelationLifecycle did not properly call Invoker.start (a one-line
fix), which prevented relation hook contexts from being cached for the
corresponding hook call. Because caching of the hook contexts is logged,
this can be verified to ensure this method is properly called for both
UnitRelationLifecycle and UnitLifecycle usages.

https://code.launchpad.net/~jimbaker/juju/unit-rel-lifecycle-start-invoker/+merge/104195

(do not edit description out of merge proposal)

Please review this at https://codereview.appspot.com/6131061/

Affected files:
   A [revision details]
   M juju/hooks/invoker.py
   M juju/unit/lifecycle.py
   M juju/unit/tests/test_lifecycle.py

Index: [revision details]
=== added file '[revision details]'
--- [revision details] 2012-01-01 00:00:00 +0000
+++ [revision details] 2012-01-01 00:00:00 +0000
@@ -0,0 +1,2 @@
+Old revision: <email address hidden>
+New revision: <email address hidden>

Index: juju/hooks/invoker.py
=== modified file 'juju/hooks/invoker.py'
--- juju/hooks/invoker.py 2012-04-05 00:49:40 +0000
+++ juju/hooks/invoker.py 2012-05-01 00:26:25 +0000
@@ -175,11 +175,16 @@
          if isinstance(self._context, RelationHookContext):
              # Exclude the parent context for being looked up as a child
              relation_idents.discard(self._context.relation_ident)
+ display_parent_relation_ident = " on %r" % \
+ self._context.relation_ident
+ else:
+ display_parent_relation_ident = ""
          for relation_ident in relation_idents:
              child = yield self._context.get_relation_hook_context(
                  relation_ident)
              self._relation_contexts[relation_ident] = child
- self._log.debug("Cached relation hook contexts: %s" % (
+ self._log.debug("Cached relation hook contexts%s: %r" % (
+ display_parent_relation_ident,
                  sorted(relation_idents)))

      @property

Index: juju/unit/lifecycle.py
=== modified file 'juju/unit/lifecycle.py'
--- juju/unit/lifecycle.py 2012-04-10 22:58:44 +0000
+++ juju/unit/lifecycle.py 2012-05-01 00:26:25 +0000
@@ -731,6 +731,7 @@

      @inlineCallbacks
      def _execute_hook(self, invoker, hook_name, change):
+ yield invoker.start()
          hook_path = os.path.join(
              self._unit_dir, "charm", "hooks", hook_name)
          yield self._run_lock.acquire()

Index: juju/unit/tests/test_lifecycle.py
=== modified file 'juju/unit/tests/test_lifecycle.py'
--- juju/unit/tests/test_lifecycle.py 2012-04-10 07:10:47 +0000
+++ juju/unit/tests/test_lifecycle.py 2012-05-01 00:26:25 +0000
@@ -34,7 +34,7 @@
  from juju.unit.tests.test_charm import CharmPublisherTestBase

  from juju.lib.testing import TestCase
-from juju.lib.mocker import (ANY, MATCH, Mocker)
+from juju.lib.mocker import MATCH

  class UnwriteablePath(object):
@@ -358,7 +358,6 @@
          yield self.states["unit"].set_relation_resolved(
              {self.states["unit_rela...

Read more...

Revision history for this message
Jim Baker (jimbaker) wrote :
534. By Jim Baker

Fixed tests that saw augmented log changes

Revision history for this message
Kapil Thangavelu (hazmat) wrote :

lgtm

https://codereview.appspot.com/6131061/diff/3001/juju/unit/tests/test_lifecycle.py
File juju/unit/tests/test_lifecycle.py (right):

https://codereview.appspot.com/6131061/diff/3001/juju/unit/tests/test_lifecycle.py#newcode901
juju/unit/tests/test_lifecycle.py:901: for i in xrange(1, 3):
don't use xrange, its of little value and dropped in py3.

https://codereview.appspot.com/6131061/diff/3001/juju/unit/tests/test_lifecycle.py#newcode1331
juju/unit/tests/test_lifecycle.py:1331: for i in xrange(1, 5):
ditto re xrange

https://codereview.appspot.com/6131061/

535. By Jim Baker

Merged trunk

536. By Jim Baker

Addressed review points

Revision history for this message
Jim Baker (jimbaker) wrote :

Thanks, changed the minors and pushed accordingly

https://codereview.appspot.com/6131061/diff/3001/juju/unit/tests/test_lifecycle.py
File juju/unit/tests/test_lifecycle.py (right):

https://codereview.appspot.com/6131061/diff/3001/juju/unit/tests/test_lifecycle.py#newcode901
juju/unit/tests/test_lifecycle.py:901: for i in xrange(1, 3):
Pure habit here, fixed by using range instead

https://codereview.appspot.com/6131061/diff/3001/juju/unit/tests/test_lifecycle.py#newcode1331
juju/unit/tests/test_lifecycle.py:1331: for i in xrange(1, 5):
Ditto fix

https://codereview.appspot.com/6131061/

Revision history for this message
Kapil Thangavelu (hazmat) wrote :

looks good, pls go ahead w the merge.

On 2012/05/04 03:48:08, jimbaker wrote:
> Thanks, changed the minors and pushed accordingly

https://codereview.appspot.com/6131061/diff/3001/juju/unit/tests/test_lifecycle.py
> File juju/unit/tests/test_lifecycle.py (right):

https://codereview.appspot.com/6131061/diff/3001/juju/unit/tests/test_lifecycle.py#newcode901
> juju/unit/tests/test_lifecycle.py:901: for i in xrange(1, 3):
> Pure habit here, fixed by using range instead

https://codereview.appspot.com/6131061/diff/3001/juju/unit/tests/test_lifecycle.py#newcode1331
> juju/unit/tests/test_lifecycle.py:1331: for i in xrange(1, 5):
> Ditto fix

https://codereview.appspot.com/6131061/

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'juju/hooks/invoker.py'
2--- juju/hooks/invoker.py 2012-04-05 00:49:40 +0000
3+++ juju/hooks/invoker.py 2012-05-04 03:42:20 +0000
4@@ -175,11 +175,16 @@
5 if isinstance(self._context, RelationHookContext):
6 # Exclude the parent context for being looked up as a child
7 relation_idents.discard(self._context.relation_ident)
8+ display_parent_relation_ident = " on %r" % \
9+ self._context.relation_ident
10+ else:
11+ display_parent_relation_ident = ""
12 for relation_ident in relation_idents:
13 child = yield self._context.get_relation_hook_context(
14 relation_ident)
15 self._relation_contexts[relation_ident] = child
16- self._log.debug("Cached relation hook contexts: %s" % (
17+ self._log.debug("Cached relation hook contexts%s: %r" % (
18+ display_parent_relation_ident,
19 sorted(relation_idents)))
20
21 @property
22
23=== modified file 'juju/hooks/tests/test_invoker.py'
24--- juju/hooks/tests/test_invoker.py 2012-05-02 00:49:10 +0000
25+++ juju/hooks/tests/test_invoker.py 2012-05-04 03:42:20 +0000
26@@ -1035,7 +1035,7 @@
27 # then by children
28 self.assertLogLines(
29 self.log.getvalue(),
30- ["Cached relation hook contexts: ['db:1']",
31+ ["Cached relation hook contexts on 'db:0': ['db:1']",
32 "Flushed values for hook 'success-hook' on 'db:0'",
33 " Setting changed: u'a'=u'42' (was unset)",
34 " Setting changed: u'b'=u'xyz' (was unset)",
35@@ -1087,7 +1087,7 @@
36 "private-address": "mysql-0.example.com"})
37 self.assertLogLines(
38 self.log.getvalue(),
39- ["Cached relation hook contexts: ['db:1', 'db:2']",
40+ ["Cached relation hook contexts on 'db:0': ['db:1', 'db:2']",
41 "Flushed values for hook 'success-hook' on 'db:0'",
42 " Setting changed: u'a'=u'42' (was unset)",
43 " Setting changed: u'b'=u'xyz' (was unset)",
44@@ -1221,7 +1221,7 @@
45 "private-address": "mysql-0.example.com"})
46 self.assertLogLines(
47 self.log.getvalue(),
48- ["Cached relation hook contexts: ['db:1']",
49+ ["Cached relation hook contexts on 'db:0': ['db:1']",
50 "Flushed values for hook %r on 'db:0'" % os.path.basename(hook),
51 " Setting changed: u'a'=u'42' (was unset) on 'db:1'",
52 " Setting changed: u'b'=u'xyz' (was unset) on 'db:1'"])
53
54=== modified file 'juju/unit/lifecycle.py'
55--- juju/unit/lifecycle.py 2012-04-10 22:58:44 +0000
56+++ juju/unit/lifecycle.py 2012-05-04 03:42:20 +0000
57@@ -731,6 +731,7 @@
58
59 @inlineCallbacks
60 def _execute_hook(self, invoker, hook_name, change):
61+ yield invoker.start()
62 hook_path = os.path.join(
63 self._unit_dir, "charm", "hooks", hook_name)
64 yield self._run_lock.acquire()
65
66=== modified file 'juju/unit/tests/test_lifecycle.py'
67--- juju/unit/tests/test_lifecycle.py 2012-04-10 07:10:47 +0000
68+++ juju/unit/tests/test_lifecycle.py 2012-05-04 03:42:20 +0000
69@@ -34,7 +34,7 @@
70 from juju.unit.tests.test_charm import CharmPublisherTestBase
71
72 from juju.lib.testing import TestCase
73-from juju.lib.mocker import (ANY, MATCH, Mocker)
74+from juju.lib.mocker import MATCH
75
76
77 class UnwriteablePath(object):
78@@ -358,7 +358,6 @@
79 yield self.states["unit"].set_relation_resolved(
80 {self.states["unit_relation"].internal_relation_id: NO_HOOKS})
81
82-
83 # Wait for the relation to come back up
84 value = yield self.states["unit"].get_relation_resolved()
85
86@@ -889,6 +888,38 @@
87 self.assertEqual("up", (yield staying_workflow.get_state()))
88 yield new_lifecycle.stop()
89
90+ @inlineCallbacks
91+ def test_start_invoker(self):
92+ """Verify the invoker is started by the unit relation lifecycle"""
93+ # Setup three different wordpress services, wordpress,
94+ # wordpress-1, wordpress-2 with one service unit each. Each of
95+ # these will be on the relation with ident app:0, app:1, app:2
96+ self.write_hook(
97+ "start",
98+ '#!/bin/sh\n echo "hello world"\n')
99+ yield self.add_opposite_service_unit(self.states)
100+ for i in range(1, 3):
101+ yield self.add_opposite_service_unit(
102+ (yield self.add_relation_service_unit_to_another_endpoint(
103+ self.states,
104+ RelationEndpoint(
105+ "wordpress-%d" % i,
106+ "client-server", "db", "client"))))
107+
108+ finished = self.wait_on_hook("app-relation-changed", 3)
109+ yield self.lifecycle.start()
110+ yield finished
111+
112+ # This will verify that config-changed and start both are
113+ # cached properly. The remaining hook caching will be for the
114+ # relation hook contexts, along some permutation based on how
115+ # the hooks are actually scheduled. However, this is tested in
116+ # UnitRelationLifecycleTest.test_start_invoker so need not be
117+ # covered here.
118+ self.assertLogLines(
119+ self.hook_log.getvalue(),
120+ ["Cached relation hook contexts: ['app:0', 'app:1', 'app:2']"] * 2)
121+
122
123 class UnitLifecycleUpgradeTest(
124 LifecycleTestBase, CharmPublisherTestBase, CharmUpgradeTestBase):
125@@ -1290,6 +1321,32 @@
126 # The scheduler should run the hooks it queued up earlier
127 yield hooks_complete
128
129+ @inlineCallbacks
130+ def test_start_invoker(self):
131+ """Verify the invoker is started by the unit relation lifecycle"""
132+ # Setup 5 different wordpress services, wordpress, wordpress-1
133+ # through wordpress-4 with one service unit each. Each of these
134+ # will be on the relation app:0 ... app:4
135+ yield self.add_opposite_service_unit(self.states)
136+ for i in range(1, 5):
137+ yield self.add_opposite_service_unit(
138+ (yield self.add_relation_service_unit_to_another_endpoint(
139+ self.states,
140+ RelationEndpoint(
141+ "wordpress-%d" % i,
142+ "client-server", "db", "client"))))
143+ yield self.lifecycle.start()
144+ yield self.wait_on_hook(
145+ sequence=["app-relation-joined", "app-relation-changed"])
146+
147+ # Currently the only action taken by the invoker.start is to
148+ # cache the relation hook context; app:0 is excluded because
149+ # it is the parent
150+ self.assertIn(
151+ ("Cached relation hook contexts on 'app:0': "
152+ "['app:1', 'app:2', 'app:3', 'app:4']"),
153+ self.hook_log.getvalue())
154+
155
156 class SubordinateUnitLifecycleTest(LifecycleTestBase, CharmPublisherTestBase):
157

Subscribers

People subscribed via source and target branches

to status/vote changes: