Added new tests to test hook_transform()
[mediagoblin.git] / mediagoblin / tests / test_pluginapi.py
1 # GNU MediaGoblin -- federated, autonomous media hosting
2 # Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
3 #
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU Affero General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or
7 # (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU Affero General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17 import sys
18
19 from configobj import ConfigObj
20 import pytest
21
22 from mediagoblin import mg_globals
23 from mediagoblin.init.plugins import setup_plugins
24 from mediagoblin.tools import pluginapi
25
26
27 def with_cleanup(*modules_to_delete):
28 def _with_cleanup(fun):
29 """Wrapper that saves and restores mg_globals"""
30 def _with_cleanup_inner(*args, **kwargs):
31 old_app_config = mg_globals.app_config
32 old_global_config = mg_globals.global_config
33 # Need to delete icky modules before and after so as to make
34 # sure things work correctly.
35 for module in modules_to_delete:
36 try:
37 del sys.modules[module]
38 except KeyError:
39 pass
40 # The plugin cache gets populated as a side-effect of
41 # importing, so it's best to clear it before and after a test.
42 pman = pluginapi.PluginManager()
43 pman.clear()
44 try:
45 return fun(*args, **kwargs)
46 finally:
47 mg_globals.app_config = old_app_config
48 mg_globals.global_config = old_global_config
49 # Need to delete icky modules before and after so as to make
50 # sure things work correctly.
51 for module in modules_to_delete:
52 try:
53 del sys.modules[module]
54 except KeyError:
55 pass
56 pman.clear()
57
58 _with_cleanup_inner.__name__ = fun.__name__
59 return _with_cleanup_inner
60 return _with_cleanup
61
62
63 def build_config(sections):
64 """Builds a ConfigObj object with specified data
65
66 :arg sections: list of ``(section_name, section_data,
67 subsection_list)`` tuples where section_data is a dict and
68 subsection_list is a list of ``(section_name, section_data,
69 subsection_list)``, ...
70
71 For example:
72
73 >>> build_config([
74 ... ('mediagoblin', {'key1': 'val1'}, []),
75 ... ('section2', {}, [
76 ... ('subsection1', {}, [])
77 ... ])
78 ... ])
79 """
80 cfg = ConfigObj()
81 cfg.filename = 'foo'
82 def _iter_section(cfg, section_list):
83 for section_name, data, subsection_list in section_list:
84 cfg[section_name] = data
85 _iter_section(cfg[section_name], subsection_list)
86
87 _iter_section(cfg, sections)
88 return cfg
89
90
91 @with_cleanup()
92 def test_no_plugins():
93 """Run setup_plugins with no plugins in config"""
94 cfg = build_config([('mediagoblin', {}, [])])
95 mg_globals.app_config = cfg['mediagoblin']
96 mg_globals.global_config = cfg
97
98 pman = pluginapi.PluginManager()
99 setup_plugins()
100
101 # Make sure we didn't load anything.
102 assert len(pman.plugins) == 0
103
104
105 @with_cleanup('mediagoblin.plugins.sampleplugin')
106 def test_one_plugin():
107 """Run setup_plugins with a single working plugin"""
108 cfg = build_config([
109 ('mediagoblin', {}, []),
110 ('plugins', {}, [
111 ('mediagoblin.plugins.sampleplugin', {}, [])
112 ])
113 ])
114
115 mg_globals.app_config = cfg['mediagoblin']
116 mg_globals.global_config = cfg
117
118 pman = pluginapi.PluginManager()
119 setup_plugins()
120
121 # Make sure we only found one plugin
122 assert len(pman.plugins) == 1
123 # Make sure the plugin is the one we think it is.
124 assert pman.plugins[0] == 'mediagoblin.plugins.sampleplugin'
125 # Make sure there was one hook registered
126 assert len(pman.hooks) == 1
127 # Make sure _setup_plugin_called was called once
128 import mediagoblin.plugins.sampleplugin
129 assert mediagoblin.plugins.sampleplugin._setup_plugin_called == 1
130
131
132 @with_cleanup('mediagoblin.plugins.sampleplugin')
133 def test_same_plugin_twice():
134 """Run setup_plugins with a single working plugin twice"""
135 cfg = build_config([
136 ('mediagoblin', {}, []),
137 ('plugins', {}, [
138 ('mediagoblin.plugins.sampleplugin', {}, []),
139 ('mediagoblin.plugins.sampleplugin', {}, []),
140 ])
141 ])
142
143 mg_globals.app_config = cfg['mediagoblin']
144 mg_globals.global_config = cfg
145
146 pman = pluginapi.PluginManager()
147 setup_plugins()
148
149 # Make sure we only found one plugin
150 assert len(pman.plugins) == 1
151 # Make sure the plugin is the one we think it is.
152 assert pman.plugins[0] == 'mediagoblin.plugins.sampleplugin'
153 # Make sure there was one hook registered
154 assert len(pman.hooks) == 1
155 # Make sure _setup_plugin_called was called once
156 import mediagoblin.plugins.sampleplugin
157 assert mediagoblin.plugins.sampleplugin._setup_plugin_called == 1
158
159
160 @with_cleanup()
161 def test_disabled_plugin():
162 """Run setup_plugins with a single working plugin twice"""
163 cfg = build_config([
164 ('mediagoblin', {}, []),
165 ('plugins', {}, [
166 ('-mediagoblin.plugins.sampleplugin', {}, []),
167 ])
168 ])
169
170 mg_globals.app_config = cfg['mediagoblin']
171 mg_globals.global_config = cfg
172
173 pman = pluginapi.PluginManager()
174 setup_plugins()
175
176 # Make sure we didn't load the plugin
177 assert len(pman.plugins) == 0
178
179
180 @with_cleanup()
181 def test_hook_handle():
182 """
183 Test the hook_handle method
184 """
185 cfg = build_config([
186 ('mediagoblin', {}, []),
187 ('plugins', {}, [
188 ('mediagoblin.tests.testplugins.callables1', {}, []),
189 ('mediagoblin.tests.testplugins.callables2', {}, []),
190 ('mediagoblin.tests.testplugins.callables3', {}, []),
191 ])
192 ])
193
194 mg_globals.app_config = cfg['mediagoblin']
195 mg_globals.global_config = cfg
196
197 setup_plugins()
198
199 # Just one hook provided
200 call_log = []
201 assert pluginapi.hook_handle(
202 "just_one", call_log) == "Called just once"
203 assert call_log == ["expect this one call"]
204
205 # Nothing provided and unhandled not okay
206 call_log = []
207 pluginapi.hook_handle(
208 "nothing_handling", call_log) == None
209 assert call_log == []
210
211 # Nothing provided and unhandled okay
212 call_log = []
213 assert pluginapi.hook_handle(
214 "nothing_handling", call_log, unhandled_okay=True) is None
215 assert call_log == []
216
217 # Multiple provided, go with the first!
218 call_log = []
219 assert pluginapi.hook_handle(
220 "multi_handle", call_log) == "the first returns"
221 assert call_log == ["Hi, I'm the first"]
222
223 # Multiple provided, one has CantHandleIt
224 call_log = []
225 assert pluginapi.hook_handle(
226 "multi_handle_with_canthandle",
227 call_log) == "the second returns"
228 assert call_log == ["Hi, I'm the second"]
229
230
231 @with_cleanup()
232 def test_hook_runall():
233 """
234 Test the hook_runall method
235 """
236 cfg = build_config([
237 ('mediagoblin', {}, []),
238 ('plugins', {}, [
239 ('mediagoblin.tests.testplugins.callables1', {}, []),
240 ('mediagoblin.tests.testplugins.callables2', {}, []),
241 ('mediagoblin.tests.testplugins.callables3', {}, []),
242 ])
243 ])
244
245 mg_globals.app_config = cfg['mediagoblin']
246 mg_globals.global_config = cfg
247
248 setup_plugins()
249
250 # Just one hook, check results
251 call_log = []
252 assert pluginapi.hook_runall(
253 "just_one", call_log) == ["Called just once"]
254 assert call_log == ["expect this one call"]
255
256 # None provided, check results
257 call_log = []
258 assert pluginapi.hook_runall(
259 "nothing_handling", call_log) == []
260 assert call_log == []
261
262 # Multiple provided, check results
263 call_log = []
264 assert pluginapi.hook_runall(
265 "multi_handle", call_log) == [
266 "the first returns",
267 "the second returns",
268 "the third returns",
269 ]
270 assert call_log == [
271 "Hi, I'm the first",
272 "Hi, I'm the second",
273 "Hi, I'm the third"]
274
275 # Multiple provided, one has CantHandleIt, check results
276 call_log = []
277 assert pluginapi.hook_runall(
278 "multi_handle_with_canthandle", call_log) == [
279 "the second returns",
280 "the third returns",
281 ]
282 assert call_log == [
283 "Hi, I'm the second",
284 "Hi, I'm the third"]
285
286
287 @with_cleanup()
288 def test_hook_transform():
289 """
290 Test the hook_transform method
291 """
292 cfg = build_config([
293 ('mediagoblin', {}, []),
294 ('plugins', {}, [
295 ('mediagoblin.tests.testplugins.callables1', {}, []),
296 ('mediagoblin.tests.testplugins.callables2', {}, []),
297 ('mediagoblin.tests.testplugins.callables3', {}, []),
298 ])
299 ])
300
301 mg_globals.app_config = cfg['mediagoblin']
302 mg_globals.global_config = cfg
303
304 setup_plugins()
305
306 assert pluginapi.hook_transform(
307 "expand_tuple", (-1, 0)) == (-1, 0, 1, 2, 3)