Merge lp:~tealeg/landscape-client/package-monitor-scoped-resynch into lp:~landscape/landscape-client/trunk

Proposed by Geoff Teale
Status: Merged
Approved by: Geoff Teale
Approved revision: 723
Merged at revision: 713
Proposed branch: lp:~tealeg/landscape-client/package-monitor-scoped-resynch
Merge into: lp:~landscape/landscape-client/trunk
Diff against target: 178 lines (+76/-56)
3 files modified
landscape/monitor/packagemonitor.py (+1/-0)
landscape/monitor/tests/test_packagemonitor.py (+75/-15)
landscape/monitor/tests/test_usermonitor.py (+0/-41)
To merge this branch: bzr merge lp:~tealeg/landscape-client/package-monitor-scoped-resynch
Reviewer Review Type Date Requested Status
Björn Tillenius (community) Approve
Jerry Seutter (community) Approve
Review via email: mp+175014@code.launchpad.net

This proposal supersedes a proposal from 2013-07-12.

Commit message

This branch makes the PackageMonitor plugin only respond to resynchronize-clients events when they are either "package" or global scope.

Description of the change

This branch makes the PackageMonitor plugin only respond to resynchronize-clients events when they are either "package" or global scope.

To post a comment you must log in.
Revision history for this message
Jerry Seutter (jseutter) wrote : Posted in a previous version of this proposal

+1, looks good.

landscape/monitor/tests/test_packagemonitor.py:233:80: E501 line too long (80 characters)

review: Approve
Revision history for this message
Jerry Seutter (jseutter) wrote : Posted in a previous version of this proposal

In other branches the call signature for _resynchronize uses scopes:
def _resynchronize(self, scopes):

Can you update this changeset to use scopes instead of scope?

Revision history for this message
Geoff Teale (tealeg) wrote : Posted in a previous version of this proposal

> +1, looks good.
>
> landscape/monitor/tests/test_packagemonitor.py:233:80: E501 line too long (80
> characters)

Done.

Revision history for this message
Geoff Teale (tealeg) wrote : Posted in a previous version of this proposal

> In other branches the call signature for _resynchronize uses scopes:
> def _resynchronize(self, scopes):
>
> Can you update this changeset to use scopes instead of scope?

Done.

Revision history for this message
Björn Tillenius (bjornt) wrote : Posted in a previous version of this proposal

[1]

+ if len(scopes) == 0 or self.scope in scopes:

This makes me a bit sad. Having this in every _resynchronize() doesn't
doesn't look good.

I see that we register the resynchronize method with something like
this:

  self.registry.reactor.call_on("resynchronize", self._resynchronize)

I'd suggest doing something like this instead:

  self.registry.register_resynchronize(self.scope, self._resynchronize)

That way self._resynchronize would be called only for the relevant
scope, which makes the method easier to read.

review: Needs Fixing
Revision history for this message
Geoff Teale (tealeg) wrote : Posted in a previous version of this proposal

> [1]
>
> + if len(scopes) == 0 or self.scope in scopes:
>
> This makes me a bit sad. Having this in every _resynchronize() doesn't
> doesn't look good.
>
> I see that we register the resynchronize method with something like
> this:
>
> self.registry.reactor.call_on("resynchronize", self._resynchronize)
>
> I'd suggest doing something like this instead:
>
> self.registry.register_resynchronize(self.scope, self._resynchronize)
>
> That way self._resynchronize would be called only for the relevant
> scope, which makes the method easier to read.

Hi Bjorn, would you be happy for me to make that change as a follow on branch? It effects multiple branches here and it would be cleaner to tidy it all up in one swoop.

Revision history for this message
Björn Tillenius (bjornt) wrote : Posted in a previous version of this proposal

On Wed, Jul 10, 2013 at 05:37:53PM -0000, Geoff Teale wrote:
> > [1]
> >
> > + if len(scopes) == 0 or self.scope in scopes:
> >
> > This makes me a bit sad. Having this in every _resynchronize() doesn't
> > doesn't look good.
> >
> > I see that we register the resynchronize method with something like
> > this:
> >
> > self.registry.reactor.call_on("resynchronize", self._resynchronize)
> >
> > I'd suggest doing something like this instead:
> >
> > self.registry.register_resynchronize(self.scope, self._resynchronize)
> >
> > That way self._resynchronize would be called only for the relevant
> > scope, which makes the method easier to read.
>
> Hi Bjorn, would you be happy for me to make that change as a follow on
> branch? It effects multiple branches here and it would be cleaner to
> tidy it all up in one swoop.

Sure, that would be fine, if it's easier.

Revision history for this message
Geoff Teale (tealeg) wrote : Posted in a previous version of this proposal

> > Hi Bjorn, would you be happy for me to make that change as a follow on
> > branch? It effects multiple branches here and it would be cleaner to
> > tidy it all up in one swoop.
>
> Sure, that would be fine, if it's easier.

OK, I'll add a clean up branch at the end, I have some other calls to tidy up across all branches too.

722. By Geoff Teale

merge forwards and resolve conflicts.

Revision history for this message
Jerry Seutter (jseutter) wrote :

+1

review: Approve
Revision history for this message
Björn Tillenius (bjornt) wrote :

Looks good, +1

[1]

+ def test_not_resynchronize_with_other_scope(self):
+ """
+ If a 'resynchronize' reactor event is fired with an irrelevant scope,
+ the package monitor should not respond to this.
+ """
+ self.monitor.add(self.package_monitor)
+ self.createReporterTask()
+
+ disk_scope = ["disk"]
+ self.monitor.reactor.fire("resynchronize", disk_scope)
+
+ # The next task should *not* be the resynchronize message.
+ self.assertSingleReporterTask(
+ {'ids': [None], 'request-id': 1, 'type': 'package-ids'}, 1)

Where does that dict on the last line come from? Ok, after reading the
diff I can see that it's from createReporterTask(), but if someone looks
at the test only, it's hard to see.

It would be better to either explicitly add that task you expect to be
there, or make createReportTask() return the task and id, so that it's
clear that you expect the existing task to still be there, and no a new
one.

review: Approve
723. By Geoff Teale

Make test more readable by returning the task from createReporterTask.

Revision history for this message
Geoff Teale (tealeg) wrote :

> Looks good, +1
>
> [1]
>

Agreed, I've tidied that up.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'landscape/monitor/packagemonitor.py'
2--- landscape/monitor/packagemonitor.py 2013-07-12 08:18:35 +0000
3+++ landscape/monitor/packagemonitor.py 2013-07-25 13:19:26 +0000
4@@ -11,6 +11,7 @@
5 class PackageMonitor(MonitorPlugin):
6
7 run_interval = 1800
8+ scope = "package"
9
10 def __init__(self, package_store_filename=None):
11 super(PackageMonitor, self).__init__()
12
13=== modified file 'landscape/monitor/tests/test_packagemonitor.py'
14--- landscape/monitor/tests/test_packagemonitor.py 2013-07-16 08:30:55 +0000
15+++ landscape/monitor/tests/test_packagemonitor.py 2013-07-25 13:19:26 +0000
16@@ -23,6 +23,33 @@
17
18 self.package_monitor = PackageMonitor(self.package_store_filename)
19
20+ def createReporterTask(self):
21+ """
22+ Put a task for the package reported into the package store.
23+ """
24+ message = {"type": "package-ids", "ids": [None], "request-id": 1}
25+ return self.package_store.add_task("reporter", message)
26+
27+ def assertSingleReporterTask(self, data, task_id):
28+ """
29+ Check that we have exactly one task, that it contains the right data
30+ and that it's ID matches our expectation.
31+ """
32+ # The next task should contain the passed data.
33+ task = self.package_store.get_next_task("reporter")
34+ self.assertEqual(task.data, data)
35+
36+ # We want to make sure it has the correct id of 2 so that we
37+ # know it's not a new task that the reporter could possibly
38+ # remove by accident.
39+ self.assertEqual(task.id, task_id)
40+
41+ # Let's remove that task and make sure there are no more tasks
42+ # in the queue.
43+ task.remove()
44+ task = self.package_store.get_next_task("reporter")
45+ self.assertEqual(task, None)
46+
47 def test_create_default_store_upon_message_handling(self):
48 """
49 If the package sqlite database file doesn't exist yet, it is created
50@@ -200,28 +227,61 @@
51
52 def test_resynchronize(self):
53 """
54- If a 'resynchronize' reactor event is fired, the package
55- monitor should clear all queued tasks and queue a task that
56+ If a 'resynchronize' reactor event is fired with 'package' scope, the
57+ package monitor should clear all queued tasks and queue a task that
58 tells the report to clear out the rest of the package data.
59 """
60 self.monitor.add(self.package_monitor)
61- message = {"type": "package-ids", "ids": [None], "request-id": 1}
62- self.package_store.add_task("reporter", message)
63+ self.createReporterTask()
64+
65+ # The server doesn't currently send 'package' scope, but we should
66+ # support it in case we change that in the future.
67+ package_scope = ["package"]
68+ self.monitor.reactor.fire("resynchronize", package_scope)
69+
70+ self.assertSingleReporterTask({"type": "resynchronize"}, 2)
71+
72+ def test_resynchronize_gets_new_session_id(self):
73+ """
74+ When a 'resynchronize' reactor event is fired, the C{PackageMonitor}
75+ acquires a new session ID (as the old one will be blocked).
76+ """
77+ self.monitor.add(self.package_monitor)
78+ session_id = self.package_monitor._session_id
79+ self.createReporterTask()
80+
81+ self.package_monitor.client.broker.message_store.drop_session_ids()
82+ self.monitor.reactor.fire("resynchronize")
83+ self.assertNotEqual(session_id, self.package_monitor._session_id)
84+
85+ def test_resynchronize_on_global_scope(self):
86+ """
87+ If a 'resynchronize' reactor event is fired with global scope (the
88+ empty list) , the package monitor should act as if it were an event
89+ with 'package' scope.
90+ """
91+ self.monitor.add(self.package_monitor)
92+ self.createReporterTask()
93
94 self.monitor.reactor.fire("resynchronize")
95
96 # The next task should be the resynchronize message.
97- task = self.package_store.get_next_task("reporter")
98- self.assertEqual(task.data, {"type": "resynchronize"})
99-
100- # We want to make sure it is not the first message
101- self.assertNotEqual(task.id, 1)
102-
103- # Let's remove that task and make sure there are no more tasks
104- # in the queue.
105- task.remove()
106- task = self.package_store.get_next_task("reporter")
107- self.assertEqual(task, None)
108+ self.assertSingleReporterTask({"type": "resynchronize"}, 2)
109+
110+ def test_not_resynchronize_with_other_scope(self):
111+ """
112+ If a 'resynchronize' reactor event is fired with an irrelevant scope,
113+ the package monitor should not respond to this.
114+ """
115+ self.monitor.add(self.package_monitor)
116+ task = self.createReporterTask()
117+
118+ disk_scope = ["disk"]
119+ self.monitor.reactor.fire("resynchronize", disk_scope)
120+
121+ # The next task should *not* be the resynchronize message, but instead
122+ # the original task we created.
123+ self.assertSingleReporterTask(task.data, task.id)
124
125 def test_spawn_reporter_doesnt_chdir(self):
126 command = self.makeFile("#!/bin/sh\necho RUN\n")
127
128=== modified file 'landscape/monitor/tests/test_usermonitor.py'
129--- landscape/monitor/tests/test_usermonitor.py 2013-07-16 09:01:54 +0000
130+++ landscape/monitor/tests/test_usermonitor.py 2013-07-25 13:19:26 +0000
131@@ -178,47 +178,6 @@
132 self.assertMessages(
133 self.broker_service.message_store.get_pending_messages(),
134 [])
135-# =======
136-# When a C{resynchronize} event occurs any cached L{UserChange}
137-# snapshots should be cleared and a new message with users generated.
138-# """
139-# self.provider.users = [("jdoe", "x", 1000, 1000, "JD,,,,",
140-# "/home/jdoe", "/bin/sh")]
141-# self.provider.groups = [("webdev", "x", 1000, ["jdoe"])]
142-# self.broker_service.message_store.set_accepted_types(["users"])
143-# self.monitor.add(self.plugin)
144-# self.successResultOf(self.plugin.run())
145-
146-# persist = self.plugin._persist
147-# self.assertTrue(persist.get("users"))
148-# self.assertTrue(persist.get("groups"))
149-# self.assertMessages(
150-# self.broker_service.message_store.get_pending_messages(),
151-# [{"create-group-members": {u"webdev":[u"jdoe"]},
152-# "create-groups": [{"gid": 1000, "name": u"webdev"}],
153-# "create-users": [{"enabled": True, "home-phone": None,
154-# "location": None, "name": u"JD",
155-# "primary-gid": 1000, "uid": 1000,
156-# "username": u"jdoe", "work-phone": None}],
157-# "type": "users"}])
158-
159-# # Clear all the messages from the message store
160-# self.broker_service.message_store.delete_all_messages()
161-
162-# self.monitor.reactor.fire("resynchronize")
163-
164-# self.successResultOf(self.plugin.run())
165-# self.assertMessages(
166-# self.broker_service.message_store.get_pending_messages(),
167-# [{"create-group-members": {u"webdev":[u"jdoe"]},
168-# "create-groups": [{"gid": 1000, "name": u"webdev"}],
169-# "create-users": [{"enabled": True, "home-phone": None,
170-# "location": None, "name": u"JD",
171-# "primary-gid": 1000, "uid": 1000,
172-# "username": u"jdoe",
173-# "work-phone": None}],
174-# "type": "users"}])
175-# >>>>>>> MERGE-SOURCE
176
177 def test_run(self):
178 """

Subscribers

People subscribed via source and target branches

to all changes: