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