Mercurial > piecrust2
comparison tests/conftest.py @ 1126:be550e1f6423
tests: Improve failure reporting, improve CLI tests.
CLI tests can now optionally run in a non-prepared temp directory.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Wed, 28 Feb 2018 20:16:04 -0800 |
parents | 2aa6174453c8 |
children | 952f3c24a99d |
comparison
equal
deleted
inserted
replaced
1125:8c3506e5ea3f | 1126:be550e1f6423 |
---|---|
104 return bool(self.config.getoption('--pc-mock-debug')) | 104 return bool(self.config.getoption('--pc-mock-debug')) |
105 | 105 |
106 def _prepareMockFs(self): | 106 def _prepareMockFs(self): |
107 fs = mock_fs() | 107 fs = mock_fs() |
108 | 108 |
109 if self.spec.get('no_kitchen', False): | |
110 fs.withDir('/') | |
111 return fs | |
112 | |
109 # Suppress any formatting or layout so we can compare | 113 # Suppress any formatting or layout so we can compare |
110 # much simpler strings. | 114 # much simpler strings. |
111 config = { | 115 config = { |
112 'site': { | 116 'site': { |
113 'default_format': 'none', | 117 'default_format': 'none', |
213 argv = self.spec['args'] | 217 argv = self.spec['args'] |
214 if isinstance(argv, str): | 218 if isinstance(argv, str): |
215 argv = argv.split(' ') | 219 argv = argv.split(' ') |
216 if self.is_theme_site: | 220 if self.is_theme_site: |
217 argv.insert(0, '--theme') | 221 argv.insert(0, '--theme') |
218 argv = ['--root', fs.path('/kitchen')] + argv | 222 if not self.spec.get('no_kitchen', False): |
219 | 223 argv = ['--root', fs.path('/kitchen')] + argv |
220 expected_code = self.spec.get('code', 0) | |
221 expected_out = self.spec.get('out', None) | |
222 | 224 |
223 with mock_fs_scope(fs, keep=self.mock_debug): | 225 with mock_fs_scope(fs, keep=self.mock_debug): |
226 cwd = os.getcwd() | |
224 memstream = io.StringIO() | 227 memstream = io.StringIO() |
225 hdl = logging.StreamHandler(stream=memstream) | 228 hdl = logging.StreamHandler(stream=memstream) |
226 logging.getLogger().addHandler(hdl) | 229 logging.getLogger().addHandler(hdl) |
227 try: | 230 try: |
228 from piecrust.main import _pre_parse_chef_args, _run_chef | 231 from piecrust.main import _pre_parse_chef_args, _run_chef |
232 os.chdir(fs.path('/')) | |
229 pre_args = _pre_parse_chef_args(argv) | 233 pre_args = _pre_parse_chef_args(argv) |
230 exit_code = _run_chef(pre_args, argv) | 234 exit_code = _run_chef(pre_args, argv) |
231 finally: | 235 finally: |
232 logging.getLogger().removeHandler(hdl) | 236 logging.getLogger().removeHandler(hdl) |
233 | 237 os.chdir(cwd) |
234 assert expected_code == exit_code | 238 |
235 | 239 expected_code = self.spec.get('code', 0) |
240 if expected_code != exit_code: | |
241 raise UnexpectedChefExitCodeError("Got '%d', expected '%d'." % | |
242 (exit_code, expected_code)) | |
243 | |
244 expected_out = self.spec.get('out', None) | |
236 if expected_out is not None: | 245 if expected_out is not None: |
237 actual_out = memstream.getvalue() | 246 actual_out = memstream.getvalue() |
238 if not self.spec.get('no_strip'): | 247 if not self.spec.get('no_strip'): |
239 actual_out = actual_out.rstrip(' \n') | 248 actual_out = actual_out.rstrip(' \n') |
240 expected_out = expected_out.rstrip(' \n') | 249 expected_out = expected_out.rstrip(' \n') |
241 if self.spec.get('replace_out_path_sep'): | 250 if self.spec.get('replace_out_path_sep'): |
242 expected_out = expected_out.replace('/', os.sep) | 251 expected_out = expected_out.replace('/', os.sep) |
243 assert expected_out == actual_out | 252 if expected_out != actual_out: |
253 raise UnexpectedChefOutputError(expected_out, actual_out) | |
254 | |
255 expected_files = self.spec.get('files', None) | |
256 if expected_files is not None: | |
257 for path in expected_files: | |
258 path = '/' + path.lstrip('/') | |
259 if not os.path.exists(fs.path(path)): | |
260 raise MissingChefOutputFileError(fs, path) | |
244 | 261 |
245 def reportinfo(self): | 262 def reportinfo(self): |
246 return self.fspath, 0, "bake: %s" % self.name | 263 return self.fspath, 0, "bake: %s" % self.name |
247 | 264 |
248 def repr_failure(self, excinfo): | 265 def repr_failure(self, excinfo): |
266 if isinstance(excinfo.value, UnexpectedChefExitCodeError): | |
267 return str(excinfo.value) | |
249 if isinstance(excinfo.value, UnexpectedChefOutputError): | 268 if isinstance(excinfo.value, UnexpectedChefOutputError): |
250 return ('\n'.join( | 269 return ('\n'.join( |
251 ['Unexpected command output. Left is expected output, ' | 270 ['Unexpected command output. Expected:', |
252 'right is actual output'] + | 271 excinfo.value.args[0], |
253 excinfo.value.args[0])) | 272 "Got:", |
273 excinfo.value.args[1]])) | |
274 if isinstance(excinfo.value, MissingChefOutputFileError): | |
275 lines = print_fs_tree(excinfo.value.args[0].path('')) | |
276 return ('\n'.join( | |
277 ["Missing file: %s" % excinfo.value.args[1], | |
278 "Got output directory:"] + | |
279 lines)) | |
254 return super(ChefTestItem, self).repr_failure(excinfo) | 280 return super(ChefTestItem, self).repr_failure(excinfo) |
255 | 281 |
256 | 282 |
283 class UnexpectedChefExitCodeError(Exception): | |
284 pass | |
285 | |
286 | |
257 class UnexpectedChefOutputError(Exception): | 287 class UnexpectedChefOutputError(Exception): |
288 pass | |
289 | |
290 | |
291 class MissingChefOutputFileError(Exception): | |
258 pass | 292 pass |
259 | 293 |
260 | 294 |
261 class ChefTestFile(YamlTestFileBase): | 295 class ChefTestFile(YamlTestFileBase): |
262 __item_class__ = ChefTestItem | 296 __item_class__ = ChefTestItem |
289 for r in records.records: | 323 for r in records.records: |
290 for e in r.getEntries(): | 324 for e in r.getEntries(): |
291 errors += e.getAllErrors() | 325 errors += e.getAllErrors() |
292 raise BakeError(errors) | 326 raise BakeError(errors) |
293 | 327 |
294 check_expected_outputs(self.spec, fs, ExpectedBakeOutputError) | 328 check_expected_outputs(self.spec, fs, UnexpectedBakeOutputError) |
295 | 329 |
296 def reportinfo(self): | 330 def reportinfo(self): |
297 return self.fspath, 0, "bake: %s" % self.name | 331 return self.fspath, 0, "bake: %s" % self.name |
298 | 332 |
299 def repr_failure(self, excinfo): | 333 def repr_failure(self, excinfo): |
300 if isinstance(excinfo.value, ExpectedBakeOutputError): | 334 if isinstance(excinfo.value, UnexpectedBakeOutputError): |
301 return ('\n'.join( | 335 return ('\n'.join( |
302 ['Unexpected bake output. Left is expected output, ' | 336 ['Unexpected bake output. Left is expected output, ' |
303 'right is actual output'] + | 337 'right is actual output'] + |
304 excinfo.value.args[0])) | 338 excinfo.value.args[0])) |
305 elif isinstance(excinfo.value, BakeError): | 339 elif isinstance(excinfo.value, BakeError): |
313 | 347 |
314 class BakeError(Exception): | 348 class BakeError(Exception): |
315 pass | 349 pass |
316 | 350 |
317 | 351 |
318 class ExpectedBakeOutputError(Exception): | 352 class UnexpectedBakeOutputError(Exception): |
319 pass | 353 pass |
320 | 354 |
321 | 355 |
322 class BakeTestFile(YamlTestFileBase): | 356 class BakeTestFile(YamlTestFileBase): |
323 __item_class__ = BakeTestItem | 357 __item_class__ = BakeTestItem |