mirror of
https://github.com/Combodo/iTop.git
synced 2026-04-17 07:38:42 +02:00
Compare commits
49 Commits
3.1.0-desi
...
issue/6667
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cc4af0a027 | ||
|
|
3366bae0ab | ||
|
|
03b484c349 | ||
|
|
70081ecf33 | ||
|
|
575ba1cd7b | ||
|
|
d130959692 | ||
|
|
a8c689c6c0 | ||
|
|
1990ccb5d8 | ||
|
|
e107be56e4 | ||
|
|
0f8e87e001 | ||
|
|
d92d2b5e9e | ||
|
|
ebd0136773 | ||
|
|
f6653e1594 | ||
|
|
65bb76b9e3 | ||
|
|
f238593966 | ||
|
|
d951d3b872 | ||
|
|
ccceb870e3 | ||
|
|
ed6df77cbb | ||
|
|
1ad28312ec | ||
|
|
f002aa04cd | ||
|
|
b86d70623e | ||
|
|
fe3467309d | ||
|
|
851ab9c356 | ||
|
|
aef3c2e609 | ||
|
|
5212e15cc4 | ||
|
|
f04fc546b5 | ||
|
|
caf3076b12 | ||
|
|
c4c400d852 | ||
|
|
6cc4cc4fb6 | ||
|
|
d7495af207 | ||
|
|
13ad98b9b3 | ||
|
|
4be54fdd65 | ||
|
|
6d13397ba1 | ||
|
|
48e7e0309a | ||
|
|
2ce9b2afaf | ||
|
|
d64a91d4ce | ||
|
|
c0c8a13864 | ||
|
|
5ffa41bc16 | ||
|
|
d2eef06276 | ||
|
|
77b14c516e | ||
|
|
880a824f2f | ||
|
|
f7f1b5f399 | ||
|
|
85f66f5e0c | ||
|
|
a5c980113b | ||
|
|
18efbfa803 | ||
|
|
7aa478d6ff | ||
|
|
97700dbf15 | ||
|
|
c25c69d746 | ||
|
|
734a788340 |
@@ -66,6 +66,8 @@ gitGraph
|
||||
commit id: "2023-06-19" tag: "3.1.0-beta" type: REVERSE
|
||||
commit id: "2023-07-26" tag: "3.1.0-1" type: HIGHLIGHT
|
||||
branch support/3.1 order: 840
|
||||
checkout support/3.1
|
||||
commit id: "2023-08-09" tag: "3.1.0-2"
|
||||
```
|
||||
|
||||
To learn more, check the [iTop community versions history on the official wiki](https://www.itophub.io/wiki/page?id=latest:release:start).
|
||||
To learn more, check the [iTop community versions history on the official wiki](https://www.itophub.io/wiki/page?id=latest:release:start).
|
||||
|
||||
@@ -1397,13 +1397,23 @@ class utils
|
||||
return APPROOT . 'env-' . MetaModel::GetEnvironment() . '/';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string A path to the folder into which data can be written
|
||||
* @internal
|
||||
* @since N°6097 2.7.10 3.0.4 3.1.1
|
||||
*/
|
||||
public static function GetDataPath(): string
|
||||
{
|
||||
return APPROOT.'data/';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string A path to a folder into which any module can store cache data
|
||||
* The corresponding folder is created or cleaned upon code compilation
|
||||
*/
|
||||
public static function GetCachePath()
|
||||
{
|
||||
return APPROOT.'data/cache-'.MetaModel::GetEnvironment().'/';
|
||||
return static::GetDataPath().'cache-'.MetaModel::GetEnvironment().'/';
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -431,6 +431,7 @@ class CMDBSource
|
||||
{
|
||||
self::$m_sDBName = '';
|
||||
}
|
||||
self::_TablesInfoCacheReset(); // reset the table info cache!
|
||||
}
|
||||
|
||||
public static function CreateTable($sQuery)
|
||||
@@ -627,18 +628,24 @@ class CMDBSource
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Exception $e
|
||||
* @param Exception $e
|
||||
* @param bool $bForQuery to get the proper DB connection
|
||||
* @param bool $bCheckMysqliErrno if false won't try to check for mysqli::errno value
|
||||
*
|
||||
* @since 2.7.1
|
||||
* @since 3.0.0 N°4325 add new optional parameter to use the correct DB connection
|
||||
* @since 3.0.4 3.1.1 3.2.0 N°6643 new bCheckMysqliErrno parameter as a workaround for mysqli::errno cannot be mocked
|
||||
*/
|
||||
private static function LogDeadLock(Exception $e, $bForQuery = false)
|
||||
private static function LogDeadLock(Exception $e, $bForQuery = false, $bCheckMysqliErrno = true)
|
||||
{
|
||||
// checks MySQL error code
|
||||
$iMySqlErrorNo = DbConnectionWrapper::GetDbConnection($bForQuery)->errno;
|
||||
if (!in_array($iMySqlErrorNo, array(self::MYSQL_ERRNO_WAIT_TIMEOUT, self::MYSQL_ERRNO_DEADLOCK))) {
|
||||
return;
|
||||
if ($bCheckMysqliErrno) {
|
||||
$iMySqlErrorNo = DbConnectionWrapper::GetDbConnection($bForQuery)->errno;
|
||||
if (!in_array($iMySqlErrorNo, array(self::MYSQL_ERRNO_WAIT_TIMEOUT, self::MYSQL_ERRNO_DEADLOCK))) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
$iMySqlErrorNo = "N/A";
|
||||
}
|
||||
|
||||
// Get error info
|
||||
@@ -665,7 +672,10 @@ class CMDBSource
|
||||
);
|
||||
DeadLockLog::Info($sMessage, $iMySqlErrorNo, $aLogContext);
|
||||
|
||||
IssueLog::Error($sMessage, LogChannels::DEADLOCK, $e->getMessage());
|
||||
IssueLog::Error($sMessage, LogChannels::DEADLOCK, [
|
||||
'exception.class' => get_class($e),
|
||||
'exception.message' => $e->getMessage(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3574,7 +3574,8 @@ abstract class DBObject implements iDisplay
|
||||
$oKPI->ComputeStatsForExtension($this, 'AfterUpdate');
|
||||
|
||||
// - TriggerOnObjectUpdate
|
||||
$aParams = array('class_list' => MetaModel::EnumParentClasses(get_class($this), ENUM_PARENT_CLASSES_ALL));
|
||||
$aClassList = MetaModel::EnumParentClasses(get_class($this), ENUM_PARENT_CLASSES_ALL);
|
||||
$aParams = array('class_list' => $aClassList);
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL('SELECT TriggerOnObjectUpdate AS t WHERE t.target_class IN (:class_list)'),
|
||||
array(), $aParams);
|
||||
while ($oTrigger = $oSet->Fetch()) {
|
||||
@@ -3588,6 +3589,44 @@ abstract class DBObject implements iDisplay
|
||||
}
|
||||
}
|
||||
|
||||
$sClass = get_class($this);
|
||||
if (MetaModel::HasLifecycle($sClass))
|
||||
{
|
||||
$sStateAttCode = MetaModel::GetStateAttributeCode($sClass);
|
||||
if (isset($this->m_aPreviousValuesForUpdatedAttributes[$sStateAttCode])) {
|
||||
$sPreviousState = $this->m_aPreviousValuesForUpdatedAttributes[$sStateAttCode];
|
||||
// Change state triggers...
|
||||
$aParams = array(
|
||||
'class_list' => MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL),
|
||||
'previous_state' => $sPreviousState,
|
||||
'new_state' => $this->Get($sStateAttCode),
|
||||
);
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL('SELECT TriggerOnStateLeave AS t WHERE t.target_class IN (:class_list) AND t.state=:previous_state'), array(), $aParams);
|
||||
while ($oTrigger = $oSet->Fetch()) {
|
||||
/** @var \TriggerOnStateLeave $oTrigger */
|
||||
try {
|
||||
$oTrigger->DoActivate($this->ToArgs('this'));
|
||||
}
|
||||
catch (Exception $e) {
|
||||
$oTrigger->LogException($e, $this);
|
||||
utils::EnrichRaisedException($oTrigger, $e);
|
||||
}
|
||||
}
|
||||
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL('SELECT TriggerOnStateEnter AS t WHERE t.target_class IN (:class_list) AND t.state=:new_state'), array(), $aParams);
|
||||
while ($oTrigger = $oSet->Fetch()) {
|
||||
/** @var \TriggerOnStateEnter $oTrigger */
|
||||
try {
|
||||
$oTrigger->DoActivate($this->ToArgs('this'));
|
||||
}
|
||||
catch (Exception $e) {
|
||||
$oTrigger->LogException($e, $this);
|
||||
utils::EnrichRaisedException($oTrigger, $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Activate any existing trigger
|
||||
// - TriggerOnObjectMention
|
||||
// Forgotten by the fix of N°3245
|
||||
@@ -4283,36 +4322,6 @@ abstract class DBObject implements iDisplay
|
||||
$this->DBWrite();
|
||||
}
|
||||
|
||||
// Change state triggers...
|
||||
$aParams = array(
|
||||
'class_list' => MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL),
|
||||
'previous_state' => $sPreviousState,
|
||||
'new_state' => $sNewState,
|
||||
);
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnStateLeave AS t WHERE t.target_class IN (:class_list) AND t.state=:previous_state"), array(), $aParams);
|
||||
while ($oTrigger = $oSet->Fetch()) {
|
||||
/** @var \TriggerOnStateLeave $oTrigger */
|
||||
try {
|
||||
$oTrigger->DoActivate($this->ToArgs('this'));
|
||||
}
|
||||
catch (Exception $e) {
|
||||
$oTrigger->LogException($e, $this);
|
||||
utils::EnrichRaisedException($oTrigger, $e);
|
||||
}
|
||||
}
|
||||
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnStateEnter AS t WHERE t.target_class IN (:class_list) AND t.state=:new_state"), array(), $aParams);
|
||||
while ($oTrigger = $oSet->Fetch()) {
|
||||
/** @var \TriggerOnStateEnter $oTrigger */
|
||||
try {
|
||||
$oTrigger->DoActivate($this->ToArgs('this'));
|
||||
}
|
||||
catch (Exception $e) {
|
||||
$oTrigger->LogException($e, $this);
|
||||
utils::EnrichRaisedException($oTrigger, $e);
|
||||
}
|
||||
}
|
||||
|
||||
$this->FireEvent(EVENT_DB_AFTER_APPLY_STIMULUS, $aEventData);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
@@ -6810,25 +6830,21 @@ abstract class MetaModel
|
||||
* $bMustBeFound=false)
|
||||
* @throws CoreException if no result found and $bMustBeFound=true
|
||||
* @throws ArchivedObjectException if archive mode disabled and result is archived and $bMustBeFound=true
|
||||
* @throws \Exception
|
||||
*
|
||||
*/
|
||||
public static function GetObject($sClass, $iKey, $bMustBeFound = true, $bAllowAllData = false, $aModifierProperties = null)
|
||||
{
|
||||
$oObject = self::GetObjectWithArchive($sClass, $iKey, $bMustBeFound, $bAllowAllData, $aModifierProperties);
|
||||
|
||||
if (empty($oObject))
|
||||
{
|
||||
if (empty($oObject)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!utils::IsArchiveMode() && $oObject->IsArchived())
|
||||
{
|
||||
if (!utils::IsArchiveMode() && $oObject->IsArchived()) {
|
||||
if ($bMustBeFound) {
|
||||
throw new ArchivedObjectException("The object $sClass::$iKey is archived");
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return $oObject;
|
||||
@@ -7611,14 +7627,12 @@ abstract class MetaModel
|
||||
// Build the list of available extensions
|
||||
//
|
||||
$aInterfaces = [
|
||||
'iApplicationUIExtension',
|
||||
'iPreferencesExtension',
|
||||
'iApplicationObjectExtension',
|
||||
'iLoginFSMExtension',
|
||||
'iLoginUIExtension',
|
||||
'iLogoutExtension',
|
||||
'iQueryModifier',
|
||||
'iOnClassInitialization',
|
||||
'iLoginUIExtension',
|
||||
'iPreferencesExtension',
|
||||
'iApplicationUIExtension',
|
||||
'iApplicationObjectExtension',
|
||||
'iPopupMenuExtension',
|
||||
'iPageUIExtension',
|
||||
'iPageUIBlockExtension',
|
||||
@@ -7632,10 +7646,12 @@ abstract class MetaModel
|
||||
'iBackofficeDictEntriesExtension',
|
||||
'iBackofficeDictEntriesPrefixesExtension',
|
||||
'iPortalUIExtension',
|
||||
'ModuleHandlerApiInterface',
|
||||
'iNewsroomProvider',
|
||||
'iQueryModifier',
|
||||
'iOnClassInitialization',
|
||||
'iModuleExtension',
|
||||
'iKPILoggerExtension',
|
||||
'ModuleHandlerApiInterface',
|
||||
'iNewsroomProvider',
|
||||
];
|
||||
foreach ($aInterfaces as $sInterface) {
|
||||
self::$m_aExtensionClassNames[$sInterface] = array();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -892,7 +892,10 @@ class iTopDesignFormat
|
||||
$oNodeList = $oXPath->query("/itop_design/classes//class/fields/field/values/value");
|
||||
foreach ($oNodeList as $oNode) {
|
||||
$sCode = $oNode->textContent;
|
||||
$oNode->textContent = '';
|
||||
// N°6562 textContent is readonly, see https://www.php.net/manual/en/class.domnode.php#95545
|
||||
// $oNode->textContent = '';
|
||||
// N°6562 to update text node content we must use the node methods !
|
||||
$oNode->removeChild($oNode->firstChild);
|
||||
$oCodeNode = $oNode->ownerDocument->createElement("code", $sCode);
|
||||
$oNode->appendChild($oCodeNode);
|
||||
}
|
||||
@@ -982,7 +985,14 @@ class iTopDesignFormat
|
||||
if ($oStyleNode) {
|
||||
$this->DeleteNode($oStyleNode);
|
||||
}
|
||||
$oNode->textContent = $sCode;
|
||||
|
||||
// N°6562 textContent is readonly, see https://www.php.net/manual/en/class.domnode.php#95545
|
||||
// $oNode->textContent = $sCode;
|
||||
// N°6562 to update text node content we must use the node methods !
|
||||
// we are using DOMDocument::createTextNode instead of new DOMText because elements created using the constructor are read only
|
||||
// see https://www.php.net/manual/en/domelement.construct.php
|
||||
$oTextContentNode = $this->oDocument->createTextNode($sCode);
|
||||
$oNode->appendChild($oTextContentNode);
|
||||
}
|
||||
}
|
||||
// - Style
|
||||
|
||||
@@ -320,12 +320,19 @@ EOF
|
||||
if ($this->oField->GetCurrentValue() !== null && $this->oField->GetCurrentValue() !== 0 && $this->oField->GetCurrentValue() !== '')
|
||||
{
|
||||
// Note : AllowAllData set to true here instead of checking scope's flag because we are displaying a value that has been set and validated
|
||||
$oFieldValue = MetaModel::GetObject($sFieldValueClass, $this->oField->GetCurrentValue(), true, true);
|
||||
$oFieldValue = MetaModel::GetObjectWithArchive($sFieldValueClass, $this->oField->GetCurrentValue(), true, true);
|
||||
$sFieldHtmlValue = $oFieldValue->GetName();
|
||||
$sFieldUrl = ApplicationContext::MakeObjectUrl($sFieldValueClass, $this->oField->GetCurrentValue());
|
||||
if(!empty($sFieldUrl))
|
||||
if($oFieldValue->IsArchived())
|
||||
{
|
||||
$sFieldHtmlValue = '<a href="'.$sFieldUrl.'" data-toggle="itop-portal-modal">'.$sFieldHtmlValue.'</a>';
|
||||
$sFieldHtmlValue = '<span class="text_decoration"><span class="fas fa-archive"></span></span>' . $sFieldHtmlValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sFieldUrl = ApplicationContext::MakeObjectUrl($sFieldValueClass, $this->oField->GetCurrentValue());
|
||||
if (!empty($sFieldUrl))
|
||||
{
|
||||
$sFieldHtmlValue = '<a href="' . $sFieldUrl . '" data-toggle="itop-portal-modal">' . $sFieldHtmlValue . '</a>';
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -138,12 +138,24 @@ class Router
|
||||
{
|
||||
$aRoutes = [];
|
||||
$bUseCache = false === utils::IsDevelopmentEnvironment();
|
||||
$bMustWriteCache = false;
|
||||
$sCacheFilePath = $this->GetCacheFileAbsPath();
|
||||
|
||||
// Try to read from cache
|
||||
if ($bUseCache) {
|
||||
if (is_file($sCacheFilePath)) {
|
||||
$aRoutes = include $sCacheFilePath;
|
||||
$aCachedRoutes = include $sCacheFilePath;
|
||||
|
||||
// N°6618 - Protection against corrupted cache returning `1` instead of an array of routes
|
||||
if (is_array($aCachedRoutes)) {
|
||||
$aRoutes = $aCachedRoutes;
|
||||
} else {
|
||||
// Invalid cache force re-generation
|
||||
// Note that even if it is re-generated corrupted again, this protection should prevent crashes
|
||||
$bMustWriteCache = true;
|
||||
}
|
||||
} else {
|
||||
$bMustWriteCache = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,11 +192,11 @@ class Router
|
||||
}
|
||||
}
|
||||
|
||||
// Save to cache
|
||||
if ($bUseCache) {
|
||||
// Save to cache if it doesn't exist already
|
||||
if ($bMustWriteCache) {
|
||||
$sCacheContent = "<?php\n\nreturn ".var_export($aRoutes, true).";";
|
||||
SetupUtils::builddir(dirname($sCacheFilePath));
|
||||
file_put_contents($sCacheFilePath, $sCacheContent);
|
||||
file_put_contents($sCacheFilePath, $sCacheContent, LOCK_EX);
|
||||
}
|
||||
|
||||
return $aRoutes;
|
||||
|
||||
@@ -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)
|
||||
@@ -2,5 +2,12 @@
|
||||
"require-dev": {
|
||||
"phpunit/phpunit" : "^9",
|
||||
"sempro/phpunit-pretty-print": "^1.4"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Combodo\\iTop\\Test\\UnitTest\\": "src/BaseTestCase/",
|
||||
"Combodo\\iTop\\Test\\UnitTest\\Hook\\": "src/Hook/",
|
||||
"Combodo\\iTop\\Test\\UnitTest\\Service\\": "src/Service/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
1
tests/php-unit-tests/experiments/README.md
Normal file
1
tests/php-unit-tests/experiments/README.md
Normal file
@@ -0,0 +1 @@
|
||||
This directory aims at providing experimental proof of the mechanics of PHPUnit
|
||||
@@ -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],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2023 Combodo SARL
|
||||
* This file is part of iTop.
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Integration;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
use Dict;
|
||||
use const APPROOT;
|
||||
|
||||
/**
|
||||
* As {@see DictionariesConsistencyTest}, we are testing dict files, but the ones that are compiled, so we cannot be in the beforeSetup group !
|
||||
*/
|
||||
class CompiledDictionariesConsistencyTest extends ItopTestCase
|
||||
{
|
||||
/**
|
||||
* make sure N°5305 dictionary changes (CSV import ergonomy) are still here and UI remains unbroken for any lang
|
||||
*
|
||||
* One of the things checked is the number of parameters in the dict value. This is for now crashing the app (N°5491)
|
||||
* and we have multiple inconsistencies in our existing dict files... So it is complicated to have a generic test for all files !
|
||||
* At least we are protecting those new entries...
|
||||
*/
|
||||
public function testImportCsvMessageStillOk()
|
||||
{
|
||||
$aFailedLabels = [];
|
||||
$aLabelsToTest = [
|
||||
'UI:CSVReport-Value-SetIssue' => [],
|
||||
'UI:CSVReport-Value-ChangeIssue' => ['arg1'],
|
||||
'UI:CSVReport-Value-NoMatch' => ['arg1'],
|
||||
'UI:CSVReport-Value-NoMatch-PossibleValues' => ['arg1', 'arg2'],
|
||||
'UI:CSVReport-Value-NoMatch-NoObject' => ['arg1'],
|
||||
'UI:CSVReport-Value-NoMatch-NoObject-ForCurrentUser' => ['arg1'],
|
||||
'UI:CSVReport-Value-NoMatch-SomeObjectNotVisibleForCurrentUser' => ['arg1'],
|
||||
];
|
||||
|
||||
$sCompiledLanguagesFilePath = APPROOT . 'env-' . \utils::GetCurrentEnvironment() . '/dictionaries/languages.php';
|
||||
$this->assertFileExists($sCompiledLanguagesFilePath, 'We must have an existing compiled language.php file in the current env !');
|
||||
require_once($sCompiledLanguagesFilePath);
|
||||
$this->assertNotEmpty(Dict::GetLanguages(), 'the languages.php file exists but didn\'t load any language');
|
||||
|
||||
foreach (glob(APPROOT . 'env-' . \utils::GetCurrentEnvironment() . '/dictionaries/*.dict.php') as $sDictFile) {
|
||||
if (preg_match('/.*\\/(.*).dict.php/', $sDictFile, $aMatches)) {
|
||||
$sLangCode = $aMatches[1];
|
||||
$sLanguageCode = strtoupper(str_replace('-', ' ', $sLangCode));
|
||||
Dict::SetUserLanguage($sLanguageCode);
|
||||
|
||||
foreach ($aLabelsToTest as $sLabelKey => $aLabelArgs) {
|
||||
echo "Testing $sDictFile, label $sLabelKey with " . \var_export($aLabelArgs, true) . "\n";
|
||||
try {
|
||||
$sLabelValue = Dict::Format($sLabelKey, ...$aLabelArgs);
|
||||
//$this->debug($sLabelValue);
|
||||
} catch (\ValueError $e) {
|
||||
$aFailedLabels[] = $sLabelKey;
|
||||
|
||||
$this->debug([
|
||||
'exception' => $e->getMessage(),
|
||||
'trace' => $e->getTraceAsString(),
|
||||
'label_name' => $sLabelKey,
|
||||
'label_args' => $aLabelArgs,
|
||||
]);
|
||||
}
|
||||
}
|
||||
$this->assertEquals([], $aFailedLabels, "$sDictFile : test fail for lang $sLangCode and labels (" . implode(", ", $aFailedLabels) . ')');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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'],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,9 +16,9 @@
|
||||
namespace Combodo\iTop\Test\UnitTest\Integration;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
use Dict;
|
||||
|
||||
/**
|
||||
* For tests on compiled dict files, see {@see CompiledDictionariesConsistencyTest}
|
||||
* @group beforeSetup
|
||||
*/
|
||||
class DictionariesConsistencyTest extends ItopTestCase
|
||||
@@ -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) {
|
||||
@@ -152,67 +154,4 @@ class DictionariesConsistencyTest extends ItopTestCase
|
||||
$sMessage = "File `{$sDictFile}` syntax didn't matched expectations\nparsing results=".var_export($output, true);
|
||||
self::assertEquals($bIsSyntaxValid, $bDictFileSyntaxOk, $sMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider ImportCsvMessageStillOkProvider
|
||||
* make sure N°5305 dictionary changes are still here and UI remains unbroken for any lang
|
||||
*/
|
||||
public function testImportCsvMessageStillOk($sLangCode, $sDictFile)
|
||||
{
|
||||
$aFailedLabels = [];
|
||||
$aLabelsToTest = [
|
||||
'UI:CSVReport-Value-SetIssue' => [],
|
||||
'UI:CSVReport-Value-ChangeIssue' => [ 'arg1' ],
|
||||
'UI:CSVReport-Value-NoMatch' => [ 'arg1' ],
|
||||
'UI:CSVReport-Value-NoMatch-PossibleValues' => [ 'arg1', 'arg2' ],
|
||||
'UI:CSVReport-Value-NoMatch-NoObject' => [ 'arg1' ],
|
||||
'UI:CSVReport-Value-NoMatch-NoObject-ForCurrentUser' => [ 'arg1' ],
|
||||
'UI:CSVReport-Value-NoMatch-SomeObjectNotVisibleForCurrentUser' => [ 'arg1' ],
|
||||
];
|
||||
|
||||
$sLanguageCode = strtoupper(str_replace('-', ' ', $sLangCode));
|
||||
require_once(APPROOT.'env-'.\utils::GetCurrentEnvironment().'/dictionaries/languages.php');
|
||||
Dict::SetUserLanguage($sLanguageCode);
|
||||
foreach ($aLabelsToTest as $sLabelKey => $aLabelArgs){
|
||||
try{
|
||||
$sLabelValue = Dict::Format($sLabelKey, ...$aLabelArgs);
|
||||
//$this->debug($sLabelValue);
|
||||
} catch (\ValueError $e){
|
||||
$aFailedLabels[] = $sLabelKey;
|
||||
|
||||
$this->debug([
|
||||
'exception' => $e->getMessage(),
|
||||
'trace' => $e->getTraceAsString(),
|
||||
'label_name' => $sLabelKey,
|
||||
'label_args' =>$aLabelArgs,
|
||||
]);
|
||||
}
|
||||
}
|
||||
$this->assertEquals([], $aFailedLabels, "test fail for lang $sLangCode and labels (" . implode(", ", $aFailedLabels) . ')');
|
||||
}
|
||||
|
||||
public function ImportCsvMessageStillOkProvider(){
|
||||
return $this->GetDictFiles();
|
||||
}
|
||||
|
||||
/**
|
||||
* return a map linked to *.dict.php files that are generated after setup
|
||||
* each entry key is lang code (example 'en')
|
||||
* each value is an array with lang code (again) and dict file path
|
||||
* @return array
|
||||
*/
|
||||
private function GetDictFiles() : array {
|
||||
$aDictFiles = [];
|
||||
|
||||
foreach (glob(APPROOT.'env-'.\utils::GetCurrentEnvironment().'/dictionaries/*.dict.php') as $sDictFile){
|
||||
if (preg_match('/.*\\/(.*).dict.php/', $sDictFile, $aMatches)){
|
||||
$sLangCode = $aMatches[1];
|
||||
$aDictFiles[$sLangCode] = [
|
||||
'lang' => $sLangCode,
|
||||
'file' => $sDictFile
|
||||
];
|
||||
}
|
||||
}
|
||||
return $aDictFiles;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ use utils;
|
||||
|
||||
/**
|
||||
* @package Combodo\iTop\Test\UnitTest\Setup
|
||||
* @group beforeSetup
|
||||
*/
|
||||
class iTopModulesPhpVersionIntegrationTest extends ItopTestCase {
|
||||
/**
|
||||
|
||||
@@ -24,6 +24,7 @@ use iTopDesignFormat;
|
||||
* @covers iTopDesignFormat
|
||||
*
|
||||
* @package Combodo\iTop\Test\UnitTest\Setup
|
||||
* @group beforeSetup
|
||||
*/
|
||||
class iTopModulesXmlVersionIntegrationTest extends ItopTestCase
|
||||
{
|
||||
@@ -71,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) {
|
||||
|
||||
@@ -20,6 +20,7 @@ use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
|
||||
/**
|
||||
* @package Combodo\iTop\Test\UnitTest\Setup
|
||||
* @group beforeSetup
|
||||
*/
|
||||
class iTopXmlVersionIntegrationTest extends ItopTestCase
|
||||
{
|
||||
|
||||
@@ -19,7 +19,12 @@
|
||||
printerClass="\Sempro\PHPUnitPrettyPrinter\PrettyPrinterForPhpUnit9"
|
||||
>
|
||||
|
||||
<extensions>
|
||||
<extension class="Combodo\iTop\Test\UnitTest\Hook\TestsRunStartHook" />
|
||||
</extensions>
|
||||
|
||||
<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"/>
|
||||
|
||||
@@ -19,6 +19,10 @@
|
||||
printerClass="\Sempro\PHPUnitPrettyPrinter\PrettyPrinterForPhpUnit9"
|
||||
>
|
||||
|
||||
<extensions>
|
||||
<extension class="Combodo\iTop\Test\UnitTest\Hook\TestsRunStartHook" />
|
||||
</extensions>
|
||||
|
||||
<php>
|
||||
<ini name="error_reporting" value="E_ALL"/>
|
||||
<ini name="display_errors" value="On"/>
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2023 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest;
|
||||
|
||||
use CMDBSource;
|
||||
use Combodo\iTop\Test\UnitTest\Hook\TestsRunStartHook;
|
||||
use Combodo\iTop\Test\UnitTest\Service\UnitTestRunTimeEnvironment;
|
||||
use Config;
|
||||
use Exception;
|
||||
use IssueLog;
|
||||
use MetaModel;
|
||||
use SetupUtils;
|
||||
use utils;
|
||||
|
||||
|
||||
/**
|
||||
* Class ItopCustomDatamodelTestCase
|
||||
*
|
||||
* Helper class to extend for tests needing a custom DataModel (eg. classes, attributes, etc conditions not available in the standard DM)
|
||||
* Usage:
|
||||
* - Create a test case class extending this one
|
||||
* - Override the {@see ItopCustomDatamodelTestCase::GetDatamodelDeltaAbsPath()} method to define where you XML delta is
|
||||
* - Implement your test case methods as usual
|
||||
*
|
||||
* @since N°6097 2.7.9 3.0.4 3.1.0
|
||||
*/
|
||||
abstract class ItopCustomDatamodelTestCase extends ItopDataTestCase
|
||||
{
|
||||
/**
|
||||
* @var bool[]
|
||||
*/
|
||||
protected static $aReadyCustomEnvironments = [];
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @since N°6097 Workaround to make the "runClassInSeparateProcess" directive work
|
||||
*/
|
||||
public function __construct($name = null, array $data = [], $dataName = '')
|
||||
{
|
||||
parent::__construct($name, $data, $dataName);
|
||||
|
||||
// Ensure that a test class derived from this one runs in a dedicated process as it changes the MetaModel / environment on the fly and
|
||||
// for now we have no way of switching environments properly in memory and it will result in other (regular) test classes to fail as they won't be on the expected environment.
|
||||
//
|
||||
// If we don't do this, we would have to add the `@runTestsInSeparateProcesses` on *each* test classes which we want to avoid for obvious possible mistakes.
|
||||
// Note that the `@runClassInSeparateProcess` don't work in PHPUnit yet.
|
||||
$this->setRunClassInSeparateProcess(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string Abs path to the XML delta to use for the tests of that class
|
||||
*/
|
||||
abstract public function GetDatamodelDeltaAbsPath(): string;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function LoadRequiredItopFiles(): void
|
||||
{
|
||||
parent::LoadRequiredItopFiles();
|
||||
|
||||
$this->RequireOnceItopFile('setup/setuputils.class.inc.php');
|
||||
$this->RequireOnceItopFile('setup/runtimeenv.class.inc.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string Environment used as a base (conf. file, modules, DB, ...) to prepare the test environment
|
||||
*/
|
||||
protected function GetSourceEnvironment(): string
|
||||
{
|
||||
return 'production';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @warning This should ONLY be overloaded if your test case XML deltas are NOT compatible with the others, as it will create / compile another environment, increasing the global testing time.
|
||||
*/
|
||||
public function GetTestEnvironment(): string
|
||||
{
|
||||
return 'php-unit-tests';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string Absolute path to the {@see \Combodo\iTop\Test\UnitTest\ItopCustomDatamodelTestCase::GetTestEnvironment()} folder
|
||||
*/
|
||||
final private function GetTestEnvironmentFolderAbsPath(): string
|
||||
{
|
||||
return APPROOT.'env-'.$this->GetTestEnvironment().'/';
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark {@see \Combodo\iTop\Test\UnitTest\ItopDataTestCase::GetTestEnvironment()} as ready (compiled)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
final private function MarkEnvironmentReady(): void
|
||||
{
|
||||
if (false === $this->IsEnvironmentReady()) {
|
||||
touch(static::GetTestEnvironmentFolderAbsPath());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool True if the {@see \Combodo\iTop\Test\UnitTest\ItopDataTestCase::GetTestEnvironment()} is ready (compiled, but not started)
|
||||
*
|
||||
* @details Having the environment ready means that it has been compiled for this global tests run, not that it is a relic from a previous global tests run
|
||||
*/
|
||||
final private function IsEnvironmentReady(): bool
|
||||
{
|
||||
// As these test cases run in separate processes, the best way we found to let know a process if its environment was already prepared for **this run** was to compare the modification times of:
|
||||
// - its own env-<ENV> folder
|
||||
// - a file generated at the beginning of the global test run {@see \Combodo\iTop\Test\UnitTest\Hook\TestsRunStartHook}
|
||||
$sRunStartedFilePath = TestsRunStartHook::GetRunStartedFileAbsPath();
|
||||
$sEnvFolderPath = static::GetTestEnvironmentFolderAbsPath();
|
||||
|
||||
clearstatcache();
|
||||
if (false === file_exists($sRunStartedFilePath) || false === file_exists($sEnvFolderPath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$iRunStartedFileModificationTime = filemtime($sRunStartedFilePath);
|
||||
$iEnvFolderModificationTime = filemtime($sEnvFolderPath);
|
||||
|
||||
return $iEnvFolderModificationTime >= $iRunStartedFileModificationTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function PrepareEnvironment(): void
|
||||
{
|
||||
$sSourceEnv = $this->GetSourceEnvironment();
|
||||
$sTestEnv = $this->GetTestEnvironment();
|
||||
|
||||
// Check if test env. is already set and only prepare it if it's not up-to-date
|
||||
//
|
||||
// Note: To improve performances, we compile all XML deltas from test cases derived from this class and make a single environment where everything will be ran at once.
|
||||
// This requires XML deltas to be compatible, but it is a known and accepted trade-off. See PR #457
|
||||
if (false === $this->IsEnvironmentReady()) {
|
||||
//----------------------------------------------------
|
||||
// Clear any previous "$sTestEnv" environment
|
||||
//----------------------------------------------------
|
||||
|
||||
// - Configuration file
|
||||
$sConfFile = utils::GetConfigFilePath($sTestEnv);
|
||||
$sConfFolder = dirname($sConfFile);
|
||||
if (is_file($sConfFile)) {
|
||||
chmod($sConfFile, 0777);
|
||||
SetupUtils::tidydir($sConfFolder);
|
||||
}
|
||||
|
||||
// - Datamodel delta files
|
||||
// - Cache folder
|
||||
// - Compiled folder
|
||||
// We don't need to clean them as they are already by the compilation
|
||||
|
||||
// - Drop database
|
||||
// We don't do that now, it will be done before re-creating the DB, once the metamodel is started
|
||||
|
||||
//----------------------------------------------------
|
||||
// Prepare "$sTestEnv" environment
|
||||
//----------------------------------------------------
|
||||
|
||||
// All the following is greatly inspired by the toolkit's sandbox script
|
||||
// - Prepare config file
|
||||
$oSourceConf = new Config(utils::GetConfigFilePath($sSourceEnv));
|
||||
if ($oSourceConf->Get('source_dir') === '') {
|
||||
throw new Exception('Missing entry source_dir from the config file');
|
||||
}
|
||||
|
||||
$oTestConfig = clone($oSourceConf);
|
||||
$oTestConfig->ChangeModulesPath($sSourceEnv, $sTestEnv);
|
||||
// - Switch DB name to a dedicated one so we don't mess with the original one
|
||||
$sTestEnvSanitizedForDBName = preg_replace('/[^\d\w]/', '', $sTestEnv);
|
||||
$oTestConfig->Set('db_name', $oTestConfig->Get('db_name').'_'.$sTestEnvSanitizedForDBName);
|
||||
|
||||
// - Compile env. based on the existing 'production' env.
|
||||
$oEnvironment = new UnitTestRunTimeEnvironment($sTestEnv);
|
||||
$oEnvironment->WriteConfigFileSafe($oTestConfig);
|
||||
$oEnvironment->CompileFrom($sSourceEnv, false);
|
||||
|
||||
// - Force re-creating a fresh DB
|
||||
CMDBSource::InitFromConfig($oTestConfig);
|
||||
if (CMDBSource::IsDB($oTestConfig->Get('db_name'))) {
|
||||
CMDBSource::DropDB();
|
||||
}
|
||||
CMDBSource::CreateDB($oTestConfig->Get('db_name'));
|
||||
MetaModel::Startup($sConfFile, false /* $bModelOnly */, true /* $bAllowCache */, false /* $bTraceSourceFiles */, $sTestEnv);
|
||||
|
||||
$this->MarkEnvironmentReady();
|
||||
$this->debug('Preparation of custom environment "'.$sTestEnv.'" done.');
|
||||
}
|
||||
|
||||
parent::PrepareEnvironment();
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,8 @@
|
||||
<?php
|
||||
// Copyright (c) 2010-2023 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
//
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2023 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest;
|
||||
|
||||
@@ -31,6 +18,7 @@ use CMDBObject;
|
||||
use CMDBSource;
|
||||
use Combodo\iTop\Service\Events\EventData;
|
||||
use Combodo\iTop\Service\Events\EventService;
|
||||
use Config;
|
||||
use Contact;
|
||||
use DBObject;
|
||||
use DBObjectSet;
|
||||
@@ -46,11 +34,13 @@ use MetaModel;
|
||||
use Person;
|
||||
use PluginManager;
|
||||
use Server;
|
||||
use SetupUtils;
|
||||
use TagSetFieldData;
|
||||
use Ticket;
|
||||
use URP_UserProfile;
|
||||
use User;
|
||||
use UserRequest;
|
||||
use utils;
|
||||
use VirtualHost;
|
||||
use VirtualMachine;
|
||||
use XMLDataLoader;
|
||||
@@ -61,41 +51,53 @@ define('TAG_CLASS', 'FAQ');
|
||||
define('TAG_ATTCODE', 'domains');
|
||||
|
||||
/**
|
||||
* Class ItopDataTestCase
|
||||
*
|
||||
* 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)
|
||||
*/
|
||||
class ItopDataTestCase extends ItopTestCase
|
||||
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
|
||||
*/
|
||||
const DEFAULT_TEST_ENVIRONMENT = 'production';
|
||||
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
|
||||
*/
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->RequireOnceItopFile('application/utils.inc.php');
|
||||
|
||||
$sEnv = 'production';
|
||||
$sConfigFile = APPCONF.$sEnv.'/'.ITOP_CONFIG_FILE;
|
||||
MetaModel::Startup($sConfigFile, false /* $bModelOnly */, true /* $bAllowCache */, false /* $bTraceSourceFiles */, $sEnv);
|
||||
$this->PrepareEnvironment();
|
||||
|
||||
if (static::USE_TRANSACTION)
|
||||
{
|
||||
@@ -105,8 +107,6 @@ class ItopDataTestCase extends ItopTestCase
|
||||
{
|
||||
$this->CreateTestOrganization();
|
||||
}
|
||||
|
||||
EventService::RegisterListener(EVENT_DB_OBJECT_RELOAD, [$this, 'CountObjectReload']);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -114,6 +114,9 @@ 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');
|
||||
@@ -135,10 +138,65 @@ 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();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function LoadRequiredItopFiles(): void
|
||||
{
|
||||
parent::LoadRequiredItopFiles();
|
||||
|
||||
$this->RequireOnceItopFile('application/utils.inc.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string Environment the test will run in
|
||||
* @since 2.7.9 3.0.4 3.1.0
|
||||
*/
|
||||
protected function GetTestEnvironment(): string
|
||||
{
|
||||
return self::DEFAULT_TEST_ENVIRONMENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string Absolute path of the configuration file used for the test
|
||||
* @since 2.7.9 3.0.4 3.1.0
|
||||
*/
|
||||
protected function GetConfigFileAbsPath(): string
|
||||
{
|
||||
return utils::GetConfigFilePath($this->GetTestEnvironment());
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the iTop environment for test to run
|
||||
*
|
||||
* @return void
|
||||
* @throws \CoreException
|
||||
* @throws \DictExceptionUnknownLanguage
|
||||
* @throws \MySQLException
|
||||
* @since 2.7.9 3.0.4 3.1.0
|
||||
*/
|
||||
protected function PrepareEnvironment(): void
|
||||
{
|
||||
$sEnv = $this->GetTestEnvironment();
|
||||
$sConfigFile = $this->GetConfigFileAbsPath();
|
||||
|
||||
// Start MetaModel for the prepared environment
|
||||
MetaModel::Startup($sConfigFile, false /* $bModelOnly */, true /* $bAllowCache */, false /* $bTraceSourceFiles */, $sEnv);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
@@ -147,6 +205,31 @@ 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
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
@@ -841,49 +924,6 @@ 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
|
||||
*
|
||||
@@ -910,6 +950,17 @@ 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
|
||||
@@ -1,61 +1,77 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2023 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2023 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest;
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Eric
|
||||
* Date: 20/11/2017
|
||||
* Time: 11:21
|
||||
*/
|
||||
|
||||
use CMDBSource;
|
||||
use MySQLTransactionNotClosedException;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use SetupUtils;
|
||||
|
||||
class ItopTestCase extends TestCase
|
||||
/**
|
||||
* Class ItopTestCase
|
||||
*
|
||||
* Helper class to extend for tests that DO NOT need to access the DataModel or the Database
|
||||
*
|
||||
* @author Eric Espie <eric.espie@combodo.com>
|
||||
* @package Combodo\iTop\Test\UnitTest
|
||||
*/
|
||||
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');
|
||||
|
||||
require_once static::GetAppRoot() . 'approot.inc.php';
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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");
|
||||
|
||||
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);
|
||||
}
|
||||
$this->LoadRequiredItopFiles();
|
||||
$this->LoadRequiredTestFiles();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,10 +84,60 @@ 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()}
|
||||
*
|
||||
* @return void
|
||||
* @since 2.7.9 3.0.4 3.1.0
|
||||
*/
|
||||
protected function LoadRequiredItopFiles(): void
|
||||
{
|
||||
// Empty until we actually need to require some files in the class
|
||||
}
|
||||
|
||||
/**
|
||||
* Overload this method to require necessary files through {@see \Combodo\iTop\Test\UnitTest\ItopTestCase::RequireOnceUnitTestFile()}
|
||||
*
|
||||
* @return void
|
||||
* @since 2.7.10 3.0.4 3.1.0
|
||||
*/
|
||||
protected function LoadRequiredTestFiles(): void
|
||||
{
|
||||
// Empty until we actually need to require some files in the class
|
||||
}
|
||||
|
||||
/**
|
||||
* Require once an iTop file (core or extension) from its relative path to the iTop root dir.
|
||||
* This ensure to always use the right absolute path, especially in {@see \Combodo\iTop\Test\UnitTest\ItopTestCase::RequireOnceUnitTestFile()}
|
||||
@@ -83,7 +149,7 @@ class ItopTestCase extends TestCase
|
||||
*/
|
||||
protected function RequireOnceItopFile(string $sFileRelPath): void
|
||||
{
|
||||
require_once APPROOT . $sFileRelPath;
|
||||
require_once $this->GetAppRoot() . $sFileRelPath;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -151,7 +217,7 @@ 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);
|
||||
}
|
||||
@@ -168,7 +234,7 @@ 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);
|
||||
63
tests/php-unit-tests/src/Hook/TestsRunStartHook.php
Normal file
63
tests/php-unit-tests/src/Hook/TestsRunStartHook.php
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2023 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Hook;
|
||||
|
||||
require_once __DIR__ . '/../../../../approot.inc.php';
|
||||
|
||||
use PHPUnit\Runner\AfterLastTestHook;
|
||||
use PHPUnit\Runner\BeforeFirstTestHook;
|
||||
use utils;
|
||||
|
||||
/**
|
||||
* Class TestsRunStartHook
|
||||
*
|
||||
* IMPORTANT: This will no longer work in PHPUnit 10.0 and there is no alternative for now, so we will have to migrate it when the time comes
|
||||
* @link https://localheinz.com/articles/2023/02/14/extending-phpunit-with-its-new-event-system/#content-hooks-event-system
|
||||
*
|
||||
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
|
||||
* @package Combodo\iTop\Test\UnitTest\Hook
|
||||
* @since N°6097 2.7.10 3.0.4 3.1.1
|
||||
*/
|
||||
class TestsRunStartHook implements BeforeFirstTestHook, AfterLastTestHook
|
||||
{
|
||||
/**
|
||||
* Use the modification time on this file to check whereas it is newer than the requirements in a test case
|
||||
*
|
||||
* @return string Abs. path to a file generated when the global tests run starts.
|
||||
*/
|
||||
public static function GetRunStartedFileAbsPath(): string
|
||||
{
|
||||
// Note: This can't be put in the cache-<ENV> folder as we have multiple <ENV> running across the test cases
|
||||
// We also don't want to put it in the unit tests folder as it is not supposed to be writable
|
||||
return APPROOT.'data/.php-unit-tests-run-started';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function executeBeforeFirstTest(): void
|
||||
{
|
||||
// Create / change modification timestamp of file marking the beginning of the tests run
|
||||
touch(static::GetRunStartedFileAbsPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function executeAfterLastTest(): void
|
||||
{
|
||||
// Cleanup of file marking the beginning of the tests run
|
||||
if (file_exists(static::GetRunStartedFileAbsPath())) {
|
||||
unlink(static::GetRunStartedFileAbsPath());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2023 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Service;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopCustomDatamodelTestCase;
|
||||
use IssueLog;
|
||||
use MFCoreModule;
|
||||
use ReflectionClass;
|
||||
use RunTimeEnvironment;
|
||||
|
||||
|
||||
/**
|
||||
* Class UnitTestRunTimeEnvironment
|
||||
*
|
||||
* Runtime env. dedicated to creating a temp. environment for a group of unit tests with XML deltas.
|
||||
*
|
||||
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
|
||||
* @since N°6097 2.7.10 3.0.4 3.1.1
|
||||
*/
|
||||
class UnitTestRunTimeEnvironment extends RunTimeEnvironment
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function GetMFModulesToCompile($sSourceEnv, $sSourceDir)
|
||||
{
|
||||
$aRet = parent::GetMFModulesToCompile($sSourceEnv, $sSourceDir);
|
||||
|
||||
/** @var string[] $aDeltaFiles Referential of loaded deltas. Mostly to avoid duplicates. */
|
||||
$aDeltaFiles = [];
|
||||
foreach (get_declared_classes() as $sClass) {
|
||||
// Filter on classes derived from this \Combodo\iTop\Test\UnitTest\ItopCustomDatamodelTestCaseItopCustomDatamodelTestCase
|
||||
if (false === is_a($sClass, ItopCustomDatamodelTestCase::class, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$oReflectionClass = new ReflectionClass($sClass);
|
||||
$oReflectionMethod = $oReflectionClass->getMethod('GetDatamodelDeltaAbsPath');
|
||||
|
||||
// Filter on classes with an actual XML delta (eg. not \Combodo\iTop\Test\UnitTest\ItopCustomDatamodelTestCase and maybe some other deriving from a class with a delta)
|
||||
if ($oReflectionMethod->isAbstract()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/** @var \Combodo\iTop\Test\UnitTest\ItopCustomDatamodelTestCase $oTestClassInstance */
|
||||
$oTestClassInstance = new $sClass();
|
||||
|
||||
// Check test class is for desired environment
|
||||
if ($oTestClassInstance->GetTestEnvironment() !== $this->sFinalEnv) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check XML delta actually exists
|
||||
$sDeltaFile = $oTestClassInstance->GetDatamodelDeltaAbsPath();
|
||||
if (false === is_file($sDeltaFile)) {
|
||||
$this->fail("Could not prepare '$this->sFinalEnv' as the XML delta file '$sDeltaFile' (used in $sClass) does not seem to exist");
|
||||
}
|
||||
|
||||
// Avoid duplicates
|
||||
if (in_array($sDeltaFile, $aDeltaFiles)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Prepare fake module name for delta
|
||||
$sDeltaName = preg_replace('/[^\d\w]/', '', $sDeltaFile);
|
||||
// Note: We can't use \MFDeltaModule as we can't specify the ID which leads to only 1 delta being applied... In the future we might introduce a new MFXXXModule, but in the meantime it feels alright (GLA / RQU)
|
||||
$oDelta = new MFCoreModule($sDeltaName, $sDeltaName, $sDeltaFile);
|
||||
|
||||
IssueLog::Debug('XML delta found for unit tests', static::class, [
|
||||
'Unit test class' => $sClass,
|
||||
'Delta file path' => $sDeltaFile,
|
||||
]);
|
||||
|
||||
$aDeltaFiles[] = $sDeltaFile;
|
||||
$aRet[$sDeltaName] = $oDelta;
|
||||
}
|
||||
|
||||
return $aRet;
|
||||
}
|
||||
|
||||
}
|
||||
64
tests/php-unit-tests/tools/run_class_by_class.php
Normal file
64
tests/php-unit-tests/tools/run_class_by_class.php
Normal 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__.'/../../..';
|
||||
|
||||
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";
|
||||
}
|
||||
@@ -7,8 +7,6 @@ use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class SessionTest extends ItopTestCase
|
||||
{
|
||||
|
||||
@@ -7,9 +7,6 @@ use FindStylesheetObject;
|
||||
use ThemeHandler;
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
* @covers ThemeHandler
|
||||
*/
|
||||
class ThemeHandlerTest extends ItopTestCase
|
||||
|
||||
@@ -9,9 +9,6 @@ use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
|
||||
/**
|
||||
*
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
* Class NavigationMenuTest
|
||||
*
|
||||
* @package UI\Base\Layout
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2023 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Application;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopCustomDatamodelTestCase;
|
||||
use MetaModel;
|
||||
use utils;
|
||||
|
||||
/**
|
||||
* @covers \iBackofficeLinkedScriptsExtension
|
||||
*/
|
||||
class ApplicationExtensionTest extends ItopCustomDatamodelTestCase
|
||||
{
|
||||
protected const ENUM_API_CALL_METHOD_ENUMPLUGINS = 'MetaModel::EnumPlugins';
|
||||
protected const ENUM_API_CALL_METHOD_GETCLASSESFORINTERFACE = 'utils::GetClassesForInterface';
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetDatamodelDeltaAbsPath(): string
|
||||
{
|
||||
return __DIR__ . '/Delta/application-extension-usages-in-snippets.xml';
|
||||
}
|
||||
|
||||
/**
|
||||
* This test ensures that APIs are discovered / registered / called.
|
||||
*
|
||||
* It was introduced after {@since N°6436} when some APIs registration in \MetaModel::InitClasses() were lost during a merge {@link https://github.com/Combodo/iTop/commit/6432678de9f635990e22a6512e5b30713c22204a#diff-c94890a26989b5a5ce638f82e8cc7d4c7aa24e6fbb9c2ca89850e8fa4e0e9adaL3004} preventing them from being called when requested. This was hard to detect as it needed an extension to use the lost API to witness that it was no longer called.
|
||||
*
|
||||
* For each new API, a new test case should be added here to ensure that we don't lose it later.
|
||||
* To do so:
|
||||
* - Add the API to the provider
|
||||
* - Add a class extending / implementing the API in ./Delta/application-extension-usages-in-snippets.xml
|
||||
*
|
||||
* @param string $sAPIFQCN
|
||||
* @param string $sCallMethod
|
||||
*
|
||||
* @return void
|
||||
* @dataProvider ExtensionAPIRegisteredAndCalledProvider
|
||||
*/
|
||||
public function testExtensionAPIRegisteredAndCalled(string $sAPIFQCN, string $sCallMethod)
|
||||
{
|
||||
if ($sCallMethod === static::ENUM_API_CALL_METHOD_ENUMPLUGINS) {
|
||||
$iExtendingClassesCount = count(MetaModel::EnumPlugins($sAPIFQCN));
|
||||
} else {
|
||||
$iExtendingClassesCount = count(utils::GetClassesForInterface($sAPIFQCN, '', ['[\\\\/]lib[\\\\/]', '[\\\\/]node_modules[\\\\/]', '[\\\\/]test[\\\\/]', '[\\\\/]tests[\\\\/]']));
|
||||
}
|
||||
$this->assertGreaterThan(0, $iExtendingClassesCount, "Found no class extending the $sAPIFQCN API");
|
||||
}
|
||||
|
||||
public function ExtensionAPIRegisteredAndCalledProvider(): array
|
||||
{
|
||||
// APIs not concerned by this test:
|
||||
// * \iRestServiceProvider as it is discovered by iterating over declared classes directly
|
||||
// * \iLoginUIExtension as it is not iterated directly, only its derived interfaces
|
||||
|
||||
return [
|
||||
\iLoginFSMExtension::class => [
|
||||
\iLoginFSMExtension::class,
|
||||
static::ENUM_API_CALL_METHOD_ENUMPLUGINS,
|
||||
],
|
||||
\iLogoutExtension::class => [
|
||||
\iLogoutExtension::class,
|
||||
static::ENUM_API_CALL_METHOD_ENUMPLUGINS,
|
||||
],
|
||||
\iLoginUIExtension::class => [
|
||||
\iLoginUIExtension::class,
|
||||
static::ENUM_API_CALL_METHOD_ENUMPLUGINS,
|
||||
],
|
||||
\iPreferencesExtension::class => [
|
||||
\iPreferencesExtension::class,
|
||||
static::ENUM_API_CALL_METHOD_ENUMPLUGINS,
|
||||
],
|
||||
\iApplicationUIExtension::class => [
|
||||
\iApplicationUIExtension::class,
|
||||
static::ENUM_API_CALL_METHOD_ENUMPLUGINS,
|
||||
],
|
||||
\iApplicationObjectExtension::class => [
|
||||
\iApplicationObjectExtension::class,
|
||||
static::ENUM_API_CALL_METHOD_ENUMPLUGINS,
|
||||
],
|
||||
\iPopupMenuExtension::class => [
|
||||
\iPopupMenuExtension::class,
|
||||
static::ENUM_API_CALL_METHOD_ENUMPLUGINS,
|
||||
],
|
||||
\iPageUIExtension::class => [
|
||||
\iPageUIExtension::class,
|
||||
static::ENUM_API_CALL_METHOD_ENUMPLUGINS,
|
||||
],
|
||||
\iPageUIBlockExtension::class => [
|
||||
\iPageUIBlockExtension::class,
|
||||
static::ENUM_API_CALL_METHOD_ENUMPLUGINS,
|
||||
],
|
||||
\iBackofficeLinkedScriptsExtension::class => [
|
||||
\iBackofficeLinkedScriptsExtension::class,
|
||||
static::ENUM_API_CALL_METHOD_ENUMPLUGINS,
|
||||
],
|
||||
\iBackofficeEarlyScriptExtension::class => [
|
||||
\iBackofficeEarlyScriptExtension::class,
|
||||
static::ENUM_API_CALL_METHOD_ENUMPLUGINS,
|
||||
],
|
||||
\iBackofficeScriptExtension::class => [
|
||||
\iBackofficeScriptExtension::class,
|
||||
static::ENUM_API_CALL_METHOD_ENUMPLUGINS,
|
||||
],
|
||||
\iBackofficeInitScriptExtension::class => [
|
||||
\iBackofficeInitScriptExtension::class,
|
||||
static::ENUM_API_CALL_METHOD_ENUMPLUGINS,
|
||||
],
|
||||
\iBackofficeReadyScriptExtension::class => [
|
||||
\iBackofficeReadyScriptExtension::class,
|
||||
static::ENUM_API_CALL_METHOD_ENUMPLUGINS,
|
||||
],
|
||||
\iBackofficeLinkedStylesheetsExtension::class => [
|
||||
\iBackofficeLinkedStylesheetsExtension::class,
|
||||
static::ENUM_API_CALL_METHOD_ENUMPLUGINS,
|
||||
],
|
||||
\iBackofficeStyleExtension::class => [
|
||||
\iBackofficeStyleExtension::class,
|
||||
static::ENUM_API_CALL_METHOD_ENUMPLUGINS,
|
||||
],
|
||||
\iBackofficeDictEntriesExtension::class => [
|
||||
\iBackofficeDictEntriesExtension::class,
|
||||
static::ENUM_API_CALL_METHOD_ENUMPLUGINS,
|
||||
],
|
||||
\iBackofficeDictEntriesPrefixesExtension::class => [
|
||||
\iBackofficeDictEntriesPrefixesExtension::class,
|
||||
static::ENUM_API_CALL_METHOD_ENUMPLUGINS,
|
||||
],
|
||||
\iPortalUIExtension::class => [
|
||||
\iPortalUIExtension::class,
|
||||
static::ENUM_API_CALL_METHOD_ENUMPLUGINS,
|
||||
],
|
||||
\iQueryModifier::class => [
|
||||
\iQueryModifier::class,
|
||||
static::ENUM_API_CALL_METHOD_ENUMPLUGINS,
|
||||
],
|
||||
\iOnClassInitialization::class => [
|
||||
\iOnClassInitialization::class,
|
||||
static::ENUM_API_CALL_METHOD_ENUMPLUGINS,
|
||||
],
|
||||
\iFieldRendererMappingsExtension::class => [
|
||||
\iFieldRendererMappingsExtension::class,
|
||||
static::ENUM_API_CALL_METHOD_GETCLASSESFORINTERFACE,
|
||||
],
|
||||
\iModuleExtension::class => [
|
||||
\iModuleExtension::class,
|
||||
static::ENUM_API_CALL_METHOD_ENUMPLUGINS,
|
||||
],
|
||||
\iKPILoggerExtension::class => [
|
||||
\iKPILoggerExtension::class,
|
||||
static::ENUM_API_CALL_METHOD_ENUMPLUGINS,
|
||||
],
|
||||
\ModuleHandlerApiInterface::class => [
|
||||
\ModuleHandlerApiInterface::class,
|
||||
static::ENUM_API_CALL_METHOD_ENUMPLUGINS,
|
||||
],
|
||||
\iNewsroomProvider::class => [
|
||||
\iNewsroomProvider::class,
|
||||
static::ENUM_API_CALL_METHOD_ENUMPLUGINS,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,397 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.7">
|
||||
<snippets>
|
||||
<!-- These snippets just implements application/applicationextension.inc.php APIs for the ApplicationExtensionTest unit test -->
|
||||
<snippet id="ExampleFor_iLoginFSMExtension" _delta="define">
|
||||
<placement>core</placement>
|
||||
<rank>0</rank>
|
||||
<content><![CDATA[
|
||||
class ExampleFor_iLoginFSMExtension extends \AbstractLoginFSMExtension
|
||||
{
|
||||
public function ListSupportedLoginModes()
|
||||
{
|
||||
// Do nothing, we just need the class to exists for the unit test
|
||||
}
|
||||
}
|
||||
]]></content>
|
||||
</snippet>
|
||||
<snippet id="ExampleFor_iLogoutExtension" _delta="define">
|
||||
<placement>core</placement>
|
||||
<rank>0</rank>
|
||||
<content><![CDATA[
|
||||
class ExampleFor_iLogoutExtension implements \iLogoutExtension
|
||||
{
|
||||
public function LogoutAction()
|
||||
{
|
||||
// Do nothing, we just need the class to exists for the unit test
|
||||
}
|
||||
|
||||
public function ListSupportedLoginModes()
|
||||
{
|
||||
// Do nothing, we just need the class to exists for the unit test
|
||||
}
|
||||
}
|
||||
]]></content>
|
||||
</snippet>
|
||||
<snippet id="ExampleFor_iLoginUIExtension" _delta="define">
|
||||
<placement>core</placement>
|
||||
<rank>0</rank>
|
||||
<content><![CDATA[
|
||||
class ExampleFor_iLoginUIExtension implements \iLoginUIExtension
|
||||
{
|
||||
public function GetTwigContext()
|
||||
{
|
||||
// Do nothing, we just need the class to exists for the unit test
|
||||
}
|
||||
|
||||
public function ListSupportedLoginModes()
|
||||
{
|
||||
// Do nothing, we just need the class to exists for the unit test
|
||||
}
|
||||
}
|
||||
]]></content>
|
||||
</snippet>
|
||||
<snippet id="ExampleFor_iPreferencesExtension" _delta="define">
|
||||
<placement>core</placement>
|
||||
<rank>0</rank>
|
||||
<content><![CDATA[
|
||||
class ExampleFor_iPreferencesExtension extends \AbstractPreferencesExtension
|
||||
{
|
||||
// Do nothing, we just need the class to exists for the unit test
|
||||
}
|
||||
]]></content>
|
||||
</snippet>
|
||||
<snippet id="ExampleFor_iApplicationUIExtension" _delta="define">
|
||||
<placement>core</placement>
|
||||
<rank>0</rank>
|
||||
<content><![CDATA[
|
||||
class ExampleFor_iApplicationUIExtension extends \AbstractApplicationUIExtension
|
||||
{
|
||||
// Do nothing, we just need the class to exists for the unit test
|
||||
}
|
||||
]]></content>
|
||||
</snippet>
|
||||
<snippet id="ExampleFor_iApplicationObjectExtension" _delta="define">
|
||||
<placement>core</placement>
|
||||
<rank>0</rank>
|
||||
<content><![CDATA[
|
||||
class ExampleFor_iApplicationObjectExtension extends \AbstractApplicationObjectExtension
|
||||
{
|
||||
// Do nothing, we just need the class to exists for the unit test
|
||||
}
|
||||
]]></content>
|
||||
</snippet>
|
||||
<snippet id="ExampleFor_iPopupMenuExtension" _delta="define">
|
||||
<placement>core</placement>
|
||||
<rank>0</rank>
|
||||
<content><![CDATA[
|
||||
class ExampleFor_iPopupMenuExtension implements \iPopupMenuExtension
|
||||
{
|
||||
public static function EnumItems($iMenuId, $param)
|
||||
{
|
||||
// Do nothing, we just need the class to exists for the unit test
|
||||
}
|
||||
}
|
||||
]]></content>
|
||||
</snippet>
|
||||
<snippet id="ExampleFor_ApplicationPopupMenuItem" _delta="define">
|
||||
<placement>core</placement>
|
||||
<rank>0</rank>
|
||||
<content><![CDATA[
|
||||
class ExampleFor_ApplicationPopupMenuItem extends \ApplicationPopupMenuItem
|
||||
{
|
||||
public function GetMenuItem()
|
||||
{
|
||||
// Do nothing, we just need the class to exists for the unit test
|
||||
}
|
||||
}
|
||||
]]></content>
|
||||
</snippet>
|
||||
<snippet id="ExampleFor_iPageUIExtension" _delta="define">
|
||||
<placement>core</placement>
|
||||
<rank>0</rank>
|
||||
<content><![CDATA[
|
||||
class ExampleFor_iPageUIExtension extends \AbstractPageUIExtension
|
||||
{
|
||||
// Do nothing, we just need the class to exists for the unit test
|
||||
}
|
||||
]]></content>
|
||||
</snippet>
|
||||
<snippet id="ExamplePageUIBlockExtension" _delta="define">
|
||||
<placement>core</placement>
|
||||
<rank>0</rank>
|
||||
<content><![CDATA[
|
||||
class ExampleFor_iPageUIBlockExtension extends \AbstractPageUIBlockExtension
|
||||
{
|
||||
// Do nothing, we just need the class to exists for the unit test
|
||||
}
|
||||
]]></content>
|
||||
</snippet>
|
||||
<snippet id="ExampleFor_iBackofficeLinkedScriptsExtension" _delta="define">
|
||||
<placement>core</placement>
|
||||
<rank>0</rank>
|
||||
<content><![CDATA[
|
||||
class ExampleFor_iBackofficeLinkedScriptsExtension implements \iBackofficeLinkedScriptsExtension
|
||||
{
|
||||
public function GetLinkedScriptsAbsUrls(): array
|
||||
{
|
||||
return [
|
||||
'https://foo.bar/first.js',
|
||||
'https://foo.bar/second.js',
|
||||
];
|
||||
}
|
||||
}
|
||||
]]></content>
|
||||
</snippet>
|
||||
<snippet id="ExampleFor_iBackofficeEarlyScriptExtension" _delta="define">
|
||||
<placement>core</placement>
|
||||
<rank>0</rank>
|
||||
<content><![CDATA[
|
||||
class ExampleFor_iBackofficeEarlyScriptExtension implements \iBackofficeEarlyScriptExtension
|
||||
{
|
||||
public function GetEarlyScript(): string
|
||||
{
|
||||
return <<<JS
|
||||
console.log('This is a PHP unit test');
|
||||
JS;
|
||||
}
|
||||
}
|
||||
]]></content>
|
||||
</snippet>
|
||||
<snippet id="ExampleFor_iBackofficeScriptExtension" _delta="define">
|
||||
<placement>core</placement>
|
||||
<rank>0</rank>
|
||||
<content><![CDATA[
|
||||
class ExampleFor_iBackofficeScriptExtension implements \iBackofficeScriptExtension
|
||||
{
|
||||
public function GetScript(): string
|
||||
{
|
||||
return <<<JS
|
||||
console.log('This is a PHP unit test');
|
||||
JS;
|
||||
}
|
||||
}
|
||||
]]></content>
|
||||
</snippet>
|
||||
<snippet id="ExampleFor_iBackofficeInitScriptExtension" _delta="define">
|
||||
<placement>core</placement>
|
||||
<rank>0</rank>
|
||||
<content><![CDATA[
|
||||
class ExampleFor_iBackofficeInitScriptExtension implements \iBackofficeInitScriptExtension
|
||||
{
|
||||
public function GetInitScript(): string
|
||||
{
|
||||
return <<<JS
|
||||
console.log('This is a PHP unit test');
|
||||
JS;
|
||||
}
|
||||
}
|
||||
]]></content>
|
||||
</snippet>
|
||||
<snippet id="ExampleFor_iBackofficeReadyScriptExtension" _delta="define">
|
||||
<placement>core</placement>
|
||||
<rank>0</rank>
|
||||
<content><![CDATA[
|
||||
class ExampleFor_iBackofficeReadyScriptExtension implements \iBackofficeReadyScriptExtension
|
||||
{
|
||||
public function GetReadyScript(): string
|
||||
{
|
||||
return <<<JS
|
||||
console.log('This is a PHP unit test');
|
||||
JS;
|
||||
}
|
||||
}
|
||||
]]></content>
|
||||
</snippet>
|
||||
<snippet id="ExampleFor_iBackofficeLinkedStylesheetsExtension" _delta="define">
|
||||
<placement>core</placement>
|
||||
<rank>0</rank>
|
||||
<content><![CDATA[
|
||||
class ExampleFor_iBackofficeLinkedStylesheetsExtension implements \iBackofficeLinkedStylesheetsExtension
|
||||
{
|
||||
public function GetLinkedStylesheetsAbsUrls(): array
|
||||
{
|
||||
return [
|
||||
'https://foo.bar/first.css',
|
||||
'https://foo.bar/second.css',
|
||||
];
|
||||
}
|
||||
}
|
||||
]]></content>
|
||||
</snippet>
|
||||
<snippet id="ExampleFor_iBackofficeStyleExtension" _delta="define">
|
||||
<placement>core</placement>
|
||||
<rank>0</rank>
|
||||
<content><![CDATA[
|
||||
class ExampleFor_iBackofficeStyleExtension implements \iBackofficeStyleExtension
|
||||
{
|
||||
public function GetStyle(): string
|
||||
{
|
||||
return <<<CSS
|
||||
.foo {
|
||||
color: inherit;
|
||||
}
|
||||
CSS;
|
||||
}
|
||||
}
|
||||
]]></content>
|
||||
</snippet>
|
||||
<snippet id="ExampleFor_iBackofficeDictEntriesExtension" _delta="define">
|
||||
<placement>core</placement>
|
||||
<rank>0</rank>
|
||||
<content><![CDATA[
|
||||
class ExampleFor_iBackofficeDictEntriesExtension implements \iBackofficeDictEntriesExtension
|
||||
{
|
||||
public function GetDictEntries(): array
|
||||
{
|
||||
return [
|
||||
'Foo:First' => 'Foo is first',
|
||||
'Foo:Second' => 'Foo is second',
|
||||
];
|
||||
}
|
||||
}
|
||||
]]></content>
|
||||
</snippet>
|
||||
<snippet id="ExampleFor_iBackofficeDictEntriesPrefixesExtension" _delta="define">
|
||||
<placement>core</placement>
|
||||
<rank>0</rank>
|
||||
<content><![CDATA[
|
||||
class ExampleFor_iBackofficeDictEntriesPrefixesExtension implements \iBackofficeDictEntriesPrefixesExtension
|
||||
{
|
||||
public function GetDictEntriesPrefixes(): array
|
||||
{
|
||||
return [
|
||||
'Foo:',
|
||||
'Bar:',
|
||||
];
|
||||
}
|
||||
}
|
||||
]]></content>
|
||||
</snippet>
|
||||
<snippet id="ExampleFor_iPortalUIExtension" _delta="define">
|
||||
<placement>core</placement>
|
||||
<rank>0</rank>
|
||||
<content><![CDATA[
|
||||
class ExampleFor_iPortalUIExtension extends \AbstractPortalUIExtension
|
||||
{
|
||||
// Do nothing, we just need the class to exists for the unit test
|
||||
}
|
||||
]]></content>
|
||||
</snippet>
|
||||
<snippet id="ExampleFor_iQueryModifier" _delta="define">
|
||||
<placement>core</placement>
|
||||
<rank>0</rank>
|
||||
<content><![CDATA[
|
||||
class ExampleFor_iQueryModifier implements \iQueryModifier
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
// Do nothing, we just need the class to exists for the unit test
|
||||
}
|
||||
|
||||
public function GetFieldExpression(QueryBuilderContext &$oBuild, $sClass, $sAttCode, $sColId, Expression $oFieldSQLExp, SQLQuery &$oSelect)
|
||||
{
|
||||
// Do nothing, we just need the class to exists for the unit test
|
||||
}
|
||||
}
|
||||
]]></content>
|
||||
</snippet>
|
||||
<snippet id="ExampleFor_iOnClassInitialization" _delta="define">
|
||||
<placement>core</placement>
|
||||
<rank>0</rank>
|
||||
<content><![CDATA[
|
||||
class ExampleFor_iOnClassInitialization implements \iOnClassInitialization
|
||||
{
|
||||
public function OnAfterClassInitialization($sClass)
|
||||
{
|
||||
// Do nothing, we just need the class to exists for the unit test
|
||||
}
|
||||
}
|
||||
]]></content>
|
||||
</snippet>
|
||||
<snippet id="ExampleFor_iFieldRendererMappingsExtension" _delta="define">
|
||||
<placement>core</placement>
|
||||
<rank>0</rank>
|
||||
<content><![CDATA[
|
||||
class ExampleFor_iFieldRendererMappingsExtension implements \iFieldRendererMappingsExtension
|
||||
{
|
||||
public static function RegisterSupportedFields(): array
|
||||
{
|
||||
// Do nothing, we just need the class to exists for the unit test
|
||||
}
|
||||
}
|
||||
]]></content>
|
||||
</snippet>
|
||||
<snippet id="ExampleFor_iModuleExtension" _delta="define">
|
||||
<placement>core</placement>
|
||||
<rank>0</rank>
|
||||
<content><![CDATA[
|
||||
class ExampleFor_iModuleExtension implements \iModuleExtension
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
// Do nothing, we just need the class to exists for the unit test
|
||||
}
|
||||
}
|
||||
]]></content>
|
||||
</snippet>
|
||||
<snippet id="ExampleFor_iKPILoggerExtension" _delta="define">
|
||||
<placement>core</placement>
|
||||
<rank>0</rank>
|
||||
<content><![CDATA[
|
||||
class ExampleFor_iKPILoggerExtension implements \iKPILoggerExtension
|
||||
{
|
||||
public function InitStats()
|
||||
{
|
||||
// Do nothing, we just need the class to exists for the unit test
|
||||
}
|
||||
|
||||
public function LogOperation($oKpiLogData)
|
||||
{
|
||||
// Do nothing, we just need the class to exists for the unit test
|
||||
}
|
||||
}
|
||||
]]></content>
|
||||
</snippet>
|
||||
<!-- These snippets just implements core/modulehandler.class.inc.php APIs for the ApplicationExtensionTest unit test -->
|
||||
<snippet id="ExampleFor_ModuleHandlerApiInterface" _delta="define">
|
||||
<placement>core</placement>
|
||||
<rank>0</rank>
|
||||
<content><![CDATA[
|
||||
class ExampleFor_ModuleHandlerApiInterface extends \ModuleHandlerAPI
|
||||
{
|
||||
// Do nothing, we just need the class to exists for the unit test
|
||||
}
|
||||
]]></content>
|
||||
</snippet>
|
||||
<!-- These snippets just implements application/newsroomprovider.class.inc.php APIs for the ApplicationExtensionTest unit test -->
|
||||
<snippet id="ExampleFor_iNewsroomProvider" _delta="define">
|
||||
<placement>core</placement>
|
||||
<rank>0</rank>
|
||||
<content><![CDATA[
|
||||
class ExampleFor_iNewsroomProvider extends \NewsroomProviderBase
|
||||
{
|
||||
public function GetLabel()
|
||||
{
|
||||
// Do nothing, we just need the class to exists for the unit test
|
||||
}
|
||||
|
||||
public function GetFetchURL()
|
||||
{
|
||||
// Do nothing, we just need the class to exists for the unit test
|
||||
}
|
||||
|
||||
public function GetMarkAllAsReadURL()
|
||||
{
|
||||
// Do nothing, we just need the class to exists for the unit test
|
||||
}
|
||||
|
||||
public function GetViewAllURL()
|
||||
{
|
||||
// Do nothing, we just need the class to exists for the unit test
|
||||
}
|
||||
}
|
||||
]]></content>
|
||||
</snippet>
|
||||
</snippets>
|
||||
</itop_design>
|
||||
@@ -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)
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -10,9 +10,6 @@ use utils;
|
||||
use Dict;
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
* @covers \ActionEmail
|
||||
*/
|
||||
class ActionEmailTest extends ItopDataTestCase
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -5,11 +5,6 @@ namespace Combodo\iTop\Test\UnitTest\Core;
|
||||
use AttributeURLDefaultPattern;
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class AttributeURLTest extends ItopTestCase {
|
||||
public function setUp(): void
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -6,6 +6,9 @@ namespace Combodo\iTop\Test\UnitTest\Core;
|
||||
use CMDBSource;
|
||||
use Combodo\iTop\Core\DbConnectionWrapper;
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
use Exception;
|
||||
use IssueLog;
|
||||
use LogChannels;
|
||||
use utils;
|
||||
|
||||
/**
|
||||
@@ -14,11 +17,6 @@ use utils;
|
||||
* @package Combodo\iTop\Test\UnitTest\Core
|
||||
*/
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class CMDBSourceTest extends ItopTestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
@@ -123,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()
|
||||
{
|
||||
@@ -137,4 +137,49 @@ class CMDBSourceTest extends ItopTestCase
|
||||
$bIsTlsCnx = $this->InvokeNonPublicStaticMethod(CMDBSource::class, 'IsOpenedDbConnectionUsingTls', [$oMysqli]);
|
||||
$this->assertFalse($bIsTlsCnx);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.7.10 3.0.4 3.1.1 3.2.0 N°6643 Checks writing in IssueLog is really done
|
||||
*/
|
||||
public function testLogDeadLock(): void
|
||||
{
|
||||
$sExceptionMessage = 'Test exception for deadlock';
|
||||
$oDeadlockException = new Exception($sExceptionMessage);
|
||||
|
||||
// \CMDBSource::LogDeadLock uses mysqli::errno and mysqli::query()
|
||||
// I didn't achieve mocking the errno property by either of the following means :
|
||||
// - PHPUnit mock => property is read only error
|
||||
// - DbConnectionWrapper::SetDbConnectionMockForQuery with a custom mysqli children
|
||||
// - override of errno property with an assignment (public $errno = ...;) => property is read only error
|
||||
// - override of __get() for the errno property => no error but no change
|
||||
// Solution for errno was to add a new parameter to disable errno read :/
|
||||
/** @noinspection PhpDeprecationInspection */
|
||||
$oMockMysqli = $this->getMockBuilder('mysqli')
|
||||
->setMethods(['query'])
|
||||
->getMock();
|
||||
$oMockMysqli->expects($this->any())
|
||||
->method('query')
|
||||
->willReturnCallback(function () {
|
||||
return false;
|
||||
});
|
||||
DbConnectionWrapper::SetDbConnectionMockForQuery($oMockMysqli);
|
||||
|
||||
$sTestErrorLogPath = APPROOT . 'log/error.phpunit.log';
|
||||
IssueLog::Enable($sTestErrorLogPath);
|
||||
try {
|
||||
$this->InvokeNonPublicStaticMethod(CMDBSource::class, 'LogDeadLock', [$oDeadlockException, true, false]);
|
||||
$sLastErrorLogLine = $this->GetErrorLogLastLines($sTestErrorLogPath, 10); // we are getting multiple lines as the context log introduced multiple lines per log
|
||||
$this->assertStringContainsString(LogChannels::DEADLOCK, $sLastErrorLogLine);
|
||||
$this->assertStringContainsString($sExceptionMessage, $sLastErrorLogLine);
|
||||
} finally {
|
||||
if (file_exists($sTestErrorLogPath)) {
|
||||
unlink($sTestErrorLogPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function GetErrorLogLastLines(string $sErrorLogPath, int $iLineNumbers = 1): string
|
||||
{
|
||||
return trim(implode("", array_slice(file($sErrorLogPath), -$iLineNumbers)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,10 +17,6 @@ use DBSearch;
|
||||
* <ul>
|
||||
* <li>MakeGroupByQuery</li>
|
||||
* </ul>
|
||||
*
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class DBSearchCommitTest extends ItopDataTestCase
|
||||
{
|
||||
|
||||
@@ -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'",
|
||||
|
||||
@@ -11,10 +11,6 @@ use DBSearch;
|
||||
* Class DBSearchIntersectTest
|
||||
*
|
||||
* @package Combodo\iTop\Test\UnitTest\Core
|
||||
*
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class DBSearchJoinTest extends ItopDataTestCase {
|
||||
|
||||
|
||||
@@ -43,10 +43,6 @@ use FunctionExpression;
|
||||
* <ul>
|
||||
* <li>MakeGroupByQuery</li>
|
||||
* </ul>
|
||||
*
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class DBSearchTest extends ItopDataTestCase
|
||||
{
|
||||
|
||||
@@ -10,10 +10,6 @@ use DBObjectSearch;
|
||||
* Class DBSearchUpdateRealiasingMapTest
|
||||
*
|
||||
* @package Combodo\iTop\Test\UnitTest\Core
|
||||
*
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class DBSearchUpdateRealiasingMapTest extends ItopDataTestCase
|
||||
{
|
||||
|
||||
@@ -7,11 +7,6 @@
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class DBUnionSearchTest extends ItopDataTestCase
|
||||
{
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Combodo\iTop\Test\UnitTest\Core;
|
||||
|
||||
|
||||
use CMDBSource;
|
||||
use Combodo\iTop\Test\UnitTest\iTopDataTestCase;
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use DateInterval;
|
||||
use DateTime;
|
||||
use Expression;
|
||||
@@ -13,12 +13,7 @@ use FunctionExpression;
|
||||
use MetaModel;
|
||||
use ScalarExpression;
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class ExpressionEvaluateTest extends iTopDataTestCase
|
||||
class ExpressionEvaluateTest extends ItopDataTestCase
|
||||
{
|
||||
const USE_TRANSACTION = false;
|
||||
|
||||
@@ -38,7 +33,7 @@ class ExpressionEvaluateTest extends iTopDataTestCase
|
||||
$aParameters = $oExpression->GetParameters($sParentFilter);
|
||||
sort($aExpectedParameters);
|
||||
sort($aParameters);
|
||||
static::assertEquals($aExpectedParameters, $aParameters);
|
||||
$this->assertEquals($aExpectedParameters, $aParameters);
|
||||
}
|
||||
|
||||
public function GetParametersProvider()
|
||||
@@ -86,7 +81,7 @@ class ExpressionEvaluateTest extends iTopDataTestCase
|
||||
{
|
||||
$oExpression = Expression::FromOQL($sExpression);
|
||||
$value = $oExpression->Evaluate(array());
|
||||
static::assertEquals($expectedValue, $value);
|
||||
$this->assertEquals($expectedValue, $value);
|
||||
}
|
||||
|
||||
public function VariousExpressionsProvider()
|
||||
@@ -225,7 +220,7 @@ class ExpressionEvaluateTest extends iTopDataTestCase
|
||||
$sNewExpression = "return $sExpression;";
|
||||
$oExpression = eval($sNewExpression);
|
||||
$res = $oExpression->Evaluate(array());
|
||||
static::assertEquals($expectedValue, $res);
|
||||
$this->assertEquals($expectedValue, $res);
|
||||
}
|
||||
|
||||
public function NotYetParsableExpressionsProvider()
|
||||
@@ -287,7 +282,7 @@ class ExpressionEvaluateTest extends iTopDataTestCase
|
||||
$value = $aResults[0]["test_$i"];
|
||||
$expectedValue = $aTest[1];
|
||||
$this->debug("Test #$i: {$aTests[$i][0]} => ".var_export($value, true));
|
||||
static::assertEquals($expectedValue, $value);
|
||||
$this->assertEquals($expectedValue, $value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,7 +305,7 @@ class ExpressionEvaluateTest extends iTopDataTestCase
|
||||
|
||||
$res = $oObject->EvaluateExpression($oExpression);
|
||||
|
||||
static::assertEquals($expected, $res);
|
||||
$this->assertEquals($expected, $res);
|
||||
}
|
||||
|
||||
public function ExpressionsWithObjectFieldsProvider()
|
||||
@@ -340,12 +335,18 @@ class ExpressionEvaluateTest extends iTopDataTestCase
|
||||
{
|
||||
$oExpression = Expression::FromOQL($sExpression);
|
||||
$res = $oExpression->Evaluate($aParameters);
|
||||
static::assertEquals($expected, $res);
|
||||
$this->assertEquals($expected, $res);
|
||||
}
|
||||
|
||||
public function ExpressionWithParametersProvider()
|
||||
{
|
||||
return array(
|
||||
['`DBVariables["analyze_sample_percentage"]` > 10', ['DBVariables["analyze_sample_percentage"]' => 20], true],
|
||||
['`DataBase["DBDataSize"]`', ['DataBase["DBDataSize"]' => 4096], 4096],
|
||||
['`FileSystem["ItopInstallationIntegrity"]`', ['FileSystem["ItopInstallationIntegrity"]' => 'not_conform'], 'not_conform'],
|
||||
['`DBTablesInfo["attachment"].DataSize` > 100', ['DBTablesInfo["attachment"].DataSize' => 200], true],
|
||||
['`DBTablesInfo[].DataSize` > 100', ['DBTablesInfo[].DataSize' => 50], false],
|
||||
['(`DBTablesInfo[].DataSize` > 100) AND (`DBTablesInfo[].DataFree` * 100 / (`DBTablesInfo[].DataSize` + `DBTablesInfo[].IndexSize` + `DBTablesInfo[].DataFree`) > 10)', ['DBTablesInfo[].DataSize' => 200, 'DBTablesInfo[].DataFree' => 100, 'DBTablesInfo[].IndexSize' => 10], true],
|
||||
array('CONCAT(SUBSTR(name, 4), " cause")', array('name' => 'noble'), 'le cause'),
|
||||
);
|
||||
}
|
||||
@@ -369,11 +370,11 @@ class ExpressionEvaluateTest extends iTopDataTestCase
|
||||
$res = $oExpression->IsTrue();
|
||||
if ($bExpectTrue)
|
||||
{
|
||||
static::assertTrue($res, 'arg: '.$sExpression);
|
||||
$this->assertTrue($res, 'arg: '.$sExpression);
|
||||
}
|
||||
else
|
||||
{
|
||||
static::assertFalse($res, 'arg: '.$sExpression);
|
||||
$this->assertFalse($res, 'arg: '.$sExpression);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -414,10 +415,10 @@ class ExpressionEvaluateTest extends iTopDataTestCase
|
||||
if ($bProcessed)
|
||||
{
|
||||
$sqlValue = CMDBSource::QueryToScalar("SELECT DATE_FORMAT('$sDate', '%$sFormat')");
|
||||
static::assertEquals($sqlValue, $sValueOrException, 'Check test against MySQL');
|
||||
$this->assertEquals($sqlValue, $sValueOrException, 'Check test against MySQL');
|
||||
|
||||
$res = $oExpression->Evaluate(array());
|
||||
static::assertEquals($sValueOrException, $res, 'Check evaluation');
|
||||
$this->assertEquals($sValueOrException, $res, 'Check evaluation');
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -510,7 +511,7 @@ class ExpressionEvaluateTest extends iTopDataTestCase
|
||||
{
|
||||
$oExpression = new FunctionExpression('DATE_FORMAT', array(new ScalarExpression($sDate), new ScalarExpression("%$sFormat")));
|
||||
$itopExpressionResult = $oExpression->Evaluate(array());
|
||||
static::assertSame($aMysqlDateFormatRsultsForAllFormats[$sFormat], $itopExpressionResult, "Format %$sFormat not matching MySQL for '$sDate'");
|
||||
$this->assertSame($aMysqlDateFormatRsultsForAllFormats[$sFormat], $itopExpressionResult, "Format %$sFormat not matching MySQL for '$sDate'");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -546,7 +547,7 @@ class ExpressionEvaluateTest extends iTopDataTestCase
|
||||
$oDate = new DateTime($sStartDate);
|
||||
for ($i = 0 ; $i < $iRepeat ; $i++)
|
||||
{
|
||||
$sDate = date_format($oDate, 'Y-m-d, H:i:s');
|
||||
$sDate = date_format($oDate, 'Y-m-d H:i:s');
|
||||
$this->debug("Checking '$sDate'");
|
||||
$this->testEveryTimeFormat($sDate);
|
||||
$oDate->add(new DateInterval($sInterval));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
{
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -16,11 +16,6 @@ use OQLException;
|
||||
use OqlInterpreter;
|
||||
use OQLParserException;
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class OQLParserTest extends ItopDataTestCase
|
||||
{
|
||||
const USE_TRANSACTION = false;
|
||||
|
||||
@@ -21,11 +21,6 @@ use QueryBuilderContext;
|
||||
use SQLObjectQueryBuilder;
|
||||
use utils;
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class OQLTest extends ItopDataTestCase
|
||||
{
|
||||
const USE_TRANSACTION = false;
|
||||
|
||||
@@ -18,10 +18,6 @@ use TagSetFieldData;
|
||||
|
||||
/**
|
||||
* @group itopFaqLight
|
||||
*
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class TagSetFieldDataTest extends ItopDataTestCase
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -12,10 +12,6 @@ use Team;
|
||||
/**
|
||||
* Class UniquenessMessageTest
|
||||
*
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*
|
||||
* @package Combodo\iTop\Test\UnitTest\Core
|
||||
*/
|
||||
class UniquenessMessageTest extends ItopDataTestCase
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -11,11 +11,6 @@ use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
use MetaModel;
|
||||
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class ValueSetObjectsTest extends ItopTestCase
|
||||
{
|
||||
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -33,8 +33,6 @@ define('UNIT_MAX_CACHE_FILES', 10);
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class apcEmulationTest extends ItopTestCase
|
||||
{
|
||||
|
||||
@@ -32,8 +32,6 @@ use Dict;
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class dictApcuTest extends ItopTestCase
|
||||
{
|
||||
|
||||
@@ -30,11 +30,8 @@ use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
use Dict;
|
||||
use Exception;
|
||||
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
* @runClassInSeparateProcess
|
||||
*/
|
||||
class dictTest extends ItopTestCase
|
||||
{
|
||||
|
||||
@@ -15,10 +15,6 @@ use ormCaseLog;
|
||||
* Tests of the ormCaseLog class
|
||||
*
|
||||
* @covers \ormCaseLog
|
||||
*
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class ormCaseLogTest extends ItopDataTestCase
|
||||
{
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -12,10 +12,6 @@ use utils;
|
||||
|
||||
/**
|
||||
* Tests of the ormStyle class
|
||||
*
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class ormStyleTest extends ItopTestCase
|
||||
{
|
||||
|
||||
@@ -38,10 +38,6 @@ define('MAX_TAGS', 12);
|
||||
/**
|
||||
* @group itopFaqLight
|
||||
* Tests of the ormTagSet class
|
||||
*
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class ormTagSetTest extends ItopDataTestCase
|
||||
{
|
||||
|
||||
@@ -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', '');
|
||||
|
||||
@@ -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){
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -34,10 +34,6 @@ use Exception;
|
||||
* @group itopVirtualizationMgmt
|
||||
* @group itopConfigMgmt
|
||||
* @group itopTickets
|
||||
*
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class ItopTicketTest extends ItopDataTestCase
|
||||
{
|
||||
|
||||
@@ -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]);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 ];
|
||||
|
||||
|
||||
@@ -57,12 +57,6 @@ class iTopDesignFormatTest extends ItopTestCase
|
||||
$sInputXml = $this->GetFileContent($sSamplesRelDirPath.$sXmlFileName.'.input');
|
||||
$oInputDesignFormat = static::GetItopFormatFromString($sInputXml);
|
||||
|
||||
// N°6562 Disable test for 1.7 => 3.0 conversion on PHP 8.1.21 / 8.2.8 as it is failing due to unknown reason. Cause will be investigated next week.
|
||||
if ((PHP_VERSION_ID === 80121 || PHP_VERSION_ID === 80208)
|
||||
&& $oInputDesignFormat->GetVersion() === "1.7" && $sTargetVersion === "3.0") {
|
||||
$this->markTestSkipped("Skip test for 1.7 => 3.0 conversion on PHP 8.1.21 as it is failing due to unknown reason. Cause will be investigated next week.");
|
||||
}
|
||||
|
||||
$bResult = $oInputDesignFormat->Convert($sTargetVersion);
|
||||
$aErrors = $oInputDesignFormat->GetErrors();
|
||||
$this->assertCount($iExpectedErrors, $aErrors,
|
||||
@@ -107,12 +101,6 @@ class iTopDesignFormatTest extends ItopTestCase
|
||||
$oExpectedDesignFormat = static::GetItopFormatFromString($sExpectedXml);
|
||||
$sExpectedVersion = $oExpectedDesignFormat->GetVersion();
|
||||
|
||||
// N°6562 Disable test for 1.7 => 3.0 conversion on PHP 8.1.21 / 8.2.8 as it is failing due to unknown reason. Cause will be investigated next week.
|
||||
if ((PHP_VERSION_ID === 80121 || PHP_VERSION_ID === 80208)
|
||||
&& $sInputVersion === "1.7" && $sExpectedVersion === "3.0") {
|
||||
$this->markTestSkipped("Skip test for 1.7 => 3.0 conversion on PHP 8.1.21 as it is failing due to unknown reason. Cause will be investigated next week.");
|
||||
}
|
||||
|
||||
if (version_compare($sInputVersion, $sExpectedVersion, '>=')) {
|
||||
$this->markTestSkipped("This dataset correspond to a downward conversion ($sInputVersion to $sExpectedVersion) and we want to test upwards conversions => skipping !");
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -33,9 +33,6 @@ use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
|
||||
/**
|
||||
* @group itopRequestMgmt
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class CriterionParserTest extends ItopDataTestCase
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user