3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.4 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2013 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
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. |
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. |
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 +--------------------------------------------------------------------+
27 require_once 'CiviTest/CiviUnitTestCase.php';
29 class CRM_Extension_ManagerTest
extends CiviUnitTestCase
{
30 const TESTING_TYPE
= 'report';
31 const OTHER_TESTING_TYPE
= 'module';
35 list ($this->basedir
, $this->container
) = $this->_createContainer();
36 $this->mapper
= new CRM_Extension_Mapper($this->container
);
44 * Install an extension with an invalid type name
46 * @expectedException CRM_Extension_Exception
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,
55 $manager->install(array('test.foo.bar'));
59 * Install an extension with a valid type name
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".
65 function testInstall_Disable_Uninstall() {
66 $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface');
67 $manager = $this->_createManager(array(
68 self
::TESTING_TYPE
=> $testingTypeManager,
70 $this->assertEquals('uninstalled', $manager->getStatus('test.foo.bar'));
71 $this->assertEquals('uninstalled', $manager->getStatus('test.whiz.bang'));
74 ->expects($this->exactly(2))
75 ->method('onPreInstall');
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'));
84 ->expects($this->once())
85 ->method('onPreDisable');
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
94 ->expects($this->once())
95 ->method('onPreUninstall');
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
105 * Install an extension and then harshly remove the underlying source.
106 * Subseuently disable and uninstall.
108 function testInstall_DirtyRemove_Disable_Uninstall() {
109 $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface');
110 $manager = $this->_createManager(array(
111 self
::TESTING_TYPE
=> $testingTypeManager,
113 $this->assertEquals('uninstalled', $manager->getStatus('test.foo.bar'));
115 $manager->install(array('test.foo.bar'));
116 $this->assertEquals('installed', $manager->getStatus('test.foo.bar'));
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"));
122 $this->assertEquals('installed-missing', $manager->getStatus('test.foo.bar'));
125 ->expects($this->once())
126 ->method('onPreDisable');
128 ->expects($this->once())
129 ->method('onPostDisable');
130 $manager->disable(array('test.foo.bar'));
131 $this->assertEquals('disabled-missing', $manager->getStatus('test.foo.bar'));
134 ->expects($this->once())
135 ->method('onPreUninstall');
137 ->expects($this->once())
138 ->method('onPostUninstall');
139 $manager->uninstall(array('test.foo.bar'));
140 $this->assertEquals('unknown', $manager->getStatus('test.foo.bar'));
144 * Install an extension with a valid type name
146 function testInstall_Disable_Enable() {
147 $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface');
148 $manager = $this->_createManager(array(
149 self
::TESTING_TYPE
=> $testingTypeManager,
151 $this->assertEquals('uninstalled', $manager->getStatus('test.foo.bar'));
152 $this->assertEquals('uninstalled', $manager->getStatus('test.whiz.bang'));
155 ->expects($this->exactly(2))
156 ->method('onPreInstall');
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'));
165 ->expects($this->once())
166 ->method('onPreDisable');
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'));
175 ->expects($this->once())
176 ->method('onPreEnable');
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'));
186 * Performing 'install' on a 'disabled' extension performs an 'enable'
188 function testInstall_Disable_Install() {
189 $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface');
190 $manager = $this->_createManager(array(
191 self
::TESTING_TYPE
=> $testingTypeManager,
193 $this->assertEquals('uninstalled', $manager->getStatus('test.foo.bar'));
196 ->expects($this->once())
197 ->method('onPreInstall');
199 ->expects($this->once())
200 ->method('onPostInstall');
201 $manager->install(array('test.foo.bar'));
202 $this->assertEquals('installed', $manager->getStatus('test.foo.bar'));
205 ->expects($this->once())
206 ->method('onPreDisable');
208 ->expects($this->once())
209 ->method('onPostDisable');
210 $manager->disable(array('test.foo.bar'));
211 $this->assertEquals('disabled', $manager->getStatus('test.foo.bar'));
214 ->expects($this->once())
215 ->method('onPreEnable');
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'));
224 * Install an extension with a valid type name
226 function testEnableBare() {
227 $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface');
228 $manager = $this->_createManager(array(
229 self
::TESTING_TYPE
=> $testingTypeManager,
231 $this->assertEquals('uninstalled', $manager->getStatus('test.foo.bar'));
234 ->expects($this->once())
235 ->method('onPreInstall');
237 ->expects($this->once())
238 ->method('onPostInstall');
240 ->expects($this->never())
241 ->method('onPreEnable');
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'));
250 * Get the status of an unknown extension
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,
259 $this->assertEquals('unknown', $manager->getStatus('test.foo.bar.whiz.bang'));
263 * Replace code for an extension that doesn't exist in the container
265 function testReplace_Unknown() {
266 $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface');
267 $manager = $this->_createManager(array(
268 self
::TESTING_TYPE
=> $testingTypeManager,
270 $this->assertEquals('unknown', $manager->getStatus('test.newextension'));
272 $this->download
= $this->_createDownload('test.newextension', 'newextension');
275 ->expects($this->never()) // no data to replace
276 ->method('onPreReplace');
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
);
289 * Replace code for an extension that doesn't exist in the container
291 function testReplace_Uninstalled() {
292 $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface');
293 $manager = $this->_createManager(array(
294 self
::TESTING_TYPE
=> $testingTypeManager,
296 $this->assertEquals('uninstalled', $manager->getStatus('test.whiz.bang'));
297 $this->assertEquals('oddball', $this->mapper
->keyToInfo('test.whiz.bang')->file
);
299 $this->download
= $this->_createDownload('test.whiz.bang', 'newextension');
302 ->expects($this->never()) // no data to replace
303 ->method('onPreReplace');
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
);
317 * Install a module and then replace it with new code
319 * Note that some metadata changes between versions -- the original has
320 * file="oddball", and the upgrade has file="newextension".
322 function testReplace_Installed() {
323 $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface');
324 $manager = $this->_createManager(array(
325 self
::TESTING_TYPE
=> $testingTypeManager,
327 $this->assertEquals('uninstalled', $manager->getStatus('test.whiz.bang'));
328 $this->assertEquals('oddball', $this->mapper
->keyToInfo('test.whiz.bang')->file
);
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"');
335 $this->download
= $this->_createDownload('test.whiz.bang', 'newextension');
338 ->expects($this->once())
339 ->method('onPreReplace');
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"');
353 * Install a module and then delete (leaving stale DB info); restore
354 * the module by downloading new code.
356 * Note that some metadata changes between versions -- the original has
357 * file="oddball", and the upgrade has file="newextension".
359 function testReplace_InstalledMissing() {
360 $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface');
361 $manager = $this->_createManager(array(
362 self
::TESTING_TYPE
=> $testingTypeManager,
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'));
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"));
375 $this->assertEquals('installed-missing', $manager->getStatus('test.whiz.bang'));
377 // download and reinstall
378 $this->download
= $this->_createDownload('test.whiz.bang', 'newextension');
381 ->expects($this->once())
382 ->method('onPreReplace');
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"');
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);
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);
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");