[TASK] Remove leading slash from use statements
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Tests / FunctionalTestCase.php
1 <?php
2 namespace TYPO3\CMS\Core\Tests;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Core\Tests\Functional\Framework\Frontend\Response;
18
19 /**
20 * Base test case class for functional tests, all TYPO3 CMS
21 * functional tests should extend from this class!
22 *
23 * If functional tests need additional setUp() and tearDown() code,
24 * they *must* call parent::setUp() and parent::tearDown() to properly
25 * set up and destroy the test system.
26 *
27 * The functional test system creates a full new TYPO3 CMS instance
28 * within typo3temp/ of the base system and the bootstraps this TYPO3 instance.
29 * This abstract class takes care of creating this instance with its
30 * folder structure and a LocalConfiguration, creates an own database
31 * for each test run and imports tables of loaded extensions.
32 *
33 * Functional tests must be run standalone (calling native phpunit
34 * directly) and can not be executed by eg. the ext:phpunit backend module.
35 * Additionally, the script must be called from the document root
36 * of the instance, otherwise path calculation is not successfully.
37 *
38 * Call whole functional test suite, example:
39 * - cd /var/www/t3master/foo # Document root of CMS instance, here is index.php of frontend
40 * - ./typo3conf/ext/phpunit/Composer/vendor/bin/phpunit -c typo3/sysext/core/Build/FunctionalTests.xml
41 *
42 * Call single test case, example:
43 * - cd /var/www/t3master/foo # Document root of CMS instance, here is index.php of frontend
44 * - ./typo3conf/ext/phpunit/Composer/vendor/bin/phpunit \
45 * --process-isolation \
46 * --bootstrap typo3/sysext/core/Build/FunctionalTestsBootstrap.php \
47 * typo3/sysext/core/Tests/Functional/DataHandling/DataHandlerTest.php
48 */
49 abstract class FunctionalTestCase extends BaseTestCase {
50 /**
51 * Core extensions to load.
52 *
53 * If the test case needs additional core extensions as requirement,
54 * they can be noted here and will be added to LocalConfiguration
55 * extension list and ext_tables.sql of those extensions will be applied.
56 *
57 * This property will stay empty in this abstract, so it is possible
58 * to just overwrite it in extending classes. Extensions noted here will
59 * be loaded for every test of a test case and it is not possible to change
60 * the list of loaded extensions between single tests of a test case.
61 *
62 * A default list of core extensions is always loaded.
63 *
64 * @see FunctionalTestCaseUtility $defaultActivatedCoreExtensions
65 * @var array
66 */
67 protected $coreExtensionsToLoad = array();
68
69 /**
70 * Array of test/fixture extensions paths that should be loaded for a test.
71 *
72 * This property will stay empty in this abstract, so it is possible
73 * to just overwrite it in extending classes. Extensions noted here will
74 * be loaded for every test of a test case and it is not possible to change
75 * the list of loaded extensions between single tests of a test case.
76 *
77 * Given path is expected to be relative to your document root, example:
78 *
79 * array(
80 * 'typo3conf/ext/some_extension/Tests/Functional/Fixtures/Extensions/test_extension',
81 * 'typo3conf/ext/base_extension',
82 * );
83 *
84 * Extensions in this array are linked to the test instance, loaded
85 * and their ext_tables.sql will be applied.
86 *
87 * @var array
88 */
89 protected $testExtensionsToLoad = array();
90
91 /**
92 * Array of test/fixture folder or file paths that should be linked for a test.
93 *
94 * This property will stay empty in this abstract, so it is possible
95 * to just overwrite it in extending classes. Path noted here will
96 * be linked for every test of a test case and it is not possible to change
97 * the list of folders between single tests of a test case.
98 *
99 * array(
100 * 'link-source' => 'link-destination'
101 * );
102 *
103 * Given paths are expected to be relative to the test instance root.
104 * The array keys are the source paths and the array values are the destination
105 * paths, example:
106 *
107 * array(
108 * 'typo3/sysext/impext/Tests/Functional/Fixtures/Folders/fileadmin/user_upload' =>
109 * 'fileadmin/user_upload',
110 * 'typo3conf/ext/my_own_ext/Tests/Functional/Fixtures/Folders/uploads/tx_myownext' =>
111 * 'uploads/tx_myownext'
112 * );
113 *
114 * To be able to link from my_own_ext the extension path needs also to be registered in
115 * property $testExtensionsToLoad
116 *
117 * @var array
118 */
119 protected $pathsToLinkInTestInstance = array();
120
121 /**
122 * This configuration array is merged with TYPO3_CONF_VARS
123 * that are set in default configuration and factory configuration
124 *
125 * @var array
126 */
127 protected $configurationToUseInTestInstance = array();
128
129 /**
130 * Array of folders that should be created inside the test instance document root.
131 *
132 * This property will stay empty in this abstract, so it is possible
133 * to just overwrite it in extending classes. Path noted here will
134 * be linked for every test of a test case and it is not possible to change
135 * the list of folders between single tests of a test case.
136 *
137 * Per default the following folder are created
138 * /fileadmin
139 * /typo3temp
140 * /typo3conf
141 * /typo3conf/ext
142 * /uploads
143 *
144 * To create additional folders add the paths to this array. Given paths are expected to be
145 * relative to the test instance root and have to begin with a slash. Example:
146 *
147 * array(
148 * 'fileadmin/user_upload'
149 * );
150 *
151 * @var array
152 */
153 protected $additionalFoldersToCreate = array();
154
155 /**
156 * Private utility class used in setUp() and tearDown(). Do NOT use in test cases!
157 *
158 * @var \TYPO3\CMS\Core\Tests\FunctionalTestCaseBootstrapUtility
159 */
160 private $bootstrapUtility = NULL;
161
162 /**
163 * Path to TYPO3 CMS test installation for this test case
164 *
165 * @var string
166 */
167 private $instancePath;
168
169 /**
170 * Set up creates a test instance and database.
171 *
172 * This method should be called with parent::setUp() in your test cases!
173 *
174 * @return void
175 */
176 protected function setUp() {
177 if (!defined('ORIGINAL_ROOT')) {
178 $this->markTestSkipped('Functional tests must be called through phpunit on CLI');
179 }
180 $this->bootstrapUtility = new FunctionalTestCaseBootstrapUtility();
181 $this->instancePath = $this->bootstrapUtility->setUp(
182 get_class($this),
183 $this->coreExtensionsToLoad,
184 $this->testExtensionsToLoad,
185 $this->pathsToLinkInTestInstance,
186 $this->configurationToUseInTestInstance,
187 $this->additionalFoldersToCreate
188 );
189 }
190
191 /**
192 * Get DatabaseConnection instance - $GLOBALS['TYPO3_DB']
193 *
194 * This method should be used instead of direct access to
195 * $GLOBALS['TYPO3_DB'] for easy IDE auto completion.
196 *
197 * @return \TYPO3\CMS\Core\Database\DatabaseConnection
198 */
199 protected function getDatabaseConnection() {
200 return $GLOBALS['TYPO3_DB'];
201 }
202
203 /**
204 * Initialize backend user
205 *
206 * @param int $userUid uid of the user we want to initialize. This user must exist in the fixture file
207 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
208 * @throws Exception
209 */
210 protected function setUpBackendUserFromFixture($userUid) {
211 $this->importDataSet(ORIGINAL_ROOT . 'typo3/sysext/core/Tests/Functional/Fixtures/be_users.xml');
212 $database = $this->getDatabaseConnection();
213 $userRow = $database->exec_SELECTgetSingleRow('*', 'be_users', 'uid = ' . $userUid);
214
215 /** @var $backendUser \TYPO3\CMS\Core\Authentication\BackendUserAuthentication */
216 $backendUser = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Authentication\BackendUserAuthentication::class);
217 $sessionId = $backendUser->createSessionId();
218 $_SERVER['HTTP_COOKIE'] = 'be_typo_user=' . $sessionId . '; path=/';
219 $backendUser->id = $sessionId;
220 $backendUser->sendNoCacheHeaders = FALSE;
221 $backendUser->dontSetCookie = TRUE;
222 $backendUser->createUserSession($userRow);
223
224 $GLOBALS['BE_USER'] = $backendUser;
225 $GLOBALS['BE_USER']->start();
226 if (!is_array($GLOBALS['BE_USER']->user) || !$GLOBALS['BE_USER']->user['uid']) {
227 throw new Exception(
228 'Can not initialize backend user',
229 1377095807
230 );
231 }
232 $GLOBALS['BE_USER']->backendCheckLogin();
233
234 return $backendUser;
235 }
236
237 /**
238 * Imports a data set represented as XML into the test database,
239 *
240 * @param string $path Absolute path to the XML file containing the data set to load
241 * @return void
242 * @throws Exception
243 */
244 protected function importDataSet($path) {
245 if (!is_file($path)) {
246 throw new Exception(
247 'Fixture file ' . $path . ' not found',
248 1376746261
249 );
250 }
251
252 $database = $this->getDatabaseConnection();
253
254 $xml = simplexml_load_file($path);
255 $foreignKeys = array();
256
257 /** @var $table \SimpleXMLElement */
258 foreach ($xml->children() as $table) {
259 $insertArray = array();
260
261 /** @var $column \SimpleXMLElement */
262 foreach ($table->children() as $column) {
263 $columnName = $column->getName();
264 $columnValue = NULL;
265
266 if (isset($column['ref'])) {
267 list($tableName, $elementId) = explode('#', $column['ref']);
268 $columnValue = $foreignKeys[$tableName][$elementId];
269 } elseif (isset($column['is-NULL']) && ($column['is-NULL'] === 'yes')) {
270 $columnValue = NULL;
271 } else {
272 $columnValue = (string)$table->$columnName;
273 }
274
275 $insertArray[$columnName] = $columnValue;
276 }
277
278 $tableName = $table->getName();
279 $result = $database->exec_INSERTquery($tableName, $insertArray);
280 if ($result === FALSE) {
281 throw new Exception(
282 'Error when processing fixture file: ' . $path . ' Can not insert data to table ' . $tableName . ': ' . $database->sql_error(),
283 1376746262
284 );
285 }
286 if (isset($table['id'])) {
287 $elementId = (string)$table['id'];
288 $foreignKeys[$tableName][$elementId] = $database->sql_insert_id();
289 }
290 }
291 }
292
293 /**
294 * @param int $pageId
295 * @param array $typoScriptFiles
296 */
297 protected function setUpFrontendRootPage($pageId, array $typoScriptFiles = array()) {
298 $pageId = (int)$pageId;
299 $page = $this->getDatabaseConnection()->exec_SELECTgetSingleRow('*', 'pages', 'uid=' . $pageId);
300
301 if (empty($page)) {
302 $this->fail('Cannot set up frontend root page "' . $pageId . '"');
303 }
304
305 $pagesFields = array(
306 'is_siteroot' => 1
307 );
308
309 $this->getDatabaseConnection()->exec_UPDATEquery('pages', 'uid=' . $pageId, $pagesFields);
310
311 $templateFields = array(
312 'pid' => $pageId,
313 'title' => '',
314 'config' => '',
315 'clear' => 3,
316 'root' => 1,
317 );
318
319 foreach ($typoScriptFiles as $typoScriptFile) {
320 $templateFields['config'] .= '<INCLUDE_TYPOSCRIPT: source="FILE:' . $typoScriptFile . '">' . LF;
321 }
322
323 $this->getDatabaseConnection()->exec_INSERTquery('sys_template', $templateFields);
324 }
325
326 /**
327 * @param int $pageId
328 * @param int $languageId
329 * @param int $backendUserId
330 * @param int $workspaceId
331 * @param bool $failOnFailure
332 * @return Response
333 */
334 protected function getFrontendResponse($pageId, $languageId = 0, $backendUserId = 0, $workspaceId = 0, $failOnFailure = TRUE) {
335 $pageId = (int)$pageId;
336 $languageId = (int)$languageId;
337
338 $additionalParameter = '';
339 if (!empty($backendUserId)) {
340 $additionalParameter .= '&backendUserId=' . (int)$backendUserId;
341 }
342 if (!empty($workspaceId)) {
343 $additionalParameter .= '&workspaceId=' . (int)$workspaceId;
344 }
345
346 $arguments = array(
347 'documentRoot' => $this->instancePath,
348 'requestUrl' => 'http://localhost/?id=' . $pageId . '&L=' . $languageId . $additionalParameter,
349 );
350
351 $template = new \Text_Template(ORIGINAL_ROOT . 'typo3/sysext/core/Tests/Functional/Fixtures/Frontend/request.tpl');
352 $template->setVar(
353 array(
354 'arguments' => var_export($arguments, TRUE),
355 'originalRoot' => ORIGINAL_ROOT,
356 )
357 );
358
359 $php = \PHPUnit_Util_PHP::factory();
360 $response = $php->runJob($template->render());
361 $result = json_decode($response['stdout'], TRUE);
362
363 if ($result === NULL) {
364 $this->fail('Frontend Response is empty');
365 }
366
367 if ($failOnFailure && $result['status'] === Response::STATUS_Failure) {
368 $this->fail('Frontend Response has failure:' . LF . $result['error']);
369 }
370
371 $response = new Response($result['status'], $result['content'], $result['error']);
372 return $response;
373 }
374
375 }