Merge lp:~sseman/juju-ci-tools/resource-attach-2 into lp:juju-ci-tools

Proposed by Seman
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
Reviewer Review Type Date Requested Status
Curtis Hovey (community) code Approve
Review via email: mp+295532@code.launchpad.net

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://code.launchpad.net/~sseman/juju-ci-tools/resource-attach/+merge/295141

To post a comment you must log in.
Revision history for this message
Curtis Hovey (sinzui) wrote :

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.

review: Needs Information (code)
Revision history for this message
Curtis Hovey (sinzui) wrote :

We agreed on IRC to replace args with agent_timeout and resource_timeout.

review: Approve (code)
1419. By Seman

Replaced args with agent_timeout and resource_timeout.

Revision history for this message
Seman (sseman) wrote :

Replaced args with agent_timeout and resource_timeout.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'assess_resources.py'
--- assess_resources.py 2016-05-19 03:28:29 +0000
+++ assess_resources.py 2016-05-24 22:43:31 +0000
@@ -6,6 +6,7 @@
6import logging6import logging
7import os7import os
8import sys8import sys
9from tempfile import NamedTemporaryFile
910
10from deploy_stack import (11from deploy_stack import (
11 BootstrapManager,12 BootstrapManager,
@@ -56,38 +57,95 @@
56 raise JujuAssertionError('Resource id not found.')57 raise JujuAssertionError('Resource id not found.')
5758
5859
59def push_resource(client, resource_name, finger_print, size, deploy=True):60def push_resource(client, resource_name, finger_print, size, agent_timeout,
61 resource_timeout, deploy=True, resource_file=None):
60 charm_name = 'dummy-resource'62 charm_name = 'dummy-resource'
61 charm_path = local_charm_path(charm=charm_name, juju_ver=client.version)63 charm_path = local_charm_path(charm=charm_name, juju_ver=client.version)
62 resource_file = os.path.join(charm_path, '{}.txt'.format(resource_name))64 if resource_file is None:
65 resource_file = os.path.join(
66 charm_path, '{}.txt'.format(resource_name))
67 else:
68 resource_file = os.path.join(charm_path, resource_file)
63 resource_arg = '{}={}'.format(resource_name, resource_file)69 resource_arg = '{}={}'.format(resource_name, resource_file)
64 log.info("Deploy charm with resource {}".format(resource_name))70 log.info("Deploy charm with resource {} Size: {} File: {}".format(
71 resource_name, size, resource_file))
65 if deploy:72 if deploy:
66 client.deploy(charm_path, resource=resource_arg)73 client.deploy(charm_path, resource=resource_arg)
67 else:74 else:
68 client.attach(charm_name, resource=resource_arg)75 client.attach(charm_name, resource=resource_arg)
69 # TODO: maybe need to add a wait until resource get is executed.76 client.wait_for_started(timeout=agent_timeout)
70 client.wait_for_started()77 resource_id = '{}/{}'.format(charm_name, resource_name)
78 client.wait_for_resource(
79 resource_id, charm_name, timeout=resource_timeout)
71 status = client.list_resources(charm_name)80 status = client.list_resources(charm_name)
72 resource_id = '{}/{}'.format(charm_name, resource_name)
73 verify_status(status, resource_id, resource_name, finger_print, size)81 verify_status(status, resource_id, resource_name, finger_print, size)
7482 client.show_status()
7583
76def assess_resources(client):84
85def fill_dummy_file(file_path, size):
86 with open(file_path, "wb") as f:
87 f.seek(size - 1)
88 f.write('\0')
89
90
91def large_assess(client, agent_timeout, resource_timeout):
92 tests = [
93 {"size": 1024 * 1024 * 10,
94 "finger_print": ('d7c014629d74ae132cc9f88e3ec2f31652f40a7a1fcc52c54b'
95 '04d6c0d089169bcd55958d1277b4cdf6262f21c712d0a7')},
96 {"size": 1024 * 1024 * 100,
97 "finger_print": ('c11e93892b66de781e4d0883efe10482f8d1642f3b6574ba2e'
98 'e0da6f8db03f53c0eadfb5e5e0463574c113024ded369e')},
99 {"size": 1024 * 1024 * 200,
100 "finger_print": ('77db39eca74c6205e31a7701e488a1df4b9b38a527a6084bd'
101 'bb6843fd430a0b51047378ee0255e633b32c0dda3cf43ab')}]
102 for test in tests:
103 with NamedTemporaryFile(suffix=".txt") as temp_file:
104 fill_dummy_file(temp_file.name, size=test['size'])
105 push_resource(
106 client, 'bar', test['finger_print'], test['size'],
107 agent_timeout, resource_timeout, deploy=False,
108 resource_file=temp_file.name)
109
110
111def assess_resources(client, args):
77 finger_print = ('4ddc48627c6404e538bb0957632ef68618c0839649d9ad9e41ad94472'112 finger_print = ('4ddc48627c6404e538bb0957632ef68618c0839649d9ad9e41ad94472'
78 'c1589f4b7f9d830df6c4b209d7eb1b4b5522c4d')113 'c1589f4b7f9d830df6c4b209d7eb1b4b5522c4d')
79 size = 27114 size = 27
80 push_resource(client, 'foo', finger_print, size)115 push_resource(client, 'foo', finger_print, size, args.agent_timeout,
116 args.resource_timeout)
81 finger_print = ('ffbf43d68a6960de63908bb05c14a026abeda136119d3797431bdd7b'117 finger_print = ('ffbf43d68a6960de63908bb05c14a026abeda136119d3797431bdd7b'
82 '469c1f027e57a28aeec0df01a792e9e70aad2d6b')118 '469c1f027e57a28aeec0df01a792e9e70aad2d6b')
83 size = 17119 size = 17
84 push_resource(client, 'bar', finger_print, size, deploy=False)120 push_resource(client, 'bar', finger_print, size, args.agent_timeout,
121 args.resource_timeout, deploy=False)
122 finger_print = ('2a3821585efcccff1562efea4514dd860cd536441954e182a764991'
123 '0e21f6a179a015677a68a351a11d3d2f277e551e4')
124 size = 27
125 push_resource(client, 'bar', finger_print, size, args.agent_timeout,
126 args.resource_timeout, deploy=False, resource_file='baz.txt')
127 with NamedTemporaryFile(suffix=".txt") as temp_file:
128 size = 1024 * 1024
129 finger_print = ('3164673a8ac27576ab5fc06b9adc4ce0aca5bd3025384b1cf2128'
130 'a8795e747c431e882785a0bf8dc70b42995db388575')
131 fill_dummy_file(temp_file.name, size=size)
132 push_resource(client, 'bar', finger_print, size, args.agent_timeout,
133 args.resource_timeout, deploy=False,
134 resource_file=temp_file.name)
135 if args.large_test_enabled:
136 large_assess(client, args.agent_timeout, args.resource_timeout)
85137
86138
87def parse_args(argv):139def parse_args(argv):
88 """Parse all arguments."""140 """Parse all arguments."""
89 parser = argparse.ArgumentParser(description="Assess resources")141 parser = argparse.ArgumentParser(description="Assess resources")
90 add_basic_testing_arguments(parser)142 add_basic_testing_arguments(parser)
143 parser.add_argument('--large-test-enabled', action='store_true',
144 help="Uses large file for testing.")
145 parser.add_argument('--agent-timeout', type=int, default=1800,
146 help='The time to wait for agents to start')
147 parser.add_argument('--resource-timeout', type=int, default=1800,
148 help='The time to wait for agents to start')
91 return parser.parse_args(argv)149 return parser.parse_args(argv)
92150
93151
@@ -96,7 +154,7 @@
96 configure_logging(args.verbose)154 configure_logging(args.verbose)
97 bs_manager = BootstrapManager.from_args(args)155 bs_manager = BootstrapManager.from_args(args)
98 with bs_manager.booted_context(args.upload_tools):156 with bs_manager.booted_context(args.upload_tools):
99 assess_resources(bs_manager.client)157 assess_resources(bs_manager.client, args)
100 return 0158 return 0
101159
102160
103161
=== modified file 'jujupy.py'
--- jujupy.py 2016-05-23 01:34:59 +0000
+++ jujupy.py 2016-05-24 22:43:31 +0000
@@ -36,6 +36,7 @@
36 ensure_deleted,36 ensure_deleted,
37 ensure_dir,37 ensure_dir,
38 is_ipv6_address,38 is_ipv6_address,
39 JujuResourceTimeout,
39 pause,40 pause,
40 quote,41 quote,
41 scoped_environ,42 scoped_environ,
@@ -910,6 +911,21 @@
910 args = args + ('--details',)911 args = args + ('--details',)
911 return yaml_loads(self.get_juju_output('list-resources', *args))912 return yaml_loads(self.get_juju_output('list-resources', *args))
912913
914 def wait_for_resource(self, resource_id, service_or_unit, timeout=60):
915 log.info('Waiting for resource. Resource id:{}'.format(resource_id))
916 for _ in until_timeout(timeout):
917 resources = self.list_resources(service_or_unit)['resources']
918 for resource in resources:
919 if resource['expected']['resourceid'] == resource_id:
920 if (resource['expected']['fingerprint'] ==
921 resource['unit']['fingerprint']):
922 return
923 time.sleep(.1)
924 raise JujuResourceTimeout(
925 'Timeout waiting for a resource to be downloaded. '
926 'ResourceId: {} Service or Unit: {} Timeout: {}'.format(
927 resource_id, service_or_unit, timeout))
928
913 def upgrade_charm(self, service, charm_path=None):929 def upgrade_charm(self, service, charm_path=None):
914 args = (service,)930 args = (service,)
915 if charm_path is not None:931 if charm_path is not None:
916932
=== modified file 'tests/test_assess_resources.py'
--- tests/test_assess_resources.py 2016-05-19 03:28:29 +0000
+++ tests/test_assess_resources.py 2016-05-24 22:43:31 +0000
@@ -1,10 +1,11 @@
1import copy
2import logging1import logging
2from argparse import Namespace
3from mock import Mock, patch, call3from mock import Mock, patch, call
4import StringIO4import StringIO
55
6from assess_resources import (6from assess_resources import (
7 assess_resources,7 assess_resources,
8 large_assess,
8 parse_args,9 parse_args,
9 push_resource,10 push_resource,
10 main,11 main,
@@ -57,36 +58,24 @@
57 mock_e.assert_called_once_with("an-env")58 mock_e.assert_called_once_with("an-env")
58 mock_c.assert_called_once_with(env, "/bin/juju", debug=False)59 mock_c.assert_called_once_with(env, "/bin/juju", debug=False)
59 self.assertEqual(mock_bc.call_count, 1)60 self.assertEqual(mock_bc.call_count, 1)
60 mock_assess.assert_called_once_with(client)61 mock_assess.assert_called_once_with(client, make_args())
6162
6263
63class TestAssess(TestCase):64class TestAssessResources(TestCase):
64
65 status = {'resources': [{
66 'expected': {
67 'origin': 'upload', 'used': True, 'description': 'foo resource.',
68 'username': 'admin@local', 'resourceid': 'dummy-resource/foo',
69 'name': 'foo', 'serviceid': 'dummy-resource', 'path': 'foo.txt',
70 'fingerprint': '1234', 'type': 'file', 'size': 27},
71 'unit': {
72 'origin': 'upload', 'username': 'admin@local', 'used': True,
73 'name': 'foo', 'resourceid': 'dummy-resource/foo',
74 'serviceid': 'dummy-resource', 'fingerprint': '1234',
75 'path': 'foo.txt', 'size': 27, 'type': 'file',
76 'description': 'foo resource.'}}]}
7765
78 def test_verify_status(self):66 def test_verify_status(self):
79 verify_status(self.status, 'dummy-resource/foo', 'foo', '1234', 27)67 verify_status(
68 make_resource_list(), 'dummy-resource/foo', 'foo', '1234', 27)
8069
81 def test_verify_status_exception(self):70 def test_verify_status_exception(self):
82 status = copy.deepcopy(self.status)71 status = make_resource_list()
83 status['resources'][0]['expected']['origin'] = 'charmstore'72 status['resources'][0]['expected']['origin'] = 'charmstore'
84 with self.assertRaisesRegexp(73 with self.assertRaisesRegexp(
85 JujuAssertionError, 'Unexpected resource list values'):74 JujuAssertionError, 'Unexpected resource list values'):
86 verify_status(status, 'dummy-resource/foo', 'foo', '1234', 27)75 verify_status(status, 'dummy-resource/foo', 'foo', '1234', 27)
8776
88 def test_verify_status_unit_exception(self):77 def test_verify_status_unit_exception(self):
89 status = copy.deepcopy(self.status)78 status = make_resource_list()
90 status['resources'][0]['unit']['origin'] = 'charmstore'79 status['resources'][0]['unit']['origin'] = 'charmstore'
91 with self.assertRaisesRegexp(80 with self.assertRaisesRegexp(
92 JujuAssertionError, 'Unexpected unit resource list values'):81 JujuAssertionError, 'Unexpected unit resource list values'):
@@ -95,38 +84,149 @@
95 def test_verify_status_no_resoruce_id_exception(self):84 def test_verify_status_no_resoruce_id_exception(self):
96 with self.assertRaisesRegexp(85 with self.assertRaisesRegexp(
97 JujuAssertionError, 'Resource id not found.'):86 JujuAssertionError, 'Resource id not found.'):
98 verify_status(self.status, 'NO_ID', 'foo', '1234', 27)87 verify_status(make_resource_list(), 'NO_ID', 'foo', '1234', 27)
9988
100 def test_push_resource(self):89 def test_push_resource(self):
101 mock_client = Mock(90 mock_client = Mock(
102 spec=["deploy", "wait_for_started", "list_resources"])91 spec=["deploy", "wait_for_started", "list_resources",
92 "wait_for_resource", "show_status"])
103 mock_client.version = '2.0.0'93 mock_client.version = '2.0.0'
104 mock_client.list_resources.return_value = self.status94 mock_client.list_resources.return_value = make_resource_list()
105 push_resource(mock_client, 'foo', '1234', 27)95 push_resource(mock_client, 'foo', '1234', 27, 1800, 1800)
106 mock_client.deploy.assert_called_once_with(96 mock_client.deploy.assert_called_once_with(
107 'dummy-resource', resource='foo=dummy-resource/foo.txt')97 'dummy-resource', resource='foo=dummy-resource/foo.txt')
108 mock_client.wait_for_started.assert_called_once_with()98 mock_client.wait_for_started.assert_called_once_with(timeout=1800)
99 mock_client.show_status.assert_called_once_with()
109100
110 def test_push_resource_attach(self):101 def test_push_resource_attach(self):
111 mock_client = Mock(102 mock_client = Mock(
112 spec=["attach", "wait_for_started", "list_resources"])103 spec=["attach", "wait_for_started", "list_resources",
104 "wait_for_resource", "show_status"])
113 mock_client.version = '2.0.0'105 mock_client.version = '2.0.0'
114 mock_client.list_resources.return_value = self.status106 mock_client.list_resources.return_value = make_resource_list()
115 push_resource(mock_client, 'foo', '1234', 27, deploy=False)107 push_resource(mock_client, 'foo', '1234', 27, 1800, 1800, deploy=False)
116 mock_client.attach.assert_called_once_with(108 mock_client.attach.assert_called_once_with(
117 'dummy-resource', resource='foo=dummy-resource/foo.txt')109 'dummy-resource', resource='foo=dummy-resource/foo.txt')
118 mock_client.wait_for_started.assert_called_once_with()110 mock_client.wait_for_started.assert_called_once_with(timeout=1800)
119111
120 def test_assess_resources(self):112 def test_assess_resources(self):
121 with patch("assess_resources.push_resource", autospec=True) as mock_p:113 fake_file = FakeFile()
122 assess_resources(None)114 args = make_args()
123 calls = [115 with patch("assess_resources.push_resource", autospec=True) as mock_p:
124 call(116 with patch('assess_resources.NamedTemporaryFile',
125 None, 'foo',117 autospec=True) as mock_ntf:
126 '4ddc48627c6404e538bb0957632ef68618c0839649d9ad9e41ad94472c158'118 mock_ntf.return_value.__enter__.return_value = fake_file
127 '9f4b7f9d830df6c4b209d7eb1b4b5522c4d', 27),119 assess_resources(None, args)
128 call(120 calls = [
129 None, 'bar',121 call(
130 'ffbf43d68a6960de63908bb05c14a026abeda136119d3797431bdd7b469c1'122 None, 'foo',
131 'f027e57a28aeec0df01a792e9e70aad2d6b', 17, deploy=False)]123 '4ddc48627c6404e538bb0957632ef68618c0839649d9ad9e41ad94472c158'
132 self.assertEqual(mock_p.mock_calls, calls)124 '9f4b7f9d830df6c4b209d7eb1b4b5522c4d', 27, 1800, 1800),
125 call(
126 None, 'bar',
127 'ffbf43d68a6960de63908bb05c14a026abeda136119d3797431bdd7b469c1'
128 'f027e57a28aeec0df01a792e9e70aad2d6b', 17, 1800, 1800,
129 deploy=False),
130 call(
131 None, 'bar',
132 '2a3821585efcccff1562efea4514dd860cd536441954e182a7649910e21f6'
133 'a179a015677a68a351a11d3d2f277e551e4', 27, 1800, 1800,
134 deploy=False, resource_file='baz.txt'),
135 call(
136 None, 'bar',
137 '3164673a8ac27576ab5fc06b9adc4ce0aca5bd3025384b1cf2128a8795e74'
138 '7c431e882785a0bf8dc70b42995db388575', 1024 * 1024, 1800, 1800,
139 deploy=False, resource_file='/tmp/fake'),
140 ]
141 self.assertEqual(mock_p.mock_calls, calls)
142
143 def test_assess_resources_large_test(self):
144 fake_file = FakeFile()
145 args = make_args()
146 args.large_test_enabled = True
147 with patch("assess_resources.push_resource", autospec=True) as mock_p:
148 with patch('assess_resources.fill_dummy_file',
149 autospec=True) as mock_fdf:
150 with patch('assess_resources.NamedTemporaryFile',
151 autospec=True) as mock_ntf:
152 mock_ntf.return_value.__enter__.return_value = fake_file
153 with patch('assess_resources.large_assess',
154 autospec=True) as mock_lt:
155 assess_resources(None, args)
156 calls = [
157 call(
158 None, 'foo',
159 '4ddc48627c6404e538bb0957632ef68618c0839649d9ad9e41ad94472c158'
160 '9f4b7f9d830df6c4b209d7eb1b4b5522c4d', 27, 1800, 1800),
161 call(
162 None, 'bar',
163 'ffbf43d68a6960de63908bb05c14a026abeda136119d3797431bdd7b469c1'
164 'f027e57a28aeec0df01a792e9e70aad2d6b', 17, 1800, 1800,
165 deploy=False),
166 call(
167 None, 'bar',
168 '2a3821585efcccff1562efea4514dd860cd536441954e182a7649910e21f6'
169 'a179a015677a68a351a11d3d2f277e551e4', 27, 1800, 1800,
170 deploy=False, resource_file='baz.txt'),
171 call(None, 'bar',
172 '3164673a8ac27576ab5fc06b9adc4ce0aca5bd3025384b1cf2128a8795e7'
173 '47c431e882785a0bf8dc70b42995db388575', 1024 * 1024, 1800,
174 1800, deploy=False, resource_file='/tmp/fake')]
175 self.assertEqual(mock_p.mock_calls, calls)
176 mock_fdf.assert_called_once_with('/tmp/fake', 1024 * 1024)
177 mock_lt.assert_called_once_with(None, 1800, 1800)
178
179 def test_large_tests(self):
180 fake_file = FakeFile()
181 with patch("assess_resources.push_resource", autospec=True) as mock_pr:
182 with patch('assess_resources.NamedTemporaryFile',
183 autospec=True) as mock_ntf:
184 mock_ntf.return_value.__enter__.return_value = fake_file
185 with patch('assess_resources.fill_dummy_file',
186 autospec=True):
187 large_assess(None, 1800, 1800)
188 calls = [
189 call(
190 None, 'bar',
191 'd7c014629d74ae132cc9f88e3ec2f31652f40a7a1fcc52c54b04d6c0d0891'
192 '69bcd55958d1277b4cdf6262f21c712d0a7', 1024 * 1024 * 10, 1800,
193 1800, deploy=False, resource_file='/tmp/fake'),
194 call(
195 None, 'bar',
196 'c11e93892b66de781e4d0883efe10482f8d1642f3b6574ba2ee0da6f8db03'
197 'f53c0eadfb5e5e0463574c113024ded369e', 1024 * 1024 * 100, 1800,
198 1800, deploy=False, resource_file='/tmp/fake'),
199 call(
200 None, 'bar',
201 '77db39eca74c6205e31a7701e488a1df4b9b38a527a6084bdbb6843fd430a'
202 '0b51047378ee0255e633b32c0dda3cf43ab', 1024 * 1024 * 200, 1800,
203 1800, deploy=False, resource_file='/tmp/fake')]
204 self.assertEqual(mock_pr.mock_calls, calls)
205
206
207def make_args():
208 return Namespace(
209 agent_stream=None, agent_timeout=1800, agent_url=None,
210 bootstrap_host=None, debug=False, env='an-env', juju_bin='/bin/juju',
211 keep_env=False, large_test_enabled=False, logs='/tmp/logs', machine=[],
212 region=None, resource_timeout=1800, series=None,
213 temp_env_name='an-env-mod', upload_tools=False, verbose=10)
214
215
216def make_resource_list():
217 return {'resources': [{
218 'expected': {
219 'origin': 'upload', 'used': True, 'description': 'foo resource.',
220 'username': 'admin@local', 'resourceid': 'dummy-resource/foo',
221 'name': 'foo', 'serviceid': 'dummy-resource', 'path': 'foo.txt',
222 'fingerprint': '1234', 'type': 'file', 'size': 27},
223 'unit': {
224 'origin': 'upload', 'username': 'admin@local', 'used': True,
225 'name': 'foo', 'resourceid': 'dummy-resource/foo',
226 'serviceid': 'dummy-resource', 'fingerprint': '1234',
227 'path': 'foo.txt', 'size': 27, 'type': 'file',
228 'description': 'foo resource.'}}]}
229
230
231class FakeFile:
232 name = '/tmp/fake'
133233
=== modified file 'tests/test_jujupy.py'
--- tests/test_jujupy.py 2016-05-23 03:38:07 +0000
+++ tests/test_jujupy.py 2016-05-24 22:43:31 +0000
@@ -79,7 +79,9 @@
79 TestCase,79 TestCase,
80 FakeHomeTestCase,80 FakeHomeTestCase,
81)81)
82from tests.test_assess_resources import make_resource_list
82from utility import (83from utility import (
84 JujuResourceTimeout,
83 scoped_environ,85 scoped_environ,
84 temp_dir,86 temp_dir,
85)87)
@@ -1609,6 +1611,33 @@
1609 mock_gjo.assert_called_with(1611 mock_gjo.assert_called_with(
1610 'list-resources', '--format', 'yaml', 'foo', '--details')1612 'list-resources', '--format', 'yaml', 'foo', '--details')
16111613
1614 def test_wait_for_resource(self):
1615 client = EnvJujuClient(JujuData('local'), None, None)
1616 with patch.object(
1617 client, 'list_resources',
1618 return_value=make_resource_list()) as mock_lr:
1619 client.wait_for_resource('dummy-resource/foo', 'foo')
1620 mock_lr.assert_called_once_with('foo')
1621
1622 def test_wait_for_resource_timeout(self):
1623 client = EnvJujuClient(JujuData('local'), None, None)
1624 resource_list = make_resource_list()
1625 resource_list['resources'][0]['expected']['resourceid'] = 'bad_id'
1626 with patch.object(
1627 client, 'list_resources',
1628 return_value=resource_list) as mock_lr:
1629 with patch('jujupy.until_timeout', autospec=True,
1630 return_value=[0, 1]) as mock_ju:
1631 with patch('time.sleep', autospec=True) as mock_ts:
1632 with self.assertRaisesRegexp(
1633 JujuResourceTimeout,
1634 'Timeout waiting for a resource to be downloaded'):
1635 client.wait_for_resource('dummy-resource/foo', 'foo')
1636 calls = [call('foo'), call('foo')]
1637 self.assertEqual(mock_lr.mock_calls, calls)
1638 self.assertEqual(mock_ts.mock_calls, [call(.1), call(.1)])
1639 self.assertEqual(mock_ju.mock_calls, [call(60)])
1640
1612 def test_deploy_bundle_2x(self):1641 def test_deploy_bundle_2x(self):
1613 client = EnvJujuClient(JujuData('an_env', None),1642 client = EnvJujuClient(JujuData('an_env', None),
1614 '1.23-series-arch', None)1643 '1.23-series-arch', None)
16151644
=== modified file 'utility.py'
--- utility.py 2016-05-19 03:28:29 +0000
+++ utility.py 2016-05-24 22:43:31 +0000
@@ -97,6 +97,10 @@
97 """Exception for juju assertion failures."""97 """Exception for juju assertion failures."""
9898
9999
100class JujuResourceTimeout(Exception):
101 """A timeout exception for a resource not being downloaded into a unit."""
102
103
100class enforce_juju_path(argparse.Action):104class enforce_juju_path(argparse.Action):
101 """Enforces that a path ending with juju is given."""105 """Enforces that a path ending with juju is given."""
102 def __call__(self, parser, namespace, values, option_string=None):106 def __call__(self, parser, namespace, values, option_string=None):

Subscribers

People subscribed via source and target branches