Merge lp:~marcoceppi/charm-tools/substrate-cfg into lp:charm-tools/1.2
- substrate-cfg
- Merge into 1.2
Proposed by
Marco Ceppi
Status: | Merged |
---|---|
Merged at revision: | 287 |
Proposed branch: | lp:~marcoceppi/charm-tools/substrate-cfg |
Merge into: | lp:charm-tools/1.2 |
Diff against target: |
438 lines (+187/-37) 7 files modified
.bzrignore (+2/-0) charmtools/bundles.py (+0/-1) charmtools/generate.py (+0/-1) charmtools/test.py (+109/-26) charmtools/update.py (+2/-0) tests/test_juju_test.py (+12/-9) tests/test_substrates.py (+62/-0) |
To merge this branch: | bzr merge lp:~marcoceppi/charm-tools/substrate-cfg |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
charmers | Pending | ||
Review via email: mp+201094@code.launchpad.net |
Commit message
Description of the change
Add substrate configuration to juju-test
To post a comment you must log in.
Revision history for this message
Marco Ceppi (marcoceppi) wrote : | # |
Revision history for this message
Benjamin Saller (bcsaller) wrote : | # |
LGTM
Thanks for including my suggestions (and making the actual integration
work). The changes to using a key whitelist in TestCfg are also good.
Revision history for this message
Marco Ceppi (marcoceppi) wrote : | # |
*** Submitted:
Add substrate configuration to juju-test
R=benjamin.saller
CC=
https:/
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file '.bzrignore' | |||
2 | --- .bzrignore 2013-12-16 16:12:29 +0000 | |||
3 | +++ .bzrignore 2014-01-09 20:17:53 +0000 | |||
4 | @@ -9,3 +9,5 @@ | |||
5 | 9 | lib | 9 | lib |
6 | 10 | local | 10 | local |
7 | 11 | man | 11 | man |
8 | 12 | tests/.ropeproject/ | ||
9 | 13 | charmtools/.ropeproject/ | ||
10 | 12 | 14 | ||
11 | === modified file 'charmtools/bundles.py' | |||
12 | --- charmtools/bundles.py 2013-12-20 14:06:43 +0000 | |||
13 | +++ charmtools/bundles.py 2014-01-09 20:17:53 +0000 | |||
14 | @@ -2,7 +2,6 @@ | |||
15 | 2 | import yaml | 2 | import yaml |
16 | 3 | import glob | 3 | import glob |
17 | 4 | import json | 4 | import json |
18 | 5 | import requests | ||
19 | 6 | 5 | ||
20 | 7 | from linter import Linter | 6 | from linter import Linter |
21 | 8 | from charmworldlib import bundle as cw_bundle | 7 | from charmworldlib import bundle as cw_bundle |
22 | 9 | 8 | ||
23 | === modified file 'charmtools/generate.py' | |||
24 | --- charmtools/generate.py 2013-12-12 17:20:39 +0000 | |||
25 | +++ charmtools/generate.py 2014-01-09 20:17:53 +0000 | |||
26 | @@ -16,7 +16,6 @@ | |||
27 | 16 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | 16 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
28 | 17 | 17 | ||
29 | 18 | import os | 18 | import os |
30 | 19 | import sys | ||
31 | 20 | import shutil | 19 | import shutil |
32 | 21 | import argparse | 20 | import argparse |
33 | 22 | 21 | ||
34 | 23 | 22 | ||
35 | === modified file 'charmtools/test.py' | |||
36 | --- charmtools/test.py 2013-12-21 12:59:08 +0000 | |||
37 | +++ charmtools/test.py 2014-01-09 20:17:53 +0000 | |||
38 | @@ -1,18 +1,16 @@ | |||
39 | 1 | #!/usr/bin/python | 1 | #!/usr/bin/python |
40 | 2 | # coding=latin-1 | 2 | # coding=latin-1 |
41 | 3 | 3 | ||
42 | 4 | import argparse | ||
43 | 5 | import glob | ||
44 | 6 | import logging | ||
45 | 4 | import os | 7 | import os |
46 | 8 | import re | ||
47 | 9 | import signal | ||
48 | 10 | import subprocess | ||
49 | 5 | import sys | 11 | import sys |
51 | 6 | import uuid | 12 | import time |
52 | 7 | import yaml | 13 | import yaml |
53 | 8 | import time | ||
54 | 9 | import glob | ||
55 | 10 | import signal | ||
56 | 11 | import logging | ||
57 | 12 | import argparse | ||
58 | 13 | import subprocess | ||
59 | 14 | |||
60 | 15 | from tempfile import mkdtemp | ||
61 | 16 | from datetime import timedelta | 14 | from datetime import timedelta |
62 | 17 | from contextlib import contextmanager | 15 | from contextlib import contextmanager |
63 | 18 | 16 | ||
64 | @@ -44,6 +42,10 @@ | |||
65 | 44 | pass | 42 | pass |
66 | 45 | 43 | ||
67 | 46 | 44 | ||
68 | 45 | class SubstrateMismatch(Exception): | ||
69 | 46 | pass | ||
70 | 47 | |||
71 | 48 | |||
72 | 47 | class TimeoutError(Exception): | 49 | class TimeoutError(Exception): |
73 | 48 | def __init__(self, value="Timed Out"): | 50 | def __init__(self, value="Timed Out"): |
74 | 49 | self.value = value | 51 | self.value = value |
75 | @@ -114,7 +116,7 @@ | |||
76 | 114 | self.destroy(self.juju_env) | 116 | self.destroy(self.juju_env) |
77 | 115 | except DestroyUnreliable: | 117 | except DestroyUnreliable: |
78 | 116 | self.log.warn('Unable to destroy bootstrap, trying again') | 118 | self.log.warn('Unable to destroy bootstrap, trying again') |
80 | 117 | sleep(2) | 119 | time.sleep(2) |
81 | 118 | try: | 120 | try: |
82 | 119 | self.destroy(self.juju_env) | 121 | self.destroy(self.juju_env) |
83 | 120 | except: | 122 | except: |
84 | @@ -258,6 +260,7 @@ | |||
85 | 258 | try: | 260 | try: |
86 | 259 | with timeout(self.conductor.args.timeout): | 261 | with timeout(self.conductor.args.timeout): |
87 | 260 | output = subprocess.check_output(self.test, env=self.env) | 262 | output = subprocess.check_output(self.test, env=self.env) |
88 | 263 | self.log.debug(output) | ||
89 | 261 | except TimeoutError, e: | 264 | except TimeoutError, e: |
90 | 262 | self.log.debug('Killed by timeout after %s seconds', | 265 | self.log.debug('Killed by timeout after %s seconds', |
91 | 263 | self.conductor.args.timeout) | 266 | self.conductor.args.timeout) |
92 | @@ -279,7 +282,7 @@ | |||
93 | 279 | try: | 282 | try: |
94 | 280 | self.archive_logs() | 283 | self.archive_logs() |
95 | 281 | except OrchestraError, e: | 284 | except OrchestraError, e: |
97 | 282 | juju.log.error(e) | 285 | self.log.error(e) |
98 | 283 | 286 | ||
99 | 284 | if error: | 287 | if error: |
100 | 285 | raise error | 288 | raise error |
101 | @@ -293,7 +296,7 @@ | |||
102 | 293 | raise OrchestraError('Unable to query juju status') | 296 | raise OrchestraError('Unable to query juju status') |
103 | 294 | 297 | ||
104 | 295 | services = status['services'] | 298 | services = status['services'] |
106 | 296 | machines = status['machines'] | 299 | # machines = status['machines'] |
107 | 297 | 300 | ||
108 | 298 | if self.conductor.juju_version.major == 0: | 301 | if self.conductor.juju_version.major == 0: |
109 | 299 | logs.append('/var/lib/juju/units/./*/charm.log') | 302 | logs.append('/var/lib/juju/units/./*/charm.log') |
110 | @@ -395,16 +398,16 @@ | |||
111 | 395 | class TestCfg(object): | 398 | class TestCfg(object): |
112 | 396 | _keys = ['timeout', 'set-e', 'on-timeout', 'fail-on-skip', 'tests'] | 399 | _keys = ['timeout', 'set-e', 'on-timeout', 'fail-on-skip', 'tests'] |
113 | 397 | 400 | ||
124 | 398 | def __init__(self, config_file): | 401 | def __init__(self, cfg): |
125 | 399 | if not os.path.exists(config_file): | 402 | if isinstance(cfg, basestring): |
126 | 400 | raise OSError("%s not found" % config_file) | 403 | cfg = yaml.safe_load(cfg) |
127 | 401 | 404 | ||
128 | 402 | with open(config_file) as f: | 405 | if 'options' in cfg: |
129 | 403 | cfg = yaml.safe_load(f.read()) | 406 | for key, val in cfg['options'].iteritems(): |
130 | 404 | 407 | if key in self._keys: | |
131 | 405 | for key, val in cfg['options'].iteritems(): | 408 | setattr(self, key, val) |
132 | 406 | if key in self._keys: | 409 | if 'substrates' in cfg: |
133 | 407 | setattr(self, key, val) | 410 | self.substrates = cfg.substrates |
134 | 408 | 411 | ||
135 | 409 | 412 | ||
136 | 410 | def get_juju_version(): | 413 | def get_juju_version(): |
137 | @@ -455,6 +458,71 @@ | |||
138 | 455 | return logger | 458 | return logger |
139 | 456 | 459 | ||
140 | 457 | 460 | ||
141 | 461 | class SubstrateFilter(object): | ||
142 | 462 | def __init__(self, spec): | ||
143 | 463 | self.order = spec.get('order', ['include', 'skip']) | ||
144 | 464 | self.include = spec.get('include', ['*']) | ||
145 | 465 | self.skip = spec.get('skip', []) | ||
146 | 466 | |||
147 | 467 | if isinstance(self.order, str): | ||
148 | 468 | self.order = [s.strip() for s in self.order.split(',')] | ||
149 | 469 | if self.order != ['include', 'skip'] and \ | ||
150 | 470 | self.order != ['skip', 'include']: | ||
151 | 471 | raise ValueError( | ||
152 | 472 | 'order should be defined using only include and skip') | ||
153 | 473 | |||
154 | 474 | if isinstance(self.include, str): | ||
155 | 475 | self.include = [self.include] | ||
156 | 476 | self.include = set(self.include) | ||
157 | 477 | |||
158 | 478 | if isinstance(self.skip, str): | ||
159 | 479 | self.skip = [self.skip] | ||
160 | 480 | self.skip = set(self.skip) | ||
161 | 481 | |||
162 | 482 | def filter(self, substrates): | ||
163 | 483 | """ | ||
164 | 484 | Filter a list of substrates relative to the rules generated on class | ||
165 | 485 | creation. | ||
166 | 486 | """ | ||
167 | 487 | if isinstance(substrates, str): | ||
168 | 488 | substrates = [s.strip() for s in re.split('[,\s]', substrates)] | ||
169 | 489 | |||
170 | 490 | # Apply the rules to the list of substrates returning anything that | ||
171 | 491 | # matches | ||
172 | 492 | if self.order == ['include', 'skip']: | ||
173 | 493 | result = self._filter_includes(substrates, True) | ||
174 | 494 | result = self._filter_skips(result) | ||
175 | 495 | else: | ||
176 | 496 | result = self._filter_skips(substrates, True) | ||
177 | 497 | result = self._filter_includes(result) | ||
178 | 498 | return result | ||
179 | 499 | |||
180 | 500 | def _filter_includes(self, inputList, priority=False): | ||
181 | 501 | if priority and '*' in self.include: | ||
182 | 502 | return inputList | ||
183 | 503 | return sorted(list(set(inputList).intersection(self.include))) | ||
184 | 504 | |||
185 | 505 | def _filter_skips(self, inputList, priority=False): | ||
186 | 506 | if priority and '*' in self.skip: | ||
187 | 507 | return list(self.include.intersection(inputList)) | ||
188 | 508 | return sorted(list(set(inputList).difference(self.skip))) | ||
189 | 509 | |||
190 | 510 | |||
191 | 511 | def parse_substrates(spec): | ||
192 | 512 | if isinstance(spec, basestring): | ||
193 | 513 | spec = yaml.safe_load(spec) | ||
194 | 514 | if not spec or 'substrates' not in spec: | ||
195 | 515 | raise ValueError( | ||
196 | 516 | "Invalid data passed to parse_substrates: {}".format(spec)) | ||
197 | 517 | |||
198 | 518 | specRules = SubstrateFilter(spec['substrates']) | ||
199 | 519 | return specRules | ||
200 | 520 | |||
201 | 521 | |||
202 | 522 | def allowed_substrates(spec, possible_substrates): | ||
203 | 523 | return parse_substrates(spec).filter(possible_substrates) | ||
204 | 524 | |||
205 | 525 | |||
206 | 458 | def setup_parser(): | 526 | def setup_parser(): |
207 | 459 | parser = argparse.ArgumentParser( | 527 | parser = argparse.ArgumentParser( |
208 | 460 | prog='juju test', | 528 | prog='juju test', |
209 | @@ -564,10 +632,14 @@ | |||
210 | 564 | logger.info('Starting test run on %s using Juju %s' | 632 | logger.info('Starting test run on %s using Juju %s' |
211 | 565 | % (args.juju_env, get_juju_version())) | 633 | % (args.juju_env, get_juju_version())) |
212 | 566 | logger.debug('Loading configuration options from testplan YAML') | 634 | logger.debug('Loading configuration options from testplan YAML') |
217 | 567 | test_plans = glob.glob(os.path.join(os.getcwd(), 'tests', 'testplan.y*ml')) | 635 | test_plans = glob.glob(os.path.join(os.getcwd(), 'tests', |
218 | 568 | test_plan = test_plan[0] if test_plans else None | 636 | 'test_config.y*ml')) |
219 | 569 | if test_plan: | 637 | if test_plans: |
220 | 570 | cfg = TestCfg(test_plan) | 638 | with open(test_plans[0]) as f: |
221 | 639 | test_cfg = f.read() | ||
222 | 640 | |||
223 | 641 | if test_cfg: | ||
224 | 642 | cfg = TestCfg(test_cfg) | ||
225 | 571 | for key, val in args.iteritems(): | 643 | for key, val in args.iteritems(): |
226 | 572 | logger.debug('Overwriting %s to %s from cmd' % (key, val)) | 644 | logger.debug('Overwriting %s to %s from cmd' % (key, val)) |
227 | 573 | setattr(cfg, key, val) | 645 | setattr(cfg, key, val) |
228 | @@ -577,10 +649,21 @@ | |||
229 | 577 | logger.debug('Creating a new Conductor') | 649 | logger.debug('Creating a new Conductor') |
230 | 578 | try: | 650 | try: |
231 | 579 | tester = Conductor(args) | 651 | tester = Conductor(args) |
232 | 652 | env_yaml = tester.get_environment(cfg.juju_env) | ||
233 | 653 | if 'substrates' in cfg: | ||
234 | 654 | rules = parse_substrates(cfg) | ||
235 | 655 | allowed = rules.filter(env_yaml['type']) | ||
236 | 656 | if env_yaml['type'] not in allowed: | ||
237 | 657 | raise Exception('%s is not an allowed substrate: %s' % | ||
238 | 658 | (env_yaml['type'], | ||
239 | 659 | allowed.join(', '))) | ||
240 | 580 | errors, failures, passes = tester.run() | 660 | errors, failures, passes = tester.run() |
241 | 581 | except NoTests: | 661 | except NoTests: |
242 | 582 | logger.critical('No tests were found') | 662 | logger.critical('No tests were found') |
243 | 583 | sys.exit(1) | 663 | sys.exit(1) |
244 | 664 | except Exception as e: | ||
245 | 665 | logger.critical(str(e)) | ||
246 | 666 | sys.exit(1) | ||
247 | 584 | except: | 667 | except: |
248 | 585 | raise | 668 | raise |
249 | 586 | 669 | ||
250 | 587 | 670 | ||
251 | === modified file 'charmtools/update.py' | |||
252 | --- charmtools/update.py 2013-12-16 16:12:29 +0000 | |||
253 | +++ charmtools/update.py 2014-01-09 20:17:53 +0000 | |||
254 | @@ -34,6 +34,7 @@ | |||
255 | 34 | 34 | ||
256 | 35 | return parser | 35 | return parser |
257 | 36 | 36 | ||
258 | 37 | |||
259 | 37 | def update(charm_dir, fix=False): | 38 | def update(charm_dir, fix=False): |
260 | 38 | mr = Mr(charm_dir) | 39 | mr = Mr(charm_dir) |
261 | 39 | for charm in charms.remote(): | 40 | for charm in charms.remote(): |
262 | @@ -48,6 +49,7 @@ | |||
263 | 48 | except Exception as e: | 49 | except Exception as e: |
264 | 49 | raise Exception(".mrconfig not saved: %s" % e.strerror) | 50 | raise Exception(".mrconfig not saved: %s" % e.strerror) |
265 | 50 | 51 | ||
266 | 52 | |||
267 | 51 | def main(): | 53 | def main(): |
268 | 52 | parser = setup_parser() | 54 | parser = setup_parser() |
269 | 53 | args = parser.parse_args() | 55 | args = parser.parse_args() |
270 | 54 | 56 | ||
271 | === modified file 'tests/test_juju_test.py' | |||
272 | --- tests/test_juju_test.py 2013-12-20 12:33:21 +0000 | |||
273 | +++ tests/test_juju_test.py 2014-01-09 20:17:53 +0000 | |||
274 | @@ -30,13 +30,16 @@ | |||
275 | 30 | 30 | ||
276 | 31 | PARSED_ENVIRONMENTS_YAML = yaml.safe_load(RAW_ENVIRONMENTS_YAML) | 31 | PARSED_ENVIRONMENTS_YAML = yaml.safe_load(RAW_ENVIRONMENTS_YAML) |
277 | 32 | 32 | ||
278 | 33 | |||
279 | 33 | class Arguments(object): | 34 | class Arguments(object): |
280 | 34 | def __init__(self, **kwargs): | 35 | def __init__(self, **kwargs): |
281 | 35 | for key, value in kwargs.items(): | 36 | for key, value in kwargs.items(): |
282 | 36 | setattr(self, key, value) | 37 | setattr(self, key, value) |
283 | 38 | |||
284 | 37 | def __getattr__(self, name): | 39 | def __getattr__(self, name): |
285 | 38 | return None | 40 | return None |
286 | 39 | 41 | ||
287 | 42 | |||
288 | 40 | class JujuTestPluginTest(unittest.TestCase): | 43 | class JujuTestPluginTest(unittest.TestCase): |
289 | 41 | @patch('subprocess.check_output') | 44 | @patch('subprocess.check_output') |
290 | 42 | def test_get_gojuju_version(self, mock_check_output): | 45 | def test_get_gojuju_version(self, mock_check_output): |
291 | @@ -77,7 +80,7 @@ | |||
292 | 77 | self.assertEqual(100, juju_test.convert_to_timedelta('100s')) | 80 | self.assertEqual(100, juju_test.convert_to_timedelta('100s')) |
293 | 78 | self.assertEqual(100, juju_test.convert_to_timedelta(100)) | 81 | self.assertEqual(100, juju_test.convert_to_timedelta(100)) |
294 | 79 | self.assertEqual(60, juju_test.convert_to_timedelta('1m')) | 82 | self.assertEqual(60, juju_test.convert_to_timedelta('1m')) |
296 | 80 | self.assertEqual(60*60, juju_test.convert_to_timedelta('1h')) | 83 | self.assertEqual(60 * 60, juju_test.convert_to_timedelta('1h')) |
297 | 81 | 84 | ||
298 | 82 | @patch('glob.glob') | 85 | @patch('glob.glob') |
299 | 83 | @patch('os.path.isfile') | 86 | @patch('os.path.isfile') |
300 | @@ -89,7 +92,7 @@ | |||
301 | 89 | mock_isfile.side_effect = files_exist | 92 | mock_isfile.side_effect = files_exist |
302 | 90 | mock_glob.return_value = tests_directory | 93 | mock_glob.return_value = tests_directory |
303 | 91 | 94 | ||
305 | 92 | args = Arguments(tests = 'dummy') | 95 | args = Arguments(tests='dummy') |
306 | 93 | c = juju_test.Conductor(args) | 96 | c = juju_test.Conductor(args) |
307 | 94 | results = c.find_tests() | 97 | results = c.find_tests() |
308 | 95 | 98 | ||
309 | @@ -100,7 +103,7 @@ | |||
310 | 100 | def test_conductor_find_tests_fails(self, mock_glob): | 103 | def test_conductor_find_tests_fails(self, mock_glob): |
311 | 101 | mock_glob.return_value = [] | 104 | mock_glob.return_value = [] |
312 | 102 | 105 | ||
314 | 103 | args = Arguments(tests = 'dummy') | 106 | args = Arguments(tests='dummy') |
315 | 104 | c = juju_test.Conductor(args) | 107 | c = juju_test.Conductor(args) |
316 | 105 | results = c.find_tests() | 108 | results = c.find_tests() |
317 | 106 | 109 | ||
318 | @@ -126,7 +129,7 @@ | |||
319 | 126 | 129 | ||
320 | 127 | mcheck_output.side_effect = [yml_output, Exception('not bootstrapped')] | 130 | mcheck_output.side_effect = [yml_output, Exception('not bootstrapped')] |
321 | 128 | juju_env = 'test' | 131 | juju_env = 'test' |
323 | 129 | args = Arguments(tests = 'dummy') | 132 | args = Arguments(tests='dummy') |
324 | 130 | c = juju_test.Conductor(args) | 133 | c = juju_test.Conductor(args) |
325 | 131 | results = c.status(juju_env) | 134 | results = c.status(juju_env) |
326 | 132 | 135 | ||
327 | @@ -193,7 +196,7 @@ | |||
328 | 193 | 196 | ||
329 | 194 | @patch('subprocess.check_call') | 197 | @patch('subprocess.check_call') |
330 | 195 | def test_conductor_destroy(self, mock_check_call): | 198 | def test_conductor_destroy(self, mock_check_call): |
332 | 196 | args = Arguments(tests = 'dummy') | 199 | args = Arguments(tests='dummy') |
333 | 197 | c = juju_test.Conductor(args) | 200 | c = juju_test.Conductor(args) |
334 | 198 | c.juju_version = juju_test.JujuVersion(major=1, minor=1, patch=1) | 201 | c.juju_version = juju_test.JujuVersion(major=1, minor=1, patch=1) |
335 | 199 | good_env = 'valid' | 202 | good_env = 'valid' |
336 | @@ -216,7 +219,7 @@ | |||
337 | 216 | 219 | ||
338 | 217 | bad_env = 'invalid' | 220 | bad_env = 'invalid' |
339 | 218 | 221 | ||
341 | 219 | args = Arguments(tests = 'dummy') | 222 | args = Arguments(tests='dummy') |
342 | 220 | c = juju_test.Conductor(args) | 223 | c = juju_test.Conductor(args) |
343 | 221 | c.juju_version = juju_test.JujuVersion(major=1, minor=8, patch=0) | 224 | c.juju_version = juju_test.JujuVersion(major=1, minor=8, patch=0) |
344 | 222 | self.assertRaises(juju_test.DestroyUnreliable, c.destroy, bad_env) | 225 | self.assertRaises(juju_test.DestroyUnreliable, c.destroy, bad_env) |
345 | @@ -448,7 +451,7 @@ | |||
346 | 448 | o.log.status.assert_called_with('%s (%s)' % (juju_test.TEST_FAIL, | 451 | o.log.status.assert_called_with('%s (%s)' % (juju_test.TEST_FAIL, |
347 | 449 | juju_test.TEST_TIMEOUT)) | 452 | juju_test.TEST_TIMEOUT)) |
348 | 450 | 453 | ||
350 | 451 | o.conductor.args.on_timeout='skip' | 454 | o.conductor.args.on_timeout = 'skip' |
351 | 452 | o.log.status.reset_mock() | 455 | o.log.status.reset_mock() |
352 | 453 | o.print_status(124) | 456 | o.print_status(124) |
353 | 454 | o.log.status.assert_called_with('%s (%s)' % (juju_test.TEST_FAIL, | 457 | o.log.status.assert_called_with('%s (%s)' % (juju_test.TEST_FAIL, |
354 | @@ -583,7 +586,7 @@ | |||
355 | 583 | goyml_parsed = yaml.safe_load(goyml_output) | 586 | goyml_parsed = yaml.safe_load(goyml_output) |
356 | 584 | mstatus.return_value = goyml_parsed | 587 | mstatus.return_value = goyml_parsed |
357 | 585 | 588 | ||
359 | 586 | juju_env='testing' | 589 | juju_env = 'testing' |
360 | 587 | args = Arguments(tests='dummy', juju_env=juju_env, logdir='/tmp') | 590 | args = Arguments(tests='dummy', juju_env=juju_env, logdir='/tmp') |
361 | 588 | c = juju_test.Conductor(args) | 591 | c = juju_test.Conductor(args) |
362 | 589 | c.juju_version = juju_test.JujuVersion(major=1, minor=10, patch=0) | 592 | c.juju_version = juju_test.JujuVersion(major=1, minor=10, patch=0) |
363 | @@ -623,7 +626,7 @@ | |||
364 | 623 | pyyml_parsed = yaml.safe_load(pyyml_output) | 626 | pyyml_parsed = yaml.safe_load(pyyml_output) |
365 | 624 | mstatus.return_value = pyyml_parsed | 627 | mstatus.return_value = pyyml_parsed |
366 | 625 | 628 | ||
368 | 626 | juju_env='testing' | 629 | juju_env = 'testing' |
369 | 627 | args = Arguments(tests='dummy', juju_env=juju_env, logdir='/tmp') | 630 | args = Arguments(tests='dummy', juju_env=juju_env, logdir='/tmp') |
370 | 628 | c = juju_test.Conductor(args) | 631 | c = juju_test.Conductor(args) |
371 | 629 | c.juju_version = juju_test.JujuVersion(major=0, minor=7, patch=0) | 632 | c.juju_version = juju_test.JujuVersion(major=0, minor=7, patch=0) |
372 | 630 | 633 | ||
373 | === added file 'tests/test_substrates.py' | |||
374 | --- tests/test_substrates.py 1970-01-01 00:00:00 +0000 | |||
375 | +++ tests/test_substrates.py 2014-01-09 20:17:53 +0000 | |||
376 | @@ -0,0 +1,62 @@ | |||
377 | 1 | """Unit test for juju tests substrate handling""" | ||
378 | 2 | |||
379 | 3 | import unittest | ||
380 | 4 | import yaml | ||
381 | 5 | from charmtools.test import parse_substrates, allowed_substrates | ||
382 | 6 | |||
383 | 7 | |||
384 | 8 | class JujuTestSubstrateTests(unittest.TestCase): | ||
385 | 9 | INCLUDE_SKIP = ''' | ||
386 | 10 | substrates: | ||
387 | 11 | order: include, skip | ||
388 | 12 | skip: amazon | ||
389 | 13 | include: "*" | ||
390 | 14 | ''' | ||
391 | 15 | |||
392 | 16 | SKIP_INCLUDE = ''' | ||
393 | 17 | substrates: | ||
394 | 18 | order: skip, include | ||
395 | 19 | skip: "*" | ||
396 | 20 | include: amazon | ||
397 | 21 | ''' | ||
398 | 22 | |||
399 | 23 | def test_parse_substrates_text(self): | ||
400 | 24 | self.assertRaises(ValueError, parse_substrates, '') | ||
401 | 25 | self.assertIsNotNone(parse_substrates(self.INCLUDE_SKIP)) | ||
402 | 26 | |||
403 | 27 | def test_parse_substrate_object(self): | ||
404 | 28 | data = yaml.load(self.INCLUDE_SKIP) | ||
405 | 29 | self.assertIsNotNone(parse_substrates(data)) | ||
406 | 30 | |||
407 | 31 | def test_parse_substrates_order(self): | ||
408 | 32 | result = parse_substrates(self.INCLUDE_SKIP) | ||
409 | 33 | self.assertEqual(result.order, ['include', 'skip']) | ||
410 | 34 | |||
411 | 35 | def test_parse_substrates_order_invalid(self): | ||
412 | 36 | data = self.INCLUDE_SKIP.replace('skip', 'foobar') | ||
413 | 37 | self.assertRaises(ValueError, parse_substrates, data) | ||
414 | 38 | |||
415 | 39 | def test_parse_substrates_include(self): | ||
416 | 40 | result = parse_substrates(self.INCLUDE_SKIP) | ||
417 | 41 | self.assertEqual(result.include, set(['*'])) | ||
418 | 42 | |||
419 | 43 | def test_parse_substrates_skip(self): | ||
420 | 44 | result = parse_substrates(self.INCLUDE_SKIP) | ||
421 | 45 | self.assertEqual(result.skip, set(['amazon'])) | ||
422 | 46 | |||
423 | 47 | def test_filter_include_skip(self): | ||
424 | 48 | rules = parse_substrates(self.INCLUDE_SKIP) | ||
425 | 49 | self.assertEqual(rules.filter('amazon,hp,azure'), ['azure', 'hp']) | ||
426 | 50 | |||
427 | 51 | def test_filter_skip_include(self): | ||
428 | 52 | rules = parse_substrates(self.SKIP_INCLUDE) | ||
429 | 53 | self.assertEqual(rules.filter('amazon,hp,azure'), ['amazon']) | ||
430 | 54 | |||
431 | 55 | def test_allowed_substrates(self): | ||
432 | 56 | self.assertEqual(allowed_substrates(self.INCLUDE_SKIP, | ||
433 | 57 | ['foo', 'bar', 'amazon']), | ||
434 | 58 | ['bar', 'foo']) | ||
435 | 59 | |||
436 | 60 | |||
437 | 61 | if __name__ == '__main__': | ||
438 | 62 | unittest.main() |
Reviewers: mp+201094_ code.launchpad. net,
Message:
Please take a look.
Description:
Updates to bsaller's fixes to substrate parsing
https:/ /code.launchpad .net/~marcocepp i/charm- tools/substrate -cfg/+merge/ 201094
(do not edit description out of merge proposal)
Please review this at https:/ /codereview. appspot. com/49940044/
Affected files (+189, -37 lines): bundles. py generate. py update. py juju_test. py substrates. py
M .bzrignore
A [revision details]
M charmtools/
M charmtools/
M charmtools/test.py
M charmtools/
M tests/test_
A tests/test_