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
=== modified file 'juju/hooks/invoker.py'
--- juju/hooks/invoker.py 2012-04-05 00:49:40 +0000
+++ juju/hooks/invoker.py 2012-05-04 03:42:20 +0000
@@ -175,11 +175,16 @@
175 if isinstance(self._context, RelationHookContext):175 if isinstance(self._context, RelationHookContext):
176 # Exclude the parent context for being looked up as a child176 # Exclude the parent context for being looked up as a child
177 relation_idents.discard(self._context.relation_ident)177 relation_idents.discard(self._context.relation_ident)
178 display_parent_relation_ident = " on %r" % \
179 self._context.relation_ident
180 else:
181 display_parent_relation_ident = ""
178 for relation_ident in relation_idents:182 for relation_ident in relation_idents:
179 child = yield self._context.get_relation_hook_context(183 child = yield self._context.get_relation_hook_context(
180 relation_ident)184 relation_ident)
181 self._relation_contexts[relation_ident] = child185 self._relation_contexts[relation_ident] = child
182 self._log.debug("Cached relation hook contexts: %s" % (186 self._log.debug("Cached relation hook contexts%s: %r" % (
187 display_parent_relation_ident,
183 sorted(relation_idents)))188 sorted(relation_idents)))
184189
185 @property190 @property
186191
=== modified file 'juju/hooks/tests/test_invoker.py'
--- juju/hooks/tests/test_invoker.py 2012-05-02 00:49:10 +0000
+++ juju/hooks/tests/test_invoker.py 2012-05-04 03:42:20 +0000
@@ -1035,7 +1035,7 @@
1035 # then by children1035 # then by children
1036 self.assertLogLines(1036 self.assertLogLines(
1037 self.log.getvalue(),1037 self.log.getvalue(),
1038 ["Cached relation hook contexts: ['db:1']",1038 ["Cached relation hook contexts on 'db:0': ['db:1']",
1039 "Flushed values for hook 'success-hook' on 'db:0'",1039 "Flushed values for hook 'success-hook' on 'db:0'",
1040 " Setting changed: u'a'=u'42' (was unset)",1040 " Setting changed: u'a'=u'42' (was unset)",
1041 " Setting changed: u'b'=u'xyz' (was unset)",1041 " Setting changed: u'b'=u'xyz' (was unset)",
@@ -1087,7 +1087,7 @@
1087 "private-address": "mysql-0.example.com"})1087 "private-address": "mysql-0.example.com"})
1088 self.assertLogLines(1088 self.assertLogLines(
1089 self.log.getvalue(),1089 self.log.getvalue(),
1090 ["Cached relation hook contexts: ['db:1', 'db:2']",1090 ["Cached relation hook contexts on 'db:0': ['db:1', 'db:2']",
1091 "Flushed values for hook 'success-hook' on 'db:0'",1091 "Flushed values for hook 'success-hook' on 'db:0'",
1092 " Setting changed: u'a'=u'42' (was unset)",1092 " Setting changed: u'a'=u'42' (was unset)",
1093 " Setting changed: u'b'=u'xyz' (was unset)",1093 " Setting changed: u'b'=u'xyz' (was unset)",
@@ -1221,7 +1221,7 @@
1221 "private-address": "mysql-0.example.com"})1221 "private-address": "mysql-0.example.com"})
1222 self.assertLogLines(1222 self.assertLogLines(
1223 self.log.getvalue(),1223 self.log.getvalue(),
1224 ["Cached relation hook contexts: ['db:1']",1224 ["Cached relation hook contexts on 'db:0': ['db:1']",
1225 "Flushed values for hook %r on 'db:0'" % os.path.basename(hook),1225 "Flushed values for hook %r on 'db:0'" % os.path.basename(hook),
1226 " Setting changed: u'a'=u'42' (was unset) on 'db:1'",1226 " Setting changed: u'a'=u'42' (was unset) on 'db:1'",
1227 " Setting changed: u'b'=u'xyz' (was unset) on 'db:1'"])1227 " Setting changed: u'b'=u'xyz' (was unset) on 'db:1'"])
12281228
=== modified file 'juju/unit/lifecycle.py'
--- juju/unit/lifecycle.py 2012-04-10 22:58:44 +0000
+++ juju/unit/lifecycle.py 2012-05-04 03:42:20 +0000
@@ -731,6 +731,7 @@
731731
732 @inlineCallbacks732 @inlineCallbacks
733 def _execute_hook(self, invoker, hook_name, change):733 def _execute_hook(self, invoker, hook_name, change):
734 yield invoker.start()
734 hook_path = os.path.join(735 hook_path = os.path.join(
735 self._unit_dir, "charm", "hooks", hook_name)736 self._unit_dir, "charm", "hooks", hook_name)
736 yield self._run_lock.acquire()737 yield self._run_lock.acquire()
737738
=== 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-04 03:42:20 +0000
@@ -34,7 +34,7 @@
34from juju.unit.tests.test_charm import CharmPublisherTestBase34from juju.unit.tests.test_charm import CharmPublisherTestBase
3535
36from juju.lib.testing import TestCase36from juju.lib.testing import TestCase
37from juju.lib.mocker import (ANY, MATCH, Mocker)37from juju.lib.mocker import MATCH
3838
3939
40class UnwriteablePath(object):40class UnwriteablePath(object):
@@ -358,7 +358,6 @@
358 yield self.states["unit"].set_relation_resolved(358 yield self.states["unit"].set_relation_resolved(
359 {self.states["unit_relation"].internal_relation_id: NO_HOOKS})359 {self.states["unit_relation"].internal_relation_id: NO_HOOKS})
360360
361
362 # Wait for the relation to come back up361 # Wait for the relation to come back up
363 value = yield self.states["unit"].get_relation_resolved()362 value = yield self.states["unit"].get_relation_resolved()
364363
@@ -889,6 +888,38 @@
889 self.assertEqual("up", (yield staying_workflow.get_state()))888 self.assertEqual("up", (yield staying_workflow.get_state()))
890 yield new_lifecycle.stop()889 yield new_lifecycle.stop()
891890
891 @inlineCallbacks
892 def test_start_invoker(self):
893 """Verify the invoker is started by the unit relation lifecycle"""
894 # Setup three different wordpress services, wordpress,
895 # wordpress-1, wordpress-2 with one service unit each. Each of
896 # these will be on the relation with ident app:0, app:1, app:2
897 self.write_hook(
898 "start",
899 '#!/bin/sh\n echo "hello world"\n')
900 yield self.add_opposite_service_unit(self.states)
901 for i in range(1, 3):
902 yield self.add_opposite_service_unit(
903 (yield self.add_relation_service_unit_to_another_endpoint(
904 self.states,
905 RelationEndpoint(
906 "wordpress-%d" % i,
907 "client-server", "db", "client"))))
908
909 finished = self.wait_on_hook("app-relation-changed", 3)
910 yield self.lifecycle.start()
911 yield finished
912
913 # This will verify that config-changed and start both are
914 # cached properly. The remaining hook caching will be for the
915 # relation hook contexts, along some permutation based on how
916 # the hooks are actually scheduled. However, this is tested in
917 # UnitRelationLifecycleTest.test_start_invoker so need not be
918 # covered here.
919 self.assertLogLines(
920 self.hook_log.getvalue(),
921 ["Cached relation hook contexts: ['app:0', 'app:1', 'app:2']"] * 2)
922
892923
893class UnitLifecycleUpgradeTest(924class UnitLifecycleUpgradeTest(
894 LifecycleTestBase, CharmPublisherTestBase, CharmUpgradeTestBase):925 LifecycleTestBase, CharmPublisherTestBase, CharmUpgradeTestBase):
@@ -1290,6 +1321,32 @@
1290 # The scheduler should run the hooks it queued up earlier1321 # The scheduler should run the hooks it queued up earlier
1291 yield hooks_complete1322 yield hooks_complete
12921323
1324 @inlineCallbacks
1325 def test_start_invoker(self):
1326 """Verify the invoker is started by the unit relation lifecycle"""
1327 # Setup 5 different wordpress services, wordpress, wordpress-1
1328 # through wordpress-4 with one service unit each. Each of these
1329 # will be on the relation app:0 ... app:4
1330 yield self.add_opposite_service_unit(self.states)
1331 for i in range(1, 5):
1332 yield self.add_opposite_service_unit(
1333 (yield self.add_relation_service_unit_to_another_endpoint(
1334 self.states,
1335 RelationEndpoint(
1336 "wordpress-%d" % i,
1337 "client-server", "db", "client"))))
1338 yield self.lifecycle.start()
1339 yield self.wait_on_hook(
1340 sequence=["app-relation-joined", "app-relation-changed"])
1341
1342 # Currently the only action taken by the invoker.start is to
1343 # cache the relation hook context; app:0 is excluded because
1344 # it is the parent
1345 self.assertIn(
1346 ("Cached relation hook contexts on 'app:0': "
1347 "['app:1', 'app:2', 'app:3', 'app:4']"),
1348 self.hook_log.getvalue())
1349
12931350
1294class SubordinateUnitLifecycleTest(LifecycleTestBase, CharmPublisherTestBase):1351class SubordinateUnitLifecycleTest(LifecycleTestBase, CharmPublisherTestBase):
12951352

Subscribers

People subscribed via source and target branches

to status/vote changes: