Merge lp:~sseman/juju-ci-tools/resource-attach-2 into lp:juju-ci-tools
- resource-attach-2
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 1421 |
Proposed branch: | lp:~sseman/juju-ci-tools/resource-attach-2 |
Merge into: | lp:juju-ci-tools |
Diff against target: |
457 lines (+261/-54) 5 files modified
assess_resources.py (+70/-12) jujupy.py (+16/-0) tests/test_assess_resources.py (+142/-42) tests/test_jujupy.py (+29/-0) utility.py (+4/-0) |
To merge this branch: | bzr merge lp:~sseman/juju-ci-tools/resource-attach-2 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Curtis Hovey (community) | code | Approve | |
Review via email: mp+295532@code.launchpad.net |
Commit message
Description of the change
This is the second Resources branch.
- Added wait_for_resource function to wait until a resource has been downloaded to a unit.
- Added a CI test: update a resource file, attach and make sure the update is propagated to the unit.
- Added large tests by creating dummy large file and use it as a resource. An average, it takes about an hour to download 200 MB file from the controller to the unit. To me, this is slow. Users may have to wait for about half an hour to download Java runtime.
This completes adding CI tests for Resources. The next branch will add test for Resource Charmstore.
First branch:
https:/
Curtis Hovey (sinzui) wrote : | # |
We agreed on IRC to replace args with agent_timeout and resource_timeout.
Seman (sseman) wrote : | # |
Replaced args with agent_timeout and resource_timeout.
Preview Diff
1 | === modified file 'assess_resources.py' |
2 | --- assess_resources.py 2016-05-19 03:28:29 +0000 |
3 | +++ assess_resources.py 2016-05-24 22:43:31 +0000 |
4 | @@ -6,6 +6,7 @@ |
5 | import logging |
6 | import os |
7 | import sys |
8 | +from tempfile import NamedTemporaryFile |
9 | |
10 | from deploy_stack import ( |
11 | BootstrapManager, |
12 | @@ -56,38 +57,95 @@ |
13 | raise JujuAssertionError('Resource id not found.') |
14 | |
15 | |
16 | -def push_resource(client, resource_name, finger_print, size, deploy=True): |
17 | +def push_resource(client, resource_name, finger_print, size, agent_timeout, |
18 | + resource_timeout, deploy=True, resource_file=None): |
19 | charm_name = 'dummy-resource' |
20 | charm_path = local_charm_path(charm=charm_name, juju_ver=client.version) |
21 | - resource_file = os.path.join(charm_path, '{}.txt'.format(resource_name)) |
22 | + if resource_file is None: |
23 | + resource_file = os.path.join( |
24 | + charm_path, '{}.txt'.format(resource_name)) |
25 | + else: |
26 | + resource_file = os.path.join(charm_path, resource_file) |
27 | resource_arg = '{}={}'.format(resource_name, resource_file) |
28 | - log.info("Deploy charm with resource {}".format(resource_name)) |
29 | + log.info("Deploy charm with resource {} Size: {} File: {}".format( |
30 | + resource_name, size, resource_file)) |
31 | if deploy: |
32 | client.deploy(charm_path, resource=resource_arg) |
33 | else: |
34 | client.attach(charm_name, resource=resource_arg) |
35 | - # TODO: maybe need to add a wait until resource get is executed. |
36 | - client.wait_for_started() |
37 | + client.wait_for_started(timeout=agent_timeout) |
38 | + resource_id = '{}/{}'.format(charm_name, resource_name) |
39 | + client.wait_for_resource( |
40 | + resource_id, charm_name, timeout=resource_timeout) |
41 | status = client.list_resources(charm_name) |
42 | - resource_id = '{}/{}'.format(charm_name, resource_name) |
43 | verify_status(status, resource_id, resource_name, finger_print, size) |
44 | - |
45 | - |
46 | -def assess_resources(client): |
47 | + client.show_status() |
48 | + |
49 | + |
50 | +def fill_dummy_file(file_path, size): |
51 | + with open(file_path, "wb") as f: |
52 | + f.seek(size - 1) |
53 | + f.write('\0') |
54 | + |
55 | + |
56 | +def large_assess(client, agent_timeout, resource_timeout): |
57 | + tests = [ |
58 | + {"size": 1024 * 1024 * 10, |
59 | + "finger_print": ('d7c014629d74ae132cc9f88e3ec2f31652f40a7a1fcc52c54b' |
60 | + '04d6c0d089169bcd55958d1277b4cdf6262f21c712d0a7')}, |
61 | + {"size": 1024 * 1024 * 100, |
62 | + "finger_print": ('c11e93892b66de781e4d0883efe10482f8d1642f3b6574ba2e' |
63 | + 'e0da6f8db03f53c0eadfb5e5e0463574c113024ded369e')}, |
64 | + {"size": 1024 * 1024 * 200, |
65 | + "finger_print": ('77db39eca74c6205e31a7701e488a1df4b9b38a527a6084bd' |
66 | + 'bb6843fd430a0b51047378ee0255e633b32c0dda3cf43ab')}] |
67 | + for test in tests: |
68 | + with NamedTemporaryFile(suffix=".txt") as temp_file: |
69 | + fill_dummy_file(temp_file.name, size=test['size']) |
70 | + push_resource( |
71 | + client, 'bar', test['finger_print'], test['size'], |
72 | + agent_timeout, resource_timeout, deploy=False, |
73 | + resource_file=temp_file.name) |
74 | + |
75 | + |
76 | +def assess_resources(client, args): |
77 | finger_print = ('4ddc48627c6404e538bb0957632ef68618c0839649d9ad9e41ad94472' |
78 | 'c1589f4b7f9d830df6c4b209d7eb1b4b5522c4d') |
79 | size = 27 |
80 | - push_resource(client, 'foo', finger_print, size) |
81 | + push_resource(client, 'foo', finger_print, size, args.agent_timeout, |
82 | + args.resource_timeout) |
83 | finger_print = ('ffbf43d68a6960de63908bb05c14a026abeda136119d3797431bdd7b' |
84 | '469c1f027e57a28aeec0df01a792e9e70aad2d6b') |
85 | size = 17 |
86 | - push_resource(client, 'bar', finger_print, size, deploy=False) |
87 | + push_resource(client, 'bar', finger_print, size, args.agent_timeout, |
88 | + args.resource_timeout, deploy=False) |
89 | + finger_print = ('2a3821585efcccff1562efea4514dd860cd536441954e182a764991' |
90 | + '0e21f6a179a015677a68a351a11d3d2f277e551e4') |
91 | + size = 27 |
92 | + push_resource(client, 'bar', finger_print, size, args.agent_timeout, |
93 | + args.resource_timeout, deploy=False, resource_file='baz.txt') |
94 | + with NamedTemporaryFile(suffix=".txt") as temp_file: |
95 | + size = 1024 * 1024 |
96 | + finger_print = ('3164673a8ac27576ab5fc06b9adc4ce0aca5bd3025384b1cf2128' |
97 | + 'a8795e747c431e882785a0bf8dc70b42995db388575') |
98 | + fill_dummy_file(temp_file.name, size=size) |
99 | + push_resource(client, 'bar', finger_print, size, args.agent_timeout, |
100 | + args.resource_timeout, deploy=False, |
101 | + resource_file=temp_file.name) |
102 | + if args.large_test_enabled: |
103 | + large_assess(client, args.agent_timeout, args.resource_timeout) |
104 | |
105 | |
106 | def parse_args(argv): |
107 | """Parse all arguments.""" |
108 | parser = argparse.ArgumentParser(description="Assess resources") |
109 | add_basic_testing_arguments(parser) |
110 | + parser.add_argument('--large-test-enabled', action='store_true', |
111 | + help="Uses large file for testing.") |
112 | + parser.add_argument('--agent-timeout', type=int, default=1800, |
113 | + help='The time to wait for agents to start') |
114 | + parser.add_argument('--resource-timeout', type=int, default=1800, |
115 | + help='The time to wait for agents to start') |
116 | return parser.parse_args(argv) |
117 | |
118 | |
119 | @@ -96,7 +154,7 @@ |
120 | configure_logging(args.verbose) |
121 | bs_manager = BootstrapManager.from_args(args) |
122 | with bs_manager.booted_context(args.upload_tools): |
123 | - assess_resources(bs_manager.client) |
124 | + assess_resources(bs_manager.client, args) |
125 | return 0 |
126 | |
127 | |
128 | |
129 | === modified file 'jujupy.py' |
130 | --- jujupy.py 2016-05-23 01:34:59 +0000 |
131 | +++ jujupy.py 2016-05-24 22:43:31 +0000 |
132 | @@ -36,6 +36,7 @@ |
133 | ensure_deleted, |
134 | ensure_dir, |
135 | is_ipv6_address, |
136 | + JujuResourceTimeout, |
137 | pause, |
138 | quote, |
139 | scoped_environ, |
140 | @@ -910,6 +911,21 @@ |
141 | args = args + ('--details',) |
142 | return yaml_loads(self.get_juju_output('list-resources', *args)) |
143 | |
144 | + def wait_for_resource(self, resource_id, service_or_unit, timeout=60): |
145 | + log.info('Waiting for resource. Resource id:{}'.format(resource_id)) |
146 | + for _ in until_timeout(timeout): |
147 | + resources = self.list_resources(service_or_unit)['resources'] |
148 | + for resource in resources: |
149 | + if resource['expected']['resourceid'] == resource_id: |
150 | + if (resource['expected']['fingerprint'] == |
151 | + resource['unit']['fingerprint']): |
152 | + return |
153 | + time.sleep(.1) |
154 | + raise JujuResourceTimeout( |
155 | + 'Timeout waiting for a resource to be downloaded. ' |
156 | + 'ResourceId: {} Service or Unit: {} Timeout: {}'.format( |
157 | + resource_id, service_or_unit, timeout)) |
158 | + |
159 | def upgrade_charm(self, service, charm_path=None): |
160 | args = (service,) |
161 | if charm_path is not None: |
162 | |
163 | === modified file 'tests/test_assess_resources.py' |
164 | --- tests/test_assess_resources.py 2016-05-19 03:28:29 +0000 |
165 | +++ tests/test_assess_resources.py 2016-05-24 22:43:31 +0000 |
166 | @@ -1,10 +1,11 @@ |
167 | -import copy |
168 | import logging |
169 | +from argparse import Namespace |
170 | from mock import Mock, patch, call |
171 | import StringIO |
172 | |
173 | from assess_resources import ( |
174 | assess_resources, |
175 | + large_assess, |
176 | parse_args, |
177 | push_resource, |
178 | main, |
179 | @@ -57,36 +58,24 @@ |
180 | mock_e.assert_called_once_with("an-env") |
181 | mock_c.assert_called_once_with(env, "/bin/juju", debug=False) |
182 | self.assertEqual(mock_bc.call_count, 1) |
183 | - mock_assess.assert_called_once_with(client) |
184 | - |
185 | - |
186 | -class TestAssess(TestCase): |
187 | - |
188 | - status = {'resources': [{ |
189 | - 'expected': { |
190 | - 'origin': 'upload', 'used': True, 'description': 'foo resource.', |
191 | - 'username': 'admin@local', 'resourceid': 'dummy-resource/foo', |
192 | - 'name': 'foo', 'serviceid': 'dummy-resource', 'path': 'foo.txt', |
193 | - 'fingerprint': '1234', 'type': 'file', 'size': 27}, |
194 | - 'unit': { |
195 | - 'origin': 'upload', 'username': 'admin@local', 'used': True, |
196 | - 'name': 'foo', 'resourceid': 'dummy-resource/foo', |
197 | - 'serviceid': 'dummy-resource', 'fingerprint': '1234', |
198 | - 'path': 'foo.txt', 'size': 27, 'type': 'file', |
199 | - 'description': 'foo resource.'}}]} |
200 | + mock_assess.assert_called_once_with(client, make_args()) |
201 | + |
202 | + |
203 | +class TestAssessResources(TestCase): |
204 | |
205 | def test_verify_status(self): |
206 | - verify_status(self.status, 'dummy-resource/foo', 'foo', '1234', 27) |
207 | + verify_status( |
208 | + make_resource_list(), 'dummy-resource/foo', 'foo', '1234', 27) |
209 | |
210 | def test_verify_status_exception(self): |
211 | - status = copy.deepcopy(self.status) |
212 | + status = make_resource_list() |
213 | status['resources'][0]['expected']['origin'] = 'charmstore' |
214 | with self.assertRaisesRegexp( |
215 | JujuAssertionError, 'Unexpected resource list values'): |
216 | verify_status(status, 'dummy-resource/foo', 'foo', '1234', 27) |
217 | |
218 | def test_verify_status_unit_exception(self): |
219 | - status = copy.deepcopy(self.status) |
220 | + status = make_resource_list() |
221 | status['resources'][0]['unit']['origin'] = 'charmstore' |
222 | with self.assertRaisesRegexp( |
223 | JujuAssertionError, 'Unexpected unit resource list values'): |
224 | @@ -95,38 +84,149 @@ |
225 | def test_verify_status_no_resoruce_id_exception(self): |
226 | with self.assertRaisesRegexp( |
227 | JujuAssertionError, 'Resource id not found.'): |
228 | - verify_status(self.status, 'NO_ID', 'foo', '1234', 27) |
229 | + verify_status(make_resource_list(), 'NO_ID', 'foo', '1234', 27) |
230 | |
231 | def test_push_resource(self): |
232 | mock_client = Mock( |
233 | - spec=["deploy", "wait_for_started", "list_resources"]) |
234 | + spec=["deploy", "wait_for_started", "list_resources", |
235 | + "wait_for_resource", "show_status"]) |
236 | mock_client.version = '2.0.0' |
237 | - mock_client.list_resources.return_value = self.status |
238 | - push_resource(mock_client, 'foo', '1234', 27) |
239 | + mock_client.list_resources.return_value = make_resource_list() |
240 | + push_resource(mock_client, 'foo', '1234', 27, 1800, 1800) |
241 | mock_client.deploy.assert_called_once_with( |
242 | 'dummy-resource', resource='foo=dummy-resource/foo.txt') |
243 | - mock_client.wait_for_started.assert_called_once_with() |
244 | + mock_client.wait_for_started.assert_called_once_with(timeout=1800) |
245 | + mock_client.show_status.assert_called_once_with() |
246 | |
247 | def test_push_resource_attach(self): |
248 | mock_client = Mock( |
249 | - spec=["attach", "wait_for_started", "list_resources"]) |
250 | + spec=["attach", "wait_for_started", "list_resources", |
251 | + "wait_for_resource", "show_status"]) |
252 | mock_client.version = '2.0.0' |
253 | - mock_client.list_resources.return_value = self.status |
254 | - push_resource(mock_client, 'foo', '1234', 27, deploy=False) |
255 | + mock_client.list_resources.return_value = make_resource_list() |
256 | + push_resource(mock_client, 'foo', '1234', 27, 1800, 1800, deploy=False) |
257 | mock_client.attach.assert_called_once_with( |
258 | 'dummy-resource', resource='foo=dummy-resource/foo.txt') |
259 | - mock_client.wait_for_started.assert_called_once_with() |
260 | + mock_client.wait_for_started.assert_called_once_with(timeout=1800) |
261 | |
262 | def test_assess_resources(self): |
263 | - with patch("assess_resources.push_resource", autospec=True) as mock_p: |
264 | - assess_resources(None) |
265 | - calls = [ |
266 | - call( |
267 | - None, 'foo', |
268 | - '4ddc48627c6404e538bb0957632ef68618c0839649d9ad9e41ad94472c158' |
269 | - '9f4b7f9d830df6c4b209d7eb1b4b5522c4d', 27), |
270 | - call( |
271 | - None, 'bar', |
272 | - 'ffbf43d68a6960de63908bb05c14a026abeda136119d3797431bdd7b469c1' |
273 | - 'f027e57a28aeec0df01a792e9e70aad2d6b', 17, deploy=False)] |
274 | - self.assertEqual(mock_p.mock_calls, calls) |
275 | + fake_file = FakeFile() |
276 | + args = make_args() |
277 | + with patch("assess_resources.push_resource", autospec=True) as mock_p: |
278 | + with patch('assess_resources.NamedTemporaryFile', |
279 | + autospec=True) as mock_ntf: |
280 | + mock_ntf.return_value.__enter__.return_value = fake_file |
281 | + assess_resources(None, args) |
282 | + calls = [ |
283 | + call( |
284 | + None, 'foo', |
285 | + '4ddc48627c6404e538bb0957632ef68618c0839649d9ad9e41ad94472c158' |
286 | + '9f4b7f9d830df6c4b209d7eb1b4b5522c4d', 27, 1800, 1800), |
287 | + call( |
288 | + None, 'bar', |
289 | + 'ffbf43d68a6960de63908bb05c14a026abeda136119d3797431bdd7b469c1' |
290 | + 'f027e57a28aeec0df01a792e9e70aad2d6b', 17, 1800, 1800, |
291 | + deploy=False), |
292 | + call( |
293 | + None, 'bar', |
294 | + '2a3821585efcccff1562efea4514dd860cd536441954e182a7649910e21f6' |
295 | + 'a179a015677a68a351a11d3d2f277e551e4', 27, 1800, 1800, |
296 | + deploy=False, resource_file='baz.txt'), |
297 | + call( |
298 | + None, 'bar', |
299 | + '3164673a8ac27576ab5fc06b9adc4ce0aca5bd3025384b1cf2128a8795e74' |
300 | + '7c431e882785a0bf8dc70b42995db388575', 1024 * 1024, 1800, 1800, |
301 | + deploy=False, resource_file='/tmp/fake'), |
302 | + ] |
303 | + self.assertEqual(mock_p.mock_calls, calls) |
304 | + |
305 | + def test_assess_resources_large_test(self): |
306 | + fake_file = FakeFile() |
307 | + args = make_args() |
308 | + args.large_test_enabled = True |
309 | + with patch("assess_resources.push_resource", autospec=True) as mock_p: |
310 | + with patch('assess_resources.fill_dummy_file', |
311 | + autospec=True) as mock_fdf: |
312 | + with patch('assess_resources.NamedTemporaryFile', |
313 | + autospec=True) as mock_ntf: |
314 | + mock_ntf.return_value.__enter__.return_value = fake_file |
315 | + with patch('assess_resources.large_assess', |
316 | + autospec=True) as mock_lt: |
317 | + assess_resources(None, args) |
318 | + calls = [ |
319 | + call( |
320 | + None, 'foo', |
321 | + '4ddc48627c6404e538bb0957632ef68618c0839649d9ad9e41ad94472c158' |
322 | + '9f4b7f9d830df6c4b209d7eb1b4b5522c4d', 27, 1800, 1800), |
323 | + call( |
324 | + None, 'bar', |
325 | + 'ffbf43d68a6960de63908bb05c14a026abeda136119d3797431bdd7b469c1' |
326 | + 'f027e57a28aeec0df01a792e9e70aad2d6b', 17, 1800, 1800, |
327 | + deploy=False), |
328 | + call( |
329 | + None, 'bar', |
330 | + '2a3821585efcccff1562efea4514dd860cd536441954e182a7649910e21f6' |
331 | + 'a179a015677a68a351a11d3d2f277e551e4', 27, 1800, 1800, |
332 | + deploy=False, resource_file='baz.txt'), |
333 | + call(None, 'bar', |
334 | + '3164673a8ac27576ab5fc06b9adc4ce0aca5bd3025384b1cf2128a8795e7' |
335 | + '47c431e882785a0bf8dc70b42995db388575', 1024 * 1024, 1800, |
336 | + 1800, deploy=False, resource_file='/tmp/fake')] |
337 | + self.assertEqual(mock_p.mock_calls, calls) |
338 | + mock_fdf.assert_called_once_with('/tmp/fake', 1024 * 1024) |
339 | + mock_lt.assert_called_once_with(None, 1800, 1800) |
340 | + |
341 | + def test_large_tests(self): |
342 | + fake_file = FakeFile() |
343 | + with patch("assess_resources.push_resource", autospec=True) as mock_pr: |
344 | + with patch('assess_resources.NamedTemporaryFile', |
345 | + autospec=True) as mock_ntf: |
346 | + mock_ntf.return_value.__enter__.return_value = fake_file |
347 | + with patch('assess_resources.fill_dummy_file', |
348 | + autospec=True): |
349 | + large_assess(None, 1800, 1800) |
350 | + calls = [ |
351 | + call( |
352 | + None, 'bar', |
353 | + 'd7c014629d74ae132cc9f88e3ec2f31652f40a7a1fcc52c54b04d6c0d0891' |
354 | + '69bcd55958d1277b4cdf6262f21c712d0a7', 1024 * 1024 * 10, 1800, |
355 | + 1800, deploy=False, resource_file='/tmp/fake'), |
356 | + call( |
357 | + None, 'bar', |
358 | + 'c11e93892b66de781e4d0883efe10482f8d1642f3b6574ba2ee0da6f8db03' |
359 | + 'f53c0eadfb5e5e0463574c113024ded369e', 1024 * 1024 * 100, 1800, |
360 | + 1800, deploy=False, resource_file='/tmp/fake'), |
361 | + call( |
362 | + None, 'bar', |
363 | + '77db39eca74c6205e31a7701e488a1df4b9b38a527a6084bdbb6843fd430a' |
364 | + '0b51047378ee0255e633b32c0dda3cf43ab', 1024 * 1024 * 200, 1800, |
365 | + 1800, deploy=False, resource_file='/tmp/fake')] |
366 | + self.assertEqual(mock_pr.mock_calls, calls) |
367 | + |
368 | + |
369 | +def make_args(): |
370 | + return Namespace( |
371 | + agent_stream=None, agent_timeout=1800, agent_url=None, |
372 | + bootstrap_host=None, debug=False, env='an-env', juju_bin='/bin/juju', |
373 | + keep_env=False, large_test_enabled=False, logs='/tmp/logs', machine=[], |
374 | + region=None, resource_timeout=1800, series=None, |
375 | + temp_env_name='an-env-mod', upload_tools=False, verbose=10) |
376 | + |
377 | + |
378 | +def make_resource_list(): |
379 | + return {'resources': [{ |
380 | + 'expected': { |
381 | + 'origin': 'upload', 'used': True, 'description': 'foo resource.', |
382 | + 'username': 'admin@local', 'resourceid': 'dummy-resource/foo', |
383 | + 'name': 'foo', 'serviceid': 'dummy-resource', 'path': 'foo.txt', |
384 | + 'fingerprint': '1234', 'type': 'file', 'size': 27}, |
385 | + 'unit': { |
386 | + 'origin': 'upload', 'username': 'admin@local', 'used': True, |
387 | + 'name': 'foo', 'resourceid': 'dummy-resource/foo', |
388 | + 'serviceid': 'dummy-resource', 'fingerprint': '1234', |
389 | + 'path': 'foo.txt', 'size': 27, 'type': 'file', |
390 | + 'description': 'foo resource.'}}]} |
391 | + |
392 | + |
393 | +class FakeFile: |
394 | + name = '/tmp/fake' |
395 | |
396 | === modified file 'tests/test_jujupy.py' |
397 | --- tests/test_jujupy.py 2016-05-23 03:38:07 +0000 |
398 | +++ tests/test_jujupy.py 2016-05-24 22:43:31 +0000 |
399 | @@ -79,7 +79,9 @@ |
400 | TestCase, |
401 | FakeHomeTestCase, |
402 | ) |
403 | +from tests.test_assess_resources import make_resource_list |
404 | from utility import ( |
405 | + JujuResourceTimeout, |
406 | scoped_environ, |
407 | temp_dir, |
408 | ) |
409 | @@ -1609,6 +1611,33 @@ |
410 | mock_gjo.assert_called_with( |
411 | 'list-resources', '--format', 'yaml', 'foo', '--details') |
412 | |
413 | + def test_wait_for_resource(self): |
414 | + client = EnvJujuClient(JujuData('local'), None, None) |
415 | + with patch.object( |
416 | + client, 'list_resources', |
417 | + return_value=make_resource_list()) as mock_lr: |
418 | + client.wait_for_resource('dummy-resource/foo', 'foo') |
419 | + mock_lr.assert_called_once_with('foo') |
420 | + |
421 | + def test_wait_for_resource_timeout(self): |
422 | + client = EnvJujuClient(JujuData('local'), None, None) |
423 | + resource_list = make_resource_list() |
424 | + resource_list['resources'][0]['expected']['resourceid'] = 'bad_id' |
425 | + with patch.object( |
426 | + client, 'list_resources', |
427 | + return_value=resource_list) as mock_lr: |
428 | + with patch('jujupy.until_timeout', autospec=True, |
429 | + return_value=[0, 1]) as mock_ju: |
430 | + with patch('time.sleep', autospec=True) as mock_ts: |
431 | + with self.assertRaisesRegexp( |
432 | + JujuResourceTimeout, |
433 | + 'Timeout waiting for a resource to be downloaded'): |
434 | + client.wait_for_resource('dummy-resource/foo', 'foo') |
435 | + calls = [call('foo'), call('foo')] |
436 | + self.assertEqual(mock_lr.mock_calls, calls) |
437 | + self.assertEqual(mock_ts.mock_calls, [call(.1), call(.1)]) |
438 | + self.assertEqual(mock_ju.mock_calls, [call(60)]) |
439 | + |
440 | def test_deploy_bundle_2x(self): |
441 | client = EnvJujuClient(JujuData('an_env', None), |
442 | '1.23-series-arch', None) |
443 | |
444 | === modified file 'utility.py' |
445 | --- utility.py 2016-05-19 03:28:29 +0000 |
446 | +++ utility.py 2016-05-24 22:43:31 +0000 |
447 | @@ -97,6 +97,10 @@ |
448 | """Exception for juju assertion failures.""" |
449 | |
450 | |
451 | +class JujuResourceTimeout(Exception): |
452 | + """A timeout exception for a resource not being downloaded into a unit.""" |
453 | + |
454 | + |
455 | class enforce_juju_path(argparse.Action): |
456 | """Enforces that a path ending with juju is given.""" |
457 | def __call__(self, parser, namespace, values, option_string=None): |
Hi seman. I like this branch's feature, but am not excited by the passing of args to so many methods. It isn't clear which args are used. I had to search the diff to learn that a deep function needs agent_timeout and resource_timeout. The function's required are ambiguous. There are a lot of args to out scripts and I don't want to lookup/make everything to setup timeouts.
I prefer to agent_timeout and resource_timeout as args. If passing timeouts is a problem for many scripts, maybe we want to create a timeout object that has default timeouts for everything and we can override it in scripts and tests.