76 return substr(sha1($testCaseClassName), 0, 7);
86 return ORIGINAL_ROOT .
'typo3temp/functional-' . static::getInstanceIdentifier($testCaseClassName);
102 array $coreExtensionsToLoad,
103 array $testExtensionsToLoad,
104 array $pathsToLinkInTestInstance,
105 array $configurationToUse,
106 array $additionalFoldersToCreate
112 $this->initializeTestDatabase();
123 $this->setUpTestDatabase();
125 $this->createDatabaseStructure();
138 if (@file_get_contents($this->instancePath .
'/last_run.txt') <= (time() - 300)) {
157 $this->identifier = static::getInstanceIdentifier($testCaseClassName);
167 $this->instancePath = static::getInstancePath($testCaseClassName);
177 if (is_dir($this->instancePath)) {
190 $foldersToCreate = array_merge($this->defaultFoldersToCreate, $additionalFoldersToCreate);
191 foreach ($foldersToCreate as $folder) {
192 $success = mkdir($this->instancePath . $folder);
195 'Creating directory failed: ' . $this->instancePath . $folder,
202 file_put_contents($this->instancePath .
'/last_run.txt', time());
213 ORIGINAL_ROOT .
'typo3' => $this->instancePath .
'/typo3',
214 ORIGINAL_ROOT .
'index.php' => $this->instancePath .
'/index.php' 216 foreach ($linksToSet as $from => $to) {
217 $success = symlink($from, $to);
220 'Creating link failed: from ' . $from .
' to: ' . $to,
235 foreach ($extensionPaths as $extensionPath) {
236 $absoluteExtensionPath = ORIGINAL_ROOT . $extensionPath;
237 if (!is_dir($absoluteExtensionPath)) {
239 'Test extension path ' . $absoluteExtensionPath .
' not found',
243 $destinationPath = $this->instancePath .
'/typo3conf/ext/'. basename($absoluteExtensionPath);
244 $success = symlink($absoluteExtensionPath, $destinationPath);
247 'Can not link extension folder: ' . $absoluteExtensionPath .
' to ' . $destinationPath,
265 foreach ($pathsToLinkInTestInstance as $sourcePathToLinkInTestInstance => $destinationPathToLinkInTestInstance) {
266 $sourcePath = $this->instancePath .
'/' . ltrim($sourcePathToLinkInTestInstance,
'/');
267 if (!file_exists($sourcePath)) {
269 'Path ' . $sourcePath .
' not found',
273 $destinationPath = $this->instancePath .
'/' . ltrim($destinationPathToLinkInTestInstance,
'/');
274 $success = symlink($sourcePath, $destinationPath);
277 'Can not link the path ' . $sourcePath .
' to ' . $destinationPath,
293 $databaseHost = trim(getenv(
'typo3DatabaseHost'));
294 $databaseUsername = trim(getenv(
'typo3DatabaseUsername'));
295 $databasePassword = trim(getenv(
'typo3DatabasePassword'));
296 $databasePort = trim(getenv(
'typo3DatabasePort'));
297 $databaseSocket = trim(getenv(
'typo3DatabaseSocket'));
298 if (
$databaseName || $databaseHost || $databaseUsername || $databasePassword || $databasePort || $databaseSocket) {
300 $originalConfigurationArray = array(
304 $originalConfigurationArray[
'DB'][
'database'] =
$databaseName;
307 $originalConfigurationArray[
'DB'][
'host'] = $databaseHost;
309 if ($databaseUsername) {
310 $originalConfigurationArray[
'DB'][
'username'] = $databaseUsername;
312 if ($databasePassword) {
313 $originalConfigurationArray[
'DB'][
'password'] = $databasePassword;
316 $originalConfigurationArray[
'DB'][
'port'] = $databasePort;
318 if ($databaseSocket) {
319 $originalConfigurationArray[
'DB'][
'socket'] = $databaseSocket;
321 } elseif (file_exists(ORIGINAL_ROOT .
'typo3conf/LocalConfiguration.php')) {
323 $originalConfigurationArray = require ORIGINAL_ROOT .
'typo3conf/LocalConfiguration.php';
326 'Database credentials for functional tests are neither set through environment' 327 .
' variables, and can not be found in an existing LocalConfiguration file',
333 $finalConfigurationArray = require ORIGINAL_ROOT .
'typo3/sysext/core/Configuration/FactoryConfiguration.php';
335 $this->
mergeRecursiveWithOverrule($finalConfigurationArray, require ORIGINAL_ROOT .
'typo3/sysext/core/Build/Configuration/FunctionalTestsConfiguration.php');
337 $finalConfigurationArray[
'DB'] = $originalConfigurationArray[
'DB'];
339 $this->originalDatabaseName = $originalConfigurationArray[
'DB'][
'database'];
343 if (strlen($this->databaseName) > 64) {
344 $maximumOriginalDatabaseName = 64 - strlen(
'_ft' . $this->identifier);
346 'The name of the database that is used for the functional test (' . $this->databaseName .
')' .
347 ' exceeds the maximum length of 64 character allowed by MySQL. You have to shorten your' .
348 ' original database name to ' . $maximumOriginalDatabaseName .
' characters',
356 $this->instancePath .
'/typo3conf/LocalConfiguration.php',
360 $finalConfigurationArray
366 throw new Exception(
'Can not write local configuration', 1376657277);
381 $packageStates = array(
382 'packages' => array(),
387 foreach ($this->defaultActivatedCoreExtensions as $extensionName) {
388 $packageStates[
'packages'][$extensionName] = array(
390 'packagePath' =>
'typo3/sysext/' . $extensionName .
'/',
391 'classesPath' =>
'Classes/',
396 foreach ($coreExtensionsToLoad as $extensionName) {
397 if (isset($packageSates[
'packages'][$extensionName])) {
399 $extensionName .
' is already registered as default core extension to load, no need to load it explicitly',
403 $packageStates[
'packages'][$extensionName] = array(
405 'packagePath' =>
'typo3/sysext/' . $extensionName .
'/',
406 'classesPath' =>
'Classes/',
411 foreach ($testExtensionPaths as $extensionPath) {
412 $extensionName = basename($extensionPath);
413 if (isset($packageSates[
'packages'][$extensionName])) {
415 $extensionName .
' is already registered as extension to load, no need to load it explicitly',
419 $packageStates[
'packages'][$extensionName] = array(
421 'packagePath' =>
'typo3conf/ext/' . $extensionName .
'/',
422 'classesPath' =>
'Classes/',
427 $this->instancePath .
'/typo3conf/PackageStates.php',
437 throw new Exception(
'Can not write PackageStates', 1381612729);
448 $_SERVER[
'argv'][0] =
'index.php';
450 define(
'TYPO3_MODE',
'BE');
451 define(
'TYPO3_cliMode', TRUE);
453 require_once $this->instancePath .
'/typo3/sysext/core/Classes/Core/CliBootstrap.php';
456 require_once $this->instancePath .
'/typo3/sysext/core/Classes/Core/Bootstrap.php';
459 ->loadConfigurationAndInitialize(TRUE)
460 ->loadTypo3LoadedExtAndExtLocalconf(TRUE)
461 ->applyAdditionalConfigurationSettings();
470 protected function setUpTestDatabase() {
476 'TYPO3 Fatal Error: The current username, password or host was not accepted when the' 477 .
' connection to the database was attempted to be established!',
483 $database->admin_query(
'DROP DATABASE IF EXISTS `' . $this->databaseName .
'`');
484 $createDatabaseResult =
$database->admin_query(
'CREATE DATABASE `' . $this->databaseName .
'`');
485 if (!$createDatabaseResult) {
486 $user =
$GLOBALS[
'TYPO3_CONF_VARS'][
'DB'][
'username'];
489 'Unable to create database with name ' . $this->databaseName .
'. This is probably a permission problem.' 490 .
' For this instance this could be fixed executing' 491 .
' "GRANT ALL ON `' . $this->originalDatabaseName .
'_ft%`.* TO `' . $user .
'`@`' .
$host .
'`;"',
495 $database->setDatabaseName($this->databaseName);
496 $database->sql_select_db($this->databaseName);
506 protected function initializeTestDatabase() {
512 'TYPO3 Fatal Error: The current username, password or host was not accepted when the' 513 .
' connection to the database was attempted to be established!',
517 $this->databaseName =
$GLOBALS[
'TYPO3_CONF_VARS'][
'DB'][
'database'];
518 $database->setDatabaseName($this->databaseName);
520 @
$database->sql_select_db($this->databaseName);
521 foreach (
$database->admin_get_tables() as $table) {
522 $database->admin_query(
'TRUNCATE ' . $table[
'Name'] .
';');
531 protected function createDatabaseStructure() {
537 $expectedSchemaService = $objectManager->get(
'TYPO3\\CMS\\Install\\Service\\SqlExpectedSchemaService');
540 $expectedSchemaString = $expectedSchemaService->getTablesDefinitionString(TRUE);
541 $statements = $schemaMigrationService->getStatementArray($expectedSchemaString, TRUE);
542 list($_, $insertCount) = $schemaMigrationService->getCreateTables($statements, TRUE);
544 $fieldDefinitionsFile = $schemaMigrationService->getFieldDefinitions_fileContent($expectedSchemaString);
545 $fieldDefinitionsDatabase = $schemaMigrationService->getFieldDefinitions_database();
546 $difference = $schemaMigrationService->getDatabaseExtra($fieldDefinitionsFile, $fieldDefinitionsDatabase);
547 $updateStatements = $schemaMigrationService->getUpdateSuggestions($difference);
549 $schemaMigrationService->performUpdateQueries($updateStatements[
'add'], $updateStatements[
'add']);
550 $schemaMigrationService->performUpdateQueries($updateStatements[
'change'], $updateStatements[
'change']);
551 $schemaMigrationService->performUpdateQueries($updateStatements[
'create_table'], $updateStatements[
'create_table']);
553 foreach ($insertCount as $table => $count) {
554 $insertStatements = $schemaMigrationService->getTableInsertStatements($statements, $table);
555 foreach ($insertStatements as $insertQuery) {
556 $insertQuery = rtrim($insertQuery,
';');
570 protected function tearDownTestDatabase() {
573 $result =
$database->admin_query(
'DROP DATABASE `' . $this->databaseName .
'`');
576 'Dropping test database ' . $this->databaseName .
' failed',
589 $success = $this->
rmdir($this->instancePath, TRUE);
592 'Can not remove folder: ' . $this->instancePath,
607 protected function rmdir($path, $removeNonEmpty = FALSE) {
610 $path = preg_replace(
'|/$|',
'', $path);
611 if (file_exists($path)) {
613 if (!is_link($path) && is_dir($path)) {
614 if ($removeNonEmpty == TRUE && ($handle = opendir($path))) {
615 while ($OK && FALSE !== ($file = readdir($handle))) {
616 if ($file ==
'.' || $file ==
'..') {
619 $OK = $this->
rmdir($path .
'/' . $file, $removeNonEmpty);
628 if (!stristr(PHP_OS,
'darwin') && stristr(PHP_OS,
'win') && is_link($path) && is_dir($path .
'/')) {
635 } elseif (is_link($path)) {
652 if ($fd = fopen($file,
'wb')) {
653 $res = fwrite($fd, $content);
655 if ($res === FALSE) {
676 protected function arrayExport(array $array = array(), $level = 0) {
677 $lines =
'array(' . chr(10);
679 $writeKeyIndex = FALSE;
680 $expectedKeyIndex = 0;
681 foreach ($array as $key => $value) {
682 if ($key === $expectedKeyIndex) {
686 $writeKeyIndex = TRUE;
690 foreach ($array as $key => $value) {
692 $lines .= str_repeat(chr(9), $level);
693 if ($writeKeyIndex) {
695 $lines .= is_int($key) ? $key .
' => ' :
'\'' . $key .
'\' =>
'; 697 if (is_array($value)) { 698 if (count($value) > 0) { 699 $lines .= $this->arrayExport($value, $level); 701 $lines .= 'array(),
' . chr(10); 703 } elseif (is_int($value) || is_float($value)) { 704 $lines .= $value . ',
' . chr(10); 705 } elseif (is_null($value)) { 706 $lines .= 'NULL
' . ',
' . chr(10); 707 } elseif (is_bool($value)) { 708 $lines .= $value ? 'TRUE
' : 'FALSE
'; 709 $lines .= ',
' . chr(10); 710 } elseif (is_string($value)) { 712 $stringContent = str_replace('\\
', '\\\\
', $value); 714 $stringContent = str_replace('\
'',
'\\\'', $stringContent);
715 $lines .=
'\'' . $stringContent .
'\'' .
',' . chr(10);
717 throw new \RuntimeException(
'Objects are not supported', 1342294986);
720 $lines .= str_repeat(chr(9), ($level - 1)) .
')' . ($level - 1 == 0 ?
'' :
',' . chr(10));
746 protected function mergeRecursiveWithOverrule(array &$original, array $overrule, $addKeys = TRUE, $includeEmptyValues = TRUE, $enableUnsetFeature = TRUE) {
747 foreach ($overrule as $key => $_) {
748 if ($enableUnsetFeature && $overrule[$key] ===
'__UNSET') {
749 unset($original[$key]);
752 if (isset($original[$key]) && is_array($original[$key])) {
753 if (is_array($overrule[$key])) {
754 self::mergeRecursiveWithOverrule($original[$key], $overrule[$key], $addKeys, $includeEmptyValues, $enableUnsetFeature);
757 ($addKeys || isset($original[$key])) &&
758 ($includeEmptyValues || $overrule[$key])
760 $original[$key] = $overrule[$key];
arrayExport(array $array=array(), $level=0)
writeFile($file, $content)
static getInstancePath($testCaseClassName)
$defaultActivatedCoreExtensions
linkPathsInTestInstance(array $pathsToLinkInTestInstance)
setUp( $testCaseClassName, array $coreExtensionsToLoad, array $testExtensionsToLoad, array $pathsToLinkInTestInstance, array $configurationToUse, array $additionalFoldersToCreate)
static checkEnvironmentOrDie()
static makeInstance($className)
setUpInstanceDirectories(array $additionalFoldersToCreate=array())
linkTestExtensionsToInstance(array $extensionPaths)
setUpLocalConfiguration(array $configurationToMerge)
removeOldInstanceIfExists()
mergeRecursiveWithOverrule(array &$original, array $overrule, $addKeys=TRUE, $includeEmptyValues=TRUE, $enableUnsetFeature=TRUE)
if($list_of_literals) if(!empty($literals)) if(!empty($literals)) $result
Analyse literals to prepend the N char to them if their contents aren't numeric.
setUpBasicTypo3Bootstrap()
setUpIdentifier($testCaseClassName)
recentTestInstanceExists()
rmdir($path, $removeNonEmpty=FALSE)
if(!defined('TYPO3_MODE')) $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauth.php']['logoff_pre_processing'][]
setUpPackageStates(array $coreExtensionsToLoad, array $testExtensionPaths)
setUpInstancePath($testCaseClassName)
static getInstanceIdentifier($testCaseClassName)