Merge pull request #19806 from eileenmcnaughton/msg_compat
[civicrm-core.git] / tests / phpunit / CRM / Extension / ManagerTest.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
5 | |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
10 */
11
12 /**
13 * Class CRM_Extension_ManagerTest
14 * @group headless
15 */
16 class CRM_Extension_ManagerTest extends CiviUnitTestCase {
17 const TESTING_TYPE = 'report';
18 const OTHER_TESTING_TYPE = 'module';
19
20 public function setUp(): void {
21 parent::setUp();
22 list ($this->basedir, $this->container) = $this->_createContainer();
23 $this->mapper = new CRM_Extension_Mapper($this->container);
24 }
25
26 /**
27 * Install an extension with an invalid type name.
28 *
29 * @expectedException CRM_Extension_Exception
30 */
31 public function testInstallInvalidType() {
32 $testingTypeManager = $this->getMockBuilder('CRM_Extension_Manager_Interface')->getMock();
33 $testingTypeManager->expects($this->never())
34 ->method('onPreInstall');
35 $manager = $this->_createManager([
36 self::OTHER_TESTING_TYPE => $testingTypeManager,
37 ]);
38 $manager->install(['test.foo.bar']);
39 }
40
41 /**
42 * Install an extension with a valid type name.
43 *
44 * Note: We initially install two extensions but then toggle only
45 * the second. This controls for bad SQL queries which hit either
46 * "the first row" or "all rows".
47 */
48 public function testInstall_Disable_Uninstall() {
49 $testingTypeManager = $this->getMockBuilder('CRM_Extension_Manager_Interface')->getMock();
50 $manager = $this->_createManager([
51 self::TESTING_TYPE => $testingTypeManager,
52 ]);
53 $this->assertEquals('uninstalled', $manager->getStatus('test.foo.bar'));
54 $this->assertEquals('uninstalled', $manager->getStatus('test.whiz.bang'));
55
56 $testingTypeManager
57 ->expects($this->exactly(2))
58 ->method('onPreInstall');
59 $testingTypeManager
60 ->expects($this->exactly(2))
61 ->method('onPostInstall');
62 $manager->install(['test.whiz.bang', 'test.foo.bar']);
63 $this->assertEquals('installed', $manager->getStatus('test.foo.bar'));
64 $this->assertEquals('installed', $manager->getStatus('test.whiz.bang'));
65
66 $testingTypeManager
67 ->expects($this->once())
68 ->method('onPreDisable');
69 $testingTypeManager
70 ->expects($this->once())
71 ->method('onPostDisable');
72 $manager->disable(['test.foo.bar']);
73 $this->assertEquals('disabled', $manager->getStatus('test.foo.bar'));
74 // no side-effect
75 $this->assertEquals('installed', $manager->getStatus('test.whiz.bang'));
76
77 $testingTypeManager
78 ->expects($this->once())
79 ->method('onPreUninstall');
80 $testingTypeManager
81 ->expects($this->once())
82 ->method('onPostUninstall');
83 $manager->uninstall(['test.foo.bar']);
84 $this->assertEquals('uninstalled', $manager->getStatus('test.foo.bar'));
85 // no side-effect
86 $this->assertEquals('installed', $manager->getStatus('test.whiz.bang'));
87 }
88
89 /**
90 * This is the same as testInstall_Disable_Uninstall, but we also install and remove a dependency.
91 *
92 * @throws \CRM_Extension_Exception
93 */
94 public function test_InstallAuto_DisableDownstream_UninstallDownstream() {
95 $testingTypeManager = $this->getMockBuilder('CRM_Extension_Manager_Interface')->getMock();
96 $manager = $this->_createManager([
97 self::TESTING_TYPE => $testingTypeManager,
98 ]);
99 $this->assertEquals('uninstalled', $manager->getStatus('test.foo.bar'));
100 $this->assertEquals('uninstalled', $manager->getStatus('test.foo.downstream'));
101 $this->assertEquals('uninstalled', $manager->getStatus('test.whiz.bang'));
102
103 $testingTypeManager->expects($this->exactly(2))->method('onPreInstall');
104 $testingTypeManager->expects($this->exactly(2))->method('onPostInstall');
105 $this->assertEquals(['test.foo.bar', 'test.foo.downstream'],
106 $manager->findInstallRequirements(['test.foo.downstream']));
107 $manager->install(
108 $manager->findInstallRequirements(['test.foo.downstream']));
109 $this->assertEquals('installed', $manager->getStatus('test.foo.bar'));
110 $this->assertEquals('installed', $manager->getStatus('test.foo.downstream'));
111 $this->assertEquals('uninstalled', $manager->getStatus('test.whiz.bang'));
112
113 $testingTypeManager->expects($this->once())->method('onPreDisable');
114 $testingTypeManager->expects($this->once())->method('onPostDisable');
115 $this->assertEquals(['test.foo.downstream'],
116 $manager->findDisableRequirements(['test.foo.downstream']));
117 $manager->disable(['test.foo.downstream']);
118 $this->assertEquals('installed', $manager->getStatus('test.foo.bar'));
119 $this->assertEquals('disabled', $manager->getStatus('test.foo.downstream'));
120 $this->assertEquals('uninstalled', $manager->getStatus('test.whiz.bang'));
121
122 $testingTypeManager->expects($this->once())->method('onPreUninstall');
123 $testingTypeManager->expects($this->once())->method('onPostUninstall');
124 $manager->uninstall(['test.foo.downstream']);
125 $this->assertEquals('installed', $manager->getStatus('test.foo.bar'));
126 $this->assertEquals('uninstalled', $manager->getStatus('test.foo.downstream'));
127 $this->assertEquals('uninstalled', $manager->getStatus('test.whiz.bang'));
128 }
129
130 /**
131 * This is the same as testInstallAuto_Twice
132 *
133 * @throws \CRM_Extension_Exception
134 */
135 public function testInstallAuto_Twice() {
136 $testingTypeManager = $this->getMockBuilder('CRM_Extension_Manager_Interface')->getMock();
137 $manager = $this->_createManager([
138 self::TESTING_TYPE => $testingTypeManager,
139 ]);
140 $this->assertEquals('uninstalled', $manager->getStatus('test.foo.bar'));
141 $this->assertEquals('uninstalled', $manager->getStatus('test.foo.downstream'));
142 $this->assertEquals('uninstalled', $manager->getStatus('test.whiz.bang'));
143
144 $testingTypeManager->expects($this->exactly(2))->method('onPreInstall');
145 $testingTypeManager->expects($this->exactly(2))->method('onPostInstall');
146 $this->assertEquals(['test.foo.bar', 'test.foo.downstream'],
147 $manager->findInstallRequirements(['test.foo.downstream']));
148 $manager->install(
149 $manager->findInstallRequirements(['test.foo.downstream']));
150 $this->assertEquals('installed', $manager->getStatus('test.foo.bar'));
151 $this->assertEquals('installed', $manager->getStatus('test.foo.downstream'));
152 $this->assertEquals('uninstalled', $manager->getStatus('test.whiz.bang'));
153
154 // And install a second time...
155 $testingTypeManager->expects($this->exactly(0))->method('onPreInstall');
156 $testingTypeManager->expects($this->exactly(0))->method('onPostInstall');
157 $manager->install(
158 $manager->findInstallRequirements(['test.foo.downstream']));
159 $this->assertEquals('installed', $manager->getStatus('test.foo.bar'));
160 $this->assertEquals('installed', $manager->getStatus('test.foo.downstream'));
161 $this->assertEquals('uninstalled', $manager->getStatus('test.whiz.bang'));
162 }
163
164 public function test_InstallAuto_DisableUpstream() {
165 $testingTypeManager = $this->getMockBuilder('CRM_Extension_Manager_Interface')->getMock();
166 $manager = $this->_createManager([
167 self::TESTING_TYPE => $testingTypeManager,
168 ]);
169 $this->assertEquals('uninstalled', $manager->getStatus('test.foo.bar'));
170 $this->assertEquals('uninstalled', $manager->getStatus('test.foo.downstream'));
171 $this->assertEquals('uninstalled', $manager->getStatus('test.whiz.bang'));
172
173 $testingTypeManager->expects($this->exactly(2))->method('onPreInstall');
174 $testingTypeManager->expects($this->exactly(2))->method('onPostInstall');
175 $this->assertEquals(['test.foo.bar', 'test.foo.downstream'],
176 $manager->findInstallRequirements(['test.foo.downstream']));
177 $manager->install(
178 $manager->findInstallRequirements(['test.foo.downstream']));
179 $this->assertEquals('installed', $manager->getStatus('test.foo.bar'));
180 $this->assertEquals('installed', $manager->getStatus('test.foo.downstream'));
181 $this->assertEquals('uninstalled', $manager->getStatus('test.whiz.bang'));
182
183 $testingTypeManager->expects($this->never())->method('onPreDisable');
184 $testingTypeManager->expects($this->never())->method('onPostDisable');
185 $this->assertEquals(['test.foo.downstream', 'test.foo.bar'],
186 $manager->findDisableRequirements(['test.foo.bar']));
187
188 try {
189 $manager->disable(['test.foo.bar']);
190 $this->fail('Expected disable to fail due to dependency');
191 }
192 catch (CRM_Extension_Exception $e) {
193 $this->assertRegExp('/test.foo.downstream/', $e->getMessage());
194 }
195
196 // Status unchanged
197 $this->assertEquals('installed', $manager->getStatus('test.foo.bar'));
198 $this->assertEquals('installed', $manager->getStatus('test.foo.downstream'));
199 $this->assertEquals('uninstalled', $manager->getStatus('test.whiz.bang'));
200 }
201
202 /**
203 * Install an extension and then harshly remove the underlying source.
204 * Subseuently disable and uninstall.
205 */
206 public function testInstall_DirtyRemove_Disable_Uninstall() {
207 $testingTypeManager = $this->getMockBuilder('CRM_Extension_Manager_Interface')->getMock();
208 $manager = $this->_createManager([
209 self::TESTING_TYPE => $testingTypeManager,
210 ]);
211 $this->assertEquals('uninstalled', $manager->getStatus('test.foo.bar'));
212
213 $manager->install(['test.foo.bar']);
214 $this->assertEquals('installed', $manager->getStatus('test.foo.bar'));
215
216 $this->assertTrue(file_exists("{$this->basedir}/weird/foobar/info.xml"));
217 CRM_Utils_File::cleanDir("{$this->basedir}/weird/foobar", TRUE, FALSE);
218 $this->assertFalse(file_exists("{$this->basedir}/weird/foobar/info.xml"));
219 $manager->refresh();
220 $this->assertEquals('installed-missing', $manager->getStatus('test.foo.bar'));
221
222 $testingTypeManager
223 ->expects($this->once())
224 ->method('onPreDisable');
225 $testingTypeManager
226 ->expects($this->once())
227 ->method('onPostDisable');
228 $manager->disable(['test.foo.bar']);
229 $this->assertEquals('disabled-missing', $manager->getStatus('test.foo.bar'));
230
231 $testingTypeManager
232 ->expects($this->once())
233 ->method('onPreUninstall');
234 $testingTypeManager
235 ->expects($this->once())
236 ->method('onPostUninstall');
237 $manager->uninstall(['test.foo.bar']);
238 $this->assertEquals('unknown', $manager->getStatus('test.foo.bar'));
239 }
240
241 /**
242 * Install an extension with a valid type name.
243 */
244 public function testInstall_Disable_Enable() {
245 $testingTypeManager = $this->getMockBuilder('CRM_Extension_Manager_Interface')->getMock();
246 $manager = $this->_createManager([
247 self::TESTING_TYPE => $testingTypeManager,
248 ]);
249 $this->assertEquals('uninstalled', $manager->getStatus('test.foo.bar'));
250 $this->assertEquals('uninstalled', $manager->getStatus('test.whiz.bang'));
251
252 $testingTypeManager
253 ->expects($this->exactly(2))
254 ->method('onPreInstall');
255 $testingTypeManager
256 ->expects($this->exactly(2))
257 ->method('onPostInstall');
258 $manager->install(['test.whiz.bang', 'test.foo.bar']);
259 $this->assertEquals('installed', $manager->getStatus('test.foo.bar'));
260 $this->assertEquals('installed', $manager->getStatus('test.whiz.bang'));
261
262 $testingTypeManager
263 ->expects($this->once())
264 ->method('onPreDisable');
265 $testingTypeManager
266 ->expects($this->once())
267 ->method('onPostDisable');
268 $manager->disable(['test.foo.bar']);
269 $this->assertEquals('disabled', $manager->getStatus('test.foo.bar'));
270 $this->assertEquals('installed', $manager->getStatus('test.whiz.bang'));
271
272 $testingTypeManager
273 ->expects($this->once())
274 ->method('onPreEnable');
275 $testingTypeManager
276 ->expects($this->once())
277 ->method('onPostEnable');
278 $manager->enable(['test.foo.bar']);
279 $this->assertEquals('installed', $manager->getStatus('test.foo.bar'));
280 $this->assertEquals('installed', $manager->getStatus('test.whiz.bang'));
281 }
282
283 /**
284 * Performing 'install' on a 'disabled' extension performs an 'enable'
285 */
286 public function testInstall_Disable_Install() {
287 $testingTypeManager = $this->getMockBuilder('CRM_Extension_Manager_Interface')->getMock();
288 $manager = $this->_createManager([
289 self::TESTING_TYPE => $testingTypeManager,
290 ]);
291 $this->assertEquals('uninstalled', $manager->getStatus('test.foo.bar'));
292
293 $testingTypeManager
294 ->expects($this->once())
295 ->method('onPreInstall');
296 $testingTypeManager
297 ->expects($this->once())
298 ->method('onPostInstall');
299 $manager->install(['test.foo.bar']);
300 $this->assertEquals('installed', $manager->getStatus('test.foo.bar'));
301
302 $testingTypeManager
303 ->expects($this->once())
304 ->method('onPreDisable');
305 $testingTypeManager
306 ->expects($this->once())
307 ->method('onPostDisable');
308 $manager->disable(['test.foo.bar']);
309 $this->assertEquals('disabled', $manager->getStatus('test.foo.bar'));
310
311 $testingTypeManager
312 ->expects($this->once())
313 ->method('onPreEnable');
314 $testingTypeManager
315 ->expects($this->once())
316 ->method('onPostEnable');
317 // install() instead of enable()
318 $manager->install(['test.foo.bar']);
319 $this->assertEquals('installed', $manager->getStatus('test.foo.bar'));
320 }
321
322 /**
323 * Install an extension with a valid type name.
324 */
325 public function testEnableBare() {
326 $testingTypeManager = $this->getMockBuilder('CRM_Extension_Manager_Interface')->getMock();
327 $manager = $this->_createManager([
328 self::TESTING_TYPE => $testingTypeManager,
329 ]);
330 $this->assertEquals('uninstalled', $manager->getStatus('test.foo.bar'));
331
332 $testingTypeManager
333 ->expects($this->once())
334 ->method('onPreInstall');
335 $testingTypeManager
336 ->expects($this->once())
337 ->method('onPostInstall');
338 $testingTypeManager
339 ->expects($this->never())
340 ->method('onPreEnable');
341 $testingTypeManager
342 ->expects($this->never())
343 ->method('onPostEnable');
344 // enable not install
345 $manager->enable(['test.foo.bar']);
346 $this->assertEquals('installed', $manager->getStatus('test.foo.bar'));
347 }
348
349 /**
350 * Get the status of an unknown extension.
351 */
352 public function testStatusUnknownKey() {
353 $testingTypeManager = $this->getMockBuilder('CRM_Extension_Manager_Interface')->getMock();
354 $testingTypeManager->expects($this->never())
355 ->method('onPreInstall');
356 $manager = $this->_createManager([
357 self::TESTING_TYPE => $testingTypeManager,
358 ]);
359 $this->assertEquals('unknown', $manager->getStatus('test.foo.bar.whiz.bang'));
360 }
361
362 /**
363 * Replace code for an extension that doesn't exist in the container
364 */
365 public function testReplace_Unknown() {
366 $testingTypeManager = $this->getMockBuilder('CRM_Extension_Manager_Interface')->getMock();
367 $manager = $this->_createManager([
368 self::TESTING_TYPE => $testingTypeManager,
369 ]);
370 $this->assertEquals('unknown', $manager->getStatus('test.newextension'));
371
372 $this->download = $this->_createDownload('test.newextension', 'newextension');
373
374 $testingTypeManager
375 // no data to replace
376 ->expects($this->never())
377 ->method('onPreReplace');
378 $testingTypeManager
379 // no data to replace
380 ->expects($this->never())
381 ->method('onPostReplace');
382 $manager->replace($this->download);
383 $this->assertEquals('uninstalled', $manager->getStatus('test.newextension'));
384 $this->assertTrue(file_exists("{$this->basedir}/test.newextension/info.xml"));
385 $this->assertTrue(file_exists("{$this->basedir}/test.newextension/newextension.php"));
386 $this->assertEquals(self::TESTING_TYPE, $this->mapper->keyToInfo('test.newextension')->type);
387 $this->assertEquals('newextension', $this->mapper->keyToInfo('test.newextension')->file);
388 }
389
390 /**
391 * Replace code for an extension that doesn't exist in the container
392 */
393 public function testReplace_Uninstalled() {
394 $testingTypeManager = $this->getMockBuilder('CRM_Extension_Manager_Interface')->getMock();
395 $manager = $this->_createManager([
396 self::TESTING_TYPE => $testingTypeManager,
397 ]);
398 $this->assertEquals('uninstalled', $manager->getStatus('test.whiz.bang'));
399 $this->assertEquals('oddball', $this->mapper->keyToInfo('test.whiz.bang')->file);
400
401 $this->download = $this->_createDownload('test.whiz.bang', 'newextension');
402
403 $testingTypeManager
404 // no data to replace
405 ->expects($this->never())
406 ->method('onPreReplace');
407 $testingTypeManager
408 // no data to replace
409 ->expects($this->never())
410 ->method('onPostReplace');
411 $manager->replace($this->download);
412 $this->assertEquals('uninstalled', $manager->getStatus('test.whiz.bang'));
413 $this->assertTrue(file_exists("{$this->basedir}/weird/whizbang/info.xml"));
414 $this->assertTrue(file_exists("{$this->basedir}/weird/whizbang/newextension.php"));
415 $this->assertFalse(file_exists("{$this->basedir}/weird/whizbang/oddball.php"));
416 $this->assertEquals(self::TESTING_TYPE, $this->mapper->keyToInfo('test.whiz.bang')->type);
417 $this->assertEquals('newextension', $this->mapper->keyToInfo('test.whiz.bang')->file);
418 }
419
420 /**
421 * Install a module and then replace it with new code.
422 *
423 * Note that some metadata changes between versions -- the original has
424 * file="oddball", and the upgrade has file="newextension".
425 */
426 public function testReplace_Installed() {
427 $testingTypeManager = $this->getMockBuilder('CRM_Extension_Manager_Interface')->getMock();
428 $manager = $this->_createManager([
429 self::TESTING_TYPE => $testingTypeManager,
430 ]);
431 $this->assertEquals('uninstalled', $manager->getStatus('test.whiz.bang'));
432 $this->assertEquals('oddball', $this->mapper->keyToInfo('test.whiz.bang')->file);
433
434 $manager->install(['test.whiz.bang']);
435 $this->assertEquals('installed', $manager->getStatus('test.whiz.bang'));
436 $this->assertEquals('oddball', $this->mapper->keyToInfo('test.whiz.bang')->file);
437 $this->assertDBQuery('oddball', 'SELECT file FROM civicrm_extension WHERE full_name ="test.whiz.bang"');
438
439 $this->download = $this->_createDownload('test.whiz.bang', 'newextension');
440
441 $testingTypeManager
442 ->expects($this->once())
443 ->method('onPreReplace');
444 $testingTypeManager
445 ->expects($this->once())
446 ->method('onPostReplace');
447 $manager->replace($this->download);
448 $this->assertEquals('installed', $manager->getStatus('test.whiz.bang'));
449 $this->assertTrue(file_exists("{$this->basedir}/weird/whizbang/info.xml"));
450 $this->assertTrue(file_exists("{$this->basedir}/weird/whizbang/newextension.php"));
451 $this->assertFalse(file_exists("{$this->basedir}/weird/whizbang/oddball.php"));
452 $this->assertEquals('newextension', $this->mapper->keyToInfo('test.whiz.bang')->file);
453 $this->assertDBQuery('newextension', 'SELECT file FROM civicrm_extension WHERE full_name ="test.whiz.bang"');
454 }
455
456 /**
457 * Install a module and then delete (leaving stale DB info); restore
458 * the module by downloading new code.
459 *
460 * Note that some metadata changes between versions -- the original has
461 * file="oddball", and the upgrade has file="newextension".
462 */
463 public function testReplace_InstalledMissing() {
464 $testingTypeManager = $this->getMockBuilder('CRM_Extension_Manager_Interface')->getMock();
465 $manager = $this->_createManager([
466 self::TESTING_TYPE => $testingTypeManager,
467 ]);
468
469 // initial installation
470 $this->assertEquals('uninstalled', $manager->getStatus('test.whiz.bang'));
471 $manager->install(['test.whiz.bang']);
472 $this->assertEquals('installed', $manager->getStatus('test.whiz.bang'));
473
474 // dirty remove
475 $this->assertTrue(file_exists("{$this->basedir}/weird/whizbang/info.xml"));
476 CRM_Utils_File::cleanDir("{$this->basedir}/weird/whizbang", TRUE, FALSE);
477 $this->assertFalse(file_exists("{$this->basedir}/weird/whizbang/info.xml"));
478 $manager->refresh();
479 $this->assertEquals('installed-missing', $manager->getStatus('test.whiz.bang'));
480
481 // download and reinstall
482 $this->download = $this->_createDownload('test.whiz.bang', 'newextension');
483
484 $testingTypeManager
485 ->expects($this->once())
486 ->method('onPreReplace');
487 $testingTypeManager
488 ->expects($this->once())
489 ->method('onPostReplace');
490 $manager->replace($this->download);
491 $this->assertEquals('installed', $manager->getStatus('test.whiz.bang'));
492 $this->assertTrue(file_exists("{$this->basedir}/test.whiz.bang/info.xml"));
493 $this->assertTrue(file_exists("{$this->basedir}/test.whiz.bang/newextension.php"));
494 $this->assertEquals('newextension', $this->mapper->keyToInfo('test.whiz.bang')->file);
495 $this->assertDBQuery('newextension', 'SELECT file FROM civicrm_extension WHERE full_name ="test.whiz.bang"');
496 }
497
498 /**
499 * @param $typeManagers
500 *
501 * @return CRM_Extension_Manager
502 */
503 public function _createManager($typeManagers) {
504 //list ($basedir, $c) = $this->_createContainer();
505 $mapper = new CRM_Extension_Mapper($this->container);
506 return new CRM_Extension_Manager($this->container, $this->container, $this->mapper, $typeManagers);
507 }
508
509 /**
510 * @param CRM_Utils_Cache_Interface $cache
511 * @param null $cacheKey
512 *
513 * @return array
514 */
515 public function _createContainer(CRM_Utils_Cache_Interface $cache = NULL, $cacheKey = NULL) {
516 $basedir = $this->createTempDir('ext-');
517 mkdir("$basedir/weird");
518 mkdir("$basedir/weird/foobar");
519 file_put_contents("$basedir/weird/foobar/info.xml", "<extension key='test.foo.bar' type='" . self::TESTING_TYPE . "'><file>oddball</file></extension>");
520 // not needed for now // file_put_contents("$basedir/weird/bar/oddball.php", "<?php\n");
521 mkdir("$basedir/weird/whizbang");
522 file_put_contents("$basedir/weird/whizbang/info.xml", "<extension key='test.whiz.bang' type='" . self::TESTING_TYPE . "'><file>oddball</file></extension>");
523 // not needed for now // file_put_contents("$basedir/weird/whizbang/oddball.php", "<?php\n");
524 mkdir("$basedir/weird/downstream");
525 file_put_contents("$basedir/weird/downstream/info.xml", "<extension key='test.foo.downstream' type='" . self::TESTING_TYPE . "'><file>oddball</file><requires><ext>test.foo.bar</ext></requires></extension>");
526 // not needed for now // file_put_contents("$basedir/weird/downstream/oddball.php", "<?php\n");
527 $c = new CRM_Extension_Container_Basic($basedir, 'http://example/basedir', $cache, $cacheKey);
528 return [$basedir, $c];
529 }
530
531 /**
532 * @param $key
533 * @param $file
534 *
535 * @return string
536 */
537 public function _createDownload($key, $file) {
538 $basedir = $this->createTempDir('ext-dl-');
539 file_put_contents("$basedir/info.xml", "<extension key='$key' type='" . self::TESTING_TYPE . "'><file>$file</file></extension>");
540 file_put_contents("$basedir/$file.php", "<?php\n");
541 return $basedir;
542 }
543
544 }