[FEATURE] Integrate preliminary PackageManager API
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Tests / FunctionalTestCase.php
1 <?php
2 namespace TYPO3\CMS\Core\Tests;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2013 Christian Kuhn <lolli@schwarzbu.ch>
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 *
19 * This script is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * This copyright notice MUST APPEAR in all copies of the script!
25 ***************************************************************/
26
27 /**
28 * Base test case class for functional tests, all TYPO3 CMS
29 * functional tests should extend from this class!
30 *
31 * If functional tests need additional setUp() and tearDown() code,
32 * they *must* call parent::setUp() and parent::tearDown() to properly
33 * set up and destroy the test system.
34 *
35 * The functional test system creates a full new TYPO3 CMS instance
36 * within typo3temp/ of the base system and the bootstraps this TYPO3 instance.
37 * This abstract class takes care of creating this instance with its
38 * folder structure and a LocalConfiguration, creates an own database
39 * for each test run and imports tables of loaded extensions.
40 *
41 * Functional tests must be run standalone (calling native phpunit
42 * directly) and can not be executed by eg. the ext:phpunit backend module.
43 * Additionally, the script must be called from the document root
44 * of the instance, otherwise path calculation is not successfully.
45 *
46 * Call whole functional test suite, example:
47 * - cd /var/www/t3master/foo # Document root of CMS instance, here is index.php of frontend
48 * - ./typo3conf/ext/phpunit/Composer/vendor/bin/phpunit -c typo3/sysext/core/Build/FunctionalTests.xml
49 *
50 * Call single test case, example:
51 * - cd /var/www/t3master/foo # Document root of CMS instance, here is index.php of frontend
52 * - ./typo3conf/ext/phpunit/Composer/vendor/bin/phpunit \
53 * --process-isolation \
54 * --bootstrap typo3/sysext/core/Build/FunctionalTestsBootstrap.php \
55 * typo3/sysext/core/Tests/Functional/DataHandling/DataHandlerTest.php
56 */
57 abstract class FunctionalTestCase extends BaseTestCase {
58
59 /**
60 * Core extensions to load.
61 *
62 * If the test case needs additional core extensions as requirement,
63 * they can be noted here and will be added to LocalConfiguration
64 * extension list and ext_tables.sql of those extensions will be applied.
65 *
66 * This property will stay empty in this abstract, so it is possible
67 * to just overwrite it in extending classes. Extensions noted here will
68 * be loaded for every test of a test case and it is not possible to change
69 * the list of loaded extensions between single tests of a test case.
70 *
71 * Required core extensions like core, cms, extbase and so on are loaded
72 * automatically, so there is no need to add them here. See constant
73 * REQUIRED_EXTENSIONS for a list of automatically loaded extensions.
74 *
75 * @var array
76 */
77 protected $coreExtensionsToLoad = array();
78
79 /**
80 * Array of test/fixture extensions paths that should be loaded for a test.
81 *
82 * This property will stay empty in this abstract, so it is possible
83 * to just overwrite it in extending classes. Extensions noted here will
84 * be loaded for every test of a test case and it is not possible to change
85 * the list of loaded extensions between single tests of a test case.
86 *
87 * Given path is expected to be relative to your document root, example:
88 *
89 * array(
90 * 'typo3conf/ext/some_extension/Tests/Functional/Fixtures/Extensions/test_extension',
91 * 'typo3conf/ext/base_extension',
92 * );
93 *
94 * Extensions in this array are linked to the test instance, loaded
95 * and their ext_tables.sql will be applied.
96 *
97 * @var array
98 */
99 protected $testExtensionsToLoad = array();
100
101 /**
102 * Private utility class used in setUp() and tearDown(). Do NOT use in test cases!
103 *
104 * @var \TYPO3\CMS\Core\Tests\FunctionalTestCaseBootstrapUtility
105 */
106 private $bootstrapUtility = NULL;
107
108 /**
109 * Set up creates a test instance and database.
110 *
111 * This method should be called with parent::setUp() in your test cases!
112 *
113 * @return void
114 */
115 public function setUp() {
116 if (!defined('ORIGINAL_ROOT')) {
117 $this->markTestSkipped('Functional tests must be called through phpunit on CLI');
118 }
119 $this->bootstrapUtility = new FunctionalTestCaseBootstrapUtility();
120 $this->bootstrapUtility->setUp(get_class($this), $this->coreExtensionsToLoad, $this->testExtensionsToLoad);
121 }
122
123 /**
124 * Tear down destroys the instance and database.
125 *
126 * This method should be called with parent::tearDown() in your test cases!
127 *
128 * @throws Exception
129 * @return void
130 */
131 public function tearDown() {
132 if (!($this->bootstrapUtility instanceof FunctionalTestCaseBootstrapUtility)) {
133 throw new Exception(
134 'Bootstrap utility not set. Is parent::setUp() called in setUp()?',
135 1376826527
136 );
137 }
138 $this->bootstrapUtility->tearDown();
139 }
140
141 /**
142 * Get DatabaseConnection instance - $GLOBALS['TYPO3_DB']
143 *
144 * This method should be used instead of direct access to
145 * $GLOBALS['TYPO3_DB'] for easy IDE auto completion.
146 *
147 * @return \TYPO3\CMS\Core\Database\DatabaseConnection
148 */
149 protected function getDatabase() {
150 return $GLOBALS['TYPO3_DB'];
151 }
152
153 /**
154 * Initialize backend user
155 *
156 * @param int $userUid uid of the user we want to initialize. This user must exist in the fixture file
157 * @throws Exception
158 */
159 protected function setUpBackendUserFromFixture($userUid) {
160 $this->importDataSet(ORIGINAL_ROOT . 'typo3/sysext/core/Tests/Functional/Fixtures/be_users.xml');
161 $database = $this->getDatabase();
162 $userRow = $database->exec_SELECTgetSingleRow('*', 'be_users', 'uid = ' . $userUid);
163
164 /** @var $backendUser \TYPO3\CMS\Core\Authentication\BackendUserAuthentication */
165 $backendUser = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Authentication\\BackendUserAuthentication');
166 $sessionId = $backendUser->createSessionId();
167 $_SERVER['HTTP_COOKIE'] = 'be_typo_user=' . $sessionId . '; path=/';
168 $backendUser->id = $sessionId;
169 $backendUser->sendNoCacheHeaders = FALSE;
170 $backendUser->dontSetCookie = TRUE;
171 $backendUser->createUserSession($userRow);
172
173 $GLOBALS['BE_USER'] = $backendUser;
174 $GLOBALS['BE_USER']->start();
175 if (!is_array($GLOBALS['BE_USER']->user) || !$GLOBALS['BE_USER']->user['uid']) {
176 throw new Exception(
177 'Can not initialize backend user',
178 1377095807
179 );
180 }
181 $GLOBALS['BE_USER']->backendCheckLogin();
182 }
183
184 /**
185 * Imports a data set represented as XML into the test database,
186 *
187 * @param string $path Absolute path to the XML file containing the data set to load
188 * @return void
189 * @throws Exception
190 */
191 protected function importDataSet($path) {
192 if (!is_file($path)) {
193 throw new Exception(
194 'Fixture file ' . $path . ' not found',
195 1376746261
196 );
197 }
198
199 $database = $this->getDatabase();
200
201 $xml = simplexml_load_file($path);
202 $foreignKeys = array();
203
204 /** @var $table \SimpleXMLElement */
205 foreach ($xml->children() as $table) {
206 $insertArray = array();
207
208 /** @var $column \SimpleXMLElement */
209 foreach ($table->children() as $column) {
210 $columnName = $column->getName();
211 $columnValue = NULL;
212
213 if (isset($column['ref'])) {
214 list($tableName, $elementId) = explode('#', $column['ref']);
215 $columnValue = $foreignKeys[$tableName][$elementId];
216 } elseif (isset($column['is-NULL']) && ($column['is-NULL'] === 'yes')) {
217 $columnValue = NULL;
218 } else {
219 $columnValue = (string) $table->$columnName;
220 }
221
222 $insertArray[$columnName] = $columnValue;
223 }
224
225 $tableName = $table->getName();
226 $result = $database->exec_INSERTquery($tableName, $insertArray);
227 if ($result === FALSE) {
228 throw new Exception(
229 'Error when processing fixture file: ' . $path . ' Can not insert data to table ' . $tableName,
230 1376746262
231 );
232 }
233 if (isset($table['id'])) {
234 $elementId = (string) $table['id'];
235 $foreignKeys[$tableName][$elementId] = $database->sql_insert_id();
236 }
237 }
238 }
239 }