ca62f344d9c22efef41b5434d87b63dfbaecedcb
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Tests / Unit / Package / PackageManagerTest.php
1 <?php
2 namespace TYPO3\CMS\Core\Tests\Unit\Package;
3
4 /* *
5 * This script belongs to the TYPO3 Flow framework. *
6 * *
7 * It is free software; you can redistribute it and/or modify it under *
8 * the terms of the GNU Lesser General Public License, either version 3 *
9 * of the License, or (at your option) any later version. *
10 * *
11 * The TYPO3 project - inspiring people to share! *
12 * */
13
14 use TYPO3\CMS\Core\Package\PackageInterface;
15 use org\bovigo\vfs\vfsStream;
16
17 /**
18 * Testcase for the default package manager
19 *
20 */
21 class PackageManagerTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
22
23 /**
24 * @var \TYPO3\CMS\Core\Package\PackageManager
25 */
26 protected $packageManager;
27
28 /**
29 * Sets up this test case
30 *
31 */
32 protected function setUp() {
33 vfsStream::setup('Test');
34 $mockBootstrap = $this->getMock(\TYPO3\CMS\Core\Core\Bootstrap::class, array(), array(), '', FALSE);
35 $mockCache = $this->getMock(\TYPO3\CMS\Core\Cache\Frontend\PhpFrontend::class, array('has', 'set', 'getBackend'), array(), '', FALSE);
36 $mockCacheBackend = $this->getMock(\TYPO3\CMS\Core\Cache\Backend\SimpleFileBackend::class, array('has', 'set', 'getBackend'), array(), '', FALSE);
37 $mockCache->expects($this->any())->method('has')->will($this->returnValue(FALSE));
38 $mockCache->expects($this->any())->method('set')->will($this->returnValue(TRUE));
39 $mockCache->expects($this->any())->method('getBackend')->will($this->returnValue($mockCacheBackend));
40 $mockCacheBackend->expects($this->any())->method('getCacheDirectory')->will($this->returnValue('vfs://Test/Cache'));
41 $this->packageManager = $this->getAccessibleMock(\TYPO3\CMS\Core\Package\PackageManager::class, array('sortAndSavePackageStates', 'sortAvailablePackagesByDependencies'));
42
43 mkdir('vfs://Test/Packages/Application', 0700, TRUE);
44 mkdir('vfs://Test/Configuration');
45 file_put_contents('vfs://Test/Configuration/PackageStates.php', "<?php return array ('packages' => array(), 'version' => 4); ");
46
47 $mockClassLoader = $this->getMock(\TYPO3\CMS\Core\Core\ClassLoader::class, array(), array(\TYPO3\CMS\Core\Core\Bootstrap::getInstance()->getApplicationContext()));
48 $mockClassLoader->expects($this->any())->method('setCacheIdentifier')->will($this->returnSelf());
49
50 $composerNameToPackageKeyMap = array(
51 'typo3/flow' => 'TYPO3.Flow'
52 );
53
54 $this->packageManager->injectClassLoader($mockClassLoader);
55 $this->packageManager->injectCoreCache($mockCache);
56 $this->inject($this->packageManager, 'composerNameToPackageKeyMap', $composerNameToPackageKeyMap);
57 $this->packageManager->_set('packagesBasePath', 'vfs://Test/Packages/');
58 $this->packageManager->_set('packageStatesPathAndFilename', 'vfs://Test/Configuration/PackageStates.php');
59 $this->packageManager->initialize($mockBootstrap);
60 }
61
62 /**
63 * @param string $packageKey
64 * @return \TYPO3\CMS\Core\Package\Package
65 */
66 protected function createPackage($packageKey) {
67 $packagePath = 'vfs://Test/Packages/Application/' . $packageKey . '/';
68 mkdir($packagePath, 0770, TRUE);
69 file_put_contents($packagePath . 'ext_emconf.php', '');
70 file_put_contents($packagePath . 'composer.json', '');
71 $package = new \TYPO3\CMS\Core\Package\Package($this->packageManager, $packageKey, $packagePath);
72 $this->packageManager->registerPackage($package);
73 $this->packageManager->activatePackage($packageKey);
74
75 return $package;
76 }
77
78 /**
79 * @test
80 */
81 public function getPackageReturnsTheSpecifiedPackage() {
82 $this->createPackage('TYPO3.Flow');
83 $package = $this->packageManager->getPackage('TYPO3.Flow');
84
85 $this->assertInstanceOf(\TYPO3\CMS\Core\Package\PackageInterface::class, $package, 'The result of getPackage() was no valid package object.');
86 }
87
88 /**
89 * @test
90 * @expectedException \TYPO3\CMS\Core\Package\Exception\UnknownPackageException
91 */
92 public function getPackageThrowsExceptionOnUnknownPackage() {
93 $this->packageManager->getPackage('PrettyUnlikelyThatThisPackageExists');
94 }
95
96
97 /**
98 * @test
99 */
100 public function scanAvailablePackagesTraversesThePackagesDirectoryAndRegistersPackagesItFinds() {
101 $expectedPackageKeys = array(
102 $this->getUniqueId('TYPO3.CMS'),
103 $this->getUniqueId('TYPO3.CMS.Test'),
104 $this->getUniqueId('TYPO3.YetAnotherTestPackage'),
105 $this->getUniqueId('Lolli.Pop.NothingElse')
106 );
107
108 foreach ($expectedPackageKeys as $packageKey) {
109 $packagePath = 'vfs://Test/Packages/Application/' . $packageKey . '/';
110
111 mkdir($packagePath, 0770, TRUE);
112 mkdir($packagePath . 'Classes');
113 file_put_contents($packagePath . 'composer.json', '{"name": "' . $packageKey . '", "type": "typo3-test"}');
114 }
115
116 $packageManager = $this->getAccessibleMock(\TYPO3\CMS\Core\Package\PackageManager::class, array('sortAndSavePackageStates'));
117 $packageManager->_set('packagesBasePath', 'vfs://Test/Packages/');
118 $packageManager->_set('packageStatesPathAndFilename', 'vfs://Test/Configuration/PackageStates.php');
119
120 $packageManager->_set('packages', array());
121 $packageManager->_call('scanAvailablePackages');
122
123 $packageStates = require('vfs://Test/Configuration/PackageStates.php');
124 $actualPackageKeys = array_keys($packageStates['packages']);
125 $this->assertEquals(sort($expectedPackageKeys), sort($actualPackageKeys));
126 }
127
128 /**
129 * @test
130 */
131 public function scanAvailablePackagesKeepsExistingPackageConfiguration() {
132 $expectedPackageKeys = array(
133 $this->getUniqueId('TYPO3.CMS'),
134 $this->getUniqueId('TYPO3.CMS.Test'),
135 $this->getUniqueId('TYPO3.YetAnotherTestPackage'),
136 $this->getUniqueId('Lolli.Pop.NothingElse')
137 );
138
139 foreach ($expectedPackageKeys as $packageKey) {
140 $packagePath = 'vfs://Test/Packages/Application/' . $packageKey . '/';
141
142 mkdir($packagePath, 0770, TRUE);
143 mkdir($packagePath . 'Classes');
144 file_put_contents($packagePath . 'composer.json', '{"name": "' . $packageKey . '", "type": "typo3-cms-test"}');
145 file_put_contents($packagePath . 'ext_emconf.php', '');
146 }
147
148 $packageManager = $this->getAccessibleMock(\TYPO3\CMS\Core\Package\PackageManager::class, array('dummy'));
149 $packageManager->_set('packagesBasePaths', array('local' => 'vfs://Test/Packages/Application'));
150 $packageManager->_set('packagesBasePath', 'vfs://Test/Packages/');
151 $packageManager->_set('packageStatesPathAndFilename', 'vfs://Test/Configuration/PackageStates.php');
152
153 $dependencyResolver = $this->getMock(\TYPO3\CMS\Core\Package\DependencyResolver::class, array('dummy'));
154 $packageManager->injectDependencyResolver($dependencyResolver);
155
156 $packageManager->_set('packageStatesConfiguration', array(
157 'packages' => array(
158 $packageKey => array(
159 'state' => 'inactive',
160 'packagePath' => 'Application/' . $packageKey . '/'
161 )
162 ),
163 'version' => 4
164 ));
165 $packageManager->_call('scanAvailablePackages');
166 $packageManager->_call('sortAndSavePackageStates');
167
168 $packageStates = require('vfs://Test/Configuration/PackageStates.php');
169 $this->assertEquals('inactive', $packageStates['packages'][$packageKey]['state']);
170 }
171
172
173 /**
174 * @test
175 */
176 public function packageStatesConfigurationContainsRelativePaths() {
177 $packageKeys = array(
178 $this->getUniqueId('Lolli.Pop.NothingElse'),
179 $this->getUniqueId('TYPO3.Package'),
180 $this->getUniqueId('TYPO3.YetAnotherTestPackage')
181 );
182
183 foreach ($packageKeys as $packageKey) {
184 $packagePath = 'vfs://Test/Packages/Application/' . $packageKey . '/';
185
186 mkdir($packagePath, 0770, TRUE);
187 mkdir($packagePath . 'Classes');
188 file_put_contents($packagePath . 'composer.json', '{"name": "' . $packageKey . '", "type": "typo3-cms-test"}');
189 file_put_contents($packagePath . 'ext_emconf.php', '');
190 }
191
192 $packageManager = $this->getAccessibleMock(\TYPO3\CMS\Core\Package\PackageManager::class, array('dummy'));
193 $packageManager->_set('packagesBasePaths', array('local' => 'vfs://Test/Packages/Application'));
194 $packageManager->_set('packagesBasePath', 'vfs://Test/Packages/');
195 $packageManager->_set('packageStatesPathAndFilename', 'vfs://Test/Configuration/PackageStates.php');
196
197 $dependencyResolver = $this->getMock(\TYPO3\CMS\Core\Package\DependencyResolver::class, array('dummy'));
198 $packageManager->injectDependencyResolver($dependencyResolver);
199
200 $packageManager->_set('packages', array());
201 $packageManager->_call('scanAvailablePackages');
202
203 $expectedPackageStatesConfiguration = array();
204 foreach ($packageKeys as $packageKey) {
205 $expectedPackageStatesConfiguration[$packageKey] = array(
206 'state' => 'inactive',
207 'packagePath' => 'Application/' . $packageKey . '/',
208 'composerName' => $packageKey,
209 'suggestions' => array(),
210 );
211 }
212
213 $actualPackageStatesConfiguration = $packageManager->_get('packageStatesConfiguration');
214 $this->assertEquals($expectedPackageStatesConfiguration, $actualPackageStatesConfiguration['packages']);
215 }
216
217 /**
218 * Data Provider returning valid package keys and the corresponding path
219 *
220 * @return array
221 */
222 public function packageKeysAndPaths() {
223 return array(
224 array('TYPO3.YetAnotherTestPackage', 'vfs://Test/Packages/Application/TYPO3.YetAnotherTestPackage/'),
225 array('Lolli.Pop.NothingElse', 'vfs://Test/Packages/Application/Lolli.Pop.NothingElse/')
226 );
227 }
228
229 /**
230 * @test
231 * @dataProvider packageKeysAndPaths
232 */
233 public function createPackageCreatesPackageFolderAndReturnsPackage($packageKey, $expectedPackagePath) {
234 $actualPackage = $this->createPackage($packageKey);
235 $actualPackagePath = $actualPackage->getPackagePath();
236
237 $this->assertEquals($expectedPackagePath, $actualPackagePath);
238 $this->assertTrue(is_dir($actualPackagePath), 'Package path should exist after createPackage()');
239 $this->assertEquals($packageKey, $actualPackage->getPackageKey());
240 $this->assertTrue($this->packageManager->isPackageAvailable($packageKey));
241 }
242
243 /**
244 * @test
245 */
246 public function activatePackageAndDeactivatePackageActivateAndDeactivateTheGivenPackage() {
247 $packageKey = 'Acme.YetAnotherTestPackage';
248
249 $this->createPackage($packageKey);
250
251 $this->packageManager->deactivatePackage($packageKey);
252 $this->assertFalse($this->packageManager->isPackageActive($packageKey));
253
254 $this->packageManager->activatePackage($packageKey);
255 $this->assertTrue($this->packageManager->isPackageActive($packageKey));
256 }
257
258 /**
259 * @test
260 * @expectedException \TYPO3\CMS\Core\Package\Exception\ProtectedPackageKeyException
261 */
262 public function deactivatePackageThrowsAnExceptionIfPackageIsProtected() {
263 $package = $this->createPackage('Acme.YetAnotherTestPackage');
264 $package->setProtected(TRUE);
265 $this->packageManager->deactivatePackage('Acme.YetAnotherTestPackage');
266 }
267
268 /**
269 * @test
270 * @expectedException \TYPO3\CMS\Core\Package\Exception\UnknownPackageException
271 */
272 public function deletePackageThrowsErrorIfPackageIsNotAvailable() {
273 $this->packageManager->deletePackage('PrettyUnlikelyThatThisPackageExists');
274 }
275
276 /**
277 * @test
278 * @expectedException \TYPO3\CMS\Core\Package\Exception\ProtectedPackageKeyException
279 */
280 public function deletePackageThrowsAnExceptionIfPackageIsProtected() {
281 $package = $this->createPackage('Acme.YetAnotherTestPackage');
282 $package->setProtected(TRUE);
283 $this->packageManager->deletePackage('Acme.YetAnotherTestPackage');
284 }
285
286 /**
287 * @test
288 */
289 public function deletePackageRemovesPackageFromAvailableAndActivePackagesAndDeletesThePackageDirectory() {
290 $this->createPackage('Acme.YetAnotherTestPackage');
291
292 $this->assertTrue($this->packageManager->isPackageActive('Acme.YetAnotherTestPackage'));
293 $this->assertTrue($this->packageManager->isPackageAvailable('Acme.YetAnotherTestPackage'));
294
295 $this->packageManager->deletePackage('Acme.YetAnotherTestPackage');
296
297 $this->assertFalse($this->packageManager->isPackageActive('Acme.YetAnotherTestPackage'));
298 $this->assertFalse($this->packageManager->isPackageAvailable('Acme.YetAnotherTestPackage'));
299 }
300
301 /**
302 * @return array
303 */
304 public function composerNamesAndPackageKeys() {
305 return array(
306 array('imagine/Imagine', 'imagine.Imagine'),
307 array('imagine/imagine', 'imagine.Imagine'),
308 array('typo3/cms', 'TYPO3.CMS'),
309 array('TYPO3/CMS', 'TYPO3.CMS')
310 );
311 }
312
313 /**
314 * @test
315 * @dataProvider composerNamesAndPackageKeys
316 */
317 public function getPackageKeyFromComposerNameIgnoresCaseDifferences($composerName, $packageKey) {
318 $packageStatesConfiguration = array('packages' =>
319 array(
320 'TYPO3.CMS' => array(
321 'composerName' => 'typo3/cms'
322 ),
323 'imagine.Imagine' => array(
324 'composerName' => 'imagine/Imagine'
325 )
326 )
327 );
328
329 $packageManager = $this->getAccessibleMock(\TYPO3\CMS\Core\Package\PackageManager::class, array('resolvePackageDependencies'));
330 $packageManager->_set('packageStatesConfiguration', $packageStatesConfiguration);
331
332 $this->assertEquals($packageKey, $packageManager->_call('getPackageKeyFromComposerName', $composerName));
333 }
334
335 }