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):