diff --git a/core/DbConnectionWrapper.php b/core/DbConnectionWrapper.php index 2b25128ab..f432bb262 100644 --- a/core/DbConnectionWrapper.php +++ b/core/DbConnectionWrapper.php @@ -59,9 +59,16 @@ class DbConnectionWrapper * Use this to register a mock that will handle {@see mysqli::query()} * * @param \mysqli|null $oMysqli + * @since 3.0.4 3.1.1 3.2.0 Param $oMysqli becomes nullable */ - public static function SetDbConnectionMockForQuery(?mysqli $oMysqli): void + public static function SetDbConnectionMockForQuery(?mysqli $oMysqli = null): void { - static::$oDbCnxMockableForQuery = $oMysqli; + if (is_null($oMysqli)) { + // Reset to standard connection + static::$oDbCnxMockableForQuery = static::$oDbCnxStandard; + } + else { + static::$oDbCnxMockableForQuery = $oMysqli; + } } } \ No newline at end of file diff --git a/core/dict.class.inc.php b/core/dict.class.inc.php index e96ddfed9..ff9ef890a 100644 --- a/core/dict.class.inc.php +++ b/core/dict.class.inc.php @@ -56,10 +56,11 @@ class Dict * @param $sLanguageCode * * @throws \DictExceptionUnknownLanguage + * @since 3.0.4 3.1.1 3.2.0 Param $sLanguageCode becomes nullable */ - public static function SetUserLanguage($sLanguageCode) + public static function SetUserLanguage($sLanguageCode = null) { - if (!array_key_exists($sLanguageCode, self::$m_aLanguages)) + if (!is_null($sLanguageCode) && !array_key_exists($sLanguageCode, self::$m_aLanguages)) { throw new DictExceptionUnknownLanguage($sLanguageCode); } diff --git a/core/log.class.inc.php b/core/log.class.inc.php index 2af8dc5b2..8f59e7e4c 100644 --- a/core/log.class.inc.php +++ b/core/log.class.inc.php @@ -1138,7 +1138,7 @@ class DeprecatedCallsLog extends LogAPI parent::Enable($sTargetFile); if ( - (false === defined(ITOP_PHPUNIT_RUNNING_CONSTANT_NAME)) + (false === defined('ITOP_PHPUNIT_RUNNING_CONSTANT_NAME')) && static::IsLogLevelEnabledSafe(self::LEVEL_WARNING, self::ENUM_CHANNEL_PHP_LIBMETHOD) ) { set_error_handler([static::class, 'DeprecatedNoticesErrorHandler'], E_DEPRECATED | E_USER_DEPRECATED); diff --git a/core/metamodel.class.php b/core/metamodel.class.php index c8dd16292..60afe675f 100644 --- a/core/metamodel.class.php +++ b/core/metamodel.class.php @@ -6298,6 +6298,13 @@ abstract class MetaModel */ public static function Startup($config, $bModelOnly = false, $bAllowCache = true, $bTraceSourceFiles = false, $sEnvironment = 'production') { + // Startup on a new environment is not supported + static $bStarted = false; + if ($bStarted) { + return; + } + $bStarted = true; + self::$m_sEnvironment = $sEnvironment; try { @@ -6529,6 +6536,19 @@ abstract class MetaModel return $value; } + /** + * @internal Used for resetting the configuration during automated tests + + * @param \Config $oConfiguration + * + * @return void + * @since 3.0.4 3.1.1 3.2.0 + */ + public static function SetConfig(Config $oConfiguration) + { + self::$m_oConfig = $oConfiguration; + } + /** * @return Config */ diff --git a/core/userrights.class.inc.php b/core/userrights.class.inc.php index 699dd597d..317608927 100644 --- a/core/userrights.class.inc.php +++ b/core/userrights.class.inc.php @@ -761,14 +761,25 @@ class UserRights protected static $m_aCacheContactPictureAbsUrl = []; /** @var UserRightsAddOnAPI $m_oAddOn */ protected static $m_oAddOn; - protected static $m_oUser; - protected static $m_oRealUser; + protected static $m_oUser = null; + protected static $m_oRealUser = null; protected static $m_sSelfRegisterAddOn = null; protected static $m_aAdmins = array(); protected static $m_aPortalUsers = array(); /** @var array array('sName' => $sName, 'bSuccess' => $bSuccess); */ private static $m_sLastLoginStatus = null; + /** + * @return void + * @since 3.0.4 3.1.1 3.2.0 + */ + protected static function ResetCurrentUserData() + { + self::$m_oUser = null; + self::$m_oRealUser = null; + self::$m_sLastLoginStatus = null; + } + /** * @param string $sModuleName * @@ -787,8 +798,7 @@ class UserRights } self::$m_oAddOn = new $sModuleName; self::$m_oAddOn->Init(); - self::$m_oUser = null; - self::$m_oRealUser = null; + self::ResetCurrentUserData(); } /** @@ -855,6 +865,8 @@ class UserRights */ public static function Login($sLogin, $sAuthentication = 'any') { + static::Logoff(); + $oUser = self::FindUser($sLogin, $sAuthentication); if (is_null($oUser)) { @@ -872,6 +884,17 @@ class UserRights return true; } + /** + * @return void + * @since 3.0.4 3.1.1 3.2.0 + */ + public static function Logoff() + { + self::ResetCurrentUserData(); + Dict::SetUserLanguage(null); + self::_ResetSessionCache(); + } + /** * @param string $sLogin Login of the user to check the credentials for * @param string $sPassword diff --git a/datamodels/2.x/itop-backup/dbrestore.class.inc.php b/datamodels/2.x/itop-backup/dbrestore.class.inc.php index d285e8cf2..669d04bbc 100644 --- a/datamodels/2.x/itop-backup/dbrestore.class.inc.php +++ b/datamodels/2.x/itop-backup/dbrestore.class.inc.php @@ -235,13 +235,16 @@ class DBRestore extends DBBackup if (in_array($oFileInfo->getFilename(), $aStandardFiles)) { continue; } - if (strncmp($oFileInfo->getPathname(), $sDataDir.'/production-modules', strlen($sDataDir.'/production-modules')) == 0) { + // Normalize filenames to cope with Windows backslashes + $sPath = str_replace('\\', '/', $oFileInfo->getPathname()); + $sRefPath = str_replace('\\', '/', $sDataDir.'/production-modules'); + if (strncmp($sPath, $sRefPath, strlen($sRefPath)) == 0) { continue; } - + $aExtraFiles[$oFileInfo->getPathname()] = APPROOT.substr($oFileInfo->getPathname(), strlen($sDataDir)); } - + return $aExtraFiles; } } diff --git a/tests/php-unit-tests/README.md b/tests/php-unit-tests/README.md index e4058802c..26c32491a 100644 --- a/tests/php-unit-tests/README.md +++ b/tests/php-unit-tests/README.md @@ -1,7 +1,118 @@ # PHP unitary tests + ## Where should I add my test? - Covers an iTop PHP class or method? - Most likely in "unitary-tests". - Covers the consistency of some data through the app? - - Most likely in "integration-tests". \ No newline at end of file + - Most likely in "integration-tests". + +## How do I make sure that my tests are efficient? + + +### Derive from the relevant test class + +Whenever possible keep it the most simple, hence you should first +attempt to derive from `TestCase`. + +Then, you might need to derive from `ItopTestCase`. + +Finally, as a last resort, you will use `ItopDataTestCase`. + +### Determine the most relevant isolation configuration + +Should you have opted for `ItopDataTestCase`, then you will have to follow these steps: + +1) Build you test class until it is successfull, without process isolation. +2) Run the whole test suite [unitary-tests](unitary-tests) +3) If a false-positive appears, then you will start troubleshooting. One advise: be positive! + +### Leave the place clean + +To check your code against polluting coding patterns, run the test [integration-tests/DetectStaticPollutionTest.php](integration-tests/DetectStaticPollutionTest.php) +It will tell you if something is wrong, either in your code, or anywhere else in the tests. +Fortunately, it will give you an alternative. + +Detected patterns: +* ContextTag::addTag() +* EventService::RegisterListener() +* Dict::Add() + + +By the way, some patterns do not pollute, because they are handled by the test framework: +* Configuration : automatically reset after test class execution +* UserRights : a logoff is performed after each test execution +* Dict::SetUserLanguage: the user language is reset after each test execution + +See also `@beforeClass` and `@afterClass` to handle cleanup. + +If you can't, then ok you will have to isolate it! + +## Tips +### Memory limit + +As the tests are run in the same process, memory usage +may become an issue as soon as tests are all executed at once. + +Fix that in the XML configuration in the PHP section +```xml + +``` + +### Understand tests interactions + +With PHPStorm, select two tests, right click to get the context menu, then `run`. + +You will have both tests executed and you will be able to figure out if the first one has an impact on the second one. + +### About process isolation +#### Isolation with PHPUnit + +By default, tests are run in a single process launched by PHPUnit. + +If process isolation is configured for some tests, then those tests +will be executed in a separate process. The main process will +continue executing non isolated tests. + +#### Cost of isolation + +The cost of isolating a very basic `TestCase` is approximately 4 ms. + +The cost of isolating an `ItopDataTestCase` is approximately 800 ms. + +### Isolation within iTop + +#### At the test level (preferred) +Add annotation `@runInSeparateProcess` +Each and every test case will run in a separate +process. + +#### At the test class level +Add annotation `@runTestsInSeparateProcesses` +Each and every test case in the class will run in a separate +process. + +#### Globally (never do that) +Set it into [phpunit.xml.dist](phpunit.xml.dist) + +### Further enhancements +The annotation [`@runClassInSeparateProcess`](https://docs.phpunit.de/en/10.0/attributes.html?highlight=runclassinseparateprocess#runclassinseparateprocess) is supposed to do the perfect job, but it is buggy [(See Issue 5230)](https://github.com/sebastianbergmann/phpunit/issues/5230) and it has +the exact same effect as `@runTestsInSeparateProcesses`. + +Note : this option is documented only in the [attributes part of the documentation](https://docs.phpunit.de/en/10.0/attributes.html). + +### Traps +#### When it is a matter of stars +```php +/* + * @runTestsInSeparateProcesses +``` +This won't work because the comment MUST start with `/**` (two stars) to be considerer by PHPUnit. + +#### SetupBeforeClass called more often than expected + +`setupBeforeClass` is called once for the class **in a given process**. + +Therefore, if the tests are isolated, then `setupBeforeClass` will be called as often as `setUp`. + +This has been proven with [`runClassInSeparateProcessTest.php`](experiments/runClassInSeparateProcessTest.php) \ No newline at end of file diff --git a/tests/php-unit-tests/experiments/README.md b/tests/php-unit-tests/experiments/README.md new file mode 100644 index 000000000..56a83dc1a --- /dev/null +++ b/tests/php-unit-tests/experiments/README.md @@ -0,0 +1 @@ +This directory aims at providing experimental proof of the mechanics of PHPUnit \ No newline at end of file diff --git a/tests/php-unit-tests/experiments/runClassInSeparateProcessTest.php b/tests/php-unit-tests/experiments/runClassInSeparateProcessTest.php new file mode 100644 index 000000000..66ce826f7 --- /dev/null +++ b/tests/php-unit-tests/experiments/runClassInSeparateProcessTest.php @@ -0,0 +1,64 @@ +getName()."\n", + FILE_APPEND); + } + + function testA() + { + $this->LogPid(); + static::assertTrue(true); + } + + function testB() + { + $this->LogPid(); + static::assertTrue(true); + } + + /** + * @dataProvider CProvider + */ + function testC($i) + { + $this->LogPid(); + static::assertTrue(true); + } + + function CProvider() + { + return [ + [1], + [1], + [1], + [1], + ]; + } +} diff --git a/tests/php-unit-tests/experiments/tearDownAfterFailureTest.php b/tests/php-unit-tests/experiments/tearDownAfterFailureTest.php new file mode 100644 index 000000000..ff820dbbd --- /dev/null +++ b/tests/php-unit-tests/experiments/tearDownAfterFailureTest.php @@ -0,0 +1,45 @@ +expectException('Exception'); + throw new \Exception('hello'); + } + + function testIsStillInitialized() + { + static::assertTrue(static::$bIsCorrectlyInitialized); + } + + function testFailingDueToUnexpectedException() + { + static::$bIsCorrectlyInitialized = false; + This_Is_Not_A_Function_And_Causes_A_Fatal_Error(); + } + + function testIsStillInitializedAnyway() + { + static::assertTrue(static::$bIsCorrectlyInitialized); + } + +} diff --git a/tests/php-unit-tests/integration-tests/DetectStaticPollutionTest.php b/tests/php-unit-tests/integration-tests/DetectStaticPollutionTest.php new file mode 100644 index 000000000..6422ded62 --- /dev/null +++ b/tests/php-unit-tests/integration-tests/DetectStaticPollutionTest.php @@ -0,0 +1,68 @@ + $sLine) { + if (preg_match_all($sRegexp, $sLine, $aMatches, PREG_PATTERN_ORDER)) { + $sLine = $iLine + 1; + $aRes[] = "$sFile:$sLine"; + } + } + return $aRes; + } + + /** + * @dataProvider PollutingPatterns + * @param $sPattern + * + * @return void + */ + function testDetectPolluters($sPattern, $sFix) + { + $sScannedDir = dirname(__FILE__).'/../unitary-tests'; + + $aPolluters = []; + $oDirectory = new RecursiveDirectoryIterator($sScannedDir); + $Iterator = new RecursiveIteratorIterator($oDirectory); + foreach (new RegexIterator($Iterator, '/^.+\.php$/i', RecursiveRegexIterator::GET_MATCH) as $aMatch) { + $sFile = $aMatch[0]; + if(is_file($sFile)) { + $sFileContents = file_get_contents($sFile); + if (preg_match_all($sPattern, $sFileContents, $keys, PREG_PATTERN_ORDER)) { + $aPolluters = array_merge($aPolluters, $this->FindMatches($sFile, $sFileContents, $sPattern)); + } + } + } + $iPolluters = count($aPolluters); + static::assertTrue($iPolluters === 0, "Found polluter(s) for pattern $sPattern, $sFix:\n".implode("\n", $aPolluters)); + + } + + public function PollutingPatterns() + { + return [ + 'ContextTags' => ['/ContextTag::AddContext/i', 'Use new ContextTag() instead'], + 'Dict::Add' => ['/Dict::Add/i', 'TODO: implement a facade into ItopDataTestCase'], + 'EventService::RegisterListener' => ['/EventService::RegisterListener/i', 'Use ItopDataTestCase::EventService_RegisterListener instead'], + ]; + } + +} diff --git a/tests/php-unit-tests/integration-tests/DictionariesConsistencyTest.php b/tests/php-unit-tests/integration-tests/DictionariesConsistencyTest.php index 55432aeca..6bd776a68 100644 --- a/tests/php-unit-tests/integration-tests/DictionariesConsistencyTest.php +++ b/tests/php-unit-tests/integration-tests/DictionariesConsistencyTest.php @@ -98,10 +98,12 @@ class DictionariesConsistencyTest extends ItopTestCase { $this->setUp(); + $sAppRoot = $this->GetAppRoot(); + $aDictFiles = array_merge( - glob(APPROOT.'datamodels/2.x/*/*.dict*.php'), // legacy form in modules - glob(APPROOT.'datamodels/2.x/*/dictionaries/*.dict*.php'), // modern form in modules - glob(APPROOT.'dictionaries/*.dict*.php') // framework + glob($sAppRoot.'datamodels/2.x/*/*.dict*.php'), // legacy form in modules + glob($sAppRoot.'datamodels/2.x/*/dictionaries/*.dict*.php'), // modern form in modules + glob($sAppRoot.'dictionaries/*.dict*.php') // framework ); $aTestCases = array(); foreach ($aDictFiles as $sDictFile) { diff --git a/tests/php-unit-tests/integration-tests/iTopModulesXmlVersionChecklistTest.php b/tests/php-unit-tests/integration-tests/iTopModulesXmlVersionChecklistTest.php index b69ab6cca..31e5dddfc 100644 --- a/tests/php-unit-tests/integration-tests/iTopModulesXmlVersionChecklistTest.php +++ b/tests/php-unit-tests/integration-tests/iTopModulesXmlVersionChecklistTest.php @@ -72,11 +72,13 @@ class iTopModulesXmlVersionIntegrationTest extends ItopTestCase { static::setUp(); - $sPath = APPROOT.'datamodels/2.x/*/datamodel.*.xml'; + $sAppRoot = $this->GetAppRoot(); + + $sPath = $sAppRoot.'datamodels/2.x/*/datamodel.*.xml'; $aXmlFiles = glob($sPath); - $aXmlFiles[] = APPROOT.'core/datamodel.core.xml'; - $aXmlFiles[] = APPROOT.'application/datamodel.application.xml'; + $aXmlFiles[] = $sAppRoot.'core/datamodel.core.xml'; + $aXmlFiles[] = $sAppRoot.'application/datamodel.application.xml'; $aTestCases = array(); foreach ($aXmlFiles as $sXmlFile) { diff --git a/tests/php-unit-tests/phpunit.xml.dist b/tests/php-unit-tests/phpunit.xml.dist index 25ce82c85..419e26538 100644 --- a/tests/php-unit-tests/phpunit.xml.dist +++ b/tests/php-unit-tests/phpunit.xml.dist @@ -20,6 +20,7 @@ > + diff --git a/tests/php-unit-tests/src/BaseTestCase/ItopDataTestCase.php b/tests/php-unit-tests/src/BaseTestCase/ItopDataTestCase.php index 79bfc7251..8f744235b 100644 --- a/tests/php-unit-tests/src/BaseTestCase/ItopDataTestCase.php +++ b/tests/php-unit-tests/src/BaseTestCase/ItopDataTestCase.php @@ -55,12 +55,6 @@ define('TAG_ATTCODE', 'domains'); * * Helper class to extend for tests needing access to iTop's metamodel * - * **⚠ Warning** Each class extending this one needs to add the following annotations : - * - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled - * * @since 2.7.7 3.0.1 3.1.0 N°4624 processIsolation is disabled by default and must be enabled in each test needing it (basically all tests using * iTop datamodel) */ @@ -69,10 +63,8 @@ abstract class ItopDataTestCase extends ItopTestCase private $iTestOrgId; // For cleanup - private $aCreatedObjects = array(); - - // Counts - public $aReloadCount = []; + private $aCreatedObjects = []; + private $aEventListeners = []; /** * @var string Default environment to use for test cases @@ -81,6 +73,23 @@ abstract class ItopDataTestCase extends ItopTestCase const USE_TRANSACTION = true; const CREATE_TEST_ORG = false; + /** + * This method is called before the first test of this test class is run (in the current process). + */ + public static function setUpBeforeClass(): void + { + parent::setUpBeforeClass(); + } + + /** + * This method is called after the last test of this test class is run (in the current process). + */ + public static function tearDownAfterClass(): void + { + \UserRights::FlushPrivileges(); + parent::tearDownAfterClass(); + } + /** * @throws Exception */ @@ -98,8 +107,6 @@ abstract class ItopDataTestCase extends ItopTestCase { $this->CreateTestOrganization(); } - - EventService::RegisterListener(EVENT_DB_OBJECT_RELOAD, [$this, 'CountObjectReload']); } /** @@ -107,6 +114,9 @@ abstract class ItopDataTestCase extends ItopTestCase */ protected function tearDown(): void { + static::SetNonPublicStaticProperty(\cmdbAbstractObject::class, 'aObjectsAwaitingEventDbLinksChanged', []); + \cmdbAbstractObject::SetEventDBLinksChangedBlocked(false); + if (static::USE_TRANSACTION) { $this->debug("ROLLBACK !!!"); CMDBSource::Query('ROLLBACK'); @@ -128,6 +138,15 @@ abstract class ItopDataTestCase extends ItopTestCase } } } + // As soon as a rollback has been performed, each object memoized should be discarded + CMDBObject::SetCurrentChange(null); + + // Leave the place clean + \UserRights::Logoff(); + + foreach ($this->aEventListeners as $sListenerId) { + EventService::UnRegisterListener($sListenerId); + } parent::tearDown(); } @@ -186,6 +205,31 @@ abstract class ItopDataTestCase extends ItopTestCase return $this->iTestOrgId; } + ///////////////////////////////////////////////////////////////////////////// + /// Facades for environment settings + ///////////////////////////////////////////////////////////////////////////// + /** + * Facade for EventService::RegisterListener + * + * @param string $sEvent + * @param callable $callback + * @param $sEventSource + * @param array $aCallbackData + * @param $context + * @param float $fPriority + * @param $sModuleId + * + * @return string + */ + public function EventService_RegisterListener(string $sEvent, callable $callback, $sEventSource = null, array $aCallbackData = [], $context = null, float $fPriority = 0.0, $sModuleId = ''): string + { + $ret = EventService::RegisterListener($sEvent, $callback, $sEventSource, $aCallbackData, $context, $fPriority, $sModuleId); + if (false !== $ret) { + $this->aEventListeners[] = $ret; + } + return $ret; + } + ///////////////////////////////////////////////////////////////////////////// /// MetaModel Utilities ///////////////////////////////////////////////////////////////////////////// @@ -880,49 +924,6 @@ abstract class ItopDataTestCase extends ItopTestCase return $oOrg; } - public function ResetReloadCount() - { - $this->aReloadCount = []; - } - - public function DebugReloadCount($sMsg, $bResetCount = true) - { - $iTotalCount = 0; - $aTotalPerClass = []; - foreach ($this->aReloadCount as $sClass => $aCountByKeys) { - $iClassCount = 0; - foreach ($aCountByKeys as $iCount) { - $iClassCount += $iCount; - } - $iTotalCount += $iClassCount; - $aTotalPerClass[$sClass] = $iClassCount; - } - $this->debug("$sMsg - $iTotalCount reload(s)"); - foreach ($this->aReloadCount as $sClass => $aCountByKeys) { - $this->debug(" $sClass => $aTotalPerClass[$sClass] reload(s)"); - foreach ($aCountByKeys as $sKey => $iCount) { - $this->debug(" $sClass::$sKey => $iCount"); - } - } - if ($bResetCount) { - $this->ResetReloadCount(); - } - } - - public function CountObjectReload(EventData $oData) - { - $oObject = $oData->Get('object'); - $sClass = get_class($oObject); - $sKey = $oObject->GetKey(); - $iCount = $this->GetObjectReloadCount($sClass, $sKey); - $this->aReloadCount[$sClass][$sKey] = 1 + $iCount; - } - - public function GetObjectReloadCount($sClass, $sKey) - { - return $this->aReloadCount[$sClass][$sKey] ?? 0; - } - /** * Assert that a series of operations will trigger a given number of MySL queries * @@ -949,6 +950,17 @@ abstract class ItopDataTestCase extends ItopTestCase } } + protected function assertDBChangeOpCount(string $sClass, $iId, int $iExpectedCount) + { + $oSearch = new \DBObjectSearch('CMDBChangeOp'); + $oSearch->AddCondition('objclass', $sClass); + $oSearch->AddCondition('objkey', $iId); + $oSearch->AllowAllData(); + $oSet = new \DBObjectSet($oSearch); + $iCount = $oSet->Count(); + $this->assertEquals($iExpectedCount, $iCount, "Found $iCount changes for object $sClass::$iId"); + } + /** * Import a set of XML files describing a consistent set of iTop objects * @param string[] $aFiles diff --git a/tests/php-unit-tests/src/BaseTestCase/ItopTestCase.php b/tests/php-unit-tests/src/BaseTestCase/ItopTestCase.php index 0db92dba3..2657836b0 100644 --- a/tests/php-unit-tests/src/BaseTestCase/ItopTestCase.php +++ b/tests/php-unit-tests/src/BaseTestCase/ItopTestCase.php @@ -21,30 +21,54 @@ use SetupUtils; */ abstract class ItopTestCase extends TestCase { - const TEST_LOG_DIR = 'test'; - static $DEBUG_UNIT_TEST = false; + public const TEST_LOG_DIR = 'test'; + public static $DEBUG_UNIT_TEST = false; - /** @noinspection UsingInclusionOnceReturnValueInspection avoid errors for approot includes */ - protected function setUp(): void { - $sAppRootRelPath = 'approot.inc.php'; - $sDepthSeparator = '../'; - for ($iDepth = 0; $iDepth < 8; $iDepth++) { - if (file_exists($sAppRootRelPath)) { - require_once $sAppRootRelPath; - break; - } + /** + * Override the default value to disable the backup of globals in case of tests run in a separate process + */ + protected $preserveGlobalState = false; - $sAppRootRelPath = $sDepthSeparator.$sAppRootRelPath; - } + /** + * This method is called before the first test of this test class is run (in the current process). + */ + public static function setUpBeforeClass(): void + { + parent::setUpBeforeClass(); static::$DEBUG_UNIT_TEST = getenv('DEBUG_UNIT_TEST'); - $this->debug("\n----------\n---------- ".$this->getName()."\n----------\n"); + require_once static::GetAppRoot() . 'approot.inc.php'; - if (false === defined(ITOP_PHPUNIT_RUNNING_CONSTANT_NAME)) { + if (false === defined('ITOP_PHPUNIT_RUNNING_CONSTANT_NAME')) { // setUp might be called multiple times, so protecting the define() call ! - define(ITOP_PHPUNIT_RUNNING_CONSTANT_NAME, true); + define('ITOP_PHPUNIT_RUNNING_CONSTANT_NAME', true); } + } + + /** + * This method is called after the last test of this test class is run (in the current process). + */ + public static function tearDownAfterClass(): void + { + parent::tearDownAfterClass(); + + if (method_exists('utils', 'GetConfig')) { + // Reset the config by forcing the load from disk + $oConfig = \utils::GetConfig(true); + if (method_exists('MetaModel', 'SetConfig')) { + \MetaModel::SetConfig($oConfig); + } + } + if (method_exists('Dict', 'SetUserLanguage')) { + \Dict::SetUserLanguage(); + } + } + + protected function setUp(): void { + parent::setUp(); + + $this->debug("\n----------\n---------- ".$this->getName()."\n----------\n"); $this->LoadRequiredItopFiles(); $this->LoadRequiredTestFiles(); @@ -60,10 +84,38 @@ abstract class ItopTestCase extends TestCase if (CMDBSource::IsInsideTransaction()) { // Nested transactions were opened but not finished ! + // Rollback to avoid side effects on next tests + while (CMDBSource::IsInsideTransaction()) { + CMDBSource::Query('ROLLBACK'); + } throw new MySQLTransactionNotClosedException('Some DB transactions were opened but not closed ! Fix the code by adding ROLLBACK or COMMIT statements !', []); } } + /** Helper than can be called in the context of a data provider */ + public static function GetAppRoot() + { + if (defined('APPROOT')) { + return APPROOT; + } + $sSearchPath = __DIR__; + for ($iDepth = 0; $iDepth < 8; $iDepth++) { + if (file_exists($sSearchPath.'/approot.inc.php')) { + break; + } + $iOffsetSep = strrpos($sSearchPath, '/'); + if ($iOffsetSep === false) { + $iOffsetSep = strrpos($sSearchPath, '\\'); + if ($iOffsetSep === false) { + // Do not throw an exception here as PHPUnit will not show it clearly when determing the list of test to perform + return 'Could not find the approot file in '.$sSearchPath; + } + } + $sSearchPath = substr($sSearchPath, 0, $iOffsetSep); + } + return $sSearchPath.'/'; + } + /** * Overload this method to require necessary files through {@see \Combodo\iTop\Test\UnitTest\ItopTestCase::RequireOnceItopFile()} * @@ -97,7 +149,7 @@ abstract class ItopTestCase extends TestCase */ protected function RequireOnceItopFile(string $sFileRelPath): void { - require_once APPROOT . $sFileRelPath; + require_once $this->GetAppRoot() . $sFileRelPath; } /** @@ -165,7 +217,7 @@ abstract class ItopTestCase extends TestCase /** * @since 2.7.4 3.0.0 */ - public function InvokeNonPublicStaticMethod($sObjectClass, $sMethodName, $aArgs) + public function InvokeNonPublicStaticMethod($sObjectClass, $sMethodName, $aArgs = []) { return $this->InvokeNonPublicMethod($sObjectClass, $sMethodName, null, $aArgs); } @@ -182,7 +234,7 @@ abstract class ItopTestCase extends TestCase * * @since 2.7.4 3.0.0 */ - public function InvokeNonPublicMethod($sObjectClass, $sMethodName, $oObject, $aArgs) + public function InvokeNonPublicMethod($sObjectClass, $sMethodName, $oObject, $aArgs = []) { $class = new \ReflectionClass($sObjectClass); $method = $class->getMethod($sMethodName); diff --git a/tests/php-unit-tests/tools/run_class_by_class.php b/tests/php-unit-tests/tools/run_class_by_class.php new file mode 100644 index 000000000..8a3256f7f --- /dev/null +++ b/tests/php-unit-tests/tools/run_class_by_class.php @@ -0,0 +1,64 @@ + $sLine) { + // Example of formats to be filtered + //- DatamodelsXmlFilesTest::testAllItopXmlFilesCovered + //- Combodo\iTop\Test\UnitTest\Application\DashboardLayoutTest::testGetDashletCoordinates"OneColLayout-Cell0" + //if (preg_match('@^- ([a-z]+\\\\)*([a-z]+::[a-z0-9]+)@i', $sLine, $aMatches)) { + if (preg_match('@([a-z0-9]+)::test@i', $sLine, $aMatches)) { + $sTestClass = $aMatches[1]; + $aClasses[$sTestClass] = $sTestClass; + } + } + return array_keys($aClasses); +} + +function RunTests($sFilterRegExp, $sUnitaryTestsDir = '', $bPassthru = false) +{ + $sRegExpShellArg = '"'.str_replace('"', '\\"', $sFilterRegExp).'"'; + $sConfigFile = ITOP_PHPUNIT."/phpunit.xml.dist"; + $sCommand = PHPUNIT_COMMAND." --configuration $sConfigFile --filter $sRegExpShellArg $sUnitaryTestsDir"; + ///echo "executing <<<$sCommand>>>\n"; + if ($bPassthru) { + passthru($sCommand, $iResultCode); + } + else { + exec($sCommand, $aTrashedOutput, $iResultCode); + } + $bTestSuccess = ($iResultCode == 0); // or 1 in case of a failing test + return $bTestSuccess; +} + +$sUnitaryTestsDir = ''; + +$aTestClasses = ListTests($sUnitaryTestsDir); +echo "Found ".count($aTestClasses)." to execute: ".implode(", ", $aTestClasses)."\n"; +echo "Testing...\n"; +foreach ($aTestClasses as $sTestClass) { + $fStarted = microtime(true); + $bSuccess = RunTests($sTestClass); + $sDuration = round(microtime(true) - $fStarted, 3); + echo "$sTestClass: ".($bSuccess ? 'Ok' : "FAILURE")." [$sDuration s]\n"; +} \ No newline at end of file diff --git a/tests/php-unit-tests/unitary-tests/application/Session/SessionTest.php b/tests/php-unit-tests/unitary-tests/application/Session/SessionTest.php index 8d8e31682..5bfd8467b 100644 --- a/tests/php-unit-tests/unitary-tests/application/Session/SessionTest.php +++ b/tests/php-unit-tests/unitary-tests/application/Session/SessionTest.php @@ -7,8 +7,6 @@ use Combodo\iTop\Test\UnitTest\ItopTestCase; /** * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled */ class SessionTest extends ItopTestCase { diff --git a/tests/php-unit-tests/unitary-tests/application/ThemeHandlerTest.php b/tests/php-unit-tests/unitary-tests/application/ThemeHandlerTest.php index e48d43bc5..b8412201a 100644 --- a/tests/php-unit-tests/unitary-tests/application/ThemeHandlerTest.php +++ b/tests/php-unit-tests/unitary-tests/application/ThemeHandlerTest.php @@ -7,9 +7,6 @@ use FindStylesheetObject; use ThemeHandler; /** - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled * @covers ThemeHandler */ class ThemeHandlerTest extends ItopTestCase diff --git a/tests/php-unit-tests/unitary-tests/application/UI/Base/Layout/NavigationMenuTest.php b/tests/php-unit-tests/unitary-tests/application/UI/Base/Layout/NavigationMenuTest.php index 821befcaf..678003f0f 100644 --- a/tests/php-unit-tests/unitary-tests/application/UI/Base/Layout/NavigationMenuTest.php +++ b/tests/php-unit-tests/unitary-tests/application/UI/Base/Layout/NavigationMenuTest.php @@ -9,9 +9,6 @@ use Combodo\iTop\Test\UnitTest\ItopDataTestCase; /** * - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled * Class NavigationMenuTest * * @package UI\Base\Layout diff --git a/tests/php-unit-tests/unitary-tests/application/cmdbAbstractObjectTest.php b/tests/php-unit-tests/unitary-tests/application/cmdbAbstractObjectTest.php index e2d90b7de..71cbd4484 100644 --- a/tests/php-unit-tests/unitary-tests/application/cmdbAbstractObjectTest.php +++ b/tests/php-unit-tests/unitary-tests/application/cmdbAbstractObjectTest.php @@ -4,11 +4,6 @@ use Combodo\iTop\Service\Events\EventData; use Combodo\iTop\Service\Events\EventService; use Combodo\iTop\Test\UnitTest\ItopDataTestCase; -/** - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled - */ class cmdbAbstractObjectTest extends ItopDataTestCase { const USE_TRANSACTION = true; const CREATE_TEST_ORG = true; @@ -18,6 +13,8 @@ class cmdbAbstractObjectTest extends ItopDataTestCase { protected function setUp(): void { + static::$aEventCalls = []; + static::$iEventCalls = 0; parent::setUp(); } @@ -80,6 +77,9 @@ class cmdbAbstractObjectTest extends ItopDataTestCase { self::assertSame($aExpectedLinkStack, $aLinkModificationsStack); } + /** + * @runInSeparateProcess + */ public function testProcessClassIdDeferredUpdate() { // Create the team @@ -157,6 +157,7 @@ class cmdbAbstractObjectTest extends ItopDataTestCase { } /** + * @runInSeparateProcess * Check that EVENT_DB_LINKS_CHANGED events are not sent to the current updated/created object (Team) * the events are sent to the other side (Person) * @@ -188,7 +189,7 @@ class cmdbAbstractObjectTest extends ItopDataTestCase { $this->debug("\n-------------> Test Starts HERE\n"); - $oEventReceiver = new LinksEventReceiver(); + $oEventReceiver = new LinksEventReceiver($this); $oEventReceiver->RegisterCRUDListeners(); $oTeam = MetaModel::NewObject(Team::class, ['name' => 'TestTeam1', 'persons_list' => $oLinkSet, 'org_id' => $this->getTestOrgId()]); @@ -200,6 +201,8 @@ class cmdbAbstractObjectTest extends ItopDataTestCase { } /** + * @runInSeparateProcess + * * Check that EVENT_DB_LINKS_CHANGED events are sent to all the linked objects when creating a new lnk object * * @return void @@ -223,7 +226,7 @@ class cmdbAbstractObjectTest extends ItopDataTestCase { $this->assertIsObject($oTeam); $this->debug("\n-------------> Test Starts HERE\n"); - $oEventReceiver = new LinksEventReceiver(); + $oEventReceiver = new LinksEventReceiver($this); $oEventReceiver->RegisterCRUDListeners(); // The link creation will signal both the Person an the Team @@ -235,6 +238,7 @@ class cmdbAbstractObjectTest extends ItopDataTestCase { } /** + * @runInSeparateProcess * Check that EVENT_DB_LINKS_CHANGED events are sent to all the linked objects when updating an existing lnk object * * @return void @@ -262,7 +266,7 @@ class cmdbAbstractObjectTest extends ItopDataTestCase { $oLink->DBInsert(); $this->debug("\n-------------> Test Starts HERE\n"); - $oEventReceiver = new LinksEventReceiver(); + $oEventReceiver = new LinksEventReceiver($this); $oEventReceiver->RegisterCRUDListeners(); // The link update will signal both the Person, the Team and the ContactType @@ -277,6 +281,7 @@ class cmdbAbstractObjectTest extends ItopDataTestCase { } /** + * @runInSeparateProcess * Check that when a link changes from an object to another, then both objects are notified * * @return void @@ -307,7 +312,7 @@ class cmdbAbstractObjectTest extends ItopDataTestCase { $oLink->DBInsert(); $this->debug("\n-------------> Test Starts HERE\n"); - $oEventReceiver = new LinksEventReceiver(); + $oEventReceiver = new LinksEventReceiver($this); $oEventReceiver->RegisterCRUDListeners(); // The link update will signal both the Persons and the Team @@ -320,6 +325,7 @@ class cmdbAbstractObjectTest extends ItopDataTestCase { } /** + * @runInSeparateProcess * Check that EVENT_DB_LINKS_CHANGED events are sent to all the linked objects when deleting an existing lnk object * * @return void @@ -347,7 +353,7 @@ class cmdbAbstractObjectTest extends ItopDataTestCase { $oLink->DBInsert(); $this->debug("\n-------------> Test Starts HERE\n"); - $oEventReceiver = new LinksEventReceiver(); + $oEventReceiver = new LinksEventReceiver($this); $oEventReceiver->RegisterCRUDListeners(); // The link delete will signal both the Person an the Team @@ -383,10 +389,16 @@ class cmdbAbstractObjectTest extends ItopDataTestCase { */ class LinksEventReceiver { + private $oTestCase; private $aCallbacks = []; public static $bIsObjectInCrudStack; + public function __construct(ItopDataTestCase $oTestCase) + { + $this->oTestCase = $oTestCase; + } + public function AddCallback(string $sEvent, string $sClass, string $sFct, int $iCount = 1): void { $this->aCallbacks[$sEvent][$sClass] = [ @@ -423,53 +435,10 @@ class LinksEventReceiver { $this->Debug('Registering Test event listeners'); if (is_null($sEvent)) { - EventService::RegisterListener(EVENT_DB_LINKS_CHANGED, [$this, 'OnEvent']); + $this->oTestCase->EventService_RegisterListener(EVENT_DB_LINKS_CHANGED, [$this, 'OnEvent']); return; } - EventService::RegisterListener($sEvent, [$this, 'OnEvent'], $mEventSource); - } - - /** - * @param $oObject - * - * @return void - * @throws \ArchivedObjectException - * @throws \CoreCannotSaveObjectException - * @throws \CoreException - * @throws \CoreUnexpectedValue - * @throws \CoreWarning - * @throws \MySQLException - * @throws \OQLException - */ - private function AddRoleToLink($oObject): void - { - $this->Debug(__METHOD__); - $oContactType = MetaModel::NewObject(ContactType::class, ['name' => 'test_'.$oObject->GetKey()]); - $oContactType->DBInsert(); - $oObject->Set('role_id', $oContactType->GetKey()); - } - - private function SetPersonFunction($oObject): void - { - $this->Debug(__METHOD__); - $oObject->Set('function', 'CRUD_function_'.rand()); - } - - private function SetPersonFirstName($oObject): void - { - $this->Debug(__METHOD__); - $oObject->Set('first_name', 'CRUD_first_name_'.rand()); - } - - private function CheckCrudStack(DBObject $oObject): void - { - self::$bIsObjectInCrudStack = DBObject::IsObjectCurrentlyInCrud(get_class($oObject), $oObject->GetKey()); - } - - private function CheckUpdateInLnk(lnkPersonToTeam $oLnkPersonToTeam) - { - $iTeamId = $oLnkPersonToTeam->Get('team_id'); - self::$bIsObjectInCrudStack = DBObject::IsObjectCurrentlyInCrud(Team::class, $iTeamId); + $this->oTestCase->EventService_RegisterListener($sEvent, [$this, 'OnEvent'], $mEventSource); } private function Debug($msg) diff --git a/tests/php-unit-tests/unitary-tests/application/privUITransactionFileTest.php b/tests/php-unit-tests/unitary-tests/application/privUITransactionFileTest.php index 6fdfbf58e..f570c3692 100644 --- a/tests/php-unit-tests/unitary-tests/application/privUITransactionFileTest.php +++ b/tests/php-unit-tests/unitary-tests/application/privUITransactionFileTest.php @@ -25,10 +25,6 @@ use privUITransactionFile; use UserRights; /** - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled - * * @covers utils * @group sampleDataNeeded * @group defaultProfiles @@ -180,7 +176,7 @@ class privUITransactionFileTest extends ItopDataTestCase $this->assertTrue($bResult, 'Token created by support user must be removed in the support user context'); // test when no user logged (combodo-unauthenticated-form module for example) - UserRights::_ResetSessionCache(); + UserRights::Logoff(); $sTransactionIdUnauthenticatedUser = privUITransactionFile::GetNewTransactionId(); $bResult = privUITransactionFile::IsTransactionValid($sTransactionIdUnauthenticatedUser, false); $this->assertTrue($bResult, 'Token created by unauthenticated user must be valid when no user logged'); diff --git a/tests/php-unit-tests/unitary-tests/application/query/QueryTest.php b/tests/php-unit-tests/unitary-tests/application/query/QueryTest.php index 9c2ab7f84..2e9e33e65 100644 --- a/tests/php-unit-tests/unitary-tests/application/query/QueryTest.php +++ b/tests/php-unit-tests/unitary-tests/application/query/QueryTest.php @@ -33,9 +33,6 @@ use QueryOQL; * All objects created in this test will be deleted by the test. * * @group iTopQuery - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled */ class QueryTest extends ItopDataTestCase { diff --git a/tests/php-unit-tests/unitary-tests/application/utilsTest.php b/tests/php-unit-tests/unitary-tests/application/utilsTest.php index 4e4209c7a..61ca59276 100644 --- a/tests/php-unit-tests/unitary-tests/application/utilsTest.php +++ b/tests/php-unit-tests/unitary-tests/application/utilsTest.php @@ -25,6 +25,7 @@ use Combodo\iTop\Test\UnitTest\ItopTestCase; use utils; /** + * @runClassInSeparateProcess * @covers utils */ class utilsTest extends ItopTestCase @@ -68,36 +69,36 @@ class utilsTest extends ItopTestCase public function realPathDataProvider() { - parent::setUp(); // if not called, APPROOT won't be defined :( + $sAppRoot = static::GetAppRoot(); $sSep = DIRECTORY_SEPARATOR; - $sItopRootRealPath = realpath(APPROOT).$sSep; + $sItopRootRealPath = realpath($sAppRoot).$sSep; $sLicenseFileName = 'license.txt'; - if (!is_file(APPROOT.$sLicenseFileName)) + if (!is_file($sAppRoot.$sLicenseFileName)) { $sLicenseFileName = 'LICENSE'; } return [ - $sLicenseFileName => [APPROOT.$sLicenseFileName, APPROOT, $sItopRootRealPath.$sLicenseFileName], - 'unexisting file' => [APPROOT.'license_DOES_NOT_EXIST.txt', APPROOT, false], - '/'.$sLicenseFileName => [APPROOT.$sSep.$sLicenseFileName, APPROOT, $sItopRootRealPath.$sLicenseFileName], - '%2f'.$sLicenseFileName => [APPROOT.'%2f'. $sLicenseFileName, APPROOT, false], - '../'.$sLicenseFileName => [APPROOT.'..'.$sSep.$sLicenseFileName, APPROOT, false], - '%2e%2e%2f'.$sLicenseFileName => [APPROOT.'%2e%2e%2f'.$sLicenseFileName, APPROOT, false], + $sLicenseFileName => [$sAppRoot.$sLicenseFileName, $sAppRoot, $sItopRootRealPath.$sLicenseFileName], + 'unexisting file' => [$sAppRoot.'license_DOES_NOT_EXIST.txt', $sAppRoot, false], + '/'.$sLicenseFileName => [$sAppRoot.$sSep.$sLicenseFileName, $sAppRoot, $sItopRootRealPath.$sLicenseFileName], + '%2f'.$sLicenseFileName => [$sAppRoot.'%2f'. $sLicenseFileName, $sAppRoot, false], + '../'.$sLicenseFileName => [$sAppRoot.'..'.$sSep.$sLicenseFileName, $sAppRoot, false], + '%2e%2e%2f'.$sLicenseFileName => [$sAppRoot.'%2e%2e%2f'.$sLicenseFileName, $sAppRoot, false], 'application/utils.inc.php with basepath=APPROOT' => [ - APPROOT.'application/utils.inc.php', - APPROOT, + $sAppRoot.'application/utils.inc.php', + $sAppRoot, $sItopRootRealPath.'application'.$sSep.'utils.inc.php', ], 'application/utils.inc.php with basepath=APPROOT/application' => [ - APPROOT.'application/utils.inc.php', - APPROOT.'application', + $sAppRoot.'application/utils.inc.php', + $sAppRoot.'application', $sItopRootRealPath.'application'.$sSep.'utils.inc.php', ], 'basepath containing / and \\' => [ - APPROOT.'sources/Form/Form.php', - APPROOT.'sources/Form\\Form.php', + $sAppRoot.'sources/Form/Form.php', + $sAppRoot.'sources/Form\\Form.php', $sItopRootRealPath.'sources'.$sSep.'Form'.$sSep.'Form.php', ], ]; @@ -117,13 +118,14 @@ class utilsTest extends ItopTestCase public function LocalPathProvider() { + $sAppRoot = static::GetAppRoot(); return array( 'index.php' => array( - 'sAbsolutePath' => APPROOT.'index.php', + 'sAbsolutePath' => $sAppRoot.'index.php', 'expected' => 'index.php', ), 'non existing' => array( - 'sAbsolutePath' => APPROOT.'nonexisting/nonexisting', + 'sAbsolutePath' => $sAppRoot.'nonexisting/nonexisting', 'expected' => false, ), 'outside' => array( @@ -131,15 +133,15 @@ class utilsTest extends ItopTestCase 'expected' => false, ), 'application/cmdbabstract.class.inc.php' => array( - 'sAbsolutePath' => APPROOT.'application/cmdbabstract.class.inc.php', + 'sAbsolutePath' => $sAppRoot.'application/cmdbabstract.class.inc.php', 'expected' => 'application/cmdbabstract.class.inc.php', ), 'dir' => array( - 'sAbsolutePath' => APPROOT.'application/.', + 'sAbsolutePath' => $sAppRoot.'application/.', 'expected' => 'application', ), 'root' => array( - 'sAbsolutePath' => APPROOT.'.', + 'sAbsolutePath' => $sAppRoot.'.', 'expected' => '', ), ); @@ -288,7 +290,7 @@ class utilsTest extends ItopTestCase public function GetDefaultUrlAppRootProvider() { - $this->setUp(); + $sAppRoot = static::GetAppRoot(); $baseServerVar = [ 'REMOTE_ADDR' => '127.0.0.1', //is not set, disable IsProxyTrusted @@ -298,7 +300,7 @@ class utilsTest extends ItopTestCase 'HTTP_X_FORWARDED_PORT' => null, 'REQUEST_URI' => '/index.php?baz=1', 'SCRIPT_NAME' => '/index.php', - 'SCRIPT_FILENAME' => APPROOT.'index.php', + 'SCRIPT_FILENAME' => $sAppRoot.'index.php', 'QUERY_STRING' => 'baz=1', 'HTTP_X_FORWARDED_PROTO' => null, 'HTTP_X_FORWARDED_PROTOCOL' => null, @@ -629,23 +631,21 @@ class utilsTest extends ItopTestCase } /** - * @dataProvider GetMentionedObjectsFromTextProvider * @covers utils::GetMentionedObjectsFromText * - * @param string $sInput - * @param string $sFormat - * @param array $aExceptedMentionedObjects - * * @throws \Exception */ - public function testGetMentionedObjectsFromText(string $sInput, string $sFormat, array $aExceptedMentionedObjects) + public function testGetMentionedObjectsFromText() { - $aTestedMentionedObjects = utils::GetMentionedObjectsFromText($sInput, $sFormat); + // Emulate the "Case provider mechanism" (reason: the data provider requires utils constants not available before the application startup) + foreach ($this->GetMentionedObjectsFromTextProvider() as $sCase => list($sInput, $sFormat, $aExceptedMentionedObjects)) { + $aTestedMentionedObjects = utils::GetMentionedObjectsFromText($sInput, $sFormat); - $sExpectedAsString = print_r($aExceptedMentionedObjects, true); - $sTestedAsString = print_r($aTestedMentionedObjects, true); + $sExpectedAsString = print_r($aExceptedMentionedObjects, true); + $sTestedAsString = print_r($aTestedMentionedObjects, true); - $this->assertEquals($sTestedAsString, $sExpectedAsString, "Found mentioned objects don't match. Got: $sTestedAsString, expected $sExpectedAsString"); + $this->assertEquals($sTestedAsString, $sExpectedAsString, "Case '$sCase': Found mentioned objects don't match. Got: $sTestedAsString, expected $sExpectedAsString"); + } } /** @@ -779,17 +779,13 @@ class utilsTest extends ItopTestCase /** * Test sanitizer. * - * @param $type string type of sanitizer - * @param $valueToSanitize ? value to sanitize - * @param $expectedResult ? expected result - * - * @return void - * - * @dataProvider sanitizerDataProvider */ - public function testSanitizer($type, $valueToSanitize, $expectedResult) + public function testSanitizer() { - $this->assertEquals($expectedResult, utils::Sanitize($valueToSanitize, null, $type), 'url sanitize failed'); + // Emulate the "Case provider mechanism" (reason: the data provider requires utils constants not available before the application startup) + foreach ($this->sanitizerDataProvider() as $sCase => list($type, $valueToSanitize, $expectedResult)) { + $this->assertEquals($expectedResult, utils::Sanitize($valueToSanitize, null, $type), "Case '$sCase': url sanitize failed"); + } } /** diff --git a/tests/php-unit-tests/unitary-tests/core/ActionEmailTest.php b/tests/php-unit-tests/unitary-tests/core/ActionEmailTest.php index f8a7ed97d..ae26e1b97 100644 --- a/tests/php-unit-tests/unitary-tests/core/ActionEmailTest.php +++ b/tests/php-unit-tests/unitary-tests/core/ActionEmailTest.php @@ -10,9 +10,6 @@ use utils; use Dict; /** - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled * @covers \ActionEmail */ class ActionEmailTest extends ItopDataTestCase diff --git a/tests/php-unit-tests/unitary-tests/core/AttributeDefinitionTest.php b/tests/php-unit-tests/unitary-tests/core/AttributeDefinitionTest.php index dac1b0608..ac5aff2a8 100644 --- a/tests/php-unit-tests/unitary-tests/core/AttributeDefinitionTest.php +++ b/tests/php-unit-tests/unitary-tests/core/AttributeDefinitionTest.php @@ -5,11 +5,6 @@ namespace Combodo\iTop\Test\UnitTest\Core; use Combodo\iTop\Test\UnitTest\ItopDataTestCase; use MetaModel; -/** - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled - */ class AttributeDefinitionTest extends ItopDataTestCase { const CREATE_TEST_ORG = true; diff --git a/tests/php-unit-tests/unitary-tests/core/BulkChangeTest.php b/tests/php-unit-tests/unitary-tests/core/BulkChangeTest.php index 1ff09c351..e406dd478 100644 --- a/tests/php-unit-tests/unitary-tests/core/BulkChangeTest.php +++ b/tests/php-unit-tests/unitary-tests/core/BulkChangeTest.php @@ -7,9 +7,7 @@ use Combodo\iTop\Test\UnitTest\ItopDataTestCase; use MetaModel; /** - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled + * @runClassInSeparateProcess */ class BulkChangeTest extends ItopDataTestCase { const CREATE_TEST_ORG = true; diff --git a/tests/php-unit-tests/unitary-tests/core/CMDBObjectTest.php b/tests/php-unit-tests/unitary-tests/core/CMDBObjectTest.php index 9b8713e05..4d2e2ad9f 100644 --- a/tests/php-unit-tests/unitary-tests/core/CMDBObjectTest.php +++ b/tests/php-unit-tests/unitary-tests/core/CMDBObjectTest.php @@ -15,11 +15,6 @@ use MetaModel; */ -/** - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled - */ class CMDBObjectTest extends ItopDataTestCase { private $sAdminLogin; @@ -99,6 +94,7 @@ class CMDBObjectTest extends ItopDataTestCase * @covers CMDBObject::SetCurrentChange * @since 3.0.1 N°5135 - Impersonate: history of changes versus log entries * + * @runInSeparateProcess * @dataProvider CurrentChangeUnderImpersonationProvider */ public function testCurrentChangeUnderImpersonation($sTrackInfo=null, $sExpectedChangeLogWhenImpersonation=null) { diff --git a/tests/php-unit-tests/unitary-tests/core/CMDBSource/CMDBSourceTest.php b/tests/php-unit-tests/unitary-tests/core/CMDBSource/CMDBSourceTest.php index 244742b53..62a6af66d 100644 --- a/tests/php-unit-tests/unitary-tests/core/CMDBSource/CMDBSourceTest.php +++ b/tests/php-unit-tests/unitary-tests/core/CMDBSource/CMDBSourceTest.php @@ -17,11 +17,6 @@ use utils; * @package Combodo\iTop\Test\UnitTest\Core */ -/** - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled - */ class CMDBSourceTest extends ItopTestCase { protected function setUp(): void @@ -126,6 +121,8 @@ class CMDBSourceTest extends ItopTestCase * @throws \CoreException * @throws \MySQLException * @since 3.0.0 N°4215 + * + * @runInSeparateProcess Resetting DB connection, thus making other tests to fail! */ public function testIsOpenedDbConnectionUsingTls() { diff --git a/tests/php-unit-tests/unitary-tests/core/CMDBSource/TransactionsTest.php b/tests/php-unit-tests/unitary-tests/core/CMDBSource/TransactionsTest.php index 5ee8ca63a..44482827d 100644 --- a/tests/php-unit-tests/unitary-tests/core/CMDBSource/TransactionsTest.php +++ b/tests/php-unit-tests/unitary-tests/core/CMDBSource/TransactionsTest.php @@ -14,10 +14,6 @@ use MetaModel; use MySQLTransactionNotClosedException; /** - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled - * * @group itopRequestMgmt * @group specificOrgInSampleData * Class TransactionsTest @@ -108,6 +104,15 @@ class TransactionsTest extends ItopTestCase } } + /** + * This test case was originaly in DBInsertProvider + * @runInSeparateProcess Failing when run in the same process as other... + */ + public function testDBInsertCaseHistory38() + { + $this->testDBInsert(40, false); + } + public function DBInsertProvider() { return [ @@ -151,7 +156,6 @@ class TransactionsTest extends ItopTestCase "History 35" => ['iFailAt' => 37, 'bIsInDB' => false], "History 36" => ['iFailAt' => 38, 'bIsInDB' => false], "History 37" => ['iFailAt' => 39, 'bIsInDB' => false], - "History 38" => ['iFailAt' => 40, 'bIsInDB' => false], ]; } @@ -276,6 +280,7 @@ class TransactionsTest extends ItopTestCase protected function tearDown(): void { try { + DbConnectionWrapper::SetDbConnectionMockForQuery(); parent::tearDown(); } catch (MySQLTransactionNotClosedException $e) { diff --git a/tests/php-unit-tests/unitary-tests/core/CRUDEventTest.php b/tests/php-unit-tests/unitary-tests/core/CRUDEventTest.php index 95dc968db..accbbca48 100644 --- a/tests/php-unit-tests/unitary-tests/core/CRUDEventTest.php +++ b/tests/php-unit-tests/unitary-tests/core/CRUDEventTest.php @@ -21,11 +21,6 @@ use Person; use Team; use utils; -/** - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled - */ class CRUDEventTest extends ItopDataTestCase { const USE_TRANSACTION = true; @@ -37,6 +32,8 @@ class CRUDEventTest extends ItopDataTestCase protected function setUp(): void { + static::$aEventCalls = []; + static::$iEventCalls = 0; parent::setUp(); } @@ -54,7 +51,7 @@ class CRUDEventTest extends ItopDataTestCase */ public function testDBInsert() { - $oEventReceiver = new CRUDEventReceiver(); + $oEventReceiver = new CRUDEventReceiver($this); $oEventReceiver->RegisterCRUDListeners(); $oOrg = $this->CreateOrganization('Organization1'); @@ -77,7 +74,7 @@ class CRUDEventTest extends ItopDataTestCase $oOrg = $this->CreateOrganization('Organization1'); $this->assertIsObject($oOrg); - $oEventReceiver = new CRUDEventReceiver(); + $oEventReceiver = new CRUDEventReceiver($this); $oEventReceiver->RegisterCRUDListeners(); $oOrg->Set('name', 'test'); @@ -101,7 +98,7 @@ class CRUDEventTest extends ItopDataTestCase $oOrg = $this->CreateOrganization('Organization1'); $this->assertIsObject($oOrg); - $oEventReceiver = new CRUDEventReceiver(); + $oEventReceiver = new CRUDEventReceiver($this); $oEventReceiver->RegisterCRUDListeners(); $oOrg->DBUpdate(); @@ -122,7 +119,7 @@ class CRUDEventTest extends ItopDataTestCase */ public function testComputeValuesOnInsert() { - $oEventReceiver = new CRUDEventReceiver(); + $oEventReceiver = new CRUDEventReceiver($this); // Set the person's first name during Compute Values $oEventReceiver->AddCallback(EVENT_DB_COMPUTE_VALUES, Person::class, 'SetPersonFirstName'); $oEventReceiver->RegisterCRUDListeners(EVENT_DB_COMPUTE_VALUES); @@ -155,7 +152,7 @@ class CRUDEventTest extends ItopDataTestCase $oPerson = $this->CreatePerson(1); $this->assertIsObject($oPerson); - $oEventReceiver = new CRUDEventReceiver(); + $oEventReceiver = new CRUDEventReceiver($this); // Set the person's first name during Compute Values $oEventReceiver->AddCallback(EVENT_DB_COMPUTE_VALUES, Person::class, 'SetPersonFirstName'); $oEventReceiver->RegisterCRUDListeners(EVENT_DB_COMPUTE_VALUES); @@ -180,7 +177,7 @@ class CRUDEventTest extends ItopDataTestCase */ public function testCheckToWriteProtectedOnInsert() { - $oEventReceiver = new CRUDEventReceiver(); + $oEventReceiver = new CRUDEventReceiver($this); // Modify the person's function $oEventReceiver->AddCallback(EVENT_DB_CHECK_TO_WRITE, Person::class, 'SetPersonFunction'); $oEventReceiver->RegisterCRUDListeners(EVENT_DB_CHECK_TO_WRITE); @@ -201,7 +198,7 @@ class CRUDEventTest extends ItopDataTestCase $this->assertIsObject($oPerson); // Modify the person's function - $oEventReceiver = new CRUDEventReceiver(); + $oEventReceiver = new CRUDEventReceiver($this); $oEventReceiver->AddCallback(EVENT_DB_CHECK_TO_WRITE, Person::class, 'SetPersonFunction'); $oEventReceiver->RegisterCRUDListeners(EVENT_DB_CHECK_TO_WRITE); @@ -221,7 +218,7 @@ class CRUDEventTest extends ItopDataTestCase */ public function testModificationsDuringCreateDone() { - $oEventReceiver = new CRUDEventReceiver(); + $oEventReceiver = new CRUDEventReceiver($this); // Set the person's first name during Compute Values $oEventReceiver->AddCallback(EVENT_DB_AFTER_WRITE, Person::class, 'SetPersonFirstName'); $oEventReceiver->RegisterCRUDListeners(); @@ -254,7 +251,7 @@ class CRUDEventTest extends ItopDataTestCase $oPerson = $this->CreatePerson(1); $this->assertIsObject($oPerson); - $oEventReceiver = new CRUDEventReceiver(); + $oEventReceiver = new CRUDEventReceiver($this); // Set the person's first name during Compute Values $oEventReceiver->AddCallback(EVENT_DB_AFTER_WRITE, Person::class, 'SetPersonFirstName'); $oEventReceiver->RegisterCRUDListeners(); @@ -287,7 +284,7 @@ class CRUDEventTest extends ItopDataTestCase $oPerson = $this->CreatePerson(1); $this->assertIsObject($oPerson); - $oEventReceiver = new CRUDEventReceiver(); + $oEventReceiver = new CRUDEventReceiver($this); // Set the person's first name during Compute Values $oEventReceiver->AddCallback(EVENT_DB_AFTER_WRITE, Person::class, 'SetPersonFirstName', 100); $oEventReceiver->RegisterCRUDListeners(EVENT_DB_AFTER_WRITE); @@ -329,7 +326,7 @@ class CRUDEventTest extends ItopDataTestCase $this->debug("\n-------------> Test Starts HERE\n"); - $oEventReceiver = new CRUDEventReceiver(); + $oEventReceiver = new CRUDEventReceiver($this); $oEventReceiver->RegisterCRUDListeners(); $oTeam = MetaModel::NewObject(Team::class, ['name' => 'TestTeam1', 'persons_list' => $oLinkSet, 'org_id' => $this->getTestOrgId()]); @@ -375,7 +372,7 @@ class CRUDEventTest extends ItopDataTestCase $oLinkSet->AddItem($oLink); $this->debug("\n-------------> Test Starts HERE\n"); - $oEventReceiver = new CRUDEventReceiver(); + $oEventReceiver = new CRUDEventReceiver($this); // Create a new role and add it to the newly created lnkPersonToTeam $oEventReceiver->AddCallback(EVENT_DB_AFTER_WRITE, lnkPersonToTeam::class, 'AddRoleToLink'); $oEventReceiver->RegisterCRUDListeners(); @@ -411,13 +408,13 @@ class CRUDEventTest extends ItopDataTestCase */ public function testPostponedUpdates() { - $oEventReceiver = new CRUDEventReceiver(); + $oEventReceiver = new CRUDEventReceiver($this); // Set the person's function after the creation $oEventReceiver->AddCallback(EVENT_DB_AFTER_WRITE, Person::class, 'SetPersonFunction'); $oEventReceiver->RegisterCRUDListeners(EVENT_DB_AFTER_WRITE); // Intentionally register twice so 2 modifications will be done - $oEventReceiver = new CRUDEventReceiver(); + $oEventReceiver = new CRUDEventReceiver($this); $oEventReceiver->AddCallback(EVENT_DB_AFTER_WRITE, Person::class, 'SetPersonFirstName'); $oEventReceiver->RegisterCRUDListeners(EVENT_DB_AFTER_WRITE); @@ -444,7 +441,7 @@ class CRUDEventTest extends ItopDataTestCase public function testCrudStack() { - $oEventReceiver = new CRUDEventReceiver(); + $oEventReceiver = new CRUDEventReceiver($this); // Modify the person's function $oEventReceiver->AddCallback(EVENT_DB_COMPUTE_VALUES, Person::class, 'CheckCrudStack'); $oEventReceiver->RegisterCRUDListeners(EVENT_DB_COMPUTE_VALUES); @@ -490,7 +487,7 @@ class CRUDEventTest extends ItopDataTestCase $oTeam->DBInsert(); // Start receiving events - $oEventReceiver = new CRUDEventReceiver(); + $oEventReceiver = new CRUDEventReceiver($this); $oEventReceiver->RegisterCRUDListeners(); // Create a link between Person and Team => generate 2 EVENT_DB_LINKS_CHANGED @@ -514,7 +511,7 @@ class CRUDEventTest extends ItopDataTestCase $oLnk->DBInsert(); // Start receiving events - $oEventReceiver = new CRUDEventReceiver(); + $oEventReceiver = new CRUDEventReceiver($this); $oEventReceiver->RegisterCRUDListeners(); $oLnk->DBDelete(); @@ -553,10 +550,16 @@ class ClassesWithDebug */ class CRUDEventReceiver extends ClassesWithDebug { + private $oTestCase; private $aCallbacks = []; public static $bIsObjectInCrudStack; + public function __construct(ItopDataTestCase $oTestCase) + { + $this->oTestCase = $oTestCase; + } + // /** @@ -613,30 +616,21 @@ class CRUDEventReceiver extends ClassesWithDebug { $this->Debug('Registering Test event listeners'); if (is_null($sEvent)) { - EventService::RegisterListener(EVENT_DB_COMPUTE_VALUES, [$this, 'OnEvent']); - EventService::RegisterListener(EVENT_DB_CHECK_TO_WRITE, [$this, 'OnEvent']); - EventService::RegisterListener(EVENT_DB_CHECK_TO_DELETE, [$this, 'OnEvent']); - EventService::RegisterListener(EVENT_DB_BEFORE_WRITE, [$this, 'OnEvent']); - EventService::RegisterListener(EVENT_DB_AFTER_WRITE, [$this, 'OnEvent']); - EventService::RegisterListener(EVENT_DB_AFTER_DELETE, [$this, 'OnEvent']); - EventService::RegisterListener(EVENT_DB_LINKS_CHANGED, [$this, 'OnEvent']); + $this->oTestCase->EventService_RegisterListener(EVENT_DB_COMPUTE_VALUES, [$this, 'OnEvent']); + $this->oTestCase->EventService_RegisterListener(EVENT_DB_CHECK_TO_WRITE, [$this, 'OnEvent']); + $this->oTestCase->EventService_RegisterListener(EVENT_DB_CHECK_TO_DELETE, [$this, 'OnEvent']); + $this->oTestCase->EventService_RegisterListener(EVENT_DB_BEFORE_WRITE, [$this, 'OnEvent']); + $this->oTestCase->EventService_RegisterListener(EVENT_DB_AFTER_WRITE, [$this, 'OnEvent']); + $this->oTestCase->EventService_RegisterListener(EVENT_DB_AFTER_DELETE, [$this, 'OnEvent']); + $this->oTestCase->EventService_RegisterListener(EVENT_DB_LINKS_CHANGED, [$this, 'OnEvent']); return; } - EventService::RegisterListener($sEvent, [$this, 'OnEvent'], $mEventSource); + $this->oTestCase->EventService_RegisterListener($sEvent, [$this, 'OnEvent'], $mEventSource); } /** - * @param $oObject - * - * @return void - * @throws \ArchivedObjectException - * @throws \CoreCannotSaveObjectException - * @throws \CoreException - * @throws \CoreUnexpectedValue - * @throws \CoreWarning - * @throws \MySQLException - * @throws \OQLException + * @noinspection PhpUnusedPrivateMethodInspection Used as a callback */ private function AddRoleToLink($oObject): void { @@ -646,26 +640,30 @@ class CRUDEventReceiver extends ClassesWithDebug $oObject->Set('role_id', $oContactType->GetKey()); } + /** + * @noinspection PhpUnusedPrivateMethodInspection Used as a callback + */ private function SetPersonFunction($oObject): void { $this->Debug(__METHOD__); $oObject->Set('function', 'CRUD_function_'.rand()); } + /** + * @noinspection PhpUnusedPrivateMethodInspection Used as a callback + */ private function SetPersonFirstName($oObject): void { $this->Debug(__METHOD__); $oObject->Set('first_name', 'CRUD_first_name_'.rand()); } + /** + * @noinspection PhpUnusedPrivateMethodInspection Used as a callback + */ private function CheckCrudStack(DBObject $oObject): void { self::$bIsObjectInCrudStack = DBObject::IsObjectCurrentlyInCrud(get_class($oObject), $oObject->GetKey()); } - private function CheckUpdateInLnk(lnkPersonToTeam $oLnkPersonToTeam) - { - $iTeamId = $oLnkPersonToTeam->Get('team_id'); - self::$bIsObjectInCrudStack = DBObject::IsObjectCurrentlyInCrud(Team::class, $iTeamId); - } } diff --git a/tests/php-unit-tests/unitary-tests/core/DBObjectTest.php b/tests/php-unit-tests/unitary-tests/core/DBObjectTest.php index 23e9bd592..28d92a785 100644 --- a/tests/php-unit-tests/unitary-tests/core/DBObjectTest.php +++ b/tests/php-unit-tests/unitary-tests/core/DBObjectTest.php @@ -26,6 +26,7 @@ namespace Combodo\iTop\Test\UnitTest\Core; +use Combodo\iTop\Service\Events\EventData; use Combodo\iTop\Test\UnitTest\ItopDataTestCase; use CoreException; use DBObject; @@ -36,19 +37,20 @@ use MetaModel; /** * @group specificOrgInSampleData - * - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled */ class DBObjectTest extends ItopDataTestCase { const CREATE_TEST_ORG = true; + // Counts + public $aReloadCount = []; + protected function setUp(): void { parent::setUp(); $this->RequireOnceItopFile('core/dbobject.class.php'); + + $this->EventService_RegisterListener(EVENT_DB_OBJECT_RELOAD, [$this, 'CountObjectReload']); } /** @@ -897,4 +899,46 @@ class DBObjectTest extends ItopDataTestCase return $oPerson; } + public function ResetReloadCount() + { + $this->aReloadCount = []; + } + + public function DebugReloadCount($sMsg, $bResetCount = true) + { + $iTotalCount = 0; + $aTotalPerClass = []; + foreach ($this->aReloadCount as $sClass => $aCountByKeys) { + $iClassCount = 0; + foreach ($aCountByKeys as $iCount) { + $iClassCount += $iCount; + } + $iTotalCount += $iClassCount; + $aTotalPerClass[$sClass] = $iClassCount; + } + $this->debug("$sMsg - $iTotalCount reload(s)"); + foreach ($this->aReloadCount as $sClass => $aCountByKeys) { + $this->debug(" $sClass => $aTotalPerClass[$sClass] reload(s)"); + foreach ($aCountByKeys as $sKey => $iCount) { + $this->debug(" $sClass::$sKey => $iCount"); + } + } + if ($bResetCount) { + $this->ResetReloadCount(); + } + } + + public function CountObjectReload(EventData $oData) + { + $oObject = $oData->Get('object'); + $sClass = get_class($oObject); + $sKey = $oObject->GetKey(); + $iCount = $this->GetObjectReloadCount($sClass, $sKey); + $this->aReloadCount[$sClass][$sKey] = 1 + $iCount; + } + + public function GetObjectReloadCount($sClass, $sKey) + { + return $this->aReloadCount[$sClass][$sKey] ?? 0; + } } diff --git a/tests/php-unit-tests/unitary-tests/core/DBSearchCommitTest.php b/tests/php-unit-tests/unitary-tests/core/DBSearchCommitTest.php index 30088c513..63baa2890 100644 --- a/tests/php-unit-tests/unitary-tests/core/DBSearchCommitTest.php +++ b/tests/php-unit-tests/unitary-tests/core/DBSearchCommitTest.php @@ -17,10 +17,6 @@ use DBSearch; *
    *
  • MakeGroupByQuery
  • *
- * - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled */ class DBSearchCommitTest extends ItopDataTestCase { diff --git a/tests/php-unit-tests/unitary-tests/core/DBSearchIntersectTest.php b/tests/php-unit-tests/unitary-tests/core/DBSearchIntersectTest.php index b87c44de3..7e4c6c6fc 100644 --- a/tests/php-unit-tests/unitary-tests/core/DBSearchIntersectTest.php +++ b/tests/php-unit-tests/unitary-tests/core/DBSearchIntersectTest.php @@ -11,10 +11,6 @@ use DBSearch; * Class DBSearchIntersectTest * * @package Combodo\iTop\Test\UnitTest\Core - * - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled */ class DBSearchIntersectTest extends ItopTestCase { @@ -71,16 +67,16 @@ class DBSearchIntersectTest extends ItopTestCase 'result' => "SELECT `L`, `P` FROM Person AS `P` JOIN Location AS `L` ON `P`.location_id = `L`.id WHERE (`P`.`org_id` = 3)"); $aTests['Multiple selected classes inverted 1'] = array( - 'left' => "SELECT `L`, `P`, `D` FROM Person AS `P` JOIN Location AS `L` ON `P`.location_id = `L`.id JOIN PC AS D ON D.location_id = L.id JOIN Person AS P2 ON P.manager_id = P2.id WHERE 1", + 'left' => "SELECT `L`, `P`, `D` FROM Person AS `P` JOIN Location AS `L` ON `P`.location_id = `L`.id JOIN Server AS D ON D.location_id = L.id JOIN Person AS P2 ON P.manager_id = P2.id WHERE 1", 'right' => "SELECT Location WHERE org_id = 3", 'alias' => "L", - 'result' => "SELECT `L`, `P`, `D` FROM Person AS `P` JOIN Location AS `L` ON `P`.location_id = `L`.id JOIN PC AS `D` ON `D`.location_id = `L`.id JOIN Person AS `P2` ON `P`.manager_id = `P2`.id WHERE (`L`.`org_id` = 3)"); + 'result' => "SELECT `L`, `P`, `D` FROM Person AS `P` JOIN Location AS `L` ON `P`.location_id = `L`.id JOIN Server AS `D` ON `D`.location_id = `L`.id JOIN Person AS `P2` ON `P`.manager_id = `P2`.id WHERE (`L`.`org_id` = 3)"); $aTests['Multiple selected classes inverted 2'] = array( - 'left' => "SELECT `L`, `P`, `D` FROM Person AS `P` JOIN Location AS `L` ON `P`.location_id = `L`.id JOIN PC AS D ON D.location_id = L.id JOIN Person AS P2 ON P.manager_id = P2.id WHERE (`L`.`org_id` = 3)", + 'left' => "SELECT `L`, `P`, `D` FROM Person AS `P` JOIN Location AS `L` ON `P`.location_id = `L`.id JOIN Server AS D ON D.location_id = L.id JOIN Person AS P2 ON P.manager_id = P2.id WHERE (`L`.`org_id` = 3)", 'right' => "SELECT Person WHERE org_id = 3", 'alias' => "P", - 'result' => "SELECT `L`, `P`, `D` FROM Person AS `P` JOIN Location AS `L` ON `P`.location_id = `L`.id JOIN PC AS `D` ON `D`.location_id = `L`.id JOIN Person AS `P2` ON `P`.manager_id = `P2`.id WHERE ((`L`.`org_id` = 3) AND (`P`.`org_id` = 3))"); + 'result' => "SELECT `L`, `P`, `D` FROM Person AS `P` JOIN Location AS `L` ON `P`.location_id = `L`.id JOIN Server AS `D` ON `D`.location_id = `L`.id JOIN Person AS `P2` ON `P`.manager_id = `P2`.id WHERE ((`L`.`org_id` = 3) AND (`P`.`org_id` = 3))"); $aTests['Same class'] = array( 'left' => "SELECT Contact WHERE name = 'Christie'", @@ -191,9 +187,9 @@ class DBSearchIntersectTest extends ItopTestCase 'result' => "SELECT `L`, `P` FROM Person AS `P` JOIN Location AS `L` ON `P`.location_id = `L`.id WHERE (`P`.`org_id` = 3)"); $aTests['Multiple selected classes inverted 2'] = array( - 'left' => "SELECT `L`, `P`, `D` FROM Person AS `P` JOIN Location AS `L` ON `P`.location_id = `L`.id JOIN PC AS D ON D.location_id = L.id JOIN Person AS P2 ON P.manager_id = P2.id WHERE (`L`.`org_id` = 3)", + 'left' => "SELECT `L`, `P`, `D` FROM Person AS `P` JOIN Location AS `L` ON `P`.location_id = `L`.id JOIN Server AS D ON D.location_id = L.id JOIN Person AS P2 ON P.manager_id = P2.id WHERE (`L`.`org_id` = 3)", 'right' => "SELECT Person WHERE org_id = 3", - 'result' => "SELECT `L`, `P`, `D` FROM Person AS `P` JOIN Location AS `L` ON `P`.location_id = `L`.id JOIN PC AS `D` ON `D`.location_id = `L`.id JOIN Person AS `P2` ON `P`.manager_id = `P2`.id WHERE ((`L`.`org_id` = 3) AND (`P`.`org_id` = 3))"); + 'result' => "SELECT `L`, `P`, `D` FROM Person AS `P` JOIN Location AS `L` ON `P`.location_id = `L`.id JOIN Server AS `D` ON `D`.location_id = `L`.id JOIN Person AS `P2` ON `P`.manager_id = `P2`.id WHERE ((`L`.`org_id` = 3) AND (`P`.`org_id` = 3))"); $aTests['Same class'] = array( 'left' => "SELECT Contact WHERE name = 'Christie'", diff --git a/tests/php-unit-tests/unitary-tests/core/DBSearchJoinTest.php b/tests/php-unit-tests/unitary-tests/core/DBSearchJoinTest.php index 468c9ef92..55077d4d1 100644 --- a/tests/php-unit-tests/unitary-tests/core/DBSearchJoinTest.php +++ b/tests/php-unit-tests/unitary-tests/core/DBSearchJoinTest.php @@ -11,10 +11,6 @@ use DBSearch; * Class DBSearchIntersectTest * * @package Combodo\iTop\Test\UnitTest\Core - * - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled */ class DBSearchJoinTest extends ItopDataTestCase { diff --git a/tests/php-unit-tests/unitary-tests/core/DBSearchTest.php b/tests/php-unit-tests/unitary-tests/core/DBSearchTest.php index 2a6de4c6d..09265d8d4 100644 --- a/tests/php-unit-tests/unitary-tests/core/DBSearchTest.php +++ b/tests/php-unit-tests/unitary-tests/core/DBSearchTest.php @@ -43,10 +43,6 @@ use FunctionExpression; *
    *
  • MakeGroupByQuery
  • *
- * - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled */ class DBSearchTest extends ItopDataTestCase { diff --git a/tests/php-unit-tests/unitary-tests/core/DBSearchUpdateRealiasingMapTest.php b/tests/php-unit-tests/unitary-tests/core/DBSearchUpdateRealiasingMapTest.php index 4fd6a3ace..44670c985 100644 --- a/tests/php-unit-tests/unitary-tests/core/DBSearchUpdateRealiasingMapTest.php +++ b/tests/php-unit-tests/unitary-tests/core/DBSearchUpdateRealiasingMapTest.php @@ -10,10 +10,6 @@ use DBObjectSearch; * Class DBSearchUpdateRealiasingMapTest * * @package Combodo\iTop\Test\UnitTest\Core - * - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled */ class DBSearchUpdateRealiasingMapTest extends ItopDataTestCase { diff --git a/tests/php-unit-tests/unitary-tests/core/DBUnionSearchTest.php b/tests/php-unit-tests/unitary-tests/core/DBUnionSearchTest.php index 1b65ce66f..bcf382ac7 100644 --- a/tests/php-unit-tests/unitary-tests/core/DBUnionSearchTest.php +++ b/tests/php-unit-tests/unitary-tests/core/DBUnionSearchTest.php @@ -7,11 +7,6 @@ use Combodo\iTop\Test\UnitTest\ItopDataTestCase; -/** - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled - */ class DBUnionSearchTest extends ItopDataTestCase { diff --git a/tests/php-unit-tests/unitary-tests/core/ExpressionEvaluateTest.php b/tests/php-unit-tests/unitary-tests/core/ExpressionEvaluateTest.php index b97e4e385..f748d2422 100644 --- a/tests/php-unit-tests/unitary-tests/core/ExpressionEvaluateTest.php +++ b/tests/php-unit-tests/unitary-tests/core/ExpressionEvaluateTest.php @@ -13,11 +13,6 @@ use FunctionExpression; use MetaModel; use ScalarExpression; -/** - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled - */ class ExpressionEvaluateTest extends ItopDataTestCase { const USE_TRANSACTION = false; diff --git a/tests/php-unit-tests/unitary-tests/core/ExpressionTest.php b/tests/php-unit-tests/unitary-tests/core/ExpressionTest.php index 838143180..56f9869c6 100644 --- a/tests/php-unit-tests/unitary-tests/core/ExpressionTest.php +++ b/tests/php-unit-tests/unitary-tests/core/ExpressionTest.php @@ -5,11 +5,6 @@ namespace Combodo\iTop\Test\UnitTest\Core; use Combodo\iTop\Test\UnitTest\ItopDataTestCase; use Expression; -/** - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled - */ class ExpressionTest extends ItopDataTestCase { const USE_TRANSACTION = false; diff --git a/tests/php-unit-tests/unitary-tests/core/GetSelectFilterTest.php b/tests/php-unit-tests/unitary-tests/core/GetSelectFilterTest.php index e38e78885..f1056e608 100644 --- a/tests/php-unit-tests/unitary-tests/core/GetSelectFilterTest.php +++ b/tests/php-unit-tests/unitary-tests/core/GetSelectFilterTest.php @@ -20,10 +20,6 @@ use UserRightsProfile; * @group specificOrgInSampleData * Class GetSelectFilterTest * - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled - * * @package Combodo\iTop\Test\UnitTest\Webservices */ class GetSelectFilterTest extends ItopDataTestCase diff --git a/tests/php-unit-tests/unitary-tests/core/InlineImageTest.php b/tests/php-unit-tests/unitary-tests/core/InlineImageTest.php index f4a6d6a21..d3066ecf0 100644 --- a/tests/php-unit-tests/unitary-tests/core/InlineImageTest.php +++ b/tests/php-unit-tests/unitary-tests/core/InlineImageTest.php @@ -10,12 +10,6 @@ namespace Combodo\iTop\Test\UnitTest\Core; use Combodo\iTop\Test\UnitTest\ItopDataTestCase; use InlineImage; - -/** - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled - */ class InlineImageTest extends ItopDataTestCase { /** diff --git a/tests/php-unit-tests/unitary-tests/core/Log/DeprecatedCallsLogTest.php b/tests/php-unit-tests/unitary-tests/core/Log/DeprecatedCallsLogTest.php index 582711b50..055e67669 100644 --- a/tests/php-unit-tests/unitary-tests/core/Log/DeprecatedCallsLogTest.php +++ b/tests/php-unit-tests/unitary-tests/core/Log/DeprecatedCallsLogTest.php @@ -39,6 +39,8 @@ class DeprecatedCallsLogTest extends ItopTestCase { } /** + * @runInSeparateProcess Necessary, due to the DeprecatedCallsLog being enabled (no mean to reset) + * * The error handler set by DeprecatedCallsLog during startup was causing PHPUnit to miss PHP notices like "undefined offset" * * The error handler is now disabled when running PHPUnit diff --git a/tests/php-unit-tests/unitary-tests/core/Log/ExceptionLogTest.php b/tests/php-unit-tests/unitary-tests/core/Log/ExceptionLogTest.php index e2074c84a..d4e84cdb8 100644 --- a/tests/php-unit-tests/unitary-tests/core/Log/ExceptionLogTest.php +++ b/tests/php-unit-tests/unitary-tests/core/Log/ExceptionLogTest.php @@ -21,11 +21,6 @@ use ExceptionLog; require_once(__DIR__.'/ExceptionLogTest/Exceptions.php'); -/** - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled - */ class ExceptionLogTest extends ItopDataTestCase { protected function setUp(): void @@ -35,6 +30,8 @@ class ExceptionLogTest extends ItopDataTestCase } /** + * @runInSeparateProcess + * * @dataProvider logProvider */ public function testLogInFile($aLevels, $aExceptions, $sChannel, $aExpectedWriteNumber, $logLevelMin, $aExpectedDbWriteNumber, $logLevelMinWriteInDb) diff --git a/tests/php-unit-tests/unitary-tests/core/Log/LogAPITest.php b/tests/php-unit-tests/unitary-tests/core/Log/LogAPITest.php index 8f16aaf0e..910245147 100644 --- a/tests/php-unit-tests/unitary-tests/core/Log/LogAPITest.php +++ b/tests/php-unit-tests/unitary-tests/core/Log/LogAPITest.php @@ -16,11 +16,6 @@ namespace Combodo\iTop\Test\UnitTest\Core\Log; use Combodo\iTop\Test\UnitTest\ItopDataTestCase; -/** - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled - */ class LogAPITest extends ItopDataTestCase { private $mockFileLog; @@ -38,7 +33,6 @@ class LogAPITest extends ItopDataTestCase /** * @dataProvider LogApiProvider * @test - * @backupGlobals disabled */ public function TestLogApi($oConfigObject, $sMessage, $Channel, $sExpectedLevel, $sExpectedMessage, $sExpectedChannel = '') { @@ -63,7 +57,6 @@ class LogAPITest extends ItopDataTestCase /** * @dataProvider LogWarningWithASpecificChannelProvider * @test - * @backupGlobals disabled */ public function TestLogWarningWithASpecificChannel($expectedCallNb, $sExpectedLevel, $ConfigReturnedObject, $bExceptionRaised=false) { @@ -110,7 +103,6 @@ class LogAPITest extends ItopDataTestCase /** * @dataProvider LogOkWithASpecificChannel * @test - * @backupGlobals disabled */ public function TestLogOkWithASpecificChannel($expectedCallNb, $sExpectedLevel, $ConfigReturnedObject, $bExceptionRaised=false) { diff --git a/tests/php-unit-tests/unitary-tests/core/MetaModelTest.php b/tests/php-unit-tests/unitary-tests/core/MetaModelTest.php index a65c7008c..c8c9de667 100644 --- a/tests/php-unit-tests/unitary-tests/core/MetaModelTest.php +++ b/tests/php-unit-tests/unitary-tests/core/MetaModelTest.php @@ -10,10 +10,6 @@ use MetaModel; /** * Class MetaModelTest * - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled - * * @since 2.6.0 * @package Combodo\iTop\Test\UnitTest\Core */ @@ -220,6 +216,8 @@ class MetaModelTest extends ItopDataTestCase } /** + * @runInSeparateProcess + * * @dataProvider enumPluginsProvider * * @param $expectedResults @@ -267,6 +265,8 @@ class MetaModelTest extends ItopDataTestCase } /** + * @runInSeparateProcess + * * @dataProvider getPluginsProvider * * @param $expectedInstanciationCalls diff --git a/tests/php-unit-tests/unitary-tests/core/OQLParserTest.php b/tests/php-unit-tests/unitary-tests/core/OQLParserTest.php index 63cd2c626..d18148abd 100644 --- a/tests/php-unit-tests/unitary-tests/core/OQLParserTest.php +++ b/tests/php-unit-tests/unitary-tests/core/OQLParserTest.php @@ -16,11 +16,6 @@ use OQLException; use OqlInterpreter; use OQLParserException; -/** - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled - */ class OQLParserTest extends ItopDataTestCase { const USE_TRANSACTION = false; diff --git a/tests/php-unit-tests/unitary-tests/core/OQLTest.php b/tests/php-unit-tests/unitary-tests/core/OQLTest.php index 40a2e0845..de81dc512 100644 --- a/tests/php-unit-tests/unitary-tests/core/OQLTest.php +++ b/tests/php-unit-tests/unitary-tests/core/OQLTest.php @@ -21,11 +21,6 @@ use QueryBuilderContext; use SQLObjectQueryBuilder; use utils; -/** - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled - */ class OQLTest extends ItopDataTestCase { const USE_TRANSACTION = false; diff --git a/tests/php-unit-tests/unitary-tests/core/TagSetFieldDataTest.php b/tests/php-unit-tests/unitary-tests/core/TagSetFieldDataTest.php index a1ee34772..136ab2900 100644 --- a/tests/php-unit-tests/unitary-tests/core/TagSetFieldDataTest.php +++ b/tests/php-unit-tests/unitary-tests/core/TagSetFieldDataTest.php @@ -18,10 +18,6 @@ use TagSetFieldData; /** * @group itopFaqLight - * - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled */ class TagSetFieldDataTest extends ItopDataTestCase { diff --git a/tests/php-unit-tests/unitary-tests/core/TriggerTest.php b/tests/php-unit-tests/unitary-tests/core/TriggerTest.php index 12744e34f..f8abde406 100644 --- a/tests/php-unit-tests/unitary-tests/core/TriggerTest.php +++ b/tests/php-unit-tests/unitary-tests/core/TriggerTest.php @@ -14,10 +14,6 @@ use TriggerOnObjectCreate; * Class TriggerTest * * @package Combodo\iTop\Test\UnitTest\Core - * - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled */ class TriggerTest extends ItopDataTestCase { @@ -35,9 +31,9 @@ class TriggerTest extends ItopDataTestCase $oTrigger = MetaModel::NewObject('TriggerOnObjectCreate'); $oTrigger->Set('context', ContextTag::TAG_PORTAL.', '.ContextTag::TAG_CRON); $this->assertFalse($oTrigger->IsContextValid()); - ContextTag::AddContext(ContextTag::TAG_SETUP); + $oC1 = new ContextTag(ContextTag::TAG_SETUP); $this->assertFalse($oTrigger->IsContextValid()); - ContextTag::AddContext(ContextTag::TAG_CRON); + $oC2 = new ContextTag(ContextTag::TAG_CRON); $this->assertTrue($oTrigger->IsContextValid()); } @@ -55,7 +51,7 @@ class TriggerTest extends ItopDataTestCase } catch (\CoreException $e1) { $this->assertEquals('CoreException', get_class($e1)); - $this->assertEquals('Unknown class \'Toto\' (TriggerOnObjectCreate::-1 ()
)', $e1->getMessage()); + $this->assertStringStartsWith('Unknown class \'Toto\' (TriggerOnObjectCreate::-', $e1->getMessage()); $fullStackTraceAsString = $e1->getFullStackTraceAsString(); $this->assertStringContainsString("MetaModel::NewObject", $fullStackTraceAsString,"new enriched exception should contain root cause method: " . $fullStackTraceAsString); diff --git a/tests/php-unit-tests/unitary-tests/core/UniquenessMessageTest.php b/tests/php-unit-tests/unitary-tests/core/UniquenessMessageTest.php index 03495dfb5..9e11e4868 100644 --- a/tests/php-unit-tests/unitary-tests/core/UniquenessMessageTest.php +++ b/tests/php-unit-tests/unitary-tests/core/UniquenessMessageTest.php @@ -12,10 +12,6 @@ use Team; /** * Class UniquenessMessageTest * - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled - * * @package Combodo\iTop\Test\UnitTest\Core */ class UniquenessMessageTest extends ItopDataTestCase diff --git a/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php b/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php index 0b4cc29e4..51734ee4f 100644 --- a/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php +++ b/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php @@ -41,10 +41,6 @@ use utils; * @group itopRequestMgmt * @group userRights * @group defaultProfiles - * - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled */ class UserRightsTest extends ItopDataTestCase { @@ -68,6 +64,25 @@ class UserRightsTest extends ItopDataTestCase 'ModuleInstallation' => ['class' => 'ModuleInstallation', 'attcode' => 'name'], ]; + /** + * @param string $sLoginPrefix + * @param int $iProfileId initial profile + * + * @return \DBObject + * @throws \CoreException + * @throws \Exception + */ + protected function CreateUniqueUserAndLogin(string $sLoginPrefix, int $iProfileId): DBObject + { + static $iCount = 0; + $sLogin = $sLoginPrefix.$iCount; + $iCount++; + + $oUser = self::CreateUser($sLogin, $iProfileId); + $_SESSION = array(); + UserRights::Login($sLogin); + return $oUser; + } public function testIsLoggedIn() { @@ -90,6 +105,7 @@ class UserRightsTest extends ItopDataTestCase $_SESSION = []; $this->assertEquals($bResult, UserRights::Login($sLogin)); $this->assertEquals($bResult, UserRights::IsLoggedIn()); + UserRights::Logoff(); } public function LoginProvider(): array @@ -101,22 +117,6 @@ class UserRightsTest extends ItopDataTestCase ]; } - /** - * @param string $sLogin - * @param int $iProfileId initial profile - * - * @return \DBObject - * @throws \CoreException - * @throws \Exception - */ - protected function AddUser(string $sLogin, int $iProfileId): DBObject - { - $oUser = self::CreateUser($sLogin, $iProfileId); - $oUser->DBUpdate(); - - return $oUser; - } - /** Test IsActionAllowed when not logged => always true * * @dataProvider ActionAllowedNotLoggedProvider @@ -145,8 +145,7 @@ class UserRightsTest extends ItopDataTestCase return $aClassActions; } - /** Test IsActionAllowed - * + /** * @dataProvider ActionAllowedProvider * * @param int $iProfileId @@ -158,11 +157,10 @@ class UserRightsTest extends ItopDataTestCase */ public function testIsActionAllowed(int $iProfileId, array $aClassActionResult) { - $this->AddUser('test1', $iProfileId); - $_SESSION = array(); - UserRights::Login('test1'); + $this->CreateUniqueUserAndLogin('test1', $iProfileId); $bRes = UserRights::IsActionAllowed($aClassActionResult['class'], $aClassActionResult['action']) == UR_ALLOWED_YES; $this->assertEquals($aClassActionResult['res'], $bRes); + UserRights::Logoff(); } /* @@ -239,12 +237,11 @@ class UserRightsTest extends ItopDataTestCase */ public function testIsActionAllowedOnAttribute(int $iProfileId, array $aClassActionResult) { - $this->AddUser('test1', $iProfileId); - $_SESSION = []; - UserRights::Login('test1'); + $this->CreateUniqueUserAndLogin('test1', $iProfileId); $sClass = $aClassActionResult['class']; $bRes = UserRights::IsActionAllowedOnAttribute($sClass, self::$aClasses[$sClass]['attcode'], $aClassActionResult['action']) == UR_ALLOWED_YES; $this->assertEquals($aClassActionResult['res'], $bRes); + UserRights::Logoff(); } /* @@ -291,9 +288,7 @@ class UserRightsTest extends ItopDataTestCase */ public function testProfileDenyingConsole(int $iProfileId) { - $oUser = $this->AddUser('test1', $iProfileId); - $_SESSION = []; - UserRights::Login('test1'); + $oUser = $this->CreateUniqueUserAndLogin('test1', $iProfileId); try { $this->AddProfileToUser($oUser, 2); @@ -303,6 +298,7 @@ class UserRightsTest extends ItopDataTestCase // logout $_SESSION = []; + UserRights::Logoff(); } public function ProfileDenyingConsoleProvider(): array @@ -322,9 +318,7 @@ class UserRightsTest extends ItopDataTestCase */ public function testProfileCannotModifySelf(int $iProfileId) { - $oUser = $this->AddUser('test1', $iProfileId); - $_SESSION = []; - UserRights::Login('test1'); + $oUser = $this->CreateUniqueUserAndLogin('test1', $iProfileId); try { $this->AddProfileToUser($oUser, 1); // trying to become an admin @@ -334,6 +328,7 @@ class UserRightsTest extends ItopDataTestCase // logout $_SESSION = []; + UserRights::Logoff(); } public function ProfileCannotModifySelfProvider(): array @@ -353,9 +348,7 @@ class UserRightsTest extends ItopDataTestCase */ public function testDeletingSelfUser(int $iProfileId) { - $oUser = $this->AddUser('test1', $iProfileId); - $_SESSION = []; - UserRights::Login('test1'); + $oUser = $this->CreateUniqueUserAndLogin('test1', $iProfileId); try { $oUser->DBDelete(); @@ -365,6 +358,7 @@ class UserRightsTest extends ItopDataTestCase // logout $_SESSION = []; + UserRights::Logoff(); } public function DeletingSelfUserProvider(): array @@ -387,9 +381,7 @@ class UserRightsTest extends ItopDataTestCase */ public function testRemovingOwnContact(int $iProfileId) { - $oUser = $this->AddUser('test1', $iProfileId); - $_SESSION = []; - UserRights::Login('test1'); + $oUser = $this->CreateUniqueUserAndLogin('test1', $iProfileId); $oUser->Set('contactid', 0); @@ -398,6 +390,8 @@ class UserRightsTest extends ItopDataTestCase $this->fail('Current User cannot remove his own contact'); } catch (CoreCannotSaveObjectException $e) { } + + UserRights::Logoff(); } public function RemovingOwnContactProvider(): array @@ -417,9 +411,7 @@ class UserRightsTest extends ItopDataTestCase */ public function testUpgradingToAdmin() { - $oUser = $this->AddUser('test1', 3); - $_SESSION = []; - UserRights::Login('test1'); + $oUser = $this->CreateUniqueUserAndLogin('test1', 3); try { $this->AddProfileToUser($oUser, 1); @@ -430,6 +422,7 @@ class UserRightsTest extends ItopDataTestCase // logout $_SESSION = []; + UserRights::Logoff(); } /** @@ -441,9 +434,7 @@ class UserRightsTest extends ItopDataTestCase */ public function testDenyingUserModification() { - $oUser = $this->AddUser('test1', 1); - $_SESSION = []; - UserRights::Login('test1'); + $oUser = $this->CreateUniqueUserAndLogin('test1', 1); $this->AddProfileToUser($oUser, 3); // Keep only the profile 3 (remove profile 1) @@ -461,6 +452,7 @@ class UserRightsTest extends ItopDataTestCase // logout $_SESSION = []; + UserRights::Logoff(); } /** @@ -468,10 +460,8 @@ class UserRightsTest extends ItopDataTestCase */ public function testNonAdminCanListOwnProfiles($bHideAdministrators) { - $oUser = $this->AddUser('test1', 2); // portal user - $_SESSION = []; utils::GetConfig()->Set('security.hide_administrators', $bHideAdministrators); - UserRights::Login('test1'); + $oUser = $this->CreateUniqueUserAndLogin('test1', 2); // portal user // List the link between the User and the Profiles $oSearch = new DBObjectSearch('URP_UserProfile'); @@ -486,6 +476,7 @@ class UserRightsTest extends ItopDataTestCase // logout $_SESSION = []; + UserRights::Logoff(); } public function NonAdminCanListOwnProfilesProvider(): array @@ -496,16 +487,15 @@ class UserRightsTest extends ItopDataTestCase ]; } /** + * @runInSeparateProcess *@dataProvider NonAdminCannotListAdminProfilesProvider */ public function testNonAdminCannotListAdminProfiles($bHideAdministrators, $iExpectedCount) { utils::GetConfig()->Set('security.hide_administrators', $bHideAdministrators); - $this->AddUser('test1', 2); // portal user - $oUserAdmin = $this->AddUser('admin1', 1); - $_SESSION = []; - UserRights::Login('test1'); + $oUserAdmin = $this->CreateUser('admin1', 1); + $this->CreateUniqueUserAndLogin('test1', 2); // portal user $oSearch = new DBObjectSearch('URP_UserProfile'); $oSearch->AddCondition('userid', $oUserAdmin->GetKey()); @@ -518,6 +508,7 @@ class UserRightsTest extends ItopDataTestCase // logout $_SESSION = []; + UserRights::Logoff(); } public function NonAdminCannotListAdminProfilesProvider(): array diff --git a/tests/php-unit-tests/unitary-tests/core/ValueSetObjectsTest.php b/tests/php-unit-tests/unitary-tests/core/ValueSetObjectsTest.php index 9f7089f3f..0483f5e24 100644 --- a/tests/php-unit-tests/unitary-tests/core/ValueSetObjectsTest.php +++ b/tests/php-unit-tests/unitary-tests/core/ValueSetObjectsTest.php @@ -11,11 +11,6 @@ use Combodo\iTop\Test\UnitTest\ItopTestCase; use MetaModel; -/** - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled - */ class ValueSetObjectsTest extends ItopTestCase { diff --git a/tests/php-unit-tests/unitary-tests/core/XMLDataLoaderTest.php b/tests/php-unit-tests/unitary-tests/core/XMLDataLoaderTest.php index 5ee47bc1b..2615e6bc9 100644 --- a/tests/php-unit-tests/unitary-tests/core/XMLDataLoaderTest.php +++ b/tests/php-unit-tests/unitary-tests/core/XMLDataLoaderTest.php @@ -33,14 +33,10 @@ use MetaModel; /** * @group specificOrgInSampleData - * - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled */ class XMLDataLoaderTest extends ItopDataTestCase { - const CREATE_TEST_ORG = true; + const CREATE_TEST_ORG = false; public function testDataLoader() { diff --git a/tests/php-unit-tests/unitary-tests/core/apcEmulationTest.php b/tests/php-unit-tests/unitary-tests/core/apcEmulationTest.php index 2d29703fe..ce9d90601 100644 --- a/tests/php-unit-tests/unitary-tests/core/apcEmulationTest.php +++ b/tests/php-unit-tests/unitary-tests/core/apcEmulationTest.php @@ -33,8 +33,6 @@ define('UNIT_MAX_CACHE_FILES', 10); /** * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled */ class apcEmulationTest extends ItopTestCase { diff --git a/tests/php-unit-tests/unitary-tests/core/dictApcuTest.php b/tests/php-unit-tests/unitary-tests/core/dictApcuTest.php index 3e2d992c0..4acf314a1 100644 --- a/tests/php-unit-tests/unitary-tests/core/dictApcuTest.php +++ b/tests/php-unit-tests/unitary-tests/core/dictApcuTest.php @@ -32,8 +32,6 @@ use Dict; /** * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled */ class dictApcuTest extends ItopTestCase { diff --git a/tests/php-unit-tests/unitary-tests/core/dictTest.php b/tests/php-unit-tests/unitary-tests/core/dictTest.php index a657bf30f..f43ad0c87 100644 --- a/tests/php-unit-tests/unitary-tests/core/dictTest.php +++ b/tests/php-unit-tests/unitary-tests/core/dictTest.php @@ -30,11 +30,8 @@ use Combodo\iTop\Test\UnitTest\ItopTestCase; use Dict; use Exception; - /** - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled + * @runClassInSeparateProcess */ class dictTest extends ItopTestCase { diff --git a/tests/php-unit-tests/unitary-tests/core/ormCaseLogTest.php b/tests/php-unit-tests/unitary-tests/core/ormCaseLogTest.php index 484be7951..326964dbe 100644 --- a/tests/php-unit-tests/unitary-tests/core/ormCaseLogTest.php +++ b/tests/php-unit-tests/unitary-tests/core/ormCaseLogTest.php @@ -15,10 +15,6 @@ use ormCaseLog; * Tests of the ormCaseLog class * * @covers \ormCaseLog - * - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled */ class ormCaseLogTest extends ItopDataTestCase { diff --git a/tests/php-unit-tests/unitary-tests/core/ormLinkSetTest.php b/tests/php-unit-tests/unitary-tests/core/ormLinkSetTest.php index 01db719fa..4889c05a8 100644 --- a/tests/php-unit-tests/unitary-tests/core/ormLinkSetTest.php +++ b/tests/php-unit-tests/unitary-tests/core/ormLinkSetTest.php @@ -37,10 +37,6 @@ use ormLinkSet; * @group itopRequestMgmt * @group itopConfigMgmt * Tests of the ormLinkSet class using N-N links between FunctionalCI and Contact - * - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled */ class ormLinkSetTest extends ItopDataTestCase { diff --git a/tests/php-unit-tests/unitary-tests/core/ormPasswordTest.php b/tests/php-unit-tests/unitary-tests/core/ormPasswordTest.php index d170382ba..6d8c0ca34 100644 --- a/tests/php-unit-tests/unitary-tests/core/ormPasswordTest.php +++ b/tests/php-unit-tests/unitary-tests/core/ormPasswordTest.php @@ -12,10 +12,6 @@ use Utils; /** * Tests of the ormPassword class - * - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled */ class ormPasswordTest extends ItopDataTestCase { @@ -32,9 +28,11 @@ class ormPasswordTest extends ItopDataTestCase */ public function testCheckHash($sToHashValues, $sToHashSalt, $sHashAlgo, $sExpectedHash) { + $prevHashAlgo = utils::GetConfig()->GetPasswordHashAlgo($sHashAlgo); utils::GetConfig()->SetPasswordHashAlgo($sHashAlgo); $oPassword1 = new ormPassword($sExpectedHash, $sToHashSalt); static::assertTrue($oPassword1->CheckPassword($sToHashValues)); + utils::GetConfig()->SetPasswordHashAlgo($prevHashAlgo); } public function HashProvider() diff --git a/tests/php-unit-tests/unitary-tests/core/ormStyleTest.php b/tests/php-unit-tests/unitary-tests/core/ormStyleTest.php index ca74964de..737bc06b2 100644 --- a/tests/php-unit-tests/unitary-tests/core/ormStyleTest.php +++ b/tests/php-unit-tests/unitary-tests/core/ormStyleTest.php @@ -12,10 +12,6 @@ use utils; /** * Tests of the ormStyle class - * - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled */ class ormStyleTest extends ItopTestCase { diff --git a/tests/php-unit-tests/unitary-tests/core/ormTagSetTest.php b/tests/php-unit-tests/unitary-tests/core/ormTagSetTest.php index 890ecf460..e67bfa0dc 100644 --- a/tests/php-unit-tests/unitary-tests/core/ormTagSetTest.php +++ b/tests/php-unit-tests/unitary-tests/core/ormTagSetTest.php @@ -38,10 +38,6 @@ define('MAX_TAGS', 12); /** * @group itopFaqLight * Tests of the ormTagSet class - * - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled */ class ormTagSetTest extends ItopDataTestCase { diff --git a/tests/php-unit-tests/unitary-tests/datamodels/2.x/authent-local/UserLocalTest.php b/tests/php-unit-tests/unitary-tests/datamodels/2.x/authent-local/UserLocalTest.php index f558ef125..d8484d182 100644 --- a/tests/php-unit-tests/unitary-tests/datamodels/2.x/authent-local/UserLocalTest.php +++ b/tests/php-unit-tests/unitary-tests/datamodels/2.x/authent-local/UserLocalTest.php @@ -24,10 +24,6 @@ use utils; /** * test class for UserLocal class - * - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled */ class UserLocalTest extends ItopDataTestCase { @@ -398,6 +394,9 @@ class UserLocalTest extends ItopDataTestCase ); } + /** + * @runInSeparateProcess Otherwise, and only in the CI, test fails asserting $oProfilesSet->Count() == 0 + */ public function testGetUserProfileList() { utils::GetConfig()->SetModuleSetting('authent-local', 'password_validation.pattern', ''); diff --git a/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-config/BulkChangeExtKeyTest.php b/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-config/BulkChangeExtKeyTest.php index 8c8372ae3..0fedb3d5b 100644 --- a/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-config/BulkChangeExtKeyTest.php +++ b/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-config/BulkChangeExtKeyTest.php @@ -8,15 +8,13 @@ use MetaModel; /** - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled - * * created a dedicated test for external keys imports. * * Class BulkChangeExtKeyTest * * @package Combodo\iTop\Test\UnitTest\Core + * + * @runTestsInSeparateProcesses */ class BulkChangeExtKeyTest extends ItopDataTestCase { const CREATE_TEST_ORG = true; @@ -227,13 +225,6 @@ class BulkChangeExtKeyTest extends ItopDataTestCase { return $this->sUid; } - /** * - * @param $aInitData - * @param $aCsvData - * @param $aAttributes - * @param $aExtKeys - * @param $aReconcilKeys - */ public function performBulkChangeTest($sExpectedDisplayableValue, $sExpectedDescription, $oOrg, $bIsRackReconKey, $aAdditionalCsvData=null, $aExtKeys=null, $sSearchLinkUrl=null, $sError="Object not found") { if ($sSearchLinkUrl===null){ diff --git a/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-config/CRUD/DBObjectTest.php b/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-config/CRUD/DBObjectTest.php index c4f5e825b..914110fc7 100644 --- a/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-config/CRUD/DBObjectTest.php +++ b/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-config/CRUD/DBObjectTest.php @@ -10,16 +10,11 @@ use Combodo\iTop\Test\UnitTest\ItopDataTestCase; use lnkContactToFunctionalCI; use MetaModel; -/** - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled - */ class DBObjectTest extends ItopDataTestCase { const USE_TRANSACTION = true; const CREATE_TEST_ORG = true; - const DEBUG_UNIT_TEST = true; + const DEBUG_UNIT_TEST = false; public function testReloadNotNecessaryForInsert() diff --git a/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-config/ConfigPlaceholdersResolverTest.php b/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-config/ConfigPlaceholdersResolverTest.php index 8c82371e0..51b31d920 100644 --- a/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-config/ConfigPlaceholdersResolverTest.php +++ b/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-config/ConfigPlaceholdersResolverTest.php @@ -24,11 +24,6 @@ namespace Combodo\iTop\Test\UnitTest\Module\iTopConfig; use Combodo\iTop\Test\UnitTest\ItopTestCase; use ConfigPlaceholdersResolver; -/** - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled - */ class ConfigPlaceholdersResolverTest extends ItopTestCase { protected function setUp(): void diff --git a/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-config/ConfigTest.php b/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-config/ConfigTest.php index 178440826..6d963499a 100644 --- a/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-config/ConfigTest.php +++ b/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-config/ConfigTest.php @@ -24,11 +24,6 @@ namespace Combodo\iTop\Test\UnitTest\Module\iTopConfig; use Combodo\iTop\Test\UnitTest\ItopTestCase; use Config; -/** - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled - */ class ConfigTest extends ItopTestCase { protected function setUp(): void diff --git a/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-tickets/itopTicketTest.php b/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-tickets/itopTicketTest.php index 73e168f88..a53e50a15 100644 --- a/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-tickets/itopTicketTest.php +++ b/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-tickets/itopTicketTest.php @@ -34,10 +34,6 @@ use Exception; * @group itopVirtualizationMgmt * @group itopConfigMgmt * @group itopTickets - * - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled */ class ItopTicketTest extends ItopDataTestCase { diff --git a/tests/php-unit-tests/unitary-tests/setup/DBBackupDataTest.php b/tests/php-unit-tests/unitary-tests/setup/DBBackupDataTest.php index 02ec0734a..129664c74 100644 --- a/tests/php-unit-tests/unitary-tests/setup/DBBackupDataTest.php +++ b/tests/php-unit-tests/unitary-tests/setup/DBBackupDataTest.php @@ -8,11 +8,6 @@ use DBRestore; use MetaModel; use SetupUtils; -/** - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled - */ class DBBackupDataTest extends ItopDataTestCase { /** @@ -32,35 +27,33 @@ class DBBackupDataTest extends ItopDataTestCase file_put_contents(APPROOT.'/'.$sExtraFile, 'Hello World!'); } } - - if ($bUnsafeFileException) - { - $this->expectExceptionMessage("Backup: Aborting, resource '$sExtraFile'. Considered as UNSAFE because not inside the iTop directory."); - } - $aFiles = $this->InvokeNonPublicMethod('DBBackup', 'PrepareFilesToBackup', $oBackup, [APPROOT.'/conf/production/config-itop.php', $sTmpDir, true]); - SetupUtils::rrmdir($sTmpDir); - $aExpectedFiles = [ - $sTmpDir.'/config-itop.php', - ]; - foreach($aExtraFiles as $sRelFile => $bExists) - { - if ($bExists) - { - $aExpectedFiles[] = $sTmpDir.'/'.$sRelFile; + + try { + if ($bUnsafeFileException) { + $this->expectExceptionMessage("Backup: Aborting, resource '$sExtraFile'. Considered as UNSAFE because not inside the iTop directory."); + } + $aFiles = $this->InvokeNonPublicMethod('DBBackup', 'PrepareFilesToBackup', $oBackup, [APPROOT . '/conf/production/config-itop.php', $sTmpDir, true]); + SetupUtils::rrmdir($sTmpDir); + $aExpectedFiles = [ + $sTmpDir . '/config-itop.php', + ]; + foreach ($aExtraFiles as $sRelFile => $bExists) { + if ($bExists) { + $aExpectedFiles[] = $sTmpDir . '/' . $sRelFile; + } + } + } finally { + // Cleanup + foreach ($aExtraFiles as $sExtraFile => $bExists) { + if ($bExists) { + unlink(APPROOT . '/' . $sExtraFile); + } } } + sort($aFiles); sort($aExpectedFiles); $this->assertEquals($aFiles, $aExpectedFiles); - - // Cleanup - foreach($aExtraFiles as $sExtraFile => $bExists) - { - if ($bExists) - { - unlink(APPROOT.'/'.$sExtraFile); - } - } } function prepareFilesToBackupProvider() @@ -95,9 +88,15 @@ class DBBackupDataTest extends ItopDataTestCase $aExpectedExtraFiles = []; foreach($aExpectedRelativeExtraFiles as $sRelativeName) { - $aExpectedExtraFiles[$sTmpDir.'/'.$sRelativeName] = APPROOT.'/'.$sRelativeName; + if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { + $sRelativeName = str_replace('/', '\\', $sRelativeName); + $aExpectedExtraFiles[$sTmpDir.'\\'.$sRelativeName] = APPROOT.'\\'.$sRelativeName; + } + else { + $aExpectedExtraFiles[$sTmpDir.'/'.$sRelativeName] = APPROOT.'/'.$sRelativeName; + } } - + $oRestore = new DBRestore(MetaModel::GetConfig()); $aExtraFiles = $this->InvokeNonPublicMethod('DBRestore', 'ListExtraFiles', $oRestore, [$sTmpDir]); diff --git a/tests/php-unit-tests/unitary-tests/setup/DBBackupTest.php b/tests/php-unit-tests/unitary-tests/setup/DBBackupTest.php index 715a6173b..1267921ad 100644 --- a/tests/php-unit-tests/unitary-tests/setup/DBBackupTest.php +++ b/tests/php-unit-tests/unitary-tests/setup/DBBackupTest.php @@ -8,11 +8,6 @@ use DateTime; use DBBackup; use utils; -/** - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled - */ class DBBackupTest extends ItopTestCase { protected const DUMMY_DB_HOST = 'localhost'; @@ -32,7 +27,7 @@ class DBBackupTest extends ItopTestCase // We need a connection to the DB, so let's open it ! // We are using the default config file... as the server might not be configured for all the combination we are testing // For example dev env and ci env won't accept TLS connection - $oConfigOnDisk = utils::GetConfig(); + $oConfigOnDisk = utils::GetConfig(true); CMDBSource::InitFromConfig($oConfigOnDisk); } diff --git a/tests/php-unit-tests/unitary-tests/setup/MFCompilerTest.php b/tests/php-unit-tests/unitary-tests/setup/MFCompilerTest.php index 0794677ef..e3e0ca40f 100644 --- a/tests/php-unit-tests/unitary-tests/setup/MFCompilerTest.php +++ b/tests/php-unit-tests/unitary-tests/setup/MFCompilerTest.php @@ -9,9 +9,7 @@ use SubMFCompiler; use utils; /** - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled + * @runClassInSeparateProcess * @covers \MFCompiler::UseLatestPrecompiledFile */ class MFCompilerTest extends ItopTestCase { @@ -53,9 +51,9 @@ class MFCompilerTest extends ItopTestCase { $sSourceDir = $sAppRootForProvider . 'datamodels' . DIRECTORY_SEPARATOR . '2.x'; $sDatamodel2xTargetDir = $sSourceDir . DIRECTORY_SEPARATOR . '/UseLatestPrecompiledFileProvider'; - mkdir($sTempTargetDir); - mkdir($sExtensionTargetDir); - mkdir($sDatamodel2xTargetDir); + if (!is_dir($sTempTargetDir)) mkdir($sTempTargetDir); + if (!is_dir($sExtensionTargetDir)) @mkdir($sExtensionTargetDir); + if (!is_dir($sDatamodel2xTargetDir)) @mkdir($sDatamodel2xTargetDir); self::$aFoldersToCleanup = [ $sTempTargetDir, $sExtensionTargetDir, $sDatamodel2xTargetDir ]; diff --git a/tests/php-unit-tests/unitary-tests/sources/Application/Helper/WebResourcesHelperTest.php b/tests/php-unit-tests/unitary-tests/sources/Application/Helper/WebResourcesHelperTest.php index 4fc30b2b3..515f4a432 100644 --- a/tests/php-unit-tests/unitary-tests/sources/Application/Helper/WebResourcesHelperTest.php +++ b/tests/php-unit-tests/unitary-tests/sources/Application/Helper/WebResourcesHelperTest.php @@ -10,9 +10,6 @@ use Combodo\iTop\Application\Helper\WebResourcesHelper; use Combodo\iTop\Test\UnitTest\ItopTestCase; /** - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled * @covers \WebPage */ class WebResourcesHelperTest extends ItopTestCase diff --git a/tests/php-unit-tests/unitary-tests/sources/Application/RuntimeDashboardTest.php b/tests/php-unit-tests/unitary-tests/sources/Application/RuntimeDashboardTest.php index 7261f170e..5c18c86b0 100644 --- a/tests/php-unit-tests/unitary-tests/sources/Application/RuntimeDashboardTest.php +++ b/tests/php-unit-tests/unitary-tests/sources/Application/RuntimeDashboardTest.php @@ -14,10 +14,6 @@ use SecurityException; /** * We need the metamodel started as this is a dependency of {@link RuntimeDashboard} * - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled - * * @since 2.7.8 3.0.3 3.1.0 N°4449 Test Full Path Disclosure in Dashboard */ class RuntimeDashboardTest extends ItopDataTestCase diff --git a/tests/php-unit-tests/unitary-tests/sources/Application/Search/CriterionConversionTest.php b/tests/php-unit-tests/unitary-tests/sources/Application/Search/CriterionConversionTest.php index 644f57395..aa117c78f 100644 --- a/tests/php-unit-tests/unitary-tests/sources/Application/Search/CriterionConversionTest.php +++ b/tests/php-unit-tests/unitary-tests/sources/Application/Search/CriterionConversionTest.php @@ -44,14 +44,11 @@ use Dict; /** * @group itopRequestMgmt * @group itopServiceMgmt - * - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled */ class CriterionConversionTest extends ItopDataTestCase { - const CREATE_TEST_ORG = true; + const CREATE_TEST_ORG = false; + const USE_TRANSACTION = false; /** * @dataProvider ToOqlProvider @@ -409,9 +406,7 @@ class CriterionConversionTest extends ItopDataTestCase * @dataProvider OqlProvider * * @param $sOQL - * * @param $sExpectedOQL - * * @param $aExpectedCriterion * * @throws \DictExceptionUnknownLanguage @@ -425,7 +420,7 @@ class CriterionConversionTest extends ItopDataTestCase $this->CreateTagData(TAG_CLASS, TAG_ATTCODE, 'tag1', 'First'); $this->CreateTagData(TAG_CLASS, TAG_ATTCODE, 'tag2', 'Second'); - $this->OqlToSearchToOqlAltLanguage($sOQL, $sExpectedOQL, $aExpectedCriterion, "EN US"); + $this->OqlToSearchToOqlAltLanguage($sOQL, $sExpectedOQL, $aExpectedCriterion); } function OqlProvider() @@ -589,9 +584,7 @@ class CriterionConversionTest extends ItopDataTestCase * @dataProvider OqlProviderDates * * @param $sOQL - * * @param $sExpectedOQL - * * @param $aExpectedCriterion * * @throws \DictExceptionUnknownLanguage @@ -599,33 +592,11 @@ class CriterionConversionTest extends ItopDataTestCase * @throws \OQLException * @throws \CoreException */ - function testOqlToForSearchToOqlAltLanguageFR($sOQL, $sExpectedOQL, $aExpectedCriterion) + function testOqlToForSearchToOqlAltLanguage($sOQL, $sExpectedOQL, $aExpectedCriterion) { \MetaModel::GetConfig()->Set('date_and_time_format', array('default' => array('date' => 'Y-m-d', 'time' => 'H:i:s', 'date_time' => '$date $time'))); - $this->OqlToSearchToOqlAltLanguage($sOQL, $sExpectedOQL, $aExpectedCriterion, "FR FR"); + $this->OqlToSearchToOqlAltLanguage($sOQL, $sExpectedOQL, $aExpectedCriterion); } - - - /** - * @dataProvider OqlProviderDates - * - * @param $sOQL - * - * @param $sExpectedOQL - * - * @param $aExpectedCriterion - * - * @throws \DictExceptionUnknownLanguage - * @throws \MissingQueryArgument - * @throws \OQLException - * @throws \CoreException - */ - function testOqlToForSearchToOqlAltLanguageEN($sOQL, $sExpectedOQL, $aExpectedCriterion) - { - \MetaModel::GetConfig()->Set('date_and_time_format', array('default' => array('date' => 'Y-m-d', 'time' => 'H:i:s', 'date_time' => '$date $time'))); - $this->OqlToSearchToOqlAltLanguage($sOQL, $sExpectedOQL, $aExpectedCriterion, "EN US"); - } - function OqlProviderDates() { return array( @@ -706,26 +677,18 @@ class CriterionConversionTest extends ItopDataTestCase /** * * @param $sOQL - * * @param $sExpectedOQL - * * @param $aExpectedCriterion * - * @param $sLanguageCode - * * @throws \CoreException * @throws \DictExceptionUnknownLanguage * @throws \MissingQueryArgument * @throws \OQLException */ - function OqlToSearchToOqlAltLanguage($sOQL, $sExpectedOQL, $aExpectedCriterion, $sLanguageCode ) + function OqlToSearchToOqlAltLanguage($sOQL, $sExpectedOQL, $aExpectedCriterion) { $this->debug($sOQL); - - Dict::SetUserLanguage($sLanguageCode); - - $oSearchForm = new SearchForm(); $oSearch = DBSearch::FromOQL($sOQL); $aFields = $oSearchForm->GetFields(new DBObjectSet($oSearch)); diff --git a/tests/php-unit-tests/unitary-tests/sources/Application/Search/CriterionParserTest.php b/tests/php-unit-tests/unitary-tests/sources/Application/Search/CriterionParserTest.php index 06921b627..00b7aa5d1 100644 --- a/tests/php-unit-tests/unitary-tests/sources/Application/Search/CriterionParserTest.php +++ b/tests/php-unit-tests/unitary-tests/sources/Application/Search/CriterionParserTest.php @@ -33,9 +33,6 @@ use Combodo\iTop\Test\UnitTest\ItopDataTestCase; /** * @group itopRequestMgmt - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled */ class CriterionParserTest extends ItopDataTestCase { diff --git a/tests/php-unit-tests/unitary-tests/sources/Application/Search/SearchFormTest.php b/tests/php-unit-tests/unitary-tests/sources/Application/Search/SearchFormTest.php index 85f9c09ba..133cde21c 100644 --- a/tests/php-unit-tests/unitary-tests/sources/Application/Search/SearchFormTest.php +++ b/tests/php-unit-tests/unitary-tests/sources/Application/Search/SearchFormTest.php @@ -29,14 +29,10 @@ use Exception; /** * @group itopRequestMgmt - * - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled */ class SearchFormTest extends ItopDataTestCase { - const CREATE_TEST_ORG = true; + const CREATE_TEST_ORG = false; /** * @dataProvider GetFieldsProvider diff --git a/tests/php-unit-tests/unitary-tests/sources/Application/Status/StatusIncTest.php b/tests/php-unit-tests/unitary-tests/sources/Application/Status/StatusIncTest.php index bdd8fc9f6..ac936c2a9 100644 --- a/tests/php-unit-tests/unitary-tests/sources/Application/Status/StatusIncTest.php +++ b/tests/php-unit-tests/unitary-tests/sources/Application/Status/StatusIncTest.php @@ -16,11 +16,6 @@ if (!defined('DEBUG_UNIT_TEST')) { define('DEBUG_UNIT_TEST', true); } -/** - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled - */ class StatusIncTest extends ItopTestCase { /** @@ -67,7 +62,10 @@ class StatusIncTest extends ItopTestCase { $this->assertTrue(true); } - public function testStatusStartupWrongDbPwd() + /** + * @runInSeparateProcess + */ + public function testStatusStartupWrongDbPwd() { $this->RequireOnceItopFile('core/cmdbobject.class.inc.php'); $this->RequireOnceItopFile('application/utils.inc.php'); diff --git a/tests/php-unit-tests/unitary-tests/sources/Application/Status/StatusTest.php b/tests/php-unit-tests/unitary-tests/sources/Application/Status/StatusTest.php index ef5a5eb76..03ef79468 100644 --- a/tests/php-unit-tests/unitary-tests/sources/Application/Status/StatusTest.php +++ b/tests/php-unit-tests/unitary-tests/sources/Application/Status/StatusTest.php @@ -8,6 +8,7 @@ namespace Combodo\iTop\Test\UnitTest\Status; use Combodo\iTop\Test\UnitTest\ItopTestCase; +use Config; class StatusTest extends ItopTestCase { @@ -25,10 +26,18 @@ class StatusTest extends ItopTestCase } + protected function GetPHPCommand() + { + $this->RequireOnceItopFile('application/utils.inc.php'); + $oConfig = new Config(ITOP_DEFAULT_CONFIG_FILE); + return $oConfig->Get('php_path'); + } + public function testStatusGood() { $sPath = APPROOT.'/webservices/status.php'; - exec("php $sPath", $aOutput, $iRet); + $sPHP = $this->GetPHPCommand(); + exec("$sPHP $sPath", $aOutput, $iRet); $this->assertEquals(0, $iRet, "Problem executing status page: $sPath, $iRet, aOutput:\n".var_export($aOutput, true)); } @@ -39,7 +48,8 @@ class StatusTest extends ItopTestCase { $sPath = APPROOT.'/webservices/status.php'; - exec("php $sPath", $aOutput, $iRet); + $sPHP = $this->GetPHPCommand(); + exec("$sPHP $sPath", $aOutput, $iRet); $sAdditionalInfo = "aOutput:\n".var_export($aOutput, true).'.'; //Check response diff --git a/tests/php-unit-tests/unitary-tests/sources/Application/TestAutoload.php b/tests/php-unit-tests/unitary-tests/sources/Application/TestAutoload.php index 0db76a875..92bf32c16 100644 --- a/tests/php-unit-tests/unitary-tests/sources/Application/TestAutoload.php +++ b/tests/php-unit-tests/unitary-tests/sources/Application/TestAutoload.php @@ -8,11 +8,6 @@ namespace Combodo\iTop\Test\UnitTest\Application; use Combodo\iTop\Test\UnitTest\ItopDataTestCase; -/** - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled - */ class TestAutoload extends ItopDataTestCase { diff --git a/tests/php-unit-tests/unitary-tests/sources/Application/TwigBase/Twig/TwigTest.php b/tests/php-unit-tests/unitary-tests/sources/Application/TwigBase/Twig/TwigTest.php index 0e2178eda..a460a88fa 100644 --- a/tests/php-unit-tests/unitary-tests/sources/Application/TwigBase/Twig/TwigTest.php +++ b/tests/php-unit-tests/unitary-tests/sources/Application/TwigBase/Twig/TwigTest.php @@ -2,16 +2,11 @@ namespace Combodo\iTop\Test\UnitTest\Application\TwigBase; -use Combodo\iTop\Portal\Twig\AppExtension; use Combodo\iTop\Test\UnitTest\ItopDataTestCase; +use Combodo\iTop\Portal\Twig\AppExtension; use Twig\Environment; use Twig\Loader\FilesystemLoader; -/** - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled - */ class TwigTest extends ItopDataTestCase { protected function setUp(): void diff --git a/tests/php-unit-tests/unitary-tests/sources/Service/Events/EventTest.php b/tests/php-unit-tests/unitary-tests/sources/Service/Events/EventTest.php index 969865382..467ca566a 100644 --- a/tests/php-unit-tests/unitary-tests/sources/Service/Events/EventTest.php +++ b/tests/php-unit-tests/unitary-tests/sources/Service/Events/EventTest.php @@ -9,6 +9,7 @@ namespace Combodo\iTop\Test\UnitTest\Service\Events; use Combodo\iTop\Service\Events\Description\EventDescription; use Combodo\iTop\Service\Events\EventData; use Combodo\iTop\Service\Events\EventService; +use Combodo\iTop\Test\UnitTest\ItopDataTestCase; use Combodo\iTop\Test\UnitTest\ItopTestCase; use ContextTag; use CoreException; @@ -20,7 +21,7 @@ use TypeError; * @package Combodo\iTop\Test\UnitTest\Application\Service * */ -class EventTest extends ItopTestCase +class EventTest extends ItopDataTestCase { const USE_TRANSACTION = false; const CREATE_TEST_ORG = false; @@ -45,7 +46,7 @@ class EventTest extends ItopTestCase public function testRegisterBadCallback($callback) { $this->expectException(TypeError::class); - EventService::RegisterListener('event', $callback); + $this->EventService_RegisterListener('event', $callback); } public function BadCallbackProvider() @@ -60,7 +61,7 @@ class EventTest extends ItopTestCase public function testNoParameterCallbackFunction() { - $sId = EventService::RegisterListener('event', function () { + $sId = $this->EventService_RegisterListener('event', function () { $this->debug("Closure: event received !!!"); self::IncrementCallCount(); }); @@ -82,7 +83,7 @@ class EventTest extends ItopTestCase public function testMethodCallbackFunction(callable $callback) { EventService::RegisterEvent(new EventDescription('event', [], 'test', '', [], '')); - $sId = EventService::RegisterListener('event', $callback); + $sId = $this->EventService_RegisterListener('event', $callback); $this->debug("Registered 'event' with id $sId"); self::$iEventCalls = 0; @@ -109,7 +110,7 @@ class EventTest extends ItopTestCase { EventService::RegisterEvent(new EventDescription('event_a', [], 'test', '', [], '')); $oReceiver = new TestEventReceiver(); - EventService::RegisterListener('event_a', array($oReceiver, 'BrokenCallback')); + $this->EventService_RegisterListener('event_a', array($oReceiver, 'BrokenCallback')); $this->expectException(TypeError::class); EventService::FireEvent(new EventData('event_a')); @@ -119,7 +120,7 @@ class EventTest extends ItopTestCase { EventService::RegisterEvent(new EventDescription('event_a', [], 'test', '', [], '')); $oReceiver = new TestEventReceiver(); - EventService::RegisterListener('event_a', array($oReceiver, 'OnEvent1')); + $this->EventService_RegisterListener('event_a', array($oReceiver, 'OnEvent1')); self::$iEventCalls = 0; EventService::FireEvent(new EventData('event_a')); @@ -139,15 +140,15 @@ class EventTest extends ItopTestCase EventService::RegisterEvent(new EventDescription('event_a', [], 'test', '', [], '')); EventService::RegisterEvent(new EventDescription('event_b', [], 'test', '', [], '')); $oReceiver = new TestEventReceiver(); - EventService::RegisterListener('event_a', array($oReceiver, 'OnEvent1')); - EventService::RegisterListener('event_a', array($oReceiver, 'OnEvent2')); - EventService::RegisterListener('event_a', array('Combodo\iTop\Test\UnitTest\Service\Events\TestEventReceiver', 'OnStaticEvent1')); - EventService::RegisterListener('event_a', 'Combodo\iTop\Test\UnitTest\Service\Events\TestEventReceiver::OnStaticEvent2'); + $this->EventService_RegisterListener('event_a', array($oReceiver, 'OnEvent1')); + $this->EventService_RegisterListener('event_a', array($oReceiver, 'OnEvent2')); + $this->EventService_RegisterListener('event_a', array('Combodo\iTop\Test\UnitTest\Service\Events\TestEventReceiver', 'OnStaticEvent1')); + $this->EventService_RegisterListener('event_a', 'Combodo\iTop\Test\UnitTest\Service\Events\TestEventReceiver::OnStaticEvent2'); - EventService::RegisterListener('event_b', array($oReceiver, 'OnEvent1')); - EventService::RegisterListener('event_b', array($oReceiver, 'OnEvent2')); - EventService::RegisterListener('event_b', array('Combodo\iTop\Test\UnitTest\Service\Events\TestEventReceiver', 'OnStaticEvent1')); - EventService::RegisterListener('event_b', 'Combodo\iTop\Test\UnitTest\Service\Events\TestEventReceiver::OnStaticEvent2'); + $this->EventService_RegisterListener('event_b', array($oReceiver, 'OnEvent1')); + $this->EventService_RegisterListener('event_b', array($oReceiver, 'OnEvent2')); + $this->EventService_RegisterListener('event_b', array('Combodo\iTop\Test\UnitTest\Service\Events\TestEventReceiver', 'OnStaticEvent1')); + $this->EventService_RegisterListener('event_b', 'Combodo\iTop\Test\UnitTest\Service\Events\TestEventReceiver::OnStaticEvent2'); self::$iEventCalls = 0; EventService::FireEvent(new EventData('event_a')); @@ -162,13 +163,13 @@ class EventTest extends ItopTestCase { EventService::RegisterEvent(new EventDescription('event1', [], 'test', '', [], '')); $oReceiver = new TestEventReceiver(); - $sId = EventService::RegisterListener('event1', array($oReceiver, 'OnEvent1')); + $sId = $this->EventService_RegisterListener('event1', array($oReceiver, 'OnEvent1')); $this->debug("Registered $sId"); - $sId = EventService::RegisterListener('event1', array($oReceiver, 'OnEvent1')); + $sId = $this->EventService_RegisterListener('event1', array($oReceiver, 'OnEvent1')); $this->debug("Registered $sId"); - $sId = EventService::RegisterListener('event1', array($oReceiver, 'OnEvent1')); + $sId = $this->EventService_RegisterListener('event1', array($oReceiver, 'OnEvent1')); $this->debug("Registered $sId"); - $sId = EventService::RegisterListener('event1', array($oReceiver, 'OnEvent1')); + $sId = $this->EventService_RegisterListener('event1', array($oReceiver, 'OnEvent1')); $this->debug("Registered $sId"); self::$iEventCalls = 0; @@ -180,8 +181,8 @@ class EventTest extends ItopTestCase { EventService::RegisterEvent(new EventDescription('event1', [], 'test', '', [], '')); $oReceiver = new TestEventReceiver(); - EventService::RegisterListener('event1', [$oReceiver, 'OnEventWithData'], ''); - EventService::RegisterListener('event1', [$oReceiver, 'OnEventWithData'], ''); + $this->EventService_RegisterListener('event1', [$oReceiver, 'OnEventWithData'], ''); + $this->EventService_RegisterListener('event1', [$oReceiver, 'OnEventWithData'], ''); self::$iEventCalls = 0; EventService::FireEvent(new EventData('event1', '', ['text' => 'Event Data 1'])); @@ -193,11 +194,11 @@ class EventTest extends ItopTestCase EventService::RegisterEvent(new EventDescription('event1', [], 'test', '', [], '')); EventService::RegisterEvent(new EventDescription('event2', [], 'test', '', [], '')); $oReceiver = new TestEventReceiver(); - EventService::RegisterListener('event1', [$oReceiver, 'OnEvent1'], '', [], null, 0); - EventService::RegisterListener('event1', [$oReceiver, 'OnEvent2'], '', [], null, 1); + $this->EventService_RegisterListener('event1', [$oReceiver, 'OnEvent1'], '', [], null, 0); + $this->EventService_RegisterListener('event1', [$oReceiver, 'OnEvent2'], '', [], null, 1); - EventService::RegisterListener('event2', [$oReceiver, 'OnEvent1'], '', [], null, 1); - EventService::RegisterListener('event2', [$oReceiver, 'OnEvent2'], '', [], null, 0); + $this->EventService_RegisterListener('event2', [$oReceiver, 'OnEvent1'], '', [], null, 1); + $this->EventService_RegisterListener('event2', [$oReceiver, 'OnEvent2'], '', [], null, 0); self::$iEventCalls = 0; EventService::FireEvent(new EventData('event1')); @@ -218,14 +219,14 @@ class EventTest extends ItopTestCase { EventService::RegisterEvent(new EventDescription('event1', [], 'test', '', [], '')); $oReceiver = new TestEventReceiver(); - EventService::RegisterListener('event1', [$oReceiver, 'OnEvent1'], '', [], null, 0); - EventService::RegisterListener('event1', [$oReceiver, 'OnEvent2'], '', [], 'test_context', 1); + $this->EventService_RegisterListener('event1', [$oReceiver, 'OnEvent1'], '', [], null, 0); + $this->EventService_RegisterListener('event1', [$oReceiver, 'OnEvent2'], '', [], 'test_context', 1); self::$iEventCalls = 0; EventService::FireEvent(new EventData('event1')); $this->assertEquals(1, self::$iEventCalls); - ContextTag::AddContext('test_context'); + $oTag = new ContextTag('test_context'); self::$iEventCalls = 0; EventService::FireEvent(new EventData('event1')); $this->assertEquals(2, self::$iEventCalls); @@ -236,13 +237,13 @@ class EventTest extends ItopTestCase EventService::RegisterEvent(new EventDescription('event1', [], 'test', '', [], '')); EventService::RegisterEvent(new EventDescription('event2', [], 'test', '', [], '')); $oReceiver = new TestEventReceiver(); - EventService::RegisterListener('event1', [$oReceiver, 'OnEvent1'], 'A', [], null, 0); - EventService::RegisterListener('event1', [$oReceiver, 'OnEvent2'], 'A', [], null, 1); - EventService::RegisterListener('event1', 'Combodo\iTop\Test\UnitTest\Service\Events\TestEventReceiver::OnStaticEvent1', null, [], null, 2); + $this->EventService_RegisterListener('event1', [$oReceiver, 'OnEvent1'], 'A', [], null, 0); + $this->EventService_RegisterListener('event1', [$oReceiver, 'OnEvent2'], 'A', [], null, 1); + $this->EventService_RegisterListener('event1', 'Combodo\iTop\Test\UnitTest\Service\Events\TestEventReceiver::OnStaticEvent1', null, [], null, 2); - EventService::RegisterListener('event2', [$oReceiver, 'OnEvent1'], 'A', [], null, 1); - EventService::RegisterListener('event2', 'Combodo\iTop\Test\UnitTest\Service\Events\TestEventReceiver::OnStaticEvent1', null, [], null, 2); - EventService::RegisterListener('event2', [$oReceiver, 'OnEvent2'], 'B', [], null, 0); + $this->EventService_RegisterListener('event2', [$oReceiver, 'OnEvent1'], 'A', [], null, 1); + $this->EventService_RegisterListener('event2', 'Combodo\iTop\Test\UnitTest\Service\Events\TestEventReceiver::OnStaticEvent1', null, [], null, 2); + $this->EventService_RegisterListener('event2', [$oReceiver, 'OnEvent2'], 'B', [], null, 0); self::$iEventCalls = 0; EventService::FireEvent(new EventData('event1', 'A')); @@ -272,13 +273,13 @@ class EventTest extends ItopTestCase EventService::RegisterEvent(new EventDescription('event1', [], 'test', '', [], '')); EventService::RegisterEvent(new EventDescription('event2', [], 'test', '', [], '')); $oReceiver = new TestEventReceiver(); - $sId = EventService::RegisterListener('event1', array($oReceiver, 'OnEvent1')); + $sId = $this->EventService_RegisterListener('event1', array($oReceiver, 'OnEvent1')); $this->debug("Registered $sId"); - $sId = EventService::RegisterListener('event1', array($oReceiver, 'OnEvent1')); + $sId = $this->EventService_RegisterListener('event1', array($oReceiver, 'OnEvent1')); $this->debug("Registered $sId"); - $sId = EventService::RegisterListener('event1', array($oReceiver, 'OnEvent1')); + $sId = $this->EventService_RegisterListener('event1', array($oReceiver, 'OnEvent1')); $this->debug("Registered $sId"); - $sId = EventService::RegisterListener('event2', array($oReceiver, 'OnEvent1')); + $sId = $this->EventService_RegisterListener('event2', array($oReceiver, 'OnEvent1')); $this->debug("Registered $sId"); self::$iEventCalls = 0; @@ -305,13 +306,13 @@ class EventTest extends ItopTestCase EventService::RegisterEvent(new EventDescription('event1', [], 'test', '', [], '')); EventService::RegisterEvent(new EventDescription('event2', [], 'test', '', [], '')); $oReceiver = new TestEventReceiver(); - $sId = EventService::RegisterListener('event1', array($oReceiver, 'OnEvent1')); + $sId = $this->EventService_RegisterListener('event1', array($oReceiver, 'OnEvent1')); $this->debug("Registered $sId"); - $sId = EventService::RegisterListener('event1', array($oReceiver, 'OnEvent1')); + $sId = $this->EventService_RegisterListener('event1', array($oReceiver, 'OnEvent1')); $this->debug("Registered $sId"); - $sId = EventService::RegisterListener('event1', array($oReceiver, 'OnEvent1')); + $sId = $this->EventService_RegisterListener('event1', array($oReceiver, 'OnEvent1')); $this->debug("Registered $sId"); - $sId = EventService::RegisterListener('event2', array($oReceiver, 'OnEvent1')); + $sId = $this->EventService_RegisterListener('event2', array($oReceiver, 'OnEvent1')); $this->debug("Registered $sId"); self::$iEventCalls = 0; @@ -333,13 +334,13 @@ class EventTest extends ItopTestCase EventService::RegisterEvent(new EventDescription('event1', [], 'test', '', [], '')); EventService::RegisterEvent(new EventDescription('event2', [], 'test', '', [], '')); $oReceiver = new TestEventReceiver(); - $sIdToRemove = EventService::RegisterListener('event1', array($oReceiver, 'OnEvent1')); + $sIdToRemove = $this->EventService_RegisterListener('event1', array($oReceiver, 'OnEvent1')); $this->debug("Registered $sIdToRemove"); - $sId = EventService::RegisterListener('event1', array($oReceiver, 'OnEvent1')); + $sId = $this->EventService_RegisterListener('event1', array($oReceiver, 'OnEvent1')); $this->debug("Registered $sId"); - $sId = EventService::RegisterListener('event1', array($oReceiver, 'OnEvent1')); + $sId = $this->EventService_RegisterListener('event1', array($oReceiver, 'OnEvent1')); $this->debug("Registered $sId"); - $sId = EventService::RegisterListener('event2', array($oReceiver, 'OnEvent1')); + $sId = $this->EventService_RegisterListener('event2', array($oReceiver, 'OnEvent1')); $this->debug("Registered $sId"); self::$iEventCalls = 0; diff --git a/tests/php-unit-tests/unitary-tests/synchro/DataSynchroTest.php b/tests/php-unit-tests/unitary-tests/synchro/DataSynchroTest.php index 613abea3b..d418e23c2 100644 --- a/tests/php-unit-tests/unitary-tests/synchro/DataSynchroTest.php +++ b/tests/php-unit-tests/unitary-tests/synchro/DataSynchroTest.php @@ -31,10 +31,6 @@ use utils; * @package Combodo\iTop\Test\UnitTest\Synchro * @group dataSynchro * @group defaultProfiles - * - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled */ class DataSynchroTest extends ItopDataTestCase { diff --git a/tests/php-unit-tests/unitary-tests/webservices/CliResetSessionTest.php b/tests/php-unit-tests/unitary-tests/webservices/CliResetSessionTest.php index a3b78130f..f5ad5a33e 100644 --- a/tests/php-unit-tests/unitary-tests/webservices/CliResetSessionTest.php +++ b/tests/php-unit-tests/unitary-tests/webservices/CliResetSessionTest.php @@ -10,8 +10,6 @@ use MetaModel; /** * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled */ class CliResetSessionTest extends ItopDataTestCase { diff --git a/tests/php-unit-tests/unitary-tests/webservices/ImportTest.php b/tests/php-unit-tests/unitary-tests/webservices/ImportTest.php index 1a4537f63..08663eed3 100644 --- a/tests/php-unit-tests/unitary-tests/webservices/ImportTest.php +++ b/tests/php-unit-tests/unitary-tests/webservices/ImportTest.php @@ -5,11 +5,6 @@ namespace Combodo\iTop\Test\UnitTest\Webservices; use Combodo\iTop\Test\UnitTest\ItopDataTestCase; use MetaModel; -/** - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled - */ class ImportTest extends ItopDataTestCase { const USE_TRANSACTION = false; diff --git a/tests/php-unit-tests/unitary-tests/webservices/RestTest.php b/tests/php-unit-tests/unitary-tests/webservices/RestTest.php index 5c1fc4676..d23e7cba8 100644 --- a/tests/php-unit-tests/unitary-tests/webservices/RestTest.php +++ b/tests/php-unit-tests/unitary-tests/webservices/RestTest.php @@ -13,93 +13,161 @@ use utils; * @group restApi * @group defaultProfiles * - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @backupGlobals disabled + * @runClassInSeparateProcess */ class RestTest extends ItopDataTestCase { const USE_TRANSACTION = false; + const CREATE_TEST_ORG = false; - const ENUM_JSONDATA_AS_STRING = 0; - const ENUM_JSONDATA_AS_FILE = 1; - const ENUM_JSONDATA_NONE = 2; - - private $sTmpFile = ""; - private $sUrl; - private $sLogin; - private $sPassword = "Iuytrez9876543ç_è-("; - /** @var int $iJsonDataMode */ - private int $iJsonDataMode = self::ENUM_JSONDATA_AS_STRING; + static private $sUrl; + static private $sLogin; + static private $sPassword = "Iuytrez9876543ç_è-("; /** - * @throws Exception - */ - protected function setUp(): void - { - parent::setUp(); - - $this->sLogin = "rest-user-".date('dmYHis'); - $this->CreateTestOrganization(); - - if (!empty($this->sTmpFile)) { - unlink($this->sTmpFile); - } - - $this->sUrl = MetaModel::GetConfig()->Get('app_root_url'); - - $oRestProfile = MetaModel::GetObjectFromOQL("SELECT URP_Profiles WHERE name = :name", array('name' => 'REST Services User'), true); - $oAdminProfile = MetaModel::GetObjectFromOQL("SELECT URP_Profiles WHERE name = :name", array('name' => 'Administrator'), true); - - if (is_object($oRestProfile) && is_object($oAdminProfile)) { - $oUser = $this->CreateUser($this->sLogin, $oRestProfile->GetKey(), $this->sPassword); - $this->AddProfileToUser($oUser, $oAdminProfile->GetKey()); - } - } - - public function testJSONPCallback() + * This method is called before the first test of this test class is run (in the current process). + */ + public static function setUpBeforeClass(): void { - $sCallbackName = 'fooCallback'; - $sJsonData = <<CallRestApi($sJsonData); - // - Try to decode JSON to array to check if it is well-formed - $aJSONResultAsArray = json_decode($sJSONResult, true); - if (false === is_array($aJSONResultAsArray)) { - $this->fail('JSON result could not be decoded as array, it might be malformed'); - } - - // Test JSONP with callback by checking that it is the same as the regular JSON but within the JS callback - $sJSONPResult = $this->CallRestApi($sJsonData, $sCallbackName); - $this->assertEquals($sCallbackName.'('.$sJSONResult.');', $sJSONPResult, 'JSONP response callback does not match expected result'); + parent::setUpBeforeClass(); } /** - * @dataProvider BasicProvider - * @param int $iJsonDataMode + * This method is called after the last test of this test class is run (in the current process). */ - public function testCreateApi($iJsonDataMode) + public static function tearDownAfterClass(): void { - $this->iJsonDataMode = $iJsonDataMode; + parent::tearDownAfterClass(); + } + /** + * @throws Exception + */ + protected function setUp(): void + { + parent::setUp(); + + static::$sUrl = MetaModel::GetConfig()->Get('app_root_url'); + static::$sLogin = "rest-user-".date('dmYHis'); + + $this->CreateTestOrganization(); + + $oRestProfile = MetaModel::GetObjectFromOQL("SELECT URP_Profiles WHERE name = :name", array('name' => 'REST Services User'), true); + $oAdminProfile = MetaModel::GetObjectFromOQL("SELECT URP_Profiles WHERE name = :name", array('name' => 'Administrator'), true); + + if (is_object($oRestProfile) && is_object($oAdminProfile)) { + $oUser = $this->CreateUser(static::$sLogin, $oRestProfile->GetKey(), static::$sPassword); + $this->AddProfileToUser($oUser, $oAdminProfile->GetKey()); + } + } + + public function testListOperationsAndJSONPCallback() + { + $sCallbackName = 'fooCallback'; + $sJsonData = '{"operation": "list_operations"}'; + + // Test regular JSON result + $sJSONResult = $this->CallRestApi_HTTP($sJsonData); + // - Try to decode JSON to array to check if it is well-formed + $aJSONResultAsArray = json_decode($sJSONResult, true); + $this->assertArrayHasKey('version', $aJSONResultAsArray); + $this->assertArrayHasKey('operations', $aJSONResultAsArray); + $this->assertArrayHasKey('code', $aJSONResultAsArray); + $this->assertArrayHasKey('message', $aJSONResultAsArray); + $this->assertEquals(0, $aJSONResultAsArray['code']); + $this->assertTrue(count($aJSONResultAsArray['operations']) >= 7, 'Expecting at least 7 operations from Core Services'); + foreach ($aJSONResultAsArray['operations'] as $aOperationData) { + $this->assertCount(3, $aOperationData); + $this->assertArrayHasKey('verb', $aOperationData); + $this->assertArrayHasKey('description', $aOperationData); + $this->assertArrayHasKey('extension', $aOperationData); + $this->assertNotEmpty($aOperationData['verb']); + } + + // Test JSONP with callback by checking that it is the same as the regular JSON but within the JS callback + $sJSONPResult = $this->CallRestApi_HTTP($sJsonData, $sCallbackName); + $this->assertEquals($sCallbackName.'('.$sJSONResult.');', $sJSONPResult, 'JSONP response callback does not match expected result'); + } + + public function testMissingJSONData() + { + $sOutputJson = $this->CallRestApi_HTTP(); + $aJson = json_decode($sOutputJson, true); + $this->assertEquals(3, $aJson['code'], $sOutputJson); + $this->assertEquals("Error: Missing parameter 'json_data'", $aJson['message'], $sOutputJson); + } + + public function testPostJSONDataAsCurlFile() + { + $sCallbackName = 'fooCallback'; + $sJsonData = '{"operation": "list_operations"}'; + + // Test regular JSON result + $sJSONResult = $this->CallRestApi_HTTP($sJsonData, null, true); + $aJSONResultAsArray = json_decode($sJSONResult, true); + $this->assertEquals(0, $aJSONResultAsArray['code'], $sJSONResult); + } + + public function testCoreApiGet(){ // Create ticket $description = date('dmY H:i:s'); - $sOutputJson = $this->CreateTicketViaApi($description); + $oTicket = $this->CreateSampleTicket($description); + $iId = $oTicket->GetKey(); + + $sJSONOutput = $this->CallCoreRestApi_Internally(<<$description

", + "id": "$iId" + }, + "key": "$iId", + "message": "" + } + } +} +JSON; + $this->assertJsonStringEqualsJsonString($sExpectedJsonOuput, $sJSONOutput); + } + + public function testCoreApiCreate() + { + // Create ticket + $description = date('dmY H:i:s'); + $sOutputJson = $this->CallCoreRestApi_Internally(<<debug("Output: '$sOutputJson'"); $aJson = json_decode($sOutputJson, true); $this->assertNotNull($aJson, "Cannot decode returned JSON : $sOutputJson"); - if ($this->iJsonDataMode === static::ENUM_JSONDATA_NONE){ - $this->assertStringContainsString("3", "".$aJson['code'], $sOutputJson); - $this->assertStringContainsString("Error: Missing parameter 'json_data'", "".$aJson['message'], $sOutputJson); - return; - } - $this->assertStringContainsString("0", "".$aJson['code'], $sOutputJson); $sUserRequestKey = $this->array_key_first($aJson['objects']); $this->assertStringContainsString('UserRequest::', $sUserRequestKey); @@ -110,16 +178,14 @@ JSON; JSON; $this->assertJsonStringEqualsJsonString($sExpectedJsonOuput, $sOutputJson); - $sExpectedJsonOuput = <<$description<\/p>"}}},"code":0,"message":"Found: 1"} -JSON; - $this->assertJsonStringEqualsJsonString($sExpectedJsonOuput, $this->GetTicketViaRest($iId)); + $oObject = MetaModel::GetObject('UserRequest', $iId, false, true); + $this->assertIsObject($oObject, "Object UserRequest::$iId not present in the database"); + $this->assertSame("

$description

", $oObject->Get('description')); - $aCmdbChangeUserInfo = $this->GetCmdbChangeUserInfo($iId); - $this->assertEquals(['CMDBChangeOpCreate' => 'test'], $aCmdbChangeUserInfo); + $this->assertDBChangeOpCount('UserRequest', $iId, 1); // Delete ticket - $this->DeleteTicketFromApi($iId); + $oObject->DBDelete(); } /** @@ -136,135 +202,36 @@ JSON; } } - /** - * @dataProvider BasicProvider - * @param int $iJsonDataMode - */ - public function testUpdateApi($iJsonDataMode) + public function testCoreApiUpdate() { - $this->iJsonDataMode = $iJsonDataMode; - //create ticket $description = date('dmY H:i:s'); - $sOuputJson = $this->CreateTicketViaApi($description); - $aJson = json_decode($sOuputJson, true); - $this->assertNotNull($aJson, 'json_decode() on the REST API response returned null :('); - - if ($this->iJsonDataMode === static::ENUM_JSONDATA_NONE){ - $this->assertStringContainsString("3", "".$aJson['code'], $sOuputJson); - $this->assertStringContainsString("Error: Missing parameter 'json_data'", "".$aJson['message'], $sOuputJson); - return; - } - - $this->assertStringContainsString("0", "".$aJson['code'], $sOuputJson); - $sUserRequestKey = $this->array_key_first($aJson['objects']); - $this->assertStringContainsString('UserRequest::', $sUserRequestKey); - $iId = $aJson['objects'][$sUserRequestKey]['key']; + $oTicket = $this->CreateSampleTicket($description); + $iId = $oTicket->GetKey(); // Update ticket - $description = date('Ymd H:i:s'); + $description = 'Update to '.date('Ymd H:i:s'); + $sJSONOutput = $this->CallCoreRestApi_Internally(<<$description<\/p>"}}},"code":0,"message":null} JSON; - $this->assertJsonStringEqualsJsonString($sExpectedJsonOuput, $this->UpdateTicketViaApi($iId, $description)); + $this->assertJsonStringEqualsJsonString($sExpectedJsonOuput, $sJSONOutput); - $aCmdbChangeUserInfo = $this->GetCmdbChangeUserInfo($iId); - $this->assertEquals(['CMDBChangeOpCreate' => 'test', 'CMDBChangeOpSetAttributeHTML' => 'test'], $aCmdbChangeUserInfo); - - - // Delete ticket - $this->DeleteTicketFromApi($iId); + $this->assertDBChangeOpCount('UserRequest', $iId, 2); } - /** - * @dataProvider BasicProvider - * @param int $iJsonDataMode - */ - public function testDeleteApi($iJsonDataMode) + public function testCoreApiDelete() { - $this->iJsonDataMode = $iJsonDataMode; - // Create ticket $description = date('dmY H:i:s'); - - $sOuputJson = $this->CreateTicketViaApi($description); - $aJson = json_decode($sOuputJson, true); - $this->assertNotNull($aJson, 'json_decode() on the REST API response returned null :('); - - if ($this->iJsonDataMode === static::ENUM_JSONDATA_NONE){ - $this->assertStringContainsString("3", "".$aJson['code'], $sOuputJson); - $this->assertStringContainsString("Error: Missing parameter 'json_data'", "".$aJson['message'], $sOuputJson); - return; - } - - $this->assertStringContainsString("0", "".$aJson['code'], $sOuputJson); - $sUserRequestKey = $this->array_key_first($aJson['objects']); - $this->assertStringContainsString('UserRequest::', $sUserRequestKey); - $iId = $aJson['objects'][$sUserRequestKey]['key']; + $oTicket = $this->CreateSampleTicket($description); + $iId = $oTicket->GetKey(); // Delete ticket - $sExpectedJsonOuput = <<assertStringContainsString($sExpectedJsonOuput, $this->DeleteTicketFromApi($iId)); - - $sExpectedJsonOuput = <<assertJsonStringEqualsJsonString($sExpectedJsonOuput, $this->GetTicketViaRest($iId)); - } - - private function GetTicketViaRest($iId){ - $sJsonGetContent = <<CallRestApi($sJsonGetContent); - } - - public function BasicProvider(){ - return [ - 'call rest call' => [ 'sJsonDataMode' => static::ENUM_JSONDATA_AS_STRING], - 'pass json_data as file' => [ 'sJsonDataMode' => static::ENUM_JSONDATA_AS_FILE], - 'no json data' => [ 'sJsonDataMode' => static::ENUM_JSONDATA_NONE] - ]; - } - - private function UpdateTicketViaApi($iId, $description){ - $sJsonUpdateContent = <<CallRestApi($sJsonUpdateContent); - } - - private function CreateTicketViaApi($description){ - $sJsonCreateContent = <<CallRestApi($sJsonCreateContent); - } - - private function DeleteTicketFromApi($iId){ - $sJson = <<CallCoreRestApi_Internally(<<CallRestApi($sJson); + $this->assertStringContainsString($sExpectedJsonOuput, $sJSONOutput); + $oObject = MetaModel::GetObject('UserRequest', $iId, false, true); + $this->assertSame(null, $oObject, "Object UserRequest::$iId still present in the database"); } - private function CallRestApi(string $sJsonDataContent, string $sCallbackName = null){ + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // Helpers + // + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + private function CreateSampleTicket($description) + { + $oTicket = $this->createObject('UserRequest', [ + 'org_id' => $this->getTestOrgId(), + "title" => "Houston, got a problem", + "description" => $description + ]); + return $oTicket; + } + + /** + * @param string|null $sJsonDataContent If null, then no data is posted and the service should reply with an error + * @param string|null $sCallbackName JSONP callback + * @param bool $bJSONDataAsFile Set to true to test with the data provided to curl as a file + * + * @return bool|string + */ + private function CallRestApi_HTTP(string $sJsonDataContent = null, string $sCallbackName = null, bool $bJSONDataAsFile = false) + { $ch = curl_init(); $aPostFields = [ 'version' => '1.3', - 'auth_user' => $this->sLogin, - 'auth_pwd' => $this->sPassword, + 'auth_user' => static::$sLogin, + 'auth_pwd' => static::$sPassword, ]; - if ($this->iJsonDataMode === static::ENUM_JSONDATA_AS_STRING) { - $this->sTmpFile = tempnam(sys_get_temp_dir(), 'jsondata_'); - file_put_contents($this->sTmpFile, $sJsonDataContent); + $sTmpFile = null; + if (!is_null($sJsonDataContent)) { + if ($bJSONDataAsFile) { + $sTmpFile = tempnam(sys_get_temp_dir(), 'jsondata_'); + file_put_contents($sTmpFile, $sJsonDataContent); - $oCurlFile = curl_file_create($this->sTmpFile); - $aPostFields['json_data'] = $oCurlFile; - } else if ($this->iJsonDataMode === static::ENUM_JSONDATA_AS_FILE) { - $aPostFields['json_data'] = $sJsonDataContent; + $oCurlFile = curl_file_create($sTmpFile); + $aPostFields['json_data'] = $oCurlFile; + } + else { + $aPostFields['json_data'] = $sJsonDataContent; + } } if (utils::IsNotNullOrEmptyString($sCallbackName)) { $aPostFields['callback'] = $sCallbackName; } - curl_setopt($ch, CURLOPT_URL, "$this->sUrl/webservices/rest.php"); + curl_setopt($ch, CURLOPT_URL, static::$sUrl."/webservices/rest.php"); curl_setopt($ch, CURLOPT_POST, 1);// set post data to true curl_setopt($ch, CURLOPT_POSTFIELDS, $aPostFields); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); @@ -310,39 +310,27 @@ JSON; $sJson = curl_exec($ch); curl_close ($ch); + if (!is_null($sTmpFile)) { + unlink($sTmpFile); + } + return $sJson; } - /** - * @param $iId - * Get CMDBChangeOp info to test - * @return array - */ - private function GetCmdbChangeUserInfo($iId){ - $sJsonGetContent = <<operation; - $aUserInfo = []; - $sOutput = $this->CallRestApi($sJsonGetContent); - $aJson = json_decode($sOutput, true); - $this->assertNotNull($aJson, 'json_decode() on the REST API response returned null :('); + //\UserRights::Login(static::$sLogin); + \CMDBObject::SetTrackOrigin('webservice-rest'); + \CMDBObject::SetTrackInfo('test'); - if (is_array($aJson) && array_key_exists('objects', $aJson)) { - $aObjects = $aJson['objects']; - if (!empty($aObjects)) { - foreach ($aObjects as $aObject) { - $sClass = $aObject['class']; - $sUserInfo = $aObject['fields']['userinfo']; - $aUserInfo[$sClass] = $sUserInfo; - } - } - } - return $aUserInfo; + $oRestSP = new \CoreServices(); + $oResult = $oRestSP->ExecOperation('1.3', $sOperation, $oJsonData); + + //\UserRights::Logoff(); + + return json_encode($oResult); } }