Merge lp:~veebers/juju-ci-tools/introduce-commandtime into lp:juju-ci-tools
- introduce-commandtime
- Merge into trunk
Proposed by
Christopher Lee
Status: | Merged |
---|---|
Merged at revision: | 1982 |
Proposed branch: | lp:~veebers/juju-ci-tools/introduce-commandtime |
Merge into: | lp:juju-ci-tools |
Prerequisite: | lp:~veebers/juju-ci-tools/poc-juju-ci-timing |
Diff against target: |
327 lines (+79/-24) 9 files modified
assess_container_networking.py (+1/-1) chaos.py (+3/-2) jujupy/client.py (+12/-8) jujupy/fake.py (+2/-0) jujupy/tests/test_client.py (+4/-3) jujupy/tests/test_version_client.py (+17/-7) jujupy/version_client.py (+1/-1) tests/__init__.py (+11/-0) tests/test_assess_container_networking.py (+28/-2) |
To merge this branch: | bzr merge lp:~veebers/juju-ci-tools/introduce-commandtime |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Curtis Hovey | code | Pending | |
Review via email: mp+320857@code.launchpad.net |
This proposal supersedes a proposal from 2017-03-22.
Commit message
Description of the change
Introduce CommandTime to ModelClient.juju().
This is the next step in getting CommandTime and CommandComplete introduced.
Included in this MP is an update to tests (due to the slightly different ModelClient.juju return behaviour) as well as consideration for any existing code that store the return from .juju() or any of the wrapper commands (e.g. deploy)
To post a comment you must log in.
Revision history for this message
Curtis Hovey (sinzui) wrote : Posted in a previous version of this proposal | # |
review:
Approve
(code)
Revision history for this message
Aaron Bentley (abentley) wrote : Posted in a previous version of this proposal | # |
I think maybe Chris forgot to make lp:~veebers/juju-ci-tools/poc-juju-ci-timing a prerequisite.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'assess_container_networking.py' | |||
2 | --- assess_container_networking.py 2017-02-24 18:28:04 +0000 | |||
3 | +++ assess_container_networking.py 2017-03-23 19:29:02 +0000 | |||
4 | @@ -248,7 +248,7 @@ | |||
5 | 248 | 248 | ||
6 | 249 | d = re.search(r'^default\s+via\s+([\d\.]+)\s+', routes, re.MULTILINE) | 249 | d = re.search(r'^default\s+via\s+([\d\.]+)\s+', routes, re.MULTILINE) |
7 | 250 | if d: | 250 | if d: |
9 | 251 | rc = client.juju('ssh', ('--proxy', target, | 251 | rc, _ = client.juju('ssh', ('--proxy', target, |
10 | 252 | 'ping -c1 -q ' + d.group(1)), check=False) | 252 | 'ping -c1 -q ' + d.group(1)), check=False) |
11 | 253 | if rc != 0: | 253 | if rc != 0: |
12 | 254 | raise ValueError('%s unable to ping default route' % target) | 254 | raise ValueError('%s unable to ping default route' % target) |
13 | 255 | 255 | ||
14 | === modified file 'chaos.py' | |||
15 | --- chaos.py 2016-06-27 11:41:04 +0000 | |||
16 | +++ chaos.py 2017-03-23 19:29:02 +0000 | |||
17 | @@ -146,8 +146,9 @@ | |||
18 | 146 | check_cmd += '/chaos_monkey.' + self.monkey_ids[unit_name] | 146 | check_cmd += '/chaos_monkey.' + self.monkey_ids[unit_name] |
19 | 147 | check_cmd += '/chaos_runner.lock' | 147 | check_cmd += '/chaos_runner.lock' |
20 | 148 | check_cmd += ' ]' | 148 | check_cmd += ' ]' |
23 | 149 | if self.client.juju('run', ('--unit', unit_name, check_cmd), | 149 | retvar, _ = self.client.juju( |
24 | 150 | check=False): | 150 | 'run', ('--unit', unit_name, check_cmd), check=False) |
25 | 151 | if retvar != 0: | ||
26 | 151 | return 'done' | 152 | return 'done' |
27 | 152 | return 'running' | 153 | return 'running' |
28 | 153 | 154 | ||
29 | 154 | 155 | ||
30 | === modified file 'jujupy/client.py' | |||
31 | --- jujupy/client.py 2017-03-23 19:29:02 +0000 | |||
32 | +++ jujupy/client.py 2017-03-23 19:29:02 +0000 | |||
33 | @@ -1079,7 +1079,7 @@ | |||
34 | 1079 | self.feature_flags = feature_flags | 1079 | self.feature_flags = feature_flags |
35 | 1080 | self.debug = debug | 1080 | self.debug = debug |
36 | 1081 | self._timeout_path = get_timeout_path() | 1081 | self._timeout_path = get_timeout_path() |
38 | 1082 | self.juju_timings = {} | 1082 | self.juju_timings = [] |
39 | 1083 | self.soft_deadline = soft_deadline | 1083 | self.soft_deadline = soft_deadline |
40 | 1084 | self._ignore_soft_deadline = False | 1084 | self._ignore_soft_deadline = False |
41 | 1085 | 1085 | ||
42 | @@ -1181,7 +1181,11 @@ | |||
43 | 1181 | def juju(self, command, args, used_feature_flags, | 1181 | def juju(self, command, args, used_feature_flags, |
44 | 1182 | juju_home, model=None, check=True, timeout=None, extra_env=None, | 1182 | juju_home, model=None, check=True, timeout=None, extra_env=None, |
45 | 1183 | suppress_err=False): | 1183 | suppress_err=False): |
47 | 1184 | """Run a command under juju for the current environment.""" | 1184 | """Run a command under juju for the current environment. |
48 | 1185 | |||
49 | 1186 | :return: Tuple rval, CommandTime rval being the commands exit code and | ||
50 | 1187 | a CommandTime object used for storing command timing data. | ||
51 | 1188 | """ | ||
52 | 1185 | args = self.full_args(command, args, model, timeout) | 1189 | args = self.full_args(command, args, model, timeout) |
53 | 1186 | log.info(' '.join(args)) | 1190 | log.info(' '.join(args)) |
54 | 1187 | env = self.shell_environ(used_feature_flags, juju_home) | 1191 | env = self.shell_environ(used_feature_flags, juju_home) |
55 | @@ -1191,17 +1195,17 @@ | |||
56 | 1191 | call_func = subprocess.check_call | 1195 | call_func = subprocess.check_call |
57 | 1192 | else: | 1196 | else: |
58 | 1193 | call_func = subprocess.call | 1197 | call_func = subprocess.call |
59 | 1194 | start_time = time.time() | ||
60 | 1195 | # Mutate os.environ instead of supplying env parameter so Windows can | 1198 | # Mutate os.environ instead of supplying env parameter so Windows can |
61 | 1196 | # search env['PATH'] | 1199 | # search env['PATH'] |
62 | 1197 | stderr = subprocess.PIPE if suppress_err else None | 1200 | stderr = subprocess.PIPE if suppress_err else None |
63 | 1201 | # Keep track of commands and how long the take. | ||
64 | 1202 | command_time = CommandTime(command, args, env) | ||
65 | 1198 | with scoped_environ(env): | 1203 | with scoped_environ(env): |
66 | 1199 | log.debug('Running juju with env: {}'.format(env)) | 1204 | log.debug('Running juju with env: {}'.format(env)) |
67 | 1200 | with self._check_timeouts(): | 1205 | with self._check_timeouts(): |
68 | 1201 | rval = call_func(args, stderr=stderr) | 1206 | rval = call_func(args, stderr=stderr) |
72 | 1202 | self.juju_timings.setdefault(args, []).append( | 1207 | self.juju_timings.append(command_time) |
73 | 1203 | (time.time() - start_time)) | 1208 | return rval, command_time |
71 | 1204 | return rval | ||
74 | 1205 | 1209 | ||
75 | 1206 | def expect(self, command, args, used_feature_flags, juju_home, model=None, | 1210 | def expect(self, command, args, used_feature_flags, juju_home, model=None, |
76 | 1207 | timeout=None, extra_env=None): | 1211 | timeout=None, extra_env=None): |
77 | @@ -1926,7 +1930,7 @@ | |||
78 | 1926 | '--config', config_file)) | 1930 | '--config', config_file)) |
79 | 1927 | 1931 | ||
80 | 1928 | def destroy_model(self): | 1932 | def destroy_model(self): |
82 | 1929 | exit_status = self.juju( | 1933 | exit_status, _ = self.juju( |
83 | 1930 | 'destroy-model', (self.env.environment, '-y',), | 1934 | 'destroy-model', (self.env.environment, '-y',), |
84 | 1931 | include_e=False, timeout=get_teardown_timeout(self)) | 1935 | include_e=False, timeout=get_teardown_timeout(self)) |
85 | 1932 | return exit_status | 1936 | return exit_status |
86 | @@ -1960,7 +1964,7 @@ | |||
87 | 1960 | self.destroy_controller(all_models=True) | 1964 | self.destroy_controller(all_models=True) |
88 | 1961 | except subprocess.CalledProcessError: | 1965 | except subprocess.CalledProcessError: |
89 | 1962 | logging.warning('tear_down destroy-controller failed') | 1966 | logging.warning('tear_down destroy-controller failed') |
91 | 1963 | retval = self.kill_controller() | 1967 | retval, _ = self.kill_controller() |
92 | 1964 | message = 'tear_down kill-controller result={}'.format(retval) | 1968 | message = 'tear_down kill-controller result={}'.format(retval) |
93 | 1965 | if retval == 0: | 1969 | if retval == 0: |
94 | 1966 | logging.info(message) | 1970 | logging.info(message) |
95 | 1967 | 1971 | ||
96 | === modified file 'jujupy/fake.py' | |||
97 | --- jujupy/fake.py 2017-03-17 20:43:14 +0000 | |||
98 | +++ jujupy/fake.py 2017-03-23 19:29:02 +0000 | |||
99 | @@ -19,6 +19,7 @@ | |||
100 | 19 | JujuData, | 19 | JujuData, |
101 | 20 | SoftDeadlineExceeded, | 20 | SoftDeadlineExceeded, |
102 | 21 | ) | 21 | ) |
103 | 22 | from jujupy.client import CommandTime | ||
104 | 22 | 23 | ||
105 | 23 | __metaclass__ = type | 24 | __metaclass__ = type |
106 | 24 | 25 | ||
107 | @@ -977,6 +978,7 @@ | |||
108 | 977 | self.controller_state.shares.remove(username) | 978 | self.controller_state.shares.remove(username) |
109 | 978 | if command == 'restore-backup': | 979 | if command == 'restore-backup': |
110 | 979 | model_state.restore_backup() | 980 | model_state.restore_backup() |
111 | 981 | return 0, CommandTime(command, args) | ||
112 | 980 | 982 | ||
113 | 981 | @contextmanager | 983 | @contextmanager |
114 | 982 | def juju_async(self, command, args, used_feature_flags, | 984 | def juju_async(self, command, args, used_feature_flags, |
115 | 983 | 985 | ||
116 | === modified file 'jujupy/tests/test_client.py' | |||
117 | --- jujupy/tests/test_client.py 2017-03-23 19:29:02 +0000 | |||
118 | +++ jujupy/tests/test_client.py 2017-03-23 19:29:02 +0000 | |||
119 | @@ -104,6 +104,7 @@ | |||
120 | 104 | FakeHomeTestCase, | 104 | FakeHomeTestCase, |
121 | 105 | FakePopen, | 105 | FakePopen, |
122 | 106 | observable_temp_file, | 106 | observable_temp_file, |
123 | 107 | patch_juju_call, | ||
124 | 107 | TestCase, | 108 | TestCase, |
125 | 108 | ) | 109 | ) |
126 | 109 | from jujupy.utility import ( | 110 | from jujupy.utility import ( |
127 | @@ -904,7 +905,7 @@ | |||
128 | 904 | def test_destroy_model(self): | 905 | def test_destroy_model(self): |
129 | 905 | env = JujuData('foo', {'type': 'ec2'}) | 906 | env = JujuData('foo', {'type': 'ec2'}) |
130 | 906 | client = ModelClient(env, None, None) | 907 | client = ModelClient(env, None, None) |
132 | 907 | with patch.object(client, 'juju') as mock: | 908 | with patch_juju_call(client) as mock: |
133 | 908 | client.destroy_model() | 909 | client.destroy_model() |
134 | 909 | mock.assert_called_with( | 910 | mock.assert_called_with( |
135 | 910 | 'destroy-model', ('foo', '-y'), | 911 | 'destroy-model', ('foo', '-y'), |
136 | @@ -913,7 +914,7 @@ | |||
137 | 913 | def test_destroy_model_azure(self): | 914 | def test_destroy_model_azure(self): |
138 | 914 | env = JujuData('foo', {'type': 'azure'}) | 915 | env = JujuData('foo', {'type': 'azure'}) |
139 | 915 | client = ModelClient(env, None, None) | 916 | client = ModelClient(env, None, None) |
141 | 916 | with patch.object(client, 'juju') as mock: | 917 | with patch_juju_call(client) as mock: |
142 | 917 | client.destroy_model() | 918 | client.destroy_model() |
143 | 918 | mock.assert_called_with( | 919 | mock.assert_called_with( |
144 | 919 | 'destroy-model', ('foo', '-y'), | 920 | 'destroy-model', ('foo', '-y'), |
145 | @@ -922,7 +923,7 @@ | |||
146 | 922 | def test_destroy_model_gce(self): | 923 | def test_destroy_model_gce(self): |
147 | 923 | env = JujuData('foo', {'type': 'gce'}) | 924 | env = JujuData('foo', {'type': 'gce'}) |
148 | 924 | client = ModelClient(env, None, None) | 925 | client = ModelClient(env, None, None) |
150 | 925 | with patch.object(client, 'juju') as mock: | 926 | with patch_juju_call(client) as mock: |
151 | 926 | client.destroy_model() | 927 | client.destroy_model() |
152 | 927 | mock.assert_called_with( | 928 | mock.assert_called_with( |
153 | 928 | 'destroy-model', ('foo', '-y'), | 929 | 'destroy-model', ('foo', '-y'), |
154 | 929 | 930 | ||
155 | === modified file 'jujupy/tests/test_version_client.py' | |||
156 | --- jujupy/tests/test_version_client.py 2017-03-10 21:15:12 +0000 | |||
157 | +++ jujupy/tests/test_version_client.py 2017-03-23 19:29:02 +0000 | |||
158 | @@ -573,7 +573,8 @@ | |||
159 | 573 | def test_destroy_environment(self): | 573 | def test_destroy_environment(self): |
160 | 574 | env = SimpleEnvironment('foo', {'type': 'ec2'}) | 574 | env = SimpleEnvironment('foo', {'type': 'ec2'}) |
161 | 575 | client = EnvJujuClient1X(env, None, None) | 575 | client = EnvJujuClient1X(env, None, None) |
163 | 576 | with patch.object(client, 'juju') as mock: | 576 | with patch.object( |
164 | 577 | client, 'juju', autospec=True, return_value=(0, None)) as mock: | ||
165 | 577 | client.destroy_environment() | 578 | client.destroy_environment() |
166 | 578 | mock.assert_called_with( | 579 | mock.assert_called_with( |
167 | 579 | 'destroy-environment', ('foo', '--force', '-y'), | 580 | 'destroy-environment', ('foo', '--force', '-y'), |
168 | @@ -582,7 +583,9 @@ | |||
169 | 582 | def test_destroy_environment_no_force(self): | 583 | def test_destroy_environment_no_force(self): |
170 | 583 | env = SimpleEnvironment('foo', {'type': 'ec2'}) | 584 | env = SimpleEnvironment('foo', {'type': 'ec2'}) |
171 | 584 | client = EnvJujuClient1X(env, None, None) | 585 | client = EnvJujuClient1X(env, None, None) |
173 | 585 | with patch.object(client, 'juju') as mock: | 586 | with patch.object( |
174 | 587 | client, 'juju', | ||
175 | 588 | autospec=True, return_value=(0, None)) as mock: | ||
176 | 586 | client.destroy_environment(force=False) | 589 | client.destroy_environment(force=False) |
177 | 587 | mock.assert_called_with( | 590 | mock.assert_called_with( |
178 | 588 | 'destroy-environment', ('foo', '-y'), | 591 | 'destroy-environment', ('foo', '-y'), |
179 | @@ -591,7 +594,8 @@ | |||
180 | 591 | def test_destroy_environment_azure(self): | 594 | def test_destroy_environment_azure(self): |
181 | 592 | env = SimpleEnvironment('foo', {'type': 'azure'}) | 595 | env = SimpleEnvironment('foo', {'type': 'azure'}) |
182 | 593 | client = EnvJujuClient1X(env, None, None) | 596 | client = EnvJujuClient1X(env, None, None) |
184 | 594 | with patch.object(client, 'juju') as mock: | 597 | with patch.object( |
185 | 598 | client, 'juju', autospec=True, return_value=(0, None)) as mock: | ||
186 | 595 | client.destroy_environment(force=False) | 599 | client.destroy_environment(force=False) |
187 | 596 | mock.assert_called_with( | 600 | mock.assert_called_with( |
188 | 597 | 'destroy-environment', ('foo', '-y'), | 601 | 'destroy-environment', ('foo', '-y'), |
189 | @@ -600,7 +604,9 @@ | |||
190 | 600 | def test_destroy_environment_gce(self): | 604 | def test_destroy_environment_gce(self): |
191 | 601 | env = SimpleEnvironment('foo', {'type': 'gce'}) | 605 | env = SimpleEnvironment('foo', {'type': 'gce'}) |
192 | 602 | client = EnvJujuClient1X(env, None, None) | 606 | client = EnvJujuClient1X(env, None, None) |
194 | 603 | with patch.object(client, 'juju') as mock: | 607 | with patch.object( |
195 | 608 | client, 'juju', | ||
196 | 609 | autospec=True, return_value=(0, None)) as mock: | ||
197 | 604 | client.destroy_environment(force=False) | 610 | client.destroy_environment(force=False) |
198 | 605 | mock.assert_called_with( | 611 | mock.assert_called_with( |
199 | 606 | 'destroy-environment', ('foo', '-y'), | 612 | 'destroy-environment', ('foo', '-y'), |
200 | @@ -609,7 +615,8 @@ | |||
201 | 609 | def test_destroy_environment_delete_jenv(self): | 615 | def test_destroy_environment_delete_jenv(self): |
202 | 610 | env = SimpleEnvironment('foo', {'type': 'ec2'}) | 616 | env = SimpleEnvironment('foo', {'type': 'ec2'}) |
203 | 611 | client = EnvJujuClient1X(env, None, None) | 617 | client = EnvJujuClient1X(env, None, None) |
205 | 612 | with patch.object(client, 'juju'): | 618 | with patch.object( |
206 | 619 | client, 'juju', autospec=True, return_value=(0, None)): | ||
207 | 613 | with temp_env({}) as juju_home: | 620 | with temp_env({}) as juju_home: |
208 | 614 | client.env.juju_home = juju_home | 621 | client.env.juju_home = juju_home |
209 | 615 | jenv_path = get_jenv_path(juju_home, 'foo') | 622 | jenv_path = get_jenv_path(juju_home, 'foo') |
210 | @@ -622,7 +629,8 @@ | |||
211 | 622 | def test_destroy_model(self): | 629 | def test_destroy_model(self): |
212 | 623 | env = SimpleEnvironment('foo', {'type': 'ec2'}) | 630 | env = SimpleEnvironment('foo', {'type': 'ec2'}) |
213 | 624 | client = EnvJujuClient1X(env, None, None) | 631 | client = EnvJujuClient1X(env, None, None) |
215 | 625 | with patch.object(client, 'juju') as mock: | 632 | with patch.object( |
216 | 633 | client, 'juju', autospec=True, return_value=(0, None)) as mock: | ||
217 | 626 | client.destroy_model() | 634 | client.destroy_model() |
218 | 627 | mock.assert_called_with( | 635 | mock.assert_called_with( |
219 | 628 | 'destroy-environment', ('foo', '-y'), | 636 | 'destroy-environment', ('foo', '-y'), |
220 | @@ -631,7 +639,9 @@ | |||
221 | 631 | def test_kill_controller(self): | 639 | def test_kill_controller(self): |
222 | 632 | client = EnvJujuClient1X( | 640 | client = EnvJujuClient1X( |
223 | 633 | SimpleEnvironment('foo', {'type': 'ec2'}), None, None) | 641 | SimpleEnvironment('foo', {'type': 'ec2'}), None, None) |
225 | 634 | with patch.object(client, 'juju') as juju_mock: | 642 | with patch.object( |
226 | 643 | client, 'juju', | ||
227 | 644 | autospec=True, return_value=(0, None)) as juju_mock: | ||
228 | 635 | client.kill_controller() | 645 | client.kill_controller() |
229 | 636 | juju_mock.assert_called_once_with( | 646 | juju_mock.assert_called_once_with( |
230 | 637 | 'destroy-environment', ('foo', '--force', '-y'), check=False, | 647 | 'destroy-environment', ('foo', '--force', '-y'), check=False, |
231 | 638 | 648 | ||
232 | === modified file 'jujupy/version_client.py' | |||
233 | --- jujupy/version_client.py 2017-03-10 19:54:30 +0000 | |||
234 | +++ jujupy/version_client.py 2017-03-23 19:29:02 +0000 | |||
235 | @@ -498,7 +498,7 @@ | |||
236 | 498 | force_arg = ('--force',) | 498 | force_arg = ('--force',) |
237 | 499 | else: | 499 | else: |
238 | 500 | force_arg = () | 500 | force_arg = () |
240 | 501 | exit_status = self.juju( | 501 | exit_status, _ = self.juju( |
241 | 502 | 'destroy-environment', | 502 | 'destroy-environment', |
242 | 503 | (self.env.environment,) + force_arg + ('-y',), | 503 | (self.env.environment,) + force_arg + ('-y',), |
243 | 504 | check=False, include_e=False, | 504 | check=False, include_e=False, |
244 | 505 | 505 | ||
245 | === modified file 'tests/__init__.py' | |||
246 | --- tests/__init__.py 2017-03-10 19:46:30 +0000 | |||
247 | +++ tests/__init__.py 2017-03-23 19:29:02 +0000 | |||
248 | @@ -152,6 +152,17 @@ | |||
249 | 152 | os.environ[key] = org_value | 152 | os.environ[key] = org_value |
250 | 153 | 153 | ||
251 | 154 | 154 | ||
252 | 155 | @contextmanager | ||
253 | 156 | def patch_juju_call(client, return_value=(0, None)): | ||
254 | 157 | """Simple patch for client.juju call. | ||
255 | 158 | |||
256 | 159 | :param return_value: A tuple to return representing the retvar and | ||
257 | 160 | CommandTime object | ||
258 | 161 | """ | ||
259 | 162 | with patch.object(client, 'juju', return_value=return_value) as mock: | ||
260 | 163 | yield mock | ||
261 | 164 | |||
262 | 165 | |||
263 | 155 | def assert_juju_call(test_case, mock_method, client, expected_args, | 166 | def assert_juju_call(test_case, mock_method, client, expected_args, |
264 | 156 | call_index=None): | 167 | call_index=None): |
265 | 157 | """Check a mock's positional arguments. | 168 | """Check a mock's positional arguments. |
266 | 158 | 169 | ||
267 | === modified file 'tests/test_assess_container_networking.py' | |||
268 | --- tests/test_assess_container_networking.py 2017-01-20 20:58:41 +0000 | |||
269 | +++ tests/test_assess_container_networking.py 2017-03-23 19:29:02 +0000 | |||
270 | @@ -17,6 +17,7 @@ | |||
271 | 17 | LXD_MACHINE, | 17 | LXD_MACHINE, |
272 | 18 | SimpleEnvironment, | 18 | SimpleEnvironment, |
273 | 19 | ) | 19 | ) |
274 | 20 | from jujupy.client import CommandTime | ||
275 | 20 | 21 | ||
276 | 21 | import assess_container_networking as jcnet | 22 | import assess_container_networking as jcnet |
277 | 22 | from tests import ( | 23 | from tests import ( |
278 | @@ -78,6 +79,29 @@ | |||
279 | 78 | if cmd != 'bootstrap': | 79 | if cmd != 'bootstrap': |
280 | 79 | self.commands.append((cmd, args)) | 80 | self.commands.append((cmd, args)) |
281 | 80 | if cmd == 'ssh': | 81 | if cmd == 'ssh': |
282 | 82 | ct = CommandTime(cmd, args) | ||
283 | 83 | if len(self._ssh_output) == 0: | ||
284 | 84 | return "", ct | ||
285 | 85 | |||
286 | 86 | try: | ||
287 | 87 | ct = CommandTime(cmd, args) | ||
288 | 88 | return self._ssh_output[self._call_number()], ct | ||
289 | 89 | except IndexError: | ||
290 | 90 | # If we ran out of values, just return the last one | ||
291 | 91 | return self._ssh_output[-1], ct | ||
292 | 92 | else: | ||
293 | 93 | return super(JujuMock, self).juju(cmd, *rargs, **kwargs) | ||
294 | 94 | |||
295 | 95 | def get_juju_output(self, cmd, *rargs, **kwargs): | ||
296 | 96 | # Almost exactly like juju() except get_juju_output doesn't return | ||
297 | 97 | # a CommandTime | ||
298 | 98 | if len(rargs) == 1: | ||
299 | 99 | args = rargs[0] | ||
300 | 100 | else: | ||
301 | 101 | args = rargs | ||
302 | 102 | if cmd != 'bootstrap': | ||
303 | 103 | self.commands.append((cmd, args)) | ||
304 | 104 | if cmd == 'ssh': | ||
305 | 81 | if len(self._ssh_output) == 0: | 105 | if len(self._ssh_output) == 0: |
306 | 82 | return "" | 106 | return "" |
307 | 83 | 107 | ||
308 | @@ -87,7 +111,7 @@ | |||
309 | 87 | # If we ran out of values, just return the last one | 111 | # If we ran out of values, just return the last one |
310 | 88 | return self._ssh_output[-1] | 112 | return self._ssh_output[-1] |
311 | 89 | else: | 113 | else: |
313 | 90 | return super(JujuMock, self).juju(cmd, *rargs, **kwargs) | 114 | return super(JujuMock, self).get_juju_output(cmd, *rargs, **kwargs) |
314 | 91 | 115 | ||
315 | 92 | def _call_number(self): | 116 | def _call_number(self): |
316 | 93 | call_number = self._call_n | 117 | call_number = self._call_n |
317 | @@ -117,7 +141,9 @@ | |||
318 | 117 | patch.object(self.client, 'wait_for', lambda *args, **kw: None), | 141 | patch.object(self.client, 'wait_for', lambda *args, **kw: None), |
319 | 118 | patch.object(self.client, 'wait_for_started', | 142 | patch.object(self.client, 'wait_for_started', |
320 | 119 | self.juju_mock.get_status), | 143 | self.juju_mock.get_status), |
322 | 120 | patch.object(self.client, 'get_juju_output', self.juju_mock.juju), | 144 | patch.object( |
323 | 145 | self.client, 'get_juju_output', | ||
324 | 146 | self.juju_mock.get_juju_output), | ||
325 | 121 | ] | 147 | ] |
326 | 122 | 148 | ||
327 | 123 | for patcher in patches: | 149 | for patcher in patches: |
Thank you. I don't like the name actual_completion() I have some ideas inline. I leave it to you to decide the name you like. I also have a suggestion for a a test.