[BUGFIX] Acceptance test paths
[Packages/TYPO3.CMS.git] / components / testing_framework / Classes / Core / Acceptance / AcceptanceCoreEnvironment.php
1 <?php
2 declare(strict_types=1);
3 namespace TYPO3\Components\TestingFramework\Core\Acceptance;
4
5 /*
6 * This file is part of the TYPO3 CMS project.
7 *
8 * It is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, either version 2
10 * of the License, or any later version.
11 *
12 * For the full copyright and license information, please read the
13 * LICENSE.txt file that was distributed with this source code.
14 *
15 * The TYPO3 project - inspiring people to share!
16 */
17
18 use Codeception\Event\SuiteEvent;
19 use Codeception\Events;
20 use Codeception\Extension;
21 use TYPO3\CMS\Core\Cache\Backend\NullBackend;
22 use TYPO3\CMS\Core\Core\Bootstrap;
23 use TYPO3\CMS\Core\Database\ConnectionPool;
24 use TYPO3\CMS\Core\Utility\GeneralUtility;
25 use TYPO3\CMS\Styleguide\TcaDataGenerator\Generator;
26 use TYPO3\Components\TestingFramework\Core\Testbase;
27
28 /**
29 * This codeception extension creates a full TYPO3 instance within
30 * typo3temp. Own acceptance test suites may extend from this class
31 * and change the properties. This can be used to not copy the whole
32 * bootstrapTypo3Environment() method but reuse it instead.
33 */
34 class AcceptanceCoreEnvironment extends Extension
35 {
36 /**
37 * Additional core extensions to load.
38 *
39 * To be used in own acceptance test suites.
40 *
41 * If a test suite needs additional core extensions, for instance as a dependency of
42 * an extension that is tested, those core extension names can be noted here and will
43 * be loaded.
44 *
45 * @var array
46 */
47 protected $coreExtensionsToLoad = [];
48
49 /**
50 * Array of test/fixture extensions paths that should be loaded for a test.
51 *
52 * To be used in own acceptance test suites.
53 *
54 * Given path is expected to be relative to your document root, example:
55 *
56 * array(
57 * 'typo3conf/ext/some_extension/Tests/Functional/Fixtures/Extensions/test_extension',
58 * 'typo3conf/ext/base_extension',
59 * );
60 *
61 * Extensions in this array are linked to the test instance, loaded
62 * and their ext_tables.sql will be applied.
63 *
64 * @var array
65 */
66 protected $testExtensionsToLoad = [];
67
68 /**
69 * Array of test/fixture folder or file paths that should be linked for a test.
70 *
71 * To be used in own acceptance test suites.
72 *
73 * array(
74 * 'link-source' => 'link-destination'
75 * );
76 *
77 * Given paths are expected to be relative to the test instance root.
78 * The array keys are the source paths and the array values are the destination
79 * paths, example:
80 *
81 * array(
82 * 'typo3/sysext/impext/Tests/Functional/Fixtures/Folders/fileadmin/user_upload' =>
83 * 'fileadmin/user_upload',
84 * 'typo3conf/ext/my_own_ext/Tests/Functional/Fixtures/Folders/uploads/tx_myownext' =>
85 * 'uploads/tx_myownext'
86 * );
87 *
88 * To be able to link from my_own_ext the extension path needs also to be registered in
89 * property $testExtensionsToLoad
90 *
91 * @var array
92 */
93 protected $pathsToLinkInTestInstance = [];
94
95 /**
96 * This configuration array is merged with TYPO3_CONF_VARS
97 * that are set in default configuration and factory configuration
98 *
99 * To be used in own acceptance test suites.
100 *
101 * @var array
102 */
103 protected $configurationToUseInTestInstance = [];
104
105 /**
106 * Array of folders that should be created inside the test instance document root.
107 *
108 * To be used in own acceptance test suites.
109 *
110 * Per default the following folder are created
111 * /fileadmin
112 * /typo3temp
113 * /typo3conf
114 * /typo3conf/ext
115 * /uploads
116 *
117 * To create additional folders add the paths to this array. Given paths are expected to be
118 * relative to the test instance root and have to begin with a slash. Example:
119 *
120 * array(
121 * 'fileadmin/user_upload'
122 * );
123 *
124 * @var array
125 */
126 protected $additionalFoldersToCreate = [];
127
128 /**
129 * XML database fixtures to be loaded into database.
130 *
131 * Given paths are expected to be relative to your document root.
132 *
133 * @var array
134 */
135 protected $xmlDatabaseFixtures = [
136 'components/testing_framework/Resources/Core/Acceptance/Fixtures/be_users.xml',
137 'components/testing_framework/Resources/Core/Acceptance/Fixtures/be_sessions.xml',
138 'components/testing_framework/Resources/Core/Acceptance/Fixtures/be_groups.xml',
139 'components/testing_framework/Resources/Core/Acceptance/Fixtures/sys_category.xml',
140 'components/testing_framework/Resources/Core/Acceptance/Fixtures/tx_extensionmanager_domain_model_extension.xml',
141 'components/testing_framework/Resources/Core/Acceptance/Fixtures/tx_extensionmanager_domain_model_repository.xml',
142 ];
143
144 /**
145 * Events to listen to
146 */
147 public static $events = [
148 Events::SUITE_BEFORE => 'bootstrapTypo3Environment',
149 Events::TEST_AFTER => 'cleanupTypo3Environment'
150 ];
151
152 /**
153 * Handle SUITE_BEFORE event.
154 *
155 * Create a full standalone TYPO3 instance within typo3temp/var/tests/acceptance,
156 * create a database and create database schema.
157 *
158 * @param SuiteEvent $suiteEvent
159 */
160 public function bootstrapTypo3Environment(SuiteEvent $suiteEvent)
161 {
162 $testbase = new Testbase();
163 $testbase->enableDisplayErrors();
164 $testbase->defineBaseConstants();
165 $testbase->defineOriginalRootPath();
166 $testbase->createDirectory(ORIGINAL_ROOT . 'typo3temp/var/tests/acceptance');
167 $testbase->createDirectory(ORIGINAL_ROOT . 'typo3temp/var/transient');
168
169 $instancePath = ORIGINAL_ROOT . 'typo3temp/var/tests/acceptance';
170
171 $testbase->defineTypo3ModeBe();
172 $testbase->setTypo3TestingContext();
173 $testbase->removeOldInstanceIfExists($instancePath);
174 // Basic instance directory structure
175 $testbase->createDirectory($instancePath . '/fileadmin');
176 $testbase->createDirectory($instancePath . '/typo3temp/var/transient');
177 $testbase->createDirectory($instancePath . '/typo3temp/assets');
178 $testbase->createDirectory($instancePath . '/typo3conf/ext');
179 $testbase->createDirectory($instancePath . '/uploads');
180 // Additionally requested directories
181 foreach ($this->additionalFoldersToCreate as $directory) {
182 $testbase->createDirectory($instancePath . '/' . $directory);
183 }
184 $testbase->createLastRunTextfile($instancePath);
185 $testbase->setUpInstanceCoreLinks($instancePath);
186 // ext:styleguide is always loaded
187 $testExtensionsToLoad = array_merge(
188 [ 'typo3conf/ext/styleguide' ],
189 $this->testExtensionsToLoad
190 );
191 $testbase->linkTestExtensionsToInstance($instancePath, $testExtensionsToLoad);
192 $testbase->linkPathsInTestInstance($instancePath, $this->pathsToLinkInTestInstance);
193 $localConfiguration['DB'] = $testbase->getOriginalDatabaseSettingsFromEnvironmentOrLocalConfiguration();
194 $originalDatabaseName = $localConfiguration['DB']['Connections']['Default']['dbname'];
195 // Append the unique identifier to the base database name to end up with a single database per test case
196 $localConfiguration['DB']['Connections']['Default']['dbname'] = $originalDatabaseName . '_at';
197 $testbase->testDatabaseNameIsNotTooLong($originalDatabaseName, $localConfiguration);
198 // Set some hard coded base settings for the instance. Those could be overruled by
199 // $this->configurationToUseInTestInstance if needed again.
200 $localConfiguration['BE']['debug'] = true;
201 $localConfiguration['BE']['lockHashKeyWords'] = '';
202 $localConfiguration['BE']['installToolPassword'] = $this->getInstallToolPassword();
203 $localConfiguration['BE']['loginSecurityLevel'] = 'rsa';
204 $localConfiguration['SYS']['isInitialInstallationInProgress'] = false;
205 $localConfiguration['SYS']['isInitialDatabaseImportDone'] = true;
206 $localConfiguration['SYS']['displayErrors'] = false;
207 $localConfiguration['SYS']['debugExceptionHandler'] = '';
208 $localConfiguration['SYS']['trustedHostsPattern'] = 'localhost:8000';
209 $localConfiguration['SYS']['encryptionKey'] = 'iAmInvalid';
210 // @todo: This sql_mode should be enabled as soon as styleguide and dataHandler can cope with it
211 //$localConfiguration['SYS']['setDBinit'] = 'SET SESSION sql_mode = \'STRICT_ALL_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_VALUE_ON_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY\';';
212 $localConfiguration['SYS']['caching']['cacheConfigurations']['extbase_object']['backend'] = NullBackend::class;
213 $testbase->setUpLocalConfiguration($instancePath, $localConfiguration, $this->configurationToUseInTestInstance);
214 $defaultCoreExtensionsToLoad = [
215 'core',
216 'beuser',
217 'extbase',
218 'fluid',
219 'filelist',
220 'extensionmanager',
221 'lang',
222 'setup',
223 'rsaauth',
224 'saltedpasswords',
225 'backend',
226 'about',
227 'belog',
228 'install',
229 't3skin',
230 'frontend',
231 'recordlist',
232 'reports',
233 'sv',
234 'scheduler',
235 'tstemplate',
236 ];
237 $testbase->setUpPackageStates($instancePath, $defaultCoreExtensionsToLoad, $this->coreExtensionsToLoad, $testExtensionsToLoad);
238 $testbase->setUpBasicTypo3Bootstrap($instancePath);
239 $testbase->setUpTestDatabase($localConfiguration['DB']['Connections']['Default']['dbname'], $originalDatabaseName);
240 $testbase->loadExtensionTables();
241 $testbase->createDatabaseStructure();
242
243 // Unset a closure or phpunit kicks in with a 'serialization of \Closure is not allowed'
244 // Alternative solution:
245 // unset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['cliKeys']['extbase']);
246 $suite = $suiteEvent->getSuite();
247 $suite->setBackupGlobals(false);
248
249 foreach ($this->xmlDatabaseFixtures as $fixture) {
250 $testbase->importXmlDatabaseFixture(ORIGINAL_ROOT . $fixture);
251 }
252
253 // styleguide generator uses DataHandler for some parts. DataHandler needs an initialized BE user
254 // with admin right and the live workspace.
255 Bootstrap::getInstance()->initializeBackendUser();
256 $GLOBALS['BE_USER']->user['admin'] = 1;
257 $GLOBALS['BE_USER']->user['uid'] = 1;
258 $GLOBALS['BE_USER']->workspace = 0;
259 Bootstrap::getInstance()->initializeLanguageObject();
260
261 $styleguideGenerator = new Generator();
262 $styleguideGenerator->create();
263
264 // @todo: Find out why that is needed to execute the first test successfully
265 $this->cleanupTypo3Environment();
266 }
267
268 /**
269 * Method executed after each test
270 *
271 * @return void
272 */
273 public function cleanupTypo3Environment()
274 {
275 // Reset uc db field of be_user "admin" to null to reduce
276 // possible side effects between single tests.
277 GeneralUtility::makeInstance(ConnectionPool::class)
278 ->getConnectionForTable('be_users')
279 ->update('be_users', ['uc' => null], ['uid' => 1]);
280 }
281
282 /**
283 * Set install tool password. This is either a salted password
284 * of a given typo3InstallToolPassword environment variable, or
285 * a hardcoded value that does not allow login.
286 *
287 * @return string
288 */
289 protected function getInstallToolPassword(): string
290 {
291 $password = getenv('typo3InstallToolPassword');
292 if (!empty($password)) {
293 $saltFactory = \TYPO3\CMS\Saltedpasswords\Salt\SaltFactory::getSaltingInstance(null, 'BE');
294 return $saltFactory->getHashedPassword($password);
295 } else {
296 return '$P$notnotnotnotnotnot.validvalidva';
297 }
298 }
299 }