Merge lp:~frankban/juju-quickstart/watcher-logs into lp:juju-quickstart

Proposed by Francesco Banconi
Status: Merged
Merged at revision: 20
Proposed branch: lp:~frankban/juju-quickstart/watcher-logs
Merge into: lp:juju-quickstart
Diff against target: 193 lines (+83/-25)
2 files modified
quickstart/juju.py (+20/-2)
quickstart/tests/test_juju.py (+63/-23)
To merge this branch: bzr merge lp:~frankban/juju-quickstart/watcher-logs
Reviewer Review Type Date Requested Status
Juju GUI Hackers Pending
Review via email: mp+196262@code.launchpad.net

Description of the change

Re-enable watcher requests/responses logging.

Tests: `make check`.

QA:
Run `.venv/bin/python juju-quickstart --debug` and
check that all the "AllWatcher" requests/responses
are properly logged.

https://codereview.appspot.com/30810043/

To post a comment you must log in.
Revision history for this message
Francesco Banconi (frankban) wrote :

Reviewers: mp+196262_code.launchpad.net,

Message:
Please take a look.

Description:
Re-enable watcher requests/responses logging.

Tests: `make check`.

QA:
Run `.venv/bin/python juju-quickstart --debug` and
check that all the "AllWatcher" requests/responses
are properly logged.

https://code.launchpad.net/~frankban/juju-quickstart/watcher-logs/+merge/196262

(do not edit description out of merge proposal)

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

Affected files (+85, -25 lines):
   A [revision details]
   M quickstart/juju.py
   M quickstart/tests/test_juju.py

Revision history for this message
Brad Crittenden (bac) wrote :

LGTM QA-OK

https://codereview.appspot.com/30810043/diff/1/quickstart/tests/test_juju.py
File quickstart/tests/test_juju.py (right):

https://codereview.appspot.com/30810043/diff/1/quickstart/tests/test_juju.py#newcode216
quickstart/tests/test_juju.py:216: # We are only interested on the calls
from now on.
s/on/in/

https://codereview.appspot.com/30810043/

21. By Francesco Banconi

Changes as per review.

Revision history for this message
Francesco Banconi (frankban) wrote :

*** Submitted:

Re-enable watcher requests/responses logging.

Tests: `make check`.

QA:
Run `.venv/bin/python juju-quickstart --debug` and
check that all the "AllWatcher" requests/responses
are properly logged.

R=bac
CC=
https://codereview.appspot.com/30810043

https://codereview.appspot.com/30810043/diff/1/quickstart/tests/test_juju.py
File quickstart/tests/test_juju.py (right):

https://codereview.appspot.com/30810043/diff/1/quickstart/tests/test_juju.py#newcode216
quickstart/tests/test_juju.py:216: # We are only interested on the calls
from now on.
On 2013/11/22 13:10:08, bac wrote:
> s/on/in/

Done.

https://codereview.appspot.com/30810043/

Revision history for this message
Francesco Banconi (frankban) wrote :

Thanks for the review Brad!

https://codereview.appspot.com/30810043/

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'quickstart/juju.py'
2--- quickstart/juju.py 2013-11-18 20:34:09 +0000
3+++ quickstart/juju.py 2013-11-22 13:15:18 +0000
4@@ -75,6 +75,24 @@
5 }
6 return self._rpc(request)
7
8+ def get_watcher(self):
9+ """Return a connected/authenticated environment watcher.
10+
11+ This method is similar to jujuclient.Environment.get_watch, but it
12+ enables logging on the resulting watcher requests/responses traffic.
13+ """
14+ # Logging is enabled by the connect factory function, which uses our
15+ # customized WebSocketConnection. Note that, since jujuclient does not
16+ # track request identifiers, it is not currently possible to avoid
17+ # establishing a new connection for each watcher.
18+ env = connect(self.endpoint)
19+ # For the remaining bits, see jujuclient.Environment.get_watch.
20+ env.login(**self._creds)
21+ watcher = jujuclient.Watcher(env.conn)
22+ self._watches.append(watcher)
23+ watcher.start()
24+ return watcher
25+
26 def get_status(self):
27 """Return the current status of the environment.
28
29@@ -86,7 +104,7 @@
30 change (i.e. "change" or "remove");
31 - data is a dict containing information about the releated entity.
32 """
33- with self.get_watch() as watcher:
34+ with self.get_watcher() as watcher:
35 changeset = watcher.next()
36 return changeset
37
38@@ -96,7 +114,7 @@
39 For each changeset, call the given processor callable, and yield
40 the values returned by the processor.
41 """
42- with self.get_watch() as watcher:
43+ with self.get_watcher() as watcher:
44 # The watcher closes when the context manager exit hook is called.
45 for changeset in watcher:
46 changes = processor(changeset)
47
48=== modified file 'quickstart/tests/test_juju.py'
49--- quickstart/tests/test_juju.py 2013-11-19 12:22:32 +0000
50+++ quickstart/tests/test_juju.py 2013-11-22 13:15:18 +0000
51@@ -100,17 +100,17 @@
52 'Params': params,
53 }
54
55- def patch_get_watch(self, return_value):
56- """Patch the Environment.get_watch method.
57+ def patch_get_watcher(self, return_value):
58+ """Patch the Environment.get_watcher method.
59
60 When the resulting mock is used as a context manager, the given return
61 value is returned.
62 """
63- get_watch_path = 'quickstart.juju.jujuclient.Environment.get_watch'
64- mock_get_watch = mock.MagicMock()
65- mock_get_watch().__enter__.return_value = iter(return_value)
66- mock_get_watch.reset_mock()
67- return mock.patch(get_watch_path, mock_get_watch)
68+ get_watcher_path = 'quickstart.juju.Environment.get_watcher'
69+ mock_get_watcher = mock.MagicMock()
70+ mock_get_watcher().__enter__.return_value = iter(return_value)
71+ mock_get_watcher.reset_mock()
72+ return mock.patch(get_watcher_path, mock_get_watcher)
73
74 def processor(self, changeset):
75 self.changesets.append(changeset)
76@@ -209,39 +209,79 @@
77 }
78 mock_rpc.assert_called_once_with(expected)
79
80+ @patch_rpc
81+ def test_get_watcher(self, mock_rpc):
82+ # Environment watching is correctly started.
83+ self.env.login('Secret!')
84+ # We are only interested in the calls from now on.
85+ mock_rpc.reset_mock()
86+ connect_path = 'quickstart.juju.WebSocketConnection.connect'
87+ watcher_rpc_path = 'quickstart.juju.jujuclient.Watcher._rpc'
88+ with mock.patch(connect_path) as mock_connect:
89+ with mock.patch(watcher_rpc_path) as mock_watcher_rpc:
90+ watcher = self.env.get_watcher()
91+ # The returned watcher is running.
92+ self.assertTrue(watcher.running)
93+ # The watcher uses our customized WebSocket connection with logging.
94+ self.assertIsInstance(watcher.conn, juju.WebSocketConnection)
95+ # A connection has been established with the API backend.
96+ mock_connect.assert_called_once_with(self.api_url, origin=self.api_url)
97+ # The connection used by the watcher is authenticated.
98+ expected = {
99+ 'Type': 'Admin',
100+ 'Request': 'Login',
101+ 'Params': {'AuthTag': 'user-admin', 'Password': 'Secret!'},
102+ }
103+ mock_rpc.assert_called_once_with(expected)
104+ # The watcher sent the correct start request.
105+ mock_watcher_rpc.assert_called_with({
106+ 'Type': 'Client',
107+ 'Request': 'WatchAll',
108+ 'Params': {},
109+ })
110+
111 def test_get_status(self):
112 # The current status of the Juju environment is properly returned.
113- changeset1 = ['change1', 'change2']
114- changeset2 = ['change3']
115- with self.patch_get_watch([changeset1, changeset2]) as mock_get_watch:
116+ changesets = [['change1', 'change2'], ['change3']]
117+ with self.patch_get_watcher(changesets) as mock_get_watcher:
118 status = self.env.get_status()
119 # The get_status call only waits for the first changeset.
120- self.assertEqual(changeset1, status)
121+ self.assertEqual(changesets[0], status)
122 # The watcher is correctly closed.
123- self.assertEqual(1, mock_get_watch().__exit__.call_count)
124+ self.assertEqual(1, mock_get_watcher().__exit__.call_count)
125+
126+ @patch_rpc
127+ def test_login(self, mock_rpc):
128+ # The login API call is properly generated.
129+ self.env.login('Secret!')
130+ expected = {
131+ 'Type': 'Admin',
132+ 'Request': 'Login',
133+ 'Params': {'AuthTag': 'user-admin', 'Password': 'Secret!'},
134+ }
135+ mock_rpc.assert_called_once_with(expected)
136
137 def test_watch_changes(self):
138 # It is possible to watch for changes using a processor callable.
139- changeset1 = ['change1', 'change2']
140- changeset2 = ['change3']
141- with self.patch_get_watch([changeset1, changeset2]) as mock_get_watch:
142+ changesets = [['change1', 'change2'], ['change3']]
143+ with self.patch_get_watcher(changesets) as mock_get_watcher:
144 watcher = self.env.watch_changes(self.processor)
145 # The first set of changes is correctly returned.
146 changeset = watcher.next()
147- self.assertEqual(changeset1, changeset)
148+ self.assertEqual(changesets[0], changeset)
149 # The second set of changes is correctly returned.
150 changeset = watcher.next()
151- self.assertEqual(changeset2, changeset)
152+ self.assertEqual(changesets[1], changeset)
153 # All the changes have been processed.
154- self.assertEqual([changeset1, changeset2], self.changesets)
155+ self.assertEqual(changesets, self.changesets)
156 # Ensure the API has been used properly.
157- mock_get_watch().__enter__.assert_called_once_with()
158+ mock_get_watcher().__enter__.assert_called_once_with()
159
160 def test_watch_changes_map(self):
161 # The processor callable can be used to modify changes.
162 changeset1 = ['change1', 'change2']
163 changeset2 = ['change3']
164- with self.patch_get_watch([changeset1, changeset2]):
165+ with self.patch_get_watcher([changeset1, changeset2]):
166 watcher = self.env.watch_changes(len)
167 changesets = list(watcher)
168 self.assertEqual([len(changeset1), len(changeset2)], changesets)
169@@ -251,7 +291,7 @@
170 changeset1 = ['change1', 'change2']
171 changeset2 = ['change3']
172 processor = lambda changes: None if len(changes) == 1 else changes
173- with self.patch_get_watch([changeset1, changeset2]):
174+ with self.patch_get_watcher([changeset1, changeset2]):
175 watcher = self.env.watch_changes(processor)
176 changesets = list(watcher)
177 self.assertEqual([changeset1], changesets)
178@@ -260,13 +300,13 @@
179 # A stop API call on the AllWatcher is performed when the watcher is
180 # garbage collected.
181 changeset = ['change1', 'change2']
182- with self.patch_get_watch([changeset]) as mock_get_watch:
183+ with self.patch_get_watcher([changeset]) as mock_get_watcher:
184 watcher = self.env.watch_changes(self.processor)
185 # The first set of changes is correctly returned.
186 watcher.next()
187 del watcher
188 # Ensure the API has been used properly.
189- self.assertEqual(1, mock_get_watch().__exit__.call_count)
190+ self.assertEqual(1, mock_get_watcher().__exit__.call_count)
191
192
193 class TestWebSocketConnection(unittest.TestCase):

Subscribers

People subscribed via source and target branches