Mercurial > piecrust2
comparison tests/conftest.py @ 974:72f17534d58e
tests: First pass on making unit tests work again.
- Fix all imports
- Add more helper functions to work with mock file-systems
- Simplify some code by running chef directly on the mock FS
- Fix a couple tests
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Tue, 17 Oct 2017 01:07:30 -0700 |
parents | 8ac2d6045d1d |
children | 45ad976712ec |
comparison
equal
deleted
inserted
replaced
973:8419daaa7a0e | 974:72f17534d58e |
---|---|
6 import logging | 6 import logging |
7 import pytest | 7 import pytest |
8 import yaml | 8 import yaml |
9 import colorama | 9 import colorama |
10 from werkzeug.exceptions import HTTPException | 10 from werkzeug.exceptions import HTTPException |
11 from piecrust.app import apply_variant_and_values | 11 from piecrust.app import PieCrustFactory, apply_variants_and_values |
12 from piecrust.configuration import merge_dicts | 12 from piecrust.configuration import merge_dicts |
13 from .mockutil import mock_fs, mock_fs_scope | 13 from .mockutil import mock_fs, mock_fs_scope |
14 | 14 |
15 | 15 |
16 def pytest_runtest_setup(item): | 16 def pytest_runtest_setup(item): |
17 pass | 17 pass |
18 | 18 |
19 | 19 |
20 def pytest_addoption(parser): | 20 def pytest_addoption(parser): |
21 parser.addoption( | 21 parser.addoption( |
22 '--log-debug', | 22 '--log-debug', |
23 action='store_true', | 23 action='store_true', |
24 help="Sets the PieCrust logger to output debug info to stdout.") | 24 help="Sets the PieCrust logger to output debug info to stdout.") |
25 parser.addoption( | 25 parser.addoption( |
26 '--mock-debug', | 26 '--log-file', |
27 action='store_true', | 27 help="Sets the PieCrust logger to write to a file.") |
28 help="Prints contents of the mock file-system.") | 28 parser.addoption( |
29 '--mock-debug', | |
30 action='store_true', | |
31 help="Prints contents of the mock file-system.") | |
29 | 32 |
30 | 33 |
31 def pytest_configure(config): | 34 def pytest_configure(config): |
32 if config.getoption('--log-debug'): | 35 if config.getoption('--log-debug'): |
33 hdl = logging.StreamHandler(stream=sys.stdout) | 36 hdl = logging.StreamHandler(stream=sys.stdout) |
34 logging.getLogger('piecrust').addHandler(hdl) | 37 logging.getLogger('piecrust').addHandler(hdl) |
35 logging.getLogger('piecrust').setLevel(logging.DEBUG) | 38 logging.getLogger('piecrust').setLevel(logging.DEBUG) |
39 | |
40 log_file = config.getoption('--log-file') | |
41 if log_file: | |
42 hdl = logging.StreamHandler( | |
43 stream=open(log_file, 'w', encoding='utf8')) | |
44 logging.getLogger().addHandler(hdl) | |
36 | 45 |
37 | 46 |
38 def pytest_collect_file(parent, path): | 47 def pytest_collect_file(parent, path): |
39 if path.ext == '.yaml' and path.basename.startswith("test"): | 48 if path.ext == '.yaml' and path.basename.startswith("test"): |
40 category = os.path.basename(path.dirname) | 49 category = os.path.basename(path.dirname) |
53 # ourselves... it's not pretty, but at least it's more useful. | 62 # ourselves... it's not pretty, but at least it's more useful. |
54 if excinfo.value.__cause__: | 63 if excinfo.value.__cause__: |
55 import traceback | 64 import traceback |
56 ex = excinfo.value | 65 ex = excinfo.value |
57 return '\n'.join( | 66 return '\n'.join( |
58 traceback.format_exception( | 67 traceback.format_exception( |
59 type(ex), ex, ex.__traceback__)) | 68 type(ex), ex, ex.__traceback__)) |
60 return '' | 69 return '' |
61 | 70 |
62 | 71 |
63 class YamlTestFileBase(pytest.File): | 72 class YamlTestFileBase(pytest.File): |
64 def collect(self): | 73 def collect(self): |
87 fs = mock_fs() | 96 fs = mock_fs() |
88 | 97 |
89 # Suppress any formatting or layout so we can compare | 98 # Suppress any formatting or layout so we can compare |
90 # much simpler strings. | 99 # much simpler strings. |
91 config = { | 100 config = { |
92 'site': { | 101 'site': { |
93 'default_format': 'none', | 102 'default_format': 'none', |
94 'default_page_layout': 'none', | 103 'default_page_layout': 'none', |
95 'default_post_layout': 'none'} | 104 'default_post_layout': 'none'} |
96 } | 105 } |
97 | 106 |
98 # Website or theme config. | 107 # Website or theme config. |
99 test_theme_config = self.spec.get('theme_config') | 108 test_theme_config = self.spec.get('theme_config') |
100 if test_theme_config is not None: | 109 if test_theme_config is not None: |
101 merge_dicts(config, test_theme_config) | 110 merge_dicts(config, test_theme_config) |
249 from piecrust.baking.baker import Baker | 258 from piecrust.baking.baker import Baker |
250 with mock_fs_scope(fs, keep=self.mock_debug): | 259 with mock_fs_scope(fs, keep=self.mock_debug): |
251 out_dir = fs.path('kitchen/_counter') | 260 out_dir = fs.path('kitchen/_counter') |
252 app = fs.getApp(theme_site=self.is_theme_site) | 261 app = fs.getApp(theme_site=self.is_theme_site) |
253 | 262 |
254 variant = self.spec.get('config_variant') | |
255 values = self.spec.get('config_values') | 263 values = self.spec.get('config_values') |
256 if values is not None: | 264 if values is not None: |
257 values = list(values.items()) | 265 values = list(values.items()) |
258 apply_variant_and_values(app, variant, values) | 266 variants = self.spec.get('config_variants') |
259 | 267 if variants is not None: |
260 baker = Baker(app, out_dir, | 268 variants = list(variants.items()) |
261 applied_config_variant=variant, | 269 apply_variants_and_values(app, variants, values) |
262 applied_config_values=values) | 270 |
263 record = baker.bake() | 271 appfactory = PieCrustFactory(app.root_dir, |
264 | 272 config_variants=variants, |
265 if not record.success: | 273 config_values=values) |
274 baker = Baker(appfactory, app, out_dir) | |
275 records = baker.bake() | |
276 | |
277 if not records.success: | |
266 errors = [] | 278 errors = [] |
267 for e in record.entries: | 279 for r in records.records: |
268 errors += e.getAllErrors() | 280 for e in r.getEntries(): |
281 errors += e.getAllErrors() | |
269 raise BakeError(errors) | 282 raise BakeError(errors) |
270 | 283 |
271 check_expected_outputs(self.spec, fs, ExpectedBakeOutputError) | 284 check_expected_outputs(self.spec, fs, ExpectedBakeOutputError) |
272 | 285 |
273 def reportinfo(self): | 286 def reportinfo(self): |
380 from werkzeug.wrappers import BaseResponse | 393 from werkzeug.wrappers import BaseResponse |
381 with mock_fs_scope(fs, keep=self.mock_debug): | 394 with mock_fs_scope(fs, keep=self.mock_debug): |
382 if is_admin_test: | 395 if is_admin_test: |
383 from piecrust.admin.web import create_foodtruck_app | 396 from piecrust.admin.web import create_foodtruck_app |
384 s = { | 397 s = { |
385 'FOODTRUCK_CMDLINE_MODE': True, | 398 'FOODTRUCK_CMDLINE_MODE': True, |
386 'FOODTRUCK_ROOT': fs.path('/kitchen') | 399 'FOODTRUCK_ROOT': fs.path('/kitchen') |
387 } | 400 } |
388 test_app = create_foodtruck_app(s) | 401 test_app = create_foodtruck_app(s) |
389 else: | 402 else: |
390 from piecrust.app import PieCrustFactory | 403 from piecrust.app import PieCrustFactory |
391 from piecrust.serving.server import Server | 404 from piecrust.serving.server import Server |
392 appfactory = PieCrustFactory( | 405 appfactory = PieCrustFactory( |
393 fs.path('/kitchen'), | 406 fs.path('/kitchen'), |
394 theme_site=self.is_theme_site) | 407 theme_site=self.is_theme_site) |
395 server = Server(appfactory) | 408 server = Server(appfactory) |
396 test_app = self._TestApp(server) | 409 test_app = self._TestApp(server) |
397 | 410 |
398 client = Client(test_app, BaseResponse) | 411 client = Client(test_app, BaseResponse) |
399 resp = client.get(url) | 412 resp = client.get(url) |
415 | 428 |
416 def repr_failure(self, excinfo): | 429 def repr_failure(self, excinfo): |
417 from piecrust.serving.server import MultipleNotFound | 430 from piecrust.serving.server import MultipleNotFound |
418 if isinstance(excinfo.value, MultipleNotFound): | 431 if isinstance(excinfo.value, MultipleNotFound): |
419 res = '\n'.join( | 432 res = '\n'.join( |
420 ["HTTP error 404 returned:", | 433 ["HTTP error 404 returned:", |
421 str(excinfo.value)] + | 434 str(excinfo.value)] + |
422 [str(e) for e in excinfo.value._nfes]) | 435 [str(e) for e in excinfo.value._nfes]) |
423 res += repr_nested_failure(excinfo) | 436 res += repr_nested_failure(excinfo) |
424 return res | 437 return res |
425 elif isinstance(excinfo.value, HTTPException): | 438 elif isinstance(excinfo.value, HTTPException): |
426 res = '\n'.join( | 439 res = '\n'.join( |
427 ["HTTP error %s returned:" % excinfo.value.code, | 440 ["HTTP error %s returned:" % excinfo.value.code, |
428 excinfo.value.description]) | 441 excinfo.value.description]) |
429 res += repr_nested_failure(excinfo) | 442 res += repr_nested_failure(excinfo) |
430 return res | 443 return res |
431 return super(ServeTestItem, self).repr_failure(excinfo) | 444 return super(ServeTestItem, self).repr_failure(excinfo) |
432 | 445 |
433 | 446 |
449 self.path = path or '' | 462 self.path = path or '' |
450 self.time = t or time.time() | 463 self.time = t or time.time() |
451 | 464 |
452 def createChildContext(self, name): | 465 def createChildContext(self, name): |
453 ctx = CompareContext( | 466 ctx = CompareContext( |
454 path='%s/%s' % (self.path, name), | 467 path='%s/%s' % (self.path, name), |
455 t=self.time) | 468 t=self.time) |
456 return ctx | 469 return ctx |
457 | 470 |
458 | 471 |
459 def _compare(left, right, ctx): | 472 def _compare(left, right, ctx): |
460 if type(left) != type(right): | 473 if type(left) != type(right): |