Merge remote-tracking branch 'origin/support/3.0' into support/3.1

# Conflicts:
#	tests/php-unit-tests/src/BaseTestCase/ItopTestCase.php
This commit is contained in:
Romain Quetiez
2023-08-17 17:45:40 +02:00
85 changed files with 1128 additions and 903 deletions

View File

@@ -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;
}
}
}

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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
*/

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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".
- 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
<ini name="memory_limit" value="512M"/>
```
### 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)

View File

@@ -0,0 +1 @@
This directory aims at providing experimental proof of the mechanics of PHPUnit

View File

@@ -0,0 +1,64 @@
<?php
namespace Combodo\iTop\Test\UnitTest;
/**
* Shows that
* 1) the option runClassInSeparateProcess is equivalent to runTestsInSeparateProcesses
* 2) setUpBeforeClass is called within each spawned process (the main one, then in eventuel subprocesses)
* 3) setUp behaves as expected, i.e. called one within the same process as the test itself
*
* @preserveGlobalState disabled
* @runClassInSeparateProcess
*/
class runClassInSeparateProcessTest extends ItopDataTestCase
{
static public function setUpBeforeClass(): void
{
parent::setUpBeforeClass(); // TODO: Change the autogenerated stub
file_put_contents(
dirname(__FILE__).'/pid.txt',
getmypid().';'.static::class.';'.__METHOD__."\n",
FILE_APPEND);
}
protected function LogPid()
{
file_put_contents(
dirname(__FILE__).'/pid.txt',
getmypid().';'.static::class.';'.$this->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],
];
}
}

View File

@@ -0,0 +1,45 @@
<?php
namespace Combodo\iTop\Test\UnitTest;
use PHPUnit\Framework\TestCase;
/**
* Shows that tearDown is called after a fatal error within a test
*/
class tearDownAfterFailureTest extends TestCase
{
static $bIsCorrectlyInitialized = true;
protected function tearDown(): void
{
parent::tearDown();
static::$bIsCorrectlyInitialized = true;
}
function testIsInitializedAndChangeIt()
{
static::assertTrue(static::$bIsCorrectlyInitialized);
static::$bIsCorrectlyInitialized = false;
$this->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);
}
}

View File

@@ -0,0 +1,68 @@
<?php
namespace Combodo\iTop\Test\UnitTest;
use PHPUnit\Framework\TestCase;
use GlobIterator;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use RecursiveRegexIterator;
use RegexIterator;
/**
* Performs code static analysis to detect patterns that will change the values of static data and therefor could affect other tests while running them in a single process
*
* @runClassInSeparateProcess
* @preserveGlobalState disabled
*/
class detectStaticPollutionTest extends TestCase
{
protected function FindMatches($sFile, $sFileContents, $sRegexp)
{
$aRes = [];
foreach (explode("\n", $sFileContents) as $iLine => $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'],
];
}
}

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -20,6 +20,7 @@
>
<php>
<ini name="memory_limit" value="512M"/>
<ini name="error_reporting" value="E_ALL"/>
<ini name="display_errors" value="On"/>
<ini name="log_errors" value="On"/>

View File

@@ -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

View File

@@ -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);

View File

@@ -0,0 +1,64 @@
<?php
/**
* Usage: php run_class_by_class.php
*
* Execute the whole test suite (as declared in phpunit.xml.dist) one class at a time.
* This is to ensure that test class are still independant from each other, after a rework of ItopTestCase, for instance.
*/
const PHP_EXE = 'php';
const ITOP_ROOT = __DIR__.'/../../dev-itop';
const ITOP_PHPUNIT = ITOP_ROOT.'/tests/php-unit-tests';
const PHPUNIT_COMMAND = PHP_EXE.' '.ITOP_PHPUNIT.'/vendor/phpunit/phpunit/phpunit';
function ListTests($sUnitaryTestsDir = '')
{
$sConfigFile = ITOP_PHPUNIT."/phpunit.xml.dist";
$sCommand = PHPUNIT_COMMAND." --configuration $sConfigFile --list-tests $sUnitaryTestsDir";
exec($sCommand, $aOutput, $iResultCode);
//passthru($sCommand, $iResultCode);
if ($iResultCode != 0) { // or 1 in case of a failing test
echo "Failed executing command: $sCommand\n";
return [];
}
$aClasses = [];
foreach ($aOutput as $iLine => $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";
}

View File

@@ -7,8 +7,6 @@ use Combodo\iTop\Test\UnitTest\ItopTestCase;
/**
* @runTestsInSeparateProcesses
* @preserveGlobalState disabled
* @backupGlobals disabled
*/
class SessionTest extends ItopTestCase
{

View File

@@ -7,9 +7,6 @@ use FindStylesheetObject;
use ThemeHandler;
/**
* @runTestsInSeparateProcesses
* @preserveGlobalState disabled
* @backupGlobals disabled
* @covers ThemeHandler
*/
class ThemeHandlerTest extends ItopTestCase

View File

@@ -9,9 +9,6 @@ use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
/**
*
* @runTestsInSeparateProcesses
* @preserveGlobalState disabled
* @backupGlobals disabled
* Class NavigationMenuTest
*
* @package UI\Base\Layout

View File

@@ -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)

View File

@@ -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');

View File

@@ -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
{

View File

@@ -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");
}
}
/**

View File

@@ -10,9 +10,6 @@ use utils;
use Dict;
/**
* @runTestsInSeparateProcesses
* @preserveGlobalState disabled
* @backupGlobals disabled
* @covers \ActionEmail
*/
class ActionEmailTest extends ItopDataTestCase

View File

@@ -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;

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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()
{

View File

@@ -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) {

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -17,10 +17,6 @@ use DBSearch;
* <ul>
* <li>MakeGroupByQuery</li>
* </ul>
*
* @runTestsInSeparateProcesses
* @preserveGlobalState disabled
* @backupGlobals disabled
*/
class DBSearchCommitTest extends ItopDataTestCase
{

View File

@@ -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'",

View File

@@ -11,10 +11,6 @@ use DBSearch;
* Class DBSearchIntersectTest
*
* @package Combodo\iTop\Test\UnitTest\Core
*
* @runTestsInSeparateProcesses
* @preserveGlobalState disabled
* @backupGlobals disabled
*/
class DBSearchJoinTest extends ItopDataTestCase {

View File

@@ -43,10 +43,6 @@ use FunctionExpression;
* <ul>
* <li>MakeGroupByQuery</li>
* </ul>
*
* @runTestsInSeparateProcesses
* @preserveGlobalState disabled
* @backupGlobals disabled
*/
class DBSearchTest extends ItopDataTestCase
{

View File

@@ -10,10 +10,6 @@ use DBObjectSearch;
* Class DBSearchUpdateRealiasingMapTest
*
* @package Combodo\iTop\Test\UnitTest\Core
*
* @runTestsInSeparateProcesses
* @preserveGlobalState disabled
* @backupGlobals disabled
*/
class DBSearchUpdateRealiasingMapTest extends ItopDataTestCase
{

View File

@@ -7,11 +7,6 @@
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
/**
* @runTestsInSeparateProcesses
* @preserveGlobalState disabled
* @backupGlobals disabled
*/
class DBUnionSearchTest extends ItopDataTestCase
{

View File

@@ -13,11 +13,6 @@ use FunctionExpression;
use MetaModel;
use ScalarExpression;
/**
* @runTestsInSeparateProcesses
* @preserveGlobalState disabled
* @backupGlobals disabled
*/
class ExpressionEvaluateTest extends ItopDataTestCase
{
const USE_TRANSACTION = false;

View File

@@ -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;

View File

@@ -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

View File

@@ -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
{
/**

View File

@@ -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

View File

@@ -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)

View File

@@ -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)
{

View File

@@ -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

View File

@@ -16,11 +16,6 @@ use OQLException;
use OqlInterpreter;
use OQLParserException;
/**
* @runTestsInSeparateProcesses
* @preserveGlobalState disabled
* @backupGlobals disabled
*/
class OQLParserTest extends ItopDataTestCase
{
const USE_TRANSACTION = false;

View File

@@ -21,11 +21,6 @@ use QueryBuilderContext;
use SQLObjectQueryBuilder;
use utils;
/**
* @runTestsInSeparateProcesses
* @preserveGlobalState disabled
* @backupGlobals disabled
*/
class OQLTest extends ItopDataTestCase
{
const USE_TRANSACTION = false;

View File

@@ -18,10 +18,6 @@ use TagSetFieldData;
/**
* @group itopFaqLight
*
* @runTestsInSeparateProcesses
* @preserveGlobalState disabled
* @backupGlobals disabled
*/
class TagSetFieldDataTest extends ItopDataTestCase
{

View File

@@ -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\' (<b title="Trigger">TriggerOnObjectCreate</b>::-1 ()<br/>)', $e1->getMessage());
$this->assertStringStartsWith('Unknown class \'Toto\' (<b title="Trigger">TriggerOnObjectCreate</b>::-', $e1->getMessage());
$fullStackTraceAsString = $e1->getFullStackTraceAsString();
$this->assertStringContainsString("MetaModel::NewObject", $fullStackTraceAsString,"new enriched exception should contain root cause method: " . $fullStackTraceAsString);

View File

@@ -12,10 +12,6 @@ use Team;
/**
* Class UniquenessMessageTest
*
* @runTestsInSeparateProcesses
* @preserveGlobalState disabled
* @backupGlobals disabled
*
* @package Combodo\iTop\Test\UnitTest\Core
*/
class UniquenessMessageTest extends ItopDataTestCase

View File

@@ -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

View File

@@ -11,11 +11,6 @@ use Combodo\iTop\Test\UnitTest\ItopTestCase;
use MetaModel;
/**
* @runTestsInSeparateProcesses
* @preserveGlobalState disabled
* @backupGlobals disabled
*/
class ValueSetObjectsTest extends ItopTestCase
{

View File

@@ -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()
{

View File

@@ -33,8 +33,6 @@ define('UNIT_MAX_CACHE_FILES', 10);
/**
* @runTestsInSeparateProcesses
* @preserveGlobalState disabled
* @backupGlobals disabled
*/
class apcEmulationTest extends ItopTestCase
{

View File

@@ -32,8 +32,6 @@ use Dict;
/**
* @runTestsInSeparateProcesses
* @preserveGlobalState disabled
* @backupGlobals disabled
*/
class dictApcuTest extends ItopTestCase
{

View File

@@ -30,11 +30,8 @@ use Combodo\iTop\Test\UnitTest\ItopTestCase;
use Dict;
use Exception;
/**
* @runTestsInSeparateProcesses
* @preserveGlobalState disabled
* @backupGlobals disabled
* @runClassInSeparateProcess
*/
class dictTest extends ItopTestCase
{

View File

@@ -15,10 +15,6 @@ use ormCaseLog;
* Tests of the ormCaseLog class
*
* @covers \ormCaseLog
*
* @runTestsInSeparateProcesses
* @preserveGlobalState disabled
* @backupGlobals disabled
*/
class ormCaseLogTest extends ItopDataTestCase
{

View File

@@ -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
{

View File

@@ -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()

View File

@@ -12,10 +12,6 @@ use utils;
/**
* Tests of the ormStyle class
*
* @runTestsInSeparateProcesses
* @preserveGlobalState disabled
* @backupGlobals disabled
*/
class ormStyleTest extends ItopTestCase
{

View File

@@ -38,10 +38,6 @@ define('MAX_TAGS', 12);
/**
* @group itopFaqLight
* Tests of the ormTagSet class
*
* @runTestsInSeparateProcesses
* @preserveGlobalState disabled
* @backupGlobals disabled
*/
class ormTagSetTest extends ItopDataTestCase
{

View File

@@ -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', '');

View File

@@ -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){

View File

@@ -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()

View File

@@ -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

View File

@@ -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

View File

@@ -34,10 +34,6 @@ use Exception;
* @group itopVirtualizationMgmt
* @group itopConfigMgmt
* @group itopTickets
*
* @runTestsInSeparateProcesses
* @preserveGlobalState disabled
* @backupGlobals disabled
*/
class ItopTicketTest extends ItopDataTestCase
{

View File

@@ -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]);

View File

@@ -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);
}

View File

@@ -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 ];

View File

@@ -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

View File

@@ -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

View File

@@ -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));

View File

@@ -33,9 +33,6 @@ use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
/**
* @group itopRequestMgmt
* @runTestsInSeparateProcesses
* @preserveGlobalState disabled
* @backupGlobals disabled
*/
class CriterionParserTest extends ItopDataTestCase
{

View File

@@ -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

View File

@@ -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');

View File

@@ -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

View File

@@ -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
{

View File

@@ -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

View File

@@ -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;

View File

@@ -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
{

View File

@@ -10,8 +10,6 @@ use MetaModel;
/**
* @runTestsInSeparateProcesses
* @preserveGlobalState disabled
* @backupGlobals disabled
*/
class CliResetSessionTest extends ItopDataTestCase
{

View File

@@ -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;

View File

@@ -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 = <<<JSON
{
"operation": "list_operations"
}
JSON;
// Test regular JSON result
$sJSONResult = $this->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(<<<JSON
{
"operation": "core/get",
"class": "UserRequest",
"key": "SELECT UserRequest WHERE id=$iId",
"output_fields": "id, description"
}
JSON);
$sExpectedJsonOuput = <<<JSON
{
"code": 0,
"message": "Found: 1",
"objects": {
"UserRequest::$iId": {
"class": "UserRequest",
"code": 0,
"fields": {
"description": "<p>$description</p>",
"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(<<<JSON
{
"operation": "core/create",
"comment": "test",
"class": "UserRequest",
"output_fields": "id",
"fields":
{
"org_id": "SELECT Organization WHERE name = \"Demo\"",
"title": "Houston, got a problem",
"description": "$description"
}
}
JSON);
$this->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 = <<<JSON
{"objects":{"UserRequest::$iId":{"code":0,"message":"","class":"UserRequest","key":"$iId","fields":{"id":"$iId","description":"<p>$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("<p>$description</p>", $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(<<<JSON
{"operation": "core/update","comment": "test","class": "UserRequest","key":"$iId","output_fields": "description","fields":{"description": "$description"}}
JSON);
$sExpectedJsonOuput = <<<JSON
{"objects":{"UserRequest::$iId":{"code":0,"message":"updated","class":"UserRequest","key":"$iId","fields":{"description":"<p>$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 = <<<JSON
"objects":{"UserRequest::$iId"
JSON;
$this->assertStringContainsString($sExpectedJsonOuput, $this->DeleteTicketFromApi($iId));
$sExpectedJsonOuput = <<<JSON
{"objects":null,"code":0,"message":"Found: 0"}
JSON;
$this->assertJsonStringEqualsJsonString($sExpectedJsonOuput, $this->GetTicketViaRest($iId));
}
private function GetTicketViaRest($iId){
$sJsonGetContent = <<<JSON
{
"operation": "core/get",
"class": "UserRequest",
"key": "SELECT UserRequest WHERE id=$iId",
"output_fields": "id, description"
}
JSON;
return $this->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 = <<<JSON
{"operation": "core/update","comment": "test","class": "UserRequest","key":"$iId","output_fields": "description","fields":{"description": "$description"}}
JSON;
return $this->CallRestApi($sJsonUpdateContent);
}
private function CreateTicketViaApi($description){
$sJsonCreateContent = <<<JSON
{
"operation": "core/create",
"comment": "test",
"class": "UserRequest",
"output_fields": "id",
"fields":
{
"org_id": "SELECT Organization WHERE name = \"Demo\"",
"title": "Houston, got a problem",
"description": "$description"
}
}
JSON;
return $this->CallRestApi($sJsonCreateContent);
}
private function DeleteTicketFromApi($iId){
$sJson = <<<JSON
$sJSONOutput = $this->CallCoreRestApi_Internally(<<<JSON
{
"operation": "core/delete",
"comment": "Cleanup",
@@ -272,34 +239,67 @@ JSON;
"key":$iId,
"simulate": false
}
JSON);
$sExpectedJsonOuput = <<<JSON
"objects":{"UserRequest::$iId"
JSON;
return $this->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 = <<<JSON
{
"operation": "core/get",
"class": "CMDBChangeOp",
"key": "SELECT CMDBChangeOp WHERE objclass='UserRequest' AND objkey=$iId",
"output_fields": "userinfo"
}
JSON;
private function CallCoreRestApi_Internally(string $sJsonDataContent)
{
$oJsonData = json_decode($sJsonDataContent);
$sOperation = $oJsonData->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);
}
}