3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.7 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2015 |
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 +--------------------------------------------------------------------+
29 * Class CRM_Extension_ManagerTest
32 class CRM_Extension_ManagerTest
extends CiviUnitTestCase
{
33 const TESTING_TYPE
= 'report';
34 const OTHER_TESTING_TYPE
= 'module';
36 public function setUp() {
38 list ($this->basedir
, $this->container
) = $this->_createContainer();
39 $this->mapper
= new CRM_Extension_Mapper($this->container
);
42 public function tearDown() {
47 * Install an extension with an invalid type name.
49 * @expectedException CRM_Extension_Exception
51 public function testInstallInvalidType() {
52 $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface');
53 $testingTypeManager->expects($this->never())
54 ->method('onPreInstall');
55 $manager = $this->_createManager(array(
56 self
::OTHER_TESTING_TYPE
=> $testingTypeManager,
58 $manager->install(array('test.foo.bar'));
62 * Install an extension with a valid type name.
64 * Note: We initially install two extensions but then toggle only
65 * the second. This controls for bad SQL queries which hit either
66 * "the first row" or "all rows".
68 public function testInstall_Disable_Uninstall() {
69 $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface');
70 $manager = $this->_createManager(array(
71 self
::TESTING_TYPE
=> $testingTypeManager,
73 $this->assertEquals('uninstalled', $manager->getStatus('test.foo.bar'));
74 $this->assertEquals('uninstalled', $manager->getStatus('test.whiz.bang'));
77 ->expects($this->exactly(2))
78 ->method('onPreInstall');
80 ->expects($this->exactly(2))
81 ->method('onPostInstall');
82 $manager->install(array('test.whiz.bang', 'test.foo.bar'));
83 $this->assertEquals('installed', $manager->getStatus('test.foo.bar'));
84 $this->assertEquals('installed', $manager->getStatus('test.whiz.bang'));
87 ->expects($this->once())
88 ->method('onPreDisable');
90 ->expects($this->once())
91 ->method('onPostDisable');
92 $manager->disable(array('test.foo.bar'));
93 $this->assertEquals('disabled', $manager->getStatus('test.foo.bar'));
94 $this->assertEquals('installed', $manager->getStatus('test.whiz.bang')); // no side-effect
97 ->expects($this->once())
98 ->method('onPreUninstall');
100 ->expects($this->once())
101 ->method('onPostUninstall');
102 $manager->uninstall(array('test.foo.bar'));
103 $this->assertEquals('uninstalled', $manager->getStatus('test.foo.bar'));
104 $this->assertEquals('installed', $manager->getStatus('test.whiz.bang')); // no side-effect
108 * Install an extension and then harshly remove the underlying source.
109 * Subseuently disable and uninstall.
111 public function testInstall_DirtyRemove_Disable_Uninstall() {
112 $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface');
113 $manager = $this->_createManager(array(
114 self
::TESTING_TYPE
=> $testingTypeManager,
116 $this->assertEquals('uninstalled', $manager->getStatus('test.foo.bar'));
118 $manager->install(array('test.foo.bar'));
119 $this->assertEquals('installed', $manager->getStatus('test.foo.bar'));
121 $this->assertTrue(file_exists("{$this->basedir}/weird/foobar/info.xml"));
122 CRM_Utils_File
::cleanDir("{$this->basedir}/weird/foobar", TRUE, FALSE);
123 $this->assertFalse(file_exists("{$this->basedir}/weird/foobar/info.xml"));
125 $this->assertEquals('installed-missing', $manager->getStatus('test.foo.bar'));
128 ->expects($this->once())
129 ->method('onPreDisable');
131 ->expects($this->once())
132 ->method('onPostDisable');
133 $manager->disable(array('test.foo.bar'));
134 $this->assertEquals('disabled-missing', $manager->getStatus('test.foo.bar'));
137 ->expects($this->once())
138 ->method('onPreUninstall');
140 ->expects($this->once())
141 ->method('onPostUninstall');
142 $manager->uninstall(array('test.foo.bar'));
143 $this->assertEquals('unknown', $manager->getStatus('test.foo.bar'));
147 * Install an extension with a valid type name.
149 public function testInstall_Disable_Enable() {
150 $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface');
151 $manager = $this->_createManager(array(
152 self
::TESTING_TYPE
=> $testingTypeManager,
154 $this->assertEquals('uninstalled', $manager->getStatus('test.foo.bar'));
155 $this->assertEquals('uninstalled', $manager->getStatus('test.whiz.bang'));
158 ->expects($this->exactly(2))
159 ->method('onPreInstall');
161 ->expects($this->exactly(2))
162 ->method('onPostInstall');
163 $manager->install(array('test.whiz.bang', 'test.foo.bar'));
164 $this->assertEquals('installed', $manager->getStatus('test.foo.bar'));
165 $this->assertEquals('installed', $manager->getStatus('test.whiz.bang'));
168 ->expects($this->once())
169 ->method('onPreDisable');
171 ->expects($this->once())
172 ->method('onPostDisable');
173 $manager->disable(array('test.foo.bar'));
174 $this->assertEquals('disabled', $manager->getStatus('test.foo.bar'));
175 $this->assertEquals('installed', $manager->getStatus('test.whiz.bang'));
178 ->expects($this->once())
179 ->method('onPreEnable');
181 ->expects($this->once())
182 ->method('onPostEnable');
183 $manager->enable(array('test.foo.bar'));
184 $this->assertEquals('installed', $manager->getStatus('test.foo.bar'));
185 $this->assertEquals('installed', $manager->getStatus('test.whiz.bang'));
189 * Performing 'install' on a 'disabled' extension performs an 'enable'
191 public function testInstall_Disable_Install() {
192 $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface');
193 $manager = $this->_createManager(array(
194 self
::TESTING_TYPE
=> $testingTypeManager,
196 $this->assertEquals('uninstalled', $manager->getStatus('test.foo.bar'));
199 ->expects($this->once())
200 ->method('onPreInstall');
202 ->expects($this->once())
203 ->method('onPostInstall');
204 $manager->install(array('test.foo.bar'));
205 $this->assertEquals('installed', $manager->getStatus('test.foo.bar'));
208 ->expects($this->once())
209 ->method('onPreDisable');
211 ->expects($this->once())
212 ->method('onPostDisable');
213 $manager->disable(array('test.foo.bar'));
214 $this->assertEquals('disabled', $manager->getStatus('test.foo.bar'));
217 ->expects($this->once())
218 ->method('onPreEnable');
220 ->expects($this->once())
221 ->method('onPostEnable');
222 $manager->install(array('test.foo.bar')); // install() instead of enable()
223 $this->assertEquals('installed', $manager->getStatus('test.foo.bar'));
227 * Install an extension with a valid type name.
229 public function testEnableBare() {
230 $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface');
231 $manager = $this->_createManager(array(
232 self
::TESTING_TYPE
=> $testingTypeManager,
234 $this->assertEquals('uninstalled', $manager->getStatus('test.foo.bar'));
237 ->expects($this->once())
238 ->method('onPreInstall');
240 ->expects($this->once())
241 ->method('onPostInstall');
243 ->expects($this->never())
244 ->method('onPreEnable');
246 ->expects($this->never())
247 ->method('onPostEnable');
248 $manager->enable(array('test.foo.bar')); // enable not install
249 $this->assertEquals('installed', $manager->getStatus('test.foo.bar'));
253 * Get the status of an unknown extension.
255 public function testStatusUnknownKey() {
256 $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface');
257 $testingTypeManager->expects($this->never())
258 ->method('onPreInstall');
259 $manager = $this->_createManager(array(
260 self
::TESTING_TYPE
=> $testingTypeManager,
262 $this->assertEquals('unknown', $manager->getStatus('test.foo.bar.whiz.bang'));
266 * Replace code for an extension that doesn't exist in the container
268 public function testReplace_Unknown() {
269 $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface');
270 $manager = $this->_createManager(array(
271 self
::TESTING_TYPE
=> $testingTypeManager,
273 $this->assertEquals('unknown', $manager->getStatus('test.newextension'));
275 $this->download
= $this->_createDownload('test.newextension', 'newextension');
278 ->expects($this->never())// no data to replace
279 ->method('onPreReplace');
281 ->expects($this->never())// no data to replace
282 ->method('onPostReplace');
283 $manager->replace($this->download
);
284 $this->assertEquals('uninstalled', $manager->getStatus('test.newextension'));
285 $this->assertTrue(file_exists("{$this->basedir}/test.newextension/info.xml"));
286 $this->assertTrue(file_exists("{$this->basedir}/test.newextension/newextension.php"));
287 $this->assertEquals(self
::TESTING_TYPE
, $this->mapper
->keyToInfo('test.newextension')->type
);
288 $this->assertEquals('newextension', $this->mapper
->keyToInfo('test.newextension')->file
);
292 * Replace code for an extension that doesn't exist in the container
294 public function testReplace_Uninstalled() {
295 $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface');
296 $manager = $this->_createManager(array(
297 self
::TESTING_TYPE
=> $testingTypeManager,
299 $this->assertEquals('uninstalled', $manager->getStatus('test.whiz.bang'));
300 $this->assertEquals('oddball', $this->mapper
->keyToInfo('test.whiz.bang')->file
);
302 $this->download
= $this->_createDownload('test.whiz.bang', 'newextension');
305 ->expects($this->never())// no data to replace
306 ->method('onPreReplace');
308 ->expects($this->never())// no data to replace
309 ->method('onPostReplace');
310 $manager->replace($this->download
);
311 $this->assertEquals('uninstalled', $manager->getStatus('test.whiz.bang'));
312 $this->assertTrue(file_exists("{$this->basedir}/weird/whizbang/info.xml"));
313 $this->assertTrue(file_exists("{$this->basedir}/weird/whizbang/newextension.php"));
314 $this->assertFalse(file_exists("{$this->basedir}/weird/whizbang/oddball.php"));
315 $this->assertEquals(self
::TESTING_TYPE
, $this->mapper
->keyToInfo('test.whiz.bang')->type
);
316 $this->assertEquals('newextension', $this->mapper
->keyToInfo('test.whiz.bang')->file
);
320 * Install a module and then replace it with new code.
322 * Note that some metadata changes between versions -- the original has
323 * file="oddball", and the upgrade has file="newextension".
325 public function testReplace_Installed() {
326 $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface');
327 $manager = $this->_createManager(array(
328 self
::TESTING_TYPE
=> $testingTypeManager,
330 $this->assertEquals('uninstalled', $manager->getStatus('test.whiz.bang'));
331 $this->assertEquals('oddball', $this->mapper
->keyToInfo('test.whiz.bang')->file
);
333 $manager->install(array('test.whiz.bang'));
334 $this->assertEquals('installed', $manager->getStatus('test.whiz.bang'));
335 $this->assertEquals('oddball', $this->mapper
->keyToInfo('test.whiz.bang')->file
);
336 $this->assertDBQuery('oddball', 'SELECT file FROM civicrm_extension WHERE full_name ="test.whiz.bang"');
338 $this->download
= $this->_createDownload('test.whiz.bang', 'newextension');
341 ->expects($this->once())
342 ->method('onPreReplace');
344 ->expects($this->once())
345 ->method('onPostReplace');
346 $manager->replace($this->download
);
347 $this->assertEquals('installed', $manager->getStatus('test.whiz.bang'));
348 $this->assertTrue(file_exists("{$this->basedir}/weird/whizbang/info.xml"));
349 $this->assertTrue(file_exists("{$this->basedir}/weird/whizbang/newextension.php"));
350 $this->assertFalse(file_exists("{$this->basedir}/weird/whizbang/oddball.php"));
351 $this->assertEquals('newextension', $this->mapper
->keyToInfo('test.whiz.bang')->file
);
352 $this->assertDBQuery('newextension', 'SELECT file FROM civicrm_extension WHERE full_name ="test.whiz.bang"');
356 * Install a module and then delete (leaving stale DB info); restore
357 * the module by downloading new code.
359 * Note that some metadata changes between versions -- the original has
360 * file="oddball", and the upgrade has file="newextension".
362 public function testReplace_InstalledMissing() {
363 $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface');
364 $manager = $this->_createManager(array(
365 self
::TESTING_TYPE
=> $testingTypeManager,
368 // initial installation
369 $this->assertEquals('uninstalled', $manager->getStatus('test.whiz.bang'));
370 $manager->install(array('test.whiz.bang'));
371 $this->assertEquals('installed', $manager->getStatus('test.whiz.bang'));
374 $this->assertTrue(file_exists("{$this->basedir}/weird/whizbang/info.xml"));
375 CRM_Utils_File
::cleanDir("{$this->basedir}/weird/whizbang", TRUE, FALSE);
376 $this->assertFalse(file_exists("{$this->basedir}/weird/whizbang/info.xml"));
378 $this->assertEquals('installed-missing', $manager->getStatus('test.whiz.bang'));
380 // download and reinstall
381 $this->download
= $this->_createDownload('test.whiz.bang', 'newextension');
384 ->expects($this->once())
385 ->method('onPreReplace');
387 ->expects($this->once())
388 ->method('onPostReplace');
389 $manager->replace($this->download
);
390 $this->assertEquals('installed', $manager->getStatus('test.whiz.bang'));
391 $this->assertTrue(file_exists("{$this->basedir}/test.whiz.bang/info.xml"));
392 $this->assertTrue(file_exists("{$this->basedir}/test.whiz.bang/newextension.php"));
393 $this->assertEquals('newextension', $this->mapper
->keyToInfo('test.whiz.bang')->file
);
394 $this->assertDBQuery('newextension', 'SELECT file FROM civicrm_extension WHERE full_name ="test.whiz.bang"');
398 * @param $typeManagers
400 * @return CRM_Extension_Manager
402 public function _createManager($typeManagers) {
403 //list ($basedir, $c) = $this->_createContainer();
404 $mapper = new CRM_Extension_Mapper($this->container
);
405 return new CRM_Extension_Manager($this->container
, $this->container
, $this->mapper
, $typeManagers);
409 * @param CRM_Utils_Cache_Interface $cache
410 * @param null $cacheKey
414 public function _createContainer(CRM_Utils_Cache_Interface
$cache = NULL, $cacheKey = NULL) {
415 $basedir = $this->createTempDir('ext-');
416 mkdir("$basedir/weird");
417 mkdir("$basedir/weird/foobar");
418 file_put_contents("$basedir/weird/foobar/info.xml", "<extension key='test.foo.bar' type='" . self
::TESTING_TYPE
. "'><file>oddball</file></extension>");
419 // not needed for now // file_put_contents("$basedir/weird/bar/oddball.php", "<?php\n");
420 mkdir("$basedir/weird/whizbang");
421 file_put_contents("$basedir/weird/whizbang/info.xml", "<extension key='test.whiz.bang' type='" . self
::TESTING_TYPE
. "'><file>oddball</file></extension>");
422 // not needed for now // file_put_contents("$basedir/weird/whizbang/oddball.php", "<?php\n");
423 $c = new CRM_Extension_Container_Basic($basedir, 'http://example/basedir', $cache, $cacheKey);
424 return array($basedir, $c);
433 public function _createDownload($key, $file) {
434 $basedir = $this->createTempDir('ext-dl-');
435 file_put_contents("$basedir/info.xml", "<extension key='$key' type='" . self
::TESTING_TYPE
. "'><file>$file</file></extension>");
436 file_put_contents("$basedir/$file.php", "<?php\n");