Commit | Line | Data |
---|---|---|
6a488035 | 1 | <?php |
b6708aeb | 2 | /* |
3 | +--------------------------------------------------------------------+ | |
81621fee | 4 | | CiviCRM version 4.7 | |
b6708aeb | 5 | +--------------------------------------------------------------------+ |
e7112fa7 | 6 | | Copyright CiviCRM LLC (c) 2004-2015 | |
b6708aeb | 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 | +--------------------------------------------------------------------+ | |
e70a7fc0 | 26 | */ |
6a488035 | 27 | |
e9479dcf EM |
28 | /** |
29 | * Class CRM_Extension_ManagerTest | |
acb109b7 | 30 | * @group headless |
e9479dcf | 31 | */ |
6a488035 TO |
32 | class CRM_Extension_ManagerTest extends CiviUnitTestCase { |
33 | const TESTING_TYPE = 'report'; | |
34 | const OTHER_TESTING_TYPE = 'module'; | |
35 | ||
00be9182 | 36 | public function setUp() { |
6a488035 TO |
37 | parent::setUp(); |
38 | list ($this->basedir, $this->container) = $this->_createContainer(); | |
39 | $this->mapper = new CRM_Extension_Mapper($this->container); | |
40 | } | |
41 | ||
00be9182 | 42 | public function tearDown() { |
6a488035 TO |
43 | parent::tearDown(); |
44 | } | |
45 | ||
46 | /** | |
eceb18cc | 47 | * Install an extension with an invalid type name. |
6a488035 TO |
48 | * |
49 | * @expectedException CRM_Extension_Exception | |
50 | */ | |
00be9182 | 51 | public function testInstallInvalidType() { |
6a488035 TO |
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 | /** | |
eceb18cc | 62 | * Install an extension with a valid type name. |
6a488035 TO |
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 | */ | |
00be9182 | 68 | public function testInstall_Disable_Uninstall() { |
6a488035 TO |
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 | */ | |
00be9182 | 111 | public function testInstall_DirtyRemove_Disable_Uninstall() { |
6a488035 TO |
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 | /** | |
eceb18cc | 147 | * Install an extension with a valid type name. |
6a488035 | 148 | */ |
00be9182 | 149 | public function testInstall_Disable_Enable() { |
6a488035 TO |
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 | */ | |
00be9182 | 191 | public function testInstall_Disable_Install() { |
6a488035 TO |
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 | /** | |
eceb18cc | 227 | * Install an extension with a valid type name. |
6a488035 | 228 | */ |
00be9182 | 229 | public function testEnableBare() { |
6a488035 TO |
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 | /** | |
eceb18cc | 253 | * Get the status of an unknown extension. |
6a488035 | 254 | */ |
00be9182 | 255 | public function testStatusUnknownKey() { |
6a488035 TO |
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 | */ | |
00be9182 | 268 | public function testReplace_Unknown() { |
6a488035 TO |
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 | |
92915c55 | 278 | ->expects($this->never())// no data to replace |
6a488035 TO |
279 | ->method('onPreReplace'); |
280 | $testingTypeManager | |
92915c55 | 281 | ->expects($this->never())// no data to replace |
6a488035 TO |
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 | */ | |
00be9182 | 294 | public function testReplace_Uninstalled() { |
6a488035 TO |
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 | |
92915c55 | 305 | ->expects($this->never())// no data to replace |
6a488035 TO |
306 | ->method('onPreReplace'); |
307 | $testingTypeManager | |
92915c55 | 308 | ->expects($this->never())// no data to replace |
6a488035 TO |
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 | /** | |
eceb18cc | 320 | * Install a module and then replace it with new code. |
6a488035 TO |
321 | * |
322 | * Note that some metadata changes between versions -- the original has | |
323 | * file="oddball", and the upgrade has file="newextension". | |
324 | */ | |
00be9182 | 325 | public function testReplace_Installed() { |
6a488035 TO |
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 | */ | |
00be9182 | 362 | public function testReplace_InstalledMissing() { |
6a488035 TO |
363 | $testingTypeManager = $this->getMock('CRM_Extension_Manager_Interface'); |
364 | $manager = $this->_createManager(array( | |
365 | self::TESTING_TYPE => $testingTypeManager, | |
366 | )); | |
b6708aeb | 367 | |
6a488035 TO |
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 | ||
4cbe18b8 EM |
397 | /** |
398 | * @param $typeManagers | |
399 | * | |
400 | * @return CRM_Extension_Manager | |
401 | */ | |
00be9182 | 402 | public function _createManager($typeManagers) { |
6a488035 TO |
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 | ||
4cbe18b8 EM |
408 | /** |
409 | * @param CRM_Utils_Cache_Interface $cache | |
410 | * @param null $cacheKey | |
411 | * | |
412 | * @return array | |
413 | */ | |
00be9182 | 414 | public function _createContainer(CRM_Utils_Cache_Interface $cache = NULL, $cacheKey = NULL) { |
6a488035 TO |
415 | $basedir = $this->createTempDir('ext-'); |
416 | mkdir("$basedir/weird"); | |
417 | mkdir("$basedir/weird/foobar"); | |
92fcb95f | 418 | file_put_contents("$basedir/weird/foobar/info.xml", "<extension key='test.foo.bar' type='" . self::TESTING_TYPE . "'><file>oddball</file></extension>"); |
6a488035 TO |
419 | // not needed for now // file_put_contents("$basedir/weird/bar/oddball.php", "<?php\n"); |
420 | mkdir("$basedir/weird/whizbang"); | |
92fcb95f | 421 | file_put_contents("$basedir/weird/whizbang/info.xml", "<extension key='test.whiz.bang' type='" . self::TESTING_TYPE . "'><file>oddball</file></extension>"); |
6a488035 TO |
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 | ||
4cbe18b8 EM |
427 | /** |
428 | * @param $key | |
429 | * @param $file | |
430 | * | |
431 | * @return string | |
432 | */ | |
00be9182 | 433 | public function _createDownload($key, $file) { |
6a488035 | 434 | $basedir = $this->createTempDir('ext-dl-'); |
92fcb95f | 435 | file_put_contents("$basedir/info.xml", "<extension key='$key' type='" . self::TESTING_TYPE . "'><file>$file</file></extension>"); |
6a488035 TO |
436 | file_put_contents("$basedir/$file.php", "<?php\n"); |
437 | return $basedir; | |
438 | } | |
96025800 | 439 | |
6a488035 | 440 | } |