Mercurial > piecrust2
comparison tests/test_pipelines_asset.py @ 979:45ad976712ec
tests: Big push to get the tests to pass again.
- Lots of fixes everywhere in the code.
- Try to handle debug logging in the multiprocessing worker pool when running in pytest. Not perfect, but usable for now.
- Replace all `.md` test files with `.html` since now a auto-format extension always sets the format.
- Replace `out` with `outfiles` in most places since now blog archives are added to the bake output and I don't want to add expected outputs for blog archives everywhere.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Sun, 29 Oct 2017 22:51:57 -0700 |
parents | 72f17534d58e |
children | 2b2eaee96121 |
comparison
equal
deleted
inserted
replaced
978:7e51d14097cb | 979:45ad976712ec |
---|---|
1 import time | 1 import time |
2 import os.path | 2 import os.path |
3 import shutil | 3 import random |
4 import inspect | 4 import inspect |
5 import pytest | 5 import pytest |
6 from piecrust.pipelines.asset import get_filtered_processors | 6 from piecrust.pipelines.asset import get_filtered_processors |
7 from piecrust.pipelines.records import MultiRecord | 7 from piecrust.pipelines.records import MultiRecord |
8 from piecrust.processing.base import SimpleFileProcessor | 8 from piecrust.processing.base import SimpleFileProcessor |
9 from .mockutil import mock_fs, mock_fs_scope | 9 from .mockutil import mock_fs, mock_fs_scope |
10 | 10 |
11 | 11 |
12 class FooProcessor(SimpleFileProcessor): | 12 class FooProcessor(SimpleFileProcessor): |
13 def __init__(self, exts=None, open_func=None): | 13 def __init__(self, name=None, exts=None, open_func=None): |
14 exts = exts or {'foo', 'foo'} | 14 self.PROCESSOR_NAME = name or 'foo' |
15 super(FooProcessor, self).__init__({exts[0]: exts[1]}) | 15 exts = exts or {'foo': 'foo'} |
16 self.PROCESSOR_NAME = exts[0] | 16 super().__init__(exts) |
17 self.open_func = open_func or open | 17 self.open_func = open_func or open |
18 | 18 |
19 def _doProcess(self, in_path, out_path): | 19 def _doProcess(self, in_path, out_path): |
20 with self.open_func(in_path, 'r') as f: | 20 with self.open_func(in_path, 'r') as f: |
21 text = f.read() | 21 text = f.read() |
22 with self.open_func(out_path, 'w') as f: | 22 with self.open_func(out_path, 'w') as f: |
23 f.write("%s: %s" % (self.PROCESSOR_NAME.upper(), text)) | 23 f.write("%s: %s" % (self.PROCESSOR_NAME.upper(), text)) |
24 return True | 24 return True |
25 | 25 |
26 | 26 |
27 class NoopProcessor(SimpleFileProcessor): | 27 def _get_test_plugin_name(): |
28 def __init__(self, exts): | 28 return 'foo_%d' % random.randrange(1000) |
29 super(NoopProcessor, self).__init__({exts[0]: exts[1]}) | 29 |
30 self.PROCESSOR_NAME = exts[0] | 30 |
31 self.processed = [] | 31 def _get_test_fs(*, plugins=None, processors=None): |
32 | 32 plugins = plugins or [] |
33 def _doProcess(self, in_path, out_path): | 33 processors = processors or [] |
34 self.processed.append(in_path) | 34 processors.append('copy') |
35 shutil.copyfile(in_path, out_path) | |
36 return True | |
37 | |
38 | |
39 def _get_test_fs(processors=None): | |
40 if processors is None: | |
41 processors = 'copy' | |
42 return (mock_fs() | 35 return (mock_fs() |
43 .withDir('counter') | 36 .withDir('counter') |
44 .withConfig({ | 37 .withConfig({ |
38 'site': { | |
39 'plugins': plugins | |
40 }, | |
45 'pipelines': { | 41 'pipelines': { |
46 'asset': { | 42 'asset': { |
47 'processors': processors | 43 'processors': processors |
48 } | 44 } |
49 } | 45 } |
50 })) | 46 })) |
51 | 47 |
52 | 48 |
53 def _create_test_plugin(fs, *, foo_exts=None, noop_exts=None): | 49 def _create_test_plugin(fs, plugname, *, foo_name=None, foo_exts=None): |
54 src = [ | 50 src = [ |
55 'from piecrust.plugins.base import PieCrustPlugin', | 51 'from piecrust.plugins.base import PieCrustPlugin', |
56 'from piecrust.processing.base import SimpleFileProcessor'] | 52 'from piecrust.processing.base import SimpleFileProcessor'] |
57 | 53 |
58 foo_lines = inspect.getsourcelines(FooProcessor) | 54 foo_lines = inspect.getsourcelines(FooProcessor) |
59 src += [''] | 55 src += [''] |
60 src += map(lambda l: l.rstrip('\n'), foo_lines[0]) | 56 src += map(lambda l: l.rstrip('\n'), foo_lines[0]) |
61 | 57 |
62 noop_lines = inspect.getsourcelines(NoopProcessor) | |
63 src += [''] | |
64 src += map(lambda l: l.rstrip('\n'), noop_lines[0]) | |
65 | |
66 src += [ | 58 src += [ |
67 '', | 59 '', |
68 'class FooNoopPlugin(PieCrustPlugin):', | 60 'class FooPlugin(PieCrustPlugin):', |
69 ' def getProcessors(self):', | 61 ' def getProcessors(self):', |
70 ' yield FooProcessor(%s)' % repr(foo_exts), | 62 ' yield FooProcessor(%s, %s)' % (repr(foo_name), |
71 ' yield NoopProcessor(%s)' % repr(noop_exts), | 63 repr(foo_exts)), |
72 '', | 64 '', |
73 '__piecrust_plugin__ = FooNoopPlugin'] | 65 '__piecrust_plugin__ = FooPlugin'] |
74 | 66 |
75 fs.withFile('kitchen/plugins/foonoop.py', src) | 67 print("Creating plugin with source:\n%s" % '\n'.join(src)) |
68 fs.withFile('kitchen/plugins/%s.py' % plugname, '\n'.join(src)) | |
76 | 69 |
77 | 70 |
78 def _bake_assets(fs): | 71 def _bake_assets(fs): |
79 fs.runChef('bake', '-p', 'asset') | 72 fs.runChef('bake', '-p', 'asset', '-o', fs.path('counter')) |
80 | 73 |
81 | 74 |
82 def test_empty(): | 75 def test_empty(): |
83 fs = _get_test_fs() | 76 fs = _get_test_fs() |
84 with mock_fs_scope(fs): | 77 with mock_fs_scope(fs): |
89 assert expected == fs.getStructure('counter') | 82 assert expected == fs.getStructure('counter') |
90 | 83 |
91 | 84 |
92 def test_one_file(): | 85 def test_one_file(): |
93 fs = (_get_test_fs() | 86 fs = (_get_test_fs() |
94 .withFile('kitchen/assets/something.html', 'A test file.')) | 87 .withFile('kitchen/assets/something.foo', 'A test file.')) |
95 with mock_fs_scope(fs): | 88 with mock_fs_scope(fs): |
96 expected = {} | 89 expected = {} |
97 assert expected == fs.getStructure('counter') | 90 assert expected == fs.getStructure('counter') |
98 _bake_assets(fs) | 91 _bake_assets(fs) |
99 expected = {'something.html': 'A test file.'} | 92 expected = {'something.foo': 'A test file.'} |
100 assert expected == fs.getStructure('counter') | 93 assert expected == fs.getStructure('counter') |
101 | 94 |
102 | 95 |
103 def test_one_level_dirtyness(): | 96 def test_one_level_dirtyness(): |
104 fs = (_get_test_fs() | 97 fs = (_get_test_fs() |
122 assert expected == fs.getStructure('counter') | 115 assert expected == fs.getStructure('counter') |
123 assert mtime < os.path.getmtime(fs.path('/counter/blah.foo')) | 116 assert mtime < os.path.getmtime(fs.path('/counter/blah.foo')) |
124 | 117 |
125 | 118 |
126 def test_two_levels_dirtyness(): | 119 def test_two_levels_dirtyness(): |
127 fs = (_get_test_fs() | 120 plugname = _get_test_plugin_name() |
121 fs = (_get_test_fs(plugins=[plugname], processors=['foo']) | |
128 .withFile('kitchen/assets/blah.foo', 'A test file.')) | 122 .withFile('kitchen/assets/blah.foo', 'A test file.')) |
129 _create_test_plugin(fs, foo_exts=('foo', 'bar')) | 123 _create_test_plugin(fs, plugname, foo_exts={'foo': 'bar'}) |
130 with mock_fs_scope(fs): | 124 with mock_fs_scope(fs): |
131 _bake_assets(fs) | 125 _bake_assets(fs) |
132 expected = {'blah.bar': 'FOO: A test file.'} | 126 expected = {'blah.bar': 'FOO: A test file.'} |
133 assert expected == fs.getStructure('counter') | 127 assert expected == fs.getStructure('counter') |
134 mtime = os.path.getmtime(fs.path('/counter/blah.bar')) | 128 mtime = os.path.getmtime(fs.path('/counter/blah.bar')) |
162 time.sleep(1) | 156 time.sleep(1) |
163 os.remove(fs.path('/kitchen/assets/blah2.foo')) | 157 os.remove(fs.path('/kitchen/assets/blah2.foo')) |
164 expected = { | 158 expected = { |
165 'blah1.foo': 'A test file.'} | 159 'blah1.foo': 'A test file.'} |
166 assert expected == fs.getStructure('kitchen/assets') | 160 assert expected == fs.getStructure('kitchen/assets') |
167 _bake_assets(1) | 161 _bake_assets(fs) |
168 assert expected == fs.getStructure('counter') | 162 assert expected == fs.getStructure('counter') |
169 | 163 |
170 | 164 |
171 def test_record_version_change(): | 165 def test_record_version_change(): |
172 fs = (_get_test_fs() | 166 plugname = _get_test_plugin_name() |
167 fs = (_get_test_fs(plugins=[plugname], processors=['foo']) | |
173 .withFile('kitchen/assets/blah.foo', 'A test file.')) | 168 .withFile('kitchen/assets/blah.foo', 'A test file.')) |
174 _create_test_plugin(fs, foo_exts=('foo', 'foo')) | 169 _create_test_plugin(fs, plugname) |
175 with mock_fs_scope(fs): | 170 with mock_fs_scope(fs): |
176 _bake_assets(fs) | 171 time.sleep(1) |
177 assert os.path.exists(fs.path('/counter/blah.foo')) is True | 172 _bake_assets(fs) |
178 mtime = os.path.getmtime(fs.path('/counter/blah.foo')) | 173 time.sleep(0.1) |
179 | 174 mtime = os.path.getmtime(fs.path('counter/blah.foo')) |
180 time.sleep(1) | 175 |
181 _bake_assets(fs) | 176 time.sleep(1) |
182 assert mtime == os.path.getmtime(fs.path('/counter/blah.foo')) | 177 _bake_assets(fs) |
183 | 178 time.sleep(0.1) |
184 time.sleep(1) | 179 assert mtime == os.path.getmtime(fs.path('counter/blah.foo')) |
180 | |
185 MultiRecord.RECORD_VERSION += 1 | 181 MultiRecord.RECORD_VERSION += 1 |
186 try: | 182 try: |
183 time.sleep(1) | |
187 _bake_assets(fs) | 184 _bake_assets(fs) |
188 assert mtime < os.path.getmtime(fs.path('/counter/blah.foo')) | 185 time.sleep(0.1) |
186 assert mtime < os.path.getmtime(fs.path('counter/blah.foo')) | |
189 finally: | 187 finally: |
190 MultiRecord.RECORD_VERSION -= 1 | 188 MultiRecord.RECORD_VERSION -= 1 |
191 | 189 |
192 | 190 |
193 @pytest.mark.parametrize('patterns, expected', [ | 191 @pytest.mark.parametrize('patterns, expected', [ |