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', [