Mercurial > piecrust2
comparison tests/test_processing_base.py @ 120:133845647083
Better error management and removal support in baking/processing.
* Baker and processor pipeline now store errors in their records.
* They also support deleting output files that are no longer valid.
* The basic transitional record class implements more boilerplate code.
* The processor pipeline is run from the `bake` command directly.
* New unit tests.
* Unit test mocking now mocks `os.remove` too.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Sun, 09 Nov 2014 14:46:23 -0800 |
parents | 3471ffa059b2 |
children | e725af1d48fb |
comparison
equal
deleted
inserted
replaced
119:0811f92cbdc7 | 120:133845647083 |
---|---|
1 import time | |
1 import os.path | 2 import os.path |
3 import shutil | |
2 import pytest | 4 import pytest |
3 from piecrust.processing.base import ProcessorPipeline | 5 from piecrust.processing.base import (ProcessorPipeline, SimpleFileProcessor) |
6 from piecrust.processing.records import ProcessorPipelineRecord | |
4 from .mockutil import mock_fs, mock_fs_scope | 7 from .mockutil import mock_fs, mock_fs_scope |
5 | 8 |
6 | 9 |
7 def _get_pipeline(fs, **kwargs): | 10 class FooProcessor(SimpleFileProcessor): |
8 app = fs.getApp(cache=False) | 11 def __init__(self, exts=None, open_func=None): |
12 exts = exts or {'foo', 'foo'} | |
13 super(FooProcessor, self).__init__({exts[0]: exts[1]}) | |
14 self.PROCESSOR_NAME = exts[0] | |
15 self.open_func = open_func or open | |
16 | |
17 def _doProcess(self, in_path, out_path): | |
18 with self.open_func(in_path, 'r') as f: | |
19 text = f.read() | |
20 with self.open_func(out_path, 'w') as f: | |
21 f.write("%s: %s" % (self.PROCESSOR_NAME.upper(), text)) | |
22 return True | |
23 | |
24 | |
25 class NoopProcessor(SimpleFileProcessor): | |
26 def __init__(self, exts): | |
27 super(NoopProcessor, self).__init__({exts[0]: exts[1]}) | |
28 self.PROCESSOR_NAME = exts[0] | |
29 self.processed = [] | |
30 | |
31 def _doProcess(self, in_path, out_path): | |
32 self.processed.append(in_path) | |
33 shutil.copyfile(in_path, out_path) | |
34 return True | |
35 | |
36 | |
37 def _get_pipeline(fs, cache=True, **kwargs): | |
38 app = fs.getApp(cache=cache) | |
9 mounts = [os.path.join(app.root_dir, 'assets')] | 39 mounts = [os.path.join(app.root_dir, 'assets')] |
10 return ProcessorPipeline(app, mounts, fs.path('counter'), | 40 return ProcessorPipeline(app, mounts, fs.path('counter'), |
11 num_workers=1, **kwargs) | 41 num_workers=1, **kwargs) |
12 | 42 |
13 | 43 |
34 pp.run() | 64 pp.run() |
35 expected = {'something.html': 'A test file.'} | 65 expected = {'something.html': 'A test file.'} |
36 assert expected == fs.getStructure('counter') | 66 assert expected == fs.getStructure('counter') |
37 | 67 |
38 | 68 |
69 def test_one_level_dirtyness(): | |
70 fs = (mock_fs() | |
71 .withFile('kitchen/assets/blah.foo', 'A test file.')) | |
72 with mock_fs_scope(fs): | |
73 pp = _get_pipeline(fs) | |
74 pp.filterProcessors(['copy']) | |
75 pp.run() | |
76 expected = {'blah.foo': 'A test file.'} | |
77 assert expected == fs.getStructure('counter') | |
78 mtime = os.path.getmtime(fs.path('/counter/blah.foo')) | |
79 assert abs(time.time() - mtime) <= 2 | |
80 | |
81 pp.run() | |
82 assert expected == fs.getStructure('counter') | |
83 assert mtime == os.path.getmtime(fs.path('/counter/blah.foo')) | |
84 | |
85 fs.withFile('kitchen/assets/blah.foo', 'A new test file.') | |
86 pp.run() | |
87 expected = {'blah.foo': 'A new test file.'} | |
88 assert expected == fs.getStructure('counter') | |
89 assert mtime < os.path.getmtime(fs.path('/counter/blah.foo')) | |
90 | |
91 | |
92 def test_two_levels_dirtyness(): | |
93 fs = (mock_fs() | |
94 .withFile('kitchen/assets/blah.foo', 'A test file.')) | |
95 with mock_fs_scope(fs) as scope: | |
96 pp = _get_pipeline(fs) | |
97 pp.processors.append(FooProcessor(('foo', 'bar'), scope._open)) | |
98 pp.filterProcessors(['foo', 'copy']) | |
99 pp.run() | |
100 expected = {'blah.bar': 'FOO: A test file.'} | |
101 assert expected == fs.getStructure('counter') | |
102 mtime = os.path.getmtime(fs.path('/counter/blah.bar')) | |
103 assert abs(time.time() - mtime) <= 2 | |
104 | |
105 pp.run() | |
106 assert expected == fs.getStructure('counter') | |
107 assert mtime == os.path.getmtime(fs.path('/counter/blah.bar')) | |
108 | |
109 fs.withFile('kitchen/assets/blah.foo', 'A new test file.') | |
110 pp.run() | |
111 expected = {'blah.bar': 'FOO: A new test file.'} | |
112 assert expected == fs.getStructure('counter') | |
113 assert mtime < os.path.getmtime(fs.path('/counter/blah.bar')) | |
114 | |
115 | |
116 def test_removed(): | |
117 fs = (mock_fs() | |
118 .withFile('kitchen/assets/blah1.foo', 'A test file.') | |
119 .withFile('kitchen/assets/blah2.foo', 'Ooops')) | |
120 with mock_fs_scope(fs): | |
121 expected = { | |
122 'blah1.foo': 'A test file.', | |
123 'blah2.foo': 'Ooops'} | |
124 assert expected == fs.getStructure('kitchen/assets') | |
125 pp = _get_pipeline(fs) | |
126 pp.filterProcessors(['copy']) | |
127 pp.run() | |
128 assert expected == fs.getStructure('counter') | |
129 | |
130 os.remove(fs.path('/kitchen/assets/blah2.foo')) | |
131 expected = { | |
132 'blah1.foo': 'A test file.'} | |
133 assert expected == fs.getStructure('kitchen/assets') | |
134 pp.run() | |
135 assert expected == fs.getStructure('counter') | |
136 | |
137 | |
138 def test_record_version_change(): | |
139 fs = (mock_fs() | |
140 .withFile('kitchen/assets/blah.foo', 'A test file.')) | |
141 with mock_fs_scope(fs): | |
142 pp = _get_pipeline(fs) | |
143 noop = NoopProcessor(('foo', 'foo')) | |
144 pp.processors.append(noop) | |
145 pp.filterProcessors(['foo', 'copy']) | |
146 pp.run() | |
147 assert 1 == len(noop.processed) | |
148 | |
149 pp.run() | |
150 assert 1 == len(noop.processed) | |
151 | |
152 ProcessorPipelineRecord.RECORD_VERSION += 1 | |
153 try: | |
154 pp.run() | |
155 assert 2 == len(noop.processed) | |
156 finally: | |
157 ProcessorPipelineRecord.RECORD_VERSION -= 1 | |
158 | |
159 | |
39 @pytest.mark.parametrize('patterns, expected', [ | 160 @pytest.mark.parametrize('patterns, expected', [ |
40 (['_'], | 161 (['_'], |
41 {'something.html': 'A test file.'}), | 162 {'something.html': 'A test file.'}), |
42 (['html'], | 163 (['html'], |
43 {}), | 164 {}), |