Commit | Line | Data |
---|---|---|
6a488035 TO |
1 | <?php |
2 | ||
3 | require_once 'CiviTest/CiviUnitTestCase.php'; | |
4 | ||
5 | class CRM_Extension_ManagerTest extends CiviUnitTestCase { | |
6 | const TESTING_TYPE = 'report'; | |
7 | const OTHER_TESTING_TYPE = 'module'; | |
8 | ||
9 | function setUp() { | |
10 | parent::setUp(); | |
11 | list ($this->basedir, $this->container) = $this->_createContainer(); | |
12 | $this->mapper = new CRM_Extension_Mapper($this->container); | |
13 | } | |
14 | ||
15 | function tearDown() { | |
16 | parent::tearDown(); | |
17 | } | |
18 | ||
19 | /** | |
20 | * Install an extension with an invalid type name | |
21 | * | |
22 | * @expectedException CRM_Extension_Exception | |
23 | */ | |
24 | function testInstallInvalidType() { | |
25 | $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface'); | |
26 | $testingTypeManager->expects($this->never()) | |
27 | ->method('onPreInstall'); | |
28 | $manager = $this->_createManager(array( | |
29 | self::OTHER_TESTING_TYPE => $testingTypeManager, | |
30 | )); | |
31 | $manager->install(array('test.foo.bar')); | |
32 | } | |
33 | ||
34 | /** | |
35 | * Install an extension with a valid type name | |
36 | * | |
37 | * Note: We initially install two extensions but then toggle only | |
38 | * the second. This controls for bad SQL queries which hit either | |
39 | * "the first row" or "all rows". | |
40 | */ | |
41 | function testInstall_Disable_Uninstall() { | |
42 | $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface'); | |
43 | $manager = $this->_createManager(array( | |
44 | self::TESTING_TYPE => $testingTypeManager, | |
45 | )); | |
46 | $this->assertEquals('uninstalled', $manager->getStatus('test.foo.bar')); | |
47 | $this->assertEquals('uninstalled', $manager->getStatus('test.whiz.bang')); | |
48 | ||
49 | $testingTypeManager | |
50 | ->expects($this->exactly(2)) | |
51 | ->method('onPreInstall'); | |
52 | $testingTypeManager | |
53 | ->expects($this->exactly(2)) | |
54 | ->method('onPostInstall'); | |
55 | $manager->install(array('test.whiz.bang', 'test.foo.bar')); | |
56 | $this->assertEquals('installed', $manager->getStatus('test.foo.bar')); | |
57 | $this->assertEquals('installed', $manager->getStatus('test.whiz.bang')); | |
58 | ||
59 | $testingTypeManager | |
60 | ->expects($this->once()) | |
61 | ->method('onPreDisable'); | |
62 | $testingTypeManager | |
63 | ->expects($this->once()) | |
64 | ->method('onPostDisable'); | |
65 | $manager->disable(array('test.foo.bar')); | |
66 | $this->assertEquals('disabled', $manager->getStatus('test.foo.bar')); | |
67 | $this->assertEquals('installed', $manager->getStatus('test.whiz.bang')); // no side-effect | |
68 | ||
69 | $testingTypeManager | |
70 | ->expects($this->once()) | |
71 | ->method('onPreUninstall'); | |
72 | $testingTypeManager | |
73 | ->expects($this->once()) | |
74 | ->method('onPostUninstall'); | |
75 | $manager->uninstall(array('test.foo.bar')); | |
76 | $this->assertEquals('uninstalled', $manager->getStatus('test.foo.bar')); | |
77 | $this->assertEquals('installed', $manager->getStatus('test.whiz.bang')); // no side-effect | |
78 | } | |
79 | ||
80 | /** | |
81 | * Install an extension and then harshly remove the underlying source. | |
82 | * Subseuently disable and uninstall. | |
83 | */ | |
84 | function testInstall_DirtyRemove_Disable_Uninstall() { | |
85 | $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface'); | |
86 | $manager = $this->_createManager(array( | |
87 | self::TESTING_TYPE => $testingTypeManager, | |
88 | )); | |
89 | $this->assertEquals('uninstalled', $manager->getStatus('test.foo.bar')); | |
90 | ||
91 | $manager->install(array('test.foo.bar')); | |
92 | $this->assertEquals('installed', $manager->getStatus('test.foo.bar')); | |
93 | ||
94 | $this->assertTrue(file_exists("{$this->basedir}/weird/foobar/info.xml")); | |
95 | CRM_Utils_File::cleanDir("{$this->basedir}/weird/foobar", TRUE, FALSE); | |
96 | $this->assertFalse(file_exists("{$this->basedir}/weird/foobar/info.xml")); | |
97 | $manager->refresh(); | |
98 | $this->assertEquals('installed-missing', $manager->getStatus('test.foo.bar')); | |
99 | ||
100 | $testingTypeManager | |
101 | ->expects($this->once()) | |
102 | ->method('onPreDisable'); | |
103 | $testingTypeManager | |
104 | ->expects($this->once()) | |
105 | ->method('onPostDisable'); | |
106 | $manager->disable(array('test.foo.bar')); | |
107 | $this->assertEquals('disabled-missing', $manager->getStatus('test.foo.bar')); | |
108 | ||
109 | $testingTypeManager | |
110 | ->expects($this->once()) | |
111 | ->method('onPreUninstall'); | |
112 | $testingTypeManager | |
113 | ->expects($this->once()) | |
114 | ->method('onPostUninstall'); | |
115 | $manager->uninstall(array('test.foo.bar')); | |
116 | $this->assertEquals('unknown', $manager->getStatus('test.foo.bar')); | |
117 | } | |
118 | ||
119 | /** | |
120 | * Install an extension with a valid type name | |
121 | */ | |
122 | function testInstall_Disable_Enable() { | |
123 | $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface'); | |
124 | $manager = $this->_createManager(array( | |
125 | self::TESTING_TYPE => $testingTypeManager, | |
126 | )); | |
127 | $this->assertEquals('uninstalled', $manager->getStatus('test.foo.bar')); | |
128 | $this->assertEquals('uninstalled', $manager->getStatus('test.whiz.bang')); | |
129 | ||
130 | $testingTypeManager | |
131 | ->expects($this->exactly(2)) | |
132 | ->method('onPreInstall'); | |
133 | $testingTypeManager | |
134 | ->expects($this->exactly(2)) | |
135 | ->method('onPostInstall'); | |
136 | $manager->install(array('test.whiz.bang', 'test.foo.bar')); | |
137 | $this->assertEquals('installed', $manager->getStatus('test.foo.bar')); | |
138 | $this->assertEquals('installed', $manager->getStatus('test.whiz.bang')); | |
139 | ||
140 | $testingTypeManager | |
141 | ->expects($this->once()) | |
142 | ->method('onPreDisable'); | |
143 | $testingTypeManager | |
144 | ->expects($this->once()) | |
145 | ->method('onPostDisable'); | |
146 | $manager->disable(array('test.foo.bar')); | |
147 | $this->assertEquals('disabled', $manager->getStatus('test.foo.bar')); | |
148 | $this->assertEquals('installed', $manager->getStatus('test.whiz.bang')); | |
149 | ||
150 | $testingTypeManager | |
151 | ->expects($this->once()) | |
152 | ->method('onPreEnable'); | |
153 | $testingTypeManager | |
154 | ->expects($this->once()) | |
155 | ->method('onPostEnable'); | |
156 | $manager->enable(array('test.foo.bar')); | |
157 | $this->assertEquals('installed', $manager->getStatus('test.foo.bar')); | |
158 | $this->assertEquals('installed', $manager->getStatus('test.whiz.bang')); | |
159 | } | |
160 | ||
161 | /** | |
162 | * Performing 'install' on a 'disabled' extension performs an 'enable' | |
163 | */ | |
164 | function testInstall_Disable_Install() { | |
165 | $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface'); | |
166 | $manager = $this->_createManager(array( | |
167 | self::TESTING_TYPE => $testingTypeManager, | |
168 | )); | |
169 | $this->assertEquals('uninstalled', $manager->getStatus('test.foo.bar')); | |
170 | ||
171 | $testingTypeManager | |
172 | ->expects($this->once()) | |
173 | ->method('onPreInstall'); | |
174 | $testingTypeManager | |
175 | ->expects($this->once()) | |
176 | ->method('onPostInstall'); | |
177 | $manager->install(array('test.foo.bar')); | |
178 | $this->assertEquals('installed', $manager->getStatus('test.foo.bar')); | |
179 | ||
180 | $testingTypeManager | |
181 | ->expects($this->once()) | |
182 | ->method('onPreDisable'); | |
183 | $testingTypeManager | |
184 | ->expects($this->once()) | |
185 | ->method('onPostDisable'); | |
186 | $manager->disable(array('test.foo.bar')); | |
187 | $this->assertEquals('disabled', $manager->getStatus('test.foo.bar')); | |
188 | ||
189 | $testingTypeManager | |
190 | ->expects($this->once()) | |
191 | ->method('onPreEnable'); | |
192 | $testingTypeManager | |
193 | ->expects($this->once()) | |
194 | ->method('onPostEnable'); | |
195 | $manager->install(array('test.foo.bar')); // install() instead of enable() | |
196 | $this->assertEquals('installed', $manager->getStatus('test.foo.bar')); | |
197 | } | |
198 | ||
199 | /** | |
200 | * Install an extension with a valid type name | |
201 | */ | |
202 | function testEnableBare() { | |
203 | $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface'); | |
204 | $manager = $this->_createManager(array( | |
205 | self::TESTING_TYPE => $testingTypeManager, | |
206 | )); | |
207 | $this->assertEquals('uninstalled', $manager->getStatus('test.foo.bar')); | |
208 | ||
209 | $testingTypeManager | |
210 | ->expects($this->once()) | |
211 | ->method('onPreInstall'); | |
212 | $testingTypeManager | |
213 | ->expects($this->once()) | |
214 | ->method('onPostInstall'); | |
215 | $testingTypeManager | |
216 | ->expects($this->never()) | |
217 | ->method('onPreEnable'); | |
218 | $testingTypeManager | |
219 | ->expects($this->never()) | |
220 | ->method('onPostEnable'); | |
221 | $manager->enable(array('test.foo.bar')); // enable not install | |
222 | $this->assertEquals('installed', $manager->getStatus('test.foo.bar')); | |
223 | } | |
224 | ||
225 | /** | |
226 | * Get the status of an unknown extension | |
227 | */ | |
228 | function testStatusUnknownKey() { | |
229 | $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface'); | |
230 | $testingTypeManager->expects($this->never()) | |
231 | ->method('onPreInstall'); | |
232 | $manager = $this->_createManager(array( | |
233 | self::TESTING_TYPE => $testingTypeManager, | |
234 | )); | |
235 | $this->assertEquals('unknown', $manager->getStatus('test.foo.bar.whiz.bang')); | |
236 | } | |
237 | ||
238 | /** | |
239 | * Replace code for an extension that doesn't exist in the container | |
240 | */ | |
241 | function testReplace_Unknown() { | |
242 | $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface'); | |
243 | $manager = $this->_createManager(array( | |
244 | self::TESTING_TYPE => $testingTypeManager, | |
245 | )); | |
246 | $this->assertEquals('unknown', $manager->getStatus('test.newextension')); | |
247 | ||
248 | $this->download = $this->_createDownload('test.newextension', 'newextension'); | |
249 | ||
250 | $testingTypeManager | |
251 | ->expects($this->never()) // no data to replace | |
252 | ->method('onPreReplace'); | |
253 | $testingTypeManager | |
254 | ->expects($this->never()) // no data to replace | |
255 | ->method('onPostReplace'); | |
256 | $manager->replace($this->download); | |
257 | $this->assertEquals('uninstalled', $manager->getStatus('test.newextension')); | |
258 | $this->assertTrue(file_exists("{$this->basedir}/test.newextension/info.xml")); | |
259 | $this->assertTrue(file_exists("{$this->basedir}/test.newextension/newextension.php")); | |
260 | $this->assertEquals(self::TESTING_TYPE, $this->mapper->keyToInfo('test.newextension')->type); | |
261 | $this->assertEquals('newextension', $this->mapper->keyToInfo('test.newextension')->file); | |
262 | } | |
263 | ||
264 | /** | |
265 | * Replace code for an extension that doesn't exist in the container | |
266 | */ | |
267 | function testReplace_Uninstalled() { | |
268 | $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface'); | |
269 | $manager = $this->_createManager(array( | |
270 | self::TESTING_TYPE => $testingTypeManager, | |
271 | )); | |
272 | $this->assertEquals('uninstalled', $manager->getStatus('test.whiz.bang')); | |
273 | $this->assertEquals('oddball', $this->mapper->keyToInfo('test.whiz.bang')->file); | |
274 | ||
275 | $this->download = $this->_createDownload('test.whiz.bang', 'newextension'); | |
276 | ||
277 | $testingTypeManager | |
278 | ->expects($this->never()) // no data to replace | |
279 | ->method('onPreReplace'); | |
280 | $testingTypeManager | |
281 | ->expects($this->never()) // no data to replace | |
282 | ->method('onPostReplace'); | |
283 | $manager->replace($this->download); | |
284 | $this->assertEquals('uninstalled', $manager->getStatus('test.whiz.bang')); | |
285 | $this->assertTrue(file_exists("{$this->basedir}/weird/whizbang/info.xml")); | |
286 | $this->assertTrue(file_exists("{$this->basedir}/weird/whizbang/newextension.php")); | |
287 | $this->assertFalse(file_exists("{$this->basedir}/weird/whizbang/oddball.php")); | |
288 | $this->assertEquals(self::TESTING_TYPE, $this->mapper->keyToInfo('test.whiz.bang')->type); | |
289 | $this->assertEquals('newextension', $this->mapper->keyToInfo('test.whiz.bang')->file); | |
290 | } | |
291 | ||
292 | /** | |
293 | * Install a module and then replace it with new code | |
294 | * | |
295 | * Note that some metadata changes between versions -- the original has | |
296 | * file="oddball", and the upgrade has file="newextension". | |
297 | */ | |
298 | function testReplace_Installed() { | |
299 | $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface'); | |
300 | $manager = $this->_createManager(array( | |
301 | self::TESTING_TYPE => $testingTypeManager, | |
302 | )); | |
303 | $this->assertEquals('uninstalled', $manager->getStatus('test.whiz.bang')); | |
304 | $this->assertEquals('oddball', $this->mapper->keyToInfo('test.whiz.bang')->file); | |
305 | ||
306 | $manager->install(array('test.whiz.bang')); | |
307 | $this->assertEquals('installed', $manager->getStatus('test.whiz.bang')); | |
308 | $this->assertEquals('oddball', $this->mapper->keyToInfo('test.whiz.bang')->file); | |
309 | $this->assertDBQuery('oddball', 'SELECT file FROM civicrm_extension WHERE full_name ="test.whiz.bang"'); | |
310 | ||
311 | $this->download = $this->_createDownload('test.whiz.bang', 'newextension'); | |
312 | ||
313 | $testingTypeManager | |
314 | ->expects($this->once()) | |
315 | ->method('onPreReplace'); | |
316 | $testingTypeManager | |
317 | ->expects($this->once()) | |
318 | ->method('onPostReplace'); | |
319 | $manager->replace($this->download); | |
320 | $this->assertEquals('installed', $manager->getStatus('test.whiz.bang')); | |
321 | $this->assertTrue(file_exists("{$this->basedir}/weird/whizbang/info.xml")); | |
322 | $this->assertTrue(file_exists("{$this->basedir}/weird/whizbang/newextension.php")); | |
323 | $this->assertFalse(file_exists("{$this->basedir}/weird/whizbang/oddball.php")); | |
324 | $this->assertEquals('newextension', $this->mapper->keyToInfo('test.whiz.bang')->file); | |
325 | $this->assertDBQuery('newextension', 'SELECT file FROM civicrm_extension WHERE full_name ="test.whiz.bang"'); | |
326 | } | |
327 | ||
328 | /** | |
329 | * Install a module and then delete (leaving stale DB info); restore | |
330 | * the module by downloading new code. | |
331 | * | |
332 | * Note that some metadata changes between versions -- the original has | |
333 | * file="oddball", and the upgrade has file="newextension". | |
334 | */ | |
335 | function testReplace_InstalledMissing() { | |
336 | $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface'); | |
337 | $manager = $this->_createManager(array( | |
338 | self::TESTING_TYPE => $testingTypeManager, | |
339 | )); | |
340 | ||
341 | // initial installation | |
342 | $this->assertEquals('uninstalled', $manager->getStatus('test.whiz.bang')); | |
343 | $manager->install(array('test.whiz.bang')); | |
344 | $this->assertEquals('installed', $manager->getStatus('test.whiz.bang')); | |
345 | ||
346 | // dirty remove | |
347 | $this->assertTrue(file_exists("{$this->basedir}/weird/whizbang/info.xml")); | |
348 | CRM_Utils_File::cleanDir("{$this->basedir}/weird/whizbang", TRUE, FALSE); | |
349 | $this->assertFalse(file_exists("{$this->basedir}/weird/whizbang/info.xml")); | |
350 | $manager->refresh(); | |
351 | $this->assertEquals('installed-missing', $manager->getStatus('test.whiz.bang')); | |
352 | ||
353 | // download and reinstall | |
354 | $this->download = $this->_createDownload('test.whiz.bang', 'newextension'); | |
355 | ||
356 | $testingTypeManager | |
357 | ->expects($this->once()) | |
358 | ->method('onPreReplace'); | |
359 | $testingTypeManager | |
360 | ->expects($this->once()) | |
361 | ->method('onPostReplace'); | |
362 | $manager->replace($this->download); | |
363 | $this->assertEquals('installed', $manager->getStatus('test.whiz.bang')); | |
364 | $this->assertTrue(file_exists("{$this->basedir}/test.whiz.bang/info.xml")); | |
365 | $this->assertTrue(file_exists("{$this->basedir}/test.whiz.bang/newextension.php")); | |
366 | $this->assertEquals('newextension', $this->mapper->keyToInfo('test.whiz.bang')->file); | |
367 | $this->assertDBQuery('newextension', 'SELECT file FROM civicrm_extension WHERE full_name ="test.whiz.bang"'); | |
368 | } | |
369 | ||
370 | function _createManager($typeManagers) { | |
371 | //list ($basedir, $c) = $this->_createContainer(); | |
372 | $mapper = new CRM_Extension_Mapper($this->container); | |
373 | return new CRM_Extension_Manager($this->container, $this->container, $this->mapper, $typeManagers); | |
374 | } | |
375 | ||
376 | function _createContainer(CRM_Utils_Cache_Interface $cache = NULL, $cacheKey = NULL) { | |
377 | $basedir = $this->createTempDir('ext-'); | |
378 | mkdir("$basedir/weird"); | |
379 | mkdir("$basedir/weird/foobar"); | |
380 | file_put_contents("$basedir/weird/foobar/info.xml", "<extension key='test.foo.bar' type='".self::TESTING_TYPE."'><file>oddball</file></extension>"); | |
381 | // not needed for now // file_put_contents("$basedir/weird/bar/oddball.php", "<?php\n"); | |
382 | mkdir("$basedir/weird/whizbang"); | |
383 | file_put_contents("$basedir/weird/whizbang/info.xml", "<extension key='test.whiz.bang' type='".self::TESTING_TYPE."'><file>oddball</file></extension>"); | |
384 | // not needed for now // file_put_contents("$basedir/weird/whizbang/oddball.php", "<?php\n"); | |
385 | $c = new CRM_Extension_Container_Basic($basedir, 'http://example/basedir', $cache, $cacheKey); | |
386 | return array($basedir, $c); | |
387 | } | |
388 | ||
389 | function _createDownload($key, $file) { | |
390 | $basedir = $this->createTempDir('ext-dl-'); | |
391 | file_put_contents("$basedir/info.xml", "<extension key='$key' type='".self::TESTING_TYPE."'><file>$file</file></extension>"); | |
392 | file_put_contents("$basedir/$file.php", "<?php\n"); | |
393 | return $basedir; | |
394 | } | |
395 | } |