commiting uncommited changes on live site
[weblabels.fsf.org.git] / crm.fsf.org / 20131203 / files / sites / all / modules-new / civicrm / tests / phpunit / CRM / Extension / ManagerTest.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.6 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2015 |
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 */
27 require_once 'CiviTest/CiviUnitTestCase.php';
28
29 /**
30 * Class CRM_Extension_ManagerTest
31 */
32 class CRM_Extension_ManagerTest extends CiviUnitTestCase {
33 const TESTING_TYPE = 'report';
34 const OTHER_TESTING_TYPE = 'module';
35
36 public function setUp() {
37 parent::setUp();
38 list ($this->basedir, $this->container) = $this->_createContainer();
39 $this->mapper = new CRM_Extension_Mapper($this->container);
40 }
41
42 public function tearDown() {
43 parent::tearDown();
44 }
45
46 /**
47 * Install an extension with an invalid type name.
48 *
49 * @expectedException CRM_Extension_Exception
50 */
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,
57 ));
58 $manager->install(array('test.foo.bar'));
59 }
60
61 /**
62 * Install an extension with a valid type name.
63 *
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".
67 */
68 public function testInstall_Disable_Uninstall() {
69 $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface');
70 $manager = $this->_createManager(array(
71 self::TESTING_TYPE => $testingTypeManager,
72 ));
73 $this->assertEquals('uninstalled', $manager->getStatus('test.foo.bar'));
74 $this->assertEquals('uninstalled', $manager->getStatus('test.whiz.bang'));
75
76 $testingTypeManager
77 ->expects($this->exactly(2))
78 ->method('onPreInstall');
79 $testingTypeManager
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'));
85
86 $testingTypeManager
87 ->expects($this->once())
88 ->method('onPreDisable');
89 $testingTypeManager
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
95
96 $testingTypeManager
97 ->expects($this->once())
98 ->method('onPreUninstall');
99 $testingTypeManager
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
105 }
106
107 /**
108 * Install an extension and then harshly remove the underlying source.
109 * Subseuently disable and uninstall.
110 */
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,
115 ));
116 $this->assertEquals('uninstalled', $manager->getStatus('test.foo.bar'));
117
118 $manager->install(array('test.foo.bar'));
119 $this->assertEquals('installed', $manager->getStatus('test.foo.bar'));
120
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"));
124 $manager->refresh();
125 $this->assertEquals('installed-missing', $manager->getStatus('test.foo.bar'));
126
127 $testingTypeManager
128 ->expects($this->once())
129 ->method('onPreDisable');
130 $testingTypeManager
131 ->expects($this->once())
132 ->method('onPostDisable');
133 $manager->disable(array('test.foo.bar'));
134 $this->assertEquals('disabled-missing', $manager->getStatus('test.foo.bar'));
135
136 $testingTypeManager
137 ->expects($this->once())
138 ->method('onPreUninstall');
139 $testingTypeManager
140 ->expects($this->once())
141 ->method('onPostUninstall');
142 $manager->uninstall(array('test.foo.bar'));
143 $this->assertEquals('unknown', $manager->getStatus('test.foo.bar'));
144 }
145
146 /**
147 * Install an extension with a valid type name.
148 */
149 public function testInstall_Disable_Enable() {
150 $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface');
151 $manager = $this->_createManager(array(
152 self::TESTING_TYPE => $testingTypeManager,
153 ));
154 $this->assertEquals('uninstalled', $manager->getStatus('test.foo.bar'));
155 $this->assertEquals('uninstalled', $manager->getStatus('test.whiz.bang'));
156
157 $testingTypeManager
158 ->expects($this->exactly(2))
159 ->method('onPreInstall');
160 $testingTypeManager
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'));
166
167 $testingTypeManager
168 ->expects($this->once())
169 ->method('onPreDisable');
170 $testingTypeManager
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'));
176
177 $testingTypeManager
178 ->expects($this->once())
179 ->method('onPreEnable');
180 $testingTypeManager
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'));
186 }
187
188 /**
189 * Performing 'install' on a 'disabled' extension performs an 'enable'
190 */
191 public function testInstall_Disable_Install() {
192 $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface');
193 $manager = $this->_createManager(array(
194 self::TESTING_TYPE => $testingTypeManager,
195 ));
196 $this->assertEquals('uninstalled', $manager->getStatus('test.foo.bar'));
197
198 $testingTypeManager
199 ->expects($this->once())
200 ->method('onPreInstall');
201 $testingTypeManager
202 ->expects($this->once())
203 ->method('onPostInstall');
204 $manager->install(array('test.foo.bar'));
205 $this->assertEquals('installed', $manager->getStatus('test.foo.bar'));
206
207 $testingTypeManager
208 ->expects($this->once())
209 ->method('onPreDisable');
210 $testingTypeManager
211 ->expects($this->once())
212 ->method('onPostDisable');
213 $manager->disable(array('test.foo.bar'));
214 $this->assertEquals('disabled', $manager->getStatus('test.foo.bar'));
215
216 $testingTypeManager
217 ->expects($this->once())
218 ->method('onPreEnable');
219 $testingTypeManager
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'));
224 }
225
226 /**
227 * Install an extension with a valid type name.
228 */
229 public function testEnableBare() {
230 $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface');
231 $manager = $this->_createManager(array(
232 self::TESTING_TYPE => $testingTypeManager,
233 ));
234 $this->assertEquals('uninstalled', $manager->getStatus('test.foo.bar'));
235
236 $testingTypeManager
237 ->expects($this->once())
238 ->method('onPreInstall');
239 $testingTypeManager
240 ->expects($this->once())
241 ->method('onPostInstall');
242 $testingTypeManager
243 ->expects($this->never())
244 ->method('onPreEnable');
245 $testingTypeManager
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'));
250 }
251
252 /**
253 * Get the status of an unknown extension.
254 */
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,
261 ));
262 $this->assertEquals('unknown', $manager->getStatus('test.foo.bar.whiz.bang'));
263 }
264
265 /**
266 * Replace code for an extension that doesn't exist in the container
267 */
268 public function testReplace_Unknown() {
269 $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface');
270 $manager = $this->_createManager(array(
271 self::TESTING_TYPE => $testingTypeManager,
272 ));
273 $this->assertEquals('unknown', $manager->getStatus('test.newextension'));
274
275 $this->download = $this->_createDownload('test.newextension', '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.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);
289 }
290
291 /**
292 * Replace code for an extension that doesn't exist in the container
293 */
294 public function testReplace_Uninstalled() {
295 $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface');
296 $manager = $this->_createManager(array(
297 self::TESTING_TYPE => $testingTypeManager,
298 ));
299 $this->assertEquals('uninstalled', $manager->getStatus('test.whiz.bang'));
300 $this->assertEquals('oddball', $this->mapper->keyToInfo('test.whiz.bang')->file);
301
302 $this->download = $this->_createDownload('test.whiz.bang', 'newextension');
303
304 $testingTypeManager
305 ->expects($this->never())// no data to replace
306 ->method('onPreReplace');
307 $testingTypeManager
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);
317 }
318
319 /**
320 * Install a module and then replace it with new code.
321 *
322 * Note that some metadata changes between versions -- the original has
323 * file="oddball", and the upgrade has file="newextension".
324 */
325 public function testReplace_Installed() {
326 $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface');
327 $manager = $this->_createManager(array(
328 self::TESTING_TYPE => $testingTypeManager,
329 ));
330 $this->assertEquals('uninstalled', $manager->getStatus('test.whiz.bang'));
331 $this->assertEquals('oddball', $this->mapper->keyToInfo('test.whiz.bang')->file);
332
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"');
337
338 $this->download = $this->_createDownload('test.whiz.bang', 'newextension');
339
340 $testingTypeManager
341 ->expects($this->once())
342 ->method('onPreReplace');
343 $testingTypeManager
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"');
353 }
354
355 /**
356 * Install a module and then delete (leaving stale DB info); restore
357 * the module by downloading new code.
358 *
359 * Note that some metadata changes between versions -- the original has
360 * file="oddball", and the upgrade has file="newextension".
361 */
362 public function testReplace_InstalledMissing() {
363 $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface');
364 $manager = $this->_createManager(array(
365 self::TESTING_TYPE => $testingTypeManager,
366 ));
367
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'));
372
373 // dirty remove
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"));
377 $manager->refresh();
378 $this->assertEquals('installed-missing', $manager->getStatus('test.whiz.bang'));
379
380 // download and reinstall
381 $this->download = $this->_createDownload('test.whiz.bang', 'newextension');
382
383 $testingTypeManager
384 ->expects($this->once())
385 ->method('onPreReplace');
386 $testingTypeManager
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"');
395 }
396
397 /**
398 * @param $typeManagers
399 *
400 * @return CRM_Extension_Manager
401 */
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);
406 }
407
408 /**
409 * @param CRM_Utils_Cache_Interface $cache
410 * @param null $cacheKey
411 *
412 * @return array
413 */
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);
425 }
426
427 /**
428 * @param $key
429 * @param $file
430 *
431 * @return string
432 */
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");
437 return $basedir;
438 }
439
440 }