mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-13 07:24:13 +01:00
N°5608 - Rename "test" folder to "tests" to better match conventions
This commit is contained in:
BIN
tests/backups/backup-itop.tar.gz
Normal file
BIN
tests/backups/backup-itop.tar.gz
Normal file
Binary file not shown.
8
tests/ci_description.ini
Normal file
8
tests/ci_description.ini
Normal file
@@ -0,0 +1,8 @@
|
||||
[itop]
|
||||
itop_setup=tests/setup_params/default-params.xml
|
||||
itop_backup=tests/backups/backup-itop.tar.gz
|
||||
|
||||
[phpunit]
|
||||
; when empty phpunit_xml => no phpunit test performed
|
||||
; phpunit xml file description. required for phpunit testing
|
||||
phpunit_xml=tests/php-unit-tests/phpunit.xml.dist
|
||||
109
tests/manual-visual-tests/attributeset_widget_poc.html
Normal file
109
tests/manual-visual-tests/attributeset_widget_poc.html
Normal file
@@ -0,0 +1,109 @@
|
||||
<!--
|
||||
~ Copyright (c) 2010-2018 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/>
|
||||
~
|
||||
-->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>AttributeSet fields widget test</title>
|
||||
|
||||
<script>
|
||||
var aDictEntries = {"Core:AttributeSet:placeholder": "click to add"};
|
||||
</script>
|
||||
|
||||
<script src="../js/utils.js"></script>
|
||||
<script src="../js/jquery.min.js"></script>
|
||||
<script src="../js/jquery-ui-1.11.4.custom.min.js"></script>
|
||||
<script src="../js/selectize.min.js"></script>
|
||||
<script src="../js/jquery.itop-set-widget.js"></script>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="../css/light-grey.css">
|
||||
<link rel="stylesheet" type="text/css" href="../css/selectize.default.css">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>POC Set widget (itop.set_widget) et CSS</h1>
|
||||
|
||||
<h2>Edition : widget</h2>
|
||||
<form>
|
||||
<div class="field_container">
|
||||
<div>
|
||||
<div class="field_value">
|
||||
<div class="attribute-edit">
|
||||
<div class="field_input_zone field_input_set">
|
||||
<textarea id="tagset-field" rows="30" cols="60">
|
||||
{
|
||||
"possible_values": [
|
||||
{
|
||||
"code": "critical",
|
||||
"label": "Critical ticket"
|
||||
},
|
||||
{
|
||||
"code": "high",
|
||||
"label": "don't forget it !"
|
||||
},
|
||||
{
|
||||
"code": "normal",
|
||||
"label": "when time available"
|
||||
},
|
||||
{
|
||||
"code": "low",
|
||||
"label": "don't worry ;)"
|
||||
}
|
||||
],
|
||||
"max_items_allowed": 3,
|
||||
"partial_values": [
|
||||
"low"
|
||||
],
|
||||
"orig_value": [
|
||||
"critical",
|
||||
"low"
|
||||
],
|
||||
"added": "",
|
||||
"removed": ["toto"]
|
||||
}
|
||||
</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<script>
|
||||
$("#tagset-field").set_widget({isDebug: true});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
<h2>Visualisation</h2>
|
||||
|
||||
<p>
|
||||
<span class="attribute-set attribute-tag-set">
|
||||
<a href="" class="attribute-set-item attribute-set-item-city" data-code="city" data-label="Ville 🏢" data-description="">Ville 🏢</a>
|
||||
<a href="" class="attribute-set-item attribute-set-item-ocean" data-code="ocean" data-label="Mer 🌊" data-description="">Mer 🌊</a>
|
||||
<a href="" class="attribute-set-item attribute-set-item-sunny" data-code="sunny" data-label="Soleil 🌞" data-description="">Soleil 🌞</a>
|
||||
</span>
|
||||
</p>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
105
tests/manual-visual-tests/sanitize_test.php
Normal file
105
tests/manual-visual-tests/sanitize_test.php
Normal file
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
require_once '../../approot.inc.php';
|
||||
|
||||
require_once(APPROOT.'/application\utils.inc.php');
|
||||
$index = 0;
|
||||
function testSanitize ($sValue, $sType, &$index ){
|
||||
$sDefaultVal = '!defaultVal!';
|
||||
$sValueEscapedJs = str_replace('"', '\"', $sValue);
|
||||
$sSanitizedValue = utils::Sanitize($sValue, $sDefaultVal, $sType);
|
||||
|
||||
echo <<<HTML
|
||||
<tr id="test{$index}">
|
||||
<td>{$sType}</td>
|
||||
<td>{$sValue}</td>
|
||||
<td class="sanitized_php">{$sSanitizedValue}</td>
|
||||
<td class="sanitized_js"></td>
|
||||
<td class="hasDiff"></td>
|
||||
</tr>
|
||||
<script>
|
||||
var parentTr = $("tr#test{$index}"),
|
||||
sanitizedPhp = parentTr.find("td.sanitized_php").text(),
|
||||
sanitizedJs = CombodoSanitizer.Sanitize("{$sValueEscapedJs}","{$sDefaultVal}","{$sType}");
|
||||
|
||||
parentTr.find("td.sanitized_js").text(sanitizedJs);
|
||||
|
||||
if (sanitizedJs !== sanitizedPhp) {
|
||||
console.error("difference detected !", "{$sValueEscapedJs}", '{$sType}', sanitizedPhp, sanitizedJs);
|
||||
parentTr.find("td.hasDiff").text("KO");
|
||||
}
|
||||
</script>
|
||||
HTML;
|
||||
|
||||
$index++;
|
||||
}
|
||||
|
||||
$aValues = array(
|
||||
"test",
|
||||
"t;e-s_t$",
|
||||
"123test",
|
||||
"\"('èé&=hcb test",
|
||||
"<div>Hello!</div>",
|
||||
"*-+7464+guigez cfuze",
|
||||
"",
|
||||
"()=°²€",
|
||||
"éèç",
|
||||
);
|
||||
|
||||
$aTypes = array(
|
||||
'context_param',
|
||||
'element_identifier',
|
||||
'field_name',
|
||||
'integer',
|
||||
'parameter',
|
||||
'string',
|
||||
'transaction_id',
|
||||
// 'variable_name', // introduced in 3.0.0
|
||||
);
|
||||
|
||||
?>
|
||||
<!DOCTYPE>
|
||||
<html>
|
||||
<head>
|
||||
<script type="text/javascript" src="../../js/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="../../js/utils.js"></script>
|
||||
<style>
|
||||
table, tr, td {
|
||||
padding: 3px 10px;
|
||||
border: 1px solid lightgrey;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
td.hasDiff {
|
||||
color: red;
|
||||
}
|
||||
|
||||
thead {
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>Type</td>
|
||||
<td>chaine initiale</td>
|
||||
<td>chaine sanitize by php</td>
|
||||
<td>chaine sanitize by js</td>
|
||||
<td> status test</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<?php
|
||||
|
||||
foreach ($aTypes as $sType) {
|
||||
foreach ($aValues as $sValue) {
|
||||
testSanitize($sValue, $sType, $index);
|
||||
}
|
||||
}
|
||||
?></table>
|
||||
</body>
|
||||
</html>
|
||||
793
tests/php-unit-tests/ItopDataTestCase.php
Normal file
793
tests/php-unit-tests/ItopDataTestCase.php
Normal file
@@ -0,0 +1,793 @@
|
||||
<?php
|
||||
// Copyright (c) 2010-2017 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/>
|
||||
//
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest;
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Eric
|
||||
* Date: 20/11/2017
|
||||
* Time: 11:21
|
||||
*/
|
||||
|
||||
use ArchivedObjectException;
|
||||
use CMDBSource;
|
||||
use Contact;
|
||||
use DBObject;
|
||||
use DBObjectSet;
|
||||
use DBSearch;
|
||||
use Exception;
|
||||
use Farm;
|
||||
use FunctionalCI;
|
||||
use Hypervisor;
|
||||
use lnkContactToFunctionalCI;
|
||||
use lnkContactToTicket;
|
||||
use lnkFunctionalCIToTicket;
|
||||
use MetaModel;
|
||||
use Person;
|
||||
use Server;
|
||||
use TagSetFieldData;
|
||||
use Ticket;
|
||||
use URP_UserProfile;
|
||||
use VirtualHost;
|
||||
use VirtualMachine;
|
||||
|
||||
|
||||
/** @see \Combodo\iTop\Test\UnitTest\ItopDataTestCase::CreateObjectWithTagSet() */
|
||||
define('TAG_CLASS', 'FAQ');
|
||||
define('TAG_ATTCODE', 'domains');
|
||||
|
||||
/**
|
||||
* Helper class to extend for tests needing access to iTop's metamodel
|
||||
*
|
||||
* **⚠ Warning** Each class extending this one needs to add the following annotations :
|
||||
*
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°4624 processIsolation is disabled by default and must be enabled in each test needing it (basically all tests using
|
||||
* iTop datamodel)
|
||||
*/
|
||||
class ItopDataTestCase extends ItopTestCase
|
||||
{
|
||||
private $iTestOrgId;
|
||||
// For cleanup
|
||||
private $aCreatedObjects = array();
|
||||
|
||||
const USE_TRANSACTION = true;
|
||||
const CREATE_TEST_ORG = false;
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
require_once(APPROOT.'/application/startup.inc.php');
|
||||
|
||||
require_once(APPROOT.'application/utils.inc.php');
|
||||
|
||||
$sEnv = 'production';
|
||||
$sConfigFile = APPCONF.$sEnv.'/'.ITOP_CONFIG_FILE;
|
||||
MetaModel::Startup($sConfigFile, false /* $bModelOnly */, true /* $bAllowCache */, false /* $bTraceSourceFiles */, $sEnv);
|
||||
|
||||
if (static::USE_TRANSACTION)
|
||||
{
|
||||
CMDBSource::Query('START TRANSACTION');
|
||||
}
|
||||
if (static::CREATE_TEST_ORG)
|
||||
{
|
||||
$this->CreateTestOrganization();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function tearDown(): void
|
||||
{
|
||||
if (static::USE_TRANSACTION) {
|
||||
$this->debug("ROLLBACK !!!");
|
||||
CMDBSource::Query('ROLLBACK');
|
||||
} else {
|
||||
$this->debug("");
|
||||
$this->aCreatedObjects = array_reverse($this->aCreatedObjects);
|
||||
foreach ($this->aCreatedObjects as $oObject)
|
||||
{
|
||||
/** @var DBObject $oObject */
|
||||
try
|
||||
{
|
||||
$sClass = get_class($oObject);
|
||||
$iKey = $oObject->GetKey();
|
||||
$this->debug("Removing $sClass::$iKey");
|
||||
$oObject->DBDelete();
|
||||
}
|
||||
catch (Exception $e) {
|
||||
$this->debug("Error when removing created objects: $sClass::$iKey. Exception message: ".$e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getTestOrgId()
|
||||
{
|
||||
return $this->iTestOrgId;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/// Database Utilities
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* @param string $sClass
|
||||
* @param array $aParams
|
||||
*
|
||||
* @return DBObject
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function createObject($sClass, $aParams)
|
||||
{
|
||||
$oMyObj = MetaModel::NewObject($sClass);
|
||||
foreach ($aParams as $sAttCode => $oValue)
|
||||
{
|
||||
$oMyObj->Set($sAttCode, $oValue);
|
||||
}
|
||||
$oMyObj->DBInsert();
|
||||
$iKey = $oMyObj->GetKey();
|
||||
$this->debug("Created $sClass::$iKey");
|
||||
$this->aCreatedObjects[] = $oMyObj;
|
||||
|
||||
return $oMyObj;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sClass
|
||||
* @param $iKey
|
||||
* @param array $aParams
|
||||
*
|
||||
* @return DBObject
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
*/
|
||||
protected static function updateObject($sClass, $iKey, $aParams)
|
||||
{
|
||||
$oMyObj = MetaModel::GetObject($sClass, $iKey);
|
||||
foreach ($aParams as $sAttCode => $oValue)
|
||||
{
|
||||
$oMyObj->Set($sAttCode, $oValue);
|
||||
}
|
||||
$oMyObj->DBUpdate();
|
||||
|
||||
return $oMyObj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an Organization in database
|
||||
*
|
||||
* @param string $sName
|
||||
*
|
||||
* @return \Organization
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function CreateOrganization($sName)
|
||||
{
|
||||
/** @var \Organization $oObj */
|
||||
$oObj = $this->createObject('Organization', array(
|
||||
'name' => $sName,
|
||||
));
|
||||
$this->debug("Created Organization {$oObj->Get('name')}");
|
||||
|
||||
return $oObj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Ticket in database
|
||||
*
|
||||
* @param int $iNum
|
||||
*
|
||||
* @return Ticket
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function CreateTicket($iNum)
|
||||
{
|
||||
/** @var Ticket $oTicket */
|
||||
$oTicket = $this->createObject('UserRequest', array(
|
||||
'ref' => 'Ticket_'.$iNum,
|
||||
'title' => 'TICKET_'.$iNum,
|
||||
//'request_type' => 'incident',
|
||||
'description' => 'Created for unit tests.',
|
||||
'org_id' => $this->getTestOrgId(),
|
||||
));
|
||||
$this->debug("Created {$oTicket->Get('title')} ({$oTicket->Get('ref')})");
|
||||
|
||||
return $oTicket;
|
||||
}
|
||||
|
||||
protected function RemoveTicket($iNum)
|
||||
{
|
||||
$this->RemoveObjects('UserRequest', "SELECT UserRequest WHERE ref = 'Ticket_$iNum'");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Ticket in database
|
||||
*
|
||||
* @param string $sClass
|
||||
* @param string $sAttCode
|
||||
* @param string $sTagCode
|
||||
* @param string $sTagLabel
|
||||
* @param string $sTagDescription
|
||||
*
|
||||
* @return \TagSetFieldData
|
||||
* @throws \CoreException
|
||||
*/
|
||||
protected function CreateTagData($sClass, $sAttCode, $sTagCode, $sTagLabel, $sTagDescription = '')
|
||||
{
|
||||
$sTagClass = TagSetFieldData::GetTagDataClassName($sClass, $sAttCode);
|
||||
$oTagData = $this->createObject($sTagClass, array(
|
||||
'code' => $sTagCode,
|
||||
'label' => $sTagLabel,
|
||||
'obj_class' => $sClass,
|
||||
'obj_attcode' => $sAttCode,
|
||||
'description' => $sTagDescription,
|
||||
));
|
||||
$this->debug("Created {$oTagData->Get('code')} ({$oTagData->Get('label')})");
|
||||
|
||||
/** @var \TagSetFieldData $oTagData */
|
||||
return $oTagData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Ticket in database
|
||||
*
|
||||
* @param string $sClass
|
||||
* @param string $sAttCode
|
||||
* @param string $sTagCode
|
||||
*
|
||||
* @throws \CoreException
|
||||
*/
|
||||
protected function RemoveTagData($sClass, $sAttCode, $sTagCode)
|
||||
{
|
||||
$sTagClass = TagSetFieldData::GetTagDataClassName($sClass, $sAttCode);
|
||||
$this->RemoveObjects($sTagClass, "SELECT $sTagClass WHERE code = '$sTagCode'");
|
||||
}
|
||||
|
||||
private function RemoveObjects($sClass, $sOQL)
|
||||
{
|
||||
$oFilter = DBSearch::FromOQL($sOQL);
|
||||
$aRes = $oFilter->ToDataArray(array('id'));
|
||||
foreach ($aRes as $aRow)
|
||||
{
|
||||
$this->debug($aRow);
|
||||
$iKey = $aRow['id'];
|
||||
if (!empty($iKey))
|
||||
{
|
||||
$oObject = MetaModel::GetObject($sClass, $iKey);
|
||||
$oObject->DBDelete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a UserRequest in database
|
||||
*
|
||||
* @param int $iNum
|
||||
* @param int $iTimeSpent
|
||||
* @param int $iOrgId
|
||||
* @param int $iCallerId
|
||||
*
|
||||
* @return \UserRequest
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function CreateUserRequest($iNum, $iTimeSpent = 0, $iOrgId = 0, $iCallerId = 0)
|
||||
{
|
||||
/** @var \UserRequest $oTicket */
|
||||
$oTicket = $this->createObject('UserRequest', array(
|
||||
'ref' => 'Ticket_'.$iNum,
|
||||
'title' => 'BUG 1161_'.$iNum,
|
||||
//'request_type' => 'incident',
|
||||
'description' => 'Add aggregate functions',
|
||||
'time_spent' => $iTimeSpent,
|
||||
'caller_id' => $iCallerId,
|
||||
'org_id' => ($iOrgId == 0 ? $this->getTestOrgId() : $iOrgId),
|
||||
));
|
||||
$this->debug("Created {$oTicket->Get('title')} ({$oTicket->Get('ref')})");
|
||||
|
||||
return $oTicket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Server in database
|
||||
*
|
||||
* @param int $iNum
|
||||
* @param null $iRackUnit
|
||||
*
|
||||
* @return Server
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function CreateServer($iNum, $iRackUnit = null)
|
||||
{
|
||||
/** @var Server $oServer */
|
||||
$oServer = $this->createObject('Server', array(
|
||||
'name' => 'Server_'.$iNum,
|
||||
'org_id' => $this->getTestOrgId(),
|
||||
'nb_u' => $iRackUnit,
|
||||
));
|
||||
$this->debug("Created {$oServer->GetName()} ({$oServer->GetKey()})");
|
||||
|
||||
return $oServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a PhysicalInterface in database
|
||||
*
|
||||
* @param int $iNum
|
||||
* @param int $iSpeed
|
||||
* @param int $iConnectableCiId
|
||||
*
|
||||
* @return DBObject
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function CreatePhysicalInterface($iNum, $iSpeed, $iConnectableCiId)
|
||||
{
|
||||
$oObj = $this->createObject('PhysicalInterface', array(
|
||||
'name' => "$iNum",
|
||||
'speed' => $iSpeed,
|
||||
'connectableci_id' => $iConnectableCiId,
|
||||
));
|
||||
$this->debug("Created {$oObj->GetName()} ({$oObj->GetKey()})");
|
||||
|
||||
return $oObj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a FiberChannelInterface in database
|
||||
*
|
||||
* @param int $iNum
|
||||
* @param int $iSpeed
|
||||
* @param int $iConnectableCiId
|
||||
*
|
||||
* @return DBObject
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function CreateFiberChannelInterface($iNum, $iSpeed, $iConnectableCiId)
|
||||
{
|
||||
$oObj = $this->createObject('FiberChannelInterface', array(
|
||||
'name' => "$iNum",
|
||||
'speed' => $iSpeed,
|
||||
'datacenterdevice_id' => $iConnectableCiId,
|
||||
));
|
||||
$this->debug("Created {$oObj->GetName()} ({$oObj->GetKey()})");
|
||||
|
||||
return $oObj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Person in database
|
||||
*
|
||||
* @param int $iNum
|
||||
* @param int $iOrgId
|
||||
*
|
||||
* @return Person
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function CreatePerson($iNum, $iOrgId = 0)
|
||||
{
|
||||
/** @var Person $oPerson */
|
||||
$oPerson = $this->createObject('Person', array(
|
||||
'name' => 'Person_'.$iNum,
|
||||
'first_name' => 'Test',
|
||||
'org_id' => ($iOrgId == 0 ? $this->getTestOrgId() : $iOrgId),
|
||||
));
|
||||
$this->debug("Created {$oPerson->GetName()} ({$oPerson->GetKey()})");
|
||||
|
||||
return $oPerson;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sLogin
|
||||
* @param int $iProfileId
|
||||
*
|
||||
* @return \DBObject
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function CreateUser($sLogin, $iProfileId, $sPassword=null, $iContactid=2)
|
||||
{
|
||||
if (empty($sPassword)){
|
||||
$sPassword = $sLogin;
|
||||
}
|
||||
|
||||
$oUserProfile = new URP_UserProfile();
|
||||
$oUserProfile->Set('profileid', $iProfileId);
|
||||
$oUserProfile->Set('reason', 'UNIT Tests');
|
||||
$oSet = DBObjectSet::FromObject($oUserProfile);
|
||||
$oUser = $this->createObject('UserLocal', array(
|
||||
'contactid' => $iContactid,
|
||||
'login' => $sLogin,
|
||||
'password' => $sPassword,
|
||||
'language' => 'EN US',
|
||||
'profile_list' => $oSet,
|
||||
));
|
||||
$this->debug("Created {$oUser->GetName()} ({$oUser->GetKey()})");
|
||||
|
||||
return $oUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DBObject $oUser
|
||||
* @param int $iProfileId
|
||||
*
|
||||
* @return \DBObject
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function AddProfileToUser($oUser, $iProfileId)
|
||||
{
|
||||
$oUserProfile = new URP_UserProfile();
|
||||
$oUserProfile->Set('profileid', $iProfileId);
|
||||
$oUserProfile->Set('reason', 'UNIT Tests');
|
||||
/** @var DBObjectSet $oSet */
|
||||
$oSet = $oUser->Get('profile_list');
|
||||
$oSet->AddObject($oUserProfile);
|
||||
$oUser = $this->updateObject('UserLocal', $oUser->GetKey(), array(
|
||||
'profile_list' => $oSet,
|
||||
));
|
||||
$this->debug("Updated {$oUser->GetName()} ({$oUser->GetKey()})");
|
||||
|
||||
return $oUser;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a Hypervisor in database
|
||||
*
|
||||
* @param int $iNum
|
||||
* @param Server $oServer
|
||||
* @param Farm $oFarm
|
||||
*
|
||||
* @return Hypervisor
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function CreateHypervisor($iNum, $oServer, $oFarm = null)
|
||||
{
|
||||
/** @var Hypervisor $oHypervisor */
|
||||
$oHypervisor = $this->createObject('Hypervisor', array(
|
||||
'name' => 'Hypervisor_'.$iNum,
|
||||
'org_id' => $this->getTestOrgId(),
|
||||
'server_id' => $oServer->GetKey(),
|
||||
'farm_id' => is_null($oFarm) ? 0 : $oFarm->GetKey(),
|
||||
));
|
||||
if (is_null($oFarm))
|
||||
{
|
||||
$this->debug("Created {$oHypervisor->GetName()} ({$oHypervisor->GetKey()}) on {$oServer->GetName()}");
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->debug("Created {$oHypervisor->GetName()} ({$oHypervisor->GetKey()}) on {$oServer->GetName()} part of {$oFarm->GetName()}");
|
||||
}
|
||||
|
||||
return $oHypervisor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Farm in database
|
||||
*
|
||||
* @param int $iNum
|
||||
* @param string $sRedundancy
|
||||
*
|
||||
* @return Farm
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function CreateFarm($iNum, $sRedundancy = '1')
|
||||
{
|
||||
/** @var Farm $oFarm */
|
||||
$oFarm = $this->createObject('Farm', array(
|
||||
'name' => 'Farm_'.$iNum,
|
||||
'org_id' => $this->getTestOrgId(),
|
||||
'redundancy' => $sRedundancy,
|
||||
));
|
||||
$this->debug("Created {$oFarm->GetName()} ({$oFarm->GetKey()}) redundancy $sRedundancy");
|
||||
|
||||
return $oFarm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a VM in database
|
||||
*
|
||||
* @param int $iNum
|
||||
* @param VirtualHost $oVirtualHost
|
||||
*
|
||||
* @return VirtualMachine
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function CreateVirtualMachine($iNum, $oVirtualHost)
|
||||
{
|
||||
/** @var VirtualMachine $oVirtualMachine */
|
||||
$oVirtualMachine = $this->createObject('VirtualMachine', array(
|
||||
'name' => 'VirtualMachine_'.$iNum,
|
||||
'org_id' => $this->getTestOrgId(),
|
||||
'virtualhost_id' => $oVirtualHost->GetKey(),
|
||||
));
|
||||
$this->debug("Created {$oVirtualMachine->GetName()} ({$oVirtualMachine->GetKey()}) on {$oVirtualHost->GetName()}");
|
||||
|
||||
return $oVirtualMachine;
|
||||
}
|
||||
|
||||
protected function CreateObjectWithTagSet()
|
||||
{
|
||||
$oFaqCategory = MetaModel::GetObject('FAQCategory', 1, false);
|
||||
if (empty($oFaqCategory))
|
||||
{
|
||||
$oFaqCategory = $this->createObject('FAQCategory', array(
|
||||
'name' => 'FAQCategory_phpunit',
|
||||
));
|
||||
}
|
||||
|
||||
/** @var \FAQ $oFaq */
|
||||
$oFaq = $this->createObject('FAQ', array(
|
||||
'category_id' => $oFaqCategory->GetKey(),
|
||||
'title' => 'FAQ_phpunit',
|
||||
));
|
||||
$this->debug("Created {$oFaq->GetName()}");
|
||||
|
||||
return $oFaq;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a link between a contact and a CI.
|
||||
* The database is not updated.
|
||||
*
|
||||
* @param Contact $oContact
|
||||
* @param FunctionalCI $oCI
|
||||
*
|
||||
* @return lnkContactToFunctionalCI
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function AddContactToCI($oContact, $oCI)
|
||||
{
|
||||
$oNewLink = new lnkContactToFunctionalCI();
|
||||
$oNewLink->Set('contact_id', $oContact->GetKey());
|
||||
$oContacts = $oCI->Get('contacts_list');
|
||||
$oContacts->AddItem($oNewLink);
|
||||
$oCI->Set('contacts_list', $oContacts);
|
||||
|
||||
$this->debug("Added {$oContact->GetName()} to {$oCI->GetName()}");
|
||||
|
||||
return $oNewLink;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a link between a contact and a CI.
|
||||
* The database is not updated.
|
||||
*
|
||||
* @param Contact $oContact
|
||||
* @param FunctionalCI $oCI
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function RemoveContactFromCI($oContact, $oCI)
|
||||
{
|
||||
$oContacts = $oCI->Get('contacts_list');
|
||||
foreach ($oContacts as $oLnk)
|
||||
{
|
||||
if ($oLnk->Get('contact_id') == $oContact->GetKey())
|
||||
{
|
||||
$oContacts->RemoveItem($oLnk->GetKey());
|
||||
$oCI->Set('contacts_list', $oContacts);
|
||||
$this->debug("Removed {$oContact->GetName()} from {$oCI->Get('name')}");
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a link between a CI and a Ticket.
|
||||
* The database is not updated.
|
||||
*
|
||||
* @param FunctionalCI $oCI
|
||||
* @param Ticket $oTicket
|
||||
* @param string $sImpactCode
|
||||
*
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function AddCIToTicket($oCI, $oTicket, $sImpactCode)
|
||||
{
|
||||
$oNewLink = new lnkFunctionalCIToTicket();
|
||||
$oNewLink->Set('functionalci_id', $oCI->GetKey());
|
||||
$oNewLink->Set('impact_code', $sImpactCode);
|
||||
$oCIs = $oTicket->Get('functionalcis_list');
|
||||
$oCIs->AddItem($oNewLink);
|
||||
$oTicket->Set('functionalcis_list', $oCIs);
|
||||
|
||||
$this->debug("Added {$oCI->GetName()} to {$oTicket->Get('ref')} with {$sImpactCode}");
|
||||
|
||||
return array($oCI->GetKey() => $sImpactCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a link between a CI and a Ticket.
|
||||
* The database is not updated.
|
||||
*
|
||||
* @param FunctionalCI $oCI
|
||||
* @param Ticket $oTicket
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function RemoveCIFromTicket($oCI, $oTicket)
|
||||
{
|
||||
$oCIs = $oTicket->Get('functionalcis_list');
|
||||
foreach ($oCIs as $oLnk)
|
||||
{
|
||||
if ($oLnk->Get('functionalci_id') == $oCI->GetKey())
|
||||
{
|
||||
$sImpactCode = $oLnk->Get('impact_code');
|
||||
$oCIs->RemoveItem($oLnk->GetKey());
|
||||
$oTicket->Set('functionalcis_list', $oCIs);
|
||||
$this->debug("Removed {$oCI->GetName()} from {$oTicket->Get('ref')} ({$sImpactCode})");
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
$this->debug("ERROR: {$oCI->GetName()} not attached to {$oTicket->Get('ref')}");
|
||||
$this->assertTrue(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a link between a Contact and a Ticket.
|
||||
* The database is not updated.
|
||||
*
|
||||
* @param Contact $oContact
|
||||
* @param Ticket $oTicket
|
||||
* @param string $sRoleCode
|
||||
* @param array $aParams
|
||||
*
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function AddContactToTicket($oContact, $oTicket, $sRoleCode, $aParams = array())
|
||||
{
|
||||
$oNewLink = new lnkContactToTicket();
|
||||
$oNewLink->Set('contact_id', $oContact->GetKey());
|
||||
$oNewLink->Set('role_code', $sRoleCode);
|
||||
foreach ($aParams as $sAttCode => $oValue)
|
||||
{
|
||||
$oNewLink->Set($sAttCode, $oValue);
|
||||
}
|
||||
$oCIs = $oTicket->Get('contacts_list');
|
||||
$oCIs->AddItem($oNewLink);
|
||||
$oTicket->Set('contacts_list', $oCIs);
|
||||
|
||||
$this->debug("Added {$oContact->GetName()} to {$oTicket->Get('ref')} with {$sRoleCode}");
|
||||
|
||||
return array($oContact->GetKey() => $sRoleCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a link between a Contact and a Ticket.
|
||||
* The database is not updated.
|
||||
*
|
||||
* @param Contact $oContact
|
||||
* @param Ticket $oTicket
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function RemoveContactFromTicket($oContact, $oTicket)
|
||||
{
|
||||
$oContacts = $oTicket->Get('contacts_list');
|
||||
foreach ($oContacts as $oLnk)
|
||||
{
|
||||
if ($oLnk->Get('contact_id') == $oContact->GetKey())
|
||||
{
|
||||
$sRoleCode = $oLnk->Get('role_code');
|
||||
$oContacts->RemoveItem($oLnk->GetKey());
|
||||
$oTicket->Set('contacts_list', $oContacts);
|
||||
$this->debug("Removed {$oContact->GetName()} from {$oTicket->Get('ref')} ({$sRoleCode})");
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reload a Ticket from the database.
|
||||
*
|
||||
* @param DBObject $oObject
|
||||
*
|
||||
* @return \DBObject|null
|
||||
* @throws ArchivedObjectException
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function ReloadObject(&$oObject)
|
||||
{
|
||||
$oObject = MetaModel::GetObject(get_class($oObject), $oObject->GetKey());
|
||||
|
||||
return $oObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check or Display the CI list of a Ticket.
|
||||
*
|
||||
* @param Ticket $oTicket
|
||||
* @param array $aWaitedCIList { iCIId => sImpactCode }
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function CheckFunctionalCIList($oTicket, $aWaitedCIList = array())
|
||||
{
|
||||
$this->debug("\nResulting functionalcis_list {$oTicket->Get('ref')} ({$oTicket->Get('functionalcis_list')->Count()}):");
|
||||
foreach ($oTicket->Get('functionalcis_list') as $oLnk)
|
||||
{
|
||||
$this->debug($oLnk->Get('functionalci_name')." => ".$oLnk->Get('impact_code')."");
|
||||
$iId = $oLnk->Get('functionalci_id');
|
||||
if (!empty($aWaitedCIList))
|
||||
{
|
||||
$this->assertTrue(array_key_exists($iId, $aWaitedCIList));
|
||||
$this->assertEquals($aWaitedCIList[$iId], $oLnk->Get('impact_code'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check or Display the Contact list of a DBObject (having a contacts_list).
|
||||
* Can also control other attributes of the link.
|
||||
*
|
||||
* @param Ticket $oTicket
|
||||
* @param array $aWaitedContactList { iContactId => array(attcode => value) }
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function CheckContactList($oTicket, $aWaitedContactList = array())
|
||||
{
|
||||
$this->debug("\nResulting contacts_list {$oTicket->Get('ref')} ({$oTicket->Get('contacts_list')->Count()}):");
|
||||
foreach ($oTicket->Get('contacts_list') as $oLnk)
|
||||
{
|
||||
$this->debug($oLnk->Get('contact_id_friendlyname')." => ".$oLnk->Get('role_code'));
|
||||
$iId = $oLnk->Get('contact_id');
|
||||
if (!empty($aWaitedContactList))
|
||||
{
|
||||
$this->assertTrue(array_key_exists($iId, $aWaitedContactList));
|
||||
foreach ($aWaitedContactList[$iId] as $sAttCode => $oValue)
|
||||
{
|
||||
if (MetaModel::IsValidAttCode(get_class($oTicket), $sAttCode))
|
||||
{
|
||||
$this->assertEquals($oValue, $oLnk->Get($sAttCode));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function CreateTestOrganization()
|
||||
{
|
||||
// Create a specific organization for the tests
|
||||
$oOrg = $this->CreateOrganization('UnitTestOrganization');
|
||||
$this->iTestOrgId = $oOrg->GetKey();
|
||||
return $oOrg;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
175
tests/php-unit-tests/ItopTestCase.php
Normal file
175
tests/php-unit-tests/ItopTestCase.php
Normal file
@@ -0,0 +1,175 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2019 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;
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Eric
|
||||
* Date: 20/11/2017
|
||||
* Time: 11:21
|
||||
*/
|
||||
|
||||
use CMDBSource;
|
||||
use MySQLTransactionNotClosedException;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use SetupUtils;
|
||||
|
||||
define('DEBUG_UNIT_TEST', true);
|
||||
|
||||
class ItopTestCase extends TestCase
|
||||
{
|
||||
const TEST_LOG_DIR = 'test';
|
||||
|
||||
/** @noinspection UsingInclusionOnceReturnValueInspection avoid errors for approot includes */
|
||||
protected function setUp(): void
|
||||
{
|
||||
@include_once '../approot.inc.php';
|
||||
@include_once '../../approot.inc.php';
|
||||
@include_once '../../../approot.inc.php';
|
||||
@include_once '../../../../approot.inc.php';
|
||||
@include_once '../../../../../approot.inc.php';
|
||||
@include_once '../../../../../../approot.inc.php';
|
||||
@include_once '../../../../../../../approot.inc.php';
|
||||
@include_once '../../../../../../../../approot.inc.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \MySQLTransactionNotClosedException see N°5538
|
||||
* @since 2.7.8 3.0.3 3.1.0 N°5538
|
||||
*/
|
||||
protected function tearDown(): void
|
||||
{
|
||||
parent::tearDown();
|
||||
|
||||
if (CMDBSource::IsInsideTransaction()) {
|
||||
// Nested transactions were opened but not finished !
|
||||
throw new MySQLTransactionNotClosedException('Some DB transactions were opened but not closed ! Fix the code by adding ROLLBACK or COMMIT statements !', []);
|
||||
}
|
||||
}
|
||||
|
||||
protected function debug($sMsg)
|
||||
{
|
||||
if (DEBUG_UNIT_TEST) {
|
||||
if (is_string($sMsg)) {
|
||||
echo "$sMsg\n";
|
||||
} else {
|
||||
/** @noinspection ForgottenDebugOutputInspection */
|
||||
print_r($sMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function GetMicroTime()
|
||||
{
|
||||
list($uSec, $sec) = explode(" ", microtime());
|
||||
return ((float)$uSec + (float)$sec);
|
||||
}
|
||||
|
||||
public function WriteToCsvHeader($sFilename, $aHeader)
|
||||
{
|
||||
$sResultFile = APPROOT.'log/'.$sFilename;
|
||||
if (is_file($sResultFile))
|
||||
{
|
||||
@unlink($sResultFile);
|
||||
}
|
||||
SetupUtils::builddir(dirname($sResultFile));
|
||||
file_put_contents($sResultFile, implode(';', $aHeader)."\n");
|
||||
}
|
||||
|
||||
public function WriteToCsvData($sFilename, $aData)
|
||||
{
|
||||
$sResultFile = APPROOT.'log/'.$sFilename;
|
||||
$file = fopen($sResultFile, 'a');
|
||||
fputs($file, implode(';', $aData)."\n");
|
||||
fclose($file);
|
||||
}
|
||||
|
||||
public function GetTestId()
|
||||
{
|
||||
$sId = str_replace('"', '', $this->getName());
|
||||
$sId = str_replace(' ', '_', $sId);
|
||||
|
||||
return $sId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.7.4 3.0.0
|
||||
*/
|
||||
public function InvokeNonPublicStaticMethod($sObjectClass, $sMethodName, $aArgs)
|
||||
{
|
||||
return $this->InvokeNonPublicMethod($sObjectClass, $sMethodName, null, $aArgs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sObjectClass for example DBObject::class
|
||||
* @param string $sMethodName
|
||||
* @param object $oObject
|
||||
* @param array $aArgs
|
||||
*
|
||||
* @return mixed method result
|
||||
*
|
||||
* @throws \ReflectionException
|
||||
*
|
||||
* @since 2.7.4 3.0.0
|
||||
*/
|
||||
public function InvokeNonPublicMethod($sObjectClass, $sMethodName, $oObject, $aArgs)
|
||||
{
|
||||
$class = new \ReflectionClass($sObjectClass);
|
||||
$method = $class->getMethod($sMethodName);
|
||||
$method->setAccessible(true);
|
||||
|
||||
return $method->invokeArgs($oObject, $aArgs);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param object $oObject
|
||||
* @param string $sProperty
|
||||
*
|
||||
* @return mixed property
|
||||
*
|
||||
* @throws \ReflectionException
|
||||
* @since 2.7.8 3.0.3 3.1.0
|
||||
*/
|
||||
public function GetNonPublicProperty(object $oObject, string $sProperty)
|
||||
{
|
||||
$class = new \ReflectionClass(get_class($oObject));
|
||||
$property = $class->getProperty($sProperty);
|
||||
$property->setAccessible(true);
|
||||
|
||||
return $property->getValue($oObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object $oObject
|
||||
* @param string $sProperty
|
||||
* @param $value
|
||||
*
|
||||
* @throws \ReflectionException
|
||||
* @since 2.7.8 3.0.3 3.1.0
|
||||
*/
|
||||
public function SetNonPublicProperty(object $oObject, string $sProperty, $value)
|
||||
{
|
||||
$class = new \ReflectionClass(get_class($oObject));
|
||||
$property = $class->getProperty($sProperty);
|
||||
$property->setAccessible(true);
|
||||
|
||||
$property->setValue($oObject, $value);
|
||||
}
|
||||
}
|
||||
6
tests/php-unit-tests/README.md
Normal file
6
tests/php-unit-tests/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# 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".
|
||||
6
tests/php-unit-tests/composer.json
Normal file
6
tests/php-unit-tests/composer.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^8.5.23",
|
||||
"sempro/phpunit-pretty-print": "^1.4"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2020 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;
|
||||
|
||||
|
||||
class DictionariesConsistencyTest extends ItopTestCase
|
||||
{
|
||||
/**
|
||||
* Verify that language declarations match the file names (same language codes)
|
||||
*
|
||||
* @dataProvider DictionaryFileProvider
|
||||
*
|
||||
* @param $sDictFile
|
||||
*/
|
||||
public function testDictionariesLanguage($sDictFile)
|
||||
{
|
||||
$aPrefixToLanguageData = array(
|
||||
'cs' => array('CS CZ', 'Czech', 'Čeština'),
|
||||
'da' => array('DA DA', 'Danish', 'Dansk'),
|
||||
'de' => array('DE DE', 'German', 'Deutsch'),
|
||||
'en' => array('EN US', 'English', 'English'),
|
||||
'es_cr' => array('ES CR', 'Spanish', array(
|
||||
'Español, Castellaño', // old value
|
||||
'Español, Castellano', // new value since N°3635
|
||||
)),
|
||||
'fr' => array('FR FR', 'French', 'Français'),
|
||||
'hu' => array('HU HU', 'Hungarian', 'Magyar'),
|
||||
'it' => array('IT IT', 'Italian', 'Italiano'),
|
||||
'ja' => array('JA JP', 'Japanese', '日本語'),
|
||||
'nl' => array('NL NL', 'Dutch', 'Nederlands'),
|
||||
'pt_br' => array('PT BR', 'Brazilian', 'Brazilian'),
|
||||
'ru' => array('RU RU', 'Russian', 'Русский'),
|
||||
'sk' => array('SK SK', 'Slovak', 'Slovenčina'),
|
||||
'tr' => array('TR TR', 'Turkish', 'Türkçe'),
|
||||
'zh_cn' => array('ZH CN', 'Chinese', '简体中文'),
|
||||
);
|
||||
|
||||
if (!preg_match('/^(.*)\\.dict/', basename($sDictFile), $aMatches))
|
||||
{
|
||||
static::fail("Dictionary file '$sDictFile' not matching the naming convention");
|
||||
}
|
||||
|
||||
$sLangPrefix = $aMatches[1];
|
||||
if (!array_key_exists($sLangPrefix, $aPrefixToLanguageData))
|
||||
{
|
||||
static::fail("Unknown prefix '$sLangPrefix' for dictionary file '$sDictFile'");
|
||||
}
|
||||
|
||||
$sExpectedLanguageCode = $aPrefixToLanguageData[$sLangPrefix][0];
|
||||
$sExpectedEnglishLanguageDesc = $aPrefixToLanguageData[$sLangPrefix][1];
|
||||
$aExpectedLocalizedLanguageDesc = $aPrefixToLanguageData[$sLangPrefix][2];
|
||||
|
||||
$sDictPHP = file_get_contents($sDictFile);
|
||||
if ($iCount = (preg_match_all("@Dict::Add\('(.*)'\s*,\s*'(.*)'\s*,\s*'(.*)'@", $sDictPHP, $aMatches) === false))
|
||||
{
|
||||
static::fail("Pattern not working");
|
||||
}
|
||||
if ($iCount == 0)
|
||||
{
|
||||
// Empty dictionary, that's fine!
|
||||
static::assertTrue(true);
|
||||
}
|
||||
foreach ($aMatches[1] as $sLanguageCode)
|
||||
{
|
||||
static::assertSame($sExpectedLanguageCode, $sLanguageCode,
|
||||
"Unexpected language code for Dict::Add in dictionary $sDictFile");
|
||||
}
|
||||
foreach ($aMatches[2] as $sEnglishLanguageDesc)
|
||||
{
|
||||
static::assertSame($sExpectedEnglishLanguageDesc, $sEnglishLanguageDesc,
|
||||
"Unexpected language description (english) for Dict::Add in dictionary $sDictFile");
|
||||
}
|
||||
foreach ($aMatches[3] as $sLocalizedLanguageDesc)
|
||||
{
|
||||
if (false === is_array($aExpectedLocalizedLanguageDesc)) {
|
||||
$aExpectedLocalizedLanguageDesc = array($aExpectedLocalizedLanguageDesc);
|
||||
}
|
||||
static::assertContains($sLocalizedLanguageDesc,$aExpectedLocalizedLanguageDesc,
|
||||
"Unexpected language description for Dict::Add in dictionary $sDictFile");
|
||||
}
|
||||
}
|
||||
|
||||
public function DictionaryFileProvider()
|
||||
{
|
||||
static::setUp();
|
||||
|
||||
$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
|
||||
);
|
||||
$aTestCases = array();
|
||||
foreach ($aDictFiles as $sDictFile)
|
||||
{
|
||||
$aTestCases[$sDictFile] = array('sDictFile' => $sDictFile);
|
||||
}
|
||||
return $aTestCases;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2020 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 ApplicationException;
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
use iTopDesignFormat;
|
||||
use utils;
|
||||
|
||||
|
||||
/**
|
||||
* @covers iTopDesignFormat
|
||||
*
|
||||
* @package Combodo\iTop\Test\UnitTest\Setup
|
||||
*/
|
||||
class iTopModulesPhpVersionIntegrationTest extends ItopTestCase
|
||||
{
|
||||
/**
|
||||
* Verify if `module.*.php` files contained in `datamodels/1.x` or `datamodels/2.x` refers to the current itop version
|
||||
* This is an integration test
|
||||
*
|
||||
* As ess and pro targets are copying modules into datamodels/2.x this test can only be run on a community target !
|
||||
*
|
||||
* @group itop-community
|
||||
* @group skipPostBuild
|
||||
*
|
||||
* @dataProvider iTopModulesPhpVersionProvider
|
||||
*
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°4714 uses new {@link ITOP_CORE_VERSION} constant
|
||||
*/
|
||||
public function testiTopModulesPhpVersion($sExpectedVersion, $sPhpFile)
|
||||
{
|
||||
|
||||
$sModulePath = realpath($sPhpFile);
|
||||
$sModuleFileName = basename($sModulePath);
|
||||
$sModuleName = preg_replace('/[^.]+\.([^.]+)\.php/', '$1', $sModuleFileName);
|
||||
|
||||
$sFileContent = file_get_contents($sPhpFile);
|
||||
|
||||
preg_match(
|
||||
"#'$sModuleName/([^']+)'#",
|
||||
$sFileContent,
|
||||
$matches
|
||||
);
|
||||
|
||||
$this->assertSame($sExpectedVersion, $matches[1],
|
||||
'Module desc file does not contain the same version as the core: '.$sPhpFile);
|
||||
}
|
||||
|
||||
public function iTopModulesPhpVersionProvider()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
require_once APPROOT.'core/config.class.inc.php';
|
||||
require_once APPROOT.'application/utils.inc.php';
|
||||
|
||||
if (is_dir(APPROOT.'datamodels/2.x')) {
|
||||
$DatamodelsPath = APPROOT.'datamodels/2.x';
|
||||
} elseif (is_dir(APPROOT.'datamodels/1.x')) {
|
||||
$DatamodelsPath = APPROOT.'datamodels/1.x';
|
||||
} else {
|
||||
throw new \Exception('Cannot local the datamodels directory');
|
||||
}
|
||||
|
||||
$sPath = $DatamodelsPath.'/*/module.*.php';
|
||||
$aPhpFiles = glob($sPath);
|
||||
|
||||
$sExpectedVersion = ITOP_CORE_VERSION;
|
||||
|
||||
$aTestCases = array();
|
||||
foreach ($aPhpFiles as $sPhpFile) {
|
||||
$aTestCases[$sPhpFile] = array(
|
||||
'sExpectedVersion' => $sExpectedVersion,
|
||||
'sPhpFile' => $sPhpFile,
|
||||
);
|
||||
}
|
||||
|
||||
return $aTestCases;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider ItopWikiVersionProvider
|
||||
* @since 2.7.7 3.0.1 3.1.1 N°4714 new ITOP_CORE_VERSION constant
|
||||
*/
|
||||
public function testItopWikiVersion($sItopVersion, $sExpectedWikiVersion) {
|
||||
try {
|
||||
$sActualWikiVersion = utils::GetItopVersionWikiSyntax($sItopVersion);
|
||||
}
|
||||
catch (ApplicationException $e) {
|
||||
self::fail('Cannot get wiki version : '.$e->getMessage());
|
||||
}
|
||||
self::assertSame($sExpectedWikiVersion, $sActualWikiVersion, 'Computed wiki version is wrong !');
|
||||
}
|
||||
|
||||
public function ItopWikiVersionProvider()
|
||||
{
|
||||
return [
|
||||
['2.7.0', '2_7_0'],
|
||||
['2.7.7', '2_7_0'],
|
||||
['3.0.0', '3_0_0'],
|
||||
['3.0.1', '3_0_0'],
|
||||
['3.1.0', '3_1_0'],
|
||||
['3.1.1', '3_1_0'],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2020 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 DOMDocument;
|
||||
use iTopDesignFormat;
|
||||
|
||||
|
||||
/**
|
||||
* @covers iTopDesignFormat
|
||||
*
|
||||
* @package Combodo\iTop\Test\UnitTest\Setup
|
||||
*/
|
||||
class iTopModulesXmlVersionIntegrationTest extends ItopTestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
require_once APPROOT.'setup/itopdesignformat.class.inc.php';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Verify if the `datamodels/2.x/datamodel.*.xml` files refer to the latest version of the design
|
||||
* This is an integration test
|
||||
*
|
||||
* As ess and pro targets are copying modules into datamodels/2.x this test can only be run on a community target !
|
||||
*
|
||||
* @group itop-community
|
||||
* @group skipPostBuild
|
||||
*
|
||||
* @dataProvider DatamodelItopXmlVersionProvider
|
||||
*/
|
||||
public function testDatamodelItopXmlVersion($sXmlFile)
|
||||
{
|
||||
$oOriginalXml = new DOMDocument();
|
||||
$oOriginalXml->load($sXmlFile);
|
||||
|
||||
$oTransformedXml = new DOMDocument();
|
||||
$oTransformedXml->load($sXmlFile);
|
||||
$oFormat = new iTopDesignFormat($oTransformedXml);
|
||||
|
||||
if ($oFormat->Convert()) {
|
||||
// Compare the original and new format
|
||||
$sExpectedXmlVersion = ITOP_DESIGN_LATEST_VERSION;
|
||||
$this->assertSame($oTransformedXml->saveXML(), $oOriginalXml->saveXML(),
|
||||
"Datamodel file $sXmlFile:2 not in the latest format ($sExpectedXmlVersion)");
|
||||
} else {
|
||||
$this->fail("Failed to convert $sXmlFile into the latest format");
|
||||
}
|
||||
}
|
||||
|
||||
public function DatamodelItopXmlVersionProvider()
|
||||
{
|
||||
static::setUp();
|
||||
|
||||
$sPath = APPROOT.'datamodels/2.x/*/datamodel.*.xml';
|
||||
$aXmlFiles = glob($sPath);
|
||||
|
||||
$aXmlFiles[] = APPROOT.'core/datamodel.core.xml';
|
||||
$aXmlFiles[] = APPROOT.'application/datamodel.application.xml';
|
||||
|
||||
$aTestCases = array();
|
||||
foreach ($aXmlFiles as $sXmlFile) {
|
||||
$aTestCases[$sXmlFile] = array(
|
||||
'sXmlFile' => $sXmlFile,
|
||||
);
|
||||
}
|
||||
|
||||
return $aTestCases;
|
||||
}
|
||||
|
||||
}
|
||||
343
tests/php-unit-tests/legacy-tests/GroupByAndFunctions.php
Normal file
343
tests/php-unit-tests/legacy-tests/GroupByAndFunctions.php
Normal file
@@ -0,0 +1,343 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2019 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
|
||||
*/
|
||||
|
||||
require_once ('../../../approot.inc.php');
|
||||
require_once(APPROOT.'application/application.inc.php');
|
||||
require_once(APPROOT.'application/itopwebpage.class.inc.php');
|
||||
require_once(APPROOT.'application/startup.inc.php');
|
||||
require_once(APPROOT.'application/loginwebpage.class.inc.php');
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// Main program
|
||||
//
|
||||
LoginWebPage::DoLogin(true); // Check user rights and prompt if needed
|
||||
|
||||
|
||||
$sSubmit = utils::ReadParam('submit', '', false, 'raw_data');
|
||||
if ($sSubmit != 'Reset')
|
||||
{
|
||||
$sOQL = utils::ReadParam('OQL_Request', '', false, 'raw_data');
|
||||
}
|
||||
else
|
||||
{
|
||||
$sOQL = '';
|
||||
}
|
||||
$bError = false;
|
||||
$oP = new iTopWebPage('Database inconsistencies');
|
||||
$oP->set_base(utils::GetAbsoluteUrlAppRoot().'tests/');
|
||||
$oP->set_title('Grouping with functions');
|
||||
$oP->add('<div style="padding: 15px;"><h2>Grouping with functions</h2>');
|
||||
$oP->add('<div style="padding: 15px; background: #ddd;">');
|
||||
try
|
||||
{
|
||||
if (!empty($sOQL))
|
||||
{
|
||||
// Getting class attributes
|
||||
$oSearch = DBSearch::FromOQL($sOQL);
|
||||
$aSearches = $oSearch->GetSearches();
|
||||
if ($oSearch instanceof DBUnionSearch)
|
||||
{
|
||||
$sClass = $aSearches[0]->GetClassAlias();
|
||||
$sRealClass = $aSearches[0]->GetClass();
|
||||
}
|
||||
else
|
||||
{
|
||||
$sClass = $oSearch->GetClassAlias();
|
||||
$sRealClass = $oSearch->GetClass();
|
||||
}
|
||||
|
||||
$sGroupBy1 = utils::ReadParam('groupby_1', '');
|
||||
$sGroupBy2 = utils::ReadParam('groupby_2', '');
|
||||
$sOrderBy1 = utils::ReadParam('orderby_1', '');
|
||||
$sOrderBy2 = utils::ReadParam('orderby_2', '');
|
||||
|
||||
$sAttributesOptions1 = '';
|
||||
$sAttributesOptions2 = '';
|
||||
$sAttributesOptions3 = '';
|
||||
$sAttributesOptions4 = '';
|
||||
|
||||
foreach(array('_itop_sum_', '_itop_avg_', '_itop_min_', '_itop_max_', '_itop_count_', 'group1', 'group2') as $sAttCode)
|
||||
{
|
||||
$sAttributesOptions3 .= '<option value="'.$sAttCode.'" '.($sOrderBy1 == $sAttCode ? 'selected' : '').'>'.$sAttCode.'</option>';
|
||||
$sAttributesOptions4 .= '<option value="'.$sAttCode.'" '.($sOrderBy2 == $sAttCode ? 'selected' : '').'>'.$sAttCode.'</option>';
|
||||
}
|
||||
|
||||
foreach(MetaModel::ListAttributeDefs($sRealClass) as $sAttCode => $oAttDef)
|
||||
{
|
||||
// Skip this attribute if not defined in this table
|
||||
if ($oSearch instanceof DBUnionSearch)
|
||||
{
|
||||
foreach($aSearches as $oSubQuery)
|
||||
{
|
||||
$sSubClass = $oSubQuery->GetClass();
|
||||
if (!MetaModel::IsValidAttCode($sSubClass, $sAttCode))
|
||||
{
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
$sAttributesOptions1 .= '<option value="'.$sAttCode.'" '.($sGroupBy1 == $sAttCode ? 'selected' : '').'>'.$sAttCode.'</option>';
|
||||
$sAttributesOptions2 .= '<option value="'.$sAttCode.'" '.($sGroupBy2 == $sAttCode ? 'selected' : '').'>'.$sAttCode.'</option>';
|
||||
}
|
||||
|
||||
$iLimit = intval(utils::ReadParam('top', '0'));
|
||||
|
||||
$sInvOrder1 = utils::ReadParam('desc1', '');
|
||||
$sCheck1 = ($sInvOrder1 == 'on' ? 'checked' : '');
|
||||
|
||||
$sInvOrder2 = utils::ReadParam('desc2', '');
|
||||
$sCheck2 = ($sInvOrder2 == 'on' ? 'checked' : '');
|
||||
|
||||
$sFuncField = utils::ReadParam('funcfield', '');
|
||||
|
||||
$sFuncFieldOption = '';
|
||||
foreach(MetaModel::ListAttributeDefs($sRealClass) as $sAttCode => $oAttDef)
|
||||
{
|
||||
// Skip this attribute if not defined in this table
|
||||
if ($oSearch instanceof DBUnionSearch)
|
||||
{
|
||||
foreach($aSearches as $oSubQuery)
|
||||
{
|
||||
$sSubClass = $oSubQuery->GetClass();
|
||||
if (!MetaModel::IsValidAttCode($sSubClass, $sAttCode))
|
||||
{
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (get_class($oAttDef))
|
||||
{
|
||||
case 'Integer':
|
||||
case 'AttributeDecimal':
|
||||
case 'AttributeDuration':
|
||||
case 'AttributeSubItem':
|
||||
case 'AttributePercentage':
|
||||
$sFuncFieldOption .= '<option value="'.$sAttCode.'" '.($sFuncField == $sAttCode ? 'selected' : '').'>'.$sAttCode.'</option>';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
$oP->p('<div class="header_message message_error">'.$e->getMessage().'</div>');
|
||||
$bError = true;
|
||||
}
|
||||
$oP->add("<div><form>");
|
||||
$oP->add("<input type=\"submit\" name=\"submit\" value=\"Reset\">\n");
|
||||
$oP->add("</form></div>");
|
||||
|
||||
$oP->add("<form>");
|
||||
|
||||
$oP->add(
|
||||
<<<EOF
|
||||
<div>
|
||||
<label>Search OQL:</label>
|
||||
<div>
|
||||
<textarea id='OQL_Request' name='OQL_Request' cols='60' rows='5'>$sOQL</textarea>
|
||||
</div>
|
||||
</div>
|
||||
EOF
|
||||
);
|
||||
|
||||
if (!empty($sOQL) && !$bError)
|
||||
{
|
||||
$oP->add(
|
||||
<<<EOF
|
||||
<div>
|
||||
<label>Group by:</label>
|
||||
<div>
|
||||
<select id="groupby_1" name="groupby_1">
|
||||
$sAttributesOptions1
|
||||
</select>
|
||||
<select id="groupby_2" name="groupby_2">
|
||||
<option></option>
|
||||
$sAttributesOptions2
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label>Order by:</label>
|
||||
<div>
|
||||
<select id="orderby_1" name="orderby_1">$sAttributesOptions3</select>
|
||||
<label>Inv order</label><input type="checkbox" name="desc1" $sCheck1/>
|
||||
</div>
|
||||
<div>
|
||||
<select id="orderby_2" name="orderby_2">
|
||||
<option></option>
|
||||
$sAttributesOptions4
|
||||
</select>
|
||||
<label>Inv order</label><input type="checkbox" name="desc2" $sCheck2/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label>Functions on:</label>
|
||||
<div>
|
||||
<select id="funcfield" name="funcfield">$sFuncFieldOption</select>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label>Top:</label>
|
||||
<div><input type="text" id="top" name="top" value="$iLimit"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
$oP->add("<input type=\"submit\" name=\"submit\" value=\"Search\">\n");
|
||||
|
||||
$oP->add("</form>");
|
||||
|
||||
$sSQL = '';
|
||||
|
||||
|
||||
if (empty($sOQL) || empty($sGroupBy1))
|
||||
{
|
||||
$oP->output();
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
$iLimitStart = 0;
|
||||
$aOrderBy = array();
|
||||
if (!empty($sOrderBy1))
|
||||
{
|
||||
$aOrderBy[$sOrderBy1] = ($sInvOrder1 != 'on');
|
||||
}
|
||||
if (!empty($sOrderBy2))
|
||||
{
|
||||
$aOrderBy[$sOrderBy2] = ($sInvOrder2 != 'on');
|
||||
}
|
||||
|
||||
$aGroupBy = array();
|
||||
$oExpr1 = Expression::FromOQL($sClass.'.'.$sGroupBy1);
|
||||
$aGroupBy["group1"] = $oExpr1;
|
||||
|
||||
if (!empty($sGroupBy2))
|
||||
{
|
||||
$oExpr2 = Expression::FromOQL($sClass.'.'.$sGroupBy2);
|
||||
$aGroupBy["group2"] = $oExpr2;
|
||||
}
|
||||
|
||||
$aArgs = array();
|
||||
|
||||
if (empty($sFuncField))
|
||||
{
|
||||
$aFunctions = array();
|
||||
}
|
||||
else
|
||||
{
|
||||
$oTimeExpr = Expression::FromOQL($sClass.'.'.$sFuncField);
|
||||
$oSumExpr = new FunctionExpression('SUM', array($oTimeExpr));
|
||||
$oAvgExpr = new FunctionExpression('AVG', array($oTimeExpr));
|
||||
$oMinExpr = new FunctionExpression('MIN', array($oTimeExpr));
|
||||
$oMaxExpr = new FunctionExpression('MAX', array($oTimeExpr));
|
||||
// Alias => Expression
|
||||
$aFunctions = array(
|
||||
'_itop_sum_' => $oSumExpr,
|
||||
'_itop_avg_' => $oAvgExpr,
|
||||
'_itop_min_' => $oMinExpr,
|
||||
'_itop_max_' => $oMaxExpr,
|
||||
);
|
||||
}
|
||||
|
||||
$sSQL = $oSearch->MakeGroupByQuery($aArgs, $aGroupBy, false, $aFunctions, $aOrderBy, $iLimit, $iLimitStart);
|
||||
|
||||
$aRes = CMDBSource::QueryToArray($sSQL);
|
||||
|
||||
// Display results
|
||||
if (!empty($aRes))
|
||||
{
|
||||
$oP->add('<div>');
|
||||
$oP->add('<table class="listResults">');
|
||||
$aLine = $aRes[0];
|
||||
$aCols = array();
|
||||
$oP->add('<tr>');
|
||||
foreach(array_keys($aLine) as $item)
|
||||
{
|
||||
if (!is_numeric($item))
|
||||
{
|
||||
$aCols[] = $item;
|
||||
$oP->add("<th>$item</th>");
|
||||
}
|
||||
}
|
||||
$oP->add('</tr>');
|
||||
|
||||
foreach($aRes as $aLine)
|
||||
{
|
||||
$oP->add('<tr>');
|
||||
foreach($aCols as $sCol)
|
||||
{
|
||||
$oP->add("<td>".$aLine[$sCol]."</td>");
|
||||
}
|
||||
$oP->add('</tr>');
|
||||
}
|
||||
|
||||
$oP->add('</table>');
|
||||
$oP->add('</div>');
|
||||
}
|
||||
else
|
||||
{
|
||||
$oP->add("<p>No Result</p>\n");
|
||||
}
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
$oP->p('<div class="header_message message_error">'.$e->getMessage().'</div>');
|
||||
$bError = true;
|
||||
}
|
||||
|
||||
$oP->add("<div class=\"header_message message_info\">$sSQL</div>\n");
|
||||
|
||||
$oP->output();
|
||||
|
||||
return;
|
||||
|
||||
/*
|
||||
echo "<pre>";
|
||||
$aClassSelection = MetaModel::GetClasses();
|
||||
foreach($aClassSelection as $sClass)
|
||||
{
|
||||
if (!MetaModel::HasTable($sClass))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
|
||||
{
|
||||
// Skip this attribute if not defined in this table
|
||||
if (!MetaModel::IsAttributeOrigin($sClass, $sAttCode))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
switch (get_class($oAttDef))
|
||||
{
|
||||
case 'Integer':
|
||||
case 'AttributeDecimal':
|
||||
case 'AttributeDuration':
|
||||
case 'AttributeSubItem':
|
||||
case 'AttributePercentage':
|
||||
echo "$sClass:$sAttCode = ".get_class($oAttDef)."\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
1
tests/php-unit-tests/legacy-tests/README.md
Normal file
1
tests/php-unit-tests/legacy-tests/README.md
Normal file
@@ -0,0 +1 @@
|
||||
Tests in this folder have been written before the introduction of PHPUnit in iTop, they are not run by the CI.
|
||||
287
tests/php-unit-tests/legacy-tests/VerifyOQL.php
Normal file
287
tests/php-unit-tests/legacy-tests/VerifyOQL.php
Normal file
@@ -0,0 +1,287 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2019 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Copyright (C) 2013-2019 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
|
||||
*/
|
||||
|
||||
require_once('../../../approot.inc.php');
|
||||
require_once(APPROOT.'/application/application.inc.php');
|
||||
require_once(APPROOT.'/application/itopwebpage.class.inc.php');
|
||||
require_once(APPROOT.'/application/startup.inc.php');
|
||||
require_once(APPROOT.'/application/loginwebpage.class.inc.php');
|
||||
|
||||
LoginWebPage::DoLogin(); // Check user rights and prompt if needed
|
||||
ApplicationMenu::CheckMenuIdEnabled('RunQueriesMenu');
|
||||
|
||||
function ShowExamples($oP, $sExpression)
|
||||
{
|
||||
$bUsingExample = false;
|
||||
|
||||
$aExamples = array(
|
||||
'Pedagogic examples' => array(
|
||||
"Web applications" => "SELECT WebApplication",
|
||||
"Person having an 'A' in their name" => "SELECT Person AS B WHERE B.name LIKE '%A%'",
|
||||
"Servers having a name like dbserver1.demo.com or dbserver023.foo.fr" => "SELECT Server WHERE name REGEXP '^dbserver[0-9]+\\\\..+\\\\.[a-z]{2,3}$'",
|
||||
"Changes planned on new year's day" => "SELECT Change AS ch WHERE ch.start_date >= '2009-12-31' AND ch.end_date <= '2010-01-01'",
|
||||
"IPs in a range" => "SELECT DatacenterDevice AS dev WHERE INET_ATON(dev.managementip) > INET_ATON('10.22.32.224') AND INET_ATON(dev.managementip) < INET_ATON('10.22.32.255')",
|
||||
"Persons below a given root organization" => "SELECT Person AS P JOIN Organization AS Node ON P.org_id = Node.id JOIN Organization AS Root ON Node.parent_id BELOW Root.id WHERE Root.id=1",
|
||||
),
|
||||
'Usefull examples' => array(
|
||||
"NW interfaces of equipment in production for customer 'Demo'" => "SELECT PhysicalInterface AS if JOIN DatacenterDevice AS dev ON if.connectableci_id = dev.id WHERE dev.status = 'production' AND dev.organization_name = 'Demo'",
|
||||
"My tickets" => "SELECT Ticket AS t WHERE t.agent_id = :current_contact_id",
|
||||
"People being owner of an active ticket" => "SELECT Person AS p JOIN UserRequest AS u ON u.agent_id = p.id WHERE u.status != 'closed'",
|
||||
"Contracts terminating in the next thirty days" => "SELECT Contract AS c WHERE c.end_date > NOW() AND c.end_date < DATE_ADD(NOW(), INTERVAL 30 DAY)",
|
||||
"Orphan tickets (opened one hour ago, still not assigned)" => "SELECT UserRequest AS u WHERE u.start_date < DATE_SUB(NOW(), INTERVAL 60 MINUTE) AND u.status = 'new'",
|
||||
"Long lasting incidents (duration > 8 hours)" => "SELECT UserRequest AS u WHERE u.close_date > DATE_ADD(u.start_date, INTERVAL 8 HOUR)",
|
||||
),
|
||||
);
|
||||
|
||||
$aDisplayData = array();
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sContext = $oAppContext->GetForForm();
|
||||
foreach ($aExamples as $sTopic => $aQueries)
|
||||
{
|
||||
foreach ($aQueries as $sDescription => $sOql)
|
||||
{
|
||||
$sHighlight = '';
|
||||
$sDisable = '';
|
||||
if ($sOql == $sExpression)
|
||||
{
|
||||
// this one is currently being tested, highlight it
|
||||
$sHighlight = "background-color:yellow;";
|
||||
$sDisable = 'disabled';
|
||||
// and remember we are testing a query of the list
|
||||
$bUsingExample = true;
|
||||
}
|
||||
//$aDisplayData[$sTopic][] = array(
|
||||
$aDisplayData[Dict::S('UI:RunQuery:QueryExamples')][] = array(
|
||||
'desc' => "<div style=\"$sHighlight\">".htmlentities($sDescription, ENT_QUOTES, 'UTF-8')."</div>",
|
||||
'oql' => "<div style=\"$sHighlight\">".htmlentities($sOql, ENT_QUOTES, 'UTF-8')."</div>",
|
||||
'go' => "<form method=\"get\"><input type=\"hidden\" name=\"expression\" value=\"$sOql\"><input type=\"submit\" value=\"".Dict::S('UI:Button:Test')."\" $sDisable>$sContext</form>\n",
|
||||
);
|
||||
}
|
||||
}
|
||||
$aDisplayConfig = array();
|
||||
$aDisplayConfig['desc'] = array('label' => Dict::S('UI:RunQuery:HeaderPurpose'), 'description' => Dict::S('UI:RunQuery:HeaderPurpose+'));
|
||||
$aDisplayConfig['oql'] = array('label' => Dict::S('UI:RunQuery:HeaderOQLExpression'), 'description' => Dict::S('UI:RunQuery:HeaderOQLExpression+'));
|
||||
$aDisplayConfig['go'] = array('label' => '', 'description' => '');
|
||||
|
||||
foreach ($aDisplayData as $sTopic => $aQueriesDisplayData)
|
||||
{
|
||||
$bShowOpened = $bUsingExample;
|
||||
$oP->StartCollapsibleSection($sTopic, $bShowOpened);
|
||||
$oP->table($aDisplayConfig, $aQueriesDisplayData);
|
||||
$oP->EndCollapsibleSection();
|
||||
}
|
||||
}
|
||||
|
||||
$sOperation = utils::ReadParam('operation', 'menu');
|
||||
$oAppContext = new ApplicationContext();
|
||||
|
||||
$oP = new iTopWebPage(Dict::S('UI:RunQuery:Title'));
|
||||
$oP->SetBreadCrumbEntry('ui-tool-runquery', Dict::S('Menu:RunQueriesMenu'), Dict::S('Menu:RunQueriesMenu+'), '', utils::GetAbsoluteUrlAppRoot().'images/wrench.png');
|
||||
|
||||
// Main program
|
||||
$sExpression = utils::ReadParam('expression', '', false, 'raw_data');
|
||||
$sEncoding = utils::ReadParam('encoding', 'oql');
|
||||
|
||||
ShowExamples($oP, $sExpression);
|
||||
|
||||
try
|
||||
{
|
||||
if ($sEncoding == 'crypted')
|
||||
{
|
||||
// Translate $sExpression into a oql expression
|
||||
$sClearText = base64_decode($sExpression);
|
||||
echo "<strong>FYI: '$sClearText'</strong><br/>\n";
|
||||
$oFilter = DBObjectSearch::unserialize($sExpression);
|
||||
$sExpression = $oFilter->ToOQL();
|
||||
}
|
||||
|
||||
$oFilter = null;
|
||||
$aArgs = array();
|
||||
$sSyntaxError = null;
|
||||
|
||||
if (!empty($sExpression))
|
||||
{
|
||||
try
|
||||
{
|
||||
$oFilter = DBObjectSearch::FromOQL($sExpression);
|
||||
} catch (Exception $e)
|
||||
{
|
||||
if ($e instanceof OqlException)
|
||||
{
|
||||
$sSyntaxError = $e->getHtmlDesc();
|
||||
}
|
||||
else
|
||||
{
|
||||
$sSyntaxError = $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
if ($oFilter)
|
||||
{
|
||||
$aArgs = array();
|
||||
foreach ($oFilter->GetQueryParams() as $sParam => $foo)
|
||||
{
|
||||
$value = utils::ReadParam('arg_'.$sParam, null, true, 'raw_data');
|
||||
if (!is_null($value))
|
||||
{
|
||||
$aArgs[$sParam] = $value;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aArgs[$sParam] = '';
|
||||
}
|
||||
}
|
||||
$oFilter->SetInternalParams($aArgs);
|
||||
}
|
||||
}
|
||||
|
||||
$oP->add("<form method=\"post\">\n");
|
||||
$oP->add(Dict::S('UI:RunQuery:ExpressionToEvaluate')."<br/>\n");
|
||||
$oP->add("<textarea cols=\"120\" rows=\"8\" id=\"expression\" name=\"expression\">".htmlentities($sExpression, ENT_QUOTES, 'UTF-8')."</textarea>\n");
|
||||
$oP->add_linked_script(utils::GetAbsoluteUrlAppRoot()."/js/jquery.hotkeys.js");
|
||||
$oP->add_ready_script(<<<EOF
|
||||
$("#expression").select();
|
||||
$("#expression").on("keydown", null, "ctrl+return", function() {
|
||||
$(this).closest("form").submit();
|
||||
});
|
||||
EOF
|
||||
);
|
||||
|
||||
if (count($aArgs) > 0)
|
||||
{
|
||||
$oP->add("<div class=\"wizContainer\">\n");
|
||||
$oP->add("<h3>Query arguments</h3>\n");
|
||||
foreach ($aArgs as $sParam => $sValue)
|
||||
{
|
||||
$oP->p("$sParam: <input type=\"string\" name=\"arg_$sParam\" value=\"$sValue\">\n");
|
||||
}
|
||||
$oP->add("</div>\n");
|
||||
}
|
||||
|
||||
$oP->add("<input type=\"submit\" value=\"".Dict::S('UI:Button:Evaluate')."\" title=\"".Dict::S('UI:Button:Evaluate:Title')."\">\n");
|
||||
$oP->add($oAppContext->GetForForm());
|
||||
$oP->add("</form>\n");
|
||||
|
||||
|
||||
if ($oFilter)
|
||||
{
|
||||
$oP->add("<h3>Query results</h3>\n");
|
||||
|
||||
$oResultBlock = new DisplayBlock($oFilter, 'list', false);
|
||||
$oResultBlock->Display($oP, 'runquery');
|
||||
|
||||
// Breadcrumb
|
||||
//$iCount = $oResultBlock->GetDisplayedCount();
|
||||
$sPageId = "ui-search-".$oFilter->GetClass();
|
||||
$sLabel = MetaModel::GetName($oFilter->GetClass());
|
||||
$aArgs = array();
|
||||
foreach (array_merge($_POST, $_GET) as $sKey => $value)
|
||||
{
|
||||
if (is_array($value))
|
||||
{
|
||||
$aItems = array();
|
||||
foreach ($value as $sItemKey => $sItemValue)
|
||||
{
|
||||
$aArgs[] = $sKey.'['.$sItemKey.']='.urlencode($sItemValue);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$aArgs[] = $sKey.'='.urlencode($value);
|
||||
}
|
||||
}
|
||||
$sUrl = utils::GetAbsoluteUrlAppRoot().'pages/run_query.php?'.implode('&', $aArgs);
|
||||
$oP->SetBreadCrumbEntry($sPageId, $sLabel, $oFilter->ToOQL(true), $sUrl, '../images/breadcrumb-search.png');
|
||||
|
||||
$oP->p('');
|
||||
$oP->StartCollapsibleSection(Dict::S('UI:RunQuery:MoreInfo'), false, 'runQuery');
|
||||
$oP->p('<pre>'.$oFilter->ToOQL().'</pre>');
|
||||
$oP->EndCollapsibleSection();
|
||||
|
||||
$aModifierProperties = MetaModel::MakeModifierProperties($oFilter);
|
||||
|
||||
$oP->StartCollapsibleSection('OQL Developed');
|
||||
$oSQLObjectQueryBuilder = new SQLObjectQueryBuilder($oFilter);
|
||||
$oBuild = new QueryBuilderContext($oFilter, $aModifierProperties);
|
||||
$oP->p('<pre>'.$oSQLObjectQueryBuilder->DebugOQLClassTree($oBuild).'</pre>');
|
||||
$oP->EndCollapsibleSection();
|
||||
|
||||
$oP->StartCollapsibleSection('SQL Count');
|
||||
$oSQLObjectQueryBuilder = new SQLObjectQueryBuilder($oFilter);
|
||||
$oBuild = new QueryBuilderContext($oFilter, $aModifierProperties);
|
||||
$oSQLQueryCount = $oSQLObjectQueryBuilder->BuildSQLQueryStruct(null, true, $aModifierProperties);
|
||||
$oP->p('<pre>'.$oSQLQueryCount->RenderSelect(array(), array(), 0, 0, true, true).'</pre>');
|
||||
$oP->EndCollapsibleSection();
|
||||
|
||||
$oP->StartCollapsibleSection('SQL');
|
||||
$oSQLObjectQueryBuilder = new SQLObjectQueryBuilder($oFilter);
|
||||
$oBuild = new QueryBuilderContext($oFilter, $aModifierProperties);
|
||||
$oSQLQuery = $oSQLObjectQueryBuilder->BuildSQLQueryStruct(null, false, $aModifierProperties);
|
||||
$oP->p('<pre>'.$oSQLQuery->RenderSelect(array(), array(), 10, 0, false, true).'</pre>');
|
||||
$oP->EndCollapsibleSection();
|
||||
|
||||
}
|
||||
elseif ($sSyntaxError)
|
||||
{
|
||||
if ($e instanceof OqlException)
|
||||
{
|
||||
$sWrongWord = $e->GetWrongWord();
|
||||
$aSuggestedWords = $e->GetSuggestions();
|
||||
if (count($aSuggestedWords) > 0)
|
||||
{
|
||||
$sSuggestedWord = OqlException::FindClosestString($sWrongWord, $aSuggestedWords);
|
||||
|
||||
if (strlen($sSuggestedWord) > 0)
|
||||
{
|
||||
$oP->p('<b>'.Dict::Format('UI:RunQuery:Error', $e->GetIssue().' <em>'.$sWrongWord).'</em></b>');
|
||||
$sBefore = substr($sExpression, 0, $e->GetColumn());
|
||||
$sAfter = substr($sExpression, $e->GetColumn() + strlen($sWrongWord));
|
||||
$sFixedExpression = $sBefore.$sSuggestedWord.$sAfter;
|
||||
$sFixedExpressionHtml = $sBefore.'<span style="background-color:yellow">'.$sSuggestedWord.'</span>'.$sAfter;
|
||||
$oP->p("Suggesting: $sFixedExpressionHtml");
|
||||
$oP->add('<button onClick="$(\'textarea[name=expression]\').val(\''.htmlentities(addslashes($sFixedExpression)).'\');">Use this query</button>');
|
||||
}
|
||||
else
|
||||
{
|
||||
$oP->p('<b>'.Dict::Format('UI:RunQuery:Error', $e->getHtmlDesc()).'</b>');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$oP->p('<b>'.Dict::Format('UI:RunQuery:Error', $e->getHtmlDesc()).'</b>');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$oP->p('<b>'.Dict::Format('UI:RunQuery:Error', $e->getMessage()).'</b>');
|
||||
}
|
||||
}
|
||||
} catch (Exception $e)
|
||||
{
|
||||
$oP->p('<b>'.Dict::Format('UI:RunQuery:Error', $e->getMessage()).'</b>');
|
||||
}
|
||||
|
||||
$oP->output();
|
||||
|
||||
863
tests/php-unit-tests/legacy-tests/benchmark.php
Normal file
863
tests/php-unit-tests/legacy-tests/benchmark.php
Normal file
@@ -0,0 +1,863 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2019 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
|
||||
*/
|
||||
|
||||
require_once('../../../approot.inc.php');
|
||||
require_once(APPROOT.'/application/application.inc.php');
|
||||
require_once(APPROOT.'/application/itopwebpage.class.inc.php');
|
||||
require_once(APPROOT.'/application/wizardhelper.class.inc.php');
|
||||
require_once(APPROOT.'/application/startup.inc.php');
|
||||
require_once(APPROOT.'/application/loginwebpage.class.inc.php');
|
||||
require_once(APPROOT.'/application/utils.inc.php');
|
||||
require_once(APPROOT.'/setup/setuppage.class.inc.php');
|
||||
|
||||
//ini_set('memory_limit', '2048M');
|
||||
|
||||
class BenchmarkDataCreation
|
||||
{
|
||||
var $m_iIfByServer;
|
||||
var $m_iIfByNWDevice;
|
||||
var $m_aRequested;
|
||||
var $m_aPlanned;
|
||||
var $m_aCreatedByClass = array();
|
||||
var $m_aCreatedByDesc = array();
|
||||
|
||||
var $m_aStatsByClass = array();
|
||||
|
||||
/** @var \CMDBChange $m_oChange */
|
||||
var $m_oChange;
|
||||
public function __construct()
|
||||
{
|
||||
CMDBObject::SetTrackInfo('Benchmark setup');
|
||||
}
|
||||
|
||||
public function PlanStructure($iPlannedContacts, $iPlannedContracts)
|
||||
{
|
||||
$this->m_aRequested = array(
|
||||
'plannedcontacts' => $iPlannedContacts,
|
||||
'plannedcontracts' => $iPlannedContracts,
|
||||
);
|
||||
$this->m_aPlanned = array(
|
||||
'Contacts' => $iPlannedContacts,
|
||||
'Contracts' => $iPlannedContracts,
|
||||
'Documents' => $iPlannedContracts * 2,
|
||||
);
|
||||
}
|
||||
|
||||
public function PlanCis($iPlannedCIs)
|
||||
{
|
||||
$this->m_aRequested = array(
|
||||
'plannedcis' => $iPlannedCIs,
|
||||
);
|
||||
|
||||
$this->m_iIfByServer = 2;
|
||||
$this->m_iIfByNWDevice = 10;
|
||||
|
||||
$iServers = ceil($iPlannedCIs * 9 / 10);
|
||||
$iNWDevices = ceil($iPlannedCIs / 10);
|
||||
$iInterfaces = $iServers * $this->m_iIfByServer + $iNWDevices * $this->m_iIfByNWDevice;
|
||||
$iApplications = $iServers * 5;
|
||||
$iSolutions = ceil($iApplications / 2);
|
||||
$iProcesses = ceil($iSolutions / 2);
|
||||
|
||||
$this->m_aPlanned = array(
|
||||
'Network devices' => $iNWDevices,
|
||||
'Servers' => $iServers,
|
||||
'Interfaces' => $iInterfaces,
|
||||
'Application SW' => 2,
|
||||
'Applications' => $iApplications,
|
||||
'Solutions' => $iSolutions,
|
||||
'Processes' => $iProcesses,
|
||||
);
|
||||
}
|
||||
|
||||
public function PlanTickets($iPlannedTickets, $iBigTicketCis)
|
||||
{
|
||||
$this->m_aRequested = array(
|
||||
'plannedtickets' => $iPlannedTickets,
|
||||
'plannedbigticketcis' => $iBigTicketCis,
|
||||
);
|
||||
|
||||
$this->m_aPlanned = array(
|
||||
'Incidents' => ceil($iPlannedTickets / 2),
|
||||
'Changes' => ceil($iPlannedTickets / 2),
|
||||
'Big ticket: CIs' => $iBigTicketCis,
|
||||
);
|
||||
}
|
||||
|
||||
public function ShowPlans($oP)
|
||||
{
|
||||
$oP->add("<h2>Planned creations</h2>\n");
|
||||
$aPlanned = $this->m_aPlanned;
|
||||
$aForm = array();
|
||||
foreach ($aPlanned as $sKey => $iCount)
|
||||
{
|
||||
$aForm[] = array(
|
||||
'label' => $sKey,
|
||||
'input' => $iCount,
|
||||
);
|
||||
}
|
||||
$oP->form($aForm);
|
||||
}
|
||||
|
||||
public function ShowForm($oP, $sNextOperation)
|
||||
{
|
||||
$aRequested = $this->m_aRequested;
|
||||
$oP->add("<form method=\"post\" onSubmit=\"return DoSubmit('Loading data...', 10)\">\n");
|
||||
$oP->add("<input type=\"hidden\" name=\"operation\" value=\"$sNextOperation\">\n");
|
||||
foreach($this->m_aRequested as $sName => $sValue)
|
||||
{
|
||||
$oP->add("<input type=\"hidden\" name=\"$sName\" value=\"$sValue\">\n");
|
||||
}
|
||||
$oP->add("<button type=\"submit\">Next >></button>\n");
|
||||
$oP->add("</form>\n");
|
||||
}
|
||||
|
||||
protected function CreateObject($sClass, $aData, $sClassDesc = '')
|
||||
{
|
||||
$mu_t1 = MyHelpers::getmicrotime();
|
||||
|
||||
$oMyObject = MetaModel::NewObject($sClass);
|
||||
foreach($aData as $sProp => $value)
|
||||
{
|
||||
if (is_array($value))
|
||||
{
|
||||
// transform into a link set
|
||||
$sCSVSpec = implode('|', $value);
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sProp);
|
||||
$value = $oAttDef->MakeValueFromString($sCSVSpec, $bLocalizedValue = false, $sSepItem = '|', $sSepAttribute = ';', $sSepValue = ':', $sAttributeQualifier = '"');
|
||||
}
|
||||
$oMyObject->Set($sProp, $value);
|
||||
}
|
||||
|
||||
$iId = $oMyObject->DBInsertNoReload();
|
||||
|
||||
$sClassId = "$sClass ($sClassDesc)";
|
||||
$this->m_aCreatedByDesc[$sClassId][] = $iId;
|
||||
$this->m_aCreatedByClass[$sClass][] = $iId;
|
||||
|
||||
$mu_t2 = MyHelpers::getmicrotime();
|
||||
$this->m_aStatsByClass[$sClass][] = $mu_t2 - $mu_t1;
|
||||
|
||||
return $iId;
|
||||
}
|
||||
|
||||
static $m_aClassIdCache = array();
|
||||
protected function GetClassIds($sClass)
|
||||
{
|
||||
if (!isset(self::$m_aClassIdCache[$sClass]))
|
||||
{
|
||||
// Load the cache now
|
||||
self::$m_aClassIdCache[$sClass] = array();
|
||||
|
||||
$oSet = new DBObjectSet(new DBObjectSearch($sClass));
|
||||
while($oObj = $oSet->Fetch())
|
||||
{
|
||||
self::$m_aClassIdCache[$sClass][] = $oObj->GetKey();
|
||||
}
|
||||
}
|
||||
return self::$m_aClassIdCache[$sClass];
|
||||
}
|
||||
|
||||
protected function RandomId($sClass, $sClassDesc = '')
|
||||
{
|
||||
$sClassId = "$sClass ($sClassDesc)";
|
||||
if (isset($this->m_aCreatedByDesc[$sClassId]))
|
||||
{
|
||||
return $this->m_aCreatedByDesc[$sClassId][array_rand($this->m_aCreatedByDesc[$sClassId])];
|
||||
}
|
||||
|
||||
$aIds = self::GetClassIds($sClass);
|
||||
return $aIds[array_rand($aIds)];
|
||||
}
|
||||
|
||||
static protected function FindId($sClass)
|
||||
{
|
||||
$oSet = new DBObjectSet(new DBObjectSearch($sClass));
|
||||
if ($oSet->Count() < 1)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
$oObj = $oSet->Fetch();
|
||||
return $oObj->GetKey();
|
||||
}
|
||||
|
||||
static protected function FindIdFromOQL($sOQL)
|
||||
{
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL));
|
||||
if ($oSet->Count() < 1)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
$oObj = $oSet->Fetch();
|
||||
return $oObj->GetKey();
|
||||
}
|
||||
|
||||
protected function my_array_rand($aData, $iCount)
|
||||
{
|
||||
if ($iCount == 0)
|
||||
{
|
||||
return array();
|
||||
}
|
||||
elseif ($iCount == 1)
|
||||
{
|
||||
// array_rand() for one item returns only the key
|
||||
$key = array_rand($aData);
|
||||
$aSample = array($key);
|
||||
}
|
||||
elseif ($iCount <= count($aData))
|
||||
{
|
||||
$aSample = array_rand($aData, $iCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
$aSample = array_merge(array_keys($aData), self::my_array_rand($aData, $iCount - count($aData)));
|
||||
}
|
||||
return $aSample;
|
||||
}
|
||||
|
||||
protected function CreateLinks($iFrom, $iCount, $sLinkClass, $sAttCodeFrom, $sAttCodeTo)
|
||||
{
|
||||
$oAttTo = MetaModel::GetAttributeDef($sLinkClass, $sAttCodeTo);
|
||||
$sToClass = $oAttTo->GetTargetClass();
|
||||
|
||||
$aTargets = self::GetClassIds($sToClass);
|
||||
$aSample = self::my_array_rand($aTargets, $iCount);
|
||||
|
||||
foreach($aSample as $key)
|
||||
{
|
||||
$aData = array(
|
||||
$sAttCodeFrom => $iFrom,
|
||||
$sAttCodeTo => $aTargets[$key],
|
||||
);
|
||||
$this->CreateObject($sLinkClass, $aData);
|
||||
}
|
||||
}
|
||||
|
||||
public function CreateStructure($oP)
|
||||
{
|
||||
$aClasses = MetaModel::GetClasses();
|
||||
$aActions = array('Read', 'Bulk Read', 'Delete', 'Bulk Delete', 'Modify', 'Bulk Modify');
|
||||
$aStdProfiles = array(2, 3, 4, 5, 6, 7, 8, 9);
|
||||
|
||||
////////////////////////////////////////
|
||||
// New specific profile, giving access to everything
|
||||
//
|
||||
$aData = array(
|
||||
'name' => 'Data guru',
|
||||
'description' => 'Could do anything, because everything is granted',
|
||||
);
|
||||
$iGuruProfile = $this->CreateObject('URP_Profiles', $aData);
|
||||
foreach($aClasses as $sClass)
|
||||
{
|
||||
foreach($aActions as $sAction)
|
||||
{
|
||||
$aData = array(
|
||||
'profileid' => $iGuruProfile,
|
||||
'class' => $sClass,
|
||||
'permission' => 'yes',
|
||||
'action' => $sAction,
|
||||
);
|
||||
$this->CreateObject('URP_ActionGrant', $aData);
|
||||
}
|
||||
}
|
||||
|
||||
// User login with super access rights
|
||||
//
|
||||
$aData = array(
|
||||
'org_id' => self::FindId('Organization'),
|
||||
'location_id' => self::FindId('Location'),
|
||||
'first_name' => 'Jesus',
|
||||
'name' => 'Deus',
|
||||
'email' => 'guru@combodo.com',
|
||||
);
|
||||
$iPerson = $this->CreateObject('Person', $aData);
|
||||
$aData = array(
|
||||
'contactid' => $iPerson,
|
||||
'login' => 'guru',
|
||||
'password' => 'guru',
|
||||
'language' => 'EN US',
|
||||
'profile_list' => array("profileid:$iGuruProfile;reason:he is the one"),
|
||||
);
|
||||
$iLogin = $this->CreateObject('UserLocal', $aData);
|
||||
|
||||
////////////////////////////////////////
|
||||
// User login having all std profiles
|
||||
//
|
||||
$aData = array(
|
||||
'org_id' => self::FindId('Organization'),
|
||||
'location_id' => self::FindId('Location'),
|
||||
'first_name' => 'Little ze',
|
||||
'name' => 'Foo',
|
||||
'email' => 'foo@combodo.com',
|
||||
);
|
||||
$iPerson = $this->CreateObject('Person', $aData);
|
||||
|
||||
$aProfileSet = array();
|
||||
foreach($aStdProfiles as $iProfileId)
|
||||
{
|
||||
$aProfileSet[] = "profileid:$iProfileId;reason:xxx";
|
||||
}
|
||||
$aData = array(
|
||||
'contactid' => $iPerson,
|
||||
'login' => 'foo',
|
||||
'password' => 'foo',
|
||||
'language' => 'EN US',
|
||||
'profile_list' => $aProfileSet,
|
||||
);
|
||||
$iLogin = $this->CreateObject('UserLocal', $aData);
|
||||
|
||||
/////////////////////////
|
||||
//
|
||||
// Organizations
|
||||
//
|
||||
$aData = array(
|
||||
'name' => 'Benchmark',
|
||||
);
|
||||
$iOrg = $this->CreateObject('Organization', $aData);
|
||||
|
||||
/////////////////////////
|
||||
//
|
||||
// Locations
|
||||
//
|
||||
$aData = array(
|
||||
'org_id' => $iOrg,
|
||||
'name' => 'Rio de Janeiro',
|
||||
);
|
||||
$iLoc = $this->CreateObject('Location', $aData);
|
||||
|
||||
/////////////////////////
|
||||
//
|
||||
// Teams
|
||||
//
|
||||
$aData = array(
|
||||
'org_id' => $iOrg,
|
||||
'location_id' => $iLoc,
|
||||
'name' => 'Fluminense',
|
||||
'email' => 'fluminense@combodo.com',
|
||||
);
|
||||
$iTeam = $this->CreateObject('Team', $aData);
|
||||
|
||||
/////////////////////////
|
||||
//
|
||||
// Persons
|
||||
//
|
||||
for($i = 0 ; $i < $this->m_aPlanned['Contacts'] ; $i++)
|
||||
{
|
||||
$aData = array(
|
||||
'org_id' => $iOrg,
|
||||
'location_id' => $iLoc,
|
||||
'first_name' => 'Joaõ',
|
||||
'name' => 'Ningem #'.$i,
|
||||
'email' => 'foo'.$i.'@nowhere.fr',
|
||||
);
|
||||
$iPerson = $this->CreateObject('Person', $aData);
|
||||
|
||||
// Contract/Infra
|
||||
//
|
||||
$aData = array(
|
||||
'contact_id' => $iPerson,
|
||||
'team_id' => $this->RandomId('Team'),
|
||||
);
|
||||
$this->CreateObject('lnkTeamToContact', $aData);
|
||||
}
|
||||
|
||||
/////////////////////////
|
||||
//
|
||||
// Services
|
||||
//
|
||||
$aData = array(
|
||||
'org_id' => $iOrg,
|
||||
'name' => 'My Service',
|
||||
);
|
||||
$iService = $this->CreateObject('Service', $aData);
|
||||
|
||||
/////////////////////////
|
||||
//
|
||||
// Service subcategories
|
||||
//
|
||||
$aData = array(
|
||||
'name' => 'My subcategory',
|
||||
'service_id' => $iService,
|
||||
);
|
||||
$iOrg = $this->CreateObject('ServiceSubcategory', $aData);
|
||||
|
||||
/////////////////////////
|
||||
//
|
||||
// Contracts
|
||||
//
|
||||
for($i = 0 ; $i < $this->m_aPlanned['Contracts'] ; $i++)
|
||||
{
|
||||
$aData = array(
|
||||
'name' => "Contract #$i",
|
||||
'description' => 'Created for benchmarking purposes',
|
||||
'org_id' => $this->RandomId('Organization'),
|
||||
'provider_id' => $this->RandomId('Organization'),
|
||||
'start_date' => '2009-12-25',
|
||||
'end_date' => '2019-08-01',
|
||||
'support_team_id' => $this->RandomId('Team'),
|
||||
);
|
||||
$iContract = $this->CreateObject('CustomerContract', $aData);
|
||||
|
||||
// Contract/Contact (10% of contacts)
|
||||
//
|
||||
$iContactCount = ceil($this->m_aPlanned['Contracts'] / 10);
|
||||
for($iLinked = 0 ; $iLinked < $iContactCount ; $iLinked++)
|
||||
{
|
||||
$aData = array(
|
||||
'contact_id' => $this->RandomId('Person'),
|
||||
'contract_id' => $iContract,
|
||||
'role' => 'role '.$iLinked,
|
||||
);
|
||||
$this->CreateObject('lnkContractToContact', $aData);
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////
|
||||
//
|
||||
// Documents
|
||||
//
|
||||
$sMyDoc = '';
|
||||
for($i = 0 ; $i < 1000 ; $i++)
|
||||
{
|
||||
// 100 chars
|
||||
$sMyDoc .= "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678\n";
|
||||
}
|
||||
$oRefDoc = new ormDocument($sMyDoc, 'text/plain');
|
||||
|
||||
for($i = 0 ; $i < $this->m_aPlanned['Documents'] ; $i++)
|
||||
{
|
||||
$aData = array(
|
||||
'org_id' => $iOrg,
|
||||
'name' => "document$i",
|
||||
'contents' => $oRefDoc,
|
||||
);
|
||||
$this->CreateObject('FileDoc', $aData);
|
||||
}
|
||||
}
|
||||
|
||||
public function CreateCis($oP)
|
||||
{
|
||||
$iOrg = $this->FindIdFromOQL("SELECT Organization WHERE name = 'Benchmark'");
|
||||
$iLoc = $this->FindIdFromOQL("SELECT Location WHERE org_id = $iOrg");
|
||||
|
||||
/////////////////////////
|
||||
//
|
||||
// Servers
|
||||
//
|
||||
for($i = 0 ; $i < $this->m_aPlanned['Servers'] ; $i++)
|
||||
{
|
||||
$aData = array(
|
||||
'org_id' => $iOrg,
|
||||
'location_id' => $iLoc,
|
||||
'name' => 'server'.$i,
|
||||
'status' => 'production',
|
||||
);
|
||||
$iServer = $this->CreateObject('Server', $aData);
|
||||
|
||||
// Contract/Infra
|
||||
$this->CreateLinks($iServer, 1, 'lnkContractToCI', 'ci_id', 'contract_id');
|
||||
|
||||
// Interfaces
|
||||
for($iLinked = 0 ; $iLinked < $this->m_iIfByServer ; $iLinked++)
|
||||
{
|
||||
$aData = array(
|
||||
'name' => "eth$iLinked",
|
||||
'status' => 'implementation',
|
||||
'org_id' => $iOrg,
|
||||
'device_id' => $iServer,
|
||||
'status' => 'production',
|
||||
);
|
||||
$this->CreateObject('NetworkInterface', $aData, 'server if');
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////
|
||||
//
|
||||
// Network devices
|
||||
//
|
||||
for($i = 0 ; $i < $this->m_aPlanned['Network devices'] ; $i++)
|
||||
{
|
||||
$aData = array(
|
||||
'org_id' => $iOrg,
|
||||
'location_id' => $iLoc,
|
||||
'name' => 'equipment #'.$i,
|
||||
'status' => 'production',
|
||||
);
|
||||
$iNWDevice = $this->CreateObject('NetworkDevice', $aData);
|
||||
|
||||
// Contract/Infra
|
||||
$this->CreateLinks($iNWDevice, 1, 'lnkContractToCI', 'ci_id', 'contract_id');
|
||||
|
||||
// Interfaces
|
||||
//
|
||||
for($iLinked = 0 ; $iLinked < $this->m_iIfByNWDevice ; $iLinked++)
|
||||
{
|
||||
$aData = array(
|
||||
'name' => "eth$iLinked",
|
||||
'status' => 'implementation',
|
||||
'org_id' => $iOrg,
|
||||
'device_id' => $iNWDevice,
|
||||
'connected_if' => $this->RandomId('NetworkInterface', 'server if'),
|
||||
'status' => 'production',
|
||||
);
|
||||
$this->CreateObject('NetworkInterface', $aData, 'equipment if');
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////
|
||||
//
|
||||
// Application Software
|
||||
//
|
||||
for($i = 0 ; $i < $this->m_aPlanned['Application SW'] ; $i++)
|
||||
{
|
||||
$aData = array(
|
||||
'name' => 'Software #'.$i,
|
||||
);
|
||||
$iNWDevice = $this->CreateObject('Application', $aData);
|
||||
}
|
||||
|
||||
/////////////////////////
|
||||
//
|
||||
// Applications
|
||||
//
|
||||
for($i = 0 ; $i < $this->m_aPlanned['Applications'] ; $i++)
|
||||
{
|
||||
$aData = array(
|
||||
'org_id' => $iOrg,
|
||||
'device_id' => $this->RandomId('Server'),
|
||||
'software_id' => $this->RandomId('Application'),
|
||||
'name' => 'Application #'.$i,
|
||||
'status' => 'production',
|
||||
);
|
||||
$iAppInstance = $this->CreateObject('ApplicationInstance', $aData);
|
||||
|
||||
// Contract/Infra
|
||||
$this->CreateLinks($iAppInstance, 1, 'lnkContractToCI', 'ci_id', 'contract_id');
|
||||
}
|
||||
|
||||
/////////////////////////
|
||||
//
|
||||
// Application Solution
|
||||
//
|
||||
for($i = 0 ; $i < $this->m_aPlanned['Solutions'] ; $i++)
|
||||
{
|
||||
$aData = array(
|
||||
'org_id' => $iOrg,
|
||||
'name' => 'Solution #'.$i,
|
||||
'status' => 'production',
|
||||
);
|
||||
$iAppSolution = $this->CreateObject('ApplicationSolution', $aData);
|
||||
|
||||
// Contract/Infra
|
||||
$this->CreateLinks($iAppSolution, 1, 'lnkContractToCI', 'ci_id', 'contract_id');
|
||||
}
|
||||
|
||||
/////////////////////////
|
||||
//
|
||||
// Business Process
|
||||
//
|
||||
for($i = 0 ; $i < $this->m_aPlanned['Processes'] ; $i++)
|
||||
{
|
||||
$aData = array(
|
||||
'org_id' => $iOrg,
|
||||
'name' => 'Process #'.$i,
|
||||
'status' => 'production',
|
||||
);
|
||||
$iProcess = $this->CreateObject('BusinessProcess', $aData);
|
||||
|
||||
// Contract/Infra
|
||||
$this->CreateLinks($iProcess, 1, 'lnkContractToCI', 'ci_id', 'contract_id');
|
||||
}
|
||||
}
|
||||
|
||||
public function CreateTickets($oP)
|
||||
{
|
||||
$iOrg = $this->FindIdFromOQL("SELECT Organization WHERE name = 'Benchmark'");
|
||||
$iLoc = $this->FindIdFromOQL("SELECT Location WHERE org_id = $iOrg");
|
||||
|
||||
/////////////////////////
|
||||
//
|
||||
// Incident Tickets
|
||||
//
|
||||
for($i = 0 ; $i < $this->m_aPlanned['Incidents'] ; $i++)
|
||||
{
|
||||
$aData = array(
|
||||
'org_id' => $iOrg,
|
||||
'caller_id' => $this->RandomId('Person'),
|
||||
'workgroup_id' => $this->RandomId('Team'),
|
||||
'agent_id' => $this->RandomId('Person'),
|
||||
'service_id' => $this->RandomId('Service'),
|
||||
'servicesubcategory_id' => $this->RandomId('ServiceSubcategory'),
|
||||
'title' => 'Incident #'.$i,
|
||||
'description' => 'O que aconteceu?',
|
||||
'ticket_log' => 'Testing...',
|
||||
);
|
||||
$iTicket = $this->CreateObject('Incident', $aData);
|
||||
|
||||
// Incident/Infra
|
||||
$iInfraCount = rand(1, 6);
|
||||
$this->CreateLinks($iTicket, $iInfraCount, 'lnkTicketToCI', 'ticket_id', 'ci_id');
|
||||
|
||||
// Incident/Infra
|
||||
$iContactCount = rand(1, 6);
|
||||
$this->CreateLinks($iTicket, $iContactCount, 'lnkTicketToContact', 'ticket_id', 'contact_id');
|
||||
}
|
||||
|
||||
/////////////////////////
|
||||
//
|
||||
// Big Ticket
|
||||
//
|
||||
$aData = array(
|
||||
'org_id' => $iOrg,
|
||||
'caller_id' => $this->RandomId('Person'),
|
||||
'workgroup_id' => $this->RandomId('Team'),
|
||||
'agent_id' => $this->RandomId('Person'),
|
||||
'service_id' => $this->RandomId('Service'),
|
||||
'servicesubcategory_id' => $this->RandomId('ServiceSubcategory'),
|
||||
'title' => 'Big ticket',
|
||||
'description' => 'O que aconteceu?',
|
||||
'ticket_log' => 'Testing...',
|
||||
);
|
||||
$iTicket = $this->CreateObject('Incident', $aData);
|
||||
|
||||
// Incident/Infra
|
||||
$iInfraCount = $this->m_aPlanned['Big ticket: CIs'];
|
||||
$this->CreateLinks($iTicket, $iInfraCount, 'lnkTicketToCI', 'ticket_id', 'ci_id');
|
||||
|
||||
// Incident/Infra
|
||||
$iContactCount = rand(1, 6);
|
||||
$this->CreateLinks($iTicket, $iContactCount, 'lnkTicketToContact', 'ticket_id', 'contact_id');
|
||||
|
||||
/////////////////////////
|
||||
//
|
||||
// Change Tickets
|
||||
//
|
||||
for($i = 0 ; $i < $this->m_aPlanned['Changes'] ; $i++)
|
||||
{
|
||||
$aData = array(
|
||||
'org_id' => $iOrg,
|
||||
'requestor_id' => $this->RandomId('Person'),
|
||||
'workgroup_id' => $this->RandomId('Team'),
|
||||
'agent_id' => $this->RandomId('Person'),
|
||||
'supervisor_group_id' => $this->RandomId('Team'),
|
||||
'supervisor_id' => $this->RandomId('Person'),
|
||||
'manager_group_id' => $this->RandomId('Team'),
|
||||
'manager_id' => $this->RandomId('Person'),
|
||||
'title' => 'change #'.$i,
|
||||
'description' => "Let's do something there",
|
||||
);
|
||||
$iTicket = $this->CreateObject('NormalChange', $aData);
|
||||
|
||||
// Incident/Infra
|
||||
$iInfraCount = rand(1, 6);
|
||||
$this->CreateLinks($iTicket, $iInfraCount, 'lnkTicketToCI', 'ticket_id', 'ci_id');
|
||||
|
||||
// Incident/Infra
|
||||
$iContactCount = rand(1, 6);
|
||||
$this->CreateLinks($iTicket, $iContactCount, 'lnkTicketToContact', 'ticket_id', 'contact_id');
|
||||
}
|
||||
}
|
||||
|
||||
public function MakeFeedback($oP)
|
||||
{
|
||||
foreach($this->m_aCreatedByClass as $sClass => $aClassIds)
|
||||
{
|
||||
$iSample = reset($aClassIds);
|
||||
$sSample = "<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=details&class=$sClass&id=$iSample\">sample</a>";
|
||||
|
||||
$iDuration = number_format(array_sum($this->m_aStatsByClass[$sClass]), 3);
|
||||
$fDurationMin = number_format(min($this->m_aStatsByClass[$sClass]), 3);
|
||||
$fDurationMax = number_format(max($this->m_aStatsByClass[$sClass]), 3);
|
||||
$fDurationAverage = number_format(array_sum($this->m_aStatsByClass[$sClass]) / count($this->m_aStatsByClass[$sClass]), 3);
|
||||
|
||||
$oP->add("<ul>");
|
||||
$oP->add("<li>");
|
||||
$oP->add("$sClass: ".count($this->m_aStatsByClass[$sClass])." - $sSample<br/>");
|
||||
$oP->add("Duration: $fDurationMin => $fDurationMax; Avg:$fDurationAverage; Total: $iDuration");
|
||||
$oP->add("</li>");
|
||||
$oP->add("</ul>");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ask the user what are the settings for the data load
|
||||
*/
|
||||
function DisplayStep1(SetupPage $oP)
|
||||
{
|
||||
$sNextOperation = 'step2';
|
||||
$oP->add("<h1>iTop benchmarking</h1>\n");
|
||||
|
||||
$oP->add("<form method=\"post\" onSubmit=\"return DoSubmit('Evaluating real plans...', 10)\">\n");
|
||||
$oP->add("<fieldset><legend>Data load configuration</legend>\n");
|
||||
$aForm = array();
|
||||
$aForm[] = array(
|
||||
'label' => "Contacts:",
|
||||
'input' => "<input id=\"from\" type=\"text\" name=\"plannedcontacts\" value=\"100\">",
|
||||
'help' => '',
|
||||
);
|
||||
$aForm[] = array(
|
||||
'label' => "Contracts:",
|
||||
'input' => "<input id=\"from\" type=\"text\" name=\"plannedcontracts\" value=\"10\">",
|
||||
'help' => '',
|
||||
);
|
||||
$oP->form($aForm);
|
||||
$oP->add("</fieldset>\n");
|
||||
$oP->add("<input type=\"hidden\" name=\"operation\" value=\"create_structure\">\n");
|
||||
$oP->add("<button type=\"submit\">Next >></button>\n");
|
||||
$oP->add("</form>\n");
|
||||
|
||||
$oP->add("<form method=\"post\" onSubmit=\"return DoSubmit('Evaluating real plans...', 10)\">\n");
|
||||
$oP->add("<fieldset><legend>Data load configuration</legend>\n");
|
||||
$aForm = array();
|
||||
$aForm[] = array(
|
||||
'label' => "Main CIs:",
|
||||
'input' => "<input id=\"to\" type=\"text\" name=\"plannedcis\" value=\"70\">",
|
||||
'help' => ' exclude interfaces, subnets or any other type of secondary CI',
|
||||
);
|
||||
$oP->form($aForm);
|
||||
$oP->add("</fieldset>\n");
|
||||
$oP->add("<input type=\"hidden\" name=\"operation\" value=\"create_cis\">\n");
|
||||
$oP->add("<button type=\"submit\">Next >></button>\n");
|
||||
$oP->add("</form>\n");
|
||||
|
||||
$oP->add("<form method=\"post\" onSubmit=\"return DoSubmit('Evaluating real plans...', 10)\">\n");
|
||||
$oP->add("<fieldset><legend>Data load configuration</legend>\n");
|
||||
$aForm = array();
|
||||
$aForm[] = array(
|
||||
'label' => "Tickets:",
|
||||
'input' => "<input id=\"to\" type=\"text\" name=\"plannedtickets\" value=\"200\">",
|
||||
'help' => ' 50% incidents, 50% changes',
|
||||
);
|
||||
$aForm[] = array(
|
||||
'label' => "CIs for the big ticket:",
|
||||
'input' => "<input id=\"to\" type=\"text\" name=\"plannedbigticketcis\" value=\"200\">",
|
||||
'help' => 'Number of CI for the single big ticket',
|
||||
);
|
||||
$oP->form($aForm);
|
||||
$oP->add("</fieldset>\n");
|
||||
$oP->add("<input type=\"hidden\" name=\"operation\" value=\"create_tickets\">\n");
|
||||
$oP->add("<button type=\"submit\">Next >></button>\n");
|
||||
$oP->add("</form>\n");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Main program
|
||||
*/
|
||||
|
||||
LoginWebPage::DoLogin(); // Check user rights and prompt if needed
|
||||
|
||||
$sOperation = Utils::ReadParam('operation', 'step1');
|
||||
$oP = new SetupPage('iTop benchmark utility');
|
||||
|
||||
ExecutionKPI::EnableDuration();
|
||||
$oKPI = new ExecutionKPI();
|
||||
|
||||
try
|
||||
{
|
||||
switch($sOperation)
|
||||
{
|
||||
case 'step1':
|
||||
DisplayStep1($oP);
|
||||
break;
|
||||
|
||||
case 'create_structure':
|
||||
$oP->no_cache();
|
||||
$oP->add_xframe_options('DENY');
|
||||
$iPlannedContacts = Utils::ReadParam('plannedcontacts');
|
||||
$iPlannedContracts = Utils::ReadParam('plannedcontracts');
|
||||
|
||||
$oDataCreation = new BenchmarkDataCreation();
|
||||
$oDataCreation->PlanStructure($iPlannedContacts, $iPlannedContracts);
|
||||
$oDataCreation->ShowPlans($oP);
|
||||
$oDataCreation->ShowForm($oP, 'create_structure_go');
|
||||
break;
|
||||
|
||||
case 'create_structure_go':
|
||||
$oP->no_cache();
|
||||
$iPlannedContacts = Utils::ReadParam('plannedcontacts');
|
||||
$iPlannedContracts = Utils::ReadParam('plannedcontracts');
|
||||
|
||||
$oDataCreation = new BenchmarkDataCreation();
|
||||
$oDataCreation->PlanStructure($iPlannedContacts, $iPlannedContracts);
|
||||
$oDataCreation->CreateStructure($oP);
|
||||
$oDataCreation->MakeFeedback($oP);
|
||||
break;
|
||||
|
||||
case 'create_cis':
|
||||
$oP->no_cache();
|
||||
$iPlannedCIs = Utils::ReadParam('plannedcis');
|
||||
|
||||
$oDataCreation = new BenchmarkDataCreation();
|
||||
$oDataCreation->PlanCis($iPlannedCIs);
|
||||
$oDataCreation->ShowPlans($oP);
|
||||
$oDataCreation->ShowForm($oP, 'create_cis_go');
|
||||
break;
|
||||
|
||||
case 'create_cis_go':
|
||||
$oP->no_cache();
|
||||
$iPlannedCIs = Utils::ReadParam('plannedcis');
|
||||
|
||||
$oDataCreation = new BenchmarkDataCreation();
|
||||
$oDataCreation->PlanCis($iPlannedCIs);
|
||||
$oDataCreation->CreateCis($oP);
|
||||
$oDataCreation->MakeFeedback($oP);
|
||||
break;
|
||||
|
||||
case 'create_tickets':
|
||||
$oP->no_cache();
|
||||
$iPlannedTickets = Utils::ReadParam('plannedtickets');
|
||||
$iBigTicketCis = Utils::ReadParam('plannedbigticketcis');
|
||||
|
||||
$oDataCreation = new BenchmarkDataCreation();
|
||||
$oDataCreation->PlanTickets($iPlannedTickets, $iBigTicketCis);
|
||||
$oDataCreation->ShowPlans($oP);
|
||||
$oDataCreation->ShowForm($oP, 'create_tickets_go');
|
||||
break;
|
||||
|
||||
case 'create_tickets_go':
|
||||
$oP->no_cache();
|
||||
$iPlannedTickets = Utils::ReadParam('plannedtickets');
|
||||
$iBigTicketCis = Utils::ReadParam('plannedbigticketcis');
|
||||
|
||||
$oDataCreation = new BenchmarkDataCreation();
|
||||
$oDataCreation->PlanTickets($iPlannedTickets, $iBigTicketCis);
|
||||
$oDataCreation->CreateTickets($oP);
|
||||
$oDataCreation->MakeFeedback($oP);
|
||||
break;
|
||||
|
||||
default:
|
||||
$oP->error("Error: unsupported operation '$sOperation'");
|
||||
}
|
||||
}
|
||||
catch(ZZException $e)
|
||||
{
|
||||
$oP->error("Error: '".$e->getMessage()."'");
|
||||
}
|
||||
catch(ZZCoreException $e)
|
||||
{
|
||||
$oP->error("Error: '".$e->getHtmlDesc()."'");
|
||||
}
|
||||
$oKPI->ComputeAndReport('Total execution');
|
||||
//DBSearch::RecordQueryTrace();
|
||||
$oP->output();
|
||||
?>
|
||||
146
tests/php-unit-tests/legacy-tests/build_test_oql.php
Normal file
146
tests/php-unit-tests/legacy-tests/build_test_oql.php
Normal file
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
// Copyright (c) 2010-2017 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/>
|
||||
//
|
||||
|
||||
/**
|
||||
* Date: 06/10/2017
|
||||
*/
|
||||
|
||||
|
||||
require_once('../../../approot.inc.php');
|
||||
require_once(APPROOT.'application/startup.inc.php');
|
||||
|
||||
\LoginWebPage::DoLogin(true);
|
||||
|
||||
$sOQLFile = APPROOT.'log/oql_records.txt';
|
||||
$sTestFile = APPROOT.'tests/core/oql_records.php';
|
||||
|
||||
$oTestHandle = @fopen($sTestFile, "w");
|
||||
|
||||
@fwrite($oTestHandle, "<?php\n\n");
|
||||
|
||||
$aFoundOQLs = array();
|
||||
$iCount = 0;
|
||||
$iRead = 0;
|
||||
|
||||
$oOQLHandle = @fopen($sOQLFile, "r");
|
||||
if ($oOQLHandle) {
|
||||
while (($sBuffer = fgets($oOQLHandle)) !== false) {
|
||||
$iRead++;
|
||||
$aRecord = unserialize($sBuffer);
|
||||
|
||||
$sOQL = $aRecord['oql'];
|
||||
|
||||
$sChecksum = md5($sBuffer);
|
||||
if (isset($aFoundOQLs[$sChecksum])) { continue; }
|
||||
$aFoundOQLs[$sChecksum] = true;
|
||||
|
||||
$iCount++;
|
||||
$sOrderBy = ConvertArray($aRecord['order_by']);
|
||||
$sAttToLoad = ConvertArray($aRecord['att_to_load']);
|
||||
$iLimitCount = $aRecord['limit_count'];
|
||||
$iLimitStart = $aRecord['limit_start'];
|
||||
|
||||
// $sOQL, $aOrderBy, $aArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart
|
||||
|
||||
$sLine = "\$aData[\"SELECT $iCount\"] = array(\"$sOQL\", $sOrderBy, array(), $sAttToLoad, array(), $iLimitCount, $iLimitStart);\n";
|
||||
@fwrite($oTestHandle, $sLine);
|
||||
}
|
||||
if (!feof($oOQLHandle)) {
|
||||
echo "Erreur: fgets() a échoué\n";
|
||||
}
|
||||
@fclose($oOQLHandle);
|
||||
}
|
||||
@fwrite($oTestHandle, "\n");
|
||||
|
||||
@fclose($oTestHandle);
|
||||
|
||||
echo "File '$sTestFile' generated with $iCount entries (from $iRead captured OQL).\n";
|
||||
|
||||
|
||||
/// Group by
|
||||
|
||||
|
||||
$sOQLFile = APPROOT.'log/oql_group_by_records.txt';
|
||||
$sTestFile = APPROOT.'tests/core/oql_group_by_records.php';
|
||||
|
||||
$oTestHandle = @fopen($sTestFile, "w");
|
||||
|
||||
@fwrite($oTestHandle, "<?php\n\n");
|
||||
|
||||
$aFoundOQLs = array();
|
||||
$iCount = 1000;
|
||||
$iRead = 0;
|
||||
|
||||
$oOQLHandle = @fopen($sOQLFile, "r");
|
||||
if ($oOQLHandle) {
|
||||
while (($sBuffer = fgets($oOQLHandle)) !== false) {
|
||||
$iRead++;
|
||||
$aRecord = unserialize($sBuffer);
|
||||
|
||||
$sOQL = $aRecord['oql'];
|
||||
|
||||
$sChecksum = md5($sBuffer);
|
||||
if (isset($aFoundOQLs[$sChecksum])) { continue; }
|
||||
$aFoundOQLs[$sChecksum] = true;
|
||||
|
||||
$iCount++;
|
||||
$sOrderBy = ConvertArray($aRecord['order_by']);
|
||||
$sGroupByExpr = ConvertArray($aRecord['group_by_expr']);
|
||||
$sSelectExpr = ConvertArray($aRecord['select_expr']);
|
||||
if ($aRecord['exclude_null_values'])
|
||||
{
|
||||
$bExcludeNullValues = 'true';
|
||||
}
|
||||
else
|
||||
{
|
||||
$bExcludeNullValues = 'false';
|
||||
}
|
||||
$iLimitCount = $aRecord['limit_count'];
|
||||
$iLimitStart = $aRecord['limit_start'];
|
||||
|
||||
// $sOQL, $aArgs, $aGroupByExpr, $bExcludeNullValues, $aSelectExpr, $aOrderBy, $iLimitCount, $iLimitStart
|
||||
|
||||
$sLine = "\$aData[\"SELECT $iCount\"] = array(\"$sOQL\", array(), $sGroupByExpr, $bExcludeNullValues, $sSelectExpr, $sOrderBy, $iLimitCount, $iLimitStart);\n";
|
||||
@fwrite($oTestHandle, $sLine);
|
||||
}
|
||||
if (!feof($oOQLHandle)) {
|
||||
echo "Erreur: fgets() a échoué\n";
|
||||
}
|
||||
@fclose($oOQLHandle);
|
||||
}
|
||||
@fwrite($oTestHandle, "\n");
|
||||
|
||||
@fclose($oTestHandle);
|
||||
|
||||
echo "<br>File '$sTestFile' generated with ".($iCount-1000)." entries (from $iRead captured OQL).\n";
|
||||
|
||||
function ConvertArray($aArray)
|
||||
{
|
||||
if (is_null($aArray))
|
||||
{
|
||||
return 'null';
|
||||
}
|
||||
|
||||
if (empty($aArray))
|
||||
{
|
||||
return 'array()';
|
||||
}
|
||||
|
||||
return 'unserialize(\''.str_replace("'", "\\'",serialize($aArray)).'\')';
|
||||
}
|
||||
38
tests/php-unit-tests/legacy-tests/config-test-farm.php
Normal file
38
tests/php-unit-tests/legacy-tests/config-test-farm.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
//
|
||||
// phpMyORM configuration file
|
||||
//
|
||||
// To be manually edited (or generated by the configuration wizard)
|
||||
//
|
||||
// The file is used in MetaModel::LoadConfig() which does all the necessary initialization job
|
||||
//
|
||||
|
||||
$MySettings = array(
|
||||
'db_host' => 'localhost',
|
||||
'db_user' => 'root',
|
||||
'db_pwd' => '',
|
||||
'db_name' => 'TestFarm',
|
||||
'db_subname' => '', // use it to differentiate two applications instances running on the same DB
|
||||
);
|
||||
|
||||
// Modules: file names should be specified as a absolute paths
|
||||
|
||||
$MyModules = array(
|
||||
'application' => array (
|
||||
// '../core/event.class.inc.php',
|
||||
// '../core/action.class.inc.php',
|
||||
// '../core/trigger.class.inc.php',
|
||||
// to be continued...
|
||||
),
|
||||
'business' => array (
|
||||
'../business/test_farm.class.inc.php',
|
||||
// to be continued...
|
||||
),
|
||||
'addons' => array (
|
||||
//'user rights' => '/addons/userrights/userrightsnull.class.inc.php', // or userrightsmatrix.class.inc.php
|
||||
// other modules to come later
|
||||
)
|
||||
);
|
||||
|
||||
?>
|
||||
104
tests/php-unit-tests/legacy-tests/display_cache_content.php
Normal file
104
tests/php-unit-tests/legacy-tests/display_cache_content.php
Normal file
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2019 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
|
||||
*/
|
||||
|
||||
/**
|
||||
* Date: 06/10/2017
|
||||
*/
|
||||
|
||||
require_once('../../../approot.inc.php');
|
||||
require_once(APPROOT.'application/startup.inc.php');
|
||||
|
||||
|
||||
$sEnvironment = MetaModel::GetEnvironmentId();
|
||||
$aEntries = array();
|
||||
$aCacheUserData = apc_cache_info_compat();
|
||||
if (is_array($aCacheUserData) && isset($aCacheUserData['cache_list']))
|
||||
{
|
||||
$sPrefix = 'itop-'.$sEnvironment.'-query-cache-';
|
||||
|
||||
foreach($aCacheUserData['cache_list'] as $i => $aEntry)
|
||||
{
|
||||
$sEntryKey = array_key_exists('info', $aEntry) ? $aEntry['info'] : $aEntry['key'];
|
||||
if (strpos($sEntryKey, $sPrefix) === 0)
|
||||
{
|
||||
$aEntries[] = $sEntryKey;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
echo "<pre>";
|
||||
|
||||
if (empty($aEntries))
|
||||
{
|
||||
echo "No Data";
|
||||
return;
|
||||
}
|
||||
|
||||
$sKey = $aEntries[0];
|
||||
$result = apc_fetch($sKey);
|
||||
if (!is_object($result))
|
||||
{
|
||||
return;
|
||||
}
|
||||
$oSQLQuery = $result;
|
||||
|
||||
echo "NB Tables before;NB Tables after;";
|
||||
foreach($oSQLQuery->m_aContextData as $sField => $oValue)
|
||||
{
|
||||
echo $sField.';';
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
sort($aEntries);
|
||||
|
||||
foreach($aEntries as $sKey)
|
||||
{
|
||||
$result = apc_fetch($sKey);
|
||||
if (is_object($result))
|
||||
{
|
||||
$oSQLQuery = $result;
|
||||
if (isset($oSQLQuery->m_aContextData))
|
||||
{
|
||||
echo $oSQLQuery->m_iOriginalTableCount.";".$oSQLQuery->CountTables().';';
|
||||
foreach($oSQLQuery->m_aContextData as $oValue)
|
||||
{
|
||||
if (is_array($oValue))
|
||||
{
|
||||
$sVal = json_encode($oValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (empty($oValue))
|
||||
{
|
||||
$sVal = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sVal = $oValue;
|
||||
}
|
||||
}
|
||||
echo $sVal.';';
|
||||
}
|
||||
echo "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
echo "</pre>";
|
||||
|
||||
354
tests/php-unit-tests/legacy-tests/replay_query_log.php
Normal file
354
tests/php-unit-tests/legacy-tests/replay_query_log.php
Normal file
@@ -0,0 +1,354 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2019 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
|
||||
*/
|
||||
|
||||
function LogResult($sString)
|
||||
{
|
||||
file_put_contents(APPROOT.'data/queries.results.log', "\n".$sString, FILE_APPEND);
|
||||
}
|
||||
|
||||
function LogBenchmarkCSV()
|
||||
{
|
||||
$aValues = array();
|
||||
foreach (func_get_args() as $arg)
|
||||
{
|
||||
if (is_string($arg))
|
||||
{
|
||||
$aValues[] = '"'.str_replace('"', '""', $arg).'"';
|
||||
}
|
||||
else
|
||||
{
|
||||
$aValues[] = (string) $arg;
|
||||
}
|
||||
}
|
||||
$sLine = implode(';', $aValues); // the preferred for MS Excel
|
||||
file_put_contents(APPROOT.'data/queries.benchmark.csv', "\n".$sLine, FILE_APPEND);
|
||||
}
|
||||
|
||||
class QueryLogEntry
|
||||
{
|
||||
public function __construct($aLogEntryId, $aLogEntryData)
|
||||
{
|
||||
$this->aErrors = array();
|
||||
$this->sSql = '';
|
||||
$this->MakeDuration = 0;
|
||||
$this->fExecDuration = 0;
|
||||
$this->iTableCount = 0;
|
||||
$this->aRows = array();
|
||||
|
||||
$this->sLogId = $aLogEntryId;
|
||||
$this->sOql = $aLogEntryData['oql'];
|
||||
$this->sOqlHtml = htmlentities($this->sOql, ENT_QUOTES, 'UTF-8');
|
||||
|
||||
|
||||
$aQueryData = unserialize($aLogEntryData['data']);
|
||||
$this->oFilter = $aQueryData['filter'];
|
||||
$this->sClass = $this->oFilter->GetClass();
|
||||
$this->aArgs = $aQueryData['args'];
|
||||
|
||||
$iRepeat = utils::ReadParam('repeat', 3);
|
||||
|
||||
if ($aQueryData['type'] == 'select')
|
||||
{
|
||||
$this->aOrderBy = $aQueryData['order_by'];
|
||||
$this->aAttToLoad = $aQueryData['att_to_load'];
|
||||
$this->aExtendedDataSpec = $aQueryData['extended_data_spec'];
|
||||
$this->iLimitCount = $aQueryData['limit_count'];
|
||||
$this->iLimitStart = $aQueryData['limit_start'];
|
||||
$this->bGetCount = $aQueryData['is_count'];
|
||||
|
||||
if ($this->bGetCount)
|
||||
{
|
||||
$this->sQueryType = 'COUNT';
|
||||
$this->sQueryDesc = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->sQueryType = 'LIST';
|
||||
$this->sQueryDesc = "limit count: $this->iLimitCount";
|
||||
$this->sQueryDesc .= "; limit start: $this->iLimitStart";
|
||||
if (count($this->aOrderBy) > 0)
|
||||
{
|
||||
$this->sQueryDesc .= "; order by: ".implode(',', array_keys($this->aOrderBy));
|
||||
}
|
||||
if (is_array($this->aAttToLoad))
|
||||
{
|
||||
$this->sQueryDesc .= "; attributes: ".implode(',', array_keys($this->aAttToLoad));
|
||||
}
|
||||
}
|
||||
|
||||
$fRefTime = MyHelpers::getmicrotime();
|
||||
try
|
||||
{
|
||||
for($i = 0 ; $i < $iRepeat ; $i++)
|
||||
{
|
||||
$this->sSql = $this->oFilter->MakeSelectQuery($this->aOrderBy, $this->aArgs, $this->aAttToLoad, $this->aExtendedDataSpec, $this->iLimitCount, $this->iLimitStart, $this->bGetCount);
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
$this->aErrors[] = "Failed to create the SQL:".$e->getMessage();
|
||||
}
|
||||
$this->fMakeDuration = (MyHelpers::getmicrotime() - $fRefTime) / $iRepeat;
|
||||
}
|
||||
elseif ($aQueryData['type'] == 'group_by')
|
||||
{
|
||||
$this->aGroupByExpr = $aQueryData['group_by_expr'];
|
||||
|
||||
$this->sQueryType = 'GROUP BY';
|
||||
$aGroupedBy = array();
|
||||
foreach ($this->aGroupByExpr as $oExpr)
|
||||
{
|
||||
$aGroupedBy[] = $oExpr->Render();
|
||||
}
|
||||
$this->sQueryDesc = implode(', ', $aGroupedBy);
|
||||
|
||||
$fRefTime = MyHelpers::getmicrotime();
|
||||
try
|
||||
{
|
||||
for($i = 0 ; $i < $iRepeat ; $i++)
|
||||
{
|
||||
$this->sSql = $this->oFilter->MakeGroupByQuery($this->aArgs, $this->aGroupByExpr);
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
$this->aErrors[] = "Failed to create the SQL:".$e->getMessage();
|
||||
}
|
||||
$this->fMakeDuration = (MyHelpers::getmicrotime() - $fRefTime) / $iRepeat;
|
||||
}
|
||||
else
|
||||
{
|
||||
// unsupported
|
||||
$this->sQueryType = 'ERROR';
|
||||
$this->sQueryDesc = "Unkown type of query: ".$aQueryData['type'];
|
||||
}
|
||||
}
|
||||
|
||||
public function Exec()
|
||||
{
|
||||
if ($this->sSql != '')
|
||||
{
|
||||
$iRepeat = utils::ReadParam('repeat', 3);
|
||||
try
|
||||
{
|
||||
$resQuery = null;
|
||||
$fRefTime = MyHelpers::getmicrotime();
|
||||
for($i = 0 ; $i < $iRepeat ; $i++)
|
||||
{
|
||||
$resQuery = CMDBSource::Query($this->sSql);
|
||||
}
|
||||
$this->fExecDuration = (MyHelpers::getmicrotime() - $fRefTime) / $iRepeat;
|
||||
|
||||
// This is not relevant...
|
||||
if (preg_match_all('|\s*JOIN\s*\(\s*`|', $this->sSql, $aMatches)) // JOIN (`mytable...
|
||||
{
|
||||
$this->iTableCount = 1 + count($aMatches[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->iTableCount = 1;
|
||||
}
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
$this->aErrors[] = "Failed to execute the SQL:".$e->getMessage();
|
||||
}
|
||||
if ($resQuery)
|
||||
{
|
||||
while ($aRow = CMDBSource::FetchArray($resQuery))
|
||||
{
|
||||
$this->aRows[] = $aRow;
|
||||
}
|
||||
CMDBSource::FreeResult($resQuery);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function HasErrors()
|
||||
{
|
||||
return (count($this->aErrors) > 0);
|
||||
}
|
||||
|
||||
public function Display($oP)
|
||||
{
|
||||
$oP->p($this->sOqlHtml);
|
||||
$oP->p($this->sQueryType);
|
||||
$oP->p($this->sQueryDesc);
|
||||
foreach ($this->aErrors as $sError)
|
||||
{
|
||||
$oP->p($sError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Main program
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
require_once('../../../approot.inc.php');
|
||||
require_once(APPROOT.'/application/application.inc.php');
|
||||
require_once(APPROOT.'/application/ajaxwebpage.class.inc.php');
|
||||
|
||||
require_once(APPROOT.'/application/startup.inc.php');
|
||||
$operation = utils::ReadParam('operation', '');
|
||||
|
||||
require_once(APPROOT.'/application/loginwebpage.class.inc.php');
|
||||
LoginWebPage::DoLogin(); // Check user rights and prompt if needed
|
||||
|
||||
$oP = new WebPage('Replay queries.log');
|
||||
|
||||
|
||||
ini_set('memory_limit', '512M');
|
||||
|
||||
require_once(APPROOT.'/data/queries.log');
|
||||
$iCount = count($aQueriesLog);
|
||||
$oP->p("Nombre de requêtes: ".$iCount);
|
||||
|
||||
$sOperation = utils::ReadParam('operation', '');
|
||||
|
||||
switch ($sOperation)
|
||||
{
|
||||
case '':
|
||||
default:
|
||||
$oP->add("<ol>\n");
|
||||
foreach ($aQueriesLog as $sQueryId => $aOqlData)
|
||||
{
|
||||
$sOql = $aOqlData['oql'];
|
||||
$sOqlHtml = htmlentities($sOql, ENT_QUOTES, 'UTF-8');
|
||||
$oP->add("<li>$sOqlHtml <a href=\"?operation=zoom&query=$sQueryId\">zoom</a></li>\n");
|
||||
}
|
||||
$oP->add("</ol>\n");
|
||||
|
||||
$oP->add("<form action=\"?operation=benchmark&repeat=3\" method=\"post\">\n");
|
||||
$oP->add("<input type=\"submit\" value=\"Benchmark (3 repeats)!\">\n");
|
||||
$oP->add("</form>\n");
|
||||
|
||||
$oP->add("<form action=\"?operation=check\" method=\"post\">\n");
|
||||
$oP->add("<input type=\"submit\" value=\"Check!\">\n");
|
||||
$oP->add("</form>\n");
|
||||
break;
|
||||
|
||||
case 'zoom':
|
||||
$sQueryId = utils::ReadParam('query', '', false, 'raw_data');
|
||||
$oP->add("<h2>Zoom on query</h2>\n");
|
||||
$oQuery = new QueryLogEntry($sQueryId, $aQueriesLog[$sQueryId]);
|
||||
$oQuery->Exec();
|
||||
$oQuery->Display($oP);
|
||||
|
||||
$oP->add("<pre>$oQuery->sSql</pre>\n");
|
||||
$oP->p("Tables: $oQuery->iTableCount");
|
||||
|
||||
if (strlen($oQuery->sSql) > 0)
|
||||
{
|
||||
$aExplain = CMDBSource::ExplainQuery($oQuery->sSql);
|
||||
$oP->add("<h4>Explain</h4>\n");
|
||||
$oP->add("<table style=\"border=1px;\">\n");
|
||||
foreach ($aExplain as $aRow)
|
||||
{
|
||||
$oP->add(" <tr>\n");
|
||||
$oP->add(" <td>".implode('</td><td>', $aRow)."</td>\n");
|
||||
$oP->add(" </tr>\n");
|
||||
}
|
||||
$oP->add("</table>\n");
|
||||
}
|
||||
|
||||
if (count($oQuery->aRows))
|
||||
{
|
||||
$oP->add("<h4>Values</h4>\n");
|
||||
$oP->add("<table style=\"border=1px;\">\n");
|
||||
foreach ($oQuery->aRows as $iRow => $aRow)
|
||||
{
|
||||
$oP->add(" <tr>\n");
|
||||
$oP->add(" <td>".implode('</td><td>', $aRow)."</td>\n");
|
||||
$oP->add(" </tr>\n");
|
||||
}
|
||||
$oP->add("</table>\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
$oP->p("No data");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
|
||||
case 'check':
|
||||
$oP->add("<h2>List queries in error</h2>\n");
|
||||
foreach ($aQueriesLog as $sQueryId => $aOqlData)
|
||||
{
|
||||
$oQuery = new QueryLogEntry($sQueryId, $aOqlData);
|
||||
$oQuery->Exec();
|
||||
|
||||
if ($oQuery->HasErrors())
|
||||
{
|
||||
$oQuery->Display($oP);
|
||||
$oP->p("<a href=\"?operation=zoom&query=$sQueryId\">zoom</a>");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'benchmark':
|
||||
$oP->add("<h2>Create data/queries.xxx reports</h2>\n");
|
||||
// Reset the log contents
|
||||
file_put_contents(APPROOT.'data/queries.results.log', date('Y-m-d H:i:s')."\n");
|
||||
file_put_contents(APPROOT.'data/queries.benchmark.csv', '');
|
||||
LogBenchmarkCSV('type', 'properties', 'make duration', 'class', 'tables', 'query length', 'exec duration', 'rows', 'oql');
|
||||
|
||||
$iErrors = 0;
|
||||
|
||||
foreach ($aQueriesLog as $sQueryId => $aOqlData)
|
||||
{
|
||||
$oQuery = new QueryLogEntry($sQueryId, $aOqlData);
|
||||
$oQuery->Exec();
|
||||
|
||||
LogResult('-----------------------------------------------------------');
|
||||
LogResult($oQuery->sOql);
|
||||
LogResult($oQuery->sQueryType);
|
||||
if (strlen($oQuery->sQueryDesc) > 0)
|
||||
{
|
||||
LogResult($oQuery->sQueryDesc);
|
||||
}
|
||||
|
||||
if ($oQuery->HasErrors())
|
||||
{
|
||||
foreach($oQuery->aErrors as $sError)
|
||||
{
|
||||
LogResult($sError);
|
||||
$iErrors++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogResult("row count = ".count($oQuery->aRows));
|
||||
foreach($oQuery->aRows as $iRow => $aRow)
|
||||
{
|
||||
LogResult("row: ".serialize($aRow));
|
||||
if ($iRow > 100) break;
|
||||
}
|
||||
|
||||
LogBenchmarkCSV($oQuery->sQueryType, $oQuery->sQueryDesc, sprintf('%1.3f', round($oQuery->fMakeDuration, 3)), $oQuery->sClass, $oQuery->iTableCount, strlen($oQuery->sSql), sprintf('%1.4f', round($oQuery->fExecDuration, 4)), count($oQuery->aRows), $oQuery->sOql);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$oP->output();
|
||||
?>
|
||||
552
tests/php-unit-tests/legacy-tests/test.class.inc.php
Normal file
552
tests/php-unit-tests/legacy-tests/test.class.inc.php
Normal file
@@ -0,0 +1,552 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2017 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/>
|
||||
|
||||
/**
|
||||
* Core automated tests - basics
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2017 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
|
||||
require_once(APPROOT.'/core/coreexception.class.inc.php');
|
||||
require_once(APPROOT.'/core/attributedef.class.inc.php');
|
||||
require_once(APPROOT.'/core/filterdef.class.inc.php');
|
||||
require_once(APPROOT.'/core/stimulus.class.inc.php');
|
||||
require_once(APPROOT.'/core/MyHelpers.class.inc.php');
|
||||
|
||||
require_once(APPROOT.'/core/oql/expression.class.inc.php');
|
||||
require_once(APPROOT.'/core/cmdbsource.class.inc.php');
|
||||
require_once(APPROOT.'/core/sqlquery.class.inc.php');
|
||||
require_once(APPROOT.'/core/sqlobjectquery.class.inc.php');
|
||||
require_once(APPROOT.'/core/sqlunionquery.class.inc.php');
|
||||
|
||||
require_once(APPROOT.'/core/log.class.inc.php');
|
||||
require_once(APPROOT.'/core/kpi.class.inc.php');
|
||||
|
||||
require_once(APPROOT.'/core/dbobject.class.php');
|
||||
require_once(APPROOT.'/core/dbsearch.class.php');
|
||||
require_once(APPROOT.'/core/dbobjectset.class.php');
|
||||
|
||||
require_once(APPROOT.'/application/cmdbabstract.class.inc.php');
|
||||
|
||||
require_once(APPROOT.'/core/userrights.class.inc.php');
|
||||
|
||||
require_once(APPROOT.'/webservices/webservices.class.inc.php');
|
||||
|
||||
|
||||
// Just to differentiate programmatically triggered exceptions and other kind of errors (usefull?)
|
||||
class UnitTestException extends Exception
|
||||
{}
|
||||
|
||||
|
||||
/**
|
||||
* Improved display of the backtrace
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class ExceptionFromError extends Exception
|
||||
{
|
||||
public function getTraceAsHtml()
|
||||
{
|
||||
$aBackTrace = $this->getTrace();
|
||||
return MyHelpers::get_callstack_html(0, $this->getTrace());
|
||||
// return "<pre>\n".$this->getTraceAsString()."</pre>\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test handler API and basic helpers
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
abstract class TestHandler
|
||||
{
|
||||
protected $m_aSuccesses;
|
||||
protected $m_aWarnings;
|
||||
protected $m_aErrors;
|
||||
protected $m_sOutput;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->m_aSuccesses = array();
|
||||
$this->m_aWarnings = array();
|
||||
$this->m_aErrors = array();
|
||||
}
|
||||
|
||||
static public function GetName() {return "fooname";}
|
||||
static public function GetDescription(){return "foodesc";}
|
||||
|
||||
protected function DoPrepare() {return true;}
|
||||
abstract protected function DoExecute();
|
||||
protected function DoCleanup() {return true;}
|
||||
|
||||
protected static function DumpVariable($var)
|
||||
{
|
||||
echo "<pre class=\"vardump\">\n";
|
||||
print_r($var);
|
||||
echo "</pre>\n";
|
||||
}
|
||||
|
||||
protected function ReportSuccess($sMessage, $sSubtestId = '')
|
||||
{
|
||||
$this->m_aSuccesses[] = $sMessage;
|
||||
}
|
||||
|
||||
protected function ReportWarning($sMessage, $sSubtestId = '')
|
||||
{
|
||||
$this->m_aWarnings[] = $sMessage;
|
||||
}
|
||||
|
||||
protected function ReportError($sMessage, $sSubtestId = '')
|
||||
{
|
||||
$this->m_aErrors[] = $sMessage;
|
||||
}
|
||||
|
||||
public function GetResults()
|
||||
{
|
||||
return $this->m_aSuccesses;
|
||||
}
|
||||
|
||||
public function GetWarnings()
|
||||
{
|
||||
return $this->m_aWarnings;
|
||||
}
|
||||
|
||||
public function GetErrors()
|
||||
{
|
||||
return $this->m_aErrors;
|
||||
}
|
||||
|
||||
public function GetOutput()
|
||||
{
|
||||
return $this->m_sOutput;
|
||||
}
|
||||
|
||||
public function error_handler($errno, $errstr, $errfile, $errline)
|
||||
{
|
||||
// Note: return false to call the default handler (stop the program if an error)
|
||||
|
||||
if ($errstr == 'assert()') $errno = E_USER_ERROR;
|
||||
|
||||
switch ($errno)
|
||||
{
|
||||
case E_USER_ERROR:
|
||||
case E_WARNING: //(assertion failed)
|
||||
$this->ReportError("$errfile@$errline - $errstr");
|
||||
break;
|
||||
case E_USER_WARNING:
|
||||
$this->ReportWarning("$errfile@$errline - $errstr");
|
||||
break;
|
||||
case E_USER_NOTICE:
|
||||
$this->ReportWarning("$errfile@$errline - $errstr");
|
||||
break;
|
||||
default:
|
||||
$this->ReportWarning("$errfile@$errline - Unknown error type: [$errno] $errstr");
|
||||
echo "Unknown error type: [$errno] $errstr in $errfile at $errline<br />\n";
|
||||
break;
|
||||
}
|
||||
return true; // do not call the default handler
|
||||
}
|
||||
|
||||
public function Execute()
|
||||
{
|
||||
ob_start();
|
||||
set_error_handler(array($this, 'error_handler'));
|
||||
try
|
||||
{
|
||||
$this->DoPrepare();
|
||||
$this->DoExecute();
|
||||
}
|
||||
catch (ExceptionFromError $e)
|
||||
{
|
||||
$this->ReportError($e->getMessage().' - '.$e->getTraceAsHtml());
|
||||
}
|
||||
catch (CoreException $e)
|
||||
{
|
||||
//$this->ReportError($e->getMessage());
|
||||
//$this->ReportError($e->__tostring());
|
||||
$this->ReportError($e->getMessage().' - '.$e->getTraceAsHtml());
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
//$this->ReportError($e->getMessage());
|
||||
//$this->ReportError($e->__tostring());
|
||||
$this->ReportError('class '.get_class($e).' --- '.$e->getMessage().' - '.$e->getTraceAsString());
|
||||
}
|
||||
restore_error_handler();
|
||||
$this->m_sOutput = ob_get_clean();
|
||||
return (count($this->GetErrors()) == 0);
|
||||
}
|
||||
|
||||
static protected function DoPostRequestAuth($sRelativeUrl, $aData, $sLogin = 'admin', $sPassword = 'admin', $sOptionnalHeaders = null)
|
||||
{
|
||||
$aDataAndAuth = $aData;
|
||||
// To be changed to use basic authentication
|
||||
$aDataAndAuth['operation'] = 'login';
|
||||
$aDataAndAuth['auth_user'] = $sLogin;
|
||||
$aDataAndAuth['auth_pwd'] = $sPassword;
|
||||
$sHost = $_SERVER['HTTP_HOST'];
|
||||
$sRawPath = $_SERVER['SCRIPT_NAME'];
|
||||
$sPath = dirname($sRawPath);
|
||||
$sUrl = "http://$sHost/$sPath/$sRelativeUrl";
|
||||
|
||||
return self::DoPostRequest($sUrl, $aDataAndAuth, $sOptionnalHeaders);
|
||||
}
|
||||
|
||||
// Source: http://netevil.org/blog/2006/nov/http-post-from-php-without-curl
|
||||
// originaly named after do_post_request
|
||||
// Partially adapted to our coding conventions
|
||||
static protected function DoPostRequest($sUrl, $aData, $sOptionnalHeaders = null)
|
||||
{
|
||||
// $sOptionnalHeaders is a string containing additional HTTP headers that you would like to send in your request.
|
||||
|
||||
$sData = http_build_query($aData);
|
||||
|
||||
$aParams = array('http' => array(
|
||||
'method' => 'POST',
|
||||
'content' => $sData,
|
||||
'header'=> "Content-type: application/x-www-form-urlencoded\r\nContent-Length: ".strlen($sData)."\r\n",
|
||||
));
|
||||
if ($sOptionnalHeaders !== null)
|
||||
{
|
||||
$aParams['http']['header'] .= $sOptionnalHeaders;
|
||||
}
|
||||
$ctx = stream_context_create($aParams);
|
||||
|
||||
$fp = @fopen($sUrl, 'rb', false, $ctx);
|
||||
if (!$fp)
|
||||
{
|
||||
global $php_errormsg;
|
||||
if (isset($php_errormsg))
|
||||
{
|
||||
throw new Exception("Problem with $sUrl, $php_errormsg");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Problem with $sUrl");
|
||||
}
|
||||
}
|
||||
$response = @stream_get_contents($fp);
|
||||
if ($response === false)
|
||||
{
|
||||
throw new Exception("Problem reading data from $sUrl, $php_errormsg");
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Test to execute a piece of code (checks if an error occurs)
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
abstract class TestFunction extends TestHandler
|
||||
{
|
||||
// simply overload DoExecute (temporary)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test to execute a piece of code (checks if an error occurs)
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
abstract class TestWebServices extends TestHandler
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to execute a piece of code (checks if an error occurs)
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
abstract class TestSoapWebService extends TestHandler
|
||||
{
|
||||
// simply overload DoExecute (temporary)
|
||||
|
||||
function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to check that a function outputs some values depending on its input
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
abstract class TestFunctionInOut extends TestFunction
|
||||
{
|
||||
// abstract static public function GetCallSpec(); // parameters to call_user_func
|
||||
// abstract static public function GetInOut(); // array of input => output
|
||||
|
||||
protected function DoExecute()
|
||||
{
|
||||
$aTests = $this->GetInOut();
|
||||
if (is_array($aTests))
|
||||
{
|
||||
foreach ($aTests as $iTestId => $aTest)
|
||||
{
|
||||
$ret = call_user_func_array($this->GetCallSpec(), $aTest['args']);
|
||||
if ($ret != $aTest['output'])
|
||||
{
|
||||
// Note: to be improved to cope with non string parameters
|
||||
$this->ReportError("Found '$ret' while expecting '".$aTest['output']."'", $iTestId);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->ReportSuccess("Found the expected output '$ret'", $iTestId);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$ret = call_user_func($this->GetCallSpec());
|
||||
$this->ReportSuccess('Finished successfully');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test to check an URL (Searches for Error/Warning/Etc keywords)
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
abstract class TestUrl extends TestHandler
|
||||
{
|
||||
// abstract static public function GetUrl();
|
||||
// abstract static public function GetErrorKeywords();
|
||||
// abstract static public function GetWarningKeywords();
|
||||
|
||||
protected function DoExecute()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test to check a user management module
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
abstract class TestUserRights extends TestHandler
|
||||
{
|
||||
protected function DoExecute()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test to execute a scenario on a given DB
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
abstract class TestScenarioOnDB extends TestHandler
|
||||
{
|
||||
// abstract static public function GetDBHost();
|
||||
// abstract static public function GetDBUser();
|
||||
// abstract static public function GetDBPwd();
|
||||
// abstract static public function GetDBName();
|
||||
|
||||
protected function DoPrepare()
|
||||
{
|
||||
$sDBHost = $this->GetDBHost();
|
||||
$sDBUser = $this->GetDBUser();
|
||||
$sDBPwd = $this->GetDBPwd();
|
||||
$sDBName = $this->GetDBName();
|
||||
|
||||
CMDBSource::Init($sDBHost, $sDBUser, $sDBPwd);
|
||||
CMDBSource::SetCharacterSet();
|
||||
if (CMDBSource::IsDB($sDBName))
|
||||
{
|
||||
CMDBSource::DropDB($sDBName);
|
||||
}
|
||||
CMDBSource::CreateDB($sDBName);
|
||||
}
|
||||
|
||||
protected function DoCleanup()
|
||||
{
|
||||
// CMDBSource::DropDB($this->GetDBName());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test to use a business model on a given DB
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
abstract class TestBizModel extends TestHandler
|
||||
{
|
||||
// abstract static public function GetDBSubName();
|
||||
// abstract static public function GetBusinessModelFile();
|
||||
// abstract static public function GetConfigFile();
|
||||
|
||||
static public function GetConfigFile() {return 'conf/production/config-itop.php';}
|
||||
|
||||
protected function DoPrepare()
|
||||
{
|
||||
$sConfigFile = APPROOT.$this->GetConfigFile();
|
||||
MetaModel::Startup($sConfigFile);
|
||||
// #@# Temporary disabled by Romain
|
||||
// MetaModel::CheckDefinitions();
|
||||
|
||||
// something here to create records... but that's another story
|
||||
}
|
||||
|
||||
protected $m_oChange;
|
||||
protected function GetCurrentChange()
|
||||
{
|
||||
if (!isset($this->m_oChange))
|
||||
{
|
||||
new CMDBChange();
|
||||
$oMyChange = MetaModel::NewObject("CMDBChange");
|
||||
$oMyChange->Set("date", time());
|
||||
$oMyChange->Set("userinfo", "Someone doing some tests");
|
||||
$iChangeId = $oMyChange->DBInsertNoReload();
|
||||
$this->m_oChange = $oMyChange;
|
||||
}
|
||||
return $this->m_oChange;
|
||||
}
|
||||
protected function ObjectToDB($oNew, $bReload = false)
|
||||
{
|
||||
if ($bReload)
|
||||
{
|
||||
$iId = $oNew->DBInsert();
|
||||
}
|
||||
else
|
||||
{
|
||||
$iId = $oNew->DBInsertNoReload();
|
||||
}
|
||||
return $iId;
|
||||
}
|
||||
|
||||
protected function UpdateObjectInDB($oObject)
|
||||
{
|
||||
$oObject->DBUpdate();
|
||||
}
|
||||
protected function ResetDB()
|
||||
{
|
||||
if (MetaModel::DBExists(false))
|
||||
{
|
||||
MetaModel::DBDrop();
|
||||
}
|
||||
MetaModel::DBCreate();
|
||||
}
|
||||
|
||||
static protected function show_list($oObjectSet)
|
||||
{
|
||||
$oObjectSet->Rewind();
|
||||
$aData = array();
|
||||
while ($oItem = $oObjectSet->Fetch())
|
||||
{
|
||||
$aValues = array();
|
||||
foreach(MetaModel::GetAttributesList(get_class($oItem)) as $sAttCode)
|
||||
{
|
||||
$aValues[$sAttCode] = $oItem->GetAsHTML($sAttCode);
|
||||
}
|
||||
//echo $oItem->GetKey()." => ".implode(", ", $aValues)."</br>\n";
|
||||
$aData[] = $aValues;
|
||||
}
|
||||
echo MyHelpers::make_table_from_assoc_array($aData);
|
||||
}
|
||||
|
||||
static protected function search_and_show_list(DBSearch $oMyFilter)
|
||||
{
|
||||
$oObjSet = new CMDBObjectSet($oMyFilter);
|
||||
echo $oMyFilter->ToOQL()."' - Found ".$oObjSet->Count()." items.</br>\n";
|
||||
self::show_list($oObjSet);
|
||||
}
|
||||
|
||||
static protected function search_and_show_list_from_oql($sOQL)
|
||||
{
|
||||
echo $sOQL."...<br/>\n";
|
||||
$oNewFilter = DBObjectSearch::FromOQL($sOQL);
|
||||
self::search_and_show_list($oNewFilter);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test to execute a scenario common to any business model (tries to build all the possible queries, etc.)
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
abstract class TestBizModelGeneric extends TestBizModel
|
||||
{
|
||||
static public function GetName()
|
||||
{
|
||||
return 'Full test on a given business model';
|
||||
}
|
||||
|
||||
static public function GetDescription()
|
||||
{
|
||||
return 'Systematic tests: gets each and every existing class and tries every attribute, search filters, etc.';
|
||||
}
|
||||
|
||||
protected function DoPrepare()
|
||||
{
|
||||
parent::DoPrepare();
|
||||
|
||||
if (!MetaModel::DBExists(false))
|
||||
{
|
||||
MetaModel::DBCreate();
|
||||
}
|
||||
// something here to create records... but that's another story
|
||||
}
|
||||
|
||||
protected function DoExecute()
|
||||
{
|
||||
foreach(MetaModel::GetClasses() as $sClassName)
|
||||
{
|
||||
if (MetaModel::HasTable($sClassName)) continue;
|
||||
|
||||
$oNobody = MetaModel::GetObject($sClassName, 123);
|
||||
$oBaby = new $sClassName;
|
||||
$oFilter = new DBObjectSearch($sClassName);
|
||||
|
||||
// Challenge reversibility of OQL / filter object
|
||||
//
|
||||
$sExpr1 = $oFilter->ToOQL();
|
||||
$oNewFilter = DBObjectSearch::FromOQL($sExpr1);
|
||||
$sExpr2 = $oNewFilter->ToOQL();
|
||||
if ($sExpr1 != $sExpr2)
|
||||
{
|
||||
$this->ReportError("Found two different OQL expression out of the (same?) filter: <em>$sExpr1</em> != <em>$sExpr2</em>");
|
||||
}
|
||||
|
||||
// Use the filter (perform the query)
|
||||
//
|
||||
$oSet = new CMDBObjectSet($oFilter);
|
||||
$this->ReportSuccess('Found '.$oSet->Count()." objects of class $sClassName");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
162
tests/php-unit-tests/legacy-tests/test.php
Normal file
162
tests/php-unit-tests/legacy-tests/test.php
Normal file
@@ -0,0 +1,162 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2019 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
|
||||
*/
|
||||
|
||||
?>
|
||||
<style>
|
||||
.vardump {
|
||||
font-size:8pt;
|
||||
line-height:100%;
|
||||
}
|
||||
</style>
|
||||
<?php
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Helpers
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function ReadMandatoryParam($sName)
|
||||
{
|
||||
$value = utils::ReadParam($sName, null);
|
||||
if (is_null($value))
|
||||
{
|
||||
echo "<p>Missing mandatory argument <b>$sName</b></p>";
|
||||
exit;
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
function IsAValidTestClass($sClassName)
|
||||
{
|
||||
// Must be a child of TestHandler
|
||||
//
|
||||
if (!is_subclass_of($sClassName, 'TestHandler')) return false;
|
||||
|
||||
// Must not be abstract
|
||||
//
|
||||
$oReflectionClass = new ReflectionClass($sClassName);
|
||||
if (!$oReflectionClass->isInstantiable()) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function GetTestClassLine($sClassName)
|
||||
{
|
||||
$oReflectionClass = new ReflectionClass($sClassName);
|
||||
return $oReflectionClass->getStartLine();
|
||||
}
|
||||
|
||||
function DisplayEvents($aEvents, $sTitle)
|
||||
{
|
||||
echo "<h4>$sTitle</h4>\n";
|
||||
if (count($aEvents) > 0)
|
||||
{
|
||||
echo "<ul>\n";
|
||||
foreach ($aEvents as $sEvent)
|
||||
{
|
||||
echo "<li>$sEvent</li>\n";
|
||||
}
|
||||
echo "</ul>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
echo "<p>none</p>\n";
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Main
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
date_default_timezone_set('Europe/Paris');
|
||||
|
||||
require_once('../../../approot.inc.php');
|
||||
require_once(APPROOT.'/application/utils.inc.php');
|
||||
require_once('./test.class.inc.php');
|
||||
require_once('./testlist.inc.php');
|
||||
|
||||
require_once(APPROOT.'/core/cmdbobject.class.inc.php');
|
||||
|
||||
|
||||
$sTodo = utils::ReadParam("todo", "");
|
||||
if ($sTodo == '')
|
||||
{
|
||||
// Show the list of tests
|
||||
//
|
||||
echo "<h3>Existing tests</h3>\n";
|
||||
echo "<ul>\n";
|
||||
foreach (get_declared_classes() as $sClassName)
|
||||
{
|
||||
if (!IsAValidTestClass($sClassName)) continue;
|
||||
|
||||
$sName = call_user_func(array($sClassName, 'GetName'));
|
||||
$sDescription = call_user_func(array($sClassName, 'GetDescription'));
|
||||
echo "<li><a href=\"?todo=exec&testid=$sClassName\">$sName</a> ($sDescription)</li>\n";
|
||||
}
|
||||
echo "</ul>\n";
|
||||
}
|
||||
else if ($sTodo == 'exec')
|
||||
{
|
||||
// Execute a test
|
||||
//
|
||||
$sTestClass = ReadMandatoryParam("testid");
|
||||
|
||||
if (!IsAValidTestClass($sTestClass))
|
||||
{
|
||||
echo "<p>Wrong value for testid, expecting a valid class name</p>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$oTest = new $sTestClass();
|
||||
$iStartLine = GetTestClassLine($sTestClass);
|
||||
echo "<h3>Testing: ".$oTest->GetName()."</h3>\n";
|
||||
echo "<h6>testlist.inc.php: $iStartLine</h6>\n";
|
||||
$bRes = $oTest->Execute();
|
||||
}
|
||||
|
||||
/*
|
||||
MyHelpers::var_dump_html($oTest->GetResults());
|
||||
MyHelpers::var_dump_html($oTest->GetWarnings());
|
||||
MyHelpers::var_dump_html($oTest->GetErrors());
|
||||
*/
|
||||
|
||||
if ($bRes)
|
||||
{
|
||||
echo "<p>Success :-)</p>\n";
|
||||
DisplayEvents($oTest->GetResults(), 'Results');
|
||||
}
|
||||
else
|
||||
{
|
||||
echo "<p>Failure :-(</p>\n";
|
||||
}
|
||||
DisplayEvents($oTest->GetErrors(), 'Errors');
|
||||
DisplayEvents($oTest->GetWarnings(), 'Warnings');
|
||||
|
||||
// Render the output
|
||||
//
|
||||
echo "<h4>Actual output</h4>\n";
|
||||
echo "<div style=\"border: dashed; background-color:light-grey;\">\n";
|
||||
echo $oTest->GetOutput();
|
||||
echo "</div>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
5203
tests/php-unit-tests/legacy-tests/testlist.inc.php
Normal file
5203
tests/php-unit-tests/legacy-tests/testlist.inc.php
Normal file
File diff suppressed because it is too large
Load Diff
81
tests/php-unit-tests/phpunit.xml.dist
Normal file
81
tests/php-unit-tests/phpunit.xml.dist
Normal file
@@ -0,0 +1,81 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/8.5/phpunit.xsd"
|
||||
bootstrap="unittestautoload.php"
|
||||
backupGlobals="true"
|
||||
colors="true"
|
||||
columns="120"
|
||||
convertErrorsToExceptions="true"
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnError="false"
|
||||
stopOnFailure="false"
|
||||
stopOnIncomplete="false"
|
||||
stopOnRisky="false"
|
||||
stopOnSkipped="false"
|
||||
verbose="true"
|
||||
printerClass="Sempro\PHPUnitPrettyPrinter\PrettyPrinter"
|
||||
>
|
||||
|
||||
<php>
|
||||
<ini name="error_reporting" value="E_ALL"/>
|
||||
<ini name="display_errors" value="On"/>
|
||||
<ini name="log_errors" value="On"/>
|
||||
<ini name="html_errors" value="Off"/>
|
||||
<env name="PHPUNIT_PRETTY_PRINT_PROGRESS" value="true"/>
|
||||
</php>
|
||||
|
||||
<testsuites>
|
||||
<testsuite name="Application">
|
||||
<directory>unitary-tests/application</directory>
|
||||
</testsuite>
|
||||
<testsuite name="Core">
|
||||
<directory>unitary-tests/core</directory>
|
||||
</testsuite>
|
||||
<!-- Important: For now this suite must be here and not with the other core module suites or it will crash the CI -->
|
||||
<testsuite name="Authent-local">
|
||||
<directory>unitary-tests/datamodels/2.x/authent-local</directory>
|
||||
</testsuite>
|
||||
<testsuite name="Integration">
|
||||
<directory>integration-tests</directory>
|
||||
</testsuite>
|
||||
<testsuite name="Itop-Config">
|
||||
<directory>unitary-tests/datamodels/2.x/itop-config</directory>
|
||||
</testsuite>
|
||||
<testsuite name="Itop-Tickets">
|
||||
<directory>unitary-tests/datamodels/2.x/itop-tickets</directory>
|
||||
</testsuite>
|
||||
<testsuite name="Setup">
|
||||
<directory>unitary-tests/setup</directory>
|
||||
</testsuite>
|
||||
<!-- Note: The unitary-tests/sources/application/TwigBase is omitted for now as the test is not working -->
|
||||
<testsuite name="SourcesApplicationSearch">
|
||||
<directory>unitary-tests/sources/application/search</directory>
|
||||
</testsuite>
|
||||
<testsuite name="SourcesComposer">
|
||||
<directory>unitary-tests/sources/Composer</directory>
|
||||
</testsuite>
|
||||
<testsuite name="Status">
|
||||
<directory>unitary-tests/status</directory>
|
||||
</testsuite>
|
||||
<testsuite name="Webservices">
|
||||
<directory>unitary-tests/webservices</directory>
|
||||
</testsuite>
|
||||
|
||||
<testsuite name="Extensions">
|
||||
<directory>../../../env-production/*/test</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<!-- Code coverage white list -->
|
||||
<filter>
|
||||
<whitelist>
|
||||
<file>../../../core/apc-emulation.php</file>
|
||||
<file>../../../core/ormlinkset.class.inc.php</file>
|
||||
<file>../../../datamodels/2.x/itop-tickets/main.itop-tickets.php</file>
|
||||
</whitelist>
|
||||
</filter>
|
||||
|
||||
</phpunit>
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2010-2020 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/>
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\ReleaseChecklist;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
use iTopDesignFormat;
|
||||
|
||||
|
||||
/**
|
||||
* Class iTopDesignFormatChecklistTest
|
||||
*
|
||||
* @covers iTopDesignFormat
|
||||
*/
|
||||
class SetupCssIntegrityChecklistTest extends ItopTestCase
|
||||
{
|
||||
public function testSetupCssIntegrity()
|
||||
{
|
||||
$sSetupCssPath = APPROOT.'css/setup.css';
|
||||
$sSetupCssContent = file_get_contents($sSetupCssPath);
|
||||
$this->assertContains('/* integrityCheck: begin (do not remove/edit) */', $sSetupCssContent);
|
||||
$this->assertContains('/* integrityCheck: end (do not remove/edit) */', $sSetupCssContent);
|
||||
$this->assertGreaterThan(4000, strlen($sSetupCssContent), "Test if the resulting file $sSetupCssPath is long enough, the value is totally arbitrary (at the time of the writing the file is 5660o long");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\ReleaseChecklist;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
use iTopDesignFormat;
|
||||
use PHPUnit\Exception;
|
||||
|
||||
|
||||
/**
|
||||
* Class iTopDesignFormatChecklistTest
|
||||
* Ticket 3053 - Check XML conversion methods
|
||||
*
|
||||
* @covers iTopDesignFormat
|
||||
*
|
||||
* @package Combodo\iTop\Test\UnitTest\Setup
|
||||
*/
|
||||
class TestForITopDesignFormatClass extends ItopTestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
require_once APPROOT.'setup/modelfactory.class.inc.php';
|
||||
require_once APPROOT.'setup/itopdesignformat.class.inc.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* release checklist step: make sure we have datamodel conversion functions for new iTop version
|
||||
*/
|
||||
public function testCurrentVersion_DataModelConversionFunctions()
|
||||
{
|
||||
$aErrors = [];
|
||||
$aDatamodelCurrentVersions = array();
|
||||
$aDataModelFiles = $this->GetDataModelFiles(APPROOT.'/datamodels');
|
||||
|
||||
//retrieve current XML version in datamoldels files
|
||||
foreach ($aDataModelFiles as $sDataModelFile)
|
||||
{
|
||||
if (preg_match('/itop_design .* version="([\d\.]*)"/', file_get_contents($sDataModelFile), $aMatches))
|
||||
{
|
||||
$sVersion = $aMatches[1];
|
||||
if (!array_key_exists($sVersion, $aDatamodelCurrentVersions))
|
||||
{
|
||||
if (trim($sVersion) === '')
|
||||
{
|
||||
$aErrors[] = "cannot retrieve itop_design datamodel version in $sDataModelFile:1";
|
||||
continue;
|
||||
}
|
||||
|
||||
$aDatamodelCurrentVersions[$sVersion] = $sVersion;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//make sure there is only one found
|
||||
$this->assertTrue(is_array($aDatamodelCurrentVersions));
|
||||
|
||||
$sFirstVersion = array_keys(iTopDesignFormat::$aVersions)[0];
|
||||
$sLatestVersion = array_keys(iTopDesignFormat::$aVersions)[count(iTopDesignFormat::$aVersions)-1];
|
||||
foreach ($aDatamodelCurrentVersions as $sCurrentVersion)
|
||||
{
|
||||
try{
|
||||
//check we have migration function from current version to previous
|
||||
$this->CheckCondition(array_key_exists($sCurrentVersion, iTopDesignFormat::$aVersions), "Missing $sCurrentVersion conversion functions in iTopDesignFormat.");
|
||||
$aCurrentVersionInfo = iTopDesignFormat::$aVersions[$sCurrentVersion];
|
||||
$this->CheckCondition(is_array($aCurrentVersionInfo), "Wrong $sCurrentVersion config in iTopDesignFormat.");
|
||||
$this->CheckCondition(array_key_exists('previous', $aCurrentVersionInfo), "Missing previous for $sCurrentVersion config in iTopDesignFormat.");
|
||||
$this->TestDefinedFunction($aCurrentVersionInfo, 'go_to_next', $sCurrentVersion, ($sCurrentVersion=== $sLatestVersion));
|
||||
$this->TestDefinedFunction($aCurrentVersionInfo, 'go_to_previous', $sCurrentVersion, ($sCurrentVersion==='1.0'));
|
||||
|
||||
//check we have migration function from N-1 version to current one
|
||||
if (($sCurrentVersion!=='1.0')) {
|
||||
$sPreviousVersion = $aCurrentVersionInfo['previous'];
|
||||
$this->CheckCondition(array_key_exists($sPreviousVersion, iTopDesignFormat::$aVersions),
|
||||
"$sCurrentVersion: Missing $sPreviousVersion config in iTopDesignFormat.");
|
||||
$aPreviousVersionInfo = iTopDesignFormat::$aVersions[$sPreviousVersion];
|
||||
$this->CheckCondition(is_array($aPreviousVersionInfo),
|
||||
"$sCurrentVersion: wrong $sPreviousVersion config in iTopDesignFormat.");
|
||||
$this->CheckCondition(array_key_exists('previous', $aPreviousVersionInfo),
|
||||
"$sCurrentVersion: Missing previous for $sPreviousVersion config in iTopDesignFormat.");
|
||||
$this->TestDefinedFunction($aPreviousVersionInfo, 'go_to_previous', $sPreviousVersion, ($sPreviousVersion === '1.0'));
|
||||
$this->TestDefinedFunction($aPreviousVersionInfo, 'go_to_next', $sPreviousVersion, ($sPreviousVersion === $sLatestVersion));
|
||||
}
|
||||
|
||||
//check we have migration function from current version to next one
|
||||
if (($sCurrentVersion!== $sLatestVersion)) {
|
||||
$sNextVersion = $aCurrentVersionInfo['next'];
|
||||
$this->CheckCondition(array_key_exists($sNextVersion, iTopDesignFormat::$aVersions),
|
||||
"$sCurrentVersion: Missing $sNextVersion config in iTopDesignFormat.");
|
||||
$aNextVersionInfo = iTopDesignFormat::$aVersions[$sNextVersion];
|
||||
$this->CheckCondition(is_array($aNextVersionInfo),
|
||||
"$sCurrentVersion: wrong $sNextVersion config in iTopDesignFormat.");
|
||||
$this->CheckCondition(array_key_exists('previous', $aNextVersionInfo),
|
||||
"$sCurrentVersion: Missing previous for $sNextVersion config in iTopDesignFormat.");
|
||||
$this->TestDefinedFunction($aNextVersionInfo, 'go_to_previous', $sNextVersion, ($sNextVersion === '1.0'));
|
||||
$this->TestDefinedFunction($aNextVersionInfo, 'go_to_next', $sNextVersion, ($sNextVersion === $sLatestVersion));
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
$aErrors[] = $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
if (count($aErrors)!=0)
|
||||
{
|
||||
$sMsg = "Issue with conversion functions:\n";
|
||||
$sMsg .= implode("\n", $aErrors);
|
||||
$this->fail($sMsg);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
private function CheckCondition($bCondition, $sMsg)
|
||||
{
|
||||
if ($bCondition === false)
|
||||
{
|
||||
throw new \Exception($sMsg);
|
||||
}
|
||||
}
|
||||
|
||||
private function TestDefinedFunction($aCurrentVersionInfo, $sFunctionKey, $sVersion, $bNullFunction=false)
|
||||
{
|
||||
$sInfo = json_encode($aCurrentVersionInfo, true);
|
||||
$this->CheckCondition(array_key_exists($sFunctionKey, $aCurrentVersionInfo), "Missing $sFunctionKey in $sVersion config in iTopDesignFormat: " . $sInfo);
|
||||
//echo $aCurrentVersionInfo[$sFunctionKey].'\n';
|
||||
if ($bNullFunction === false)
|
||||
{
|
||||
$oReflectionClass = new \ReflectionClass(iTopDesignFormat::class);
|
||||
$this->CheckCondition($oReflectionClass->hasMethod($aCurrentVersionInfo[$sFunctionKey]), "wrong go_to_previous function '".$aCurrentVersionInfo[$sFunctionKey]."'' for $sVersion config in iTopDesignFormat." . $sInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->CheckCondition(is_null($aCurrentVersionInfo[$sFunctionKey]), "$sVersion $sFunctionKey function should be null");
|
||||
}
|
||||
}
|
||||
|
||||
public function GetDataModelFiles($sFolder)
|
||||
{
|
||||
$aDataModelFiles = array();
|
||||
if (is_dir($sFolder))
|
||||
{
|
||||
foreach (glob($sFolder."/*") as $sPath)
|
||||
{
|
||||
if (is_dir($sPath))
|
||||
{
|
||||
/** @noinspection SlowArrayOperationsInLoopInspection */
|
||||
$aDataModelFiles = array_merge($aDataModelFiles, $this->GetDataModelFiles($sPath));
|
||||
}
|
||||
else if (preg_match("/datamodel\..*\.xml/", basename($sPath)))
|
||||
{
|
||||
$aDataModelFiles[] = $sPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $aDataModelFiles;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\ReleaseChecklist;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
use iTopDesignFormat;
|
||||
|
||||
|
||||
/**
|
||||
* Class iTopDesignFormatChecklistTest
|
||||
* Ticket 3061 - Automatically check the installation.xml consistency
|
||||
*
|
||||
* @covers iTopDesignFormat
|
||||
*
|
||||
* @package Combodo\iTop\Test\UnitTest\Setup
|
||||
*/
|
||||
class iTopModuleXmlInstallationChecklistTest extends ItopTestCase
|
||||
{
|
||||
/**
|
||||
* make sure installation.xml is provided and respects XML format
|
||||
*/
|
||||
public function testInstallationXmlFormat()
|
||||
{
|
||||
$sInstallationXmlPath = APPROOT . 'datamodels/2.x/installation.xml';
|
||||
$this->assertTrue(is_file($sInstallationXmlPath), "$sInstallationXmlPath does not exist");
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
try{
|
||||
$doc->loadxml(file_get_contents($sInstallationXmlPath));
|
||||
}
|
||||
catch(\Exception $e)
|
||||
{
|
||||
$this->assertFalse(true, "$sInstallationXmlPath is not a valid XML content: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* make sure installation.xml includes all packaged modules
|
||||
*/
|
||||
public function testAllModuleAreIncludedInInstallationXml()
|
||||
{
|
||||
$sInstallationXmlPath = APPROOT.'datamodels/2.x/installation.xml';
|
||||
if (!is_file($sInstallationXmlPath)) {
|
||||
$sInstallationXmlPath = APPROOT.'datamodels/1.x/installation.xml';
|
||||
}
|
||||
$this->assertTrue(is_file($sInstallationXmlPath), "$sInstallationXmlPath does not exist");
|
||||
|
||||
$sInstallationXmlContent = file_get_contents($sInstallationXmlPath);
|
||||
preg_match_all("|<module>(.*)</module>|", $sInstallationXmlContent, $aMatches);
|
||||
$aDeclaredModules = [];
|
||||
if (!empty($aMatches)) {
|
||||
foreach ($aMatches[1] as $sModule) {
|
||||
if (!array_key_exists($sModule, $aDeclaredModules)) {
|
||||
$aDeclaredModules[$sModule] = $sModule;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->assertArraySubset(
|
||||
$this->GetFilteredModulesFromDatamodels(APPROOT.'/datamodels'),
|
||||
$aDeclaredModules,
|
||||
false,
|
||||
"{$sInstallationXmlPath} does not list all modules in /datamodels ! List of modules in installation.xml:\n ".var_export($aDeclaredModules, true)
|
||||
);
|
||||
|
||||
$aModulesFromDatamodels = $this->GetAllModules(APPROOT.'/datamodels');
|
||||
$this->assertArraySubset(
|
||||
$aDeclaredModules,
|
||||
$aModulesFromDatamodels,
|
||||
false,
|
||||
"Not all modules are contained in {$sInstallationXmlPath}. List of modules in /datamodels:\n ".var_export($aModulesFromDatamodels, true)
|
||||
);
|
||||
}
|
||||
|
||||
public function GetFilteredModulesFromDatamodels($sFolder)
|
||||
{
|
||||
$aExcludedModules = ['authent-external', 'authent-ldap'];
|
||||
$aModules = array();
|
||||
if (is_dir($sFolder))
|
||||
{
|
||||
foreach (glob($sFolder."/*") as $sPath)
|
||||
{
|
||||
if (is_dir($sPath))
|
||||
{
|
||||
$aModules = array_merge($aModules, $this->GetFilteredModulesFromDatamodels($sPath));
|
||||
}
|
||||
else if (preg_match("/module\..*\.php/", basename($sPath)))
|
||||
{
|
||||
$sModulePhpContent = file_get_contents($sPath);
|
||||
if (strpos($sModulePhpContent, "SetupWebPage::AddModule")!==false
|
||||
&& strpos($sModulePhpContent, "'mandatory' => true")===false)
|
||||
{
|
||||
//filter modules autoselected due to below condition
|
||||
if (strpos($sModulePhpContent, "'mandatory' => false")!==false
|
||||
&& strpos($sModulePhpContent, "'visible' => false")!==false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$sModule = basename(dirname($sPath));
|
||||
if (in_array($sModule, $aExcludedModules))// || $sModule === 'authent-ldap')
|
||||
{
|
||||
//hardcode this condition to make sure test is OK (CI context) + added a ticket to work/investigate why it is failed for these 2 cases (itop dev context)
|
||||
continue;
|
||||
}
|
||||
|
||||
$aModules[$sModule] = $sModule;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $aModules;
|
||||
}
|
||||
|
||||
public function GetAllModules($sFolder)
|
||||
{
|
||||
$aModules = array();
|
||||
if (is_dir($sFolder))
|
||||
{
|
||||
foreach (glob($sFolder."/*") as $sPath)
|
||||
{
|
||||
if (is_dir($sPath))
|
||||
{
|
||||
$aModules = array_merge($aModules, $this->GetAllModules($sPath));
|
||||
}
|
||||
else if (preg_match("/module\..*\.php/", basename($sPath)))
|
||||
{
|
||||
$sModulePhpContent = file_get_contents($sPath);
|
||||
if (strpos($sModulePhpContent, "SetupWebPage::AddModule")!==false)
|
||||
{
|
||||
$sModule = basename(dirname($sPath));
|
||||
$aModules[$sModule] = $sModule;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $aModules;
|
||||
}
|
||||
}
|
||||
43
tests/php-unit-tests/postbuild_integration.xml.dist
Normal file
43
tests/php-unit-tests/postbuild_integration.xml.dist
Normal file
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/8.5/phpunit.xsd"
|
||||
bootstrap="unittestautoload.php"
|
||||
backupGlobals="true"
|
||||
colors="true"
|
||||
columns="120"
|
||||
convertErrorsToExceptions="true"
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnError="false"
|
||||
stopOnFailure="false"
|
||||
stopOnIncomplete="false"
|
||||
stopOnRisky="false"
|
||||
stopOnSkipped="false"
|
||||
verbose="true"
|
||||
>
|
||||
|
||||
<php>
|
||||
<ini name="error_reporting" value="E_ALL"/>
|
||||
<ini name="display_errors" value="On"/>
|
||||
<ini name="log_errors" value="On"/>
|
||||
<ini name="html_errors" value="Off"/>
|
||||
</php>
|
||||
|
||||
<testsuites>
|
||||
<testsuite name="PostBuildIntegration">
|
||||
<directory>post-build-integration-tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<!-- Code coverage white list -->
|
||||
<filter>
|
||||
<whitelist>
|
||||
<file>../../../core/apc-emulation.php</file>
|
||||
<file>../../../core/ormlinkset.class.inc.php</file>
|
||||
<file>../../../datamodels/2.x/itop-tickets/main.itop-tickets.php</file>
|
||||
</whitelist>
|
||||
</filter>
|
||||
|
||||
</phpunit>
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2020 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
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
|
||||
/**
|
||||
* @covers utils
|
||||
*/
|
||||
class DashboardLayoutTest extends ItopTestCase
|
||||
{
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function GetDashletCoordinatesProvider()
|
||||
{
|
||||
return array(
|
||||
'OneColLayout-Cell0' => array('DashboardLayoutOneCol', 0, array(0, 0)),
|
||||
'OneColLayout-Cell1' => array('DashboardLayoutOneCol', 1, array(0, 1)),
|
||||
'TwoColsLayout-Cell0' => array('DashboardLayoutTwoCols', 0, array(0, 0)),
|
||||
'TwoColsLayout-Cell1' => array('DashboardLayoutTwoCols', 1, array(1, 0)),
|
||||
'TwoColsLayout-Cell2' => array('DashboardLayoutTwoCols', 2, array(0, 1)),
|
||||
'TwoColsLayout-Cell3' => array('DashboardLayoutTwoCols', 3, array(1, 1)),
|
||||
'ThreeColsLayout-Cell0' => array('DashboardLayoutThreeCols', 0, array(0, 0)),
|
||||
'ThreeColsLayout-Cell1' => array('DashboardLayoutThreeCols', 1, array(1, 0)),
|
||||
'ThreeColsLayout-Cell2' => array('DashboardLayoutThreeCols', 2, array(2, 0)),
|
||||
'ThreeColsLayout-Cell3' => array('DashboardLayoutThreeCols', 3, array(0, 1)),
|
||||
'ThreeColsLayout-Cell4' => array('DashboardLayoutThreeCols', 4, array(1, 1)),
|
||||
'ThreeColsLayout-Cell5' => array('DashboardLayoutThreeCols', 5, array(2, 1)),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sDashboardLayoutClass
|
||||
* @param int $iCellIdx
|
||||
* @param array $aExpectedCoordinates
|
||||
* @dataProvider GetDashletCoordinatesProvider
|
||||
* @since N°2735
|
||||
*/
|
||||
public function testGetDashletCoordinates($sDashboardLayoutClass, $iCellIdx, $aExpectedCoordinates)
|
||||
{
|
||||
$oDashboardLayout = new $sDashboardLayoutClass();
|
||||
$aDashletCoordinates = $oDashboardLayout->GetDashletCoordinates($iCellIdx);
|
||||
|
||||
$this->assertEquals($aExpectedCoordinates,$aDashletCoordinates);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2020 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
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
* @covers utils
|
||||
*/
|
||||
class privUITransactionFileTest extends ItopDataTestCase
|
||||
{
|
||||
/** @var int ID of the "support agent" pofile in the sample data */
|
||||
const SAMPLE_DATA_SUPPORT_PROFILE_ID = 5;
|
||||
const USER1_TEST_LOGIN = 'user1_support_test_privUITransaction';
|
||||
const USER2_TEST_LOGIN = 'user2_support_test_privUITransaction';
|
||||
|
||||
/**
|
||||
* @dataProvider cleanupOldTransactionsProvider
|
||||
*/
|
||||
public function testCleanupOldTransactions($iCleanableCreated, $iPreservableCreated, $sCleanablePrefix, $sPreservablePrefix)
|
||||
{
|
||||
MetaModel::GetConfig()->Set('transactions_gc_threshold', 100);
|
||||
|
||||
$iBaseLimit = time() - 24*3600; //24h
|
||||
|
||||
$sBaseDir = sys_get_temp_dir();
|
||||
$sDir = "$sBaseDir/privUITransactionFileTest/cleanupOldTransactions";
|
||||
if (is_dir($sDir)) {
|
||||
$this->rm($sDir);
|
||||
}
|
||||
mkdir("$sDir", 0777, true);
|
||||
|
||||
for ($i = 0; $i < $iCleanableCreated; $i++) {
|
||||
touch("$sDir/{$sCleanablePrefix}$i", $iBaseLimit - 10*60);
|
||||
}
|
||||
for ($i = 0; $i < $iPreservableCreated; $i++) {
|
||||
touch("$sDir/{$sPreservablePrefix}$i", $iBaseLimit + 10*60);
|
||||
}
|
||||
|
||||
$iCleanableCount = count(glob("$sDir/{$sCleanablePrefix}*"));
|
||||
$iPreservableCount = count(glob("$sDir/{$sPreservablePrefix}*"));
|
||||
$this->assertEquals($iCleanableCreated, $iCleanableCount);
|
||||
$this->assertEquals($iPreservableCreated, $iPreservableCount);
|
||||
|
||||
$aArgs = [
|
||||
'sTransactionDir' => "$sDir",
|
||||
];
|
||||
$oprivUITransactionFile = new privUITransactionFile();
|
||||
$this->InvokeNonPublicMethod(get_class($oprivUITransactionFile), 'CleanupOldTransactions', $oprivUITransactionFile, $aArgs);
|
||||
|
||||
$iCleanableCount = count(glob("$sDir/{$sCleanablePrefix}*"));
|
||||
$iPreservableCount = count(glob("$sDir/{$sPreservablePrefix}*"));
|
||||
$this->assertEquals(0, $iCleanableCount);
|
||||
$this->assertEquals($iPreservableCreated, $iPreservableCount);
|
||||
}
|
||||
|
||||
public function cleanupOldTransactionsProvider()
|
||||
{
|
||||
$iBaseLimit = time() - 60 * 10; //ten minutes ago
|
||||
|
||||
$sBaseDir = sys_get_temp_dir();
|
||||
$sDir = "$sBaseDir/privUITransactionFileTest/cleanupOldTransactions";
|
||||
|
||||
return [
|
||||
'linux - no content' => [
|
||||
'iCleanableCreated' => 0,
|
||||
'iPreservableCreated' => 0,
|
||||
'sCleanablePrefix' => 'cleanable-',
|
||||
'sPreservablePrefix' => 'preservable-',
|
||||
],
|
||||
'linux - cleanable content' => [
|
||||
'iCleanableCreated' => 2,
|
||||
'iPreservableCreated' => 0,
|
||||
'sCleanablePrefix' => 'cleanable-',
|
||||
'sPreservablePrefix' => 'preservable-',
|
||||
],
|
||||
'linux - preseved content' => [
|
||||
'iCleanableCreated' => 0,
|
||||
'iPreservableCreated' => 2,
|
||||
'sCleanablePrefix' => 'cleanable-',
|
||||
'sPreservablePrefix' => 'preservable-',
|
||||
],
|
||||
'win - no content' => [
|
||||
'iCleanableCreated' => 0,
|
||||
'iPreservableCreated' => 0,
|
||||
'sCleanablePrefix' => 'cle',
|
||||
'sPreservablePrefix' => 'pre',
|
||||
],
|
||||
'win - cleanable content' => [
|
||||
'iCleanableCreated' => 2,
|
||||
'iPreservableCreated' => 0,
|
||||
'sCleanablePrefix' => 'cle',
|
||||
'sPreservablePrefix' => 'pre',
|
||||
],
|
||||
'win - preseved content' => [
|
||||
'iCleanableCreated' => 0,
|
||||
'iPreservableCreated' => 2,
|
||||
'sCleanablePrefix' => 'cle',
|
||||
'sPreservablePrefix' => 'pre',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function rm($sDir) {
|
||||
$aFiles = array_diff(scandir($sDir), ['.','..']);
|
||||
foreach ($aFiles as $sFile) {
|
||||
if ((is_dir("$sDir/$sFile"))) {
|
||||
$this->rm("$sDir/$sFile");
|
||||
} else {
|
||||
unlink("$sDir/$sFile");
|
||||
}
|
||||
}
|
||||
return rmdir($sDir);
|
||||
}
|
||||
|
||||
const USER_TEST_LOGIN = 'support_test_privUITransaction';
|
||||
|
||||
/**
|
||||
* @throws \SecurityException
|
||||
* @uses self::SAMPLE_DATA_SUPPORT_PROFILE_ID
|
||||
* @uses self::USER1_TEST_LOGIN
|
||||
* @uses self::USER2_TEST_LOGIN
|
||||
*/
|
||||
public function testIsTransactionValid()
|
||||
{
|
||||
$this->CreateUser(static::USER1_TEST_LOGIN, self::SAMPLE_DATA_SUPPORT_PROFILE_ID);
|
||||
$this->CreateUser(static::USER2_TEST_LOGIN, self::SAMPLE_DATA_SUPPORT_PROFILE_ID);
|
||||
|
||||
// create token in the user1 context
|
||||
$bUser1Login1 = UserRights::Login(self::USER1_TEST_LOGIN);
|
||||
$this->assertTrue($bUser1Login1, 'Login with user1 throw an error');
|
||||
$sTransactionIdUserSupport = privUITransactionFile::GetNewTransactionId();
|
||||
$bResult = privUITransactionFile::IsTransactionValid($sTransactionIdUserSupport, false);
|
||||
$this->assertTrue($bResult, 'Token created by support user must be valid in the support user context');
|
||||
|
||||
// test token in the user2 context
|
||||
$bUser2Login = UserRights::Login(self::USER2_TEST_LOGIN);
|
||||
$this->assertTrue($bUser2Login, 'Login with user2 throw an error');
|
||||
$bResult = privUITransactionFile::IsTransactionValid($sTransactionIdUserSupport, false);
|
||||
$this->assertFalse($bResult, 'Token created by support user must be invalid in the admin user context');
|
||||
$bResult = privUITransactionFile::RemoveTransaction($sTransactionIdUserSupport);
|
||||
$this->assertFalse($bResult, 'Token created by support user cannot be removed in the admin user context');
|
||||
|
||||
// test other methods in the user1 context
|
||||
$bUser1Login2 = UserRights::Login(self::USER1_TEST_LOGIN);
|
||||
$this->assertTrue($bUser1Login2, 'Login with user1 throw an error');
|
||||
$bResult = privUITransactionFile::RemoveTransaction($sTransactionIdUserSupport);
|
||||
$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();
|
||||
$sTransactionIdUnauthenticatedUser = privUITransactionFile::GetNewTransactionId();
|
||||
$bResult = privUITransactionFile::IsTransactionValid($sTransactionIdUnauthenticatedUser, false);
|
||||
$this->assertTrue($bResult, 'Token created by unauthenticated user must be valid when no user logged');
|
||||
$bResult = privUITransactionFile::RemoveTransaction($sTransactionIdUnauthenticatedUser);
|
||||
$this->assertTrue($bResult, 'Token created by unauthenticated user must be removed when no user logged');
|
||||
}
|
||||
}
|
||||
499
tests/php-unit-tests/unitary-tests/application/utilsTest.php
Normal file
499
tests/php-unit-tests/unitary-tests/application/utilsTest.php
Normal file
@@ -0,0 +1,499 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2018 Dennis Lassiter
|
||||
*
|
||||
* 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/>
|
||||
*
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
|
||||
/**
|
||||
* @covers utils
|
||||
*/
|
||||
class utilsTest extends ItopTestCase
|
||||
{
|
||||
public function testEndsWith()
|
||||
{
|
||||
$this->assertFalse(utils::EndsWith('a', 'bbbb'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider memoryLimitDataProvider
|
||||
*/
|
||||
public function testIsMemoryLimit($expected, $memoryLimit, $requiredMemory)
|
||||
{
|
||||
$this->assertSame($expected, utils::IsMemoryLimitOk($memoryLimit, $requiredMemory));
|
||||
}
|
||||
|
||||
/**
|
||||
* DataProvider for testIsMemoryLimitOk
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function memoryLimitDataProvider()
|
||||
{
|
||||
return [
|
||||
'current -1, required 1024' => [true, -1, 1024],
|
||||
'current 1024, required 1024' => [true, 1024, 1024],
|
||||
'current 2048, required 1024' => [true, 2048, 1024],
|
||||
'current 1024, required 2048' => [false, 1024, 2048],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider realPathDataProvider
|
||||
* @covers utils::RealPath()
|
||||
*/
|
||||
public function testRealPath($sPath, $sBasePath, $expected)
|
||||
{
|
||||
$this->assertSame($expected, utils::RealPath($sPath, $sBasePath), "utils::RealPath($sPath, $sBasePath) does not match $expected");
|
||||
}
|
||||
|
||||
public function realPathDataProvider()
|
||||
{
|
||||
parent::setUp(); // if not called, APPROOT won't be defined :(
|
||||
|
||||
$sSep = DIRECTORY_SEPARATOR;
|
||||
$sItopRootRealPath = realpath(APPROOT).$sSep;
|
||||
$sLicenseFileName = 'license.txt';
|
||||
if (!is_file(APPROOT.$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],
|
||||
'application/utils.inc.php with basepath=APPROOT' => [
|
||||
APPROOT.'application/utils.inc.php',
|
||||
APPROOT,
|
||||
$sItopRootRealPath.'application'.$sSep.'utils.inc.php',
|
||||
],
|
||||
'application/utils.inc.php with basepath=APPROOT/application' => [
|
||||
APPROOT.'application/utils.inc.php',
|
||||
APPROOT.'application',
|
||||
$sItopRootRealPath.'application'.$sSep.'utils.inc.php',
|
||||
],
|
||||
'basepath containing / and \\' => [
|
||||
APPROOT.'sources/form/form.class.inc.php',
|
||||
APPROOT.'sources/form\\form.class.inc.php',
|
||||
$sItopRootRealPath.'sources'.$sSep.'form'.$sSep.'form.class.inc.php',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider LocalPathProvider
|
||||
*
|
||||
* @param $sAbsolutePath
|
||||
* @param $expected
|
||||
*/
|
||||
public function testLocalPath($sAbsolutePath, $expected)
|
||||
{
|
||||
$this->assertSame($expected, utils::LocalPath($sAbsolutePath));
|
||||
|
||||
}
|
||||
|
||||
public function LocalPathProvider()
|
||||
{
|
||||
return array(
|
||||
'index.php' => array(
|
||||
'sAbsolutePath' => APPROOT.'index.php',
|
||||
'expected' => 'index.php',
|
||||
),
|
||||
'non existing' => array(
|
||||
'sAbsolutePath' => APPROOT.'nonexisting/nonexisting',
|
||||
'expected' => false,
|
||||
),
|
||||
'outside' => array(
|
||||
'sAbsolutePath' => '/tmp',
|
||||
'expected' => false,
|
||||
),
|
||||
'application/cmdbabstract.class.inc.php' => array(
|
||||
'sAbsolutePath' => APPROOT.'application/cmdbabstract.class.inc.php',
|
||||
'expected' => 'application/cmdbabstract.class.inc.php',
|
||||
),
|
||||
'dir' => array(
|
||||
'sAbsolutePath' => APPROOT.'application/.',
|
||||
'expected' => 'application',
|
||||
),
|
||||
'root' => array(
|
||||
'sAbsolutePath' => APPROOT.'.',
|
||||
'expected' => '',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider appRootUrlProvider
|
||||
* @covers utils::GetAppRootUrl
|
||||
*/
|
||||
public function testGetAppRootUrl($sReturnValue, $sCurrentScript, $sAppRoot, $sAbsoluteUrl)
|
||||
{
|
||||
$this->assertEquals($sReturnValue, utils::GetAppRootUrl($sCurrentScript, $sAppRoot, $sAbsoluteUrl));
|
||||
}
|
||||
|
||||
public function appRootUrlProvider()
|
||||
{
|
||||
return array(
|
||||
'Setup index (windows antislash)' => array('http://localhost/', 'C:\Dev\wamp64\www\itop-dev\setup\index.php', 'C:\Dev\wamp64\www\itop-dev', 'http://localhost/setup/'),
|
||||
'Setup index (windows slash)' => array('http://127.0.0.1/', 'C:/web/setup/index.php', 'C:/web', 'http://127.0.0.1/setup/'),
|
||||
'Setup index (windows slash, drive letter case difference)' => array('http://127.0.0.1/', 'c:/web/setup/index.php', 'C:/web', 'http://127.0.0.1/setup/'),
|
||||
);
|
||||
}
|
||||
|
||||
public function GetAbsoluteUrlAppRootPersistency() {
|
||||
$this->setUp();
|
||||
|
||||
return [
|
||||
'ForceTrustProxy 111' => [
|
||||
'bBehindReverseProxy' => false,
|
||||
'bForceTrustProxy1' => true,
|
||||
'sExpectedAppRootUrl1' => 'https://proxy.com:4443/',
|
||||
'bForceTrustProxy2' => true,
|
||||
'sExpectedAppRootUrl2' => 'https://proxy.com:4443/',
|
||||
'bForceTrustProxy3' => true,
|
||||
'sExpectedAppRootUrl3' => 'https://proxy.com:4443/',
|
||||
],
|
||||
'ForceTrustProxy 101' => [
|
||||
'bBehindReverseProxy' => false,
|
||||
'bForceTrustProxy1' => true,
|
||||
'sExpectedAppRootUrl1' => 'https://proxy.com:4443/',
|
||||
'bForceTrustProxy2' => false,
|
||||
'sExpectedAppRootUrl2' => 'https://proxy.com:4443/',
|
||||
'bForceTrustProxy3' => true,
|
||||
'sExpectedAppRootUrl3' => 'https://proxy.com:4443/',
|
||||
],
|
||||
'ForceTrustProxy 011' => [
|
||||
'bBehindReverseProxy' => false,
|
||||
'bForceTrustProxy1' => false,
|
||||
'sExpectedAppRootUrl1' => 'http://example.com/',
|
||||
'bForceTrustProxy2' => true,
|
||||
'sExpectedAppRootUrl2' => 'https://proxy.com:4443/',
|
||||
'bForceTrustProxy3' => true,
|
||||
'sExpectedAppRootUrl3' => 'https://proxy.com:4443/',
|
||||
],
|
||||
'ForceTrustProxy 110' => [
|
||||
'bBehindReverseProxy' => false,
|
||||
'bForceTrustProxy1' => true,
|
||||
'sExpectedAppRootUrl1' => 'https://proxy.com:4443/',
|
||||
'bForceTrustProxy2' => true,
|
||||
'sExpectedAppRootUrl2' => 'https://proxy.com:4443/',
|
||||
'bForceTrustProxy3' => false,
|
||||
'sExpectedAppRootUrl3' => 'https://proxy.com:4443/',
|
||||
],
|
||||
'ForceTrustProxy 010' => [
|
||||
'bBehindReverseProxy' => false,
|
||||
'bForceTrustProxy1' => false,
|
||||
'sExpectedAppRootUrl1' => 'http://example.com/',
|
||||
'bForceTrustProxy2' => true,
|
||||
'sExpectedAppRootUrl2' => 'https://proxy.com:4443/',
|
||||
'bForceTrustProxy3' => false,
|
||||
'sExpectedAppRootUrl3' => 'https://proxy.com:4443/',
|
||||
],
|
||||
'ForceTrustProxy 001' => [
|
||||
'bBehindReverseProxy' => false,
|
||||
'bForceTrustProxy1' => false,
|
||||
'sExpectedAppRootUrl1' => 'http://example.com/',
|
||||
'bForceTrustProxy2' => false,
|
||||
'sExpectedAppRootUrl2' => 'http://example.com/',
|
||||
'bForceTrustProxy3' => true,
|
||||
'sExpectedAppRootUrl3' => 'https://proxy.com:4443/',
|
||||
],
|
||||
'ForceTrustProxy 000' => [
|
||||
'bBehindReverseProxy' => false,
|
||||
'bForceTrustProxy1' => false,
|
||||
'sExpectedAppRootUrl1' => 'http://example.com/',
|
||||
'bForceTrustProxy2' => false,
|
||||
'sExpectedAppRootUrl2' => 'http://example.com/',
|
||||
'bForceTrustProxy3' => false,
|
||||
'sExpectedAppRootUrl3' => 'http://example.com/',
|
||||
],
|
||||
'BehindReverseProxy ForceTrustProxy 010' => [
|
||||
'bBehindReverseProxy' => true,
|
||||
'bForceTrustProxy1' => false,
|
||||
'sExpectedAppRootUrl1' => 'https://proxy.com:4443/',
|
||||
'bForceTrustProxy2' => true,
|
||||
'sExpectedAppRootUrl2' => 'https://proxy.com:4443/',
|
||||
'bForceTrustProxy3' => false,
|
||||
'sExpectedAppRootUrl3' => 'https://proxy.com:4443/',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @dataProvider GetAbsoluteUrlAppRootPersistency
|
||||
*/
|
||||
public function testGetAbsoluteUrlAppRootPersistency($bBehindReverseProxy,$bForceTrustProxy1 ,$sExpectedAppRootUrl1,$bForceTrustProxy2 , $sExpectedAppRootUrl2,$bForceTrustProxy3 , $sExpectedAppRootUrl3)
|
||||
{
|
||||
utils::GetConfig()->Set('behind_reverse_proxy', $bBehindReverseProxy);
|
||||
utils::GetConfig()->Set('app_root_url', '');
|
||||
|
||||
//should match http://example.com/ when not trusting the proxy
|
||||
//should match https://proxy.com:4443/ when trusting the proxy
|
||||
$_SERVER = [
|
||||
'REMOTE_ADDR' => '127.0.0.1', //is not set, disable IsProxyTrusted
|
||||
'SERVER_NAME' => 'example.com',
|
||||
'SERVER_PORT' => '80',
|
||||
'REQUEST_URI' => '/index.php?baz=1',
|
||||
'SCRIPT_NAME' => '/index.php',
|
||||
'SCRIPT_FILENAME' => APPROOT.'index.php',
|
||||
'QUERY_STRING' => 'baz=1',
|
||||
'HTTP_X_FORWARDED_HOST' => 'proxy.com',
|
||||
'HTTP_X_FORWARDED_PORT' => '4443',
|
||||
'HTTP_X_FORWARDED_PROTO' => 'https',
|
||||
'HTTPS' => null,
|
||||
];
|
||||
|
||||
$this->assertEquals($sExpectedAppRootUrl1, utils::GetAbsoluteUrlAppRoot($bForceTrustProxy1));
|
||||
|
||||
$this->assertEquals($sExpectedAppRootUrl2, utils::GetAbsoluteUrlAppRoot($bForceTrustProxy2));
|
||||
|
||||
$this->assertEquals($sExpectedAppRootUrl3, utils::GetAbsoluteUrlAppRoot($bForceTrustProxy3));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @dataProvider GetDefaultUrlAppRootProvider
|
||||
*/
|
||||
public function testGetDefaultUrlAppRoot($bForceTrustProxy, $bConfTrustProxy, $aServerVars, $sExpectedAppRootUrl)
|
||||
{
|
||||
$_SERVER = $aServerVars;
|
||||
utils::GetConfig()->Set('behind_reverse_proxy', $bConfTrustProxy);
|
||||
$sAppRootUrl = utils::GetDefaultUrlAppRoot($bForceTrustProxy);
|
||||
$this->assertEquals($sExpectedAppRootUrl, $sAppRootUrl);
|
||||
}
|
||||
|
||||
public function GetDefaultUrlAppRootProvider()
|
||||
{
|
||||
$this->setUp();
|
||||
|
||||
$baseServerVar = [
|
||||
'REMOTE_ADDR' => '127.0.0.1', //is not set, disable IsProxyTrusted
|
||||
'SERVER_NAME' => 'example.com',
|
||||
'HTTP_X_FORWARDED_HOST' => null,
|
||||
'SERVER_PORT' => '80',
|
||||
'HTTP_X_FORWARDED_PORT' => null,
|
||||
'REQUEST_URI' => '/index.php?baz=1',
|
||||
'SCRIPT_NAME' => '/index.php',
|
||||
'SCRIPT_FILENAME' => APPROOT.'index.php',
|
||||
'QUERY_STRING' => 'baz=1',
|
||||
'HTTP_X_FORWARDED_PROTO' => null,
|
||||
'HTTP_X_FORWARDED_PROTOCOL' => null,
|
||||
'HTTPS' => null,
|
||||
];
|
||||
|
||||
return [
|
||||
'no proxy, http' => [
|
||||
'bForceTrustProxy' => false,
|
||||
'bConfTrustProxy' => false,
|
||||
'aServerVars' => array_merge($baseServerVar, []),
|
||||
'sExpectedAppRootUrl' => 'http://example.com/',
|
||||
],
|
||||
'no proxy, subPath, http' => [
|
||||
'bForceTrustProxy' => false,
|
||||
'bConfTrustProxy' => false,
|
||||
'aServerVars' => array_merge($baseServerVar, [
|
||||
'REQUEST_URI' => '/foo/index.php?baz=1',
|
||||
]),
|
||||
'sExpectedAppRootUrl' => 'http://example.com/foo/',
|
||||
],
|
||||
'IIS lack REQUEST_URI' => [
|
||||
'bForceTrustProxy' => false,
|
||||
'bConfTrustProxy' => false,
|
||||
'aServerVars' => array_merge($baseServerVar, [
|
||||
'REQUEST_URI' => null,
|
||||
'SCRIPT_NAME' => '/foo/index.php',
|
||||
]),
|
||||
'sExpectedAppRootUrl' => 'http://example.com/foo/',
|
||||
],
|
||||
'no proxy, https' => [
|
||||
'bForceTrustProxy' => false,
|
||||
'bConfTrustProxy' => false,
|
||||
'aServerVars' => array_merge($baseServerVar, [
|
||||
'SERVER_PORT' => '443',
|
||||
'HTTPS' => 'on',
|
||||
]),
|
||||
'sExpectedAppRootUrl' => 'https://example.com/',
|
||||
],
|
||||
'no proxy, https on 4443' => [
|
||||
'bForceTrustProxy' => false,
|
||||
'bConfTrustProxy' => false,
|
||||
'aServerVars' => array_merge($baseServerVar, [
|
||||
'SERVER_PORT' => '4443',
|
||||
'HTTPS' => 'on',
|
||||
]),
|
||||
'sExpectedAppRootUrl' => 'https://example.com:4443/',
|
||||
],
|
||||
'with proxy, not enabled' => [
|
||||
'bForceTrustProxy' => false,
|
||||
'bConfTrustProxy' => false,
|
||||
'aServerVars' => array_merge($baseServerVar, [
|
||||
'HTTP_X_FORWARDED_HOST' => 'proxy.com',
|
||||
'HTTP_X_FORWARDED_PORT' => '4443',
|
||||
'HTTP_X_FORWARDED_PROTO' => 'https',
|
||||
]),
|
||||
'sExpectedAppRootUrl' => 'http://example.com/',
|
||||
],
|
||||
'with proxy, enabled HTTP_X_FORWARDED_PROTO' => [
|
||||
'bForceTrustProxy' => false,
|
||||
'bConfTrustProxy' => true,
|
||||
'aServerVars' => array_merge($baseServerVar, [
|
||||
'HTTP_X_FORWARDED_HOST' => 'proxy.com',
|
||||
'HTTP_X_FORWARDED_PORT' => '4443',
|
||||
'HTTP_X_FORWARDED_PROTO' => 'https',
|
||||
]),
|
||||
'sExpectedAppRootUrl' => 'https://proxy.com:4443/',
|
||||
],
|
||||
'with proxy, enabled - alt HTTP_X_FORWARDED_PROTO COL' => [
|
||||
'bForceTrustProxy' => false,
|
||||
'bConfTrustProxy' => true,
|
||||
'aServerVars' => array_merge($baseServerVar, [
|
||||
'HTTP_X_FORWARDED_HOST' => 'proxy.com',
|
||||
'HTTP_X_FORWARDED_PORT' => '4443',
|
||||
'HTTP_X_FORWARDED_PROTOCOL' => 'https',
|
||||
]),
|
||||
'sExpectedAppRootUrl' => 'https://proxy.com:4443/',
|
||||
],
|
||||
'with proxy, disabled, forced' => [
|
||||
'bForceTrustProxy' => true,
|
||||
'bConfTrustProxy' => false,
|
||||
'aServerVars' => array_merge($baseServerVar, [
|
||||
'HTTP_X_FORWARDED_HOST' => 'proxy.com',
|
||||
'HTTP_X_FORWARDED_PORT' => '4443',
|
||||
'HTTP_X_FORWARDED_PROTO' => 'https',
|
||||
]),
|
||||
'sExpectedAppRootUrl' => 'https://proxy.com:4443/',
|
||||
],
|
||||
'with proxy, enabled, forced' => [
|
||||
'bForceTrustProxy' => true,
|
||||
'bConfTrustProxy' => true,
|
||||
'aServerVars' => array_merge($baseServerVar, [
|
||||
'HTTP_X_FORWARDED_HOST' => 'proxy.com',
|
||||
'HTTP_X_FORWARDED_PORT' => '4443',
|
||||
'HTTP_X_FORWARDED_PROTO' => 'https',
|
||||
]),
|
||||
'sExpectedAppRootUrl' => 'https://proxy.com:4443/',
|
||||
],
|
||||
|
||||
'with proxy, disabled, forced, no remote addr' => [
|
||||
'bForceTrustProxy' => true,
|
||||
'bConfTrustProxy' => false,
|
||||
'aServerVars' => array_merge($baseServerVar, [
|
||||
'REMOTE_ADDR' => null,
|
||||
'HTTP_X_FORWARDED_HOST' => 'proxy.com',
|
||||
'HTTP_X_FORWARDED_PORT' => '4443',
|
||||
'HTTP_X_FORWARDED_PROTO' => 'https',
|
||||
]),
|
||||
'sExpectedAppRootUrl' => 'https://proxy.com:4443/',
|
||||
],
|
||||
'with proxy, enabled, no remote addr' => [
|
||||
'bForceTrustProxy' => false,
|
||||
'bConfTrustProxy' => true,
|
||||
'aServerVars' => array_merge($baseServerVar, [
|
||||
'REMOTE_ADDR' => null,
|
||||
'HTTP_X_FORWARDED_HOST' => 'proxy.com',
|
||||
'HTTP_X_FORWARDED_PORT' => '4443',
|
||||
'HTTP_X_FORWARDED_PROTO' => 'https',
|
||||
]),
|
||||
'sExpectedAppRootUrl' => 'http://example.com/',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sExpressionToConvert
|
||||
* @param int $iExpectedConvertedValue
|
||||
*
|
||||
* @dataProvider ConvertToBytesProvider
|
||||
*/
|
||||
public function testConvertToBytes($sExpressionToConvert, $iExpectedConvertedValue)
|
||||
{
|
||||
$iCurrentConvertedValue = utils::ConvertToBytes($sExpressionToConvert);
|
||||
self::assertEquals($iExpectedConvertedValue, $iCurrentConvertedValue, 'Converted value wasn\'t the one expected !');
|
||||
self::assertSame($iExpectedConvertedValue, $iCurrentConvertedValue, 'Value was converted but not of the expected type');
|
||||
}
|
||||
|
||||
public function ConvertToBytesProvider()
|
||||
{
|
||||
return [
|
||||
'123 int value' => ['123', 123],
|
||||
'-1 no limit' => ['-1', -1],
|
||||
'56k' => ['56k', 56 * 1024],
|
||||
'512M' => ['512M', 512 * 1024 * 1024],
|
||||
'2G' => ['2G', 2 * 1024 * 1024 * 1024],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
$this->assertEquals($expectedResult, utils::Sanitize($valueToSanitize, null, $type), 'url sanitize failed');
|
||||
}
|
||||
|
||||
/**
|
||||
* DataProvider for testSanitizer
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function sanitizerDataProvider()
|
||||
{
|
||||
return [
|
||||
'good integer' => ['integer', '2565', '2565'],
|
||||
'bad integer' => ['integer', 'a2656', '2656'],
|
||||
/**
|
||||
* 'class' filter needs a loaded datamodel... and is only an indirection to \MetaModel::IsValidClass so might very important to test !
|
||||
* If we switch this class to ItopDataTestCase then we are seeing :
|
||||
* - the class now takes 18s to process instead of... 459ms when using ItopTestCase !!!
|
||||
* - multiple errors are thrown in testGetAbsoluteUrlAppRootPersistency :(
|
||||
* We decided it wasn't worse the effort to test the 'class' filter !
|
||||
*/
|
||||
// 'good class' => ['class', 'UserRequest', 'UserRequest'],
|
||||
// 'bad class' => ['class', 'MyUserRequest',null],
|
||||
'good string' => ['string', 'Is Peter smart and funny?', 'Is Peter smart and funny?'],
|
||||
'bad string' => ['string', 'Is Peter <smart> & funny?', 'Is Peter <smart> & funny?'],
|
||||
'good transaction_id' => ['transaction_id', '8965.-dd', '8965.-dd'],
|
||||
'bad transaction_id' => ['transaction_id', '8965.-dd+', null],
|
||||
'good parameter' => ['parameter', 'JU8965-dd=_', 'JU8965-dd=_'],
|
||||
'bad parameter' => ['parameter', '8965.-dd+', null],
|
||||
'good field_name' => ['field_name', 'Name->bUzz38', 'Name->bUzz38'],
|
||||
'bad field_name' => ['field_name', 'name-buzz', null],
|
||||
'good context_param' => ['context_param', '%dssD25_=%:+-', '%dssD25_=%:+-'],
|
||||
'bad context_param' => ['context_param', '%dssD,25_=%:+-', null],
|
||||
'good element_identifier' => ['element_identifier', 'AD05nb', 'AD05nb'],
|
||||
'bad element_identifier' => ['element_identifier', 'AD05nb+', 'AD05nb'],
|
||||
'good url' => ['url', 'https://www.w3schools.com', 'https://www.w3schools.com'],
|
||||
'bad url' => ['url', 'https://www.w3schoo<6F><6F>ls.co<63>m', 'https://www.w3schools.com'],
|
||||
'raw_data' => ['raw_data', '<Test>\s😃😃😃', '<Test>\s😃😃😃'],
|
||||
];
|
||||
}
|
||||
}
|
||||
406
tests/php-unit-tests/unitary-tests/core/BulkChangeTest.inc.php
Normal file
406
tests/php-unit-tests/unitary-tests/core/BulkChangeTest.inc.php
Normal file
@@ -0,0 +1,406 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Core;
|
||||
|
||||
use CMDBSource;
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use MetaModel;
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class BulkChangeTest extends ItopDataTestCase {
|
||||
const CREATE_TEST_ORG = true;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
require_once(APPROOT.'core/coreexception.class.inc.php');
|
||||
require_once(APPROOT.'core/bulkchange.class.inc.php');
|
||||
|
||||
}
|
||||
|
||||
//bug 2888: csv import / data synchro issue with password validation
|
||||
public function testPasswordBulkChangeIssue() {
|
||||
/** @var Personn $oPerson */
|
||||
$oPerson = $this->createObject('Person', array(
|
||||
'first_name' => 'isaac',
|
||||
'name' => 'asimov',
|
||||
'email' => 'isaac.asimov@fundation.org',
|
||||
'org_id' => $this->getTestOrgId(),
|
||||
));
|
||||
|
||||
$aData = array(
|
||||
array(
|
||||
$oPerson->Get("first_name"),
|
||||
$oPerson->Get("name"),
|
||||
$oPerson->Get("email"),
|
||||
"EN US",
|
||||
"iasimov",
|
||||
"harryseldon",
|
||||
"profileid->name:Administrator",
|
||||
),
|
||||
);
|
||||
$aAttributes = array("language" => 3, "login" => 4, "password" => 5, "profile_list" => 6);
|
||||
$aExtKeys = array(
|
||||
"contactid" =>
|
||||
array("first_name" => 0, "name" => 1, "email" => 2),
|
||||
);
|
||||
$oBulk = new \BulkChange(
|
||||
"UserLocal",
|
||||
$aData,
|
||||
$aAttributes,
|
||||
$aExtKeys,
|
||||
array("login"),
|
||||
null,
|
||||
null,
|
||||
"Y-m-d H:i:s", // date format
|
||||
true // localize
|
||||
);
|
||||
|
||||
$oChange = \CMDBObject::GetCurrentChange();
|
||||
$aRes = $oBulk->Process($oChange);
|
||||
static::assertNotNull($aRes);
|
||||
|
||||
foreach ($aRes as $aRow) {
|
||||
if (array_key_exists('__STATUS__', $aRow)) {
|
||||
$sStatus = $aRow['__STATUS__'];
|
||||
$this->assertFalse(strstr($sStatus->GetDescription(), "CoreCannotSaveObjectException"),
|
||||
"CSVimport/Datasynchro: Password validation failed with: ".$sStatus->GetDescription());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* test $oBulk->Process with server 1 from demo datas
|
||||
* @dataProvider BulkChangeProvider
|
||||
*
|
||||
* @param $aData
|
||||
* @param $aAttributes
|
||||
* @param $aExtKeys
|
||||
* @param $aReconcilKeys
|
||||
*/
|
||||
public function testBulkChangeIssue($aData, $aAttributes, $aExtKeys, $aReconcilKeys, $aResult) {
|
||||
$this->debug("aReconcilKeys:".$aReconcilKeys[0]);
|
||||
$oBulk = new \BulkChange(
|
||||
"Server",
|
||||
$aData,
|
||||
$aAttributes,
|
||||
$aExtKeys,
|
||||
$aReconcilKeys,
|
||||
null,
|
||||
null,
|
||||
"Y-m-d H:i:s", // date format
|
||||
true // localize
|
||||
);
|
||||
|
||||
$oChange = \CMDBObject::GetCurrentChange();
|
||||
$aRes = $oBulk->Process($oChange);
|
||||
static::assertNotNull($aRes);
|
||||
|
||||
foreach ($aRes as $aRow) {
|
||||
if (array_key_exists('__STATUS__', $aRow)) {
|
||||
$sStatus = $aRow['__STATUS__'];
|
||||
//$this->debug("sStatus:".$sStatus->GetDescription());
|
||||
$this->assertEquals($sStatus->GetDescription(), $aResult["__STATUS__"]);
|
||||
foreach ($aRow as $i => $oCell) {
|
||||
if ($i != "finalclass" && $i != "__STATUS__") {
|
||||
$this->debug("i:".$i);
|
||||
$this->debug('GetDisplayableValue:'.$oCell->GetDisplayableValue());
|
||||
$this->debug("aResult:".$aResult[$i]);
|
||||
$this->assertEquals($oCell->GetDisplayableValue(), $aResult[$i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function BulkChangeProvider() {
|
||||
return [
|
||||
"Case 3, 5 et 8 : unchanged" => [
|
||||
[["Demo", "Server1", "1", "production", ""]],
|
||||
["name" => 1, "id" => 2, "status" => 3, "purchase_date" => 4],
|
||||
["org_id" => ["name" => 0]],
|
||||
["id"],
|
||||
[0 => "Demo", "org_id" => "3", 1 => "Server1", 2 => "1", 3 => "production", 4 => "", "id" => 1, "__STATUS__" => "unchanged"],
|
||||
],
|
||||
"Case 9 : wrong date format" => [
|
||||
[["Demo", "Server1", "1", "production", "date"]],
|
||||
["name" => 1, "id" => 2, "status" => 3, "purchase_date" => 4],
|
||||
["org_id" => ["name" => 0]],
|
||||
["id"],
|
||||
[ 0 => "Demo", "org_id" => "n/a", 1 => "Server1", 2 => "1", 3 => "production", 4 => "date", "id" => 1, "__STATUS__" => "Issue: wrong date format"],
|
||||
],
|
||||
"Case 1 : no match" => [
|
||||
[["Bad", "Server1", "1", "production", ""]],
|
||||
["name" => 1, "id" => 2, "status" => 3, "purchase_date" => 4],
|
||||
["org_id" => ["name" => 0]],
|
||||
["id"],
|
||||
["org_id" => "",1 => "Server1",2 => "1", 3 => "production", 4 => "", "id" => 1, "__STATUS__" => "Issue: Unexpected attribute value(s)"],
|
||||
],
|
||||
"Case 10 : Missing mandatory value" => [
|
||||
[["", "Server1", "1", "production", ""]],
|
||||
["name" => 1, "id" => 2, "status" => 3, "purchase_date" => 4],
|
||||
["org_id" => ["name" => 0]],
|
||||
["id"],
|
||||
[ "org_id" => "", 1 => "Server1", 2 => "1", 3 => "production", 4 => "", "id" => 1, "__STATUS__" => "Issue: Unexpected attribute value(s)"],
|
||||
],
|
||||
"Case 6 : Unexpected value" => [
|
||||
[["Demo", "Server1", "1", "<svg onclick\"alert(1)\">", ""]],
|
||||
["name" => 1, "id" => 2, "status" => 3, "purchase_date" => 4],
|
||||
["org_id" => ["name" => 0]],
|
||||
["id"],
|
||||
[0 => "Demo", "org_id" => "3", 1 => "Server1", 2 => "1", 3 => "<svg onclick"alert(1)">", 4 => "", "id" => 1, "__STATUS__" => "Issue: Unexpected attribute value(s)"],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* test $oBulk->Process with new server datas
|
||||
* @dataProvider CSVImportProvider
|
||||
*
|
||||
* @param $aInitData
|
||||
* @param $aCsvData
|
||||
* @param $aAttributes
|
||||
* @param $aExtKeys
|
||||
* @param $aReconcilKeys
|
||||
*/
|
||||
public function testCas1BulkChangeIssue($aInitData, $aCsvData, $aAttributes, $aExtKeys, $aReconcilKeys, $aResult) {
|
||||
CMDBSource::Query('START TRANSACTION');
|
||||
//change value during the test
|
||||
$db_core_transactions_enabled=MetaModel::GetConfig()->Get('db_core_transactions_enabled');
|
||||
MetaModel::GetConfig()->Set('db_core_transactions_enabled',false);
|
||||
/** @var Server $oServer */
|
||||
$oServer = $this->createObject('Server', array(
|
||||
'name' => $aInitData[1],
|
||||
'status' => $aInitData[2],
|
||||
'org_id' => $aInitData[0],
|
||||
'purchase_date' => $aInitData[3],
|
||||
));
|
||||
$aCsvData[0][2]=$oServer->GetKey();
|
||||
$aResult[2]=$oServer->GetKey();
|
||||
$aResult["id"]=$oServer->GetKey();
|
||||
$this->debug("oServer->GetKey():".$oServer->GetKey());
|
||||
$this->debug("aCsvData:".json_encode($aCsvData[0]));
|
||||
$this->debug("aReconcilKeys:".$aReconcilKeys[0]);
|
||||
$oBulk = new \BulkChange(
|
||||
"Server",
|
||||
$aCsvData,
|
||||
$aAttributes,
|
||||
$aExtKeys,
|
||||
$aReconcilKeys,
|
||||
null,
|
||||
null,
|
||||
"Y-m-d H:i:s", // date format
|
||||
true // localize
|
||||
);
|
||||
$this->debug("BulkChange:");
|
||||
$oChange = \CMDBObject::GetCurrentChange();
|
||||
$this->debug("GetCurrentChange:");
|
||||
$aRes = $oBulk->Process($oChange);
|
||||
$this->debug("Process:");
|
||||
static::assertNotNull($aRes);
|
||||
$this->debug("assertNotNull:");
|
||||
foreach ($aRes as $aRow) {
|
||||
if (array_key_exists('__STATUS__', $aRow)) {
|
||||
$sStatus = $aRow['__STATUS__'];
|
||||
$this->debug("sStatus:".$sStatus->GetDescription());
|
||||
$this->assertEquals($sStatus->GetDescription(), $aResult["__STATUS__"]);
|
||||
foreach ($aRow as $i => $oCell) {
|
||||
if ($i != "finalclass" && $i != "__STATUS__") {
|
||||
$this->debug("i:".$i);
|
||||
$this->debug('GetDisplayableValue:'.$oCell->GetDisplayableValue());
|
||||
$this->debug("aResult:".$aResult[$i]);
|
||||
$this->assertEquals( $aResult[$i], $oCell->GetDisplayableValue());
|
||||
}
|
||||
}
|
||||
$this->assertEquals( $aResult[0], $aRow[0]->GetDisplayableValue());
|
||||
}
|
||||
}
|
||||
CMDBSource::Query('ROLLBACK');
|
||||
MetaModel::GetConfig()->Set('db_core_transactions_enabled',$db_core_transactions_enabled);
|
||||
}
|
||||
|
||||
public function CSVImportProvider() {
|
||||
return [
|
||||
"Case 6 - 1 : Unexpected value" => [
|
||||
["1", "ServerTest", "production", ""],
|
||||
[["Demo", "ServerTest", "key", "BadValue", ""]],
|
||||
["name" => 1, "id" => 2, "status" => 3, "purchase_date" => 4],
|
||||
["org_id" => ["name" => 0]],
|
||||
["id"],
|
||||
[0 => "Demo", "org_id" => "3", 1 => "ServerTest", 2 => "1", 3 => "BadValue", 4 => "", "id" => 1, "__STATUS__" => "Issue: Unexpected attribute value(s)"],
|
||||
],
|
||||
"Case 6 - 2 : Unexpected value" => [
|
||||
["1", "ServerTest", "production", ""],
|
||||
[["Demo", "ServerTest", "key", "<svg onclick\"alert(1)\">", ""]],
|
||||
["name" => 1, "id" => 2, "status" => 3, "purchase_date" => 4],
|
||||
["org_id" => ["name" => 0]],
|
||||
["id"],
|
||||
[0 => "Demo", "org_id" => "3", 1 => "ServerTest", 2 => "1", 3 => "<svg onclick"alert(1)">", 4 => "", "id" => 1, "__STATUS__" => "Issue: Unexpected attribute value(s)"],
|
||||
],
|
||||
"Case 8 : unchanged name" => [
|
||||
["1", "<svg onclick\"alert(1)\">", "production", ""],
|
||||
[["Demo", "<svg onclick\"alert(1)\">", "key", "production", ""]],
|
||||
["name" => 1, "id" => 2, "status" => 3, "purchase_date" => 4],
|
||||
["org_id" => ["name" => 0]],
|
||||
["id"],
|
||||
[0 => "Demo", "org_id" => "3", 1 => "<svg onclick"alert(1)">", 2 => "1", 3 => "production", 4 => "", "id" => 1, "__STATUS__" => "updated 1 cols"],
|
||||
],
|
||||
"Case 3, 5 et 8 : unchanged 2" => [
|
||||
["1", "ServerTest", "production", ""],
|
||||
[["Demo", "ServerTest", "1", "production", ""]],
|
||||
["name" => 1, "id" => 2, "status" => 3, "purchase_date" => 4],
|
||||
["org_id" => ["name" => 0]],
|
||||
["id"],
|
||||
[0 => "Demo", "org_id" => "3", 1 => "ServerTest", 2 => "1", 3 => "production", 4 => "", "id" => 1, "__STATUS__" => "updated 1 cols"],
|
||||
],
|
||||
"Case 9 - 1: wrong date format" => [
|
||||
["1", "ServerTest", "production", ""],
|
||||
[["Demo", "ServerTest", "1", "production", "date"]],
|
||||
["name" => 1, "id" => 2, "status" => 3, "purchase_date" => 4],
|
||||
["org_id" => ["name" => 0]],
|
||||
["id"],
|
||||
[ 0 => "Demo", "org_id" => "n/a", 1 => "ServerTest", 2 => "1", 3 => "production", 4 => "date", "id" => 1, "__STATUS__" => "Issue: wrong date format"],
|
||||
],
|
||||
"Case 9 - 2: wrong date format" => [
|
||||
["1", "ServerTest", "production", ""],
|
||||
[["Demo", "ServerTest", "1", "production", "<svg onclick\"alert(1)\">"]],
|
||||
["name" => 1, "id" => 2, "status" => 3, "purchase_date" => 4],
|
||||
["org_id" => ["name" => 0]],
|
||||
["id"],
|
||||
[ 0 => "Demo", "org_id" => "n/a", 1 => "ServerTest", 2 => "1", 3 => "production", 4 => "<svg onclick"alert(1)">", "id" => 1, "__STATUS__" => "Issue: wrong date format"],
|
||||
],
|
||||
"Case 1 - 1 : no match" => [
|
||||
["1", "ServerTest", "production", ""],
|
||||
[["Bad", "ServerTest", "1", "production", ""]],
|
||||
["name" => 1, "id" => 2, "status" => 3, "purchase_date" => 4],
|
||||
["org_id" => ["name" => 0]],
|
||||
["id"],
|
||||
[ 0 => "Bad", "org_id" => "",1 => "ServerTest",2 => "1", 3 => "production", 4 => "", "id" => 1, "__STATUS__" => "Issue: Unexpected attribute value(s)"],
|
||||
],
|
||||
"Case 1 - 2 : no match" => [
|
||||
["1", "ServerTest", "production", ""],
|
||||
[["<svg fonclick\"alert(1)\">", "ServerTest", "1", "production", ""]],
|
||||
["name" => 1, "id" => 2, "status" => 3, "purchase_date" => 4],
|
||||
["org_id" => ["name" => 0]],
|
||||
["id"],
|
||||
[ 0 => "<svg fonclick"alert(1)">", "org_id" => "",1 => "ServerTest",2 => "1", 3 => "production", 4 => "", "id" => 1, "__STATUS__" => "Issue: Unexpected attribute value(s)"],
|
||||
],
|
||||
"Case 10 : Missing mandatory value" => [
|
||||
["1", "ServerTest", "production", ""],
|
||||
[["", "ServerTest", "1", "production", ""]],
|
||||
["name" => 1, "id" => 2, "status" => 3, "purchase_date" => 4],
|
||||
["org_id" => ["name" => 0]],
|
||||
["id"],
|
||||
[ 0 => "", "org_id" => "", 1 => "ServerTest", 2 => "1", 3 => "production", 4 => "", "id" => 1, "__STATUS__" => "Issue: Unexpected attribute value(s)"],
|
||||
],
|
||||
|
||||
"Case 0 : Date format" => [
|
||||
["1", "ServerTest", "production", "2020-02-01"],
|
||||
[["Demo", "ServerTest", "1", "production", "2020-20-03"]],
|
||||
["name" => 1, "id" => 2, "status" => 3, "purchase_date" => 4],
|
||||
["org_id" => ["name" => 0]],
|
||||
["id"],
|
||||
[ 0 => "Demo", "org_id" => "n/a", 1 => "ServerTest", 2 => "1", 3 => "production", 4 => "2020-20-03", "id" => 1, "__STATUS__" => "Issue: wrong date format"],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* test $oBulk->Process with new server and new organization datas
|
||||
* @dataProvider CSVImportProvider2
|
||||
*
|
||||
* @param $aInitData
|
||||
* @param $aCsvData
|
||||
* @param $aAttributes
|
||||
* @param $aExtKeys
|
||||
* @param $aReconcilKeys
|
||||
*/
|
||||
public function testCas2BulkChangeIssue($aInitData, $aCsvData, $aAttributes, $aExtKeys, $aReconcilKeys, $aResult) {
|
||||
CMDBSource::Query('START TRANSACTION');
|
||||
//change value during the test
|
||||
$db_core_transactions_enabled=MetaModel::GetConfig()->Get('db_core_transactions_enabled');
|
||||
MetaModel::GetConfig()->Set('db_core_transactions_enabled',false);
|
||||
/** @var Server $oServer */
|
||||
$oOrganisation = $this->createObject('Organization', array(
|
||||
'name' =>$aInitData[0]
|
||||
));
|
||||
$aResult["org_id"]=$oOrganisation->GetKey();
|
||||
$oServer = $this->createObject('Server', array(
|
||||
'name' => $aInitData[1],
|
||||
'status' => $aInitData[2],
|
||||
'org_id' => $oOrganisation->GetKey(),
|
||||
'purchase_date' => $aInitData[3],
|
||||
));
|
||||
$aCsvData[0][2]=$oServer->GetKey();
|
||||
$aResult[2]=$oServer->GetKey();
|
||||
$aResult["id"]=$oServer->GetKey();
|
||||
$oBulk = new \BulkChange(
|
||||
"Server",
|
||||
$aCsvData,
|
||||
$aAttributes,
|
||||
$aExtKeys,
|
||||
$aReconcilKeys,
|
||||
null,
|
||||
null,
|
||||
"Y-m-d H:i:s", // date format
|
||||
true // localize
|
||||
);
|
||||
$oChange = \CMDBObject::GetCurrentChange();
|
||||
$aRes = $oBulk->Process($oChange);
|
||||
static::assertNotNull($aRes);
|
||||
foreach ($aRes as $aRow) {
|
||||
foreach ($aRow as $i => $oCell) {
|
||||
if ($i != "finalclass" && $i != "__STATUS__") {
|
||||
$this->debug("i:".$i);
|
||||
$this->debug('GetDisplayableValue:'.$oCell->GetDisplayableValue());
|
||||
$this->debug("aResult:".$aResult[$i]);
|
||||
$this->assertEquals($aResult[$i], $oCell->GetDisplayableValue());
|
||||
}
|
||||
elseif ($i == "__STATUS__") {
|
||||
$sStatus = $aRow['__STATUS__'];
|
||||
$this->assertEquals($aResult["__STATUS__"], $sStatus->GetDescription());
|
||||
}
|
||||
}
|
||||
$this->assertEquals($aResult[0], $aRow[0]->GetDisplayableValue());
|
||||
}
|
||||
CMDBSource::Query('ROLLBACK');
|
||||
MetaModel::GetConfig()->Set('db_core_transactions_enabled',$db_core_transactions_enabled);
|
||||
}
|
||||
|
||||
public function CSVImportProvider2() {
|
||||
return [
|
||||
"Case 3 : unchanged name" => [
|
||||
["dodo","ServerYO", "production", ""],
|
||||
[["dodo", "ServerYO", "key", "production", ""]],
|
||||
["name" => 1, "id" => 2, "status" => 3, "purchase_date" => 4],
|
||||
["org_id" => ["name" => 0]],
|
||||
["id"],
|
||||
[0 => "dodo", "org_id" => "3", 1 => "ServerYO", 2 => "1", 3 => "production", 4 => "", "id" => 1, "__STATUS__" => "unchanged"],
|
||||
],
|
||||
"Case 3 bis : unchanged name" => [
|
||||
["<svg >","ServerYO", "production", ""],
|
||||
[["<svg >", "ServerYO", "key", "production", ""]],
|
||||
["name" => 1, "id" => 2, "status" => 3, "purchase_date" => 4],
|
||||
["org_id" => ["name" => 0]],
|
||||
["id"],
|
||||
[0 => "<svg >", "org_id" => "3", 1 => "ServerYO", 2 => "1", 3 => "production", 4 => "", "id" => 1, "__STATUS__" => "unchanged"],
|
||||
],
|
||||
"Case 3 ter : unchanged name" => [
|
||||
["<svg onclick\"alert(1)\" >","ServerYO", "production", ""],
|
||||
[["<svg onclick\"alert(1)\" >", "ServerYO", "key", "production", ""]],
|
||||
["name" => 1, "id" => 2, "status" => 3, "purchase_date" => 4],
|
||||
["org_id" => ["name" => 0]],
|
||||
["id"],
|
||||
[0 => "<svg onclick"alert(1)" >", "org_id" => "3", 1 => "ServerYO", 2 => "1", 3 => "production", 4 => "", "id" => 1, "__STATUS__" => "unchanged"],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
75
tests/php-unit-tests/unitary-tests/core/CMDBObjectTest.php
Normal file
75
tests/php-unit-tests/unitary-tests/core/CMDBObjectTest.php
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Core;
|
||||
|
||||
|
||||
use CMDBObject;
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use MetaModel;
|
||||
|
||||
/**
|
||||
* @since 2.7.7 3.0.2 3.1.0 N°3717 tests history objects creation
|
||||
*
|
||||
* @package Combodo\iTop\Test\UnitTest\Core
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class CMDBObjectTest extends ItopDataTestCase
|
||||
{
|
||||
/**
|
||||
* @covers CMDBObject::SetCurrentChange
|
||||
*/
|
||||
public function testCurrentChange()
|
||||
{
|
||||
// save initial conditions
|
||||
$oInitialCurrentChange = CMDBObject::GetCurrentChange();
|
||||
$sInitialTrackInfo = CMDBObject::GetTrackInfo();
|
||||
// reset current change
|
||||
CMDBObject::SetCurrentChange(null);
|
||||
|
||||
//-- new object with only track info
|
||||
$sTrackInfo = 'PHPUnit test';
|
||||
CMDBObject::SetTrackInfo($sTrackInfo);
|
||||
/** @var \DocumentWeb $oTestObject */
|
||||
$oTestObject = MetaModel::NewObject('DocumentWeb');
|
||||
$oTestObject->Set('name', 'PHPUnit test');
|
||||
$oTestObject->Set('org_id', 1);
|
||||
$oTestObject->Set('url', 'https://www.combodo.com');
|
||||
$oTestObject->DBWrite();
|
||||
self::assertFalse(CMDBObject::GetCurrentChange()->IsNew(), 'TrackInfo : Current change persisted');
|
||||
self::assertEquals($sTrackInfo, CMDBObject::GetCurrentChange()->Get('userinfo'),
|
||||
'TrackInfo : current change created with expected trackinfo');
|
||||
|
||||
//-- new object with non persisted current change
|
||||
$sTrackInfo2 = $sTrackInfo.'_2';
|
||||
/** @var \CMDBChange $oCustomChange */
|
||||
$oCustomChange = MetaModel::NewObject('CMDBChange');
|
||||
$oCustomChange->Set('date', time());
|
||||
$oCustomChange->Set('userinfo', $sTrackInfo2);
|
||||
CMDBObject::SetCurrentChange($oCustomChange);
|
||||
$oTestObject->Set('url', 'https://fr.wikipedia.org');
|
||||
$oTestObject->DBUpdate();
|
||||
self::assertFalse(CMDBObject::GetCurrentChange()->IsNew(), 'SetCurrentChange : Current change persisted');
|
||||
self::assertEquals($sTrackInfo2, CMDBObject::GetCurrentChange()->Get('userinfo'),
|
||||
'SetCurrentChange : current change created with expected trackinfo');
|
||||
|
||||
//-- new object with current change init using helper method
|
||||
$sTrackInfo3 = $sTrackInfo.'_3';
|
||||
CMDBObject::SetCurrentChangeFromParams($sTrackInfo3);
|
||||
$oTestObject->Set('url', 'https://en.wikipedia.org');
|
||||
$oTestObject->DBUpdate();
|
||||
self::assertFalse(CMDBObject::GetCurrentChange()->IsNew(), 'SetCurrentChangeFromParams : Current change persisted');
|
||||
self::assertEquals($sTrackInfo3, CMDBObject::GetCurrentChange()->Get('userinfo'),
|
||||
'SetCurrentChangeFromParams : current change created with expected trackinfo');
|
||||
|
||||
// restore initial conditions
|
||||
$oTestObject->DBDelete();
|
||||
CMDBObject::SetCurrentChange($oInitialCurrentChange);
|
||||
CMDBObject::SetTrackInfo($sInitialTrackInfo);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Core;
|
||||
|
||||
use CMDBSource;
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
use utils;
|
||||
|
||||
/**
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @package Combodo\iTop\Test\UnitTest\Core
|
||||
*/
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class CMDBSourceTest extends ItopTestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
|
||||
parent::setUp();
|
||||
require_once(APPROOT.'/core/cmdbsource.class.inc.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers CMDBSource::IsSameFieldTypes
|
||||
* @dataProvider compareFieldTypesProvider
|
||||
*
|
||||
* @param boolean $bResult
|
||||
* @param string $sItopFieldType
|
||||
* @param string $sDbFieldType
|
||||
*/
|
||||
public function testCompareFieldTypes($bResult, $sItopFieldType, $sDbFieldType)
|
||||
{
|
||||
$this->assertEquals($bResult, CMDBSource::IsSameFieldTypes($sItopFieldType, $sDbFieldType), "$sItopFieldType\n VS\n $sDbFieldType");
|
||||
}
|
||||
|
||||
public function compareFieldTypesProvider()
|
||||
{
|
||||
return array(
|
||||
'same datetime types' => array(true, 'DATETIME', 'DATETIME'),
|
||||
'different types' => array(false, 'VARCHAR(255)', 'INT(11)'),
|
||||
'different types, same type options' => array(false, 'VARCHAR(11)', 'INT(11)'),
|
||||
'same int declaration, same case' => array(true, 'INT(11)', 'INT(11)'),
|
||||
'same int declaration, different case on data type' => array(true, 'INT(11)', 'int(11)'),
|
||||
'same enum declaration, same case' => array(
|
||||
true,
|
||||
"ENUM('error','idle','planned','running')",
|
||||
"ENUM('error','idle','planned','running')",
|
||||
),
|
||||
'same enum declaration, different case on data type' => array(
|
||||
true,
|
||||
"ENUM('error','idle','planned','running')",
|
||||
"enum('error','idle','planned','running')",
|
||||
),
|
||||
'same enum declaration, different case on type options' => array(
|
||||
false,
|
||||
"ENUM('ERROR','IDLE','planned','running')",
|
||||
"ENUM('error','idle','planned','running')",
|
||||
),
|
||||
'same enum declaration, different case on both data type and type options' => array(
|
||||
false,
|
||||
"ENUM('ERROR','IDLE','planned','running')",
|
||||
"enum('error','idle','planned','running')",
|
||||
),
|
||||
'MariaDB 10.2 nullable datetime' => array(
|
||||
true,
|
||||
'DATETIME',
|
||||
"datetime DEFAULT 'NULL'",
|
||||
),
|
||||
'MariaDB 10.2 nullable text' => array(
|
||||
true,
|
||||
'TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci',
|
||||
"text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT 'NULL'",
|
||||
),
|
||||
'MariaDB 10.2 nullable unsigned int' => array(
|
||||
true,
|
||||
'INT(11) UNSIGNED',
|
||||
"int(11) unsigned DEFAULT 'NULL'",
|
||||
),
|
||||
'MariaDB 10.2 varchar with default value' => array(
|
||||
true,
|
||||
'VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT 0',
|
||||
"varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '0'",
|
||||
),
|
||||
'varchar with default value not at the end' => array(
|
||||
true,
|
||||
"VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT 0 COMMENT 'my comment'",
|
||||
"varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '0' COMMENT 'my comment'",
|
||||
),
|
||||
'MariaDB 10.2 Enum with string default value' => array(
|
||||
true,
|
||||
"ENUM('error','idle','planned','running') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT 'planned'",
|
||||
"enum('error','idle','planned','running') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT 'planned'",
|
||||
),
|
||||
'MariaDB 10.2 Enum with numeric default value' => array(
|
||||
true,
|
||||
"ENUM('1','2','3') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '1'",
|
||||
"enum('1','2','3') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '1'",
|
||||
),
|
||||
'ENUM with values containing parenthesis' => array(
|
||||
true, // see N°3065 : if having distinct values having parenthesis in enum values will cause comparison to be inexact
|
||||
"ENUM('CSP A','CSP M','NA','OEM(ROC)','OPEN(VL)','RETAIL (Boite)') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci",
|
||||
"enum('CSP A','CSP M','NA','OEM(ROC)','OPEN(VL)','RETAIL (Boite)') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci",
|
||||
),
|
||||
// N°3065 before the fix this returned true :(
|
||||
'ENUM with different values, containing parenthesis' => array(
|
||||
false,
|
||||
"ENUM('value 1 (with parenthesis)','value 2') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci",
|
||||
"enum('value 1 (with parenthesis)','value 3') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci",
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \ConfigException
|
||||
* @throws \CoreException
|
||||
* @throws \MySQLException
|
||||
* @since 3.0.0 N°4215
|
||||
*/
|
||||
public function testIsOpenedDbConnectionUsingTls() {
|
||||
$oConfig = utils::GetConfig();
|
||||
CMDBSource::InitFromConfig($oConfig);
|
||||
$oMysqli = CMDBSource::GetMysqli();
|
||||
|
||||
// resets \CMDBSource::$oMySQLiForQuery to simulate call to \CMDBSource::Init with a TLS connexion
|
||||
$this->InvokeNonPublicStaticMethod(CMDBSource::class, 'SetMySQLiForQuery',[null]);
|
||||
|
||||
// before N°4215 fix, this was crashing : "Call to a member function query() on null"
|
||||
$bIsTlsCnx = $this->InvokeNonPublicStaticMethod(CMDBSource::class, 'IsOpenedDbConnectionUsingTls',[$oMysqli]);
|
||||
$this->assertFalse($bIsTlsCnx);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Core;
|
||||
|
||||
|
||||
use CMDBSource;
|
||||
use Exception;
|
||||
use IssueLog;
|
||||
use MySQLException;
|
||||
use utils;
|
||||
|
||||
class DeadLockInjection
|
||||
{
|
||||
private $bMustFail = false;
|
||||
private $iRequestCount = 0;
|
||||
private $iFailAt = 0;
|
||||
private $bShowRequest = true;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param int $iFailAt
|
||||
*/
|
||||
public function SetFailAt($iFailAt)
|
||||
{
|
||||
$this->bMustFail = true;
|
||||
$this->iRequestCount = 0;
|
||||
$this->iFailAt = $iFailAt;
|
||||
$this->bShowRequest = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $bShowRequest
|
||||
*/
|
||||
public function SetShowRequest($bShowRequest)
|
||||
{
|
||||
$this->bShowRequest = $bShowRequest;
|
||||
}
|
||||
|
||||
|
||||
public function query($sSQL)
|
||||
{
|
||||
if (utils::StartsWith($sSQL, "SELECT")) {
|
||||
return;
|
||||
}
|
||||
if ($this->bShowRequest) {
|
||||
$sShortSQL = substr(preg_replace("/\s+/", " ", substr($sSQL, 0, 180)), 0, 150);
|
||||
echo "$sShortSQL\n";
|
||||
}
|
||||
if (CMDBSource::IsInsideTransaction() && $this->bMustFail) {
|
||||
$this->iRequestCount++;
|
||||
if ($this->iRequestCount == $this->iFailAt) {
|
||||
echo "Generating a FAKE DEADLOCK\n";
|
||||
IssueLog::Trace("Generating a FAKE DEADLOCK", 'cmdbsource');
|
||||
throw new MySQLException("FAKE DEADLOCK", [], new Exception("FAKE DEADLOCK", 1213));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,286 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Core;
|
||||
|
||||
use CMDBSource;
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
use Exception;
|
||||
use MetaModel;
|
||||
use MySQLTransactionNotClosedException;
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*
|
||||
* @group itopRequestMgmt
|
||||
* Class TransactionsTest
|
||||
*
|
||||
* @package Combodo\iTop\Test\UnitTest\Core
|
||||
*/
|
||||
class TransactionsTest extends ItopTestCase
|
||||
{
|
||||
/** @var DeadLockInjection */
|
||||
private $oMySQLiMock;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
require_once('DeadLockInjection.php');
|
||||
require_once(APPROOT.'/core/cmdbsource.class.inc.php');
|
||||
$sEnv = 'production';
|
||||
$sConfigFile = APPCONF.$sEnv.'/config-itop.php';
|
||||
|
||||
MetaModel::Startup($sConfigFile, false, true, false, $sEnv);
|
||||
|
||||
$oInitialMysqli = CMDBSource::GetMysqli();
|
||||
$this->oMySQLiMock = new DeadLockInjection();
|
||||
|
||||
$oMockMysqli = $this->getMockBuilder('mysqli')
|
||||
->setMethods(['query'])
|
||||
->getMock();
|
||||
$oMockMysqli->expects($this->any())
|
||||
->method('query')
|
||||
->will($this->returnCallback(
|
||||
function ($sSql) use ($oInitialMysqli) {
|
||||
$this->oMySQLiMock->query($sSql);
|
||||
return $oInitialMysqli->query($sSql);
|
||||
}
|
||||
));
|
||||
|
||||
$this->InvokeNonPublicStaticMethod('CMDBSource', 'SetMySQLiForQuery', [$oMockMysqli]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test DBInsertNoReload database transaction by provoking deadlock exceptions
|
||||
*
|
||||
* @dataProvider DBInsertProvider
|
||||
*
|
||||
* @param int $iFailAt Specify the request occurrence that fails
|
||||
* @param bool $bIsInDB Indicates if the object must have been created or not
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \DeleteException
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function testDBInsert($iFailAt, $bIsInDB)
|
||||
{
|
||||
// Create a UserRequest with 2 contacts
|
||||
$oTicket = MetaModel::NewObject('UserRequest', [
|
||||
'ref' => 'Test Ticket',
|
||||
'title' => 'Create OK',
|
||||
'description' => 'Create OK',
|
||||
'caller_id' => 15,
|
||||
'org_id' => 3,
|
||||
]);
|
||||
$oLinkSet = $oTicket->Get('contacts_list');
|
||||
$oLinkSet->AddItem(MetaModel::NewObject('lnkContactToTicket', ['contact_id' => 6]));
|
||||
$oLinkSet->AddItem(MetaModel::NewObject('lnkContactToTicket', ['contact_id' => 7]));
|
||||
|
||||
$this->oMySQLiMock->SetFailAt($iFailAt);
|
||||
$this->debug("---> DBInsert()");
|
||||
try {
|
||||
$oTicket->DBWrite();
|
||||
}
|
||||
catch (Exception $e) {
|
||||
// If an exception occurs must be a deadlock
|
||||
$this->assertTrue(CMDBSource::IsDeadlockException($e), $e->getMessage());
|
||||
}
|
||||
|
||||
// Verify if the ticket is considered as saved in the database
|
||||
$this->assertEquals($bIsInDB, !$oTicket->IsNew(), " The ticket should be persisted in the DB");
|
||||
|
||||
if (!$oTicket->IsNew()) {
|
||||
$this->oMySQLiMock->SetShowRequest(false);
|
||||
// Delete created objects
|
||||
$oTicket->DBDelete();
|
||||
}
|
||||
}
|
||||
|
||||
public function DBInsertProvider()
|
||||
{
|
||||
return [
|
||||
"Normal case" => ['iFailAt' => -1, 'bIsInDB' => true],
|
||||
"ticket" => ['iFailAt' => 1, 'bIsInDB' => false],
|
||||
"ticket_request" => ['iFailAt' => 2, 'bIsInDB' => false],
|
||||
"priv_change" => ['iFailAt' => 3, 'bIsInDB' => false],
|
||||
"priv_changeop" => ['iFailAt' => 4, 'bIsInDB' => false],
|
||||
"priv_changeop_create" => ['iFailAt' => 5, 'bIsInDB' => false],
|
||||
"History 4" => ['iFailAt' => 6, 'bIsInDB' => false],
|
||||
"History 5" => ['iFailAt' => 7, 'bIsInDB' => false],
|
||||
"History 6" => ['iFailAt' => 8, 'bIsInDB' => false],
|
||||
"History 7" => ['iFailAt' => 9, 'bIsInDB' => false],
|
||||
"History 8" => ['iFailAt' => 10, 'bIsInDB' => false],
|
||||
"History 9" => ['iFailAt' => 11, 'bIsInDB' => false],
|
||||
"History 10" => ['iFailAt' => 12, 'bIsInDB' => false],
|
||||
"History 11" => ['iFailAt' => 13, 'bIsInDB' => false],
|
||||
"History 12" => ['iFailAt' => 14, 'bIsInDB' => false],
|
||||
"History 13" => ['iFailAt' => 15, 'bIsInDB' => false],
|
||||
"History 14" => ['iFailAt' => 16, 'bIsInDB' => false],
|
||||
"History 15" => ['iFailAt' => 17, 'bIsInDB' => false],
|
||||
// For 3.0 when CRUD sequence is ok
|
||||
// "History 16" => ['iFailAt' => 18, 'bIsInDB' => false],
|
||||
// "History 17" => ['iFailAt' => 19, 'bIsInDB' => false],
|
||||
// "History 18" => ['iFailAt' => 20, 'bIsInDB' => false],
|
||||
// "History 19" => ['iFailAt' => 21, 'bIsInDB' => false],
|
||||
// "History 20" => ['iFailAt' => 22, 'bIsInDB' => false],
|
||||
// "History 21" => ['iFailAt' => 23, 'bIsInDB' => false],
|
||||
// "History 22" => ['iFailAt' => 24, 'bIsInDB' => false],
|
||||
// "History 23" => ['iFailAt' => 25, 'bIsInDB' => false],
|
||||
// "History 24" => ['iFailAt' => 26, 'bIsInDB' => false],
|
||||
// "History 25" => ['iFailAt' => 27, 'bIsInDB' => false],
|
||||
// "History 26" => ['iFailAt' => 28, 'bIsInDB' => false],
|
||||
// "History 27" => ['iFailAt' => 29, 'bIsInDB' => false],
|
||||
// "History 28" => ['iFailAt' => 30, 'bIsInDB' => false],
|
||||
// "History 29" => ['iFailAt' => 31, 'bIsInDB' => false],
|
||||
// "History 30" => ['iFailAt' => 32, 'bIsInDB' => false],
|
||||
// "History 31" => ['iFailAt' => 33, 'bIsInDB' => false],
|
||||
// "History 32" => ['iFailAt' => 34, 'bIsInDB' => false],
|
||||
// "History 33" => ['iFailAt' => 35, 'bIsInDB' => false],
|
||||
// "History 34" => ['iFailAt' => 36, 'bIsInDB' => false],
|
||||
// "History 35" => ['iFailAt' => 37, 'bIsInDB' => false],
|
||||
// "History 36" => ['iFailAt' => 38, 'bIsInDB' => false],
|
||||
// "History 37" => ['iFailAt' => 39, 'bIsInDB' => false],
|
||||
// "History 38" => ['iFailAt' => 40, 'bIsInDB' => false],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test DBUpdate database transaction by provoking deadlock exceptions
|
||||
*
|
||||
* @dataProvider DBUpdateProvider
|
||||
* @param $iFailAt
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \DeleteException
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function testDBUpdate($iFailAt, $bIsModified)
|
||||
{
|
||||
// Create a UserRequest into the database with 2 contacts
|
||||
$oTicket = MetaModel::NewObject('UserRequest', [
|
||||
'ref' => 'Test Ticket',
|
||||
'title' => 'Create OK',
|
||||
'description' => 'Create OK',
|
||||
'solution' => 'Create OK',
|
||||
'caller_id' => 15,
|
||||
'org_id' => 3,
|
||||
]);
|
||||
$oLinkSet = $oTicket->Get('contacts_list');
|
||||
$oLinkSet->AddItem(MetaModel::NewObject('lnkContactToTicket', ['contact_id' => 6]));
|
||||
$oLinkSet->AddItem(MetaModel::NewObject('lnkContactToTicket', ['contact_id' => 7]));
|
||||
//$oTicket->Set('contacts_list', $oLinkSet);
|
||||
|
||||
$this->oMySQLiMock->SetShowRequest(false);
|
||||
$oTicket->DBWrite();
|
||||
|
||||
// Verify that the object is considered as saved in the database
|
||||
$this->assertEquals(true, !$oTicket->IsNew());
|
||||
|
||||
// Reload from db
|
||||
$oTicket = MetaModel::GetObject('UserRequest', $oTicket->GetKey());
|
||||
$oTicket->Set('description', 'Update OK');
|
||||
$oTicket->Set('solution', 'Test OK');
|
||||
$oLinkSet = $oTicket->Get('contacts_list');
|
||||
$oLinkSet->AddItem(MetaModel::NewObject('lnkContactToTicket', ['contact_id' => 8]));
|
||||
$oTicket->Set('contacts_list', $oLinkSet);
|
||||
|
||||
// Provoke an error during the update
|
||||
$this->oMySQLiMock->SetFailAt($iFailAt);
|
||||
$this->debug("---> DBUpdate()");
|
||||
try {
|
||||
$oTicket->DBWrite();
|
||||
}
|
||||
catch (Exception $e) {
|
||||
// If an exception occurs must be a deadlock
|
||||
$this->assertTrue(CMDBSource::IsDeadlockException($e));
|
||||
}
|
||||
|
||||
// Verify if the ticket is considered as saved in the database
|
||||
$this->assertEquals($bIsModified, $oTicket->IsModified());
|
||||
|
||||
// Reload from db after the update to check the value present in the database
|
||||
$oTicket = MetaModel::GetObject('UserRequest', $oTicket->GetKey());
|
||||
if ($bIsModified) {
|
||||
$this->assertEquals('Create OK', $oTicket->Get('solution'));
|
||||
} else {
|
||||
$this->assertEquals('Test OK', $oTicket->Get('solution'));
|
||||
}
|
||||
|
||||
if (!$oTicket->IsNew()) {
|
||||
$this->oMySQLiMock->SetShowRequest(false);
|
||||
// Delete created objects
|
||||
$oTicket->DBDelete();
|
||||
}
|
||||
}
|
||||
|
||||
public function DBUpdateProvider()
|
||||
{
|
||||
return [
|
||||
"Normal case" => ['iFailAt' => -1, 'bIsModified' => false],
|
||||
"ticket_request" => ['iFailAt' => 1, 'bIsModified' => true],
|
||||
"lnkcontacttoticket" => ['iFailAt' => 2, 'bIsModified' => true],
|
||||
"History 1" => ['iFailAt' => 3, 'bIsModified' => true],
|
||||
"History 2" => ['iFailAt' => 4, 'bIsModified' => true],
|
||||
"History 3" => ['iFailAt' => 5, 'bIsModified' => true],
|
||||
"History 4" => ['iFailAt' => 6, 'bIsModified' => true],
|
||||
"History 5" => ['iFailAt' => 7, 'bIsModified' => true],
|
||||
"History 6" => ['iFailAt' => 8, 'bIsModified' => true],
|
||||
"History 7" => ['iFailAt' => 9, 'bIsModified' => true],
|
||||
"History 8" => ['iFailAt' => 10, 'bIsModified' => true],
|
||||
"History 9" => ['iFailAt' => 11, 'bIsModified' => true],
|
||||
"History 10" => ['iFailAt' => 12, 'bIsModified' => true],
|
||||
"History 11" => ['iFailAt' => 13, 'bIsModified' => true],
|
||||
"History 12" => ['iFailAt' => 14, 'bIsModified' => true],
|
||||
"History 13" => ['iFailAt' => 15, 'bIsModified' => true],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @doesNotPerformAssertions
|
||||
*/
|
||||
public function testTransactionOpenedThenClosed()
|
||||
{
|
||||
CMDBSource::Query('START TRANSACTION;');
|
||||
CMDBSource::Query('COMMIT;');
|
||||
}
|
||||
|
||||
/**
|
||||
* This will throw an exception in the tearDown method.
|
||||
* This cannot be detected nor by `@expectedException` nor `expectException` method, so we have a specific tearDown impl
|
||||
*
|
||||
* @return void
|
||||
* @doesNotPerformAssertions
|
||||
*/
|
||||
public function testTransactionOpenedNotClosed()
|
||||
{
|
||||
CMDBSource::Query('START TRANSACTION;');
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
try {
|
||||
parent::tearDown();
|
||||
}
|
||||
catch (MySQLTransactionNotClosedException $e) {
|
||||
if ($this->getName() === 'testTransactionOpenedNotClosed') {
|
||||
$this->debug('Executing the testTransactionOpenNoClose method throws a '.MySQLTransactionNotClosedException::class.' exception in tearDown');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2010-2020 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/>
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Core;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
use ConfigPlaceholdersResolver;
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class ConfigPlaceholdersResolverTest extends ItopTestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
require_once(APPROOT.'core/config.class.inc.php');
|
||||
}
|
||||
/**
|
||||
* @dataProvider providerResolve
|
||||
*/
|
||||
public function testResolve($aEnv, $aServer, $sValue, $sExpected, $sExpectedExceptionClass = null)
|
||||
{
|
||||
if ($sExpectedExceptionClass)
|
||||
{
|
||||
$this->expectException($sExpectedExceptionClass);
|
||||
}
|
||||
|
||||
$oConfigPlaceholdersResolver = new ConfigPlaceholdersResolver($aEnv, $aServer);
|
||||
$sResult = $oConfigPlaceholdersResolver->Resolve($sValue);
|
||||
|
||||
$this->assertEquals($sExpected, $sResult);
|
||||
}
|
||||
|
||||
public function providerResolve()
|
||||
{
|
||||
$stdObj = (object) array('%env(HTTP_PORT)?:8080%', '%server(toto)?:8080%', '%foo(toto)?:8080%');
|
||||
|
||||
return array(
|
||||
'basic behaviour' => array(
|
||||
'aEnv' => array('ITOP_CONFIG_PLACEHOLDERS' => 1, 'HTTP_PORT' => '443'),
|
||||
'aServer' => array(),
|
||||
'sValue' => '%env(HTTP_PORT)%',
|
||||
'sExpected' => '443',
|
||||
),
|
||||
|
||||
'disabled if no ITOP_CONFIG_PLACEHOLDERS' => array(
|
||||
'aEnv' => array('HTTP_PORT' => '443'),
|
||||
'aServer' => array(),
|
||||
'sValue' => '%env(HTTP_PORT)%',
|
||||
'sExpected' => '%env(HTTP_PORT)%',
|
||||
),
|
||||
|
||||
'basic with default not used' => array(
|
||||
'aEnv' => array('ITOP_CONFIG_PLACEHOLDERS' => 1, 'HTTP_PORT' => '443'),
|
||||
'aServer' => array(),
|
||||
'sValue' => '%env(HTTP_PORT)?:foo%',
|
||||
'sExpected' => '443',
|
||||
),
|
||||
|
||||
'basic with default used' => array(
|
||||
'aEnv' => array('ITOP_CONFIG_PLACEHOLDERS' => 1, ),
|
||||
'aServer' => array(),
|
||||
'sValue' => '%env(HTTP_PORT)?:foo%',
|
||||
'sExpected' => 'foo',
|
||||
),
|
||||
|
||||
'basic with default used and empty' => array(
|
||||
'aEnv' => array('ITOP_CONFIG_PLACEHOLDERS' => 1, ),
|
||||
'aServer' => array(),
|
||||
'sValue' => '%env(HTTP_PORT)?:%',
|
||||
'sExpected' => '',
|
||||
),
|
||||
|
||||
'mixed with static' => array(
|
||||
'aEnv' => array('ITOP_CONFIG_PLACEHOLDERS' => 1, 'HTTP_PORT' => '443'),
|
||||
'aServer' => array('toto' => 'tutu'),
|
||||
'sValue' => 'http://localhost:%env(HTTP_PORT)?:8080%/',
|
||||
'sExpected' => 'http://localhost:443/',
|
||||
),
|
||||
|
||||
'multiple occurrences' => array(
|
||||
'aEnv' => array('ITOP_CONFIG_PLACEHOLDERS' => 1, 'HTTP_PORT' => '443'),
|
||||
'aServer' => array('SERVER_NAME' => 'localhost'),
|
||||
'sValue' => 'http://%server(SERVER_NAME)%:%env(HTTP_PORT)%/',
|
||||
'sExpected' => 'http://localhost:443/',
|
||||
),
|
||||
|
||||
'array as source' => array(
|
||||
'aEnv' => array('ITOP_CONFIG_PLACEHOLDERS' => 1, 'HTTP_PORT' => '443'),
|
||||
'aServer' => array('toto' => 'tutu'),
|
||||
'sValue' => array('http://localhost:%env(HTTP_PORT)?:8080%/', '%foo(HTTP_PORT)?:8080%', '%server(toto)?:8080%'),
|
||||
'sExpected' => array('http://localhost:443/', '%foo(HTTP_PORT)?:8080%', 'tutu'),
|
||||
),
|
||||
|
||||
'invalid source' => array(
|
||||
'aEnv' => array('toto' => 'tutu'),
|
||||
'aServer' => array('HTTP_PORT' => '443'),
|
||||
'sValue' => '%foo(HTTP_PORT)?:8080%',
|
||||
'sExpected' => '%foo(HTTP_PORT)?:8080%',
|
||||
),
|
||||
|
||||
'ignored source' => array(
|
||||
'aEnv' => array('ITOP_CONFIG_PLACEHOLDERS' => 1, 'HTTP_PORT' => '443'),
|
||||
'aServer' => array('toto' => 'tutu'),
|
||||
'sValue' => $stdObj,
|
||||
'sExpected' => $stdObj,
|
||||
),
|
||||
|
||||
'env matching port' => array(
|
||||
'aEnv' => array('ITOP_CONFIG_PLACEHOLDERS' => 1, 'HTTP_PORT' => '443'),
|
||||
'aServer' => array('toto' => 'tutu'),
|
||||
'sValue' => '%env(HTTP_PORT)?:8080%',
|
||||
'sExpected' => '443',
|
||||
),
|
||||
'env no matching port with default ' => array(
|
||||
'aEnv' => array('ITOP_CONFIG_PLACEHOLDERS' => 1, 'foo' => 'bar'),
|
||||
'aServer' => array('toto' => 'tutu'),
|
||||
'sValue' => '%env(HTTP_PORT)?:8080%',
|
||||
'sExpected' => '8080',
|
||||
),
|
||||
'env no matching port' => array(
|
||||
'aEnv' => array('ITOP_CONFIG_PLACEHOLDERS' => 1, 'foo' => 'bar'),
|
||||
'aServer' => array('toto' => 'tutu'),
|
||||
'sValue' => '%env(HTTP_PORT)%',
|
||||
'sExpected' => null,
|
||||
'sExpectedExceptionClass' => 'ConfigException',
|
||||
),
|
||||
|
||||
'server matching port' => array(
|
||||
'aEnv' => array('ITOP_CONFIG_PLACEHOLDERS' => 1, 'toto' => 'tutu'),
|
||||
'aServer' => array('HTTP_PORT' => '443'),
|
||||
'sValue' => '%server(HTTP_PORT)?:8080%',
|
||||
'sExpected' => '443',
|
||||
),
|
||||
'server no matching port with default ' => array(
|
||||
'aEnv' => array('ITOP_CONFIG_PLACEHOLDERS' => 1, 'toto' => 'tutu'),
|
||||
'aServer' => array('foo' => 'bar'),
|
||||
'sValue' => '%server(HTTP_PORT)?:8080%',
|
||||
'sExpected' => '8080',
|
||||
),
|
||||
'server no matching port' => array(
|
||||
'aEnv' => array('ITOP_CONFIG_PLACEHOLDERS' => 1, 'toto' => 'tutu'),
|
||||
'aServer' => array('foo' => 'bar'),
|
||||
'sValue' => '%server(HTTP_PORT)%',
|
||||
'sExpected' => null,
|
||||
'sExpectedExceptionClass' => 'ConfigException',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
99
tests/php-unit-tests/unitary-tests/core/ConfigTest.php
Normal file
99
tests/php-unit-tests/unitary-tests/core/ConfigTest.php
Normal file
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2010-2020 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/>
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Core;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
use Config;
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class ConfigTest extends ItopTestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
require_once(APPROOT.'core/config.class.inc.php');
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @dataProvider ProviderPreserveVarOnWriteToFile
|
||||
*
|
||||
* @throws \ConfigException
|
||||
* @throws \CoreException
|
||||
*
|
||||
*/
|
||||
public function testPreserveVarOnWriteToFile($sConfigFile, $sExpectedContains, $aChanges)
|
||||
{
|
||||
$sTmpFile = tempnam(sys_get_temp_dir(), "target");
|
||||
|
||||
$oConfig = new Config($sConfigFile);
|
||||
|
||||
foreach ($aChanges as $key => $val)
|
||||
{
|
||||
$oConfig->Set($key, $val);
|
||||
}
|
||||
|
||||
$oConfig->WriteToFile($sTmpFile);
|
||||
|
||||
$this->assertFileExists($sTmpFile);
|
||||
$sFileContent = file_get_contents($sTmpFile);
|
||||
|
||||
$this->assertContains($sExpectedContains, $sFileContent);
|
||||
}
|
||||
|
||||
public function ProviderPreserveVarOnWriteToFile()
|
||||
{
|
||||
return array(
|
||||
'preserve var' => array(
|
||||
'sConfigFile' => __DIR__.'/ConfigTest/config-itop-var.php',
|
||||
'sExpectedContains' => "'app_root_url' => 'http://' . (isset(\$_SERVER['SERVER_NAME']) ? \$_SERVER['SERVER_NAME'] : 'localhost') . '/itop/iTop/'",
|
||||
'aChanges' => array(),
|
||||
),
|
||||
'preserve joker' => array(
|
||||
'sConfigFile' => __DIR__.'/ConfigTest/config-itop-joker.php',
|
||||
'sExpectedContains' => "'app_root_url' => 'http://%server(SERVER_NAME)?:localhost%/itop/iTop/'",
|
||||
'aChanges' => array(),
|
||||
),
|
||||
|
||||
'preserve set same value' => array(
|
||||
'sConfigFile' => __DIR__.'/ConfigTest/config-itop-var.php',
|
||||
'sExpectedContains' => "'app_root_url' => 'http://' . (isset(\$_SERVER['SERVER_NAME']) ? \$_SERVER['SERVER_NAME'] : 'localhost') . '/itop/iTop/'",
|
||||
'aChanges' => array('app_root_url' => 'http://localhost/itop/iTop/'),
|
||||
),
|
||||
|
||||
'overwrite var' => array(
|
||||
'sConfigFile' => __DIR__.'/ConfigTest/config-itop-var.php',
|
||||
'sExpectedContains' => "'app_root_url' => 'foo",
|
||||
'aChanges' => array('app_root_url' => 'foo'),
|
||||
),
|
||||
'overwrite joker' => array(
|
||||
'sConfigFile' => __DIR__.'/ConfigTest/config-itop-joker.php',
|
||||
'sExpectedContains' => "'app_root_url' => 'foo",
|
||||
'aChanges' => array('app_root_url' => 'foo'),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Configuration file, generated for the unit tests
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
$MySettings = array(
|
||||
|
||||
|
||||
|
||||
// app_root_url: Root URL used for navigating within the application, or from an email to the application (you can put $SERVER_NAME$ as a placeholder for the server's name)
|
||||
// default: ''
|
||||
'app_root_url' => 'http://%server(SERVER_NAME)?:localhost%/itop/iTop/',
|
||||
|
||||
|
||||
);
|
||||
|
||||
/**
|
||||
*
|
||||
* Modules specific settings
|
||||
*
|
||||
*/
|
||||
$MyModuleSettings = array(
|
||||
);
|
||||
|
||||
/**
|
||||
*
|
||||
* Data model modules to be loaded. Names are specified as relative paths
|
||||
*
|
||||
*/
|
||||
$MyModules = array(
|
||||
'addons' => array('user rights' => 'addons/userrights/userrightsprofile.class.inc.php'),
|
||||
);
|
||||
?>
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Configuration file, generated for the unit tests
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
$MySettings = array(
|
||||
|
||||
|
||||
|
||||
// app_root_url: Root URL used for navigating within the application, or from an email to the application (you can put $SERVER_NAME$ as a placeholder for the server's name)
|
||||
// default: ''
|
||||
'app_root_url' => 'http://' . (isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'localhost') . '/itop/iTop/',
|
||||
|
||||
|
||||
);
|
||||
|
||||
/**
|
||||
*
|
||||
* Modules specific settings
|
||||
*
|
||||
*/
|
||||
$MyModuleSettings = array(
|
||||
);
|
||||
|
||||
/**
|
||||
*
|
||||
* Data model modules to be loaded. Names are specified as relative paths
|
||||
*
|
||||
*/
|
||||
$MyModules = array(
|
||||
'addons' => array('user rights' => 'addons/userrights/userrightsprofile.class.inc.php'),
|
||||
);
|
||||
?>
|
||||
@@ -0,0 +1,392 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Configuration file, generated by the iTop configuration wizard
|
||||
*
|
||||
* The file is used in MetaModel::LoadConfig() which does all the necessary initialization job
|
||||
*
|
||||
*/
|
||||
$MySettings = array(
|
||||
|
||||
// access_message: Message displayed to the users when there is any access restriction
|
||||
// default: 'iTop is temporarily frozen, please wait... (the admin team)'
|
||||
'access_message' => 'iTop is temporarily frozen, please wait... (the admin team)',
|
||||
|
||||
// access_mode: Access mode: ACCESS_READONLY = 0, ACCESS_ADMIN_WRITE = 2, ACCESS_FULL = 3
|
||||
// default: 3
|
||||
'access_mode' => 3,
|
||||
|
||||
// activity_panel.entry_form_opened_by_default: Whether or not the new entry form will be automatically opened when viewing an object.
|
||||
// default: false
|
||||
'activity_panel.entry_form_opened_by_default' => false,
|
||||
|
||||
// activity_panel.show_author_name_below_entries: Whether or not to show the author friendlyname next to the date on the last entry.
|
||||
// default: false
|
||||
'activity_panel.show_author_name_below_entries' => false,
|
||||
|
||||
'allowed_login_types' => 'form|external|basic',
|
||||
|
||||
// apc_cache.enabled: If set, the APC cache is allowed (the PHP extension must also be active)
|
||||
// default: true
|
||||
'apc_cache.enabled' => true,
|
||||
|
||||
// apc_cache.query_ttl: Time to live set in APC for the prepared queries (seconds - 0 means no timeout)
|
||||
// default: 3600
|
||||
'apc_cache.query_ttl' => 3600,
|
||||
|
||||
// app_root_url: Root URL used for navigating within the application, or from an email to the application (you can put $SERVER_NAME$ as a placeholder for the server's name)
|
||||
// default: ''
|
||||
'app_root_url' => 'http://localhost/itop-dev/',
|
||||
|
||||
// behind_reverse_proxy: If true, then proxies custom header (X-Forwarded-*) are taken into account. Use only if the webserver is not publicly accessible (reachable only by the reverse proxy)
|
||||
// default: false
|
||||
'behind_reverse_proxy' => false,
|
||||
|
||||
// cron_max_execution_time: Duration (seconds) of the page cron.php, must be shorter than php setting max_execution_time and shorter than the web server response timeout
|
||||
// default: 600
|
||||
'cron_max_execution_time' => 600,
|
||||
|
||||
// csv_file_default_charset: Character set used by default for downloading and uploading data as a CSV file. Warning: it is case sensitive (uppercase is preferable).
|
||||
// default: 'ISO-8859-1'
|
||||
'csv_file_default_charset' => 'ISO-8859-1',
|
||||
|
||||
'csv_import_charsets' => array(),
|
||||
|
||||
// csv_import_history_display: Display the history tab in the import wizard
|
||||
// default: false
|
||||
'csv_import_history_display' => false,
|
||||
|
||||
// date_and_time_format: Format for date and time display (per language)
|
||||
// default: array (
|
||||
// 'default' =>
|
||||
// array (
|
||||
// 'date' => 'Y-m-d',
|
||||
// 'time' => 'H:i:s',
|
||||
// 'date_time' => '$date $time',
|
||||
// ),
|
||||
// )
|
||||
'date_and_time_format' => array(
|
||||
'default' =>
|
||||
array(
|
||||
'date' => 'Y-m-d',
|
||||
'time' => 'H:i:s',
|
||||
'date_time' => '$date $time',
|
||||
),
|
||||
),
|
||||
|
||||
'db_host' => 'localhost',
|
||||
|
||||
'db_name' => 'itop_dev',
|
||||
|
||||
'db_pwd' => '',
|
||||
|
||||
'db_subname' => '',
|
||||
|
||||
'db_user' => 'root',
|
||||
|
||||
// deadline_format: The format used for displaying "deadline" attributes: any string with the following placeholders: $date$, $difference$
|
||||
// default: '$difference$'
|
||||
'deadline_format' => '$difference$',
|
||||
|
||||
'default_language' => 'EN US',
|
||||
|
||||
// email_asynchronous: If set, the emails are sent off line, which requires cron.php to be activated. Exception: some features like the email test utility will force the serialized mode
|
||||
// default: false
|
||||
'email_asynchronous' => false,
|
||||
|
||||
// email_default_sender_address: Default address provided in the email from header field.
|
||||
// default: ''
|
||||
'email_default_sender_address' => '',
|
||||
|
||||
// email_default_sender_label: Default label provided in the email from header field.
|
||||
// default: ''
|
||||
'email_default_sender_label' => '',
|
||||
|
||||
// email_transport: Mean to send emails: PHPMail (uses the function mail()) or SMTP (implements the client protocol)
|
||||
// default: 'PHPMail'
|
||||
'email_transport' => 'PHPMail',
|
||||
|
||||
// email_validation_pattern: Regular expression to validate/detect the format of an eMail address
|
||||
// default: '[a-zA-Z0-9._&\'-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z0-9-]{2,}'
|
||||
'email_validation_pattern' => '[a-zA-Z0-9._&\'-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z0-9-]{2,}',
|
||||
|
||||
'encryption_key' => '061c5b88c47ed64664618cf37b91a442b5550704aacecc5f58f96fc98087333b',
|
||||
|
||||
'encryption_library' => 'OpenSSL',
|
||||
|
||||
'ext_auth_variable' => '$_SERVER[\'REMOTE_USER\']',
|
||||
|
||||
'fast_reload_interval' => 60,
|
||||
|
||||
// graphviz_path: Path to the Graphviz "dot" executable for graphing objects lifecycle
|
||||
// default: '/usr/bin/dot'
|
||||
'graphviz_path' => 'C:\\Program Files (x86)\\Graphviz2.38\\bin\\dot.exe',
|
||||
|
||||
// high_cardinality_classes: List of classes with high cardinality (Force manual submit of search)
|
||||
// default: array (
|
||||
// )
|
||||
'high_cardinality_classes' => array(),
|
||||
|
||||
// inline_image_max_display_width: The maximum width (in pixels) when displaying images inside an HTML formatted attribute. Images will be displayed using this this maximum width.
|
||||
// default: '250'
|
||||
'inline_image_max_display_width' => '250',
|
||||
|
||||
// inline_image_max_storage_width: The maximum width (in pixels) when uploading images to be used inside an HTML formatted attribute. Images larger than the given size will be downsampled before storing them in the database.
|
||||
// default: '1600'
|
||||
'inline_image_max_storage_width' => '1600',
|
||||
|
||||
// link_set_attribute_qualifier: Link set from string: attribute qualifier (encloses both the attcode and the value)
|
||||
// default: '\''
|
||||
'link_set_attribute_qualifier' => '\'',
|
||||
|
||||
// link_set_attribute_separator: Link set from string: attribute separator
|
||||
// default: ';'
|
||||
'link_set_attribute_separator' => ';',
|
||||
|
||||
// link_set_item_separator: Link set from string: line separator
|
||||
// default: '|'
|
||||
'link_set_item_separator' => '|',
|
||||
|
||||
// link_set_value_separator: Link set from string: value separator (between the attcode and the value itself
|
||||
// default: ':'
|
||||
'link_set_value_separator' => ':',
|
||||
|
||||
'log_global' => true,
|
||||
|
||||
'log_issue' => true,
|
||||
|
||||
'log_kpi_duration' => 0,
|
||||
|
||||
'log_notification' => true,
|
||||
|
||||
'log_web_service' => true,
|
||||
|
||||
'max_display_limit' => 30,
|
||||
|
||||
// max_linkset_output: Maximum number of items shown when getting a list of related items in an email, using the form $this->some_list$. 0 means no limit.
|
||||
// default: 100
|
||||
'max_linkset_output' => 100,
|
||||
|
||||
// mentions.allowed_classes: Classes which can be mentioned through the autocomplete in the caselogs. Key of the array must be a single character that will trigger the autocomplete, value can be either a DM class or a valid OQL (eg. "@" => "Person", "?" => "SELECT FAQ WHERE status = 'published'")
|
||||
// default: array (
|
||||
// '@' => 'SELECT Person WHERE status = \'active\'',
|
||||
// )
|
||||
'mentions.allowed_classes' => array(
|
||||
'@' => 'SELECT Person WHERE status = \'active\'',
|
||||
),
|
||||
|
||||
'min_display_limit' => 20,
|
||||
|
||||
// online_help: Hyperlink to the online-help web page
|
||||
// default: 'http://www.combodo.com/itop-help'
|
||||
'online_help' => 'http://www.combodo.com/itop-help',
|
||||
|
||||
// optimize_requests_for_join_count: Optimize request joins to minimize the count (default is true, try to set it to false in case of performance issues)
|
||||
// default: true
|
||||
'optimize_requests_for_join_count' => true,
|
||||
|
||||
'password_hash_algo' => '2y',
|
||||
|
||||
// php_path: Path to the php executable in CLI mode
|
||||
// default: 'php'
|
||||
'php_path' => 'php',
|
||||
|
||||
// search_manual_submit: Force manual submit of search all requests
|
||||
// default: false
|
||||
'search_manual_submit' => false,
|
||||
|
||||
'secure_connection_required' => false,
|
||||
|
||||
// session_name: The name of the cookie used to store the PHP session id
|
||||
// default: 'iTop'
|
||||
'session_name' => 'iTop',
|
||||
|
||||
// shortcut_actions: Actions that are available as direct buttons next to the "Actions" menu
|
||||
// default: 'UI:Menu:Modify,UI:Menu:New'
|
||||
'shortcut_actions' => 'UI:Menu:Modify,UI:Menu:New',
|
||||
|
||||
// source_dir: Source directory for the datamodel files. (which gets compiled to env-production).
|
||||
// default: ''
|
||||
'source_dir' => 'datamodels/2.x/',
|
||||
|
||||
'standard_reload_interval' => 300,
|
||||
|
||||
// synchro_trace: Synchronization details: none, display, save (includes 'display')
|
||||
// default: 'none'
|
||||
'synchro_trace' => 'none',
|
||||
|
||||
// tag_set_item_separator: Tag set from string: tag label separator
|
||||
// default: '|'
|
||||
'tag_set_item_separator' => '|',
|
||||
|
||||
// timezone: Timezone (reference: http://php.net/manual/en/timezones.php). If empty, it will be left unchanged and MUST be explicitly configured in PHP
|
||||
// default: 'Europe/Paris'
|
||||
'timezone' => 'Europe/Paris',
|
||||
|
||||
// tracking_level_linked_set_default: Default tracking level if not explicitly set at the attribute level, for AttributeLinkedSet (defaults to NONE in case of a fresh install, LIST otherwise - this to preserve backward compatibility while upgrading from a version older than 2.0.3 - see TRAC #936)
|
||||
// default: 1
|
||||
'tracking_level_linked_set_default' => 0,
|
||||
|
||||
// url_validation_pattern: Regular expression to validate/detect the format of an URL (URL attributes and Wiki formatting for Text attributes)
|
||||
// default: '(https?|ftp)\\://([a-zA-Z0-9+!*(),;?&=\\$_.-]+(\\:[a-zA-Z0-9+!*(),;?&=\\$_.-]+)?@)?([a-zA-Z0-9-.]{3,})(\\:[0-9]{2,5})?(/([a-zA-Z0-9%+\\$_-]\\.?)+)*/?(\\?[a-zA-Z+&\\$_.-][a-zA-Z0-9;:[\\]@&%=+/\\$_.-]*)?(#[a-zA-Z_.-][a-zA-Z0-9+\\$_.-]*)?'
|
||||
'url_validation_pattern' => '(https?|ftp)\\://([a-zA-Z0-9+!*(),;?&=\\$_.-]+(\\:[a-zA-Z0-9+!*(),;?&=\\$_.-]+)?@)?([a-zA-Z0-9-.]{3,})(\\:[0-9]{2,5})?(/([a-zA-Z0-9%+\\$_-]\\.?)+)*/?(\\?[a-zA-Z+&\\$_.-][a-zA-Z0-9;:[\\]@&%=+/\\$_.-]*)?(#[a-zA-Z_.-][a-zA-Z0-9+\\$_.-]*)?',
|
||||
);
|
||||
|
||||
/**
|
||||
*
|
||||
* Modules specific settings
|
||||
*
|
||||
*/
|
||||
$MyModuleSettings = array(
|
||||
'authent-cas' => array(
|
||||
'cas_debug' => false,
|
||||
'cas_host' => '',
|
||||
'cas_port' => '',
|
||||
'cas_context' => '',
|
||||
'cas_version' => '',
|
||||
),
|
||||
'authent-ldap' => array(
|
||||
'host' => 'localhost',
|
||||
'port' => 389,
|
||||
'default_user' => '',
|
||||
'default_pwd' => '',
|
||||
'base_dn' => 'dc=yourcompany,dc=com',
|
||||
'user_query' => '(&(uid=%1$s)(inetuserstatus=ACTIVE))',
|
||||
'options' => array(
|
||||
17 => 3,
|
||||
8 => 0,
|
||||
),
|
||||
'start_tls' => false,
|
||||
'debug' => false,
|
||||
),
|
||||
'itop-attachments' => array(
|
||||
'allowed_classes' => array(
|
||||
0 => 'Ticket',
|
||||
),
|
||||
'position' => 'relations',
|
||||
'preview_max_width' => 290,
|
||||
'icon_preview_max_size' => 500000,
|
||||
),
|
||||
'itop-backup' => array(
|
||||
'mysql_bindir' => '',
|
||||
'week_days' => 'monday, tuesday, wednesday, thursday, friday',
|
||||
'time' => '23:30',
|
||||
'retention_count' => 5,
|
||||
'enabled' => true,
|
||||
'itop_backup_incident' => '',
|
||||
),
|
||||
'molkobain-console-tooltips' => array(
|
||||
'decoration_class' => 'fas fa-question',
|
||||
'enabled' => true,
|
||||
),
|
||||
'itop-time-tracking' => array(
|
||||
'allowed_classes' => array(
|
||||
'UserRequest' =>
|
||||
array(
|
||||
'calendar-tab' => 'SELECT UserRequest WHERE status != "closed"',
|
||||
'stopwatch' => 'SELECT UserRequest WHERE status != "closed"',
|
||||
'report-tab' => 'SELECT UserRequest WHERE status IN ("resolved", "closed")',
|
||||
),
|
||||
'Incident' =>
|
||||
array(
|
||||
'calendar-tab' => 'SELECT Incident WHERE status != "closed"',
|
||||
'stopwatch' => 'SELECT Incident WHERE status != "closed"',
|
||||
'report-tab' => 'SELECT Incident WHERE status IN ("resolved", "closed")',
|
||||
),
|
||||
'CustomerContract' =>
|
||||
array(
|
||||
'calendar-page' => 'SELECT CustomerContract WHERE status = "production"',
|
||||
'report-tab' => 'SELECT CustomerContract',
|
||||
),
|
||||
),
|
||||
'colors' => array(
|
||||
'default_stopwatch' =>
|
||||
array(
|
||||
'text' => '#ffffff',
|
||||
'background' => '#a6a6a6',
|
||||
),
|
||||
'default_calendar' =>
|
||||
array(
|
||||
'text' => '#ffffff',
|
||||
'background' => '#FFCC80',
|
||||
),
|
||||
'classes' =>
|
||||
array(
|
||||
'UserRequest' =>
|
||||
array(
|
||||
'text' => '#ffffff',
|
||||
'background' => 'shadeof:blue',
|
||||
),
|
||||
'Incident' =>
|
||||
array(
|
||||
'text' => '#ffffff',
|
||||
'background' => 'shadeof:green',
|
||||
),
|
||||
'CustomerContract' =>
|
||||
array(
|
||||
'text' => '#ffffff',
|
||||
'background' => 'shadeof:grey',
|
||||
),
|
||||
),
|
||||
),
|
||||
'clone_events' => false,
|
||||
'default_event_duration' => '00:30:00',
|
||||
'day_start_time' => '06:00:00',
|
||||
'day_end_time' => '22:00:00',
|
||||
'excluded_days' => array(
|
||||
0 => 'Saturday',
|
||||
1 => 'Sunday',
|
||||
),
|
||||
'first_day' => 1,
|
||||
'business_hours' => array(
|
||||
'days_of_week' =>
|
||||
array(
|
||||
0 => '1',
|
||||
1 => '2',
|
||||
2 => '3',
|
||||
3 => '4',
|
||||
4 => '5',
|
||||
),
|
||||
'start' => '08:00:00',
|
||||
'end' => '18:00:00',
|
||||
),
|
||||
'minimum_event_duration_display' => '00:30:00',
|
||||
'stopwatch_clean_periodicity' => 1,
|
||||
'stopwatch_max_time' => 4,
|
||||
'delete_max_event_age' => 30,
|
||||
'default_report_query' => 'SELECT TimeSpent WHERE contact_id = :contact_id AND start_date >= :start_date AND end_date < :end_date',
|
||||
'manager_report_query' => 'SELECT TimeSpent WHERE start_date >= :start_date AND end_date < :end_date',
|
||||
'manager_report_silo' => 'SELECT Person',
|
||||
'weekly_report_time_spent_attribute' => '',
|
||||
'weekly_report_time_spent_default' => '30hrs',
|
||||
'report_charts_definition' => array(
|
||||
0 =>
|
||||
array(
|
||||
'group_by_attribute' => 'contact_id',
|
||||
'label' => 'TimeTracking:ReportActivityPerUser',
|
||||
),
|
||||
1 =>
|
||||
array(
|
||||
'group_by_attribute' => 'org_id',
|
||||
'label' => 'TimeTracking:ReportActivityPerCustomer',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
/**
|
||||
*
|
||||
* Data model modules to be loaded. Names are specified as relative paths
|
||||
*
|
||||
*/
|
||||
$MyModules = array(
|
||||
'addons' => array(
|
||||
'user rights' => 'addons/userrights/userrightsprofile.class.inc.php',
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
echo 'tutu';
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
function toto() {
|
||||
echo 'this is my function !';
|
||||
}
|
||||
|
||||
toto();
|
||||
@@ -0,0 +1,390 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Configuration file, generated by the iTop configuration wizard
|
||||
*
|
||||
* The file is used in MetaModel::LoadConfig() which does all the necessary initialization job
|
||||
*
|
||||
*/
|
||||
$MySettings = array(
|
||||
|
||||
// access_message: Message displayed to the users when there is any access restriction
|
||||
// default: 'iTop is temporarily frozen, please wait... (the admin team)'
|
||||
'access_message' => 'iTop is temporarily frozen, please wait... (the admin team)',
|
||||
|
||||
// access_mode: Access mode: ACCESS_READONLY = 0, ACCESS_ADMIN_WRITE = 2, ACCESS_FULL = 3
|
||||
// default: 3
|
||||
'access_mode' => 3,
|
||||
|
||||
// activity_panel.entry_form_opened_by_default: Whether or not the new entry form will be automatically opened when viewing an object.
|
||||
// default: false
|
||||
'activity_panel.entry_form_opened_by_default' => false,
|
||||
|
||||
// activity_panel.show_author_name_below_entries: Whether or not to show the author friendlyname next to the date on the last entry.
|
||||
// default: false
|
||||
'activity_panel.show_author_name_below_entries' => false,
|
||||
|
||||
'allowed_login_types' => 'form|external|basic',
|
||||
|
||||
// apc_cache.enabled: If set, the APC cache is allowed (the PHP extension must also be active)
|
||||
// default: true
|
||||
'apc_cache.enabled' => true,
|
||||
|
||||
// apc_cache.query_ttl: Time to live set in APC for the prepared queries (seconds - 0 means no timeout)
|
||||
// default: 3600
|
||||
'apc_cache.query_ttl' => 3600,
|
||||
|
||||
// app_root_url: Root URL used for navigating within the application, or from an email to the application (you can put $SERVER_NAME$ as a placeholder for the server's name)
|
||||
// default: ''
|
||||
'app_root_url' => 'http://localhost/itop-dev/',
|
||||
|
||||
// behind_reverse_proxy: If true, then proxies custom header (X-Forwarded-*) are taken into account. Use only if the webserver is not publicly accessible (reachable only by the reverse proxy)
|
||||
// default: false
|
||||
'behind_reverse_proxy' => false,
|
||||
|
||||
// cron_max_execution_time: Duration (seconds) of the page cron.php, must be shorter than php setting max_execution_time and shorter than the web server response timeout
|
||||
// default: 600
|
||||
'cron_max_execution_time' => 600,
|
||||
|
||||
// csv_file_default_charset: Character set used by default for downloading and uploading data as a CSV file. Warning: it is case sensitive (uppercase is preferable).
|
||||
// default: 'ISO-8859-1'
|
||||
'csv_file_default_charset' => 'ISO-8859-1',
|
||||
|
||||
'csv_import_charsets' => array (
|
||||
),
|
||||
|
||||
// csv_import_history_display: Display the history tab in the import wizard
|
||||
// default: false
|
||||
'csv_import_history_display' => false,
|
||||
|
||||
// date_and_time_format: Format for date and time display (per language)
|
||||
// default: array (
|
||||
// 'default' =>
|
||||
// array (
|
||||
// 'date' => 'Y-m-d',
|
||||
// 'time' => 'H:i:s',
|
||||
// 'date_time' => '$date $time',
|
||||
// ),
|
||||
// )
|
||||
'date_and_time_format' => array (
|
||||
'default' =>
|
||||
array (
|
||||
'date' => 'Y-m-d',
|
||||
'time' => 'H:i:s',
|
||||
'date_time' => '$date $time',
|
||||
),
|
||||
),
|
||||
|
||||
'db_host' => 'localhost',
|
||||
|
||||
'db_name' => 'itop_dev',
|
||||
|
||||
'db_pwd' => '',
|
||||
|
||||
'db_subname' => '',
|
||||
|
||||
'db_user' => 'root',
|
||||
|
||||
// deadline_format: The format used for displaying "deadline" attributes: any string with the following placeholders: $date$, $difference$
|
||||
// default: '$difference$'
|
||||
'deadline_format' => '$difference$',
|
||||
|
||||
'default_language' => 'EN US',
|
||||
|
||||
// email_asynchronous: If set, the emails are sent off line, which requires cron.php to be activated. Exception: some features like the email test utility will force the serialized mode
|
||||
// default: false
|
||||
'email_asynchronous' => false,
|
||||
|
||||
// email_default_sender_address: Default address provided in the email from header field.
|
||||
// default: ''
|
||||
'email_default_sender_address' => '',
|
||||
|
||||
// email_default_sender_label: Default label provided in the email from header field.
|
||||
// default: ''
|
||||
'email_default_sender_label' => '',
|
||||
|
||||
// email_transport: Mean to send emails: PHPMail (uses the function mail()) or SMTP (implements the client protocol)
|
||||
// default: 'PHPMail'
|
||||
'email_transport' => 'PHPMail',
|
||||
|
||||
// email_validation_pattern: Regular expression to validate/detect the format of an eMail address
|
||||
// default: '[a-zA-Z0-9._&\'-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z0-9-]{2,}'
|
||||
'email_validation_pattern' => '[a-zA-Z0-9._&\'-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z0-9-]{2,}',
|
||||
|
||||
'encryption_key' => '061c5b88c47ed64664618cf37b91a442b5550704aacecc5f58f96fc98087333b',
|
||||
|
||||
'encryption_library' => 'OpenSSL',
|
||||
|
||||
'ext_auth_variable' => '$_SERVER[\'REMOTE_USER\']',
|
||||
|
||||
'fast_reload_interval' => 60,
|
||||
|
||||
// graphviz_path: Path to the Graphviz "dot" executable for graphing objects lifecycle
|
||||
// default: '/usr/bin/dot'
|
||||
'graphviz_path' => 'C:\\Program Files (x86)\\Graphviz2.38\\bin\\dot.exe',
|
||||
|
||||
// high_cardinality_classes: List of classes with high cardinality (Force manual submit of search)
|
||||
// default: array (
|
||||
// )
|
||||
'high_cardinality_classes' => array (
|
||||
),
|
||||
|
||||
// inline_image_max_display_width: The maximum width (in pixels) when displaying images inside an HTML formatted attribute. Images will be displayed using this this maximum width.
|
||||
// default: '250'
|
||||
'inline_image_max_display_width' => '250',
|
||||
|
||||
// inline_image_max_storage_width: The maximum width (in pixels) when uploading images to be used inside an HTML formatted attribute. Images larger than the given size will be downsampled before storing them in the database.
|
||||
// default: '1600'
|
||||
'inline_image_max_storage_width' => '1600',
|
||||
|
||||
// link_set_attribute_qualifier: Link set from string: attribute qualifier (encloses both the attcode and the value)
|
||||
// default: '\''
|
||||
'link_set_attribute_qualifier' => '\'',
|
||||
|
||||
// link_set_attribute_separator: Link set from string: attribute separator
|
||||
// default: ';'
|
||||
'link_set_attribute_separator' => ';',
|
||||
|
||||
// link_set_item_separator: Link set from string: line separator
|
||||
// default: '|'
|
||||
'link_set_item_separator' => '|',
|
||||
|
||||
// link_set_value_separator: Link set from string: value separator (between the attcode and the value itself
|
||||
// default: ':'
|
||||
'link_set_value_separator' => ':',
|
||||
|
||||
'log_global' => true,
|
||||
|
||||
'log_issue' => true,
|
||||
|
||||
'log_kpi_duration' => 0,
|
||||
|
||||
'log_notification' => true,
|
||||
|
||||
'log_web_service' => true,
|
||||
|
||||
'max_display_limit' => 30,
|
||||
|
||||
// max_linkset_output: Maximum number of items shown when getting a list of related items in an email, using the form $this->some_list$. 0 means no limit.
|
||||
// default: 100
|
||||
'max_linkset_output' => 100,
|
||||
|
||||
// mentions.allowed_classes: Classes which can be mentioned through the autocomplete in the caselogs. Key of the array must be a single character that will trigger the autocomplete, value can be either a DM class or a valid OQL (eg. "@" => "Person", "?" => "SELECT FAQ WHERE status = 'published'")
|
||||
// default: array (
|
||||
// '@' => 'SELECT Person WHERE status = \'active\'',
|
||||
// )
|
||||
'mentions.allowed_classes' => array (
|
||||
'@' => 'SELECT Person WHERE status = \'active\'',
|
||||
),
|
||||
|
||||
'min_display_limit' => 20,
|
||||
|
||||
// online_help: Hyperlink to the online-help web page
|
||||
// default: 'http://www.combodo.com/itop-help'
|
||||
'online_help' => 'http://www.combodo.com/itop-help',
|
||||
|
||||
// optimize_requests_for_join_count: Optimize request joins to minimize the count (default is true, try to set it to false in case of performance issues)
|
||||
// default: true
|
||||
'optimize_requests_for_join_count' => true,
|
||||
|
||||
'password_hash_algo' => '2y',
|
||||
|
||||
// php_path: Path to the php executable in CLI mode
|
||||
// default: 'php'
|
||||
'php_path' => 'php',
|
||||
|
||||
// search_manual_submit: Force manual submit of search all requests
|
||||
// default: false
|
||||
'search_manual_submit' => false,
|
||||
|
||||
'secure_connection_required' => false,
|
||||
|
||||
// session_name: The name of the cookie used to store the PHP session id
|
||||
// default: 'iTop'
|
||||
'session_name' => 'iTop',
|
||||
|
||||
// shortcut_actions: Actions that are available as direct buttons next to the "Actions" menu
|
||||
// default: 'UI:Menu:Modify,UI:Menu:New'
|
||||
'shortcut_actions' => 'UI:Menu:Modify,UI:Menu:New',
|
||||
|
||||
// source_dir: Source directory for the datamodel files. (which gets compiled to env-production).
|
||||
// default: ''
|
||||
'source_dir' => 'datamodels/2.x/',
|
||||
|
||||
'standard_reload_interval' => 300,
|
||||
|
||||
// synchro_trace: Synchronization details: none, display, save (includes 'display')
|
||||
// default: 'none'
|
||||
'synchro_trace' => 'none',
|
||||
|
||||
// tag_set_item_separator: Tag set from string: tag label separator
|
||||
// default: '|'
|
||||
'tag_set_item_separator' => '|',
|
||||
|
||||
// timezone: Timezone (reference: http://php.net/manual/en/timezones.php). If empty, it will be left unchanged and MUST be explicitly configured in PHP
|
||||
// default: 'Europe/Paris'
|
||||
'timezone' => 'Europe/Paris',
|
||||
|
||||
// tracking_level_linked_set_default: Default tracking level if not explicitly set at the attribute level, for AttributeLinkedSet (defaults to NONE in case of a fresh install, LIST otherwise - this to preserve backward compatibility while upgrading from a version older than 2.0.3 - see TRAC #936)
|
||||
// default: 1
|
||||
'tracking_level_linked_set_default' => 0,
|
||||
|
||||
// url_validation_pattern: Regular expression to validate/detect the format of an URL (URL attributes and Wiki formatting for Text attributes)
|
||||
// default: '(https?|ftp)\\://([a-zA-Z0-9+!*(),;?&=\\$_.-]+(\\:[a-zA-Z0-9+!*(),;?&=\\$_.-]+)?@)?([a-zA-Z0-9-.]{3,})(\\:[0-9]{2,5})?(/([a-zA-Z0-9%+\\$_-]\\.?)+)*/?(\\?[a-zA-Z+&\\$_.-][a-zA-Z0-9;:[\\]@&%=+/\\$_.-]*)?(#[a-zA-Z_.-][a-zA-Z0-9+\\$_.-]*)?'
|
||||
'url_validation_pattern' => '(https?|ftp)\\://([a-zA-Z0-9+!*(),;?&=\\$_.-]+(\\:[a-zA-Z0-9+!*(),;?&=\\$_.-]+)?@)?([a-zA-Z0-9-.]{3,})(\\:[0-9]{2,5})?(/([a-zA-Z0-9%+\\$_-]\\.?)+)*/?(\\?[a-zA-Z+&\\$_.-][a-zA-Z0-9;:[\\]@&%=+/\\$_.-]*)?(#[a-zA-Z_.-][a-zA-Z0-9+\\$_.-]*)?',
|
||||
);
|
||||
|
||||
/**
|
||||
*
|
||||
* Modules specific settings
|
||||
*
|
||||
*/
|
||||
$MyModuleSettings = array(
|
||||
'authent-cas' => array (
|
||||
'cas_debug' => false,
|
||||
'cas_host' => '',
|
||||
'cas_port' => '',
|
||||
'cas_context' => '',
|
||||
'cas_version' => '',
|
||||
),
|
||||
'authent-ldap' => array (
|
||||
'host' => 'localhost',
|
||||
'port' => 389,
|
||||
'default_user' => '',
|
||||
'default_pwd' => '',
|
||||
'base_dn' => 'dc=yourcompany,dc=com',
|
||||
'user_query' => '(&(uid=%1$s)(inetuserstatus=ACTIVE))',
|
||||
'options' => array (
|
||||
17 => 3,
|
||||
8 => 0,
|
||||
),
|
||||
'start_tls' => false,
|
||||
'debug' => false,
|
||||
),
|
||||
'itop-attachments' => array (
|
||||
'allowed_classes' => array (
|
||||
0 => 'Ticket',
|
||||
),
|
||||
'position' => 'relations',
|
||||
'preview_max_width' => 290,
|
||||
'icon_preview_max_size' => 500000,
|
||||
),
|
||||
'itop-backup' => array (
|
||||
'mysql_bindir' => '',
|
||||
'week_days' => 'monday, tuesday, wednesday, thursday, friday',
|
||||
'time' => '23:30',
|
||||
'retention_count' => 5,
|
||||
'enabled' => true,
|
||||
'itop_backup_incident' => '',
|
||||
),
|
||||
'molkobain-console-tooltips' => array (
|
||||
'decoration_class' => 'fas fa-question',
|
||||
'enabled' => true,
|
||||
),
|
||||
'itop-time-tracking' => array (
|
||||
'allowed_classes' => array (
|
||||
'UserRequest' =>
|
||||
array (
|
||||
'calendar-tab' => 'SELECT UserRequest WHERE status != "closed"',
|
||||
'stopwatch' => 'SELECT UserRequest WHERE status != "closed"',
|
||||
'report-tab' => 'SELECT UserRequest WHERE status IN ("resolved", "closed")',
|
||||
),
|
||||
'Incident' =>
|
||||
array (
|
||||
'calendar-tab' => 'SELECT Incident WHERE status != "closed"',
|
||||
'stopwatch' => 'SELECT Incident WHERE status != "closed"',
|
||||
'report-tab' => 'SELECT Incident WHERE status IN ("resolved", "closed")',
|
||||
),
|
||||
'CustomerContract' =>
|
||||
array (
|
||||
'calendar-page' => 'SELECT CustomerContract WHERE status = "production"',
|
||||
'report-tab' => 'SELECT CustomerContract',
|
||||
),
|
||||
),
|
||||
'colors' => array (
|
||||
'default_stopwatch' =>
|
||||
array (
|
||||
'text' => '#ffffff',
|
||||
'background' => '#a6a6a6',
|
||||
),
|
||||
'default_calendar' =>
|
||||
array (
|
||||
'text' => '#ffffff',
|
||||
'background' => '#FFCC80',
|
||||
),
|
||||
'classes' =>
|
||||
array (
|
||||
'UserRequest' =>
|
||||
array (
|
||||
'text' => '#ffffff',
|
||||
'background' => 'shadeof:blue',
|
||||
),
|
||||
'Incident' =>
|
||||
array (
|
||||
'text' => '#ffffff',
|
||||
'background' => 'shadeof:green',
|
||||
),
|
||||
'CustomerContract' =>
|
||||
array (
|
||||
'text' => '#ffffff',
|
||||
'background' => 'shadeof:grey',
|
||||
),
|
||||
),
|
||||
),
|
||||
'clone_events' => false,
|
||||
'default_event_duration' => '00:30:00',
|
||||
'day_start_time' => '06:00:00',
|
||||
'day_end_time' => '22:00:00',
|
||||
'excluded_days' => array (
|
||||
0 => 'Saturday',
|
||||
1 => 'Sunday',
|
||||
),
|
||||
'first_day' => 1,
|
||||
'business_hours' => array (
|
||||
'days_of_week' =>
|
||||
array (
|
||||
0 => '1',
|
||||
1 => '2',
|
||||
2 => '3',
|
||||
3 => '4',
|
||||
4 => '5',
|
||||
),
|
||||
'start' => '08:00:00',
|
||||
'end' => '18:00:00',
|
||||
),
|
||||
'minimum_event_duration_display' => '00:30:00',
|
||||
'stopwatch_clean_periodicity' => 1,
|
||||
'stopwatch_max_time' => 4,
|
||||
'delete_max_event_age' => 30,
|
||||
'default_report_query' => 'SELECT TimeSpent WHERE contact_id = :contact_id AND start_date >= :start_date AND end_date < :end_date',
|
||||
'manager_report_query' => 'SELECT TimeSpent WHERE start_date >= :start_date AND end_date < :end_date',
|
||||
'manager_report_silo' => 'SELECT Person',
|
||||
'weekly_report_time_spent_attribute' => '',
|
||||
'weekly_report_time_spent_default' => '30hrs',
|
||||
'report_charts_definition' => array (
|
||||
0 =>
|
||||
array (
|
||||
'group_by_attribute' => 'contact_id',
|
||||
'label' => 'TimeTracking:ReportActivityPerUser',
|
||||
),
|
||||
1 =>
|
||||
array (
|
||||
'group_by_attribute' => 'org_id',
|
||||
'label' => 'TimeTracking:ReportActivityPerCustomer',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
/**
|
||||
*
|
||||
* Data model modules to be loaded. Names are specified as relative paths
|
||||
*
|
||||
*/
|
||||
$MyModules = array(
|
||||
'addons' => array (
|
||||
'user rights' => 'addons/userrights/userrightsprofile.class.inc.php',
|
||||
),
|
||||
);
|
||||
?>
|
||||
@@ -0,0 +1,394 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Configuration file, generated by the iTop configuration wizard
|
||||
*
|
||||
* The file is used in MetaModel::LoadConfig() which does all the necessary initialization job
|
||||
*
|
||||
*/
|
||||
$MySettings = array(
|
||||
|
||||
// access_message: Message displayed to the users when there is any access restriction
|
||||
// default: 'iTop is temporarily frozen, please wait... (the admin team)'
|
||||
'access_message' => 'iTop is temporarily frozen, please wait... (the admin team)',
|
||||
|
||||
// access_mode: Access mode: ACCESS_READONLY = 0, ACCESS_ADMIN_WRITE = 2, ACCESS_FULL = 3
|
||||
// default: 3
|
||||
'access_mode' => 3,
|
||||
|
||||
// activity_panel.entry_form_opened_by_default: Whether or not the new entry form will be automatically opened when viewing an object.
|
||||
// default: false
|
||||
'activity_panel.entry_form_opened_by_default' => false,
|
||||
|
||||
// activity_panel.show_author_name_below_entries: Whether or not to show the author friendlyname next to the date on the last entry.
|
||||
// default: false
|
||||
'activity_panel.show_author_name_below_entries' => false,
|
||||
|
||||
'allowed_login_types' => 'form|external|basic',
|
||||
|
||||
// apc_cache.enabled: If set, the APC cache is allowed (the PHP extension must also be active)
|
||||
// default: true
|
||||
'apc_cache.enabled' => true,
|
||||
|
||||
// apc_cache.query_ttl: Time to live set in APC for the prepared queries (seconds - 0 means no timeout)
|
||||
// default: 3600
|
||||
'apc_cache.query_ttl' => 3600,
|
||||
|
||||
// app_root_url: Root URL used for navigating within the application, or from an email to the application (you can put $SERVER_NAME$ as a placeholder for the server's name)
|
||||
// default: ''
|
||||
'app_root_url' => 'http://localhost/itop-dev/',
|
||||
|
||||
// behind_reverse_proxy: If true, then proxies custom header (X-Forwarded-*) are taken into account. Use only if the webserver is not publicly accessible (reachable only by the reverse proxy)
|
||||
// default: false
|
||||
'behind_reverse_proxy' => false,
|
||||
|
||||
// cron_max_execution_time: Duration (seconds) of the page cron.php, must be shorter than php setting max_execution_time and shorter than the web server response timeout
|
||||
// default: 600
|
||||
'cron_max_execution_time' => 600,
|
||||
|
||||
// csv_file_default_charset: Character set used by default for downloading and uploading data as a CSV file. Warning: it is case sensitive (uppercase is preferable).
|
||||
// default: 'ISO-8859-1'
|
||||
'csv_file_default_charset' => 'ISO-8859-1',
|
||||
|
||||
'csv_import_charsets' => array(),
|
||||
|
||||
// csv_import_history_display: Display the history tab in the import wizard
|
||||
// default: false
|
||||
'csv_import_history_display' => false,
|
||||
|
||||
// date_and_time_format: Format for date and time display (per language)
|
||||
// default: array (
|
||||
// 'default' =>
|
||||
// array (
|
||||
// 'date' => 'Y-m-d',
|
||||
// 'time' => 'H:i:s',
|
||||
// 'date_time' => '$date $time',
|
||||
// ),
|
||||
// )
|
||||
'date_and_time_format' => array(
|
||||
'default' =>
|
||||
array(
|
||||
'date' => 'Y-m-d',
|
||||
'time' => 'H:i:s',
|
||||
'date_time' => '$date $time',
|
||||
),
|
||||
),
|
||||
|
||||
'db_host' => 'localhost',
|
||||
|
||||
'db_name' => 'itop_dev',
|
||||
|
||||
'db_pwd' => '',
|
||||
|
||||
'db_subname' => '',
|
||||
|
||||
'db_user' => 'root',
|
||||
|
||||
// deadline_format: The format used for displaying "deadline" attributes: any string with the following placeholders: $date$, $difference$
|
||||
// default: '$difference$'
|
||||
'deadline_format' => '$difference$',
|
||||
|
||||
'default_language' => 'EN US',
|
||||
|
||||
// email_asynchronous: If set, the emails are sent off line, which requires cron.php to be activated. Exception: some features like the email test utility will force the serialized mode
|
||||
// default: false
|
||||
'email_asynchronous' => false,
|
||||
|
||||
// email_default_sender_address: Default address provided in the email from header field.
|
||||
// default: ''
|
||||
'email_default_sender_address' => '',
|
||||
|
||||
// email_default_sender_label: Default label provided in the email from header field.
|
||||
// default: ''
|
||||
'email_default_sender_label' => '',
|
||||
|
||||
// email_transport: Mean to send emails: PHPMail (uses the function mail()) or SMTP (implements the client protocol)
|
||||
// default: 'PHPMail'
|
||||
'email_transport' => 'PHPMail',
|
||||
|
||||
// email_validation_pattern: Regular expression to validate/detect the format of an eMail address
|
||||
// default: '[a-zA-Z0-9._&\'-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z0-9-]{2,}'
|
||||
'email_validation_pattern' => '[a-zA-Z0-9._&\'-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z0-9-]{2,}',
|
||||
|
||||
'encryption_key' => '061c5b88c47ed64664618cf37b91a442b5550704aacecc5f58f96fc98087333b',
|
||||
|
||||
'encryption_library' => 'OpenSSL',
|
||||
|
||||
'ext_auth_variable' => '$_SERVER[\'REMOTE_USER\']',
|
||||
|
||||
'fast_reload_interval' => 60,
|
||||
|
||||
// graphviz_path: Path to the Graphviz "dot" executable for graphing objects lifecycle
|
||||
// default: '/usr/bin/dot'
|
||||
'graphviz_path' => 'C:\\Program Files (x86)\\Graphviz2.38\\bin\\dot.exe',
|
||||
|
||||
// high_cardinality_classes: List of classes with high cardinality (Force manual submit of search)
|
||||
// default: array (
|
||||
// )
|
||||
'high_cardinality_classes' => array(),
|
||||
|
||||
// inline_image_max_display_width: The maximum width (in pixels) when displaying images inside an HTML formatted attribute. Images will be displayed using this this maximum width.
|
||||
// default: '250'
|
||||
'inline_image_max_display_width' => '250',
|
||||
|
||||
// inline_image_max_storage_width: The maximum width (in pixels) when uploading images to be used inside an HTML formatted attribute. Images larger than the given size will be downsampled before storing them in the database.
|
||||
// default: '1600'
|
||||
'inline_image_max_storage_width' => '1600',
|
||||
|
||||
// link_set_attribute_qualifier: Link set from string: attribute qualifier (encloses both the attcode and the value)
|
||||
// default: '\''
|
||||
'link_set_attribute_qualifier' => '\'',
|
||||
|
||||
// link_set_attribute_separator: Link set from string: attribute separator
|
||||
// default: ';'
|
||||
'link_set_attribute_separator' => ';',
|
||||
|
||||
// link_set_item_separator: Link set from string: line separator
|
||||
// default: '|'
|
||||
'link_set_item_separator' => '|',
|
||||
|
||||
// link_set_value_separator: Link set from string: value separator (between the attcode and the value itself
|
||||
// default: ':'
|
||||
'link_set_value_separator' => ':',
|
||||
|
||||
'log_global' => true,
|
||||
|
||||
'log_issue' => true,
|
||||
|
||||
'log_kpi_duration' => 0,
|
||||
|
||||
'log_level_min' => array(
|
||||
'' => LogAPI::LEVEL_WARNING,
|
||||
'InlineImage' => LogAPI::LEVEL_TRACE,
|
||||
'UserRequest' => LogAPI::LEVEL_TRACE,
|
||||
),
|
||||
|
||||
'log_notification' => true,
|
||||
|
||||
'log_web_service' => true,
|
||||
|
||||
'max_display_limit' => 30,
|
||||
|
||||
// max_linkset_output: Maximum number of items shown when getting a list of related items in an email, using the form $this->some_list$. 0 means no limit.
|
||||
// default: 100
|
||||
'max_linkset_output' => 100,
|
||||
|
||||
// mentions.allowed_classes: Classes which can be mentioned through the autocomplete in the caselogs. Key of the array must be a single character that will trigger the autocomplete, value can be either a DM class or a valid OQL (eg. "@" => "Person", "?" => "SELECT FAQ WHERE status = 'published'")
|
||||
// default: array (
|
||||
// '@' => 'SELECT Person WHERE status = \'active\'',
|
||||
// )
|
||||
'mentions.allowed_classes' => array(
|
||||
'@' => 'SELECT Person WHERE status = \'active\'',
|
||||
),
|
||||
|
||||
'min_display_limit' => 20,
|
||||
|
||||
// online_help: Hyperlink to the online-help web page
|
||||
// default: 'http://www.combodo.com/itop-help'
|
||||
'online_help' => 'http://www.combodo.com/itop-help',
|
||||
|
||||
// optimize_requests_for_join_count: Optimize request joins to minimize the count (default is true, try to set it to false in case of performance issues)
|
||||
// default: true
|
||||
'optimize_requests_for_join_count' => true,
|
||||
|
||||
'password_hash_algo' => '2y',
|
||||
|
||||
// php_path: Path to the php executable in CLI mode
|
||||
// default: 'php'
|
||||
'php_path' => 'php',
|
||||
|
||||
// search_manual_submit: Force manual submit of search all requests
|
||||
// default: false
|
||||
'search_manual_submit' => false,
|
||||
|
||||
'secure_connection_required' => false,
|
||||
|
||||
// session_name: The name of the cookie used to store the PHP session id
|
||||
// default: 'iTop'
|
||||
'session_name' => 'iTop',
|
||||
|
||||
// shortcut_actions: Actions that are available as direct buttons next to the "Actions" menu
|
||||
// default: 'UI:Menu:Modify,UI:Menu:New'
|
||||
'shortcut_actions' => 'UI:Menu:Modify,UI:Menu:New',
|
||||
|
||||
// source_dir: Source directory for the datamodel files. (which gets compiled to env-production).
|
||||
// default: ''
|
||||
'source_dir' => 'datamodels/2.x/',
|
||||
|
||||
'standard_reload_interval' => 300,
|
||||
|
||||
// synchro_trace: Synchronization details: none, display, save (includes 'display')
|
||||
// default: 'none'
|
||||
'synchro_trace' => 'none',
|
||||
|
||||
// tag_set_item_separator: Tag set from string: tag label separator
|
||||
// default: '|'
|
||||
'tag_set_item_separator' => '|',
|
||||
|
||||
// timezone: Timezone (reference: http://php.net/manual/en/timezones.php). If empty, it will be left unchanged and MUST be explicitly configured in PHP
|
||||
// default: 'Europe/Paris'
|
||||
'timezone' => 'Europe/Paris',
|
||||
|
||||
// tracking_level_linked_set_default: Default tracking level if not explicitly set at the attribute level, for AttributeLinkedSet (defaults to NONE in case of a fresh install, LIST otherwise - this to preserve backward compatibility while upgrading from a version older than 2.0.3 - see TRAC #936)
|
||||
// default: 1
|
||||
'tracking_level_linked_set_default' => 0,
|
||||
|
||||
// url_validation_pattern: Regular expression to validate/detect the format of an URL (URL attributes and Wiki formatting for Text attributes)
|
||||
// default: '(https?|ftp)\\://([a-zA-Z0-9+!*(),;?&=\\$_.-]+(\\:[a-zA-Z0-9+!*(),;?&=\\$_.-]+)?@)?([a-zA-Z0-9-.]{3,})(\\:[0-9]{2,5})?(/([a-zA-Z0-9%+\\$_-]\\.?)+)*/?(\\?[a-zA-Z+&\\$_.-][a-zA-Z0-9;:[\\]@&%=+/\\$_.-]*)?(#[a-zA-Z_.-][a-zA-Z0-9+\\$_.-]*)?'
|
||||
'url_validation_pattern' => '(https?|ftp)\\://([a-zA-Z0-9+!*(),;?&=\\$_.-]+(\\:[a-zA-Z0-9+!*(),;?&=\\$_.-]+)?@)?([a-zA-Z0-9-.]{3,})(\\:[0-9]{2,5})?(/([a-zA-Z0-9%+\\$_-]\\.?)+)*/?(\\?[a-zA-Z+&\\$_.-][a-zA-Z0-9;:[\\]@&%=+/\\$_.-]*)?(#[a-zA-Z_.-][a-zA-Z0-9+\\$_.-]*)?',
|
||||
);
|
||||
|
||||
/**
|
||||
*
|
||||
* Modules specific settings
|
||||
*
|
||||
*/
|
||||
$MyModuleSettings = array(
|
||||
'authent-cas' => array(
|
||||
'cas_debug' => false,
|
||||
'cas_host' => '',
|
||||
'cas_port' => '',
|
||||
'cas_context' => '',
|
||||
'cas_version' => '',
|
||||
),
|
||||
'authent-ldap' => array(
|
||||
'host' => 'localhost',
|
||||
'port' => 389,
|
||||
'default_user' => '',
|
||||
'default_pwd' => '',
|
||||
'base_dn' => 'dc=yourcompany,dc=com',
|
||||
'user_query' => '(&(uid=%1$s)(inetuserstatus=ACTIVE))',
|
||||
'options' => array(
|
||||
17 => 3,
|
||||
8 => 0,
|
||||
),
|
||||
'start_tls' => false,
|
||||
'debug' => false,
|
||||
),
|
||||
'itop-attachments' => array(
|
||||
'allowed_classes' => array(
|
||||
0 => 'Ticket',
|
||||
),
|
||||
'position' => 'relations',
|
||||
'preview_max_width' => 290,
|
||||
'icon_preview_max_size' => 500000,
|
||||
),
|
||||
'itop-backup' => array(
|
||||
'mysql_bindir' => '',
|
||||
'week_days' => 'monday, tuesday, wednesday, thursday, friday',
|
||||
'time' => '23:30',
|
||||
'retention_count' => 5,
|
||||
'enabled' => true,
|
||||
'itop_backup_incident' => '',
|
||||
),
|
||||
'molkobain-console-tooltips' => array(
|
||||
'decoration_class' => 'fas fa-question',
|
||||
'enabled' => true,
|
||||
),
|
||||
'itop-time-tracking' => array(
|
||||
'allowed_classes' => array(
|
||||
'UserRequest' =>
|
||||
array(
|
||||
'calendar-tab' => 'SELECT UserRequest WHERE status != "closed"',
|
||||
'stopwatch' => 'SELECT UserRequest WHERE status != "closed"',
|
||||
'report-tab' => 'SELECT UserRequest WHERE status IN ("resolved", "closed")',
|
||||
),
|
||||
'Incident' =>
|
||||
array(
|
||||
'calendar-tab' => 'SELECT Incident WHERE status != "closed"',
|
||||
'stopwatch' => 'SELECT Incident WHERE status != "closed"',
|
||||
'report-tab' => 'SELECT Incident WHERE status IN ("resolved", "closed")',
|
||||
),
|
||||
'CustomerContract' =>
|
||||
array(
|
||||
'calendar-page' => 'SELECT CustomerContract WHERE status = "production"',
|
||||
'report-tab' => 'SELECT CustomerContract',
|
||||
),
|
||||
),
|
||||
'colors' => array(
|
||||
'default_stopwatch' =>
|
||||
array(
|
||||
'text' => '#ffffff',
|
||||
'background' => '#a6a6a6',
|
||||
),
|
||||
'default_calendar' =>
|
||||
array(
|
||||
'text' => '#ffffff',
|
||||
'background' => '#FFCC80',
|
||||
),
|
||||
'classes' =>
|
||||
array(
|
||||
'UserRequest' =>
|
||||
array(
|
||||
'text' => '#ffffff',
|
||||
'background' => 'shadeof:blue',
|
||||
),
|
||||
'Incident' =>
|
||||
array(
|
||||
'text' => '#ffffff',
|
||||
'background' => 'shadeof:green',
|
||||
),
|
||||
'CustomerContract' =>
|
||||
array(
|
||||
'text' => '#ffffff',
|
||||
'background' => 'shadeof:grey',
|
||||
),
|
||||
),
|
||||
),
|
||||
'clone_events' => false,
|
||||
'default_event_duration' => '00:30:00',
|
||||
'day_start_time' => '06:00:00',
|
||||
'day_end_time' => '22:00:00',
|
||||
'excluded_days' => array(
|
||||
0 => 'Saturday',
|
||||
1 => 'Sunday',
|
||||
),
|
||||
'first_day' => 1,
|
||||
'business_hours' => array(
|
||||
'days_of_week' =>
|
||||
array(
|
||||
0 => '1',
|
||||
1 => '2',
|
||||
2 => '3',
|
||||
3 => '4',
|
||||
4 => '5',
|
||||
),
|
||||
'start' => '08:00:00',
|
||||
'end' => '18:00:00',
|
||||
),
|
||||
'minimum_event_duration_display' => '00:30:00',
|
||||
'stopwatch_clean_periodicity' => 1,
|
||||
'stopwatch_max_time' => 4,
|
||||
'delete_max_event_age' => 30,
|
||||
'default_report_query' => 'SELECT TimeSpent WHERE contact_id = :contact_id AND start_date >= :start_date AND end_date < :end_date',
|
||||
'manager_report_query' => 'SELECT TimeSpent WHERE start_date >= :start_date AND end_date < :end_date',
|
||||
'manager_report_silo' => 'SELECT Person',
|
||||
'weekly_report_time_spent_attribute' => '',
|
||||
'weekly_report_time_spent_default' => '30hrs',
|
||||
'report_charts_definition' => array(
|
||||
0 =>
|
||||
array(
|
||||
'group_by_attribute' => 'contact_id',
|
||||
'label' => 'TimeTracking:ReportActivityPerUser',
|
||||
),
|
||||
1 =>
|
||||
array(
|
||||
'group_by_attribute' => 'org_id',
|
||||
'label' => 'TimeTracking:ReportActivityPerCustomer',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
/**
|
||||
*
|
||||
* Data model modules to be loaded. Names are specified as relative paths
|
||||
*
|
||||
*/
|
||||
$MyModules = array(
|
||||
'addons' => array(
|
||||
'user rights' => 'addons/userrights/userrightsprofile.class.inc.php',
|
||||
),
|
||||
);
|
||||
?>
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace ConfigValidator;
|
||||
|
||||
use Combodo\iTop\Config\Validator\iTopConfigAstValidator;
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
use Exception;
|
||||
|
||||
class iTopConfigAstValidatorTest extends ItopTestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
require_once APPROOT.'env-production/itop-config/src/Validator/iTopConfigAstValidator.php';
|
||||
require_once APPROOT.'env-production/itop-config/src/Validator/ConfigNodesVisitor.php';
|
||||
}
|
||||
|
||||
public function testValidateFileValid()
|
||||
{
|
||||
try {
|
||||
$this->CallValidatorOnFile('config-itop_VALID.php');
|
||||
}
|
||||
catch (Exception $e) {
|
||||
$this->fail('An exception was thrown by the validation method on a valid file: '.$e->getMessage());
|
||||
}
|
||||
|
||||
$this->assertTrue(true, 'The file is valid and interpreted as such');
|
||||
}
|
||||
|
||||
public function testValidateFileValidLogLevelMinConst()
|
||||
{
|
||||
$this->markTestSkipped(' disabled test, is failing for now with error "Invalid configuration: LEVEL_WARNING of type Identifier is forbidden in line 152"');
|
||||
try {
|
||||
$this->CallValidatorOnFile('config-itop_VALID_log-level-min_const.php');
|
||||
}
|
||||
catch (Exception $e) {
|
||||
$this->fail('An exception was thrown by the validation method on a valid file: '.$e->getMessage());
|
||||
}
|
||||
|
||||
$this->assertTrue(true, 'The file is valid and interpreted as such');
|
||||
}
|
||||
|
||||
public function testValidateFileWithCode()
|
||||
{
|
||||
$this->expectExceptionMessage('type Stmt_Function is forbidden');
|
||||
$this->CallValidatorOnFile('config-itop_KO_function.php');
|
||||
}
|
||||
|
||||
public function testValidateFileValidWithCodeAtTheEnd()
|
||||
{
|
||||
$this->expectExceptionMessage('Stmt_Echo is forbidden');
|
||||
$this->CallValidatorOnFile('config-itop_KO_config_plus_code.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function CallValidatorOnFile(string $sConfigFilePath)
|
||||
{
|
||||
$sContents = file_get_contents(__DIR__.DIRECTORY_SEPARATOR.$sConfigFilePath);
|
||||
|
||||
$oiTopConfigValidator = new iTopConfigAstValidator();
|
||||
$oiTopConfigValidator->Validate($sContents);
|
||||
}
|
||||
}
|
||||
124
tests/php-unit-tests/unitary-tests/core/DBObjectTest.php
Normal file
124
tests/php-unit-tests/unitary-tests/core/DBObjectTest.php
Normal file
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
// Copyright (c) 2010-2017 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/>
|
||||
//
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Eric
|
||||
* Date: 02/10/2017
|
||||
* Time: 13:58
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Core;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use DBObject;
|
||||
use MetaModel;
|
||||
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class DBObjectTest extends ItopDataTestCase
|
||||
{
|
||||
const CREATE_TEST_ORG = true;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
require_once(APPROOT.'core/coreexception.class.inc.php');
|
||||
require_once(APPROOT.'core/dbobject.class.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test default page name
|
||||
*/
|
||||
public function testGetUIPage()
|
||||
{
|
||||
static::assertEquals('UI.php', DBObject::GetUIPage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test PKey validation
|
||||
* @dataProvider keyProviderOK
|
||||
* @param $key
|
||||
* @param $res
|
||||
*/
|
||||
public function testIsValidPKeyOK($key, $res)
|
||||
{
|
||||
static::assertEquals(DBObject::IsValidPKey($key), $res);
|
||||
}
|
||||
|
||||
public function keyProviderOK()
|
||||
{
|
||||
return array(
|
||||
array(1, true),
|
||||
array('255', true),
|
||||
array(-24576, true),
|
||||
array(0123, true),
|
||||
array(0xCAFE, true),
|
||||
array(PHP_INT_MIN, true),
|
||||
array(PHP_INT_MAX, true),
|
||||
array('test', false),
|
||||
array('', false),
|
||||
array('a255', false),
|
||||
array('PHP_INT_MIN', false));
|
||||
}
|
||||
|
||||
public function testGetOriginal()
|
||||
{
|
||||
$oObject = $this->CreateUserRequest(190664);
|
||||
|
||||
static::assertNull($oObject->GetOriginal('sla_tto_passed'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function testListPreviousValuesForUpdatedAttributes()
|
||||
{
|
||||
$oOrg = $this->CreateOrganization('testListPreviousValuesForUpdatedAttributes');
|
||||
|
||||
$this->assertCount(0, $oOrg->ListChanges());
|
||||
$oOrg->Set('code', strtoupper('testListPreviousValuesForUpdatedAttributes'));
|
||||
$this->assertCount(1, $oOrg->ListChanges());
|
||||
$oOrg->DBUpdate();
|
||||
$this->assertCount(0, $oOrg->ListChanges());
|
||||
$this->assertCount(1, $oOrg->ListPreviousValuesForUpdatedAttributes());
|
||||
|
||||
$oOrg->DBUpdate();
|
||||
|
||||
$this->assertCount(0, $oOrg->ListChanges());
|
||||
$this->assertCount(1, $oOrg->ListPreviousValuesForUpdatedAttributes());
|
||||
|
||||
$oOrg->DBDelete();
|
||||
|
||||
$oOrg = MetaModel::NewObject('Organization');
|
||||
$oOrg->Set('name', 'testListPreviousValuesForUpdatedAttributes');
|
||||
$oOrg->DBInsert();
|
||||
$oOrg->Set('code', strtoupper('testListPreviousValuesForUpdatedAttributes'));
|
||||
$oOrg->DBUpdate();
|
||||
$oOrg->DBUpdate();
|
||||
$this->markTestIncomplete('This test has not been implemented yet. wait for N°4967 fix');
|
||||
$this->debug("ERROR: N°4967 - 'Previous Values For Updated Attributes' not updated if DBUpdate is called without modifying the object");
|
||||
//$this->assertCount(0, $oOrg->ListPreviousValuesForUpdatedAttributes());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Eric
|
||||
* Date: 17/09/2018
|
||||
* Time: 12:31
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Core;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use DBObjectSet;
|
||||
use DBSearch;
|
||||
|
||||
/**
|
||||
* Tests of the DBSearch class.
|
||||
* <ul>
|
||||
* <li>MakeGroupByQuery</li>
|
||||
* </ul>
|
||||
*
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class DBSearchCommitTest extends ItopDataTestCase
|
||||
{
|
||||
// Need database COMMIT in order to create the FULLTEXT INDEX of MySQL
|
||||
const USE_TRANSACTION = false;
|
||||
|
||||
/**
|
||||
* @throws \CoreException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function testAttributeTagSet()
|
||||
{
|
||||
// Create a tag
|
||||
$this->CreateTagData(TAG_CLASS, TAG_ATTCODE, 'tag1', 'UNIT First');
|
||||
$this->CreateTagData(TAG_CLASS, TAG_ATTCODE, 'tag2', 'UNIT Second');
|
||||
//Use it
|
||||
$oObjWithTagSet = $this->CreateObjectWithTagSet();
|
||||
$oObjWithTagSet->Set(TAG_ATTCODE, 'tag1');
|
||||
$oObjWithTagSet->DBWrite();
|
||||
|
||||
$oSearch = DBSearch::FromOQL("SELECT ".TAG_CLASS);
|
||||
$oSearch->AddCondition(TAG_ATTCODE, 'tag1', 'MATCHES');
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
static::assertEquals(1, $oSet->Count());
|
||||
|
||||
|
||||
$oObjWithTagSet->Set(TAG_ATTCODE, 'tag1 tag2');
|
||||
$oObjWithTagSet->DBWrite();
|
||||
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
static::assertEquals(1, $oSet->Count());
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function testAttributeTagSet2()
|
||||
{
|
||||
// Create a tag
|
||||
$this->CreateTagData(TAG_CLASS, TAG_ATTCODE, 'tag1', 'UNIT First');
|
||||
$this->CreateTagData(TAG_CLASS, TAG_ATTCODE, 'tag2', 'UNIT Second');
|
||||
//Use it
|
||||
$oObjWithTagSet = $this->CreateObjectWithTagSet();
|
||||
$oObjWithTagSet->Set(TAG_ATTCODE, 'tag1');
|
||||
$oObjWithTagSet->DBWrite();
|
||||
|
||||
$oSearch = DBSearch::FromOQL("SELECT ".TAG_CLASS);
|
||||
$oSearch->AddCondition(TAG_ATTCODE, 'tag1');
|
||||
$oSet = new \DBObjectSet($oSearch);
|
||||
static::assertEquals(1, $oSet->Count());
|
||||
|
||||
|
||||
$oObjWithTagSet->Set(TAG_ATTCODE, 'tag1 tag2');
|
||||
$oObjWithTagSet->DBWrite();
|
||||
|
||||
$oSet = new \DBObjectSet($oSearch);
|
||||
static::assertEquals(0, $oSet->Count());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,457 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Core;
|
||||
|
||||
use CMDBSource;
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
use DBSearch;
|
||||
|
||||
/**
|
||||
* Class DBSearchIntersectTest
|
||||
*
|
||||
* @package Combodo\iTop\Test\UnitTest\Core
|
||||
*
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class DBSearchIntersectTest extends ItopTestCase
|
||||
{
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
require_once(APPROOT.'application/startup.inc.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider FilterProvider
|
||||
*
|
||||
* @param $sLeftSelect
|
||||
* @param $sRightSelect
|
||||
* @param $sClassAlias
|
||||
* @param $sResult
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function testFilter($sLeftSelect, $sRightSelect, $sClassAlias, $sResult)
|
||||
{
|
||||
$oLeftSearch = DBSearch::FromOQL($sLeftSelect);
|
||||
$oRightSearch = DBSearch::FromOQL($sRightSelect);
|
||||
|
||||
$oResultSearch = $oLeftSearch->Filter($sClassAlias, $oRightSearch);
|
||||
CMDBSource::TestQuery($oResultSearch->MakeSelectQuery());
|
||||
$this->assertEquals($sResult, $oResultSearch->ToOQL());
|
||||
}
|
||||
|
||||
public function FilterProvider()
|
||||
{
|
||||
$aTests = array();
|
||||
|
||||
$aTests['Union filtered by parent class'] = array(
|
||||
'left' => "SELECT ApplicationSolution UNION SELECT BusinessProcess",
|
||||
'right' => "SELECT FunctionalCI WHERE org_id = 3",
|
||||
'alias' => "ApplicationSolution",
|
||||
'result' => "SELECT `ApplicationSolution` FROM ApplicationSolution AS `ApplicationSolution` WHERE (`ApplicationSolution`.`org_id` = 3) UNION SELECT `BusinessProcess` FROM BusinessProcess AS `BusinessProcess` WHERE (`BusinessProcess`.`org_id` = 3)");
|
||||
|
||||
// Bug to fix
|
||||
// $aTests['Test union #2902'] = array(
|
||||
// 'left' => "SELECT `L-1` FROM ServiceFamily AS `L-1` WHERE 1",
|
||||
// 'right' => "SELECT `sf` FROM ServiceFamily AS `sf` JOIN Service AS `s` ON `s`.servicefamily_id = `sf`.id JOIN lnkCustomerContractToService AS `l1` ON `l1`.service_id = `s`.id JOIN CustomerContract AS `cc` ON `l1`.customercontract_id = `cc`.id WHERE (`cc`.`org_id` = 3) UNION SELECT `sf` FROM ServiceFamily AS `sf` JOIN Service AS `s` ON `s`.servicefamily_id = `sf`.id JOIN lnkCustomerContractToService AS `l1` ON `l1`.service_id = `s`.id JOIN CustomerContract AS `cc` ON `l1`.customercontract_id = `cc`.id JOIN Organization AS `child` ON `cc`.org_id = `child`.id JOIN Organization AS `root` ON `child`.parent_id BELOW `root`.id WHERE (`root`.`id` = 3)",
|
||||
// 'alias' => "L-1",
|
||||
// 'result' => "SELECT `L-1` FROM ServiceFamily AS `L-1` JOIN Service AS `s` ON `s`.servicefamily_id = `L-1`.id JOIN lnkCustomerContractToService AS `l1` ON `l1`.service_id = `s`.id JOIN CustomerContract AS `cc` ON `l1`.customercontract_id = `cc`.id WHERE (`cc`.`org_id` = 3) UNION SELECT `L-1` FROM ServiceFamily AS `L-1` JOIN Service AS `s` ON `s`.servicefamily_id = `L-1`.id JOIN lnkCustomerContractToService AS `l1` ON `l1`.service_id = `s`.id JOIN CustomerContract AS `cc` ON `l1`.customercontract_id = `cc`.id JOIN Organization AS `child` ON `cc`.org_id = `child`.id JOIN Organization AS `root` ON `child`.parent_id BELOW `root`.id WHERE (`root`.`id` = 3)");
|
||||
|
||||
$aTests['Multiple selected classes inverted'] = array(
|
||||
'left' => "SELECT `L`, `P` FROM Person AS `P` JOIN Location AS `L` ON `P`.location_id = `L`.id WHERE 1",
|
||||
'right' => "SELECT Person WHERE org_id = 3",
|
||||
'alias' => "P",
|
||||
'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",
|
||||
'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)");
|
||||
|
||||
$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)",
|
||||
'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))");
|
||||
|
||||
$aTests['Same class'] = array(
|
||||
'left' => "SELECT Contact WHERE name = 'Christie'",
|
||||
'right' => "SELECT Contact WHERE org_id = 3",
|
||||
'alias' => "Contact",
|
||||
'result' => "SELECT `Contact` FROM Contact AS `Contact` WHERE ((`Contact`.`name` = 'Christie') AND (`Contact`.`org_id` = 3))");
|
||||
|
||||
$aTests['Different Alias'] = array(
|
||||
'left' => "SELECT Contact AS C WHERE C.name = 'Christie'",
|
||||
'right' => "SELECT Contact AS CC WHERE CC.org_id = 3",
|
||||
'alias' => "C",
|
||||
'result' => "SELECT `C` FROM Contact AS `C` WHERE ((`C`.`name` = 'Christie') AND (`C`.`org_id` = 3))");
|
||||
|
||||
$aTests['Multiple selected classes'] = array(
|
||||
'left' => "SELECT `L`, `P` FROM Location AS `L` JOIN Person AS `P` ON `P`.location_id = `L`.id WHERE 1",
|
||||
'right' => "SELECT Location WHERE org_id = 3",
|
||||
'alias' => "L",
|
||||
'result' => "SELECT `L`, `P` FROM Location AS `L` JOIN Person AS `P` ON `P`.location_id = `L`.id WHERE (`L`.`org_id` = 3)");
|
||||
|
||||
$aTests['Joined classes'] = array(
|
||||
'left' => "SELECT `L` FROM Location AS `L` JOIN Person AS `P` ON `P`.location_id = `L`.id WHERE 1",
|
||||
'right' => "SELECT Person WHERE org_id = 3",
|
||||
'alias' => "P",
|
||||
'result' => "SELECT `L` FROM Location AS `L` JOIN Person AS `P` ON `P`.location_id = `L`.id WHERE (`P`.`org_id` = 3)");
|
||||
|
||||
$aTests['Joined filter'] = array(
|
||||
'left' => "SELECT `P` FROM Person AS `P` WHERE 1",
|
||||
'right' => "SELECT `P` FROM Person AS `P` JOIN Location AS `L` ON `P`.location_id = `L`.id WHERE `L`.org_id = 3",
|
||||
'alias' => "P",
|
||||
'result' => "SELECT `P` FROM Person AS `P` JOIN Location AS `L` ON `P`.location_id = `L`.id WHERE (`L`.`org_id` = 3)");
|
||||
|
||||
$aTests['Joined filter on joined classes'] = array(
|
||||
'left' => "SELECT `L` FROM Location AS `L` JOIN Person AS `P` ON `P`.location_id = `L`.id WHERE 1",
|
||||
'right' => "SELECT Person FROM Person AS Person JOIN Location ON Person.location_id = Location.id WHERE Location.org_id = 3",
|
||||
'alias' => "P",
|
||||
'result' => "SELECT `L` FROM Location AS `L` JOIN Person AS `P` ON `P`.location_id = `L`.id JOIN Location AS `Location` ON `P`.location_id = `Location`.id WHERE (`Location`.`org_id` = 3)");
|
||||
|
||||
$aTests['Alias collision'] = array(
|
||||
'left' => "SELECT `L` FROM Location AS `L` JOIN Person AS `P` ON `P`.location_id = `L`.id WHERE 1",
|
||||
'right' => "SELECT Person FROM Person AS Person JOIN Location AS `L` ON Person.location_id = `L`.id WHERE `L`.org_id = 3",
|
||||
'alias' => "P",
|
||||
'result' => "SELECT `L` FROM Location AS `L` JOIN Person AS `P` ON `P`.location_id = `L`.id JOIN Location AS `L1` ON `P`.location_id = `L1`.id WHERE (`L1`.`org_id` = 3)");
|
||||
|
||||
$aTests['Test Subclass1'] = array(
|
||||
'left' => "SELECT `U` FROM UserRequest AS `U` WHERE `U`.agent_id = 3",
|
||||
'right' => "SELECT `Ticket` WHERE org_id = 3",
|
||||
'alias' => "U",
|
||||
'result' => "SELECT `U` FROM UserRequest AS `U` WHERE ((`U`.`agent_id` = 3) AND (`U`.`org_id` = 3))");
|
||||
|
||||
$aTests['Test Subclass and join'] = array(
|
||||
'left' => "SELECT `UserRequest` FROM UserRequest AS `UserRequest` JOIN Person AS `P` ON `UserRequest`.agent_id = `P`.id WHERE `UserRequest`.agent_id = 3",
|
||||
'right' => "SELECT `Ticket` WHERE org_id = 3",
|
||||
'alias' => "UserRequest",
|
||||
'result' => "SELECT `UserRequest` FROM UserRequest AS `UserRequest` JOIN Person AS `P` ON `UserRequest`.agent_id = `P`.id WHERE ((`UserRequest`.`agent_id` = 3) AND (`UserRequest`.`org_id` = 3))");
|
||||
|
||||
$aTests['Test Subclass and union'] = array(
|
||||
'left' => "SELECT `U` FROM UserRequest AS `U` WHERE `U`.agent_id = 3 UNION SELECT `T` FROM Ticket AS `T` WHERE `T`.agent_id = 3 ",
|
||||
'right' => "SELECT `Ticket` WHERE org_id = 3",
|
||||
'alias' => "U",
|
||||
'result' => "SELECT `U` FROM UserRequest AS `U` WHERE ((`U`.`agent_id` = 3) AND (`U`.`org_id` = 3)) UNION SELECT `T` FROM Ticket AS `T` WHERE ((`T`.`agent_id` = 3) AND (`T`.`org_id` = 3))");
|
||||
|
||||
|
||||
|
||||
return $aTests;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @dataProvider IntersectProvider
|
||||
*
|
||||
* @param $sLeftSelect
|
||||
* @param $sRightSelect
|
||||
* @param $sResult
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function testIntersect($sLeftSelect, $sRightSelect, $sResult)
|
||||
{
|
||||
$oLeftSearch = DBSearch::FromOQL($sLeftSelect);
|
||||
$oRightSearch = DBSearch::FromOQL($sRightSelect);
|
||||
|
||||
$oResultSearch = $oLeftSearch->Intersect($oRightSearch);
|
||||
$sOQLResult = $oResultSearch->ToOQL();
|
||||
CMDBSource::TestQuery($oResultSearch->MakeSelectQuery());
|
||||
$this->assertEquals($sResult, $sOQLResult);
|
||||
}
|
||||
|
||||
public function IntersectProvider()
|
||||
{
|
||||
$aTests = array();
|
||||
|
||||
$aTests['Nested selects 2'] = array(
|
||||
'left' => "SELECT `U` FROM UserRequest AS `U` WHERE U.agent_id = 3",
|
||||
'right' => "SELECT `UserRequest` FROM UserRequest AS `UserRequest` JOIN Person AS `P` ON `UserRequest`.agent_id = `P`.id JOIN Organization AS `Organization` ON `P`.org_id = `Organization`.id WHERE (`UserRequest`.`org_id` IN (SELECT `Organization` FROM Organization AS `Organization` WHERE (`Organization`.`id` = `UserRequest`.`org_id`)))",
|
||||
'result' => "SELECT `U` FROM UserRequest AS `U` JOIN Person AS `P` ON `U`.agent_id = `P`.id JOIN Organization AS `Organization` ON `P`.org_id = `Organization`.id WHERE ((`U`.`agent_id` = 3) AND (`U`.`org_id` IN (SELECT `Organization1` FROM Organization AS `Organization1` WHERE (`Organization1`.`id` = `U`.`org_id`))))");
|
||||
|
||||
$aTests['Nested selects'] = array(
|
||||
'left' => "SELECT `UserRequest` FROM UserRequest AS `UserRequest` JOIN Person AS `P` ON `UserRequest`.agent_id = `P`.id JOIN Organization AS `Organization` ON `P`.org_id = `Organization`.id WHERE (`UserRequest`.`org_id` IN (SELECT `Organization` FROM Organization AS `Organization` WHERE (`Organization`.`id` = `UserRequest`.`org_id`)))",
|
||||
'right' => "SELECT `UserRequest` FROM UserRequest AS `UserRequest` WHERE UserRequest.agent_id = 3",
|
||||
'result' => "SELECT `UserRequest` FROM UserRequest AS `UserRequest` JOIN Person AS `P` ON `UserRequest`.agent_id = `P`.id JOIN Organization AS `Organization` ON `P`.org_id = `Organization`.id WHERE ((`UserRequest`.`org_id` IN (SELECT `Organization1` FROM Organization AS `Organization1` WHERE (`Organization1`.`id` = `UserRequest`.`org_id`))) AND (`UserRequest`.`agent_id` = 3))");
|
||||
|
||||
$aTests['Multiple selected classes inverted'] = array(
|
||||
'left' => "SELECT `L`, `P` FROM Person AS `P` JOIN Location AS `L` ON `P`.location_id = `L`.id WHERE 1",
|
||||
'right' => "SELECT Person WHERE org_id = 3",
|
||||
'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)",
|
||||
'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))");
|
||||
|
||||
$aTests['Same class'] = array(
|
||||
'left' => "SELECT Contact WHERE name = 'Christie'",
|
||||
'right' => "SELECT Contact WHERE org_id = 3",
|
||||
'result' => "SELECT `Contact` FROM Contact AS `Contact` WHERE ((`Contact`.`name` = 'Christie') AND (`Contact`.`org_id` = 3))");
|
||||
|
||||
$aTests['Different Alias'] = array(
|
||||
'left' => "SELECT Contact AS C WHERE C.name = 'Christie'",
|
||||
'right' => "SELECT Contact AS CC WHERE CC.org_id = 3",
|
||||
'result' => "SELECT `C` FROM Contact AS `C` WHERE ((`C`.`name` = 'Christie') AND (`C`.`org_id` = 3))");
|
||||
|
||||
$aTests['Multiple selected classes'] = array(
|
||||
'left' => "SELECT `L`, `P` FROM Location AS `L` JOIN Person AS `P` ON `P`.location_id = `L`.id WHERE 1",
|
||||
'right' => "SELECT Location WHERE org_id = 3",
|
||||
'result' => "SELECT `L`, `P` FROM Location AS `L` JOIN Person AS `P` ON `P`.location_id = `L`.id WHERE (`L`.`org_id` = 3)");
|
||||
|
||||
$aTests['Alias collision'] = array(
|
||||
'left' => "SELECT `P` FROM Person AS `P` WHERE 1",
|
||||
'right' => "SELECT `Person` FROM Person AS `Person` JOIN Person AS `P` ON `P`.manager_id = `Person`.id WHERE `P`.org_id = 3",
|
||||
'result' => "SELECT `P` FROM Person AS `P` JOIN Person AS `P1` ON `P1`.manager_id = `P`.id WHERE (`P1`.`org_id` = 3)");
|
||||
|
||||
return $aTests;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \CoreException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function testIntersectNotOptimizedPointingTo()
|
||||
{
|
||||
$sBaseQuery = "SELECT l FROM lnkContactToFunctionalCI AS l JOIN Contact AS c ON l.contact_id = c.id";
|
||||
$sOQL = "SELECT l FROM lnkContactToFunctionalCI AS l JOIN Person AS p ON l.contact_id = p.id";
|
||||
$sResult = "SELECT `l` FROM lnkContactToFunctionalCI AS `l` JOIN Contact AS `c` ON `l`.contact_id = `c`.id JOIN Person AS `p` ON `l`.contact_id = `p`.id WHERE 1";
|
||||
|
||||
$oSearchA = DBSearch::FromOQL($sBaseQuery);
|
||||
$oSearchB = DBSearch::FromOQL($sOQL);
|
||||
$oIntersect = $oSearchA->Intersect($oSearchB);
|
||||
CMDBSource::TestQuery($oIntersect->MakeSelectQuery());
|
||||
$this->assertEquals($sResult, $oIntersect->ToOQL());
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \CoreException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function testIntersectNotOptimizedReferencedBy()
|
||||
{
|
||||
$sBaseQuery = "SELECT o FROM Organization AS o JOIN Contact AS c ON c.org_id = o.id WHERE c.id = 1";
|
||||
$sOQL = "SELECT o FROM Organization AS o JOIN Person AS p ON p.org_id = o.id WHERE p.id = 2";
|
||||
$sResult = "SELECT `o` FROM Organization AS `o` JOIN Contact AS `c` ON `c`.org_id = `o`.id JOIN Person AS `p` ON `p`.org_id = `o`.id WHERE ((`c`.`id` = 1) AND (`p`.`id` = 2))";
|
||||
|
||||
$oSearchA = DBSearch::FromOQL($sBaseQuery);
|
||||
$oSearchB = DBSearch::FromOQL($sOQL);
|
||||
$oIntersect = $oSearchA->Intersect($oSearchB);
|
||||
CMDBSource::TestQuery($oIntersect->MakeSelectQuery());
|
||||
$this->assertEquals($sResult, $oIntersect->ToOQL());
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \CoreException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function testIntersectOptimizedReferencedBy()
|
||||
{
|
||||
$sBaseQuery = "SELECT s FROM Service AS s JOIN Organization AS o ON s.org_id = o.id WHERE o.name = 'some name'";
|
||||
$sQueryA = "SELECT r FROM UserRequest AS r JOIN Service AS s ON r.service_id = s.id JOIN Organization AS o ON s.org_id = o.id WHERE r.agent_id = 456 AND s.servicefamily_id = 789 AND o.name = 'right_name'";
|
||||
$sResult = "SELECT `s` FROM Service AS `s` JOIN Organization AS `o` ON `s`.org_id = `o`.id JOIN UserRequest AS `r` ON `r`.service_id = `s`.id WHERE ((`o`.`name` = 'some name') AND (((`r`.`agent_id` = 456) AND (`s`.`servicefamily_id` = 789)) AND (`o`.`name` = 'right_name')))";
|
||||
|
||||
$oSearchA = DBSearch::FromOQL($sQueryA);
|
||||
$oSearchB = DBSearch::FromOQL($sBaseQuery);
|
||||
$oSearchB->AddCondition_ReferencedBy($oSearchA, 'service_id');
|
||||
CMDBSource::TestQuery($oSearchB->MakeSelectQuery());
|
||||
$this->assertEquals($sResult, $oSearchB->ToOQL());
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \CoreException
|
||||
* @throws \CoreWarning
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function testIntersectNotOptimizedAddConditionPointingTo()
|
||||
{
|
||||
$sBaseQuery = "SELECT Person FROM Person AS Person";
|
||||
$sQueryA = "SELECT o FROM Organization AS o JOIN Contact AS c ON c.org_id = o.id";
|
||||
$sResult = "SELECT `Person` FROM Person AS `Person` JOIN Organization AS `o` ON `Person`.org_id = `o`.id JOIN Contact AS `c` ON `c`.org_id = `o`.id WHERE 1";
|
||||
|
||||
$oSearchA = DBSearch::FromOQL($sQueryA);
|
||||
$oSearchB = DBSearch::FromOQL($sBaseQuery);
|
||||
$oSearchB->AddCondition_PointingTo($oSearchA, 'org_id');
|
||||
CMDBSource::TestQuery($oSearchB->MakeSelectQuery());
|
||||
$this->assertEquals($sResult, $oSearchB->ToOQL());
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \CoreException
|
||||
* @throws \CoreWarning
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function testIntersectOptimizedAddConditionPointingTo()
|
||||
{
|
||||
$sBaseQuery = "SELECT ur FROM UserRequest AS ur JOIN Person AS p ON ur.agent_id = p.id WHERE p.status != 'terminated'";
|
||||
$sQueryA = "SELECT o FROM Organization AS o JOIN UserRequest AS r ON r.org_id = o.id JOIN Person AS p ON r.caller_id = p.id WHERE o.name LIKE 'Company' AND r.service_id = 123 AND p.employee_number LIKE '007'";
|
||||
$sResult = "SELECT `ur` FROM UserRequest AS `ur` JOIN Person AS `p` ON `ur`.agent_id = `p`.id JOIN Organization AS `o` ON `ur`.org_id = `o`.id JOIN Person AS `p11` ON `ur`.caller_id = `p11`.id WHERE ((`p`.`status` != 'terminated') AND (((`o`.`name` LIKE 'Company') AND (`ur`.`service_id` = 123)) AND (`p11`.`employee_number` LIKE '007')))";
|
||||
|
||||
$oSearchA = DBSearch::FromOQL($sQueryA);
|
||||
$oSearchB = DBSearch::FromOQL($sBaseQuery);
|
||||
$oSearchB->AddCondition_PointingTo($oSearchA, 'org_id');
|
||||
CMDBSource::TestQuery($oSearchB->MakeSelectQuery());
|
||||
$this->assertEquals($sResult, $oSearchB->ToOQL());
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \CoreException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function testIntersectNotOptimizedAddConditionReferencedBy()
|
||||
{
|
||||
$sBaseQuery = "SELECT Person FROM Person AS Person";
|
||||
$sQueryA = "SELECT l FROM lnkContactToFunctionalCI AS l JOIN Contact AS c ON l.contact_id = c.id";
|
||||
$sResult = "SELECT `Person` FROM Person AS `Person` JOIN lnkContactToFunctionalCI AS `l` ON `l`.contact_id = `Person`.id JOIN Contact AS `c` ON `l`.contact_id = `c`.id WHERE 1";
|
||||
|
||||
$oSearchA = DBSearch::FromOQL($sQueryA);
|
||||
$oSearchB = DBSearch::FromOQL($sBaseQuery);
|
||||
$oSearchB->AddCondition_ReferencedBy($oSearchA, 'contact_id');
|
||||
CMDBSource::TestQuery($oSearchA->MakeSelectQuery());
|
||||
$this->assertEquals($sResult, $oSearchB->ToOQL());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider IntersectOptimizationProvider
|
||||
*
|
||||
* @param string $sOQL
|
||||
* @param string $sResult
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function testIntersectOptimization($sBaseQuery, $sOQL, $sResult)
|
||||
{
|
||||
$oSearchA = DBSearch::FromOQL($sBaseQuery);
|
||||
$oSearchB = DBSearch::FromOQL($sOQL);
|
||||
$oIntersect = $oSearchA->Intersect($oSearchB);
|
||||
CMDBSource::TestQuery($oIntersect->MakeSelectQuery());
|
||||
$this->assertEquals($sResult, $oIntersect->ToOQL());
|
||||
}
|
||||
|
||||
public function IntersectOptimizationProvider()
|
||||
{
|
||||
$aQueries = array(
|
||||
'Exact same query' => array(
|
||||
'Base Query' => 'SELECT s FROM Service AS s JOIN Organization AS o ON s.org_id = o.id WHERE o.name = "The World Company"',
|
||||
'Filter OQL' => 'SELECT s FROM Service AS s JOIN Organization AS o ON s.org_id = o.id WHERE o.name = "The World Company"',
|
||||
'Result ' => "SELECT `s` FROM Service AS `s` JOIN Organization AS `o` ON `s`.org_id = `o`.id WHERE ((`o`.`name` = 'The World Company') AND (`o`.`name` = 'The World Company'))",
|
||||
),
|
||||
'Same query, other aliases' => array(
|
||||
'Base Query' => 'SELECT s FROM Service AS s JOIN Organization AS o ON s.org_id = o.id WHERE o.name = "The World Company"',
|
||||
'Filter OQL' => 'SELECT s2 FROM Service AS s2 JOIN Organization AS o2 ON s2.org_id = o2.id WHERE o2.name = "The World Company"',
|
||||
'Result ' => "SELECT `s` FROM Service AS `s` JOIN Organization AS `o` ON `s`.org_id = `o`.id WHERE ((`o`.`name` = 'The World Company') AND (`o`.`name` = 'The World Company'))",
|
||||
),
|
||||
'Same aliases, different condition' => array(
|
||||
'Base Query' => 'SELECT s FROM Service AS s JOIN Organization AS o ON s.org_id = o.id WHERE o.name = "The World Company"',
|
||||
'Filter OQL' => 'SELECT s FROM Service AS s JOIN Organization AS o ON s.org_id = o.id WHERE o.parent_id = 0',
|
||||
'Result ' => "SELECT `s` FROM Service AS `s` JOIN Organization AS `o` ON `s`.org_id = `o`.id WHERE ((`o`.`name` = 'The World Company') AND (`o`.`parent_id` = 0))",
|
||||
),
|
||||
'Other aliases, different condition' => array(
|
||||
'Base Query' => 'SELECT s FROM Service AS s JOIN Organization AS o ON s.org_id = o.id WHERE o.name = "The World Company"',
|
||||
'Filter OQL' => 'SELECT s2 FROM Service AS s2 JOIN Organization AS o2 ON s2.org_id = o2.id WHERE o2.parent_id = 0',
|
||||
'Result ' => "SELECT `s` FROM Service AS `s` JOIN Organization AS `o` ON `s`.org_id = `o`.id WHERE ((`o`.`name` = 'The World Company') AND (`o`.`parent_id` = 0))",
|
||||
),
|
||||
'Same aliases, simpler query tree' => array(
|
||||
'Base Query' => 'SELECT s FROM Service AS s JOIN Organization AS o ON s.org_id = o.id WHERE o.name = "The World Company"',
|
||||
'Filter OQL' => 'SELECT s FROM Service AS s WHERE name LIKE "Save the World"',
|
||||
'Result ' => "SELECT `s` FROM Service AS `s` JOIN Organization AS `o` ON `s`.org_id = `o`.id WHERE ((`o`.`name` = 'The World Company') AND (`s`.`name` LIKE 'Save the World'))",
|
||||
),
|
||||
'Other aliases, simpler query tree' => array(
|
||||
'Base Query' => 'SELECT s FROM Service AS s JOIN Organization AS o ON s.org_id = o.id WHERE o.name = "The World Company"',
|
||||
'Filter OQL' => 'SELECT s2 FROM Service AS s2 WHERE name LIKE "Save the World"',
|
||||
'Result ' => "SELECT `s` FROM Service AS `s` JOIN Organization AS `o` ON `s`.org_id = `o`.id WHERE ((`o`.`name` = 'The World Company') AND (`s`.`name` LIKE 'Save the World'))",
|
||||
),
|
||||
'Same aliases, different query tree' => array(
|
||||
'Base Query' => 'SELECT s FROM Service AS s JOIN Organization AS o ON s.org_id = o.id WHERE o.name = "The World Company"',
|
||||
'Filter OQL' => 'SELECT s FROM Service AS s JOIN ServiceFamily AS f ON s.servicefamily_id = f.id WHERE s.org_id = 123 AND f.name = "Care"',
|
||||
'Result ' => "SELECT `s` FROM Service AS `s` JOIN Organization AS `o` ON `s`.org_id = `o`.id JOIN ServiceFamily AS `f` ON `s`.servicefamily_id = `f`.id WHERE ((`o`.`name` = 'The World Company') AND ((`s`.`org_id` = 123) AND (`f`.`name` = 'Care')))",
|
||||
),
|
||||
'Other aliases, different query tree' => array(
|
||||
'Base Query' => 'SELECT s FROM Service AS s JOIN Organization AS o ON s.org_id = o.id WHERE o.name = "The World Company"',
|
||||
'Filter OQL' => 'SELECT s2 FROM Service AS s2 JOIN ServiceFamily AS f ON s2.servicefamily_id = f.id WHERE s2.org_id = 123 AND f.name = "Care"',
|
||||
'Result ' => "SELECT `s` FROM Service AS `s` JOIN Organization AS `o` ON `s`.org_id = `o`.id JOIN ServiceFamily AS `f` ON `s`.servicefamily_id = `f`.id WHERE ((`o`.`name` = 'The World Company') AND ((`s`.`org_id` = 123) AND (`f`.`name` = 'Care')))",
|
||||
),
|
||||
|
||||
'2 - Exact same query' => array(
|
||||
'Base Query' => 'SELECT o FROM Organization AS o JOIN Service AS s ON s.org_id = o.id WHERE s.name = "Help"',
|
||||
'Filter OQL' => 'SELECT o FROM Organization AS o JOIN Service AS s ON s.org_id = o.id WHERE s.name = "Help"',
|
||||
'Result ' => "SELECT `o` FROM Organization AS `o` JOIN Service AS `s` ON `s`.org_id = `o`.id WHERE ((`s`.`name` = 'Help') AND (`s`.`name` = 'Help'))",
|
||||
),
|
||||
'2 - Same query, other aliases' => array(
|
||||
'Base Query' => 'SELECT o FROM Organization AS o JOIN Service AS s ON s.org_id = o.id WHERE s.name = "Help"',
|
||||
'Filter OQL' => 'SELECT o2 FROM Organization AS o2 JOIN Service AS s2 ON s2.org_id = o2.id WHERE s2.name = "Help"',
|
||||
'Result ' => "SELECT `o` FROM Organization AS `o` JOIN Service AS `s` ON `s`.org_id = `o`.id WHERE ((`s`.`name` = 'Help') AND (`s`.`name` = 'Help'))",
|
||||
),
|
||||
'2 - Same aliases, different condition' => array(
|
||||
'Base Query' => 'SELECT o FROM Organization AS o JOIN Service AS s ON s.org_id = o.id WHERE s.name = "Help"',
|
||||
'Filter OQL' => 'SELECT o FROM Organization AS o JOIN Service AS s ON s.org_id = o.id WHERE s.servicefamily_id = 321',
|
||||
'Result ' => "SELECT `o` FROM Organization AS `o` JOIN Service AS `s` ON `s`.org_id = `o`.id WHERE ((`s`.`name` = 'Help') AND (`s`.`servicefamily_id` = 321))",
|
||||
),
|
||||
'2 - Other aliases, different condition' => array(
|
||||
'Base Query' => 'SELECT o FROM Organization AS o JOIN Service AS s ON s.org_id = o.id WHERE s.name = "Help"',
|
||||
'Filter OQL' => 'SELECT o2 FROM Organization AS o2 JOIN Service AS s2 ON s2.org_id = o2.id WHERE s2.servicefamily_id = 321',
|
||||
'Result ' => "SELECT `o` FROM Organization AS `o` JOIN Service AS `s` ON `s`.org_id = `o`.id WHERE ((`s`.`name` = 'Help') AND (`s`.`servicefamily_id` = 321))",
|
||||
),
|
||||
'2 - Same aliases, simpler query tree' => array(
|
||||
'Base Query' => 'SELECT o FROM Organization AS o JOIN Service AS s ON s.org_id = o.id WHERE s.name = "Help"',
|
||||
'Filter OQL' => 'SELECT o FROM Organization AS o WHERE o.name = "Demo"',
|
||||
'Result ' => "SELECT `o` FROM Organization AS `o` JOIN Service AS `s` ON `s`.org_id = `o`.id WHERE ((`s`.`name` = 'Help') AND (`o`.`name` = 'Demo'))",
|
||||
),
|
||||
'2 - Other aliases, simpler query tree' => array(
|
||||
'Base Query' => 'SELECT o FROM Organization AS o JOIN Service AS s ON s.org_id = o.id WHERE s.name = "Help"',
|
||||
'Filter OQL' => 'SELECT o2 FROM Organization AS o2 WHERE o2.name = "Demo"',
|
||||
'Result ' => "SELECT `o` FROM Organization AS `o` JOIN Service AS `s` ON `s`.org_id = `o`.id WHERE ((`s`.`name` = 'Help') AND (`o`.`name` = 'Demo'))",
|
||||
),
|
||||
'2 - Same aliases, different query tree' => array(
|
||||
'Base Query' => 'SELECT o FROM Organization AS o JOIN Service AS s ON s.org_id = o.id WHERE s.name = "Help"',
|
||||
'Filter OQL' => 'SELECT o FROM Organization AS o JOIN Location AS l ON l.org_id = o.id WHERE l.name = "Paris"',
|
||||
'Result ' => "SELECT `o` FROM Organization AS `o` JOIN Service AS `s` ON `s`.org_id = `o`.id JOIN Location AS `l` ON `l`.org_id = `o`.id WHERE ((`s`.`name` = 'Help') AND (`l`.`name` = 'Paris'))",
|
||||
),
|
||||
'2 - Other aliases, different query tree' => array(
|
||||
'Base Query' => 'SELECT o FROM Organization AS o JOIN Service AS s ON s.org_id = o.id WHERE s.name = "Help"',
|
||||
'Filter OQL' => 'SELECT o2 FROM Organization AS o2 JOIN Location AS l ON l.org_id = o2.id WHERE l.name = "Paris"',
|
||||
'Result ' => "SELECT `o` FROM Organization AS `o` JOIN Service AS `s` ON `s`.org_id = `o`.id JOIN Location AS `l` ON `l`.org_id = `o`.id WHERE ((`s`.`name` = 'Help') AND (`l`.`name` = 'Paris'))",
|
||||
),
|
||||
|
||||
'Internal query optimizations 1' => array(
|
||||
'Base Query' => 'SELECT o FROM Organization AS o',
|
||||
'Filter OQL' => 'SELECT o FROM Organization AS o JOIN Location AS l ON l.org_id = o.id JOIN Organization AS p ON o.parent_id = p.id WHERE l.name = "Paris" AND p.code LIKE "toto"',
|
||||
'Result ' => "SELECT `o` FROM Organization AS `o` JOIN Organization AS `p` ON `o`.parent_id = `p`.id JOIN Location AS `l` ON `l`.org_id = `o`.id WHERE ((`l`.`name` = 'Paris') AND (`p`.`code` LIKE 'toto'))",
|
||||
),
|
||||
'Internal query optimizations 2' => array(
|
||||
'Base Query' => 'SELECT r FROM UserRequest AS r JOIN Service AS s ON r.service_id = s.id JOIN Organization AS o ON s.org_id = o.id WHERE o.name = "left_name"',
|
||||
'Filter OQL' => 'SELECT r FROM UserRequest AS r JOIN Service AS s ON r.service_id = s.id JOIN Organization AS o ON s.org_id = o.id WHERE o.name = "right_name"',
|
||||
'Result ' => "SELECT `r` FROM UserRequest AS `r` JOIN Service AS `s` ON `r`.service_id = `s`.id JOIN Organization AS `o` ON `s`.org_id = `o`.id WHERE ((`o`.`name` = 'left_name') AND (`o`.`name` = 'right_name'))",
|
||||
),
|
||||
);
|
||||
|
||||
return $aQueries;
|
||||
}
|
||||
|
||||
}
|
||||
184
tests/php-unit-tests/unitary-tests/core/DBSearchJoinTest.php
Normal file
184
tests/php-unit-tests/unitary-tests/core/DBSearchJoinTest.php
Normal file
@@ -0,0 +1,184 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Core;
|
||||
|
||||
use CMDBSource;
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use DBSearch;
|
||||
|
||||
/**
|
||||
* Class DBSearchIntersectTest
|
||||
*
|
||||
* @package Combodo\iTop\Test\UnitTest\Core
|
||||
*
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class DBSearchJoinTest extends ItopDataTestCase {
|
||||
|
||||
const USE_TRANSACTION = false;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
require_once(APPROOT.'application/startup.inc.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider JoinProvider
|
||||
*
|
||||
* @param $sLeftSelect
|
||||
* @param $sRightSelect
|
||||
* @param $sParentAtt
|
||||
* @param $sResult
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \CoreWarning
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function testJoin($sLeftSelect, $sRightSelect, $sParentAtt, $sResult)
|
||||
{
|
||||
$oLeftSearch = DBSearch::FromOQL($sLeftSelect);
|
||||
$oRightSearch = DBSearch::FromOQL($sRightSelect);
|
||||
|
||||
$aRealiasingMap = [];
|
||||
|
||||
$oResultSearch = $oLeftSearch->Join($oRightSearch,
|
||||
DBSearch::JOIN_REFERENCED_BY, $sParentAtt,
|
||||
TREE_OPERATOR_EQUALS, $aRealiasingMap);
|
||||
|
||||
$this->debug("\nRealiasing Map");
|
||||
$this->debug($aRealiasingMap);
|
||||
|
||||
CMDBSource::TestQuery($oResultSearch->MakeSelectQuery());
|
||||
$this->assertEquals($sResult, $oResultSearch->ToOQL());
|
||||
|
||||
// rename alias test
|
||||
$this->debug("\nBefore renaming");
|
||||
$this->debug($oResultSearch->ToOQL());
|
||||
$aLevelsPropertiesKeys = ['L-1', 'L-1-1', 'L-1-1-1'];
|
||||
foreach ($aLevelsPropertiesKeys as $sLevelAlias)
|
||||
{
|
||||
if (array_key_exists($sLevelAlias, $aRealiasingMap))
|
||||
{
|
||||
foreach ($aRealiasingMap[$sLevelAlias] as $sAliasToRename)
|
||||
{
|
||||
$oResultSearch->RenameAlias($sAliasToRename, $sLevelAlias);
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->debug("\nAfter renaming");
|
||||
$this->debug($oResultSearch->ToOQL());
|
||||
|
||||
}
|
||||
|
||||
public function JoinProvider()
|
||||
{
|
||||
// Breakpoint in BrowseBrickController::DisplayAction()
|
||||
// $aLevelsProperties[$aLevelsPropertiesKeys[$i]]['search'] = $aLevelsProperties[$aLevelsPropertiesKeys[$i]]['search']->Join($aLevelsProperties[$aLevelsPropertiesKeys[$i + 1]]['search'],
|
||||
// DBSearch::JOIN_REFERENCED_BY, $aLevelsProperties[$aLevelsPropertiesKeys[$i + 1]]['parent_att'],
|
||||
// TREE_OPERATOR_EQUALS, $aRealiasingMap);
|
||||
return [
|
||||
'Bug 3176' => [
|
||||
'left' => "SELECT `L-1-1` FROM Service AS `L-1-1` JOIN lnkCustomerContractToService AS `l1` ON `l1`.service_id = `L-1-1`.id JOIN CustomerContract AS `cc` ON `l1`.customercontract_id = `cc`.id WHERE ((`cc`.`org_id` = 2) AND (`L-1-1`.`status` != 'obsolete'))UNION SELECT `L-1-1` FROM Service AS `L-1-1` JOIN lnkCustomerContractToService AS `l11` ON `l11`.service_id = `L-1-1`.id JOIN CustomerContract AS `cc1` ON `l11`.customercontract_id = `cc1`.id JOIN Organization AS `child` ON `cc1`.org_id = `child`.id JOIN Organization AS `root` ON `child`.parent_id BELOW `root`.id WHERE ((`root`.`id` = 2) AND (`L-1-1`.`status` != 'obsolete'))",
|
||||
'right' => "SELECT `L-1-1-1` FROM ServiceSubcategory AS `L-1-1-1` WHERE (`L-1-1-1`.`status` != 'obsolete')",
|
||||
'parent_att' => 'service_id',
|
||||
'result' => "SELECT `L-1-1` FROM Service AS `L-1-1` JOIN lnkCustomerContractToService AS `l1` ON `l1`.service_id = `L-1-1`.id JOIN CustomerContract AS `cc` ON `l1`.customercontract_id = `cc`.id JOIN ServiceSubcategory AS `L-1-1-1` ON `L-1-1-1`.service_id = `L-1-1`.id WHERE (((`cc`.`org_id` = 2) AND (`L-1-1`.`status` != 'obsolete')) AND (`L-1-1-1`.`status` != 'obsolete')) UNION SELECT `L-1-1` FROM Service AS `L-1-1` JOIN lnkCustomerContractToService AS `l11` ON `l11`.service_id = `L-1-1`.id JOIN CustomerContract AS `cc1` ON `l11`.customercontract_id = `cc1`.id JOIN Organization AS `child` ON `cc1`.org_id = `child`.id JOIN Organization AS `root` ON `child`.parent_id BELOW `root`.id JOIN ServiceSubcategory AS `L-1-1-1` ON `L-1-1-1`.service_id = `L-1-1`.id WHERE (((`root`.`id` = 2) AND (`L-1-1`.`status` != 'obsolete')) AND (`L-1-1-1`.`status` != 'obsolete'))",
|
||||
],
|
||||
'Bug 2970' => [
|
||||
'left' => "SELECT `L-1-1` FROM Service AS `L-1-1` JOIN lnkCustomerContractToService AS `l1` ON `l1`.service_id = `L-1-1`.id JOIN CustomerContract AS `cc` ON `l1`.customercontract_id = `cc`.id WHERE ((`cc`.`org_id` = 2) AND (`L-1-1`.`status` != 'obsolete')) UNION SELECT `L-1-1` FROM Service AS `L-1-1` WHERE (`L-1-1`.`id` = 8)",
|
||||
'right' => "SELECT `L-1-1-1` FROM ServiceSubcategory AS `L-1-1-1` JOIN Service AS `s` ON `L-1-1-1`.service_id = `s`.id JOIN lnkCustomerContractToService AS `l1` ON `l1`.service_id = `s`.id JOIN CustomerContract AS `cc` ON `l1`.customercontract_id = `cc`.id WHERE ((`L-1-1-1`.`status` != 'obsolete') AND ((`cc`.`org_id` = 2) AND (`L-1-1-1`.`status` != 'obsolete'))) UNION SELECT `L-1-1-1` FROM ServiceSubcategory AS `L-1-1-1` JOIN Service AS `s1` ON `L-1-1-1`.service_id = `s1`.id WHERE ((`L-1-1-1`.`status` != 'obsolete') AND (`s1`.`id` = 8))",
|
||||
'parent_att' => 'service_id',
|
||||
'result' => "SELECT `L-1-1` FROM Service AS `L-1-1` JOIN lnkCustomerContractToService AS `l1` ON `l1`.service_id = `L-1-1`.id JOIN CustomerContract AS `cc` ON `l1`.customercontract_id = `cc`.id JOIN ServiceSubcategory AS `L-1-1-1` ON `L-1-1-1`.service_id = `L-1-1`.id WHERE (((`cc`.`org_id` = 2) AND (`L-1-1`.`status` != 'obsolete')) AND ((`L-1-1-1`.`status` != 'obsolete') AND ((`cc`.`org_id` = 2) AND (`L-1-1-1`.`status` != 'obsolete')))) UNION SELECT `L-1-1` FROM Service AS `L-1-1` JOIN ServiceSubcategory AS `L-1-1-1` ON `L-1-1-1`.service_id = `L-1-1`.id JOIN lnkCustomerContractToService AS `l11` ON `l11`.service_id = `L-1-1`.id JOIN CustomerContract AS `cc1` ON `l11`.customercontract_id = `cc1`.id WHERE ((`L-1-1`.`id` = 8) AND ((`L-1-1-1`.`status` != 'obsolete') AND ((`cc1`.`org_id` = 2) AND (`L-1-1-1`.`status` != 'obsolete')))) UNION SELECT `L-1-1` FROM Service AS `L-1-1` JOIN lnkCustomerContractToService AS `l1` ON `l1`.service_id = `L-1-1`.id JOIN CustomerContract AS `cc` ON `l1`.customercontract_id = `cc`.id JOIN ServiceSubcategory AS `L-1-1-1` ON `L-1-1-1`.service_id = `L-1-1`.id WHERE (((`cc`.`org_id` = 2) AND (`L-1-1`.`status` != 'obsolete')) AND ((`L-1-1-1`.`status` != 'obsolete') AND (`L-1-1`.`id` = 8))) UNION SELECT `L-1-1` FROM Service AS `L-1-1` JOIN ServiceSubcategory AS `L-1-1-1` ON `L-1-1-1`.service_id = `L-1-1`.id WHERE ((`L-1-1`.`id` = 8) AND ((`L-1-1-1`.`status` != 'obsolete') AND (`L-1-1`.`id` = 8)))",
|
||||
],
|
||||
'Bug 2585' => [
|
||||
'left' => "SELECT `L-1-1` FROM Service AS `L-1-1` JOIN lnkCustomerContractToService AS `l1` ON `l1`.service_id = `L-1-1`.id JOIN CustomerContract AS `cc` ON `l1`.customercontract_id = `cc`.id WHERE ((`cc`.`org_id` = 2) AND (`L-1-1`.`status` != 'obsolete')) UNION SELECT `L-1-1` FROM Service AS `L-1-1` WHERE (`L-1-1`.`id` = 8)",
|
||||
'right' => "SELECT `L-1-1-1` FROM ServiceSubcategory AS `L-1-1-1` JOIN Service AS `s` ON `L-1-1-1`.service_id = `s`.id JOIN lnkCustomerContractToService AS `l1` ON `l1`.service_id = `s`.id JOIN CustomerContract AS `cc` ON `l1`.customercontract_id = `cc`.id WHERE ((`L-1-1-1`.`status` != 'obsolete') AND ((`cc`.`org_id` = 2) AND (`L-1-1-1`.`status` != 'obsolete'))) UNION SELECT `L-1-1-1` FROM ServiceSubcategory AS `L-1-1-1` JOIN Service AS `s1` ON `L-1-1-1`.service_id = `s1`.id WHERE ((`L-1-1-1`.`status` != 'obsolete') AND (`s1`.`id` = 8))",
|
||||
'parent_att' => 'service_id',
|
||||
'result' => "SELECT `L-1-1` FROM Service AS `L-1-1` JOIN lnkCustomerContractToService AS `l1` ON `l1`.service_id = `L-1-1`.id JOIN CustomerContract AS `cc` ON `l1`.customercontract_id = `cc`.id JOIN ServiceSubcategory AS `L-1-1-1` ON `L-1-1-1`.service_id = `L-1-1`.id WHERE (((`cc`.`org_id` = 2) AND (`L-1-1`.`status` != 'obsolete')) AND ((`L-1-1-1`.`status` != 'obsolete') AND ((`cc`.`org_id` = 2) AND (`L-1-1-1`.`status` != 'obsolete')))) UNION SELECT `L-1-1` FROM Service AS `L-1-1` JOIN ServiceSubcategory AS `L-1-1-1` ON `L-1-1-1`.service_id = `L-1-1`.id JOIN lnkCustomerContractToService AS `l11` ON `l11`.service_id = `L-1-1`.id JOIN CustomerContract AS `cc1` ON `l11`.customercontract_id = `cc1`.id WHERE ((`L-1-1`.`id` = 8) AND ((`L-1-1-1`.`status` != 'obsolete') AND ((`cc1`.`org_id` = 2) AND (`L-1-1-1`.`status` != 'obsolete')))) UNION SELECT `L-1-1` FROM Service AS `L-1-1` JOIN lnkCustomerContractToService AS `l1` ON `l1`.service_id = `L-1-1`.id JOIN CustomerContract AS `cc` ON `l1`.customercontract_id = `cc`.id JOIN ServiceSubcategory AS `L-1-1-1` ON `L-1-1-1`.service_id = `L-1-1`.id WHERE (((`cc`.`org_id` = 2) AND (`L-1-1`.`status` != 'obsolete')) AND ((`L-1-1-1`.`status` != 'obsolete') AND (`L-1-1`.`id` = 8))) UNION SELECT `L-1-1` FROM Service AS `L-1-1` JOIN ServiceSubcategory AS `L-1-1-1` ON `L-1-1-1`.service_id = `L-1-1`.id WHERE ((`L-1-1`.`id` = 8) AND ((`L-1-1-1`.`status` != 'obsolete') AND (`L-1-1`.`id` = 8)))",
|
||||
],
|
||||
'Bug 2585 K' => [
|
||||
'left' => "SELECT `L-1` FROM ServiceFamily AS `L-1` JOIN Service AS `SHOULD_BE_TRANSLATED` ON `SHOULD_BE_TRANSLATED`.servicefamily_id = `L-1`.id JOIN lnkCustomerContractToService AS `l1` ON `l1`.service_id = `SHOULD_BE_TRANSLATED`.id JOIN CustomerContract AS `cc` ON `l1`.customercontract_id = `cc`.id WHERE (`cc`.`org_id` = 2) UNION SELECT `L-1` FROM ServiceFamily AS `L-1` JOIN Service AS `SHOULD_ALSO_BE_TRANSLATED` ON `SHOULD_ALSO_BE_TRANSLATED`.servicefamily_id = `L-1`.id WHERE (`SHOULD_ALSO_BE_TRANSLATED`.`id` = 8)",
|
||||
'right' => "SELECT `L-1-1` FROM Service AS `L-1-1` JOIN lnkCustomerContractToService AS `l1` ON `l1`.service_id = `L-1-1`.id JOIN CustomerContract AS `cc` ON `l1`.customercontract_id = `cc`.id JOIN ServiceSubcategory AS `L-1-1-1` ON `L-1-1-1`.service_id = `L-1-1`.id WHERE (((`cc`.`org_id` = 2) AND (`L-1-1`.`status` != 'obsolete')) AND ((`L-1-1-1`.`status` != 'obsolete') AND ((`cc`.`org_id` = 2) AND (`L-1-1-1`.`status` != 'obsolete')))) UNION SELECT `L-1-1` FROM Service AS `L-1-1` JOIN ServiceSubcategory AS `L-1-1-1` ON `L-1-1-1`.service_id = `L-1-1`.id JOIN lnkCustomerContractToService AS `l11` ON `l11`.service_id = `L-1-1`.id JOIN CustomerContract AS `cc1` ON `l11`.customercontract_id = `cc1`.id WHERE ((`L-1-1`.`id` = 8) AND ((`L-1-1-1`.`status` != 'obsolete') AND ((`cc1`.`org_id` = 2) AND (`L-1-1-1`.`status` != 'obsolete')))) UNION SELECT `L-1-1` FROM Service AS `L-1-1` JOIN lnkCustomerContractToService AS `l1` ON `l1`.service_id = `L-1-1`.id JOIN CustomerContract AS `cc` ON `l1`.customercontract_id = `cc`.id JOIN ServiceSubcategory AS `L-1-1-1` ON `L-1-1-1`.service_id = `L-1-1`.id WHERE (((`cc`.`org_id` = 2) AND (`L-1-1`.`status` != 'obsolete')) AND ((`L-1-1-1`.`status` != 'obsolete') AND (`L-1-1`.`id` = 8))) UNION SELECT `L-1-1` FROM Service AS `L-1-1` JOIN ServiceSubcategory AS `L-1-1-1` ON `L-1-1-1`.service_id = `L-1-1`.id WHERE ((`L-1-1`.`id` = 8) AND ((`L-1-1-1`.`status` != 'obsolete') AND (`L-1-1`.`id` = 8)))",
|
||||
'parent_att' => 'servicefamily_id',
|
||||
'result' => "SELECT `L-1` FROM ServiceFamily AS `L-1` JOIN Service AS `SHOULD_BE_TRANSLATED` ON `SHOULD_BE_TRANSLATED`.servicefamily_id = `L-1`.id JOIN lnkCustomerContractToService AS `l1` ON `l1`.service_id = `SHOULD_BE_TRANSLATED`.id JOIN CustomerContract AS `cc` ON `l1`.customercontract_id = `cc`.id JOIN ServiceSubcategory AS `L-1-1-1` ON `L-1-1-1`.service_id = `SHOULD_BE_TRANSLATED`.id WHERE ((`cc`.`org_id` = 2) AND (((`cc`.`org_id` = 2) AND (`SHOULD_BE_TRANSLATED`.`status` != 'obsolete')) AND ((`L-1-1-1`.`status` != 'obsolete') AND ((`cc`.`org_id` = 2) AND (`L-1-1-1`.`status` != 'obsolete'))))) UNION SELECT `L-1` FROM ServiceFamily AS `L-1` JOIN Service AS `SHOULD_ALSO_BE_TRANSLATED` ON `SHOULD_ALSO_BE_TRANSLATED`.servicefamily_id = `L-1`.id JOIN lnkCustomerContractToService AS `l1` ON `l1`.service_id = `SHOULD_ALSO_BE_TRANSLATED`.id JOIN CustomerContract AS `cc` ON `l1`.customercontract_id = `cc`.id JOIN ServiceSubcategory AS `L-1-1-1` ON `L-1-1-1`.service_id = `SHOULD_ALSO_BE_TRANSLATED`.id WHERE ((`SHOULD_ALSO_BE_TRANSLATED`.`id` = 8) AND (((`cc`.`org_id` = 2) AND (`SHOULD_ALSO_BE_TRANSLATED`.`status` != 'obsolete')) AND ((`L-1-1-1`.`status` != 'obsolete') AND ((`cc`.`org_id` = 2) AND (`L-1-1-1`.`status` != 'obsolete'))))) UNION SELECT `L-1` FROM ServiceFamily AS `L-1` JOIN Service AS `SHOULD_BE_TRANSLATED` ON `SHOULD_BE_TRANSLATED`.servicefamily_id = `L-1`.id JOIN lnkCustomerContractToService AS `l1` ON `l1`.service_id = `SHOULD_BE_TRANSLATED`.id JOIN CustomerContract AS `cc` ON `l1`.customercontract_id = `cc`.id JOIN ServiceSubcategory AS `L-1-1-1` ON `L-1-1-1`.service_id = `SHOULD_BE_TRANSLATED`.id WHERE ((`cc`.`org_id` = 2) AND ((`SHOULD_BE_TRANSLATED`.`id` = 8) AND ((`L-1-1-1`.`status` != 'obsolete') AND ((`cc`.`org_id` = 2) AND (`L-1-1-1`.`status` != 'obsolete'))))) UNION SELECT `L-1` FROM ServiceFamily AS `L-1` JOIN Service AS `SHOULD_ALSO_BE_TRANSLATED` ON `SHOULD_ALSO_BE_TRANSLATED`.servicefamily_id = `L-1`.id JOIN ServiceSubcategory AS `L-1-1-1` ON `L-1-1-1`.service_id = `SHOULD_ALSO_BE_TRANSLATED`.id JOIN lnkCustomerContractToService AS `l11` ON `l11`.service_id = `SHOULD_ALSO_BE_TRANSLATED`.id JOIN CustomerContract AS `cc1` ON `l11`.customercontract_id = `cc1`.id WHERE ((`SHOULD_ALSO_BE_TRANSLATED`.`id` = 8) AND ((`SHOULD_ALSO_BE_TRANSLATED`.`id` = 8) AND ((`L-1-1-1`.`status` != 'obsolete') AND ((`cc1`.`org_id` = 2) AND (`L-1-1-1`.`status` != 'obsolete'))))) UNION SELECT `L-1` FROM ServiceFamily AS `L-1` JOIN Service AS `SHOULD_BE_TRANSLATED` ON `SHOULD_BE_TRANSLATED`.servicefamily_id = `L-1`.id JOIN lnkCustomerContractToService AS `l1` ON `l1`.service_id = `SHOULD_BE_TRANSLATED`.id JOIN CustomerContract AS `cc` ON `l1`.customercontract_id = `cc`.id JOIN ServiceSubcategory AS `L-1-1-1` ON `L-1-1-1`.service_id = `SHOULD_BE_TRANSLATED`.id WHERE ((`cc`.`org_id` = 2) AND (((`cc`.`org_id` = 2) AND (`SHOULD_BE_TRANSLATED`.`status` != 'obsolete')) AND ((`L-1-1-1`.`status` != 'obsolete') AND (`SHOULD_BE_TRANSLATED`.`id` = 8)))) UNION SELECT `L-1` FROM ServiceFamily AS `L-1` JOIN Service AS `SHOULD_ALSO_BE_TRANSLATED` ON `SHOULD_ALSO_BE_TRANSLATED`.servicefamily_id = `L-1`.id JOIN lnkCustomerContractToService AS `l1` ON `l1`.service_id = `SHOULD_ALSO_BE_TRANSLATED`.id JOIN CustomerContract AS `cc` ON `l1`.customercontract_id = `cc`.id JOIN ServiceSubcategory AS `L-1-1-1` ON `L-1-1-1`.service_id = `SHOULD_ALSO_BE_TRANSLATED`.id WHERE ((`SHOULD_ALSO_BE_TRANSLATED`.`id` = 8) AND (((`cc`.`org_id` = 2) AND (`SHOULD_ALSO_BE_TRANSLATED`.`status` != 'obsolete')) AND ((`L-1-1-1`.`status` != 'obsolete') AND (`SHOULD_ALSO_BE_TRANSLATED`.`id` = 8)))) UNION SELECT `L-1` FROM ServiceFamily AS `L-1` JOIN Service AS `SHOULD_BE_TRANSLATED` ON `SHOULD_BE_TRANSLATED`.servicefamily_id = `L-1`.id JOIN lnkCustomerContractToService AS `l1` ON `l1`.service_id = `SHOULD_BE_TRANSLATED`.id JOIN CustomerContract AS `cc` ON `l1`.customercontract_id = `cc`.id JOIN ServiceSubcategory AS `L-1-1-1` ON `L-1-1-1`.service_id = `SHOULD_BE_TRANSLATED`.id WHERE ((`cc`.`org_id` = 2) AND ((`SHOULD_BE_TRANSLATED`.`id` = 8) AND ((`L-1-1-1`.`status` != 'obsolete') AND (`SHOULD_BE_TRANSLATED`.`id` = 8)))) UNION SELECT `L-1` FROM ServiceFamily AS `L-1` JOIN Service AS `SHOULD_ALSO_BE_TRANSLATED` ON `SHOULD_ALSO_BE_TRANSLATED`.servicefamily_id = `L-1`.id JOIN ServiceSubcategory AS `L-1-1-1` ON `L-1-1-1`.service_id = `SHOULD_ALSO_BE_TRANSLATED`.id WHERE ((`SHOULD_ALSO_BE_TRANSLATED`.`id` = 8) AND ((`SHOULD_ALSO_BE_TRANSLATED`.`id` = 8) AND ((`L-1-1-1`.`status` != 'obsolete') AND (`SHOULD_ALSO_BE_TRANSLATED`.`id` = 8))))",
|
||||
],
|
||||
'test 2585 K2' => [
|
||||
'left' => "SELECT Service AS s JOIN lnkCustomerContractToService AS l1 ON l1.service_id=s.id JOIN CustomerContract AS cc ON l1.customercontract_id=cc.id WHERE cc.org_id = 2 AND s.status != 'obsolete' UNION SELECT Service WHERE id = 8",
|
||||
'right' => "SELECT ServiceSubcategory AS ssc JOIN Service AS s ON ssc.service_id=s.id JOIN lnkCustomerContractToService AS l1 ON l1.service_id=s.id JOIN CustomerContract AS cc ON l1.customercontract_id=cc.id WHERE cc.org_id = 2 AND ssc.status != 'obsolete' UNION SELECT ServiceSubcategory AS ssc JOIN Service AS s ON ssc.service_id=s.id WHERE s.id = 8",
|
||||
'parent_att' => 'service_id',
|
||||
'result' => "SELECT `s` FROM Service AS `s` JOIN lnkCustomerContractToService AS `l1` ON `l1`.service_id = `s`.id JOIN CustomerContract AS `cc` ON `l1`.customercontract_id = `cc`.id JOIN ServiceSubcategory AS `ssc` ON `ssc`.service_id = `s`.id WHERE (((`cc`.`org_id` = 2) AND (`s`.`status` != 'obsolete')) AND ((`cc`.`org_id` = 2) AND (`ssc`.`status` != 'obsolete'))) UNION SELECT `Service` FROM Service AS `Service` JOIN ServiceSubcategory AS `ssc` ON `ssc`.service_id = `Service`.id JOIN lnkCustomerContractToService AS `l11` ON `l11`.service_id = `Service`.id JOIN CustomerContract AS `cc1` ON `l11`.customercontract_id = `cc1`.id WHERE ((`Service`.`id` = 8) AND ((`cc1`.`org_id` = 2) AND (`ssc`.`status` != 'obsolete'))) UNION SELECT `s` FROM Service AS `s` JOIN lnkCustomerContractToService AS `l1` ON `l1`.service_id = `s`.id JOIN CustomerContract AS `cc` ON `l1`.customercontract_id = `cc`.id JOIN ServiceSubcategory AS `ssc` ON `ssc`.service_id = `s`.id WHERE (((`cc`.`org_id` = 2) AND (`s`.`status` != 'obsolete')) AND (`s`.`id` = 8)) UNION SELECT `Service` FROM Service AS `Service` JOIN ServiceSubcategory AS `ssc` ON `ssc`.service_id = `Service`.id WHERE ((`Service`.`id` = 8) AND (`Service`.`id` = 8))",
|
||||
],
|
||||
'Bug 2585 K3' => [
|
||||
'left' => "SELECT `L-1` FROM ServiceFamily AS `L-1` JOIN Service AS `s` ON `s`.servicefamily_id = `L-1`.id WHERE 1",
|
||||
'right' => "SELECT `L-1-1` FROM Service AS `L-1-1` WHERE 1",
|
||||
'parent_att' => 'servicefamily_id',
|
||||
'result' => "SELECT `L-1` FROM ServiceFamily AS `L-1` JOIN Service AS `s` ON `s`.servicefamily_id = `L-1`.id WHERE 1",
|
||||
],
|
||||
// 'test' => [
|
||||
// 'left' => "",
|
||||
// 'right' => "",
|
||||
// 'parent_att' => '',
|
||||
// 'result' => "",
|
||||
// ],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Bug #2970
|
||||
* @throws \CoreException
|
||||
* @throws \CoreWarning
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function testFilterOnJoin()
|
||||
{
|
||||
$sReq1 = "SELECT `L-1` FROM Organization AS `L-1` WHERE (`L-1`.`id` = 2)";
|
||||
$sReq2 = "SELECT `L-1-1` FROM CustomerContract AS `L-1-1` JOIN Organization AS `SHOULD_BE_TRANSLATED` ON `L-1-1`.org_id = `SHOULD_BE_TRANSLATED`.id WHERE (((`L-1-1`.`status` = 'active') OR (`L-1-1`.`status` = 'standby')) AND (`SHOULD_BE_TRANSLATED`.`id` = 2))";
|
||||
|
||||
$oFilter1 = DBSearch::FromOQL($sReq1);
|
||||
$oFilter2 = DBSearch::FromOQL($sReq2);
|
||||
$aRealiasingMap = array();
|
||||
$oFilter1 = $oFilter1->Join($oFilter2,
|
||||
DBSearch::JOIN_REFERENCED_BY,
|
||||
'org_id',
|
||||
TREE_OPERATOR_EQUALS, $aRealiasingMap);
|
||||
|
||||
$this->debug("\nRealiasing Map");
|
||||
$this->debug($aRealiasingMap);
|
||||
|
||||
$sRes1 = $oFilter1->ToOQL();
|
||||
$this->debug("\nJoined");
|
||||
$this->debug($sRes1);
|
||||
|
||||
foreach($oFilter1->GetCriteria_ReferencedBy() as $sForeignClass => $aReferences)
|
||||
{
|
||||
foreach ($aReferences as $sForeignExtKeyAttCode => $aFiltersByOperator)
|
||||
{
|
||||
foreach ($aFiltersByOperator as $iOperatorCode => $aFilters)
|
||||
{
|
||||
foreach ($aFilters as $index => $oForeignFilter)
|
||||
{
|
||||
$this->debug("\nReferencedBy");
|
||||
$this->debug($oForeignFilter->ToOQL());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->assertFalse(strpos($sRes1, '`SHOULD_BE_TRANSLATED`.'));
|
||||
|
||||
$sReq3 = "SELECT `CustomerContract` FROM CustomerContract AS `CustomerContract` WHERE (`CustomerContract`.`org_id` IN ('2'))";
|
||||
$oFilter3 = DBSearch::FromOQL($sReq3);
|
||||
|
||||
$oFilter1 = $oFilter1->Filter('L-1-1', $oFilter3);
|
||||
|
||||
$sRes1 = $oFilter1->ToOQL();
|
||||
$this->debug("\nFiltered");
|
||||
$this->debug($sRes1);
|
||||
|
||||
$this->assertFalse(strpos($sRes1, '`SHOULD_BE_TRANSLATED`.'));
|
||||
}
|
||||
}
|
||||
738
tests/php-unit-tests/unitary-tests/core/DBSearchTest.php
Normal file
738
tests/php-unit-tests/unitary-tests/core/DBSearchTest.php
Normal file
@@ -0,0 +1,738 @@
|
||||
<?php
|
||||
// Copyright (c) 2010-2018 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/>
|
||||
//
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Eric
|
||||
* Date: 06/02/2018
|
||||
* Time: 09:58
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Core;
|
||||
|
||||
|
||||
use CMDBSource;
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use CoreOqlMultipleResultsForbiddenException;
|
||||
use DBSearch;
|
||||
use Exception;
|
||||
use Expression;
|
||||
use FunctionExpression;
|
||||
|
||||
|
||||
/**
|
||||
* Tests of the DBSearch class.
|
||||
* <ul>
|
||||
* <li>MakeGroupByQuery</li>
|
||||
* </ul>
|
||||
*
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class DBSearchTest extends ItopDataTestCase
|
||||
{
|
||||
const CREATE_TEST_ORG = true;
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
require_once(APPROOT.'application/itopwebpage.class.inc.php');
|
||||
require_once(APPROOT.'application/displayblock.class.inc.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider UReqProvider
|
||||
* @param $iOrgNb
|
||||
* @param $iPersonNb
|
||||
* @param $aReq
|
||||
* @param $iLimit
|
||||
* @param $aCountRes
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testMakeGroupByQuery($iOrgNb, $iPersonNb, $aReq, $iLimit, $aCountRes)
|
||||
{
|
||||
$sOrgs = $this->init_db($iOrgNb, $iPersonNb, $aReq);
|
||||
|
||||
$oSearch = DBSearch::FromOQL("SELECT UserRequest WHERE org_id IN ($sOrgs)");
|
||||
self::assertNotNull($oSearch);
|
||||
$oExpr1 = Expression::FromOQL('UserRequest.org_id');
|
||||
|
||||
// Alias => Expression
|
||||
$aGroupBy = array('org_id' => $oExpr1);
|
||||
|
||||
$oTimeExpr = Expression::FromOQL('UserRequest.time_spent');
|
||||
$oSumExpr = new FunctionExpression('SUM', array($oTimeExpr));
|
||||
$oAvgExpr = new FunctionExpression('AVG', array($oTimeExpr));
|
||||
$oMinExpr = new FunctionExpression('MIN', array($oTimeExpr));
|
||||
$oMaxExpr = new FunctionExpression('MAX', array($oTimeExpr));
|
||||
// Alias => Expression
|
||||
$aFunctions = array(
|
||||
'_itop_sum_' => $oSumExpr,
|
||||
'_itop_avg_' => $oAvgExpr,
|
||||
'_itop_min_' => $oMinExpr,
|
||||
'_itop_max_' => $oMaxExpr,
|
||||
);
|
||||
|
||||
// Alias => Order
|
||||
$aOrderBy = array('_itop_sum_' => true, '_itop_count_' => true);
|
||||
|
||||
$aArgs = array();
|
||||
|
||||
$sSQL = $oSearch->MakeGroupByQuery($aArgs, $aGroupBy, false, $aFunctions, $aOrderBy, $iLimit);
|
||||
$this->debug($sSQL);
|
||||
|
||||
$aRes = CMDBSource::QueryToArray($sSQL);
|
||||
$this->debug($aRes);
|
||||
|
||||
self::assertEquals(count($aCountRes), count($aRes));
|
||||
for ($i = 0; $i < count($aCountRes); $i++)
|
||||
{
|
||||
self::assertEquals($aCountRes[$i], $aRes[$i]['_itop_count_']);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function UReqProvider()
|
||||
{
|
||||
return array(
|
||||
"1 line" => array(1, 1, array(array(1, 0, 0)), 0, array('1')),
|
||||
"2 same lines" => array(1, 1, array(array(1, 0, 0), array(1, 0, 0)), 0, array('2')),
|
||||
"2 diff lines" => array(2, 2, array(array(1, 0, 0), array(1, 1, 1)), 0, array('1', '1')),
|
||||
"4 lines" => array(2, 2, array(array(1, 0, 0), array(1, 1, 1), array(1, 0, 0), array(1, 1, 1)), 0, array('2', '2')),
|
||||
"5 lines" => array(2, 2, array(array(1, 0, 0), array(1, 0, 0), array(1, 1, 1), array(1, 0, 0), array(1, 1, 1)), 0, array('2', '3')),
|
||||
"6 lines" => array(2, 4, array(array(1, 0, 0), array(1, 1, 3), array(1, 1, 1), array(1, 1, 3), array(1, 0, 2), array(1, 1, 1)), 0, array('2', '4')),
|
||||
"6 lines limit" => array(2, 4, array(array(1, 0, 0), array(1, 1, 3), array(1, 1, 1), array(1, 1, 1), array(1, 0, 0), array(1, 1, 1)), 1, array('2')),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $iOrgNb Number of Organization to create
|
||||
* @param int $iPersonNb Number of Person to create
|
||||
* @param array $aReq UserRequests to create: array(array([time_spent value], [org index], [person index]))
|
||||
* @return string organization list for select
|
||||
* @throws Exception
|
||||
*/
|
||||
private function init_db($iOrgNb, $iPersonNb, $aReq)
|
||||
{
|
||||
$aOrgIds = array();
|
||||
$sOrgs = '';
|
||||
for($i = 0; $i < $iOrgNb; $i++)
|
||||
{
|
||||
$oObj = $this->CreateOrganization('UnitTest_Org'.$i);
|
||||
$sKey = $oObj->GetKey();
|
||||
$aOrgIds[] = $sKey;
|
||||
if ($i > 0)
|
||||
{
|
||||
$sOrgs .= ",";
|
||||
}
|
||||
$sOrgs .= $sKey;
|
||||
}
|
||||
self::assertEquals($iOrgNb, count($aOrgIds));
|
||||
|
||||
$aPersonIds = array();
|
||||
for($i = 0; $i < $iPersonNb; $i++)
|
||||
{
|
||||
$oObj = $this->CreatePerson($i, $aOrgIds[$i % $iOrgNb]);
|
||||
$aPersonIds[] = $oObj->GetKey();
|
||||
}
|
||||
self::assertEquals($iPersonNb, count($aPersonIds));
|
||||
|
||||
$i = 0;
|
||||
foreach($aReq as $aParams)
|
||||
{
|
||||
$oObj = $this->CreateUserRequest($i, $aParams[0], $aOrgIds[$aParams[1]], $aPersonIds[$aParams[2]]);
|
||||
self::assertNotNull($oObj);
|
||||
$i++;
|
||||
}
|
||||
return $sOrgs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testGroupByUnion()
|
||||
{
|
||||
$oServer = $this->CreateServer(1);
|
||||
|
||||
$this->CreatePhysicalInterface(1, 1000, $oServer->GetKey());
|
||||
$this->CreateFiberChannelInterface(1, 1000, $oServer->GetKey());
|
||||
|
||||
|
||||
$oSearch = DBSearch::FromOQL("SELECT FiberChannelInterface AS FCI WHERE FCI.name = '1' UNION SELECT PhysicalInterface AS PHI WHERE PHI.name = '1'");
|
||||
self::assertNotNull($oSearch);
|
||||
$oExpr1 = Expression::FromOQL('FCI.name');
|
||||
|
||||
// Alias => Expression (first select reference)
|
||||
$aGroupBy = array('group1' => $oExpr1);
|
||||
|
||||
$oTimeExpr = Expression::FromOQL('FCI.speed');
|
||||
$oSumExpr = new FunctionExpression('SUM', array($oTimeExpr));
|
||||
$oAvgExpr = new FunctionExpression('AVG', array($oTimeExpr));
|
||||
$oMinExpr = new FunctionExpression('MIN', array($oTimeExpr));
|
||||
$oMaxExpr = new FunctionExpression('MAX', array($oTimeExpr));
|
||||
// Alias => Expression
|
||||
$aFunctions = array(
|
||||
'_itop_sum_' => $oSumExpr,
|
||||
'_itop_avg_' => $oAvgExpr,
|
||||
'_itop_min_' => $oMinExpr,
|
||||
'_itop_max_' => $oMaxExpr,
|
||||
);
|
||||
|
||||
// Alias => Order
|
||||
$aOrderBy = array('group1' => true, '_itop_count_' => true);
|
||||
|
||||
$aArgs = array();
|
||||
|
||||
$sSQL = $oSearch->MakeGroupByQuery($aArgs, $aGroupBy, false, $aFunctions, $aOrderBy);
|
||||
$this->debug($sSQL);
|
||||
|
||||
$aRes = CMDBSource::QueryToArray($sSQL);
|
||||
$this->debug($aRes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testOrderBy_1()
|
||||
{
|
||||
|
||||
$oSearch = DBSearch::FromOQL("SELECT FiberChannelInterface");
|
||||
self::assertNotNull($oSearch);
|
||||
|
||||
// Alias => Expression (first select reference)
|
||||
$oExpr1 = Expression::FromOQL('FiberChannelInterface.name');
|
||||
$aGroupBy = array('group1' => $oExpr1);
|
||||
|
||||
$oTimeExpr = Expression::FromOQL('FiberChannelInterface.speed');
|
||||
$oSumExpr = new FunctionExpression('SUM', array($oTimeExpr));
|
||||
$oAvgExpr = new FunctionExpression('AVG', array($oTimeExpr));
|
||||
$oMinExpr = new FunctionExpression('MIN', array($oTimeExpr));
|
||||
$oMaxExpr = new FunctionExpression('MAX', array($oTimeExpr));
|
||||
// Alias => Expression
|
||||
$aFunctions = array(
|
||||
'_itop_sum_' => $oSumExpr,
|
||||
'_itop_avg_' => $oAvgExpr,
|
||||
'_itop_min_' => $oMinExpr,
|
||||
'_itop_max_' => $oMaxExpr,
|
||||
);
|
||||
$aArgs = array();
|
||||
|
||||
// Alias => Order
|
||||
$aOrderBy = array(
|
||||
'group1' => true,
|
||||
'_itop_sum_' => true,
|
||||
'_itop_avg_' => true,
|
||||
'_itop_min_' => true,
|
||||
'_itop_max_' => true);
|
||||
$sSQL = $oSearch->MakeGroupByQuery($aArgs, $aGroupBy, false, $aFunctions, $aOrderBy);
|
||||
self::assertNotEmpty($sSQL);
|
||||
|
||||
// Alias => Order
|
||||
$aOrderBy = array('nothing_good' => true);
|
||||
$this->expectException("CoreException");
|
||||
$oSearch->MakeGroupByQuery($aArgs, $aGroupBy, false, $aFunctions, $aOrderBy);
|
||||
|
||||
self::assertTrue(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testSanity_1()
|
||||
{
|
||||
$oSearch = DBSearch::FromOQL("SELECT FiberChannelInterface AS FCI WHERE FCI.name = '1' UNION SELECT PhysicalInterface AS PHI WHERE PHI.name = '1'");
|
||||
self::assertNotNull($oSearch);
|
||||
$oExpr1 = Expression::FromOQL('FCI.name');
|
||||
|
||||
// Alias => Expression (first select reference)
|
||||
$aGroupBy = array('group1' => $oExpr1);
|
||||
|
||||
$oTimeExpr = Expression::FromOQL('FCI.speed');
|
||||
$oSumExpr = new FunctionExpression('SUM', array($oTimeExpr));
|
||||
$oAvgExpr = new FunctionExpression('AVG', array($oTimeExpr));
|
||||
$oMinExpr = new FunctionExpression('MIN', array($oTimeExpr));
|
||||
$oMaxExpr = new FunctionExpression('MAX', array($oTimeExpr));
|
||||
// Alias => Expression
|
||||
$aFunctions = array(
|
||||
'_itop_sum_' => $oSumExpr,
|
||||
'_itop_avg_' => $oAvgExpr,
|
||||
'group1' => $oMinExpr,
|
||||
'_itop_max_' => $oMaxExpr,
|
||||
);
|
||||
$aArgs = array();
|
||||
|
||||
// Alias => Order
|
||||
$aOrderBy = array(
|
||||
'group1' => true,
|
||||
'_itop_sum_' => true,
|
||||
'_itop_avg_' => true,
|
||||
'_itop_min_' => true,
|
||||
'_itop_max_' => true);
|
||||
|
||||
$this->expectException("CoreException");
|
||||
$oSearch->MakeGroupByQuery($aArgs, $aGroupBy, false, $aFunctions, $aOrderBy);
|
||||
|
||||
self::assertTrue(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testSanity_2()
|
||||
{
|
||||
$oSearch = DBSearch::FromOQL("SELECT FiberChannelInterface AS FCI WHERE FCI.name = '1' UNION SELECT PhysicalInterface AS PHI WHERE PHI.name = '1'");
|
||||
self::assertNotNull($oSearch);
|
||||
|
||||
// Alias => Expression (first select reference)
|
||||
$oExpr1 = Expression::FromOQL('FCI.name');
|
||||
$aGroupBy = array('group1' => $oExpr1);
|
||||
|
||||
$oTimeExpr = Expression::FromOQL('FCI.speed');
|
||||
$oSumExpr = new FunctionExpression('SUM', array($oTimeExpr));
|
||||
$oAvgExpr = new FunctionExpression('AVG', array($oTimeExpr));
|
||||
$oMinExpr = new FunctionExpression('MIN', array($oTimeExpr));
|
||||
$oMaxExpr = new FunctionExpression('MAX', array($oTimeExpr));
|
||||
// Alias => Expression
|
||||
$aFunctions = array(
|
||||
'_itop_sum_' => $oSumExpr,
|
||||
'_itop_avg_' => $oAvgExpr,
|
||||
'_itop_min_' => $oMinExpr,
|
||||
'_itop_max_' => $oMaxExpr,
|
||||
);
|
||||
$aArgs = array();
|
||||
|
||||
// Alias => Order
|
||||
$aOrderBy = array(
|
||||
'group1' => true,
|
||||
'_itop_sum_' => true,
|
||||
'_itop_avg_' => true,
|
||||
'_itop_min_' => true,
|
||||
'_itop_max_' => true);
|
||||
|
||||
$sSQL = $oSearch->MakeGroupByQuery($aArgs, $aGroupBy, false, $aFunctions, $aOrderBy);
|
||||
self::assertNotEmpty($sSQL);
|
||||
|
||||
$aGroupBy = array('group1' => 'FCI.name');
|
||||
$this->expectException("CoreException");
|
||||
$oSearch->MakeGroupByQuery($aArgs, $aGroupBy, false, $aFunctions, $aOrderBy);
|
||||
|
||||
self::assertTrue(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testSanity_3()
|
||||
{
|
||||
$oSearch = DBSearch::FromOQL("SELECT FiberChannelInterface AS FCI WHERE FCI.name = '1' UNION SELECT PhysicalInterface AS PHI WHERE PHI.name = '1'");
|
||||
self::assertNotNull($oSearch);
|
||||
|
||||
// Alias => Expression (first select reference)
|
||||
$oExpr1 = Expression::FromOQL('FCI.name');
|
||||
$aGroupBy = array('group1' => $oExpr1);
|
||||
|
||||
$oTimeExpr = Expression::FromOQL('FCI.speed');
|
||||
$oSumExpr = new FunctionExpression('SUM', array($oTimeExpr));
|
||||
$oAvgExpr = new FunctionExpression('AVG', array($oTimeExpr));
|
||||
$oMinExpr = new FunctionExpression('MIN', array($oTimeExpr));
|
||||
$oMaxExpr = new FunctionExpression('MAX', array($oTimeExpr));
|
||||
// Alias => Expression
|
||||
$aFunctions = array(
|
||||
'_itop_sum_' => $oSumExpr,
|
||||
'_itop_avg_' => $oAvgExpr,
|
||||
'_itop_min_' => $oMinExpr,
|
||||
'_itop_max_' => $oMaxExpr,
|
||||
);
|
||||
$aArgs = array();
|
||||
|
||||
// Alias => Order
|
||||
$aOrderBy = array(
|
||||
'group1' => true,
|
||||
'_itop_sum_' => true,
|
||||
'_itop_avg_' => true,
|
||||
'_itop_min_' => true,
|
||||
'_itop_max_' => true);
|
||||
|
||||
$sSQL = $oSearch->MakeGroupByQuery($aArgs, $aGroupBy, false, $aFunctions, $aOrderBy);
|
||||
self::assertNotEmpty($sSQL);
|
||||
|
||||
$aFunctions = array(
|
||||
'_itop_sum_' => 'SumExpr',
|
||||
'_itop_avg_' => $oAvgExpr,
|
||||
'_itop_min_' => $oMinExpr,
|
||||
'_itop_max_' => $oMaxExpr,
|
||||
);
|
||||
|
||||
$this->expectException("CoreException");
|
||||
$oSearch->MakeGroupByQuery($aArgs, $aGroupBy, false, $aFunctions, $aOrderBy);
|
||||
|
||||
self::assertTrue(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testSanity_4()
|
||||
{
|
||||
$oSearch = DBSearch::FromOQL("SELECT FiberChannelInterface AS FCI WHERE FCI.name = '1' UNION SELECT PhysicalInterface AS PHI WHERE PHI.name = '1'");
|
||||
self::assertNotNull($oSearch);
|
||||
|
||||
// Alias => Expression (first select reference)
|
||||
$oExpr1 = Expression::FromOQL('FCI.name');
|
||||
$aGroupBy = array('group1' => $oExpr1);
|
||||
|
||||
$oTimeExpr = Expression::FromOQL('FCI.speed');
|
||||
$oSumExpr = new FunctionExpression('SUM', array($oTimeExpr));
|
||||
$oAvgExpr = new FunctionExpression('AVG', array($oTimeExpr));
|
||||
$oMinExpr = new FunctionExpression('MIN', array($oTimeExpr));
|
||||
$oMaxExpr = new FunctionExpression('MAX', array($oTimeExpr));
|
||||
// Alias => Expression
|
||||
$aFunctions = array(
|
||||
'_itop_sum_' => $oSumExpr,
|
||||
'_itop_avg_' => $oAvgExpr,
|
||||
'_itop_min_' => $oMinExpr,
|
||||
'_itop_max_' => $oMaxExpr,
|
||||
);
|
||||
$aArgs = array();
|
||||
|
||||
// Alias => Order
|
||||
$aOrderBy = array(
|
||||
'group1' => true,
|
||||
'_itop_sum_' => true,
|
||||
'_itop_avg_' => true,
|
||||
'_itop_min_' => true,
|
||||
'_itop_max_' => true);
|
||||
|
||||
$sSQL = $oSearch->MakeGroupByQuery($aArgs, $aGroupBy, false, $aFunctions, $aOrderBy);
|
||||
self::assertNotEmpty($sSQL);
|
||||
|
||||
$aOrderBy = array(
|
||||
'group1' => true,
|
||||
'_itop_sum_' => true,
|
||||
'_itop_avg_' => 'ASC',
|
||||
'_itop_min_' => true,
|
||||
'_itop_max_' => true);
|
||||
|
||||
$this->expectException("CoreException");
|
||||
$oSearch->MakeGroupByQuery($aArgs, $aGroupBy, false, $aFunctions, $aOrderBy);
|
||||
|
||||
self::assertTrue(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testSanity_5()
|
||||
{
|
||||
$oSearch = DBSearch::FromOQL("SELECT FiberChannelInterface AS FCI WHERE FCI.name = '1' UNION SELECT PhysicalInterface AS PHI WHERE PHI.name = '1'");
|
||||
self::assertNotNull($oSearch);
|
||||
|
||||
// Alias => Expression (first select reference)
|
||||
$oExpr1 = Expression::FromOQL('FCI.name');
|
||||
$aGroupBy = array('group1' => $oExpr1);
|
||||
|
||||
$oTimeExpr = Expression::FromOQL('FCI.speed');
|
||||
$oSumExpr = new FunctionExpression('SUM', array($oTimeExpr));
|
||||
$oAvgExpr = new FunctionExpression('AVG', array($oTimeExpr));
|
||||
$oMinExpr = new FunctionExpression('MIN', array($oTimeExpr));
|
||||
$oMaxExpr = new FunctionExpression('MAX', array($oTimeExpr));
|
||||
// Alias => Expression
|
||||
$aFunctions = array(
|
||||
'_itop_sum_' => $oSumExpr,
|
||||
'_itop_avg_' => $oAvgExpr,
|
||||
'_itop_min_' => $oMinExpr,
|
||||
'_itop_max_' => $oMaxExpr,
|
||||
);
|
||||
$aArgs = array();
|
||||
|
||||
// Alias => Order
|
||||
$aOrderBy = array(
|
||||
'group1' => true,
|
||||
'_itop_sum_' => true,
|
||||
'_itop_avg_' => true,
|
||||
'_itop_min_' => true,
|
||||
'_itop_max_' => true);
|
||||
$sSQL = $oSearch->MakeGroupByQuery($aArgs, $aGroupBy, false, $aFunctions, $aOrderBy);
|
||||
self::assertNotEmpty($sSQL);
|
||||
|
||||
// Alias => Order
|
||||
$aOrderBy = array('nothing_good' => true);
|
||||
$this->expectException("CoreException");
|
||||
$oSearch->MakeGroupByQuery($aArgs, $aGroupBy, false, $aFunctions, $aOrderBy);
|
||||
|
||||
self::assertTrue(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \MySQLException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function testNoGroupBy()
|
||||
{
|
||||
$aReq = array(array(1, 0, 0), array(1, 1, 3), array(1, 1, 1), array(1, 1, 1), array(1, 0, 0), array(1, 1, 1));
|
||||
$sOrgs = $this->init_db(2, 4, $aReq);
|
||||
|
||||
$oSearch = DBSearch::FromOQL("SELECT UserRequest WHERE org_id IN ($sOrgs)");
|
||||
self::assertNotNull($oSearch);
|
||||
|
||||
|
||||
$oTimeExpr = Expression::FromOQL('UserRequest.time_spent');
|
||||
$oSumExpr = new FunctionExpression('SUM', array($oTimeExpr));
|
||||
$oAvgExpr = new FunctionExpression('AVG', array($oTimeExpr));
|
||||
$oMinExpr = new FunctionExpression('MIN', array($oTimeExpr));
|
||||
$oMaxExpr = new FunctionExpression('MAX', array($oTimeExpr));
|
||||
// Alias => Expression
|
||||
$aFunctions = array(
|
||||
'_itop_sum_' => $oSumExpr,
|
||||
'_itop_avg_' => $oAvgExpr,
|
||||
'_itop_min_' => $oMinExpr,
|
||||
'_itop_max_' => $oMaxExpr,
|
||||
);
|
||||
|
||||
$aGroupBy = array();
|
||||
$aOrderBy = array();
|
||||
$aArgs = array();
|
||||
|
||||
$sSQL = $oSearch->MakeGroupByQuery($aArgs, $aGroupBy, false, $aFunctions, $aOrderBy, 0);
|
||||
$this->debug($sSQL);
|
||||
|
||||
$aRes = CMDBSource::QueryToArray($sSQL);
|
||||
$this->debug($aRes);
|
||||
|
||||
self::assertEquals(1, count($aRes));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider GetFirstResultProvider
|
||||
*
|
||||
* @param string $sOql query to test
|
||||
* @param bool $bMustHaveOneResultMax arg passed to the tested function
|
||||
* @param int $sReturn
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
* @throws \OQLException
|
||||
*
|
||||
* @covers DBSearch::GetFirstResult()
|
||||
*/
|
||||
public function testGetFirstResult($sOql, $bMustHaveOneResultMax, $sReturn)
|
||||
{
|
||||
$oSearch = DBSearch::FromOQL($sOql);
|
||||
|
||||
$bHasThrownException = false;
|
||||
try
|
||||
{
|
||||
$oFirstResult = $oSearch->GetFirstResult($bMustHaveOneResultMax);
|
||||
}
|
||||
catch (CoreOqlMultipleResultsForbiddenException $e)
|
||||
{
|
||||
$oFirstResult = null;
|
||||
$bHasThrownException = true;
|
||||
}
|
||||
|
||||
switch ($sReturn)
|
||||
{
|
||||
case 'exception':
|
||||
self::assertEquals(true, $bHasThrownException, 'Exception raised');
|
||||
break;
|
||||
case 'null':
|
||||
self::assertNull($oFirstResult, 'Null returned');
|
||||
break;
|
||||
case 'object':
|
||||
self::assertInternalType('object', $oFirstResult, 'Object returned');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function GetFirstResultProvider()
|
||||
{
|
||||
return array(
|
||||
'One result' => array(
|
||||
'SELECT Person WHERE id = 1',
|
||||
false,
|
||||
'object',
|
||||
),
|
||||
'Multiple results, no exception' => array(
|
||||
'SELECT Person',
|
||||
false,
|
||||
'object',
|
||||
),
|
||||
'Multiple results, with exception' => array(
|
||||
'SELECT Person',
|
||||
true,
|
||||
'exception',
|
||||
),
|
||||
'Multiple results with "WHERE 1", with exception' => array(
|
||||
'SELECT Person WHERE 1',
|
||||
true,
|
||||
'exception',
|
||||
),
|
||||
'No result' => array(
|
||||
'SELECT Person WHERE id = -1',
|
||||
true,
|
||||
'null',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testSanity_GroupFunction_In_WherePart()
|
||||
{
|
||||
$sExceptionClass = '';
|
||||
$oSearch = DBSearch::FromOQL("SELECT FiberChannelInterface AS FCI");
|
||||
self::assertNotNull($oSearch);
|
||||
|
||||
try
|
||||
{
|
||||
$oExpr1 = Expression::FromOQL('AVC(FCI.name)');
|
||||
//$aGroupBy = array('group1' => $oExpr1);
|
||||
//$oSearch->MakeGroupByQuery(array(), $aGroupBy, false, array(), array());
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
$sExceptionClass = get_class($e);
|
||||
}
|
||||
|
||||
static::assertEquals('OQLParserSyntaxErrorException', $sExceptionClass);
|
||||
}
|
||||
|
||||
public function testSanity_GroupFunction_In_GroupByPart()
|
||||
{
|
||||
$sExceptionClass = '';
|
||||
try
|
||||
{
|
||||
$oSearch = DBSearch::FromOQL("SELECT FiberChannelInterface AS FCI WHERE COUNT(FCI.name) = AVC(FCI.name)");
|
||||
//$oSearch->MakeGroupByQuery(array(), array(), false, array(), array());
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
$sExceptionClass = get_class($e);
|
||||
}
|
||||
|
||||
static::assertEquals('OQLParserSyntaxErrorException', $sExceptionClass);
|
||||
}
|
||||
|
||||
public function testSanity_UnknownGroupFunction_In_SelectPart()
|
||||
{
|
||||
$sExceptionClass = '';
|
||||
try
|
||||
{
|
||||
$oTimeExpr = Expression::FromOQL('FCI.speed');
|
||||
$oWrongExpr = new FunctionExpression('GABUZOMEU', array($oTimeExpr));
|
||||
// Alias => Expression
|
||||
$aFunctions = array(
|
||||
'_itop_wrong_' => $oWrongExpr,
|
||||
);
|
||||
$oSearch = DBSearch::FromOQL("SELECT FiberChannelInterface AS FCI");
|
||||
$oSearch->MakeGroupByQuery(array(), array(), false, $aFunctions, array());
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
$sExceptionClass = get_class($e);
|
||||
}
|
||||
|
||||
//later on it should raise an exception...
|
||||
static::assertEquals('', $sExceptionClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \CoreException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function testSelectInWithVariableExpressions()
|
||||
{
|
||||
$aReq = array(array(1, 0, 0), array(1, 1, 3), array(1, 2, 1), array(1, 0, 1), array(1, 1, 0), array(1, 2, 1));
|
||||
$sOrgs = $this->init_db(3, 4, $aReq);
|
||||
$allOrgIds = explode(",", $sOrgs);
|
||||
|
||||
$TwoOrgIdsOnly = array($allOrgIds[0], $allOrgIds[1]);
|
||||
$oSearch = DBSearch::FromOQL("SELECT UserRequest WHERE org_id IN (:org_ids)");
|
||||
self::assertNotNull($oSearch);
|
||||
$oSet = new \CMDBObjectSet($oSearch, array(), array('org_ids' => $TwoOrgIdsOnly));
|
||||
static::assertEquals(4, $oSet->Count());
|
||||
|
||||
$_SERVER['REQUEST_URI'] = 'FAKE_REQUEST_URI';
|
||||
$_SERVER['REQUEST_METHOD'] = 'FAKE_REQUEST_METHOD';
|
||||
$oP = new \iTopWebPage("test");
|
||||
$oBlock = new \DisplayBlock($oSet->GetFilter(), 'list', false);
|
||||
$sHtml = $oBlock->GetDisplay($oP, 'package_table', array('menu' => true, 'display_limit' => false));
|
||||
|
||||
$iHtmlUserRequestLineCount = substr_count($sHtml, '<tr><td data-object-class="UserRequest"');
|
||||
static::assertEquals(4, $iHtmlUserRequestLineCount, "Failed Generated html :".$sHtml);
|
||||
$oP->output();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.7.2 2.8.0 N°3324
|
||||
*/
|
||||
public function testAllowAllData() {
|
||||
$oSimpleSearch = \DBObjectSearch::FromOQL('SELECT FunctionalCI');
|
||||
$oSimpleSearch->AllowAllData(false);
|
||||
self::assertFalse($oSimpleSearch->IsAllDataAllowed(), 'DBSearch AllowData value');
|
||||
$oSimpleSearch->AllowAllData(true);
|
||||
self::assertTrue($oSimpleSearch->IsAllDataAllowed(), 'DBSearch AllowData value');
|
||||
|
||||
$sNestedQuery = 'SELECT FunctionalCI WHERE id IN (SELECT Server)';
|
||||
$this->CheckNestedSearch($sNestedQuery, true);
|
||||
$this->CheckNestedSearch($sNestedQuery, false);
|
||||
}
|
||||
|
||||
private function CheckNestedSearch($sQuery, $bAllowAllData) {
|
||||
$oNestedQuerySearch = \DBObjectSearch::FromOQL($sQuery);
|
||||
$oNestedQuerySearch->AllowAllData($bAllowAllData);
|
||||
self::assertEquals($bAllowAllData, $oNestedQuerySearch->IsAllDataAllowed(), 'root DBSearch AllowData value');
|
||||
$oNestedSearchInExpression = null;
|
||||
$oNestedQuerySearch->GetCriteria()->Browse(function ($oExpression) use (&$oNestedSearchInExpression) {
|
||||
if ($oExpression instanceof \NestedQueryExpression) {
|
||||
$oNestedSearchInExpression = $oExpression->GetNestedQuery();
|
||||
|
||||
return;
|
||||
}
|
||||
});
|
||||
self::assertNotNull($oNestedSearchInExpression, 'We must have a DBSearch inside a NestedQueryExpression inside the root DBSearch');
|
||||
/** @var \DBObjectSearch $oNestedSearchInExpression */
|
||||
self::assertEquals($bAllowAllData, $oNestedSearchInExpression->IsAllDataAllowed(), 'Nested DBSearch AllowData value');
|
||||
}
|
||||
|
||||
/**
|
||||
* BUG N°4031 check AttributeObjectKey used in JOIN condition
|
||||
* @throws \ConfigException
|
||||
* @throws \CoreException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function testAttributeObjectKey()
|
||||
{
|
||||
$sQuery = "SELECT II FROM InlineImage AS II JOIN UserRequest AS UR ON II.item_id = UR.id WHERE II.item_class = 'UserRequest'";
|
||||
$oSearch = \DBObjectSearch::FromOQL($sQuery);
|
||||
$oSearch->MakeSelectQuery();
|
||||
self::assertTrue(true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Core;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use DBObjectSearch;
|
||||
|
||||
|
||||
/**
|
||||
* Class DBSearchUpdateRealiasingMapTest
|
||||
*
|
||||
* @package Combodo\iTop\Test\UnitTest\Core
|
||||
*
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class DBSearchUpdateRealiasingMapTest extends ItopDataTestCase
|
||||
{
|
||||
const USE_TRANSACTION = false;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
require_once(APPROOT.'application/startup.inc.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider UpdateRealiasingMapProvider
|
||||
* @param $aRealiasingMap
|
||||
* @param $aAliasTranslation
|
||||
* @param $aExpectedRealiasingMap
|
||||
*/
|
||||
public function testUpdateRealiasingMap($aRealiasingMap, $aAliasTranslation, $aExpectedRealiasingMap)
|
||||
{
|
||||
$oObject = new DBObjectSearch('Organization');
|
||||
$aArgs = [&$aRealiasingMap, $aAliasTranslation];
|
||||
$this->InvokeNonPublicMethod(DBObjectSearch::class, 'UpdateRealiasingMap', $oObject, $aArgs);
|
||||
$this->assertEquals($aExpectedRealiasingMap, $aRealiasingMap);
|
||||
}
|
||||
|
||||
public function UpdateRealiasingMapProvider()
|
||||
{
|
||||
return [
|
||||
'empty' => [
|
||||
'OriginalMap' => null,
|
||||
'AliasTranslation' => [],
|
||||
'ExpectedMap' => null
|
||||
],
|
||||
'Add 1 alias' => [
|
||||
'OriginalMap' => [],
|
||||
'AliasTranslation' => ['a' => ['*' => 'b']],
|
||||
'ExpectedMap' => ['a' => ['b']]
|
||||
],
|
||||
'Add 2 aliases' => [
|
||||
'OriginalMap' => [],
|
||||
'AliasTranslation' => ['a' => ['*' => 'b'], 'c' => ['*' => 'd']],
|
||||
'ExpectedMap' => ['a' => ['b'], 'c' => ['d']]
|
||||
],
|
||||
'Append 1 alias' => [
|
||||
'OriginalMap' => ['a' => ['b']],
|
||||
'AliasTranslation' => ['c' => ['*' => 'd']],
|
||||
'ExpectedMap' => ['a' => ['b'], 'c' => ['d']]
|
||||
],
|
||||
'Merge 1 alias' => [
|
||||
'OriginalMap' => ['a' => ['b']],
|
||||
'AliasTranslation' => ['a' => ['*' => 'd']],
|
||||
'ExpectedMap' => ['a' => ['b', 'd']]
|
||||
],
|
||||
'Merge same alias' => [
|
||||
'OriginalMap' => ['a' => ['b']],
|
||||
'AliasTranslation' => ['a' => ['*' => 'b']],
|
||||
'ExpectedMap' => ['a' => ['b']]
|
||||
],
|
||||
'Transitivity a->b + b->f = a->f' => [
|
||||
'OriginalMap' => ['a' => ['b', 'd'], 'c' => ['e']],
|
||||
'AliasTranslation' => ['b' => ['*' => 'f']],
|
||||
'ExpectedMap' => ['a' => ['f', 'd'], 'c' => ['e']]
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
52
tests/php-unit-tests/unitary-tests/core/ExpressionTest.php
Normal file
52
tests/php-unit-tests/unitary-tests/core/ExpressionTest.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* @dataProvider ListParametersProvider
|
||||
* @param $sOQL
|
||||
* @param $aExpected
|
||||
*
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function testListParameters($sOQL, $aExpected)
|
||||
{
|
||||
$oExpression = Expression::FromOQL($sOQL);
|
||||
$aParameters = $oExpression->ListParameters();
|
||||
$aResult = array();
|
||||
foreach ($aParameters as $oVarExpr)
|
||||
{
|
||||
/** var \VariableExpression $oVarExpr */
|
||||
$aResult[] = $oVarExpr->RenderExpression();
|
||||
}
|
||||
$this->debug($aResult);
|
||||
$this->assertSame(array_diff($aExpected, $aResult), array_diff($aResult, $aExpected));
|
||||
}
|
||||
|
||||
public function ListParametersProvider()
|
||||
{
|
||||
return array(
|
||||
array('1', array()),
|
||||
array(':id = 2', array(':id')),
|
||||
array('expiration_date < DATE_SUB(NOW(), INTERVAL :expiration_days DAY)', array(':expiration_days')),
|
||||
array('id IN (SELECT Organization WHERE :id = 2)', array(':id')),
|
||||
array('id IN (:id, 2)', array(':id')),
|
||||
array("B.name LIKE :name", array(':name')),
|
||||
array("name REGEXP :regexp", array(':regexp')),
|
||||
array(" t.agent_id = :current_contact_id", array(':current_contact_id')),
|
||||
array("INET_ATON(dev.managementip) > INET_ATON('10.22.32.224') AND INET_ATON(:ip) < INET_ATON('10.22.32.255')", array(':ip')),
|
||||
);
|
||||
}
|
||||
}
|
||||
143
tests/php-unit-tests/unitary-tests/core/LogAPITest.php
Normal file
143
tests/php-unit-tests/unitary-tests/core/LogAPITest.php
Normal file
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Eric
|
||||
* Date: 31/08/2018
|
||||
* Time: 17:03
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Core;
|
||||
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
|
||||
class LogAPITest extends ItopTestCase
|
||||
{
|
||||
private $mockFileLog;
|
||||
private $oMetaModelConfig;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->mockFileLog = $this->createMock('FileLog');
|
||||
$this->oMetaModelConfig = $this->createMock('Config');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @dataProvider LogApiProvider
|
||||
* @test
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
public function TestLogApi($oConfigObject, $sMessage, $Channel, $sExpectedLevel, $sExpectedMessage, $sExpectedChannel = '')
|
||||
{
|
||||
\IssueLog::MockStaticObjects($this->mockFileLog, $oConfigObject);
|
||||
|
||||
$this->mockFileLog->expects($this->exactly(1))
|
||||
->method($sExpectedLevel)
|
||||
->with($sExpectedMessage, $sExpectedChannel);
|
||||
|
||||
\IssueLog::Error($sMessage, $Channel);
|
||||
}
|
||||
|
||||
public function LogApiProvider()
|
||||
{
|
||||
return [
|
||||
[ $this->oMetaModelConfig, "log msg", '' , "Error", "log msg"],
|
||||
[ $this->oMetaModelConfig, "log msg", 'PoudlardChannel' , "Error", "log msg", 'PoudlardChannel'],
|
||||
[ array(), "log msg", '' , "Error", "log msg"], // Bruno?
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider LogWarningWithASpecificChannelProvider
|
||||
* @test
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
public function TestLogWarningWithASpecificChannel($expectedCallNb, $sExpectedLevel, $ConfigReturnedObject, $bExceptionRaised=false)
|
||||
{
|
||||
$this->oMetaModelConfig
|
||||
->method("Get")
|
||||
->with('log_level_min')
|
||||
->willReturn($ConfigReturnedObject);
|
||||
|
||||
\IssueLog::MockStaticObjects($this->mockFileLog, $this->oMetaModelConfig);
|
||||
|
||||
$this->mockFileLog->expects($this->exactly($expectedCallNb))
|
||||
->method($sExpectedLevel)
|
||||
->with("log msg", "GaBuZoMeuChannel");
|
||||
|
||||
try{
|
||||
\IssueLog::Warning("log msg", "GaBuZoMeuChannel");
|
||||
if ($bExceptionRaised)
|
||||
{
|
||||
$this->fail("raised should have been raised");
|
||||
}
|
||||
}
|
||||
catch(\Exception $e)
|
||||
{
|
||||
if (!$bExceptionRaised)
|
||||
{
|
||||
$this->fail("raised should NOT have been raised");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function LogWarningWithASpecificChannelProvider()
|
||||
{
|
||||
return [
|
||||
"empty config" => [ 0, "Ok", ''],
|
||||
"Default Unknown Level" => [ 0, "Ok", 'TotoLevel', true],
|
||||
"Info as Default Level" => [ 1 , "Warning", 'Info'],
|
||||
"Error as Default Level" => [ 0, "Warning", 'Error'],
|
||||
"Empty array" => [ 0, "Ok", array()],
|
||||
"Channel configured on an undefined level" => [ 0, "Ok", ["GaBuZoMeuChannel" => "TotoLevel"], true],
|
||||
"Channel defined with Error" => [ 0, "Warning", ["GaBuZoMeuChannel" => "Error"]],
|
||||
"Channel defined with Info" => [ 1, "Warning", ["GaBuZoMeuChannel" => "Info"]],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider LogOkWithASpecificChannel
|
||||
* @test
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
public function TestLogOkWithASpecificChannel($expectedCallNb, $sExpectedLevel, $ConfigReturnedObject, $bExceptionRaised=false)
|
||||
{
|
||||
$this->oMetaModelConfig
|
||||
->method("Get")
|
||||
->with('log_level_min')
|
||||
->willReturn($ConfigReturnedObject);
|
||||
|
||||
\IssueLog::MockStaticObjects($this->mockFileLog, $this->oMetaModelConfig);
|
||||
|
||||
$this->mockFileLog->expects($this->exactly($expectedCallNb))
|
||||
->method($sExpectedLevel)
|
||||
->with("log msg", "GaBuZoMeuChannel");
|
||||
|
||||
try{
|
||||
\IssueLog::Ok("log msg", "GaBuZoMeuChannel");
|
||||
if ($bExceptionRaised)
|
||||
{
|
||||
$this->fail("raised should have been raised");
|
||||
}
|
||||
}
|
||||
catch(\Exception $e)
|
||||
{
|
||||
if (!$bExceptionRaised)
|
||||
{
|
||||
$this->fail("raised should NOT have been raised");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function LogOkWithASpecificChannel()
|
||||
{
|
||||
return [
|
||||
"empty config" => [ 1, "Ok", ''],
|
||||
"Empty array" => [ 1, "Ok", array()],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Core;
|
||||
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
use DailyRotatingLogFileNameBuilder;
|
||||
use DateTime;
|
||||
|
||||
class LogFileNameBuilderTest extends ItopTestCase
|
||||
{
|
||||
const TEST_LOGFILE_PREFIX = 'fileNameBuilder.test';
|
||||
const TEST_LOGFILE_EXTENSION = 'log';
|
||||
|
||||
/**
|
||||
* @param $sLogFile
|
||||
* @param \DateTime $oNewModificationDate
|
||||
*
|
||||
* @uses \clearstatcache() if not called, the next filemtime() call will return the PHP cached date instead of the real one
|
||||
*/
|
||||
private function ChangeFileModificationDate($sLogFile, DateTime $oNewModificationDate)
|
||||
{
|
||||
touch($sLogFile, $oNewModificationDate->getTimestamp());
|
||||
clearstatcache(true, $sLogFile);
|
||||
}
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
require_once APPROOT.'core/log.class.inc.php';
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
parent::tearDown();
|
||||
|
||||
// remove log files created in the test
|
||||
$aTestLogFiles = glob(__DIR__.DIRECTORY_SEPARATOR.self::TEST_LOGFILE_PREFIX.'*.'.self::TEST_LOGFILE_EXTENSION);
|
||||
foreach ($aTestLogFiles as $sLogFile) {
|
||||
unlink($sLogFile);
|
||||
}
|
||||
}
|
||||
|
||||
public function testCheckAndRotateLogFile()
|
||||
{
|
||||
$sLogFile = __DIR__.DIRECTORY_SEPARATOR.self::TEST_LOGFILE_PREFIX.'.'.self::TEST_LOGFILE_EXTENSION;
|
||||
$oFileBuilder = new DailyRotatingLogFileNameBuilder($sLogFile);
|
||||
|
||||
if (file_exists($sLogFile))
|
||||
{
|
||||
unlink($sLogFile);
|
||||
}
|
||||
|
||||
$bIsFileExists = $oFileBuilder->IsLogFileExists();
|
||||
$this->assertFalse($bIsFileExists, 'Test log file does not exist');
|
||||
|
||||
$hLogFile = fopen($sLogFile, 'a');
|
||||
$sDate = date('Y-m-d H:i:s');
|
||||
$sTestClassName = self::class;
|
||||
fwrite($hLogFile, "$sDate | This is a line generated by $sTestClassName\n");
|
||||
fclose($hLogFile);
|
||||
$iLogDateLastModifiedTimeStamp = filemtime($sLogFile);
|
||||
$oLogFileLastModified = DateTime::createFromFormat('U', $iLogDateLastModifiedTimeStamp);
|
||||
|
||||
$sRotatedLogFile = $oFileBuilder->GetRotatedFileName($oLogFileLastModified);
|
||||
$oFileBuilder->CheckAndRotateLogFile();
|
||||
$this->assertFileExists($sLogFile, 'Test log file modification date is today, original file still exists after rotation call');
|
||||
$this->assertFileNotExists($sRotatedLogFile, 'No rotation occurred yet');
|
||||
|
||||
$oTimeYesterday = new DateTime('yesterday');
|
||||
$sRotatedLogFile = $oFileBuilder->GetRotatedFileName($oTimeYesterday);
|
||||
$this->ChangeFileModificationDate($sLogFile, $oTimeYesterday);
|
||||
|
||||
// changing modification date, but do not reset cached filebuilder date => no change
|
||||
$oFileBuilder->CheckAndRotateLogFile();
|
||||
$this->assertFileExists($sLogFile, 'Test log file modification date is yesterday but filebuilder use its cache, original file still exists after rotation call');
|
||||
$this->assertFileNotExists($sRotatedLogFile, 'No rotation occurred yet');
|
||||
|
||||
// changing modification date AND resetting filebuilder date cache
|
||||
$oFileBuilder->ResetLastModifiedDateForFile();
|
||||
$oFileBuilder->CheckAndRotateLogFile();
|
||||
$this->assertFileNotExists($sLogFile, 'Test log file modification date is yesterday, file rotated !');
|
||||
$this->assertFileExists($sRotatedLogFile, 'Rotation was done');
|
||||
|
||||
// file cleanup will be done in tearDown !
|
||||
}
|
||||
|
||||
public function ShouldRotateProvider()
|
||||
{
|
||||
return array(
|
||||
'DAILY Same day' => array('DailyRotatingLogFileNameBuilder', '2020-02-01 00:00', '2020-02-01 15:42', false),
|
||||
'DAILY Same week, different day less 24h diff' => array('DailyRotatingLogFileNameBuilder', '2020-02-01 12:00', '2020-02-02 09:00', true),
|
||||
'DAILY Same week, different day' => array('DailyRotatingLogFileNameBuilder', '2020-02-01 00:00', '2020-02-02 00:00', true),
|
||||
'DAILY 1 week diff' => array('DailyRotatingLogFileNameBuilder', '2020-02-01 00:00', '2020-02-08 00:00', true),
|
||||
'WEEKLY Same week' => array('WeeklyRotatingLogFileNameBuilder', '2020-02-01 00:00', '2020-02-01 00:00', false),
|
||||
'WEEKLY 1 week diff, same month' => array('WeeklyRotatingLogFileNameBuilder', '2020-02-01 00:00', '2020-02-08 00:00', true),
|
||||
'WEEKLY 2 weeks diff, same month' => array('WeeklyRotatingLogFileNameBuilder', '2020-02-01 00:00', '2020-02-15 00:00', true),
|
||||
'WEEKLY 1 week diff, different month' => array('WeeklyRotatingLogFileNameBuilder', '2020-01-27 00:00', '2020-02-03 00:00', true),
|
||||
'WEEKLY same week, different month' => array('WeeklyRotatingLogFileNameBuilder', '2020-01-27 00:00', '2020-02-02 00:00', false),
|
||||
'WEEKLY 1 week diff, different year' => array('WeeklyRotatingLogFileNameBuilder', '2019-12-30 00:00', '2020-01-06 00:00', true),
|
||||
'WEEKLY same week, different year' => array('WeeklyRotatingLogFileNameBuilder', '2019-12-30 00:00', '2020-01-05 00:00', true),
|
||||
'MONTHLY same month' => array('MonthlyRotatingLogFileNameBuilder', '2020-02-10 00:00', '2020-02-14 00:00', false),
|
||||
'MONTHLY on first day which is a sunday' => array('MonthlyRotatingLogFileNameBuilder', '2020-01-30 00:00', '2020-02-01 00:00', true),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sFileNameBuilderClass RotatingLogFileNameBuilder impl
|
||||
* @param string $sDateModified format Y-m-d H:i
|
||||
* @param string $sDateNow format Y-m-d H:i
|
||||
* @param bool $bExpected
|
||||
*
|
||||
* @dataProvider ShouldRotateProvider
|
||||
*/
|
||||
public function testShouldRotate($sFileNameBuilderClass, $sDateModified, $sDateNow, $bExpected)
|
||||
{
|
||||
$oDateModified = DateTime::createFromFormat('Y-m-d H:i', $sDateModified);
|
||||
$oDateNow = DateTime::createFromFormat('Y-m-d H:i', $sDateNow);
|
||||
|
||||
/** @var \RotatingLogFileNameBuilder $oFileBuilder */
|
||||
$oFileBuilder = new $sFileNameBuilderClass();
|
||||
$bShouldRotate = $oFileBuilder->ShouldRotate($oDateModified, $oDateNow);
|
||||
|
||||
$this->assertEquals($bExpected, $bShouldRotate);
|
||||
}
|
||||
|
||||
public function CronNextOccurrenceProvider()
|
||||
{
|
||||
return array(
|
||||
'DAILY morning' => array('DailyRotatingLogFileNameBuilder', '2020-02-01 05:00', '2020-02-02 00:00'),
|
||||
'DAILY midnight' => array('DailyRotatingLogFileNameBuilder', '2020-02-01 00:00', '2020-02-02 00:00'),
|
||||
'WEEKLY monday 12:42' => array('WeeklyRotatingLogFileNameBuilder', '2020-02-03 12:42', '2020-02-10 00:00'),
|
||||
'WEEKLY monday 00:00' => array('WeeklyRotatingLogFileNameBuilder', '2020-02-03 00:00', '2020-02-10 00:00'),
|
||||
'WEEKLY tuesday 12:42' => array('WeeklyRotatingLogFileNameBuilder', '2020-02-04 12:42', '2020-02-10 00:00'),
|
||||
'WEEKLY sunday 12:42' => array('WeeklyRotatingLogFileNameBuilder', '2020-02-02 12:42', '2020-02-03 00:00'),
|
||||
'MONTHLY 12/02 12:42' => array('MonthlyRotatingLogFileNameBuilder', '2020-02-12 12:42', '2020-03-01 00:00'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sFileNameBuilderClass RotatingLogFileNameBuilder impl
|
||||
* @param string $sDateNow format Y-m-d H:i
|
||||
* @param string $sExpectedOccurrence format Y-m-d H:i
|
||||
*
|
||||
* @dataProvider CronNextOccurrenceProvider
|
||||
*/
|
||||
public function testCronNextOccurrence($sFileNameBuilderClass, $sDateNow, $sExpectedOccurrence)
|
||||
{
|
||||
$oDateNow = DateTime::createFromFormat('Y-m-d H:i', $sDateNow);
|
||||
|
||||
/** @var \RotatingLogFileNameBuilder $oFileBuilder */
|
||||
$oFileBuilder = new $sFileNameBuilderClass();
|
||||
$oActualOccurrence = $oFileBuilder->GetCronProcessNextOccurrence($oDateNow);
|
||||
$sActualOccurrence = $oActualOccurrence->format('Y-m-d H:i');
|
||||
|
||||
$this->assertEquals($sExpectedOccurrence, $sActualOccurrence);
|
||||
}
|
||||
}
|
||||
86
tests/php-unit-tests/unitary-tests/core/MetaModelTest.php
Normal file
86
tests/php-unit-tests/unitary-tests/core/MetaModelTest.php
Normal file
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Core;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use MetaModel;
|
||||
|
||||
/**
|
||||
* Class MetaModelTest
|
||||
*
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*
|
||||
* @since 2.6.0
|
||||
* @package Combodo\iTop\Test\UnitTest\Core
|
||||
*/
|
||||
class MetaModelTest extends ItopDataTestCase
|
||||
{
|
||||
protected static $iDefaultUserOrgId = 1;
|
||||
protected static $iDefaultUserCallerId = 1;
|
||||
protected static $sDefaultUserRequestTitle = 'Unit test title';
|
||||
protected static $sDefaultUserRequestDescription = 'Unit test description';
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
require_once APPROOT.'/core/metamodel.class.php';
|
||||
require_once APPROOT.'/core/coreexception.class.inc.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers MetaModel::ApplyParams()
|
||||
* @dataProvider ApplyParamsProvider
|
||||
*
|
||||
* @param string $sInput
|
||||
* @param array $aParams
|
||||
* @param string $sExpectedOutput
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function testApplyParams($sInput, $aParams, $sExpectedOutput)
|
||||
{
|
||||
$oUserRequest = $this->createObject(
|
||||
'UserRequest',
|
||||
array(
|
||||
'org_id' => static::$iDefaultUserOrgId,
|
||||
'caller_id' => static::$iDefaultUserCallerId,
|
||||
'title' => static::$sDefaultUserRequestTitle,
|
||||
'description' => static::$sDefaultUserRequestDescription,
|
||||
)
|
||||
);
|
||||
|
||||
$aParams['this->object()'] = $oUserRequest;
|
||||
|
||||
$sGeneratedOutput = MetaModel::ApplyParams($sInput, $aParams);
|
||||
|
||||
$this->assertEquals($sExpectedOutput, $sGeneratedOutput, "ApplyParams test returned $sGeneratedOutput");
|
||||
}
|
||||
|
||||
public function ApplyParamsProvider()
|
||||
{
|
||||
$sTitle = static::$sDefaultUserRequestTitle;
|
||||
|
||||
$aParams = array();
|
||||
|
||||
return array(
|
||||
'Object string attribute (text format)' => array(
|
||||
'Title: $this->title$',
|
||||
$aParams,
|
||||
'Title: '.$sTitle,
|
||||
),
|
||||
'Object string attribute (html format)' => array(
|
||||
'Title: <p>$this->title$</p>',
|
||||
$aParams,
|
||||
'Title: <p>'.$sTitle.'</p>',
|
||||
),
|
||||
'Object string attribute urlencoded (html format)' => array(
|
||||
'Title: <a href="http://foo.bar/%24this->title%24">Hyperlink</a>',
|
||||
$aParams,
|
||||
'Title: <a href="http://foo.bar/'.$sTitle.'">Hyperlink</a>',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
86
tests/php-unit-tests/unitary-tests/core/OQLParserTest.php
Normal file
86
tests/php-unit-tests/unitary-tests/core/OQLParserTest.php
Normal file
File diff suppressed because one or more lines are too long
507
tests/php-unit-tests/unitary-tests/core/OQLTest.php
Normal file
507
tests/php-unit-tests/unitary-tests/core/OQLTest.php
Normal file
@@ -0,0 +1,507 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Eric
|
||||
* Date: 31/08/2018
|
||||
* Time: 17:03
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Core;
|
||||
|
||||
|
||||
use CMDBSource;
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use DBObjectSearch;
|
||||
use DBSearch;
|
||||
use Exception;
|
||||
use MetaModel;
|
||||
use OqlInterpreter;
|
||||
use QueryBuilderContext;
|
||||
use SQLObjectQueryBuilder;
|
||||
use utils;
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class OQLTest extends ItopDataTestCase
|
||||
{
|
||||
const USE_TRANSACTION = false;
|
||||
|
||||
/**
|
||||
* @doesNotPerformAssertions
|
||||
*
|
||||
* @throws \ConfigException
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function testOQLSetup()
|
||||
{
|
||||
utils::GetConfig()->Set('use_legacy_dbsearch', false, 'test');
|
||||
utils::GetConfig()->Set('apc_cache.enabled', false, 'test');
|
||||
utils::GetConfig()->Set('query_cache_enabled', false, 'test');
|
||||
utils::GetConfig()->Set('expression_cache_enabled', false, 'test');
|
||||
$sConfigFile = utils::GetConfig()->GetLoadedFile();
|
||||
@chmod($sConfigFile, 0770);
|
||||
utils::GetConfig()->WriteToFile();
|
||||
@chmod($sConfigFile, 0444); // Read-only
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider NestedQueryProvider
|
||||
* @depends testOQLSetup
|
||||
*
|
||||
* @param $sQuery
|
||||
*
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function testGoodNestedQueryQueryParser($sQuery)
|
||||
{
|
||||
$this->debug($sQuery);
|
||||
$oOql = new OqlInterpreter($sQuery);
|
||||
$oQuery = $oOql->ParseQuery();
|
||||
static::assertInstanceOf('OqlQuery', $oQuery);
|
||||
}
|
||||
|
||||
public function NestedQueryProvider()
|
||||
{
|
||||
return array(
|
||||
array("SELECT User AS U JOIN Person AS P ON U.contactid = P.id WHERE U.status='enabled' AND U.id NOT IN (SELECT User AS U JOIN Person AS P ON U.contactid=P.id JOIN URP_UserOrg AS L ON L.userid = U.id WHERE U.status='enabled' AND L.allowed_org_id = P.org_id UNION SELECT User AS U WHERE U.status='enabled' AND U.id NOT IN ( SELECT User AS U JOIN URP_UserOrg AS L ON L.userid = U.id WHERE U.status='enabled'))"),
|
||||
array('SELECT `UserRequest` FROM UserRequest AS `UserRequest` WHERE `UserRequest`.org_id IN (SELECT `Organization` FROM Organization AS `Organization` JOIN Organization AS `Organization1` ON `Organization`.parent_id BELOW `Organization1`.id WHERE (`Organization1`.`id` = \'3\'))'),
|
||||
array('SELECT `UserRequest` FROM UserRequest AS `UserRequest` WHERE (`UserRequest`.`org_id` IN (SELECT `Organization` FROM Organization AS `Organization` WHERE `Organization`.`id`=`UserRequest`.`org_id`))'),
|
||||
array("SELECT UserRequest AS Ur WHERE Ur.id NOT IN (SELECT UserRequest AS Ur JOIN lnkFunctionalCIToTicket AS lnk ON lnk.ticket_id = Ur.id)"),
|
||||
array("SELECT Ticket AS T WHERE T. finalclass IN ('userrequest' , 'change') AND T.id NOT IN (SELECT UserRequest AS Ur JOIN lnkFunctionalCIToTicket AS lnk ON lnk.ticket_id = Ur.id UNION SELECT Change AS C JOIN lnkFunctionalCIToTicket AS lnk ON lnk.ticket_id = C.id)"),
|
||||
array("SELECT PhysicalDevice WHERE status='production' AND id NOT IN (SELECT PhysicalDevice AS p JOIN lnkFunctionalCIToProviderContract AS l ON l.functionalci_id=p.id)"),
|
||||
array("SELECT Team WHERE id NOT IN (SELECT Team AS t JOIN lnkPersonToTeam AS l ON l.team_id=t.id WHERE 1)"),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider GoodQueryProvider
|
||||
* @depends testOQLSetup
|
||||
*
|
||||
* @param $sQuery
|
||||
*
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function testGoodQueryParser($sQuery)
|
||||
{
|
||||
$this->debug($sQuery);
|
||||
$oOql = new OqlInterpreter($sQuery);
|
||||
$oQuery = $oOql->ParseQuery();
|
||||
static::assertInstanceOf('OqlQuery', $oQuery);
|
||||
}
|
||||
|
||||
public function GoodQueryProvider()
|
||||
{
|
||||
return array(
|
||||
array('SELECT toto'),
|
||||
array('SELECT toto WHERE toto.a = 1'),
|
||||
array('SELECT toto WHERE toto.a = -1'),
|
||||
array('SELECT toto WHERE toto.a = (1-1)'),
|
||||
array('SELECT toto WHERE toto.a = (-1+3)'),
|
||||
array('SELECT toto WHERE toto.a = (3+-1)'),
|
||||
array('SELECT toto WHERE toto.a = (3--1)'),
|
||||
array('SELECT toto WHERE toto.a = 0xC'),
|
||||
array('SELECT toto WHERE toto.a = \'AXDVFS0xCZ32\''),
|
||||
array('SELECT toto WHERE toto.a = :myparameter'),
|
||||
array('SELECT toto WHERE toto.a IN (:param1)'),
|
||||
array('SELECT toto WHERE toto.a IN (:param1, :param2)'),
|
||||
array('SELECT toto WHERE toto.a=1'),
|
||||
array('SELECT toto WHERE toto.a = "1"'),
|
||||
array('SELECT toto WHERE toto.a & 1'),
|
||||
array('SELECT toto WHERE toto.a | 1'),
|
||||
array('SELECT toto WHERE toto.a ^ 1'),
|
||||
array('SELECT toto WHERE toto.a << 1'),
|
||||
array('SELECT toto WHERE toto.a >> 1'),
|
||||
array('SELECT toto WHERE toto.a NOT LIKE "That\'s it"'),
|
||||
array('SELECT toto WHERE toto.a NOT LIKE "That\'s \\"it\\""'),
|
||||
array('SELECT toto WHERE toto.a NOT LIKE \'That"s it\''),
|
||||
array('SELECT toto WHERE toto.a NOT LIKE \'That\\\'s it\''),
|
||||
array('SELECT toto WHERE toto.a NOT LIKE "blah \\\\ truc"'),
|
||||
array('SELECT toto WHERE toto.a NOT LIKE \'blah \\\\ truc\''),
|
||||
array('SELECT toto WHERE toto.a NOT LIKE "\\\\"'),
|
||||
array('SELECT toto WHERE toto.a NOT LIKE "\\""'),
|
||||
array('SELECT toto WHERE toto.a NOT LIKE "\\"\\\\"'),
|
||||
array('SELECT toto WHERE toto.a NOT LIKE "\\\\\\""'),
|
||||
array('SELECT toto WHERE toto.a NOT LIKE ""'),
|
||||
array('SELECT toto WHERE toto.a NOT LIKE "blah" AND toto.b LIKE "foo"'),
|
||||
array('SELECT toto WHERE toto.a = 1 AND toto.b LIKE "x" AND toto.f >= 12345'),
|
||||
array('SELECT Device JOIN Site ON Device.site = Site.id'),
|
||||
array('SELECT Device JOIN Site ON Device.site = Site.id JOIN Country ON Site.location = Country.id'),
|
||||
array('SELECT UserRightsMatrixClassGrant WHERE UserRightsMatrixClassGrant.class = \'lnkContactRealObject\' AND UserRightsMatrixClassGrant.action = \'modify\' AND UserRightsMatrixClassGrant.login = \'Denis\''),
|
||||
array('SELECT A WHERE A.col1 = \'lit1\' AND A.col2 = \'lit2\' AND A.col3 = \'lit3\''),
|
||||
array('SELECT A JOIN B ON A.myB = B.id WHERE (A.col1 = 123 AND B.col1 = \'aa\') OR (A.col3 = \'zzz\' AND B.col4 > 100)'),
|
||||
array('SELECT A JOIN B ON A.myB = B.id WHERE (A.col1 = B.col2 AND B.col1 = A.col2) OR (A.col3 = \'\' AND B.col4 > 100)'),
|
||||
array('SELECT A JOIN B ON A.myB = B.id WHERE A.col1 + B.col2 * B.col1 = A.col2'),
|
||||
array('SELECT A JOIN B ON A.myB = B.id WHERE A.col1 + (B.col2 * B.col1) = A.col2'),
|
||||
array('SELECT A JOIN B ON A.myB = B.id WHERE (A.col1 + B.col2) * B.col1 = A.col2'),
|
||||
array('SELECT A JOIN B ON A.myB = B.id WHERE (A.col1 & B.col2) = A.col2'),
|
||||
array('SELECT Device AS D_ JOIN Site AS S_ ON D_.site = S_.id WHERE S_.country = "Francia"'),
|
||||
array('SELECT A FROM A'),
|
||||
array('SELECT A JOIN B ON A.myB = B.id WHERE A.col1 = 2'),
|
||||
array('SELECT A FROM A JOIN B ON A.myB = B.id WHERE A.col1 = 2'),
|
||||
array('SELECT B FROM A JOIN B ON A.myB = B.id WHERE A.col1 = 2'),
|
||||
array('SELECT A,B FROM A JOIN B ON A.myB = B.id WHERE A.col1 = 2'),
|
||||
array('SELECT A, B FROM A JOIN B ON A.myB = B.id WHERE A.col1 = 2'),
|
||||
array('SELECT B,A FROM A JOIN B ON A.myB = B.id WHERE A.col1 = 2'),
|
||||
array('SELECT A, B,C FROM A JOIN B ON A.myB = B.id'),
|
||||
array('SELECT C FROM A JOIN B ON A.myB = B.id WHERE A.col1 = 2'),
|
||||
array('SELECT A JOIN B ON A.myB BELOW B.id WHERE A.col1 = 2'),
|
||||
array('SELECT A JOIN B ON B.myA BELOW A.id WHERE A.col1 = 2'),
|
||||
array('SELECT A JOIN B ON A.myB = B.id JOIN C ON C.parent_id BELOW B.id WHERE A.col1 = 2 AND B.id = 3'),
|
||||
array('SELECT A JOIN B ON A.myB = B.id JOIN C ON C.parent_id BELOW STRICT B.id WHERE A.col1 = 2 AND B.id = 3'),
|
||||
array('SELECT A JOIN B ON A.myB = B.id JOIN C ON C.parent_id NOT BELOW B.id WHERE A.col1 = 2 AND B.id = 3'),
|
||||
array('SELECT A JOIN B ON A.myB = B.id JOIN C ON C.parent_id NOT BELOW STRICT B.id WHERE A.col1 = 2 AND B.id = 3'),
|
||||
array('SELECT A UNION SELECT B'),
|
||||
array('SELECT A WHERE A.b = "sdf" UNION SELECT B WHERE B.a = "sfde"'),
|
||||
array('SELECT A UNION SELECT B UNION SELECT C'),
|
||||
array('SELECT A UNION SELECT B UNION SELECT C UNION SELECT D'),
|
||||
array('SELECT A JOIN B ON A.myB = B.id JOIN C ON C.parent_id NOT BELOW B.id WHERE A.col1 = 2 AND B.id = 3 UNION SELECT Device JOIN Site ON Device.site = Site.id JOIN Country ON Site.location = Country.id'),
|
||||
array('SELECT Person AS B WHERE B.name LIKE \'%A%\''),
|
||||
array('SELECT Server WHERE name REGEXP \'dbserver[0-9]+\''),
|
||||
array('SELECT Server WHERE name REGEXP \'^dbserver[0-9]+\\\\..+\\\\.[a-z]{2,3}$\''),
|
||||
array('SELECT Change AS ch WHERE ch.start_date >= \'2009-12-31\' AND ch.end_date <= \'2010-01-01\''),
|
||||
array('SELECT DatacenterDevice AS dev WHERE INET_ATON(dev.managementip) > INET_ATON(\'10.22.32.224\') AND INET_ATON(dev.managementip) < INET_ATON(\'10.22.32.255\')'),
|
||||
array('SELECT Person AS P JOIN Organization AS Node ON P.org_id = Node.id JOIN Organization AS Root ON Node.parent_id BELOW Root.id WHERE Root.id=1'),
|
||||
array('SELECT PhysicalInterface AS if JOIN DatacenterDevice AS dev ON if.connectableci_id = dev.id WHERE dev.status = \'production\' AND dev.organization_name = \'Demo\''),
|
||||
array('SELECT Ticket AS t WHERE t.agent_id = :current_contact_id'),
|
||||
array('SELECT Person AS p JOIN UserRequest AS u ON u.agent_id = p.id WHERE u.status != \'closed\''),
|
||||
array('SELECT Contract AS c WHERE c.end_date > NOW() AND c.end_date < DATE_ADD(NOW(), INTERVAL 30 DAY)'),
|
||||
array('SELECT UserRequest AS u WHERE u.start_date < DATE_SUB(NOW(), INTERVAL 60 MINUTE) AND u.status = \'new\''),
|
||||
array('SELECT UserRequest AS u WHERE u.close_date > DATE_ADD(u.start_date, INTERVAL 8 HOUR)'),
|
||||
array('SELECT Ticket WHERE tagfield MATCHES \'salad\''),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider BadQueryProvider
|
||||
* @depends testOQLSetup
|
||||
*
|
||||
* @param $sQuery
|
||||
* @param $sExpectedExceptionClass
|
||||
*
|
||||
*/
|
||||
public function testBadQueryParser($sQuery, $sExpectedExceptionClass)
|
||||
{
|
||||
$this->debug($sQuery);
|
||||
$oOql = new OqlInterpreter($sQuery);
|
||||
$sExceptionClass = '';
|
||||
try
|
||||
{
|
||||
$oOql->ParseQuery();
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
$sExceptionClass = get_class($e);
|
||||
}
|
||||
|
||||
static::assertEquals($sExpectedExceptionClass, $sExceptionClass);
|
||||
}
|
||||
|
||||
public function BadQueryProvider()
|
||||
{
|
||||
return array(
|
||||
array('SELECT toto WHERE toto.a = (3++1)', 'OQLParserSyntaxErrorException'),
|
||||
array('SELECT toto WHHHERE toto.a = "1"', 'OQLParserSyntaxErrorException'),
|
||||
array('SELECT toto WHERE toto.a == "1"', 'OQLParserSyntaxErrorException'),
|
||||
array('SELECT toto WHERE toto.a % 1', 'Exception'),
|
||||
array('SELECT toto WHERE toto.a like \'arg\'', 'OQLParserSyntaxErrorException'),
|
||||
array('SELECT toto WHERE toto.a NOT LIKE "That\'s "it""', 'OQLParserSyntaxErrorException'),
|
||||
array('SELECT toto WHERE toto.a NOT LIKE \'That\'s it\'', 'OQLParserSyntaxErrorException'),
|
||||
array('SELECT toto WHERE toto.a NOT LIKE "blah \\ truc"', 'Exception'),
|
||||
array('SELECT toto WHERE toto.a NOT LIKE \'blah \\ truc\'', 'Exception'),
|
||||
array('SELECT A JOIN B ON A.myB = B.id JOIN C ON C.parent_id = B.id WHERE A.col1 BELOW 2 AND B.id = 3', 'OQLParserSyntaxErrorException'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Needs actual datamodel
|
||||
* @depends testOQLSetup
|
||||
*
|
||||
* @dataProvider QueryNormalizationProvider
|
||||
*
|
||||
* @param $sQuery
|
||||
* @param $sExpectedExceptionClass
|
||||
*
|
||||
*/
|
||||
public function testQueryNormalization($sQuery, $sExpectedExceptionClass)
|
||||
{
|
||||
$this->debug($sQuery);
|
||||
$sExceptionClass = '';
|
||||
try
|
||||
{
|
||||
$oSearch = DBObjectSearch::FromOQL($sQuery);
|
||||
static::assertInstanceOf('DBObjectSearch', $oSearch);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
$sExceptionClass = get_class($e);
|
||||
}
|
||||
|
||||
static::assertEquals($sExpectedExceptionClass, $sExceptionClass);
|
||||
}
|
||||
|
||||
|
||||
public function QueryNormalizationProvider()
|
||||
{
|
||||
return array(
|
||||
array('SELECT Contact', ''),
|
||||
array('SELECT Contact WHERE nom_de_famille = "foo"', 'OqlNormalizeException'),
|
||||
array('SELECT Contact AS c WHERE name = "foo"', ''),
|
||||
array('SELECT Contact AS c WHERE nom_de_famille = "foo"', 'OqlNormalizeException'),
|
||||
array('SELECT Contact AS c WHERE c.name = "foo"', ''),
|
||||
array('SELECT Contact AS c WHERE Contact.name = "foo"', 'OqlNormalizeException'),
|
||||
array('SELECT Contact AS c WHERE x.name = "foo"', 'OqlNormalizeException'),
|
||||
|
||||
array('SELECT Organization AS child JOIN Organization AS root ON child.parent_id BELOW root.id', ''),
|
||||
array('SELECT Organization AS root JOIN Organization AS child ON child.parent_id BELOW root.id', ''),
|
||||
|
||||
array('SELECT RelationProfessionnelle', 'UnknownClassOqlException'),
|
||||
array('SELECT RelationProfessionnelle AS c WHERE name = "foo"', 'UnknownClassOqlException'),
|
||||
|
||||
// The first query is the base query altered only in one place in the subsequent queries
|
||||
array('SELECT Person AS p JOIN lnkPersonToTeam AS lnk ON lnk.person_id = p.id WHERE p.name LIKE "foo"', ''),
|
||||
array('SELECT Person AS p JOIN lnkXXXXXXXXXXXX AS lnk ON lnk.person_id = p.id WHERE p.name LIKE "foo"', 'UnknownClassOqlException'),
|
||||
array('SELECT Person AS p JOIN lnkPersonToTeam AS lnk ON p.person_id = p.id WHERE p.name LIKE "foo"', 'OqlNormalizeException'),
|
||||
array('SELECT Person AS p JOIN lnkPersonToTeam AS lnk ON person_id = p.id WHERE p.name LIKE "foo"', 'OqlNormalizeException'),
|
||||
array('SELECT Person AS p JOIN lnkPersonToTeam AS lnk ON lnk.person_id = id WHERE p.name LIKE "foo"', 'OqlNormalizeException'),
|
||||
array('SELECT Person AS p JOIN lnkPersonToTeam AS lnk ON lnk.role = p.id WHERE p.name LIKE "foo"', 'OqlNormalizeException'),
|
||||
array('SELECT Person AS p JOIN lnkPersonToTeam AS lnk ON lnk.team_id = p.id WHERE p.name LIKE "foo"', 'OqlNormalizeException'),
|
||||
array('SELECT Person AS p JOIN lnkPersonToTeam AS lnk ON lnk.person_id BELOW p.id WHERE p.name LIKE "bar"', ''),
|
||||
array('SELECT Person AS p JOIN lnkPersonToTeam AS lnk ON lnk.person_id = p.org_id WHERE p.name LIKE "foo"', 'OqlNormalizeException'),
|
||||
array('SELECT Person AS p JOIN lnkPersonToTeam AS lnk ON p.id = lnk.person_id WHERE p.name LIKE "foo"', 'OqlNormalizeException'), // inverted the JOIN spec
|
||||
array('SELECT Person AS p JOIN lnkPersonToTeam AS lnk ON lnk.person_id = p.id WHERE name LIKE "foo"', ''),
|
||||
array('SELECT Person AS p JOIN lnkPersonToTeam AS lnk ON lnk.person_id = p.id WHERE x.name LIKE "foo"', 'OqlNormalizeException'),
|
||||
array('SELECT Person AS p JOIN lnkPersonToTeam AS lnk ON lnk.person_id = p.id WHERE p.eman LIKE "foo"', 'OqlNormalizeException'),
|
||||
array('SELECT Person AS p JOIN lnkPersonToTeam AS lnk ON lnk.person_id = p.id WHERE eman LIKE "foo"', 'OqlNormalizeException'),
|
||||
array('SELECT Person AS p JOIN lnkPersonToTeam AS lnk ON lnk.person_id = p.id WHERE id = 1', 'OqlNormalizeException'),
|
||||
array('SELECT Person AS p JOIN lnkPersonToTeam AS lnk ON p.id = lnk.person_id WHERE p.name LIKE "foo"', 'OqlNormalizeException'),
|
||||
|
||||
array('SELECT Person AS p JOIN Organization AS o ON p.org_id = o.id WHERE p.name LIKE "foo" AND o.name LIKE "land"', ''),
|
||||
array('SELECT Person AS p JOIN Organization AS o ON p.location_id = o.id WHERE p.name LIKE "foo" AND o.name LIKE "land"', 'OqlNormalizeException'),
|
||||
array('SELECT Person AS p JOIN Organization AS o ON p.name = o.id WHERE p.name LIKE "foo" AND o.name LIKE "land"', 'OqlNormalizeException'),
|
||||
|
||||
array('SELECT Person AS p JOIN Organization AS o ON p.org_id = o.id JOIN Person AS p ON p.org_id = o.id', 'OqlNormalizeException'),
|
||||
array('SELECT Person JOIN Organization AS o ON Person.org_id = o.id JOIN Person ON Person.org_id = o.id', 'OqlNormalizeException'),
|
||||
|
||||
array('SELECT Person AS p JOIN Location AS l ON p.location_id = l.id', ''),
|
||||
array('SELECT Person AS p JOIN Location AS l ON p.location_id BELOW l.id', 'OqlNormalizeException'),
|
||||
|
||||
array('SELECT Person FROM Person JOIN Location ON Person.location_id = Location.id', ''),
|
||||
array('SELECT p FROM Person AS p JOIN Location AS l ON p.location_id = l.id', ''),
|
||||
array('SELECT l FROM Person AS p JOIN Location AS l ON p.location_id = l.id', ''),
|
||||
array('SELECT l, p FROM Person AS p JOIN Location AS l ON p.location_id = l.id', ''),
|
||||
array('SELECT p, l FROM Person AS p JOIN Location AS l ON p.location_id = l.id', ''),
|
||||
array('SELECT foo FROM Person AS p JOIN Location AS l ON p.location_id = l.id', 'OqlNormalizeException'),
|
||||
array('SELECT p, foo FROM Person AS p JOIN Location AS l ON p.location_id = l.id', 'OqlNormalizeException'),
|
||||
|
||||
// Joins based on AttributeObjectKey
|
||||
//
|
||||
array('SELECT Attachment AS a JOIN UserRequest AS r ON a.item_id = r.id', ''),
|
||||
array('SELECT UserRequest AS r JOIN Attachment AS a ON a.item_id = r.id', ''),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @depends testOQLSetup
|
||||
* @dataProvider OQLIntersectProvider
|
||||
*
|
||||
* Needs specific datamodel from unit-test-specific module
|
||||
* for lnkGRTypeToServiceSubcategory and GRType classes
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function testOQLIntersect($sOQL1, $sOQL2, $sOQLIntersect)
|
||||
{
|
||||
// Check that legacy mode is not set
|
||||
$this->assertFalse(utils::GetConfig()->Get('use_legacy_dbsearch'));
|
||||
$this->assertFalse(utils::GetConfig()->Get('apc_cache.enabled'));
|
||||
$this->assertFalse(utils::GetConfig()->Get('query_cache_enabled'));
|
||||
$this->assertFalse(utils::GetConfig()->Get('expression_cache_enabled'));
|
||||
|
||||
$oSearch1 = DBSearch::FromOQL($sOQL1);
|
||||
$oSearch2 = DBSearch::FromOQL($sOQL2);
|
||||
$oSearchI = $oSearch1->Intersect($oSearch2);
|
||||
|
||||
$sOQLResult = $oSearchI->ToOQL();
|
||||
//$this->debug($sOQLResult);
|
||||
|
||||
self::assertEquals($sOQLIntersect, $sOQLResult);
|
||||
}
|
||||
|
||||
public function OQLIntersectProvider()
|
||||
{
|
||||
return array(
|
||||
// Wrong result:
|
||||
/*
|
||||
SELECT `SSC`
|
||||
FROM ServiceSubcategory AS `SSC`
|
||||
JOIN Service AS `S` ON `SSC`.service_id = `S`.id
|
||||
JOIN lnkCustomerContractToService AS `l1` ON `l1`.service_id = `S`.id
|
||||
JOIN CustomerContract AS `cc` ON `l1`.customercontract_id = `cc`.id
|
||||
JOIN lnkGRTypeToServiceSubcategory AS `l1` ON `l1`.servicesubcategory_id = `SSC`.id
|
||||
JOIN GRType AS `GRT` ON `l1`.grtype_id = `GRT`.id
|
||||
WHERE ((`GRT`.`id` = :grtype_id) AND ((`cc`.`org_id` = :current_contact->org_id) AND (`SSC`.`status` != 'obsolete')))
|
||||
*/
|
||||
// Needs specific data model from unit-test-specific module for lnkGRTypeToServiceSubcategory and GRType classes
|
||||
// 'ServiceSubcategory' => array(
|
||||
// "SELECT ServiceSubcategory AS SSC JOIN lnkGRTypeToServiceSubcategory AS l1 ON l1.servicesubcategory_id = SSC.id JOIN GRType AS GRT ON l1.grtype_id = GRT.id JOIN Service AS S ON SSC.service_id = S.id WHERE GRT.id = :grtype_id",
|
||||
// "SELECT ServiceSubcategory AS ssc JOIN Service AS s ON ssc.service_id=s.id JOIN lnkCustomerContractToService AS l1 ON l1.service_id=s.id JOIN CustomerContract AS cc ON l1.customercontract_id=cc.id WHERE cc.org_id = :current_contact->org_id AND ssc.status != 'obsolete'",
|
||||
// "SELECT `SSC` FROM ServiceSubcategory AS `SSC` JOIN Service AS `S` ON `SSC`.service_id = `S`.id JOIN lnkCustomerContractToService AS `l11` ON `l11`.service_id = `S`.id JOIN CustomerContract AS `cc` ON `l11`.customercontract_id = `cc`.id JOIN lnkGRTypeToServiceSubcategory AS `l1` ON `l1`.servicesubcategory_id = `SSC`.id JOIN GRType AS `GRT` ON `l1`.grtype_id = `GRT`.id WHERE ((`GRT`.`id` = :grtype_id) AND ((`cc`.`org_id` = :current_contact->org_id) AND (`SSC`.`status` != 'obsolete')))"
|
||||
// ),
|
||||
'Person' => array(
|
||||
"SELECT P FROM Person AS P JOIN lnkPersonToTeam AS l1 ON l1.person_id = P.id JOIN Team AS T ON l1.team_id = T.id WHERE T.id = 3",
|
||||
"SELECT p FROM Person AS p JOIN Person AS mgr ON p.manager_id = mgr.id JOIN lnkContactToTicket AS l1 ON l1.contact_id = mgr.id JOIN Ticket AS T ON l1.ticket_id = T.id WHERE T.id = 4 AND p.id = 3",
|
||||
"SELECT `P` FROM Person AS `P` JOIN Person AS `mgr` ON `P`.manager_id = `mgr`.id JOIN lnkContactToTicket AS `l11` ON `l11`.contact_id = `mgr`.id JOIN Ticket AS `T1` ON `l11`.ticket_id = `T1`.id JOIN lnkPersonToTeam AS `l1` ON `l1`.person_id = `P`.id JOIN Team AS `T` ON `l1`.team_id = `T`.id WHERE ((`T`.`id` = 3) AND ((`T1`.`id` = 4) AND (`P`.`id` = 3)))"
|
||||
),
|
||||
'Person2' => array(
|
||||
"SELECT P FROM Person AS P JOIN lnkPersonToTeam AS l1 ON l1.person_id = P.id JOIN Team AS T ON l1.team_id = T.id JOIN Person AS MGR ON P.manager_id = MGR.id WHERE T.id = 3",
|
||||
"SELECT p FROM Person AS p JOIN Person AS mgr ON p.manager_id = mgr.id JOIN lnkContactToTicket AS l1 ON l1.contact_id = mgr.id JOIN Ticket AS T ON l1.ticket_id = T.id WHERE T.id = 4 AND p.id = 3",
|
||||
"SELECT `P` FROM Person AS `P` JOIN Person AS `MGR` ON `P`.manager_id = `MGR`.id JOIN lnkContactToTicket AS `l11` ON `l11`.contact_id = `MGR`.id JOIN Ticket AS `T1` ON `l11`.ticket_id = `T1`.id JOIN lnkPersonToTeam AS `l1` ON `l1`.person_id = `P`.id JOIN Team AS `T` ON `l1`.team_id = `T`.id WHERE ((`T`.`id` = 3) AND ((`T1`.`id` = 4) AND (`P`.`id` = 3)))"
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider MakeSelectQueryProvider
|
||||
* @param $sOQL
|
||||
* @param $sExpectedExceptionClass
|
||||
*/
|
||||
public function testMakeSelectQuery($sOQL, $sExpectedExceptionClass = '')
|
||||
{
|
||||
$sExceptionClass = '';
|
||||
try
|
||||
{
|
||||
$oSearch = DBSearch::FromOQL($sOQL);
|
||||
CMDBSource::TestQuery($oSearch->MakeSelectQuery());
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
$this->debug($e->getMessage());
|
||||
$sExceptionClass = get_class($e);
|
||||
}
|
||||
|
||||
static::assertEquals($sExpectedExceptionClass, $sExceptionClass);
|
||||
}
|
||||
|
||||
public function MakeSelectQueryProvider()
|
||||
{
|
||||
return array(
|
||||
array("SELECT `UserRequest` FROM UserRequest AS `UserRequest` JOIN Person AS `P` ON `UserRequest`.agent_id = `P`.id JOIN Organization AS `Organization` ON `P`.org_id = `Organization`.id WHERE (`UserRequest`.`org_id` IN (SELECT `Organization` FROM Organization AS `Organization` WHERE (`Organization`.`id` = `Toto`.`org_id`)))", 'OqlNormalizeException'),
|
||||
array("SELECT `UserRequest` FROM UserRequest AS `UserRequest` JOIN Person AS `P` ON `UserRequest`.agent_id = `P`.id JOIN Organization AS `Organization` ON `P`.org_id = `Organization`.id WHERE (`UserRequest`.`org_id` IN (SELECT `Organization` FROM Organization AS `Organization` WHERE (`Organization`.`id` = `UserRequest`.`org_id`)))"),
|
||||
array("SELECT `U` FROM User AS `U` JOIN Person AS `P` ON `U`.contactid = `P`.id WHERE ((`U`.`status` = 'enabled') AND (`U`.`id` NOT IN (SELECT `U` FROM User AS `U` JOIN Person AS `P` ON `U`.contactid = `P`.id JOIN URP_UserOrg AS `L` ON `L`.userid = `U`.id WHERE ((`U`.`status` = 'enabled') AND (`L`.`allowed_org_id` = `P`.`org_id`)) UNION SELECT `U` FROM User AS `U` WHERE ((`U`.`status` = 'enabled') AND (`U`.`id` NOT IN (SELECT `U` FROM User AS `U` JOIN URP_UserOrg AS `L` ON `L`.userid = `U`.id WHERE (`U`.`status` = 'enabled')))))))"),
|
||||
array("SELECT `Ur` FROM UserRequest AS `Ur` WHERE (`Ur`.`id` NOT IN (SELECT `Ur` FROM UserRequest AS `Ur` JOIN lnkFunctionalCIToTicket AS `lnk` ON `lnk`.ticket_id = `Ur`.id WHERE 1))"),
|
||||
array("SELECT `T` FROM Ticket AS `T` WHERE ((`T`.`finalclass` IN ('userrequest', 'change')) AND (`T`.`id` NOT IN (SELECT `Ur` FROM UserRequest AS `Ur` JOIN lnkFunctionalCIToTicket AS `lnk` ON `lnk`.ticket_id = `Ur`.id WHERE 1 UNION SELECT `C` FROM Change AS `C` JOIN lnkFunctionalCIToTicket AS `lnk` ON `lnk`.ticket_id = `C`.id WHERE 1)))"),
|
||||
array("SELECT `PhysicalDevice` FROM PhysicalDevice AS `PhysicalDevice` WHERE ((`PhysicalDevice`.`status` = 'production') AND (`PhysicalDevice`.`id` NOT IN (SELECT `p` FROM PhysicalDevice AS `p` JOIN lnkFunctionalCIToProviderContract AS `l` ON `l`.functionalci_id = `p`.id WHERE 1)))"),
|
||||
array("SELECT `U` FROM User AS `U` JOIN Person AS `P` ON `U`.contactid = `P`.id WHERE ((`U`.`status` = 'enabled') AND (`U`.`id` NOT IN (SELECT `U` FROM User AS `U` JOIN Person AS `P` ON `U`.contactid = `P`.id JOIN URP_UserOrg AS `L` ON `L`.userid = `U`.id WHERE ((`U1`.`status` = 'enabled') AND (`L`.`allowed_org_id` = `P`.`org_id`)) UNION SELECT `U` FROM User AS `U` WHERE ((`U`.`status` = 'enabled') AND (`U`.`id` NOT IN (SELECT `U` FROM User AS `U` JOIN URP_UserOrg AS `L` ON `L`.userid = `U`.id WHERE (`U`.`status` = 'enabled')))))))", "OqlNormalizeException"),
|
||||
array("SELECT Team WHERE id NOT IN (SELECT Team AS t JOIN lnkPersonToTeam AS l ON l.team_id=t.id WHERE 1)"),
|
||||
array("SELECT UserRequest WHERE id NOT IN (SELECT UserRequest AS u JOIN lnkFunctionalCIToTicket AS l ON l.ticket_id=u.id JOIN PhysicalDevice AS f ON l.functionalci_id=f.id WHERE f.status='production')"),
|
||||
array("SELECT UserRequest WHERE id NOT IN (SELECT UserRequest AS u JOIN lnkFunctionalCIToTicket AS l ON l.ticket_id=u.id JOIN PhysicalDevice AS f ON l.functionalci_id=f.id WHERE f.status='production' UNION SELECT UserRequest AS u JOIN lnkFunctionalCIToTicket AS l ON l.ticket_id=u.id JOIN ApplicationSolution AS f ON l.functionalci_id=f.id WHERE f.status='active')"),
|
||||
array("SELECT Person WHERE status='active' AND id NOT IN (SELECT Person AS p JOIN User AS u ON u.contactid=p.id WHERE u.status='enabled')"),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @dataProvider GetOQLClassTreeProvider
|
||||
* @param $sOQL
|
||||
* @param $sExpectedOQL
|
||||
*/
|
||||
public function testGetOQLClassTree($sOQL, $sExpectedOQL)
|
||||
{
|
||||
$oFilter = DBSearch::FromOQL($sOQL);
|
||||
$aCountAttToLoad = array();
|
||||
$sMainClass = null;
|
||||
foreach ($oFilter->GetSelectedClasses() as $sClassAlias => $sClass)
|
||||
{
|
||||
$aCountAttToLoad[$sClassAlias] = array();
|
||||
if (empty($sMainClass))
|
||||
{
|
||||
$sMainClass = $sClass;
|
||||
}
|
||||
}
|
||||
$aModifierProperties = MetaModel::MakeModifierProperties($oFilter);
|
||||
$oSQLObjectQueryBuilder = new SQLObjectQueryBuilder($oFilter);
|
||||
$oBuild = new QueryBuilderContext($oFilter, $aModifierProperties, null, null, null, $aCountAttToLoad);
|
||||
$sResultOQL = $oSQLObjectQueryBuilder->DebugOQLClassTree($oBuild);
|
||||
|
||||
static::assertEquals($sExpectedOQL, $sResultOQL);
|
||||
}
|
||||
|
||||
public function GetOQLClassTreeProvider()
|
||||
{
|
||||
return [
|
||||
'Bug 3660 1' => [
|
||||
"SELECT UserRequest AS U JOIN lnkContactToTicket AS l ON l.ticket_id=U.id JOIN Team AS T ON l.contact_id=T.id",
|
||||
"SELECT `U` FROM `UserRequest` AS `U`
|
||||
INNER JOIN `lnkContactToTicket` AS `l`
|
||||
ON `U`.`id` = `l`.`ticket_id`
|
||||
INNER JOIN `Team` AS `T`
|
||||
ON `l`.`contact_id` = `T`.`id`",
|
||||
],
|
||||
'Bug 3660 2' => [
|
||||
"SELECT UserRequest AS U JOIN lnkContactToTicket AS l ON l.ticket_id=U.id JOIN Contact AS C ON l.contact_id=C.id",
|
||||
"SELECT `U` FROM `UserRequest` AS `U`
|
||||
INNER JOIN `lnkContactToTicket` AS `l`
|
||||
ON `U`.`id` = `l`.`ticket_id`",
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider MakeSelectQueryForCountProvider
|
||||
*
|
||||
* @param $sOQL
|
||||
* @param $sExpectedSQL
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function testMakeSelectQueryForCount($sOQL, $sExpectedSQL)
|
||||
{
|
||||
$oFilter = DBSearch::FromOQL($sOQL);
|
||||
// Avoid adding all the fields for counts or "group by" requests
|
||||
$aCountAttToLoad = array();
|
||||
$sMainClass = null;
|
||||
foreach ($oFilter->GetSelectedClasses() as $sClassAlias => $sClass) {
|
||||
$aCountAttToLoad[$sClassAlias] = array();
|
||||
if (empty($sMainClass)) {
|
||||
$sMainClass = $sClass;
|
||||
}
|
||||
}
|
||||
$sSQL = $oFilter->MakeSelectQuery([], [], $aCountAttToLoad, null, 0, 0, true);
|
||||
static::assertEquals($sExpectedSQL, $sSQL);
|
||||
}
|
||||
|
||||
public function MakeSelectQueryForCountProvider()
|
||||
{
|
||||
return [
|
||||
'Bug 3618' => [
|
||||
"SELECT UserRequest WHERE private_log LIKE '%Auteur : %' UNION SELECT UserRequest",
|
||||
"SELECT COUNT(*) AS COUNT FROM (SELECT
|
||||
1
|
||||
FROM (
|
||||
SELECT
|
||||
DISTINCT `UserRequest_Ticket`.`id` AS `UserRequestid`
|
||||
FROM
|
||||
`ticket` AS `UserRequest_Ticket`
|
||||
WHERE ((`UserRequest_Ticket`.`private_log` LIKE '%Auteur : %') AND COALESCE((`UserRequest_Ticket`.`finalclass` IN ('UserRequest')), 1))
|
||||
|
||||
UNION
|
||||
SELECT
|
||||
DISTINCT `UserRequest`.`id` AS `UserRequestid`
|
||||
FROM
|
||||
`ticket_request` AS `UserRequest`
|
||||
WHERE 1
|
||||
|
||||
) as __selects__
|
||||
) AS _union_alderaan_",
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
280
tests/php-unit-tests/unitary-tests/core/TagSetFieldDataTest.php
Normal file
280
tests/php-unit-tests/unitary-tests/core/TagSetFieldDataTest.php
Normal file
@@ -0,0 +1,280 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Eric
|
||||
* Date: 10/09/2018
|
||||
* Time: 11:02
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Core;
|
||||
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use CoreException;
|
||||
use DeleteException;
|
||||
use Exception;
|
||||
use MetaModel;
|
||||
use TagSetFieldData;
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class TagSetFieldDataTest extends ItopDataTestCase
|
||||
{
|
||||
// Need database COMMIT in order to create the FULLTEXT INDEX of MySQL
|
||||
const USE_TRANSACTION = false;
|
||||
|
||||
/**
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function testGetAllowedValues()
|
||||
{
|
||||
$aAllowedValues = TagSetFieldData::GetAllowedValues(TAG_CLASS, TAG_ATTCODE);
|
||||
$iInitialCount = count($aAllowedValues);
|
||||
$this->CreateTagData(TAG_CLASS, TAG_ATTCODE, 'tag1', 'First');
|
||||
$aAllowedValues = TagSetFieldData::GetAllowedValues(TAG_CLASS, TAG_ATTCODE);
|
||||
$iCurrCount = count($aAllowedValues);
|
||||
static::assertEquals(1, $iCurrCount - $iInitialCount);
|
||||
$this->CreateTagData(TAG_CLASS, TAG_ATTCODE, 'tag2', 'Second');
|
||||
$aAllowedValues = TagSetFieldData::GetAllowedValues(TAG_CLASS, TAG_ATTCODE);
|
||||
$iCurrCount = count($aAllowedValues);
|
||||
static::assertEquals(2, $iCurrCount - $iInitialCount);
|
||||
$this->CreateTagData(TAG_CLASS, TAG_ATTCODE, 'tag3', 'Third');
|
||||
$aAllowedValues = TagSetFieldData::GetAllowedValues(TAG_CLASS, TAG_ATTCODE);
|
||||
$iCurrCount = count($aAllowedValues);
|
||||
static::assertEquals(3, $iCurrCount - $iInitialCount);
|
||||
$this->CreateTagData(TAG_CLASS, TAG_ATTCODE, 'tag4', 'Fourth');
|
||||
$aAllowedValues = TagSetFieldData::GetAllowedValues(TAG_CLASS, TAG_ATTCODE);
|
||||
$iCurrCount = count($aAllowedValues);
|
||||
static::assertEquals(4, $iCurrCount - $iInitialCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function testDoCheckToWrite()
|
||||
{
|
||||
$aAllowedValues = TagSetFieldData::GetAllowedValues(TAG_CLASS, TAG_ATTCODE);
|
||||
$iInitialCount = count($aAllowedValues);
|
||||
$this->debug("Currently $iInitialCount tags defined");
|
||||
$this->CreateTagData(TAG_CLASS, TAG_ATTCODE, 'tag1', 'First');
|
||||
$this->CreateTagData(TAG_CLASS, TAG_ATTCODE, 'tag2', 'Second');
|
||||
$this->CreateTagData(TAG_CLASS, TAG_ATTCODE, 'tag3', 'Third');
|
||||
$this->CreateTagData(TAG_CLASS, TAG_ATTCODE, 'tag4', 'Fourth');
|
||||
$aAllowedValues = TagSetFieldData::GetAllowedValues(TAG_CLASS, TAG_ATTCODE);
|
||||
$iCurrCount = count($aAllowedValues);
|
||||
static::assertEquals(4, $iCurrCount - $iInitialCount);
|
||||
|
||||
try
|
||||
{
|
||||
$this->CreateTagData(TAG_CLASS, TAG_ATTCODE, 'tag4', 'Fourth');
|
||||
} catch (CoreException $e)
|
||||
{
|
||||
$this->debug($e->getMessage());
|
||||
}
|
||||
$aAllowedValues = TagSetFieldData::GetAllowedValues(TAG_CLASS, TAG_ATTCODE);
|
||||
$iCurrCount = count($aAllowedValues);
|
||||
static::assertEquals(4, $iCurrCount - $iInitialCount);
|
||||
|
||||
try
|
||||
{
|
||||
$this->CreateTagData(TAG_CLASS, TAG_ATTCODE, 'tag4', 'zembrek');
|
||||
} catch (CoreException $e)
|
||||
{
|
||||
$this->debug($e->getMessage());
|
||||
}
|
||||
$aAllowedValues = TagSetFieldData::GetAllowedValues(TAG_CLASS, TAG_ATTCODE);
|
||||
$iCurrCount = count($aAllowedValues);
|
||||
static::assertEquals(4, $iCurrCount - $iInitialCount);
|
||||
|
||||
try
|
||||
{
|
||||
$this->CreateTagData(TAG_CLASS, TAG_ATTCODE, 'zembrek', 'Fourth');
|
||||
} catch (CoreException $e)
|
||||
{
|
||||
$this->debug($e->getMessage());
|
||||
}
|
||||
$aAllowedValues = TagSetFieldData::GetAllowedValues(TAG_CLASS, TAG_ATTCODE);
|
||||
$iCurrCount = count($aAllowedValues);
|
||||
static::assertEquals(4, $iCurrCount - $iInitialCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function testDoCheckToDelete()
|
||||
{
|
||||
$oTagData = $this->CreateTagData(TAG_CLASS, TAG_ATTCODE, 'tag1', 'First');
|
||||
$oTagData->DBDelete();
|
||||
|
||||
// Create a tag
|
||||
$oTagData = $this->CreateTagData(TAG_CLASS, TAG_ATTCODE, 'tag1', 'First');
|
||||
//Use it
|
||||
$oObjWithTagSet = $this->CreateObjectWithTagSet();
|
||||
$oObjWithTagSet->Set(TAG_ATTCODE, 'tag1');
|
||||
$oObjWithTagSet->DBWrite();
|
||||
|
||||
// Try to delete the tag, must complain !
|
||||
$this->expectException(DeleteException::class);
|
||||
$oTagData->DBDelete();
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function testComputeValues()
|
||||
{
|
||||
$sTagClass = TagSetFieldData::GetTagDataClassName(TAG_CLASS, TAG_ATTCODE);
|
||||
$oTagData = $this->createObject($sTagClass, array(
|
||||
'code' => 'tag1',
|
||||
'label' => 'First',
|
||||
));
|
||||
$this->debug("Created {$oTagData->Get('obj_class')}::{$oTagData->Get('obj_attcode')}");
|
||||
|
||||
static::assertEquals(TAG_CLASS, $oTagData->Get('obj_class'));
|
||||
static::assertEquals(TAG_ATTCODE, $oTagData->Get('obj_attcode'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test invalid tag codes
|
||||
* @dataProvider InvalidTagCodeProvider
|
||||
*
|
||||
* @expectedException \CoreException
|
||||
*
|
||||
* @param string $sTagCode
|
||||
*
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function testInvalidTagCode($sTagCode)
|
||||
{
|
||||
$this->CreateTagData(TAG_CLASS, TAG_ATTCODE, $sTagCode, 'First');
|
||||
// Should not pass here
|
||||
static::assertFalse(true);
|
||||
}
|
||||
|
||||
public function InvalidTagCodeProvider()
|
||||
{
|
||||
return array(
|
||||
'No space' => array('tag1 1'),
|
||||
'No _' => array('tag_1'),
|
||||
'No -' => array('tag-1'),
|
||||
'No %' => array('tag%1'),
|
||||
'At least 3 chars' => array(''),
|
||||
'At least 3 chars 1' => array('a'),
|
||||
'At least 3 chars 2' => array('ab'),
|
||||
'No #' => array('#tag'),
|
||||
'No !' => array('tag!'),
|
||||
'Stop Word 1' => array('about'),
|
||||
'Stop Word 2' => array('from'),
|
||||
'Stop Word 3' => array('that'),
|
||||
'Stop Word 4' => array('where'),
|
||||
'Stop Word 5' => array('who'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test invalid tag labels
|
||||
* @expectedException \CoreException
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function testInvalidTagLabel()
|
||||
{
|
||||
$this->CreateTagData(TAG_CLASS, TAG_ATTCODE, 'tag1', 'First|Second');
|
||||
// Should not pass here
|
||||
static::assertFalse(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that tag code cannot be modified if used
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function testUpdateCode()
|
||||
{
|
||||
$oTagData = $this->CreateTagData(TAG_CLASS, TAG_ATTCODE, 'tag1', 'First');
|
||||
$oTagData->Set('code', 'tag2');
|
||||
$oTagData->DBWrite();
|
||||
|
||||
//Use it
|
||||
$oObjWithTagSet = $this->CreateObjectWithTagSet();
|
||||
$oObjWithTagSet->Set(TAG_ATTCODE, 'tag2');
|
||||
$oObjWithTagSet->DBWrite();
|
||||
|
||||
// Try to change the code of the tag, must complain !
|
||||
$oTagData->Set('code', 'tag1');
|
||||
$this->expectException(CoreException::class);
|
||||
$oTagData->DBWrite();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the code length is correctly checked
|
||||
*
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function testMaxTagCodeLength()
|
||||
{
|
||||
/** @var \AttributeTagSet $oAttdef */
|
||||
$oAttdef = MetaModel::GetAttributeDef(TAG_CLASS, TAG_ATTCODE);
|
||||
|
||||
$iMaxLength = $oAttdef->GetTagCodeMaxLength();
|
||||
$sTagCode = str_repeat('a', $iMaxLength);
|
||||
|
||||
// Should work
|
||||
$this->CreateTagData(TAG_CLASS, TAG_ATTCODE, $sTagCode, $sTagCode);
|
||||
|
||||
// Too long
|
||||
$sTagCode = str_repeat('a', $iMaxLength + 1);
|
||||
try
|
||||
{
|
||||
$this->CreateTagData(TAG_CLASS, TAG_ATTCODE, $sTagCode, $sTagCode);
|
||||
} catch (CoreException $e)
|
||||
{
|
||||
$this->debug('Awaited: '.$e->getMessage());
|
||||
static::assertTrue(true);
|
||||
return;
|
||||
}
|
||||
// Failed
|
||||
static::assertFalse(true);
|
||||
}
|
||||
|
||||
public function testMaxTagsAllowed()
|
||||
{
|
||||
/** @var \AttributeTagSet $oAttDef */
|
||||
$oAttDef = MetaModel::GetAttributeDef(TAG_CLASS, TAG_ATTCODE);
|
||||
$iMaxTags = $oAttDef->GetMaxItems();
|
||||
for ($i = 0; $i < $iMaxTags; $i++)
|
||||
{
|
||||
$sTagCode = 'MaxTag'.$i;
|
||||
$this->CreateTagData(TAG_CLASS, TAG_ATTCODE, $sTagCode, $sTagCode);
|
||||
}
|
||||
$oObjWithTagSet = $this->CreateObjectWithTagSet();
|
||||
$this->debug("Max number of tags is $iMaxTags");
|
||||
$sValue = '';
|
||||
for ($i = 0; $i < ($iMaxTags + 1); $i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
$sTagCode = 'MaxTag'.$i;
|
||||
$sValue .= "$sTagCode ";
|
||||
$oObjWithTagSet->Set(TAG_ATTCODE, $sValue);
|
||||
$oObjWithTagSet->DBWrite();
|
||||
} catch (Exception $e)
|
||||
{
|
||||
// Should fail on the last iteration
|
||||
static::assertEquals($iMaxTags, $i);
|
||||
$this->debug("Setting (".($i+1).") tag(s) failed");
|
||||
return;
|
||||
}
|
||||
$this->debug("Setting (".($i+1).") tag(s) worked");
|
||||
}
|
||||
|
||||
static::assertFalse(true);
|
||||
}
|
||||
}
|
||||
100
tests/php-unit-tests/unitary-tests/core/TriggerTest.php
Normal file
100
tests/php-unit-tests/unitary-tests/core/TriggerTest.php
Normal file
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Core;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use ContextTag;
|
||||
use MetaModel;
|
||||
use TriggerOnObjectCreate;
|
||||
|
||||
/**
|
||||
* Class TriggerTest
|
||||
*
|
||||
* @package Combodo\iTop\Test\UnitTest\Core
|
||||
*
|
||||
* @runTestsInSeparateProcesses
|
||||
*/
|
||||
|
||||
class TriggerTest extends ItopDataTestCase
|
||||
{
|
||||
const USE_TRANSACTION = false;
|
||||
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
public function testIsContextValid()
|
||||
{
|
||||
/** @var TriggerOnObjectCreate $oTrigger */
|
||||
$oTrigger = MetaModel::NewObject('TriggerOnObjectCreate');
|
||||
$oTrigger->Set('context', ContextTag::TAG_PORTAL.', '.ContextTag::TAG_CRON);
|
||||
$this->assertFalse($oTrigger->IsContextValid());
|
||||
ContextTag::AddContext(ContextTag::TAG_SETUP);
|
||||
$this->assertFalse($oTrigger->IsContextValid());
|
||||
ContextTag::AddContext(ContextTag::TAG_CRON);
|
||||
$this->assertTrue($oTrigger->IsContextValid());
|
||||
}
|
||||
|
||||
public function testEnrichRaisedException_Trigger()
|
||||
{
|
||||
$oTrigger = MetaModel::NewObject('TriggerOnObjectCreate');
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
MetaModel::NewObject('Toto');
|
||||
}
|
||||
catch (\Exception $e)
|
||||
{
|
||||
\utils::EnrichRaisedException($oTrigger, $e);
|
||||
}
|
||||
$this->assertTrue(false, "An exception should have been thrown");
|
||||
}
|
||||
catch(\CoreException $e1)
|
||||
{
|
||||
$this->assertEquals('CoreException', get_class($e1));
|
||||
$this->assertEquals('Unknown class \'Toto\' (<b title="Trigger">TriggerOnObjectCreate</b>::-1 ()<br/>)', $e1->getMessage());
|
||||
|
||||
$fullStackTraceAsString = $e1->getFullStackTraceAsString();
|
||||
$this->assertContains("MetaModel::NewObject", $fullStackTraceAsString,"new enriched exception should contain root cause method: " . $fullStackTraceAsString);
|
||||
}
|
||||
}
|
||||
|
||||
public function NoEnrichmentProvider()
|
||||
{
|
||||
return [
|
||||
[ null ],
|
||||
[ new NonCmdbAbstractObject() ],
|
||||
] ;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $oCmdbAbstract
|
||||
* @dataProvider NoEnrichmentProvider
|
||||
*/
|
||||
public function testEnrichRaisedException_NoEnrichment($oCmdbAbstract)
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
MetaModel::NewObject('CoreException');
|
||||
}
|
||||
catch (\Exception $e)
|
||||
{
|
||||
\utils::EnrichRaisedException($oCmdbAbstract, $e);
|
||||
}
|
||||
$this->assertTrue(false, "An exception should have been thrown");
|
||||
}
|
||||
catch(\Exception $e1)
|
||||
{
|
||||
$this->assertEquals($e, $e1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class NonCmdbAbstractObject{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Core;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
use CoreUnexpectedValue;
|
||||
use MetaModel;
|
||||
|
||||
/**
|
||||
* Class UniquenessConstraintTest
|
||||
*
|
||||
* @since 2.6.0 N°659 uniqueness constraint
|
||||
*
|
||||
* @package Combodo\iTop\Test\UnitTest\Core
|
||||
*/
|
||||
class UniquenessConstraintTest extends ItopTestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
require_once(APPROOT.'/core/metamodel.class.php');
|
||||
require_once(APPROOT.'/core/coreexception.class.inc.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers MetaModel::CheckUniquenessRuleValidity
|
||||
* @dataProvider uniquenessRuleValidityCheckProvider
|
||||
*
|
||||
* @param bool $bIsRuleShouldBeValid
|
||||
* @param bool $bIsRuleOverride
|
||||
* @param array $aRuleProperties
|
||||
*/
|
||||
public function testUniquenessRuleValidityCheck($bIsRuleShouldBeValid, $bIsRuleOverride, $aRuleProperties)
|
||||
{
|
||||
$bRuleValidResult = true;
|
||||
try
|
||||
{
|
||||
MetaModel::CheckUniquenessRuleValidity($aRuleProperties, $bIsRuleOverride);
|
||||
}
|
||||
catch (CoreUnexpectedValue $e)
|
||||
{
|
||||
$bRuleValidResult = false;
|
||||
}
|
||||
|
||||
$this->assertEquals($bIsRuleShouldBeValid, $bRuleValidResult, "Validity test returned $bRuleValidResult");
|
||||
}
|
||||
|
||||
public function uniquenessRuleValidityCheckProvider()
|
||||
{
|
||||
return array(
|
||||
'simplest rule' => array(true, false, array('attributes' => array('name'))),
|
||||
'with all properties' => array(
|
||||
true,
|
||||
false,
|
||||
array(
|
||||
'attributes' => array('name'),
|
||||
'filter' => 'name != \'\'',
|
||||
'disabled' => false,
|
||||
'is_blocking' => true,
|
||||
),
|
||||
),
|
||||
'only disabled key without ancestor' => array(
|
||||
false,
|
||||
false,
|
||||
array(
|
||||
'disabled' => true,
|
||||
),
|
||||
),
|
||||
'only disabled key with ancestor' => array(
|
||||
true,
|
||||
true,
|
||||
array(
|
||||
'disabled' => true,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
251
tests/php-unit-tests/unitary-tests/core/UserRightsTest.php
Normal file
251
tests/php-unit-tests/unitary-tests/core/UserRightsTest.php
Normal file
@@ -0,0 +1,251 @@
|
||||
<?php
|
||||
// Copyright (c) 2010-2018 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/>
|
||||
//
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Eric
|
||||
* Date: 25/01/2018
|
||||
* Time: 11:12
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Core;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use UserRights;
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class UserRightsTest extends ItopDataTestCase
|
||||
{
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp(); // TODO: Change the autogenerated stub
|
||||
|
||||
try {
|
||||
\utils::GetConfig()->SetModuleSetting('authent-local', 'password_validation.pattern', '');
|
||||
self::CreateUser('admin', 1);
|
||||
}
|
||||
catch (\CoreCannotSaveObjectException $e) {
|
||||
}
|
||||
}
|
||||
|
||||
public static $aClasses = array(
|
||||
'FunctionalCI' => array('class' => 'FunctionalCI', 'attcode' => 'name'),
|
||||
'URP_UserProfile' => array('class' => 'URP_UserProfile', 'attcode' => 'reason'),
|
||||
'UserLocal' => array('class' => 'UserLocal', 'attcode' => 'login'),
|
||||
'UserRequest' => array('class' => 'UserRequest', 'attcode' => 'title'),
|
||||
'ModuleInstallation' => array('class' => 'ModuleInstallation', 'attcode' => 'name'),
|
||||
);
|
||||
|
||||
|
||||
public function testIsLoggedIn()
|
||||
{
|
||||
$this->assertFalse(UserRights::IsLoggedIn());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Login validation
|
||||
* @dataProvider LoginProvider
|
||||
* @param $sLogin
|
||||
* @param $bResult
|
||||
*/
|
||||
public function testLogin($sLogin, $bResult)
|
||||
{
|
||||
$_SESSION = array();
|
||||
$this->assertEquals($bResult, UserRights::Login($sLogin));
|
||||
$this->assertEquals($bResult, UserRights::IsLoggedIn());
|
||||
}
|
||||
|
||||
public function LoginProvider()
|
||||
{
|
||||
return array(
|
||||
array('admin', true),
|
||||
array('NotALoginForUnitTests', false),
|
||||
array('', false),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sLogin
|
||||
* @param int $iProfileId initial profile
|
||||
* @return \DBObject
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function AddUser($sLogin, $iProfileId)
|
||||
{
|
||||
$oUser = self::CreateUser('test1', $iProfileId);
|
||||
$oUser->DBUpdate();
|
||||
return $oUser;
|
||||
}
|
||||
|
||||
/** Test IsActionAllowed when not logged => always true
|
||||
* @dataProvider ActionAllowedNotLoggedProvider
|
||||
* @param $aClassAction
|
||||
*/
|
||||
public function testIsActionAllowedNotLogged($aClassAction)
|
||||
{
|
||||
$bRes = (UserRights::IsActionAllowed($aClassAction['class'], $aClassAction['action'])) ? true : false;
|
||||
$this->assertEquals(true, $bRes);
|
||||
}
|
||||
|
||||
public function ActionAllowedNotLoggedProvider()
|
||||
{
|
||||
$aClassActions = array();
|
||||
|
||||
foreach(array_keys(self::$aClasses) as $sClass)
|
||||
{
|
||||
for ($i = 1; $i < 8; $i++)
|
||||
{
|
||||
$aClassAction = array('class' => $sClass, 'action' => $i);
|
||||
$aClassActions[] = array($aClassAction);
|
||||
}
|
||||
}
|
||||
return $aClassActions;
|
||||
}
|
||||
|
||||
/** Test IsActionAllowed
|
||||
* @dataProvider ActionAllowedProvider
|
||||
* @param $iProfileId
|
||||
* @param $aClassActionResult
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function testIsActionAllowed($iProfileId, $aClassActionResult)
|
||||
{
|
||||
$this->AddUser('test1', $iProfileId);
|
||||
$_SESSION = array();
|
||||
$this->assertTrue(UserRights::Login('test1'));
|
||||
$bRes = (UserRights::IsActionAllowed($aClassActionResult['class'], $aClassActionResult['action'])) ? true : false;
|
||||
$this->assertEquals($aClassActionResult['res'], $bRes);
|
||||
}
|
||||
|
||||
/*
|
||||
* FunctionalCI => bizmodel searchable
|
||||
* UserRequest => bizmodel searchable requestmgmt
|
||||
* URP_UserProfile => addon/userrights
|
||||
* UserLocal => addon/authentication
|
||||
* ModuleInstallation => core view_in_gui
|
||||
*
|
||||
*/
|
||||
public function ActionAllowedProvider()
|
||||
{
|
||||
return array(
|
||||
/* Administrator (7 = UR_ACTION_CREATE) */
|
||||
'Administrator FunctionalCI write' => array(1 , array('class' => 'FunctionalCI', 'action' => 7, 'res' => true)),
|
||||
'Administrator UserRequest write' => array(1 , array('class' => 'UserRequest', 'action' => 7, 'res' => true)),
|
||||
'Administrator URP_UserProfile write' => array(1 , array('class' => 'URP_UserProfile', 'action' => 7, 'res' => true)),
|
||||
'Administrator UserLocal write' => array(1 , array('class' => 'UserLocal', 'action' => 7, 'res' => true)),
|
||||
'Administrator ModuleInstallation write' => array(1 , array('class' => 'ModuleInstallation', 'action' => 7, 'res' => true)),
|
||||
|
||||
/* User Portal (7 = UR_ACTION_CREATE) */
|
||||
'User Portal FunctionalCI write' => array(2 , array('class' => 'FunctionalCI', 'action' => 7, 'res' => false)),
|
||||
'User Portal UserRequest write' => array(2 , array('class' => 'UserRequest', 'action' => 7, 'res' => true)),
|
||||
'User Portal URP_UserProfile write' => array(2 , array('class' => 'URP_UserProfile', 'action' => 7, 'res' => false)),
|
||||
'User Portal UserLocal write' => array(2 , array('class' => 'UserLocal', 'action' => 7, 'res' => false)),
|
||||
'User Portal ModuleInstallation write' => array(2 , array('class' => 'ModuleInstallation', 'action' => 7, 'res' => false)),
|
||||
|
||||
/* Configuration manager (7 = UR_ACTION_CREATE) */
|
||||
'Configuration manager FunctionalCI write' => array(3 , array('class' => 'FunctionalCI', 'action' => 7, 'res' => true)),
|
||||
'Configuration manager UserRequest write' => array(3 , array('class' => 'UserRequest', 'action' => 7, 'res' => false)),
|
||||
'Configuration manager URP_UserProfile write' => array(3 , array('class' => 'URP_UserProfile', 'action' => 7, 'res' => false)),
|
||||
'Configuration manager UserLocal write' => array(3 , array('class' => 'UserLocal', 'action' => 7, 'res' => false)),
|
||||
'Configuration manager ModuleInstallation write' => array(3 , array('class' => 'ModuleInstallation', 'action' => 7, 'res' => false)),
|
||||
|
||||
/* Administrator (1 = UR_ACTION_READ) */
|
||||
'Administrator FunctionalCI read' => array(1 , array('class' => 'FunctionalCI', 'action' => 1, 'res' => true)),
|
||||
'Administrator UserRequest read' => array(1 , array('class' => 'UserRequest', 'action' => 1, 'res' => true)),
|
||||
'Administrator URP_UserProfile read' => array(1 , array('class' => 'URP_UserProfile', 'action' => 1, 'res' => true)),
|
||||
'Administrator UserLocal read' => array(1 , array('class' => 'UserLocal', 'action' => 1, 'res' => true)),
|
||||
'Administrator ModuleInstallation read' => array(1 , array('class' => 'ModuleInstallation', 'action' => 1, 'res' => true)),
|
||||
|
||||
/* User Portal (1 = UR_ACTION_READ) */
|
||||
'User Portal FunctionalCI read' => array(2 , array('class' => 'FunctionalCI', 'action' => 1, 'res' => true)),
|
||||
'User Portal UserRequest read' => array(2 , array('class' => 'UserRequest', 'action' => 1, 'res' => true)),
|
||||
'User Portal URP_UserProfile read' => array(2 , array('class' => 'URP_UserProfile', 'action' => 1, 'res' => false)),
|
||||
'User Portal UserLocal read' => array(2 , array('class' => 'UserLocal', 'action' => 1, 'res' => false)),
|
||||
'User Portal ModuleInstallation read' => array(2 , array('class' => 'ModuleInstallation', 'action' => 1, 'res' => true)),
|
||||
|
||||
/* Configuration manager (1 = UR_ACTION_READ) */
|
||||
'Configuration manager FunctionalCI read' => array(3 , array('class' => 'FunctionalCI', 'action' => 1, 'res' => true)),
|
||||
'Configuration manager UserRequest read' => array(3 , array('class' => 'UserRequest', 'action' => 1, 'res' => true)),
|
||||
'Configuration manager URP_UserProfile read' => array(3 , array('class' => 'URP_UserProfile', 'action' => 1, 'res' => false)),
|
||||
'Configuration manager UserLocal read' => array(3 , array('class' => 'UserLocal', 'action' => 1, 'res' => false)),
|
||||
'Configuration manager ModuleInstallation read' =>array(3 , array('class' => 'ModuleInstallation', 'action' => 1, 'res' => true)),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/** Test IsActionAllowedOnAttribute
|
||||
* @dataProvider ActionAllowedOnAttributeProvider
|
||||
* @param $iProfileId
|
||||
* @param $aClassActionResult
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function testIsActionAllowedOnAttribute($iProfileId, $aClassActionResult)
|
||||
{
|
||||
$this->AddUser('test1', $iProfileId);
|
||||
$_SESSION = array();
|
||||
$this->assertTrue(UserRights::Login('test1'));
|
||||
$sClass = $aClassActionResult['class'];
|
||||
$bRes = (UserRights::IsActionAllowedOnAttribute($sClass, self::$aClasses[$sClass]['attcode'], $aClassActionResult['action'])) ? true : false;
|
||||
$this->assertEquals($aClassActionResult['res'], $bRes);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* FunctionalCI => bizmodel searchable
|
||||
* UserRequest => bizmodel searchable requestmgmt
|
||||
* URP_UserProfile => addon/userrights grant_by_profile
|
||||
* UserLocal => addon/authentication grant_by_profile
|
||||
* ModuleInstallation => core view_in_gui
|
||||
*
|
||||
*/
|
||||
public function ActionAllowedOnAttributeProvider()
|
||||
{
|
||||
$aClassActionResult = array(
|
||||
/* Administrator (2 = UR_ACTION_MODIFY) */
|
||||
'Administrator FunctionalCI' => array(1 , array('class' => 'FunctionalCI', 'action' => 2, 'res' => true)),
|
||||
'Administrator UserRequest' => array(1 , array('class' => 'UserRequest', 'action' => 2, 'res' => true)),
|
||||
'Administrator URP_UserProfile' => array(1 , array('class' => 'URP_UserProfile', 'action' => 2, 'res' => true)),
|
||||
'Administrator UserLocal' => array(1 , array('class' => 'UserLocal', 'action' => 2, 'res' => true)),
|
||||
'Administrator ModuleInstallation' => array(1 , array('class' => 'ModuleInstallation', 'action' => 2, 'res' => true)),
|
||||
|
||||
/* User Portal (2 = UR_ACTION_MODIFY) */
|
||||
'User Portal FunctionalCI' => array(2 , array('class' => 'FunctionalCI', 'action' => 2, 'res' => false)),
|
||||
'User Portal UserRequest' => array(2 , array('class' => 'UserRequest', 'action' => 2, 'res' => true)),
|
||||
'User Portal URP_UserProfile' => array(2 , array('class' => 'URP_UserProfile', 'action' => 2, 'res' => false)),
|
||||
'User Portal UserLocal' => array(2 , array('class' => 'UserLocal', 'action' => 2, 'res' => false)),
|
||||
'User Portal ModuleInstallation' => array(2 , array('class' => 'ModuleInstallation', 'action' => 2, 'res' => true)),
|
||||
|
||||
/* Configuration manager (2 = UR_ACTION_MODIFY) */
|
||||
'Configuration manager FunctionalCI' => array(3 , array('class' => 'FunctionalCI', 'action' => 2, 'res' => true)),
|
||||
'Configuration manager UserRequest' => array(3 , array('class' => 'UserRequest', 'action' => 2, 'res' => false)),
|
||||
'Configuration manager URP_UserProfile' => array(3 , array('class' => 'URP_UserProfile', 'action' => 2, 'res' => false)),
|
||||
'Configuration manager UserLocal' => array(3 , array('class' => 'UserLocal', 'action' => 2, 'res' => false)),
|
||||
'Configuration manager ModuleInstallation' => array(3 , array('class' => 'ModuleInstallation', 'action' => 2, 'res' => true)),
|
||||
);
|
||||
|
||||
return $aClassActionResult;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Tool class to mock the config in {@link AbstractWeeklyScheduledProcess}
|
||||
*
|
||||
* The weekdays will be set to working week days (all except saturday & sunday)
|
||||
*
|
||||
* @package Combodo\iTop\Test\UnitTest\Core
|
||||
*/
|
||||
class WeeklyScheduledProcessMockConfig extends AbstractWeeklyScheduledProcess
|
||||
{
|
||||
const MODULE_NAME = 'TEST_SCHEDULED_PROCESS';
|
||||
|
||||
public function __construct($bEnabledValue, $sTimeValue)
|
||||
{
|
||||
$this->oConfig = new Config();
|
||||
$this->oConfig->SetModuleSetting(self::MODULE_NAME, self::MODULE_SETTING_ENABLED, $bEnabledValue);
|
||||
$this->oConfig->SetModuleSetting(self::MODULE_NAME, self::MODULE_SETTING_TIME, $sTimeValue);
|
||||
$this->oConfig->SetModuleSetting(self::MODULE_NAME, self::MODULE_SETTING_WEEKDAYS, 'monday, tuesday, wednesday, thursday, friday');
|
||||
}
|
||||
|
||||
protected function GetModuleName()
|
||||
{
|
||||
return self::MODULE_NAME;
|
||||
}
|
||||
|
||||
protected function GetDefaultModuleSettingTime()
|
||||
{
|
||||
return null; // config mock injected in the constructor
|
||||
}
|
||||
|
||||
public function Process($iUnixTimeLimit)
|
||||
{
|
||||
// nothing to do here (not tested)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
namespace Combodo\iTop\Test\UnitTest\Core;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
use DateTime;
|
||||
|
||||
|
||||
class WeeklyScheduledProcessTest extends ItopTestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
require_once(APPROOT.'core/backgroundprocess.inc.php');
|
||||
require_once(APPROOT.'tests/core/WeeklyScheduledProcessMockConfig.php');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @dataProvider GetNextOccurrenceProvider
|
||||
* @test
|
||||
*
|
||||
* @param boolean $bEnabledValue true if task is enabled
|
||||
* @param string $sCurrentTime Date string for current time, eg '2020-01-01 23:30'
|
||||
* @param string $sTimeValue time to run that is set in the config, eg '23:30'
|
||||
* @param string $sExpectedTime next occurrence that should be returned
|
||||
*
|
||||
* @throws \ProcessInvalidConfigException
|
||||
*/
|
||||
public function TestGetNextOccurrence($bEnabledValue, $sCurrentTime, $sTimeValue, $sExpectedTime)
|
||||
{
|
||||
$oWeeklyImpl = new \WeeklyScheduledProcessMockConfig($bEnabledValue, $sTimeValue);
|
||||
|
||||
$sItopTimeZone = $oWeeklyImpl->getOConfig()->Get('timezone');
|
||||
$timezone = new \DateTimeZone($sItopTimeZone);
|
||||
$oExpectedDateTime = new DateTime($sExpectedTime, $timezone);
|
||||
|
||||
$this->assertEquals($oExpectedDateTime, $oWeeklyImpl->GetNextOccurrence($sCurrentTime));
|
||||
}
|
||||
|
||||
public function GetNextOccurrenceProvider()
|
||||
{
|
||||
return array(
|
||||
'Disabled process' => array(false, 'now', null, '3000-01-01'),
|
||||
'working day same day, prog noon and current before noon' => array(true, '2020-05-11 11:00', '12:00', '2020-05-11 12:00'),
|
||||
'working day same day, prog noon and current is noon' => array(true, '2020-05-11 12:00', '12:00', '2020-05-12 12:00'),
|
||||
'working day same day, prog noon and current after noon' => array(true, '2020-05-11 13:00', '12:00', '2020-05-12 12:00'),
|
||||
'saturday, prog noon and current before noon' => array(true, '2020-05-09 11:00', '12:00', '2020-05-11 12:00'),
|
||||
'saturday, prog noon and current is noon' => array(true, '2020-05-09 12:00', '12:00', '2020-05-11 12:00'),
|
||||
'saturday, prog noon and current after noon' => array(true, '2020-05-09 13:00', '12:00', '2020-05-11 12:00'),
|
||||
'sunday, prog noon and current before noon' => array(true, '2020-05-10 11:00', '12:00', '2020-05-11 12:00'),
|
||||
'sunday, prog noon and current is noon' => array(true, '2020-05-10 12:00', '12:00', '2020-05-11 12:00'),
|
||||
'sunday, prog noon and current after noon' => array(true, '2020-05-10 13:00', '12:00', '2020-05-11 12:00'),
|
||||
'working day, day before, prog noon and current before midnight' => array(true, '2020-05-11 23:59', '00:00', '2020-05-12 00:00'),
|
||||
'working day same day, prog noon and current is midnight' => array(true, '2020-05-12 00:00', '00:00', '2020-05-13 00:00'),
|
||||
'working day same day, prog noon and current after midnight' => array(true, '2020-05-12 00:01', '00:00', '2020-05-13 00:00'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
195
tests/php-unit-tests/unitary-tests/core/apcEmulationTest.php
Normal file
195
tests/php-unit-tests/unitary-tests/core/apcEmulationTest.php
Normal file
@@ -0,0 +1,195 @@
|
||||
<?php
|
||||
// Copyright (c) 2010-2017 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/>
|
||||
//
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Eric
|
||||
* Date: 31/10/2017
|
||||
* Time: 14:10
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Core;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
|
||||
define('UNIT_MAX_CACHE_FILES', 10);
|
||||
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class apcEmulationTest extends ItopTestCase
|
||||
{
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
require_once(APPROOT.'core/apc-emulation.php');
|
||||
require_once 'mockApcEmulation.incphp';
|
||||
apc_clear_cache();
|
||||
}
|
||||
|
||||
public function tearDown(): void
|
||||
{
|
||||
apc_clear_cache();
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
public function testBasic()
|
||||
{
|
||||
$this->assertTrue(apc_store('test-ttl', 'This is a test with TTL', 100));
|
||||
$this->assertTrue(apc_store('test-nottl', 'This is a test without TTL'));
|
||||
|
||||
$this->assertEquals('This is a test with TTL', apc_fetch('test-ttl'));
|
||||
$this->assertEquals('This is a test without TTL', apc_fetch('test-nottl'));
|
||||
}
|
||||
|
||||
public function testMultiple()
|
||||
{
|
||||
for($i = 0; $i < UNIT_MAX_CACHE_FILES; $i++)
|
||||
{
|
||||
$this->assertTrue(apc_store('testMultiple'.$i, 'This is a test', 100));
|
||||
}
|
||||
$aInfo = apc_cache_info();
|
||||
$this->assertEquals(UNIT_MAX_CACHE_FILES, count($aInfo['cache_list']));
|
||||
}
|
||||
|
||||
public function testNumberOfFilesTTL()
|
||||
{
|
||||
for($i = 0; $i < 2 * UNIT_MAX_CACHE_FILES; $i++)
|
||||
{
|
||||
$this->assertTrue(apc_store('testNumberOfFilesTTL'.$i, 'This is a test', 100));
|
||||
}
|
||||
$aInfo = apc_cache_info();
|
||||
$this->assertEquals(UNIT_MAX_CACHE_FILES, count($aInfo['cache_list']));
|
||||
|
||||
$this->assertFalse(apc_fetch('testNumberOfFilesTTL0'));
|
||||
}
|
||||
|
||||
public function testNumberOfFilesNoTTL()
|
||||
{
|
||||
for($i = 0; $i < 2 * UNIT_MAX_CACHE_FILES; $i++)
|
||||
{
|
||||
$this->assertTrue(apc_store('testNumberOfFilesNoTTL'.$i, 'This is a test'));
|
||||
}
|
||||
$aInfo = apc_cache_info();
|
||||
$this->assertEquals(2 * UNIT_MAX_CACHE_FILES, count($aInfo['cache_list']));
|
||||
|
||||
$this->assertTrue(apc_fetch('testNumberOfFilesNoTTL0') !== false);
|
||||
}
|
||||
|
||||
public function testArray()
|
||||
{
|
||||
$aStoredEntries = array();
|
||||
$aFetchedEntries = array();
|
||||
for($i = 0; $i < UNIT_MAX_CACHE_FILES; $i++)
|
||||
{
|
||||
$sKey = 'testArray'.$i;
|
||||
$aStoredEntries[$sKey] = 'This is a test ARRAY'.rand();
|
||||
$aFetchedEntries[] = $sKey;
|
||||
}
|
||||
$aResStore = apc_store($aStoredEntries);
|
||||
$this->assertEquals(UNIT_MAX_CACHE_FILES, count($aResStore));
|
||||
foreach($aResStore as $bValue)
|
||||
{
|
||||
$this->assertTrue($bValue);
|
||||
}
|
||||
|
||||
$aInfo = apc_cache_info();
|
||||
$this->assertEquals(UNIT_MAX_CACHE_FILES, count($aInfo['cache_list']));
|
||||
|
||||
$aResFetch = apc_fetch($aFetchedEntries);
|
||||
$this->assertEquals(UNIT_MAX_CACHE_FILES, count($aResFetch));
|
||||
|
||||
foreach($aResFetch as $sKey => $sValue)
|
||||
{
|
||||
$this->assertEquals($aStoredEntries[$sKey], $sValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function testSanity()
|
||||
{
|
||||
$this->assertTrue(apc_store('testSanity', null, 100));
|
||||
$this->assertTrue(is_null(apc_fetch('testSanity')));
|
||||
|
||||
$this->assertFalse(apc_store(null, 'testSanity', 100));
|
||||
$this->assertFalse(apc_fetch(null));
|
||||
|
||||
$this->assertTrue(apc_store('testSanity2', null));
|
||||
$this->assertFalse(apc_store(null, 'testSanity2'));
|
||||
$this->assertFalse(apc_store('', 'testSanity2'));
|
||||
|
||||
$this->assertFalse(apc_delete(null));
|
||||
$this->assertFalse(apc_delete(''));
|
||||
}
|
||||
|
||||
public function testDelete()
|
||||
{
|
||||
$this->assertTrue(apc_store('test-ttl', 'This is a test with TTL', 100));
|
||||
$this->assertTrue(apc_store('test-nottl', 'This is a test without TTL'));
|
||||
|
||||
$this->assertTrue(apc_delete('test-ttl'));
|
||||
$this->assertFalse(apc_delete('test-ttl'));
|
||||
$this->assertTrue(apc_delete('test-nottl'));
|
||||
|
||||
$this->assertFalse(apc_fetch('test-ttl'));
|
||||
$this->assertFalse(apc_fetch('test-nottl'));
|
||||
}
|
||||
|
||||
public function testReuseSameKey()
|
||||
{
|
||||
// first use of the key
|
||||
$this->assertTrue(apc_store('testReuseSameKey', 'This is a test with TTL', 100));
|
||||
$this->assertEquals('This is a test with TTL', apc_fetch('testReuseSameKey'));
|
||||
// same key but no ttl
|
||||
$this->assertTrue(apc_store('testReuseSameKey', 'This is a test without TTL'));
|
||||
$this->assertEquals('This is a test without TTL', apc_fetch('testReuseSameKey'));
|
||||
// same key with ttl
|
||||
$this->assertTrue(apc_store('testReuseSameKey', 'This is a test with TTL', 100));
|
||||
$this->assertEquals('This is a test with TTL', apc_fetch('testReuseSameKey'));
|
||||
// same key with ttl but other content
|
||||
$this->assertTrue(apc_store('testReuseSameKey', 'This is a test', 100));
|
||||
$this->assertEquals('This is a test', apc_fetch('testReuseSameKey'));
|
||||
// remove entry
|
||||
$this->assertTrue(apc_delete('testReuseSameKey'));
|
||||
// check entry is removed
|
||||
$this->assertFalse(apc_fetch('testReuseSameKey'));
|
||||
}
|
||||
|
||||
public function testHuge()
|
||||
{
|
||||
$ilen = 20000000;
|
||||
$sContent = str_pad(' TEST ', $ilen, "-=", STR_PAD_BOTH);
|
||||
for($i = 0; $i < UNIT_MAX_CACHE_FILES; $i++)
|
||||
{
|
||||
$this->assertTrue(apc_store('testHuge'.$i, $sContent, 100));
|
||||
}
|
||||
$aInfo = apc_cache_info();
|
||||
$this->assertEquals(UNIT_MAX_CACHE_FILES, count($aInfo['cache_list']));
|
||||
|
||||
for($i = 0; $i < UNIT_MAX_CACHE_FILES; $i++)
|
||||
{
|
||||
$this->assertEquals($ilen, strlen(apc_fetch('testHuge'.$i)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
403
tests/php-unit-tests/unitary-tests/core/dictApcuTest.php
Normal file
403
tests/php-unit-tests/unitary-tests/core/dictApcuTest.php
Normal file
@@ -0,0 +1,403 @@
|
||||
<?php
|
||||
// Copyright (c) 2010-2017 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/>
|
||||
//
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Eric
|
||||
* Date: 30/10/2017
|
||||
* Time: 13:43
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Core;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
use Dict;
|
||||
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class dictApcuTest extends ItopTestCase
|
||||
{
|
||||
private $sEnvName;
|
||||
private $oApcService;
|
||||
private $sDictionaryFolder;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
require_once(APPROOT.'core'.DIRECTORY_SEPARATOR.'coreexception.class.inc.php');
|
||||
require_once(APPROOT.'core'.DIRECTORY_SEPARATOR.'dict.class.inc.php');
|
||||
require_once(APPROOT.'core'.DIRECTORY_SEPARATOR.'apc-service.class.inc.php');
|
||||
|
||||
$this->sEnvName = time();
|
||||
$_SESSION['itop_env'] = $this->sEnvName;
|
||||
|
||||
$this->oApcService = $this->createMock(\ApcService::class);
|
||||
Dict::SetApcService($this->oApcService);
|
||||
Dict::EnableCache('toto');
|
||||
|
||||
Dict::SetLanguagesList(['FR FR' => 'fr', 'EN US' => 'en', 'DE DE' => 'de', 'RU RU' => 'de']);
|
||||
|
||||
$this->InitDictionnaries();
|
||||
}
|
||||
|
||||
private function InitDictionnaries(){
|
||||
clearstatcache();
|
||||
$this->sDictionaryFolder = APPROOT."env-$this->sEnvName" . DIRECTORY_SEPARATOR . "dictionaries";
|
||||
@mkdir($this->sDictionaryFolder, 0777, true);
|
||||
|
||||
$sLabels = <<<STR
|
||||
'label1' => 'fr1',
|
||||
STR;
|
||||
$this->InitDictionnary($this->sDictionaryFolder, 'FR FR', 'fr-fr', $sLabels);
|
||||
|
||||
$sLabels = <<<STR
|
||||
'label1' => 'ru1',
|
||||
'label2' => 'ru2',
|
||||
STR;
|
||||
$this->InitDictionnary($this->sDictionaryFolder, 'RU RU', 'ru-ru', $sLabels);
|
||||
$sLabels = <<<STR
|
||||
'label1' => 'en1',
|
||||
'label2' => 'en2',
|
||||
'label3' => 'en3',
|
||||
STR;
|
||||
$this->InitDictionnary($this->sDictionaryFolder, 'EN US', 'en-us', $sLabels);
|
||||
|
||||
clearstatcache();
|
||||
}
|
||||
|
||||
private function InitDictionnary($sDictionaryFolder, $sLanguageCode, $sLanguageCodeInFilename, $sLabels){
|
||||
$sContent = <<<PHP
|
||||
<?php
|
||||
//
|
||||
// Dictionary built by the compiler for the language "FR FR"
|
||||
//
|
||||
Dict::SetEntries('$sLanguageCode', array(
|
||||
$sLabels
|
||||
));
|
||||
PHP;
|
||||
file_put_contents($sDictionaryFolder . DIRECTORY_SEPARATOR . "$sLanguageCodeInFilename.dict.php", $sContent);
|
||||
}
|
||||
|
||||
private function InitBrokenDictionnary($sDictionaryFolder, $sLanguageCode, $sLanguageCodeInFilename){
|
||||
$sContent = <<<PHP
|
||||
<?php
|
||||
//
|
||||
// Dictionary built by the compiler for the language "FR FR"
|
||||
//
|
||||
Dict::SetEntries('$sLanguageCode', 'stringinsteadofanarray');
|
||||
PHP;
|
||||
file_put_contents($sDictionaryFolder . DIRECTORY_SEPARATOR . "$sLanguageCodeInFilename.dict.php", $sContent);
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
foreach (glob(APPROOT."env-$this->sEnvName".DIRECTORY_SEPARATOR."dictionaries".DIRECTORY_SEPARATOR."*") as $sFile) {
|
||||
unlink($sFile);
|
||||
}
|
||||
rmdir(APPROOT."env-$this->sEnvName".DIRECTORY_SEPARATOR."dictionaries");
|
||||
rmdir(APPROOT."env-$this->sEnvName");
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
public function InitLangIfNeeded_NoApcProvider(){
|
||||
return [
|
||||
'apcu mocked' => [ 'bApcuMocked' => true ],
|
||||
'integration test - apcu service like in production - install php-apcu before' => [ 'bApcuMocked' => false ],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider InitLangIfNeeded_NoApcProvider
|
||||
*/
|
||||
public function testInitLangIfNeeded_NoApc($bApcuMocked){
|
||||
if ($bApcuMocked) {
|
||||
$this->oApcService->expects($this->any())
|
||||
->method('function_exists')
|
||||
->willReturn(false);
|
||||
|
||||
$this->oApcService->expects($this->never())
|
||||
->method('apc_fetch');
|
||||
|
||||
$this->oApcService->expects($this->never())
|
||||
->method('apc_store');
|
||||
} else {
|
||||
Dict::SetApcService(null);
|
||||
}
|
||||
|
||||
//EN US default language
|
||||
$this->assertEquals('en1', Dict::S('label1'));
|
||||
$this->assertEquals('en2', Dict::S('label2'));
|
||||
$this->assertEquals('en3', Dict::S('label3'));
|
||||
$this->assertEquals('not_defined_label', Dict::S('not_defined_label'));
|
||||
|
||||
//default language set to RU RU
|
||||
Dict::SetDefaultLanguage('RU RU');
|
||||
$this->assertEquals('ru1', Dict::S('label1'));
|
||||
$this->assertEquals('ru2', Dict::S('label2'));
|
||||
$this->assertEquals('en3', Dict::S('label3'));
|
||||
$this->assertEquals('not_defined_label', Dict::S('not_defined_label'));
|
||||
|
||||
//user language set to FR FR
|
||||
Dict::SetUserLanguage('FR FR');
|
||||
$this->assertEquals('fr1', Dict::S('label1'));
|
||||
$this->assertEquals('ru2', Dict::S('label2'));
|
||||
$this->assertEquals('en3', Dict::S('label3'));
|
||||
$this->assertEquals('not_defined_label', Dict::S('not_defined_label'));
|
||||
}
|
||||
|
||||
public function testInitLangIfNeeded_Apc_LanguageMismatchDictionnary(){
|
||||
//language mismatch!!
|
||||
$sLabels = <<<STR
|
||||
'label1' => 'de1',
|
||||
STR;
|
||||
$this->InitDictionnary($this->sDictionaryFolder, 'RU RU', 'de-de', $sLabels);
|
||||
|
||||
clearstatcache();
|
||||
$this->oApcService->expects($this->any())
|
||||
->method('function_exists')
|
||||
->willReturn(false);
|
||||
|
||||
$this->oApcService->expects($this->exactly(0))
|
||||
->method('apc_fetch');
|
||||
|
||||
$this->oApcService->expects($this->never())
|
||||
->method('apc_store');
|
||||
|
||||
Dict::SetUserLanguage('DE DE');
|
||||
$this->assertEquals('label1', Dict::S('label1'));
|
||||
}
|
||||
|
||||
public function testInitLangIfNeeded_Apc_BrokenUserDictionnary(){
|
||||
$this->InitBrokenDictionnary($this->sDictionaryFolder, 'DE DE', 'de-de');
|
||||
|
||||
$this->oApcService->expects($this->any())
|
||||
->method('function_exists')
|
||||
->willReturn(false);
|
||||
|
||||
$this->oApcService->expects($this->exactly(0))
|
||||
->method('apc_fetch');
|
||||
|
||||
$this->oApcService->expects($this->never())
|
||||
->method('apc_store');
|
||||
|
||||
Dict::SetUserLanguage('DE DE');
|
||||
$this->assertEquals('en1', Dict::S('label1'));
|
||||
|
||||
Dict::SetDefaultLanguage('RU RU');
|
||||
$this->assertEquals('ru1', Dict::S('label1'));
|
||||
}
|
||||
|
||||
public function testInitLangIfNeeded_Apc_BrokenDictionnary_UserAndDefault(){
|
||||
$this->InitBrokenDictionnary($this->sDictionaryFolder, 'DE DE', 'de-de');
|
||||
$this->InitBrokenDictionnary($this->sDictionaryFolder, 'RU RU', 'ru-ru');
|
||||
|
||||
$this->oApcService->expects($this->any())
|
||||
->method('function_exists')
|
||||
->willReturn(false);
|
||||
|
||||
$this->oApcService->expects($this->exactly(0))
|
||||
->method('apc_fetch');
|
||||
|
||||
$this->oApcService->expects($this->never())
|
||||
->method('apc_store');
|
||||
|
||||
Dict::SetUserLanguage('DE DE');
|
||||
Dict::SetDefaultLanguage('RU RU');
|
||||
$this->assertEquals('en1', Dict::S('label1'));
|
||||
}
|
||||
|
||||
public function testInitLangIfNeeded_Apc_BrokenDictionnary_ALL(){
|
||||
$this->InitBrokenDictionnary($this->sDictionaryFolder, 'DE DE', 'de-de');
|
||||
$this->InitBrokenDictionnary($this->sDictionaryFolder, 'RU RU', 'ru-ru');
|
||||
$this->InitBrokenDictionnary($this->sDictionaryFolder, 'EN US', 'en-us');
|
||||
|
||||
$this->oApcService->expects($this->any())
|
||||
->method('function_exists')
|
||||
->willReturn(false);
|
||||
|
||||
$this->oApcService->expects($this->exactly(0))
|
||||
->method('apc_fetch');
|
||||
|
||||
$this->oApcService->expects($this->never())
|
||||
->method('apc_store');
|
||||
|
||||
Dict::SetUserLanguage('DE DE');
|
||||
Dict::SetDefaultLanguage('RU RU');
|
||||
$this->assertEquals('label1', Dict::S('label1'));
|
||||
}
|
||||
|
||||
public function testInitLangIfNeeded_ApcFromCache_PropertyInUserDictionnary(){
|
||||
$this->oApcService->expects($this->any())
|
||||
->method('function_exists')
|
||||
->willReturn(true);
|
||||
|
||||
$this->oApcService->expects($this->exactly(1))
|
||||
->method('apc_fetch')
|
||||
->with('toto-dict-FR FR')
|
||||
->willReturn(['label1' => 'fr1']);
|
||||
|
||||
$this->oApcService->expects($this->exactly(0))
|
||||
->method('apc_store');
|
||||
|
||||
Dict::SetDefaultLanguage('RU RU');
|
||||
Dict::SetUserLanguage('FR FR');
|
||||
$this->assertEquals('fr1', Dict::S('label1'));
|
||||
}
|
||||
|
||||
public function testInitLangIfNeeded_ApcStore_PropertyInUserDictionnary(){
|
||||
$this->oApcService->expects($this->any())
|
||||
->method('function_exists')
|
||||
->willReturn(true);
|
||||
|
||||
$this->oApcService->expects($this->exactly(1))
|
||||
->method('apc_fetch')
|
||||
->with('toto-dict-FR FR')
|
||||
->willReturn(false);
|
||||
|
||||
$this->oApcService->expects($this->exactly(1))
|
||||
->method('apc_store')
|
||||
->with('toto-dict-FR FR', ['label1' => 'fr1']);
|
||||
|
||||
Dict::SetDefaultLanguage('RU RU');
|
||||
Dict::SetUserLanguage('FR FR');
|
||||
$this->assertEquals('fr1', Dict::S('label1'));
|
||||
}
|
||||
|
||||
//corrupted data not fixed
|
||||
//we will return label from another dictionary (defaut one => russian here)
|
||||
public function testInitLangIfNeeded_Apc_CorruptedCache_PropertyInUserDictionnary(){
|
||||
$this->oApcService->expects($this->any())
|
||||
->method('function_exists')
|
||||
->willReturn(true);
|
||||
|
||||
$this->oApcService->expects($this->exactly(2))
|
||||
->method('apc_fetch')
|
||||
->withConsecutive(['toto-dict-FR FR'], ['toto-dict-RU RU'])
|
||||
->willReturnOnConsecutiveCalls('corrupteddata', ['label1' => 'ru1']);
|
||||
|
||||
$this->oApcService->expects($this->exactly(0))
|
||||
->method('apc_store');
|
||||
|
||||
Dict::SetDefaultLanguage('RU RU');
|
||||
Dict::SetUserLanguage('FR FR');
|
||||
$this->assertEquals('ru1', Dict::S('label1'));
|
||||
}
|
||||
|
||||
public function testInitLangIfNeeded_Apc_PropertyInDefaultLanguageDictionnary(){
|
||||
$this->oApcService->expects($this->any())
|
||||
->method('function_exists')
|
||||
->willReturn(true);
|
||||
|
||||
$this->oApcService->expects($this->exactly(2))
|
||||
->method('apc_fetch')
|
||||
->withConsecutive(['toto-dict-FR FR'], ['toto-dict-RU RU'])
|
||||
->willReturnOnConsecutiveCalls([], false);
|
||||
|
||||
$this->oApcService->expects($this->exactly(1))
|
||||
->method('apc_store')
|
||||
->withConsecutive(['toto-dict-RU RU', ['label1' => 'ru1', 'label2' => 'ru2']]
|
||||
);
|
||||
|
||||
Dict::SetDefaultLanguage('RU RU');
|
||||
Dict::SetUserLanguage('FR FR');
|
||||
$this->assertEquals('ru2', Dict::S('label2'));
|
||||
}
|
||||
|
||||
//corrupted data not fixed
|
||||
//we will return label from default language dictionary (EN here)
|
||||
public function testInitLangIfNeeded_ApcCorrupted_PropertyInDefaultLanguageDictionnary(){
|
||||
$this->oApcService->expects($this->any())
|
||||
->method('function_exists')
|
||||
->willReturn(true);
|
||||
|
||||
$this->oApcService->expects($this->exactly(3))
|
||||
->method('apc_fetch')
|
||||
->withConsecutive(['toto-dict-FR FR'], ['toto-dict-RU RU'], ['toto-dict-EN US'])
|
||||
->willReturnOnConsecutiveCalls([], 'corrupteddata', ['label1' => 'en1', 'label2' => 'en2', 'label3' => 'en3']);
|
||||
|
||||
$this->oApcService->expects($this->exactly(0))
|
||||
->method('apc_store');
|
||||
|
||||
Dict::SetDefaultLanguage('RU RU');
|
||||
Dict::SetUserLanguage('FR FR');
|
||||
$this->assertEquals('en2', Dict::S('label2'));
|
||||
}
|
||||
|
||||
public function testInitLangIfNeeded_Apc_PropertyInDictDefaultLanguageDictionnary(){
|
||||
$this->oApcService->expects($this->any())
|
||||
->method('function_exists')
|
||||
->willReturn(true);
|
||||
|
||||
$this->oApcService->expects($this->exactly(3))
|
||||
->method('apc_fetch')
|
||||
->withConsecutive(['toto-dict-FR FR'], ['toto-dict-RU RU'], ['toto-dict-EN US'])
|
||||
->willReturnOnConsecutiveCalls([], [], false);
|
||||
|
||||
$this->oApcService->expects($this->exactly(1))
|
||||
->method('apc_store')
|
||||
->withConsecutive(
|
||||
['toto-dict-EN US', ['label1' => 'en1', 'label2' => 'en2', 'label3' => 'en3']]
|
||||
);
|
||||
|
||||
Dict::SetDefaultLanguage('RU RU');
|
||||
Dict::SetUserLanguage('FR FR');
|
||||
$this->assertEquals('en3', Dict::S('label3'));
|
||||
}
|
||||
|
||||
public function testInitLangIfNeeded_ApcCorrupted_PropertyInDictDefaultLanguageDictionnary(){
|
||||
$this->oApcService->expects($this->any())
|
||||
->method('function_exists')
|
||||
->willReturn(true);
|
||||
|
||||
$this->oApcService->expects($this->exactly(3))
|
||||
->method('apc_fetch')
|
||||
->withConsecutive(['toto-dict-FR FR'], ['toto-dict-RU RU'], ['toto-dict-EN US'])
|
||||
->willReturnOnConsecutiveCalls([], [], 'corrupteddata');
|
||||
|
||||
$this->oApcService->expects($this->exactly(0))
|
||||
->method('apc_store');
|
||||
|
||||
Dict::SetDefaultLanguage('RU RU');
|
||||
Dict::SetUserLanguage('FR FR');
|
||||
$this->assertEquals('label3', Dict::S('label3'));
|
||||
}
|
||||
|
||||
public function testInitLangIfNeeded_Apc_PropertyNotFound(){
|
||||
$this->oApcService->expects($this->any())
|
||||
->method('function_exists')
|
||||
->willReturn(true);
|
||||
|
||||
$this->oApcService->expects($this->exactly(3))
|
||||
->method('apc_fetch')
|
||||
->withConsecutive(['toto-dict-FR FR'], ['toto-dict-RU RU'], ['toto-dict-EN US'])
|
||||
->willReturnOnConsecutiveCalls([], [], []);
|
||||
|
||||
$this->oApcService->expects($this->exactly(0))
|
||||
->method('apc_store');
|
||||
|
||||
Dict::SetDefaultLanguage('RU RU');
|
||||
Dict::SetUserLanguage('FR FR');
|
||||
$this->assertEquals('undefined_label', Dict::S('undefined_label'));
|
||||
}
|
||||
}
|
||||
121
tests/php-unit-tests/unitary-tests/core/dictTest.php
Normal file
121
tests/php-unit-tests/unitary-tests/core/dictTest.php
Normal file
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
// Copyright (c) 2010-2017 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/>
|
||||
//
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Eric
|
||||
* Date: 30/10/2017
|
||||
* Time: 13:43
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Core;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
use Dict;
|
||||
use Exception;
|
||||
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class dictTest extends ItopTestCase
|
||||
{
|
||||
private $sEnvName;
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
require_once(APPROOT.'core'.DIRECTORY_SEPARATOR.'coreexception.class.inc.php');
|
||||
require_once(APPROOT.'core'.DIRECTORY_SEPARATOR.'dict.class.inc.php');
|
||||
require_once(APPROOT.'core'.DIRECTORY_SEPARATOR.'apc-service.class.inc.php');
|
||||
$this->sEnvName = time();
|
||||
$sDictionaryFolder = APPROOT."env-$this->sEnvName".DIRECTORY_SEPARATOR."dictionaries";
|
||||
@mkdir($sDictionaryFolder, 0777, true);
|
||||
|
||||
$sContent = <<<PHP
|
||||
<?php
|
||||
//
|
||||
// Dictionary built by the compiler for the language "FR FR"
|
||||
//
|
||||
Dict::SetEntries('FR FR', array(
|
||||
'label1' => 'gabu',
|
||||
));
|
||||
PHP;
|
||||
file_put_contents($sDictionaryFolder . DIRECTORY_SEPARATOR . "fr-fr.dict.php", $sContent);
|
||||
$sContent = <<<PHP
|
||||
<?php
|
||||
//
|
||||
// Dictionary built by the compiler for the language "FR FR"
|
||||
//
|
||||
Dict::SetEntries('EN EN', array(
|
||||
'label1' => 'zomeu',
|
||||
));
|
||||
PHP;
|
||||
file_put_contents($sDictionaryFolder . DIRECTORY_SEPARATOR . "en-en.dict.php", $sContent);
|
||||
|
||||
$_SESSION['itop_env'] = $this->sEnvName;
|
||||
//require_once 'mockDict.incphp';
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
foreach (glob(APPROOT."env-$this->sEnvName".DIRECTORY_SEPARATOR."dictionaries".DIRECTORY_SEPARATOR."*") as $sFile) {
|
||||
unlink($sFile);
|
||||
}
|
||||
rmdir(APPROOT."env-$this->sEnvName".DIRECTORY_SEPARATOR."dictionaries");
|
||||
rmdir(APPROOT."env-$this->sEnvName");
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testType()
|
||||
{
|
||||
$_SESSION['itop_env'] = 'production';
|
||||
$this->assertInternalType('string', Dict::S('Core:AttributeURL'));
|
||||
$this->assertInternalType('string', Dict::Format('Change:AttName_SetTo', '1', '2'));
|
||||
}
|
||||
|
||||
public function testInitLangIfNeeded_NoApc(){
|
||||
$oApcService = $this->createMock(\ApcService::class);
|
||||
Dict::SetApcService($oApcService);
|
||||
Dict::EnableCache('toto');
|
||||
|
||||
$oApcService->expects($this->any())
|
||||
->method('function_exists')
|
||||
->willReturn(false);
|
||||
|
||||
$oApcService->expects($this->never())
|
||||
->method('apc_fetch')
|
||||
->willReturn(false);
|
||||
|
||||
$oApcService->expects($this->never())
|
||||
->method('apc_store')
|
||||
->willReturn(false);
|
||||
|
||||
Dict::SetLanguagesList(['FR FR' => 'fr', 'EN EN' => 'en']);
|
||||
Dict::SetUserLanguage('FR FR');
|
||||
$this->assertEquals('gabu', Dict::S('label1'));
|
||||
Dict::SetUserLanguage('EN EN');
|
||||
$this->assertEquals('zomeu', Dict::S('label1'));
|
||||
}
|
||||
}
|
||||
211
tests/php-unit-tests/unitary-tests/core/iTopConfigParserTest.php
Normal file
211
tests/php-unit-tests/unitary-tests/core/iTopConfigParserTest.php
Normal file
@@ -0,0 +1,211 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by Bruno DA SILVA, working for Combodo
|
||||
* Date: 02/01/2020
|
||||
* Time: 14:43
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
|
||||
class iTopConfigParserTest extends ItopTestCase
|
||||
{
|
||||
private $conf_exists;
|
||||
private $tmpSavePath;
|
||||
private $sConfigPath;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
require_once APPROOT.'/core/iTopConfigParser.php';
|
||||
require_once APPROOT.'/setup/runtimeenv.class.inc.php';
|
||||
|
||||
clearstatcache();
|
||||
$this->sConfigPath = utils::GetConfigFilePath();
|
||||
$this->tmpSavePath = tempnam('/tmp/', 'config-itop');
|
||||
|
||||
$this->conf_exists = is_file($this->sConfigPath);
|
||||
if ($this->conf_exists)
|
||||
{
|
||||
copy($this->sConfigPath, $this->tmpSavePath);
|
||||
}
|
||||
clearstatcache();
|
||||
}
|
||||
|
||||
public function tearDown(): void
|
||||
{
|
||||
parent::tearDown();
|
||||
if ($this->conf_exists) {
|
||||
rename($this->tmpSavePath, $this->sConfigPath);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider ParserProvider
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function testMergeConf($sInitialConfig, $aExpectedVarsMap)
|
||||
{
|
||||
$oITopConfigParser = new iTopConfigParser($sInitialConfig);
|
||||
|
||||
$this->assertEquals($aExpectedVarsMap, $oITopConfigParser->GetVarsMap());
|
||||
|
||||
}
|
||||
|
||||
public function ParserProvider()
|
||||
{
|
||||
|
||||
return array(
|
||||
"test MySettings" => array(
|
||||
'sInitialConfig' => '<?php
|
||||
$a=1;
|
||||
$MySettings = array(
|
||||
"b" => $a
|
||||
);',
|
||||
'aExpectedVarsMap' => array(
|
||||
'MySettings' => array('b' => '$a'),
|
||||
'MyModuleSettings' => array(),
|
||||
'MyModules' => array(),
|
||||
)
|
||||
),
|
||||
|
||||
"test MyModuleSettings" => array(
|
||||
'sInitialConfig' => '<?php
|
||||
$a=1;
|
||||
$MyModuleSettings = array(
|
||||
"b" => $a
|
||||
);',
|
||||
'aExpectedVarsMap' => array(
|
||||
'MySettings' => array(),
|
||||
'MyModuleSettings' => array('b' => '$a'),
|
||||
'MyModules' => array(),
|
||||
)
|
||||
),
|
||||
|
||||
|
||||
"test MyModules" => array(
|
||||
'sInitialConfig' => '<?php
|
||||
$a=1;
|
||||
$MyModules = array(
|
||||
"b" => $a
|
||||
);',
|
||||
'aExpectedVarsMap' => array(
|
||||
'MySettings' =>array(),
|
||||
'MyModuleSettings' => array(),
|
||||
'MyModules' => array('b' => '$a'),
|
||||
)
|
||||
),
|
||||
|
||||
"test MyModules + MyModuleSettings " => array(
|
||||
'sInitialConfig' => '<?php
|
||||
$MyModules = array(
|
||||
"b" => $a
|
||||
);
|
||||
$MyModuleSettings = array(
|
||||
"e" => $d
|
||||
);',
|
||||
'aExpectedVarsMap' => array(
|
||||
'MySettings' =>array(),
|
||||
'MyModuleSettings' => array('e' => '$d'),
|
||||
'MyModules' => array('b' => '$a'),
|
||||
)
|
||||
),
|
||||
|
||||
"test preserve gloabl + concatenation" => array(
|
||||
'sInitialConfig' => '<?php
|
||||
$a=1;
|
||||
$MyModules = array(
|
||||
"b" => $_SERVER["REQUEST_URI"] . "/toto"
|
||||
);',
|
||||
'aExpectedVarsMap' => array(
|
||||
'MySettings' =>array(),
|
||||
'MyModuleSettings' => array(),
|
||||
'MyModules' => array('b' => '$_SERVER["REQUEST_URI"] . "/toto"'),
|
||||
)
|
||||
),
|
||||
"test MyModules array of arrays" => array(
|
||||
'sInitialConfig' => '<?php
|
||||
$a=1;
|
||||
$MyModules = array(
|
||||
"date_and_time_format" => array (
|
||||
"default" =>
|
||||
array (
|
||||
"date" => "Y-m-d",
|
||||
"time" => "H:i:s",
|
||||
"date_time" => "$date $time",
|
||||
),
|
||||
),
|
||||
);',
|
||||
'aExpectedVarsMap' => array(
|
||||
'MySettings' =>array(),
|
||||
'MyModuleSettings' => array(),
|
||||
'MyModules' => array(
|
||||
'date_and_time_format' => 'array("default" => array("date" => "Y-m-d", "time" => "H:i:s", "date_time" => "{$date} {$time}"))'
|
||||
),
|
||||
)
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \ConfigException
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function testConfigWriteToFile()
|
||||
{
|
||||
$tmpConfigFileBeforePath = tempnam( '/tmp/', 'config-itop');
|
||||
$tmpConfigFileAfterPath = tempnam( '/tmp/', 'config-itop');
|
||||
|
||||
//create new config file
|
||||
$sConfigFile = utils::GetConfig()->GetLoadedFile();
|
||||
utils::GetConfig()->WriteToFile($tmpConfigFileBeforePath);
|
||||
|
||||
//add few dynamic configurations in MySettings section
|
||||
$tmpConfigContentBefore = file_get_contents($tmpConfigFileBeforePath);
|
||||
$expected_line = <<< CONF
|
||||
'app_root_url' => 'http://\$_SERVER[\\'SERVER_NAME\\']/iTop/',
|
||||
CONF;
|
||||
//add few dynamic configurations in MyModuleSettings section
|
||||
$tmpConfigNewContentBefore = preg_replace('/.*\'app_root_url.*,/', $expected_line, $tmpConfigContentBefore);
|
||||
$expected_line = <<< CONF
|
||||
\$MyModuleSettings = array(
|
||||
'shadok_module' => array ('gabu' => '\$_SERVER[\\'ZOMEU\\']'),
|
||||
CONF;
|
||||
$tmpConfigNewContentBefore = preg_replace('/\$MyModuleSettings = array\(/', $expected_line, $tmpConfigNewContentBefore);
|
||||
|
||||
//add few dynamic configurations in MyModules section
|
||||
$expected_line = <<< CONF
|
||||
'addons' => array(
|
||||
'user rights' => 'addons/userrights/userrightsprofile.class.inc.php',
|
||||
'user rights2' => '\$_SERVER[\\'TEST\\']'
|
||||
),
|
||||
CONF;
|
||||
$tmpConfigNewContentBefore = preg_replace('/.*\'addons.*/', $expected_line, $tmpConfigNewContentBefore);
|
||||
|
||||
unlink($tmpConfigFileBeforePath);
|
||||
fwrite(fopen($tmpConfigFileBeforePath, 'w'), $tmpConfigNewContentBefore);
|
||||
|
||||
//write same content again
|
||||
$config = new Config($tmpConfigFileBeforePath, true);
|
||||
$config->WriteToFile($tmpConfigFileAfterPath);
|
||||
|
||||
//compare
|
||||
$tmpConfigContentBefore = file_get_contents($tmpConfigFileAfterPath);
|
||||
$tmpConfigContentAfter = file_get_contents($tmpConfigFileAfterPath);
|
||||
unlink($tmpConfigFileAfterPath);
|
||||
unlink($tmpConfigFileBeforePath);
|
||||
$this->assertEquals($tmpConfigContentBefore, $tmpConfigContentAfter);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \ConfigException
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function testConfigWriteToFile_FromScratchInstallation()
|
||||
{
|
||||
$oConfig = new Config();
|
||||
clearstatcache();
|
||||
$oTestEnv = new RunTimeEnvironment('test-phpunit');
|
||||
$oTestEnv->WriteConfigFileSafe($oConfig);
|
||||
$this->assertTrue(true, "Config file was written");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
// Copyright (c) 2010-2017 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/>
|
||||
//
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Eric
|
||||
* Date: 03/11/2017
|
||||
* Time: 09:55
|
||||
*/
|
||||
|
||||
// --------------- Mock
|
||||
class utils
|
||||
{
|
||||
public static function GetCachePath()
|
||||
{
|
||||
return APPROOT.'data/cache-unittest/';
|
||||
}
|
||||
}
|
||||
|
||||
class UnitConfig
|
||||
{
|
||||
public function Get($sPropCode)
|
||||
{
|
||||
return UNIT_MAX_CACHE_FILES;
|
||||
}
|
||||
}
|
||||
|
||||
class MetaModel
|
||||
{
|
||||
public static function GetConfig()
|
||||
{
|
||||
return new UnitConfig;
|
||||
}
|
||||
}
|
||||
|
||||
// --------------- End Mock
|
||||
26
tests/php-unit-tests/unitary-tests/core/mockDict.incphp
Normal file
26
tests/php-unit-tests/unitary-tests/core/mockDict.incphp
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
// Copyright (c) 2010-2017 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/>
|
||||
//
|
||||
|
||||
class utils
|
||||
{
|
||||
public static function GetCurrentEnvironment()
|
||||
{
|
||||
return 'production';
|
||||
}
|
||||
}
|
||||
376
tests/php-unit-tests/unitary-tests/core/ormLinkSetTest.php
Normal file
376
tests/php-unit-tests/unitary-tests/core/ormLinkSetTest.php
Normal file
@@ -0,0 +1,376 @@
|
||||
<?php
|
||||
// Copyright (c) 2010-2017 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/>
|
||||
//
|
||||
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Eric
|
||||
* Date: 20/12/2017
|
||||
* Time: 11:56
|
||||
*/
|
||||
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Core;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use Exception;
|
||||
use ormLinkSet;
|
||||
|
||||
|
||||
/**
|
||||
* Tests of the ormLinkSet class using N-N links between FunctionalCI and Contact
|
||||
*
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class ormLinkSetTest extends ItopDataTestCase
|
||||
{
|
||||
const CREATE_TEST_ORG = true;
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function testConstruct()
|
||||
{
|
||||
$oOrmLink = new ormLinkSet('UserRequest', 'contacts_list');
|
||||
static::assertNotNull($oOrmLink);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function testConstruct2()
|
||||
{
|
||||
$this->expectException('Exception');
|
||||
|
||||
new ormLinkSet('UserRequest', 'ref');
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testBasic()
|
||||
{
|
||||
$oServer = $this->CreateServer(1);
|
||||
$aPersons = array();
|
||||
for ($i = 0; $i < 3; $i++)
|
||||
{
|
||||
$oPerson = $this->CreatePerson($i);
|
||||
$aPersons[] = $oPerson;
|
||||
$this->AddContactToCI($oPerson, $oServer);
|
||||
}
|
||||
$oServer->DBUpdate();
|
||||
$this->ReloadObject($oServer);
|
||||
|
||||
$oContactsSet = $oServer->Get('contacts_list');
|
||||
static::assertEquals(3, $oContactsSet->Count());
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testSuccesiveAdds()
|
||||
{
|
||||
$oServer = $this->CreateServer(1);
|
||||
$aPersons = array();
|
||||
for ($i = 0; $i < 3; $i++)
|
||||
{
|
||||
$oPerson = $this->CreatePerson($i);
|
||||
$aPersons[] = $oPerson;
|
||||
$this->AddContactToCI($oPerson, $oServer);
|
||||
}
|
||||
$oServer->DBUpdate();
|
||||
$this->ReloadObject($oServer);
|
||||
|
||||
$oContactsSet = $oServer->Get('contacts_list');
|
||||
static::assertEquals(3, $oContactsSet->Count());
|
||||
|
||||
$this->AddContactToCI($this->CreatePerson($i), $oServer);
|
||||
$oContactsSet = $oServer->Get('contacts_list');
|
||||
static::assertEquals(4, $oContactsSet->Count());
|
||||
|
||||
$oServer->DBUpdate();
|
||||
$this->ReloadObject($oServer);
|
||||
|
||||
$oContactsSet = $oServer->Get('contacts_list');
|
||||
static::assertEquals(4, $oContactsSet->Count());
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testRemove()
|
||||
{
|
||||
$oServer = $this->CreateServer(1);
|
||||
$aPersons = array();
|
||||
for ($i = 0; $i < 3; $i++)
|
||||
{
|
||||
$oPerson = $this->CreatePerson($i);
|
||||
$aPersons[] = $oPerson;
|
||||
$this->AddContactToCI($oPerson, $oServer);
|
||||
}
|
||||
$oServer->DBUpdate();
|
||||
$this->ReloadObject($oServer);
|
||||
|
||||
$oContactsSet = $oServer->Get('contacts_list');
|
||||
static::assertEquals(3, $oContactsSet->Count());
|
||||
|
||||
for ($i = 0; $i < 3; $i++)
|
||||
{
|
||||
$this->RemoveContactFromCI($aPersons[$i], $oServer);
|
||||
}
|
||||
$oContactsSet = $oServer->Get('contacts_list');
|
||||
static::assertEquals(0, $oContactsSet->Count());
|
||||
|
||||
$oServer->DBUpdate();
|
||||
$this->ReloadObject($oServer);
|
||||
|
||||
$oContactsSet = $oServer->Get('contacts_list');
|
||||
static::assertEquals(0, $oContactsSet->Count());
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testAddThenRemove()
|
||||
{
|
||||
$oServer = $this->CreateServer(1);
|
||||
for ($i = 0; $i < 3; $i++)
|
||||
{
|
||||
$oPerson = $this->CreatePerson($i);
|
||||
$this->AddContactToCI($oPerson, $oServer);
|
||||
$this->RemoveContactFromCI($oPerson, $oServer);
|
||||
}
|
||||
$oContactsSet = $oServer->Get('contacts_list');
|
||||
static::assertEquals(0, $oContactsSet->Count());
|
||||
|
||||
$oServer->DBUpdate();
|
||||
$this->ReloadObject($oServer);
|
||||
|
||||
$oContactsSet = $oServer->Get('contacts_list');
|
||||
static::assertEquals(0, $oContactsSet->Count());
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testRemoveThenAdd()
|
||||
{
|
||||
$oServer = $this->CreateServer(1);
|
||||
$aPersons = array();
|
||||
for ($i = 0; $i < 3; $i++)
|
||||
{
|
||||
$oPerson = $this->CreatePerson($i);
|
||||
$aPersons[] = $oPerson;
|
||||
$this->AddContactToCI($oPerson, $oServer);
|
||||
}
|
||||
$oServer->DBUpdate();
|
||||
$this->ReloadObject($oServer);
|
||||
|
||||
$oContactsSet = $oServer->Get('contacts_list');
|
||||
static::assertEquals(3, $oContactsSet->Count());
|
||||
|
||||
for ($i = 0; $i < 3; $i++)
|
||||
{
|
||||
$this->RemoveContactFromCI($aPersons[$i], $oServer);
|
||||
$this->AddContactToCI($aPersons[$i], $oServer);
|
||||
}
|
||||
$oContactsSet = $oServer->Get('contacts_list');
|
||||
static::assertEquals(3, $oContactsSet->Count());
|
||||
|
||||
$oServer->DBUpdate();
|
||||
$this->ReloadObject($oServer);
|
||||
|
||||
$oContactsSet = $oServer->Get('contacts_list');
|
||||
static::assertEquals(3, $oContactsSet->Count());
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testAddDuplicate()
|
||||
{
|
||||
$oServer = $this->CreateServer(1);
|
||||
$aPersons = array();
|
||||
for ($i = 0; $i < 3; $i++)
|
||||
{
|
||||
$oPerson = $this->CreatePerson($i);
|
||||
$aPersons[] = $oPerson;
|
||||
$this->AddContactToCI($oPerson, $oServer);
|
||||
}
|
||||
$oServer->DBUpdate();
|
||||
$this->ReloadObject($oServer);
|
||||
|
||||
$oContactsSet = $oServer->Get('contacts_list');
|
||||
static::assertEquals(3, $oContactsSet->Count());
|
||||
|
||||
for ($i = 0; $i < 3; $i++)
|
||||
{
|
||||
$this->AddContactToCI($aPersons[$i], $oServer);
|
||||
}
|
||||
$oContactsSet = $oServer->Get('contacts_list');
|
||||
static::assertEquals(6, $oContactsSet->Count());
|
||||
|
||||
$oServer->DBUpdate();
|
||||
$this->ReloadObject($oServer);
|
||||
|
||||
$oContactsSet = $oServer->Get('contacts_list');
|
||||
static::assertEquals(3, $oContactsSet->Count());
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testModifyThenRemove()
|
||||
{
|
||||
$oServer = $this->CreateServer(1);
|
||||
$aPersons = array();
|
||||
for ($i = 0; $i < 3; $i++)
|
||||
{
|
||||
$oPerson = $this->CreatePerson($i);
|
||||
$aPersons[] = $oPerson;
|
||||
$this->AddContactToCI($oPerson, $oServer);
|
||||
}
|
||||
|
||||
$oServer->DBUpdate();
|
||||
$this->ReloadObject($oServer);
|
||||
|
||||
for ($i = 3; $i < 6; $i++)
|
||||
{
|
||||
$oPerson = $this->CreatePerson($i);
|
||||
$this->AddContactToCI($oPerson, $oServer);
|
||||
}
|
||||
|
||||
for ($i = 0; $i < 3; $i++)
|
||||
{
|
||||
$this->RemoveContactFromCI($aPersons[$i], $oServer);
|
||||
}
|
||||
|
||||
$oContactsSet = $oServer->Get('contacts_list');
|
||||
static::assertEquals(3, $oContactsSet->Count());
|
||||
}
|
||||
|
||||
/**
|
||||
* don't work cf bug N°4402
|
||||
* @throws Exception
|
||||
*/
|
||||
/*public function testListPreviousValuesForUpdatedAttributes_AttributeLinkedSetIndirect()
|
||||
{
|
||||
$oServer = $this->CreateServer(1);
|
||||
$oPerson = $this->CreatePerson(0);
|
||||
$this->AddContactToCI($oPerson, $oServer);
|
||||
|
||||
$oServer->DBUpdate();
|
||||
$this->ReloadObject($oServer);
|
||||
|
||||
$oPerson = $this->CreatePerson(1);
|
||||
$this->AddContactToCI($oPerson, $oServer);
|
||||
|
||||
$oServer->DBUpdate();
|
||||
$oSetOldFcisList = $oServer->ListPreviousValuesForUpdatedAttributes()['contacts_list']->ToDBObjectSet();
|
||||
|
||||
static::assertEquals(1, $oSetOldFcisList->Count());
|
||||
}*/
|
||||
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testListPreviousValuesForUpdatedAttributes_AttributeString()
|
||||
{
|
||||
$oServer = $this->CreateServer(1);
|
||||
$oServer->Set('serialnumber', 'my serialnumber');
|
||||
$oServer->DBUpdate();
|
||||
static::assertEquals('', $oServer->ListPreviousValuesForUpdatedAttributes()['serialnumber']);
|
||||
|
||||
$this->ReloadObject($oServer);
|
||||
$oServer->Set('serialnumber', 'my serialnumber2');
|
||||
$oServer->DBUpdate();
|
||||
static::assertEquals('my serialnumber', $oServer->ListPreviousValuesForUpdatedAttributes()['serialnumber']);
|
||||
|
||||
}
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testListPreviousValuesForUpdatedAttributes_AttributeExternalKey()
|
||||
{
|
||||
$oServer = $this->CreateServer(1);
|
||||
$idOrgInit = $oServer->Get('org_id');
|
||||
|
||||
$oOrganization = $this->CreateOrganization(1);
|
||||
$oServer->Set('org_id',$oOrganization);
|
||||
$oServer->DBUpdate();
|
||||
static::assertEquals($idOrgInit, $oServer->ListPreviousValuesForUpdatedAttributes()['org_id']);
|
||||
static::assertNotEquals($oOrganization->GetKey(), $oServer->ListPreviousValuesForUpdatedAttributes()['org_id']);
|
||||
static::assertEquals($oOrganization->GetKey(), $oServer->Get('org_id'));
|
||||
}
|
||||
/**
|
||||
* don't work cf bug N°4402
|
||||
* @throws Exception
|
||||
*/
|
||||
/*public function testListPreviousValuesForUpdatedAttributes_AttributeExternalField()
|
||||
{
|
||||
$oServer = $this->CreateServer(1);
|
||||
$OrgInit = $oServer->Get('organization_name');
|
||||
|
||||
$oOrganization = $this->CreateOrganization('Serv1');
|
||||
$oServer->Set('org_id',$oOrganization);
|
||||
$oServer->DBUpdate();
|
||||
//static::assertEquals($OrgInit, json_encode($oServer->ListPreviousValuesForUpdatedAttributes()));
|
||||
static::assertEquals($OrgInit, $oServer->ListPreviousValuesForUpdatedAttributes()['organization_name']);
|
||||
static::assertNotEquals($oOrganization->Get('name'), $oServer->ListPreviousValuesForUpdatedAttributes()['organization_name']);
|
||||
static::assertEquals($oOrganization->Get('name'), $oServer->Get('organization_name'));
|
||||
}*/
|
||||
|
||||
/**
|
||||
* don't work cf bug N°4402
|
||||
* @throws Exception
|
||||
*/
|
||||
/*public function testListPreviousValuesForUpdatedAttributes_AttributeLinkedSet()
|
||||
{
|
||||
$oServer = $this->CreateServer(1);
|
||||
$oPhysicalInterface = $this->CreatePhysicalInterface(1, 1000, $oServer->GetKey());
|
||||
$this->debug("Created PhysicalInterface {$oPhysicalInterface->GetName()} ({$oPhysicalInterface->GetKey()})");
|
||||
$oServer->DBUpdate();
|
||||
$this->ReloadObject($oServer);
|
||||
$this->debug("Nb PhysicalInterface".$oServer->Get('physicalinterface_list')->Count());
|
||||
$oPhysicalInterface2 = $this->CreatePhysicalInterface(2, 1000, $oServer->GetKey());
|
||||
$this->debug("Created PhysicalInterface {$oPhysicalInterface2->GetName()} ({$oPhysicalInterface2->GetKey()})");
|
||||
$oServer->DBUpdate();
|
||||
$oSetOldFcisList=$oServer->Get('physicalinterface_list')->ToDBObjectSet();
|
||||
while ($oObject = $oSetOldFcisList->Fetch())
|
||||
{
|
||||
$this->debug("PI: ".get_class($oObject).": ".$oObject->GetKey());
|
||||
}
|
||||
$this->debug("Nb PhysicalInterface".$oServer->Get('physicalinterface_list')->Count());
|
||||
//$oSetOldFcisList = $oServer->ListPreviousValuesForUpdatedAttributes()['physicalinterface_list']->ToDBObjectSet();
|
||||
|
||||
static::assertEquals(1, $oSetOldFcisList->Count());
|
||||
}*/
|
||||
|
||||
}
|
||||
306
tests/php-unit-tests/unitary-tests/core/ormTagSetTest.php
Normal file
306
tests/php-unit-tests/unitary-tests/core/ormTagSetTest.php
Normal file
@@ -0,0 +1,306 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (c) 2010-2018 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/>
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Eric
|
||||
* Date: 27/08/2018
|
||||
* Time: 17:26
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Core;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use CoreException;
|
||||
use Exception;
|
||||
use ormTagSet;
|
||||
|
||||
define('MAX_TAGS', 12);
|
||||
|
||||
/**
|
||||
* Tests of the ormTagSet class
|
||||
*
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class ormTagSetTest extends ItopDataTestCase
|
||||
{
|
||||
const CREATE_TEST_ORG = true;
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->CreateTagData(TAG_CLASS, TAG_ATTCODE, 'tag1', 'First');
|
||||
$this->CreateTagData(TAG_CLASS, TAG_ATTCODE, 'tag2', 'Second');
|
||||
$this->CreateTagData(TAG_CLASS, TAG_ATTCODE, 'tag3', 'Third');
|
||||
$this->CreateTagData(TAG_CLASS, TAG_ATTCODE, 'tag4', 'Fourth');
|
||||
}
|
||||
|
||||
public function testGetTagDataClass()
|
||||
{
|
||||
$oTagSet = new ormTagSet(TAG_CLASS, TAG_ATTCODE, MAX_TAGS);
|
||||
static::assertEquals($oTagSet->GetTagDataClass(), 'TagSetFieldDataFor_'.TAG_CLASS.'__'.TAG_ATTCODE);
|
||||
}
|
||||
|
||||
public function testGetValue()
|
||||
{
|
||||
$oTagSet = new ormTagSet(TAG_CLASS, TAG_ATTCODE, MAX_TAGS);
|
||||
static::assertEquals($oTagSet->GetValues(), array());
|
||||
|
||||
$oTagSet->Add('tag1');
|
||||
static::assertEquals($oTagSet->GetValues(), array('tag1'));
|
||||
|
||||
$oTagSet->Add('tag2');
|
||||
static::assertEquals($oTagSet->GetValues(), array('tag1', 'tag2'));
|
||||
}
|
||||
|
||||
public function testAddTag()
|
||||
{
|
||||
$oTagSet = new ormTagSet(TAG_CLASS, TAG_ATTCODE, MAX_TAGS);
|
||||
|
||||
$oTagSet->Add('tag1');
|
||||
static::assertEquals($oTagSet->GetValues(), array('tag1'));
|
||||
|
||||
$oTagSet->SetValues(array('tag1', 'tag2'));
|
||||
static::assertEquals($oTagSet->GetValues(), array('tag1', 'tag2'));
|
||||
|
||||
$oTagSet->Remove('tag1');
|
||||
static::assertEquals($oTagSet->GetValues(), array('tag2'));
|
||||
|
||||
$oTagSet->Add('tag1');
|
||||
static::assertEquals($oTagSet->GetValues(), array('tag1', 'tag2'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @expectedException \CoreException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
*/
|
||||
public function testMaxTagLimit()
|
||||
{
|
||||
$oTagSet = new ormTagSet(TAG_CLASS, TAG_ATTCODE, 3);
|
||||
|
||||
$oTagSet->SetValues(array('tag1', 'tag2', 'tag3'));
|
||||
|
||||
static::assertEquals($oTagSet->GetValues(), array('tag1', 'tag2', 'tag3'));
|
||||
|
||||
try
|
||||
{
|
||||
$oTagSet->SetValues(array('tag1', 'tag2', 'tag3', 'tag4'));
|
||||
}
|
||||
catch (CoreException $e)
|
||||
{
|
||||
$this->debug('Awaited: '.$e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
public function testEquals()
|
||||
{
|
||||
$oTagSet1 = new ormTagSet(TAG_CLASS, TAG_ATTCODE, MAX_TAGS);
|
||||
$oTagSet1->Add('tag1');
|
||||
static::assertTrue($oTagSet1->Equals($oTagSet1));
|
||||
|
||||
$oTagSet2 = new ormTagSet(TAG_CLASS, TAG_ATTCODE, MAX_TAGS);
|
||||
$oTagSet2->SetValues(array('tag1'));
|
||||
|
||||
static::assertTrue($oTagSet1->Equals($oTagSet2));
|
||||
|
||||
$oTagSet1->Add('tag2');
|
||||
static::assertFalse($oTagSet1->Equals($oTagSet2));
|
||||
}
|
||||
|
||||
public function testSetValue()
|
||||
{
|
||||
$oTagSet = new ormTagSet(TAG_CLASS, TAG_ATTCODE, MAX_TAGS);
|
||||
|
||||
$oTagSet->SetValues(array('tag1'));
|
||||
static::assertEquals($oTagSet->GetValues(), array('tag1'));
|
||||
|
||||
$oTagSet->SetValues(array('tag1', 'tag2'));
|
||||
static::assertEquals($oTagSet->GetValues(), array('tag1', 'tag2'));
|
||||
|
||||
}
|
||||
|
||||
public function testRemoveTag()
|
||||
{
|
||||
$oTagSet = new ormTagSet(TAG_CLASS, TAG_ATTCODE, MAX_TAGS);
|
||||
$oTagSet->Remove('tag_unknown');
|
||||
static::assertEquals($oTagSet->GetValues(), array());
|
||||
|
||||
$oTagSet->SetValues(array('tag1'));
|
||||
$oTagSet->Remove('tag_unknown');
|
||||
static::assertEquals($oTagSet->GetValues(), array('tag1'));
|
||||
|
||||
$oTagSet->SetValues(array('tag1', 'tag2'));
|
||||
$oTagSet->Remove('tag1');
|
||||
static::assertEquals($oTagSet->GetValues(), array('tag2'));
|
||||
|
||||
$oTagSet->Add('tag1');
|
||||
static::assertEquals($oTagSet->GetValues(), array('tag1', 'tag2'));
|
||||
|
||||
$oTagSet->Remove('tag1');
|
||||
static::assertEquals($oTagSet->GetValues(), array('tag2'));
|
||||
|
||||
$oTagSet->Remove('tag1');
|
||||
static::assertEquals($oTagSet->GetValues(), array('tag2'));
|
||||
|
||||
$oTagSet->Remove('tag2');
|
||||
static::assertEquals($oTagSet->GetValues(), array());
|
||||
}
|
||||
|
||||
public function testGetDelta()
|
||||
{
|
||||
$oTagSet1 = new ormTagSet(TAG_CLASS, TAG_ATTCODE, MAX_TAGS);
|
||||
$oTagSet1->SetValues(array('tag1', 'tag2'));
|
||||
|
||||
$oTagSet2 = new ormTagSet(TAG_CLASS, TAG_ATTCODE, MAX_TAGS);
|
||||
$oTagSet2->SetValues(array('tag1', 'tag3', 'tag4'));
|
||||
|
||||
$aDelta = $oTagSet1->GetDelta($oTagSet2);
|
||||
static::assertCount(2, $aDelta);
|
||||
static::assertCount(2, $aDelta['added']);
|
||||
static::assertCount(1, $aDelta['removed']);
|
||||
}
|
||||
|
||||
public function testApplyDelta()
|
||||
{
|
||||
$oTagSet1 = new ormTagSet(TAG_CLASS, TAG_ATTCODE, MAX_TAGS);
|
||||
$oTagSet1->SetValues(array('tag1', 'tag2'));
|
||||
|
||||
$oTagSet2 = new ormTagSet(TAG_CLASS, TAG_ATTCODE, MAX_TAGS);
|
||||
$oTagSet2->SetValues(array('tag1', 'tag3', 'tag4'));
|
||||
|
||||
$aDelta = $oTagSet1->GetDelta($oTagSet2);
|
||||
|
||||
$oTagSet1->ApplyDelta($aDelta);
|
||||
|
||||
static::assertTrue($oTagSet1->Equals($oTagSet2));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $aInitialTags
|
||||
* @param $aDiffTags
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
*
|
||||
* @dataProvider GetModifiedProvider
|
||||
*/
|
||||
public function testGetModified($aInitialTags, $aDiffAndExpectedTags)
|
||||
{
|
||||
$oTagSet1 = new ormTagSet(TAG_CLASS, TAG_ATTCODE, MAX_TAGS);
|
||||
$oTagSet1->SetValues($aInitialTags);
|
||||
|
||||
foreach($aDiffAndExpectedTags as $aTestItem)
|
||||
{
|
||||
$oTagSet1->GenerateDiffFromArray($aTestItem['diff']);
|
||||
static::assertEquals($aTestItem['modified'], $oTagSet1->GetModified());
|
||||
}
|
||||
}
|
||||
|
||||
public function GetModifiedProvider()
|
||||
{
|
||||
return array(
|
||||
array(
|
||||
array('tag2'),
|
||||
array(
|
||||
array('diff' => array('tag1', 'tag2'), 'modified' => array('tag1')),
|
||||
array('diff' => array('tag2'), 'modified' => array('tag1')),
|
||||
array('diff' => array(), 'modified' => array('tag1', 'tag2')),
|
||||
)
|
||||
),
|
||||
array(
|
||||
array('tag1', 'tag2'),
|
||||
array(
|
||||
array('diff' => array('tag1', 'tag3'), 'modified' => array('tag2', 'tag3')),
|
||||
array('diff' => array('tag1', 'tag2'), 'modified' => array('tag2', 'tag3')),
|
||||
array('diff' => array('tag1', 'tag2', 'tag3', 'tag4'), 'modified' => array('tag2', 'tag3', 'tag4')),
|
||||
)
|
||||
),
|
||||
array(
|
||||
array(),
|
||||
array(
|
||||
array('diff' => array('tag2'), 'modified' => array('tag2')),
|
||||
array('diff' => array('tag1', 'tag2'), 'modified' => array('tag1', 'tag2')),
|
||||
array('diff' => array('tag2'), 'modified' => array('tag1', 'tag2')),
|
||||
)
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $aInitialTags
|
||||
* @param $aDelta
|
||||
* @param $aExpectedTags
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \Exception
|
||||
* @dataProvider BulkModifyProvider
|
||||
*/
|
||||
public function testBulkModify($aInitialTags, $aDelta, $aExpectedTags)
|
||||
{
|
||||
$oTagSet1 = new ormTagSet(TAG_CLASS, TAG_ATTCODE, MAX_TAGS);
|
||||
$oTagSet1->SetValues($aInitialTags);
|
||||
|
||||
$oTagSet1->ApplyDelta($aDelta);
|
||||
|
||||
static::assertEquals($aExpectedTags, $oTagSet1->GetValues());
|
||||
}
|
||||
|
||||
public function BulkModifyProvider()
|
||||
{
|
||||
return array(
|
||||
'Add one tag' => array(
|
||||
array('tag1', 'tag2'),
|
||||
array('added' => array('tag3')),
|
||||
array('tag1', 'tag2', 'tag3')
|
||||
),
|
||||
'Remove one tag' => array(
|
||||
array('tag1', 'tag2'),
|
||||
array('removed' => array('tag2')),
|
||||
array('tag1')
|
||||
),
|
||||
'Remove unexisting tag' => array(
|
||||
array('tag1', 'tag2'),
|
||||
array('removed' => array('tag3')),
|
||||
array('tag1', 'tag2')
|
||||
),
|
||||
'Add one and remove one tag' => array(
|
||||
array('tag1', 'tag2'),
|
||||
array('added' => array('tag3'), 'removed' => array('tag2')),
|
||||
array('tag1', 'tag3')
|
||||
),
|
||||
'Remove first tag' => array(
|
||||
array('tag1', 'tag2'),
|
||||
array('removed' => array('tag1')),
|
||||
array('tag2')
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Core\Sanitizer;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
|
||||
abstract class AbstractDOMSanitizerTest extends ItopTestCase
|
||||
{
|
||||
const INPUT_DIRECTORY = 'input';
|
||||
const OUTPUT_DIRECTORY = 'output';
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
require_once(APPROOT.'application/utils.inc.php');
|
||||
require_once(APPROOT.'core/htmlsanitizer.class.inc.php');
|
||||
}
|
||||
|
||||
protected function ReadTestFile($sFileToTest, $sFolderName)
|
||||
{
|
||||
$sCurrentPath = __DIR__;
|
||||
|
||||
return file_get_contents($sCurrentPath.DIRECTORY_SEPARATOR
|
||||
.$sFolderName.DIRECTORY_SEPARATOR
|
||||
.$sFileToTest);
|
||||
}
|
||||
|
||||
protected function RemoveNewLines($sText)
|
||||
{
|
||||
$sText = str_replace("\r\n", "\n", $sText);
|
||||
$sText = str_replace("\r", "\n", $sText);
|
||||
$sText = str_replace("\n", '', $sText);
|
||||
|
||||
return $sText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an appropriate value for the given attribute, or use the counter if needed.
|
||||
* This is necessary as most of the attributes with empty or inappropriate values (like a numeric for a href) are removed by the parser
|
||||
*
|
||||
* @param string $sTagAttribute
|
||||
* @param int $iAttributeCounter
|
||||
*
|
||||
* @return string attribute value
|
||||
*/
|
||||
protected function GetTagAttributeValue($sTagAttribute, $iAttributeCounter)
|
||||
{
|
||||
$sTagAttrValue = ' '.$sTagAttribute.'="';
|
||||
if (in_array($sTagAttribute, array('href', 'src'))) {
|
||||
return $sTagAttrValue.'http://www.combodo.com"';
|
||||
}
|
||||
|
||||
if ($sTagAttribute === 'style') {
|
||||
return $sTagAttrValue.'color: black"';
|
||||
}
|
||||
|
||||
return $sTagAttrValue.$iAttributeCounter.'"';
|
||||
}
|
||||
|
||||
protected function IsClosingTag($sTag)
|
||||
{
|
||||
if (in_array($sTag, array('br', 'img', 'hr'))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,258 @@
|
||||
<?php
|
||||
namespace Combodo\iTop\Test\UnitTest\Core\Sanitizer;
|
||||
|
||||
use HTMLDOMSanitizer;
|
||||
use InlineImageMock;
|
||||
|
||||
|
||||
require_once __DIR__.'/AbstractDOMSanitizerTest.php';
|
||||
|
||||
|
||||
class HTMLDOMSanitizerTest extends AbstractDOMSanitizerTest
|
||||
{
|
||||
/**
|
||||
* @dataProvider DoSanitizeProvider
|
||||
*
|
||||
* @param string $sFileToTest filename
|
||||
*/
|
||||
public function testDoSanitize($sFileToTest)
|
||||
{
|
||||
$sInputHtml = $this->ReadTestFile($sFileToTest, self::INPUT_DIRECTORY);
|
||||
$sOutputHtml = $this->ReadTestFile($sFileToTest, self::OUTPUT_DIRECTORY);
|
||||
$sOutputHtml = $this->RemoveNewLines($sOutputHtml);
|
||||
|
||||
$oSanitizer = new HTMLDOMSanitizer();
|
||||
$sRes = $oSanitizer->DoSanitize($sInputHtml);
|
||||
|
||||
// Removing newlines as the parser gives different results depending on the PHP version
|
||||
// Didn't manage to get it right :
|
||||
// - no php.ini difference
|
||||
// - playing with the parser preserveWhitespace/formatOutput parser options didn't help
|
||||
// So we're removing new lines on both sides :/
|
||||
$sOutputHtml = $this->RemoveNewLines($sOutputHtml);
|
||||
$sRes = $this->RemoveNewLines($sRes);
|
||||
|
||||
$this->debug($sRes);
|
||||
$this->assertEquals($sOutputHtml, $sRes);
|
||||
}
|
||||
|
||||
public function DoSanitizeProvider()
|
||||
{
|
||||
return array(
|
||||
array(
|
||||
'scripts.html',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider WhiteListProvider
|
||||
*
|
||||
* @param string $sHtmlToTest HTML content
|
||||
*/
|
||||
public function testDoSanitizeWhiteList($sHtmlToTest)
|
||||
{
|
||||
$oSanitizer = new HTMLDOMSanitizer();
|
||||
$sRes = $oSanitizer->DoSanitize($sHtmlToTest);
|
||||
|
||||
// Removing newlines as the parser gives different results depending on the PHP version
|
||||
// Didn't manage to get it right :
|
||||
// - no php.ini difference
|
||||
// - playing with the parser preserveWhitespace/formatOutput parser options didn't help
|
||||
// So we're removing new lines on both sides :/
|
||||
$sHtmlToTest = $this->RemoveNewLines($sHtmlToTest);
|
||||
$sRes = $this->RemoveNewLines($sRes);
|
||||
|
||||
$this->debug($sRes);
|
||||
$this->assertEquals($sHtmlToTest, $sRes);
|
||||
}
|
||||
|
||||
public function WhiteListProvider()
|
||||
{
|
||||
// This is a copy of \HTMLDOMSanitizer::$aTagsWhiteList
|
||||
// should stay a copy as we want to check we're not removing something by mistake as it was done with the CENTER tag (N°2558)
|
||||
$aTagsWhiteList = array(
|
||||
// we don't test HTML and BODY as the parser removes them if context isn't appropriate
|
||||
'a' => array('href', 'name', 'style', 'target', 'title'),
|
||||
'p' => array('style'),
|
||||
'blockquote' => array('style'),
|
||||
'br' => array(),
|
||||
'span' => array('style'),
|
||||
'div' => array('style'),
|
||||
'b' => array(),
|
||||
'i' => array(),
|
||||
'u' => array(),
|
||||
'em' => array(),
|
||||
'strong' => array(),
|
||||
'img' => array('src', 'style', 'alt', 'title'),
|
||||
'ul' => array('style'),
|
||||
'ol' => array('style'),
|
||||
'li' => array('style'),
|
||||
'h1' => array('style'),
|
||||
'h2' => array('style'),
|
||||
'h3' => array('style'),
|
||||
'h4' => array('style'),
|
||||
'nav' => array('style'),
|
||||
'section' => array('style'),
|
||||
'code' => array('style'),
|
||||
'table' => array('style', 'width', 'summary', 'align', 'border', 'cellpadding', 'cellspacing'),
|
||||
'thead' => array('style'),
|
||||
'tbody' => array('style'),
|
||||
'tr' => array('style', 'colspan', 'rowspan'),
|
||||
'td' => array('style', 'colspan', 'rowspan'),
|
||||
'th' => array('style', 'colspan', 'rowspan'),
|
||||
'fieldset' => array('style'),
|
||||
'legend' => array('style'),
|
||||
'font' => array('face', 'color', 'style', 'size'),
|
||||
'big' => array(),
|
||||
'small' => array(),
|
||||
'tt' => array(),
|
||||
'kbd' => array(),
|
||||
'samp' => array(),
|
||||
'var' => array(),
|
||||
'del' => array(),
|
||||
's' => array(), // strikethrough
|
||||
'ins' => array(),
|
||||
'cite' => array(),
|
||||
'q' => array(),
|
||||
'hr' => array('style'),
|
||||
'pre' => array(),
|
||||
'center' => array(),
|
||||
);
|
||||
$aTestCaseArray = array();
|
||||
|
||||
$sInputText = $this->ReadTestFile('whitelist_test.html', self::INPUT_DIRECTORY);
|
||||
foreach ($aTagsWhiteList as $sTag => $aTagAttributes) {
|
||||
$sTestCaseText = $sInputText;
|
||||
$sStartTag = "<$sTag";
|
||||
$iAttrCounter = 0;
|
||||
foreach ($aTagAttributes as $sTagAttribute) {
|
||||
$sStartTag .= $this->GetTagAttributeValue($sTagAttribute, $iAttrCounter);
|
||||
$iAttrCounter++;
|
||||
}
|
||||
$sStartTag .= '>';
|
||||
$sTestCaseText = str_replace('##START_TAG##', $sStartTag, $sTestCaseText);
|
||||
|
||||
$sClosingTag = $this->IsClosingTag($sTag) ? "</$sTag>" : '';
|
||||
$sTestCaseText = str_replace('##END_TAG##', $sClosingTag, $sTestCaseText);
|
||||
|
||||
$aTestCaseArray[$sTag] = array($sTestCaseText);
|
||||
}
|
||||
|
||||
return $aTestCaseArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider RemoveBlackListedTagContentProvider
|
||||
*/
|
||||
public function testDoSanitizeRemoveBlackListedTagContent($html, $expected)
|
||||
{
|
||||
$oSanitizer = new HTMLDOMSanitizer();
|
||||
$sSanitizedHtml = $oSanitizer->DoSanitize($html);
|
||||
|
||||
$this->assertEquals($expected, str_replace("\n", '', $sSanitizedHtml));
|
||||
}
|
||||
|
||||
public function RemoveBlackListedTagContentProvider()
|
||||
{
|
||||
return array(
|
||||
'basic' => array(
|
||||
'html' => 'foo<iframe>bar</iframe>baz',
|
||||
'expected' => '<p>foobaz</p>',
|
||||
),
|
||||
'basic with body' => array(
|
||||
'html' => '<body>foo<iframe>bar</iframe>baz</body>',
|
||||
'expected' => 'foobaz',
|
||||
),
|
||||
'basic with html and body tags' => array(
|
||||
'html' => '<html><body lang="EN-GB" link="#0563C1" vlink="#954F72">foo<iframe>bar</iframe>baz</body></html>',
|
||||
'expected' => 'foobaz',
|
||||
),
|
||||
'basic with attributes' => array(
|
||||
'html' => 'foo<iframe baz="1">bar</iframe>baz',
|
||||
'expected' => '<p>foobaz</p>',
|
||||
),
|
||||
'basic with comment' => array(
|
||||
'html' => 'foo<iframe baz="1">bar<!-- foo --></iframe>baz',
|
||||
'expected' => '<p>foobaz</p>',
|
||||
),
|
||||
'basic with contentRemovable tag' => array(
|
||||
'html' => 'foo<iframe baz="1">bar<style>foo</style><script>boo</script></iframe>baz',
|
||||
'expected' => '<p>foobaz</p>',
|
||||
),
|
||||
'nested' => array(
|
||||
'html' => 'before<iframe>foo<article>baz</article>oof<article><iframe>bar</iframe>oof</article></iframe>after',
|
||||
'expected' => '<p>beforeafter</p>',
|
||||
),
|
||||
'nested with not closed br' => array(
|
||||
'html' => 'before<iframe>foo<article>baz</article>oof<br><article><iframe>bar</iframe>oof</article></iframe>after',
|
||||
'expected' => '<p>beforeafter</p>',
|
||||
),
|
||||
'nested with allowed' => array(
|
||||
'html' => 'before<iframe><div><article><p>baz</p>zab</article></div>oof</iframe>after',
|
||||
'expected' => '<p>beforeafter</p>',
|
||||
),
|
||||
'nested with spaces' => array(
|
||||
'html' => 'before<iframe><article>baz</article> oof</iframe>after',
|
||||
'expected' => '<p>beforeafter</p>',
|
||||
),
|
||||
'nested with attributes' => array(
|
||||
'html' => 'before<iframe baz="1"><article baz="1" biz="2">baz</article>oof</iframe>after',
|
||||
'expected' => '<p>beforeafter</p>',
|
||||
),
|
||||
'nested with allowed and attributes and spaces ' => array(
|
||||
'html' => '<html><body>before<iframe baz="1"><div baz="baz"><article baz="1" biz="2">baz</article>rab</div> oof</iframe>after</body></html>',
|
||||
'expected' => 'beforeafter',
|
||||
),
|
||||
'nested with allowed and contentRemovable tags' => array(
|
||||
'html' => '<html><body>before<iframe baz="1"><div ><article>baz</article>rab</div> oof<embed>embedTExt</embed></iframe>middle<style>foo</style>after<script>boo</script></body></html>',
|
||||
'expected' => 'beforemiddleafter',
|
||||
),
|
||||
|
||||
'regression: if head present => body is not trimmed' => array(
|
||||
'html' => '<html><head></head><body lang="EN-GB" link="#0563C1" vlink="#954F72">bar</body></html>',
|
||||
'expected' => 'bar',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider CallInlineImageProcessImageTagProvider
|
||||
* @uses \InlineImageMock
|
||||
*/
|
||||
public function testDoSanitizeCallInlineImageProcessImageTag($sHtml, $iExpectedCount)
|
||||
{
|
||||
require_once APPROOT.'tests/core/sanitizer/InlineImageMock.php';
|
||||
InlineImageMock::ResetCallCounter();
|
||||
|
||||
$oSanitizer = new HTMLDOMSanitizer(InlineImageMock::class);
|
||||
$oSanitizer->DoSanitize($sHtml);
|
||||
|
||||
$iCalledCount = \InlineImageMock::GetCallCounter();
|
||||
$this->assertEquals($iExpectedCount, $iCalledCount);
|
||||
}
|
||||
|
||||
public function CallInlineImageProcessImageTagProvider()
|
||||
{
|
||||
return array(
|
||||
'no image' => array(
|
||||
'html' => '<p>bar</p>',
|
||||
'expected' => 0,
|
||||
),
|
||||
'basic image' => array(
|
||||
'html' => '<img />',
|
||||
'expected' => 1,
|
||||
),
|
||||
'nested images within forbidden tags' => array(
|
||||
'html' => '<html><body><img /><iframe baz="1"><div baz="baz"><article baz="1" biz="2">baz<img /><img /></article>rab</div> oof<img /></iframe><img /></body></html>',
|
||||
'expected' => 2,
|
||||
),
|
||||
// This test will be restored with the ticket n°2556
|
||||
// 'nested images within forbidden and removed tags' => array(
|
||||
// 'html' => '<html><body><img /><iframe baz="1"><div baz="baz"><object baz="1" biz="2">baz<img /><img /></object>rab</div> oof<img /></iframe><img /></body></html>',
|
||||
// 'expected' => 2,
|
||||
// ),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
/** @noinspection PhpUnused */
|
||||
/** @noinspection PhpIllegalPsrClassPathInspection */
|
||||
/**
|
||||
* Copyright (C) 2010-2021 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/>
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Mock class used to count number of calls for the ProcessImage static method
|
||||
*
|
||||
* @used-by \Combodo\iTop\Test\UnitTest\Core\Sanitizer\HTMLDOMSanitizerTest::testDoSanitizeCallInlineImageProcessImageTag()
|
||||
*/
|
||||
class InlineImageMock
|
||||
{
|
||||
private static $iCallCounter = 0;
|
||||
|
||||
public static function ProcessImageTag(DOMNode $oNode)
|
||||
{
|
||||
self::$iCallCounter++;
|
||||
}
|
||||
|
||||
public static function ResetCallCounter()
|
||||
{
|
||||
self::$iCallCounter = 0;
|
||||
}
|
||||
|
||||
public static function GetCallCounter()
|
||||
{
|
||||
return self::$iCallCounter;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
Sample data for the HTMLDOMSanitizerTest class
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Core\Sanitizer;
|
||||
|
||||
use SVGDOMSanitizer;
|
||||
|
||||
|
||||
require_once __DIR__.'/AbstractDOMSanitizerTest.php';
|
||||
|
||||
|
||||
class SVGDOMSanitizerTest extends AbstractDOMSanitizerTest
|
||||
{
|
||||
/**
|
||||
* @dataProvider DoSanitizeProvider
|
||||
*
|
||||
* @param string $sFileToTest filename
|
||||
*/
|
||||
public function testDoSanitize($sFileToTest)
|
||||
{
|
||||
$sInputHtml = $this->ReadTestFile($sFileToTest, self::INPUT_DIRECTORY);
|
||||
$sOutputHtml = $this->ReadTestFile($sFileToTest, self::OUTPUT_DIRECTORY);
|
||||
$sOutputHtml = $this->RemoveNewLines($sOutputHtml);
|
||||
|
||||
$oSanitizer = new SVGDOMSanitizer();
|
||||
$sRes = $oSanitizer->DoSanitize($sInputHtml);
|
||||
|
||||
// Removing newlines as the parser gives different results depending on the PHP version
|
||||
// Didn't manage to get it right :
|
||||
// - no php.ini difference
|
||||
// - playing with the parser preserveWhitespace/formatOutput parser options didn't help
|
||||
// So we're removing new lines on both sides :/
|
||||
$sOutputHtml = $this->RemoveNewLines($sOutputHtml);
|
||||
$sRes = $this->RemoveNewLines($sRes);
|
||||
|
||||
$this->debug($sRes);
|
||||
$this->assertEquals($sOutputHtml, $sRes);
|
||||
}
|
||||
|
||||
public function DoSanitizeProvider()
|
||||
{
|
||||
return array(
|
||||
array(
|
||||
'scripts.svg',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<h1>Test with lots of JS scripts to filter !</h1>
|
||||
|
||||
<p><img src="http://toto.invalid/" onerror="alert('hello world !');"></p>
|
||||
|
||||
<script>
|
||||
alert("hello world !");
|
||||
</script>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" baseProfile="full" onload="alert('hello world !');">
|
||||
<rect width="300" height="100" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)"/>
|
||||
<script type="text/javascript">
|
||||
alert("XSS");
|
||||
</script>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 418 B |
@@ -0,0 +1,56 @@
|
||||
<html><head><meta http-equiv="Content-Type" content="text/html; charset=us-ascii"><meta name="Generator" content="Microsoft Word 15 (filtered medium)"><style><!--
|
||||
/* Font Definitions */
|
||||
@font-face
|
||||
{font-family:"Cambria Math";
|
||||
panose-1:2 4 5 3 5 4 6 3 2 4;}
|
||||
@font-face
|
||||
{font-family:Calibri;
|
||||
panose-1:2 15 5 2 2 2 4 3 2 4;}
|
||||
/* Style Definitions */
|
||||
p.MsoNormal, li.MsoNormal, div.MsoNormal
|
||||
{margin:0cm;
|
||||
margin-bottom:.0001pt;
|
||||
font-size:11.0pt;
|
||||
font-family:"Calibri",sans-serif;
|
||||
mso-fareast-language:EN-US;}
|
||||
a:link, span.MsoHyperlink
|
||||
{mso-style-priority:99;
|
||||
color:#0563C1;
|
||||
text-decoration:underline;}
|
||||
a:visited, span.MsoHyperlinkFollowed
|
||||
{mso-style-priority:99;
|
||||
color:#954F72;
|
||||
text-decoration:underline;}
|
||||
p.msonormal0, li.msonormal0, div.msonormal0
|
||||
{mso-style-name:msonormal;
|
||||
mso-margin-top-alt:auto;
|
||||
margin-right:0cm;
|
||||
mso-margin-bottom-alt:auto;
|
||||
margin-left:0cm;
|
||||
font-size:12.0pt;
|
||||
font-family:"Times New Roman",serif;}
|
||||
span.EmailStyle18
|
||||
{mso-style-type:personal;
|
||||
font-family:"Calibri",sans-serif;
|
||||
color:windowtext;}
|
||||
span.EmailStyle19
|
||||
{mso-style-type:personal;
|
||||
font-family:"Calibri",sans-serif;
|
||||
color:#1F497D;}
|
||||
span.EmailStyle20
|
||||
{mso-style-type:personal;
|
||||
font-family:"Calibri",sans-serif;
|
||||
color:#1F497D;}
|
||||
span.EmailStyle21
|
||||
{mso-style-type:personal-compose;
|
||||
font-family:"Calibri",sans-serif;
|
||||
color:windowtext;}
|
||||
.MsoChpDefault
|
||||
{mso-style-type:export-only;
|
||||
font-size:10.0pt;}
|
||||
@page WordSection1
|
||||
{size:612.0pt 792.0pt;
|
||||
margin:72.0pt 72.0pt 72.0pt 72.0pt;}
|
||||
div.WordSection1
|
||||
{page:WordSection1;}
|
||||
--></style></head><body lang="EN-GB" link="#0563C1" vlink="#954F72"><div class="WordSection1"><p class="MsoNormal"><span lang="DE">Test mit nur Unterschrift</span></p><p class="MsoNormal"><span lang="DE">Kein bild</span></p><p class="MsoNormal"><span lang="DE"> </span></p><p class="MsoNormal"><span lang="DE"> </span></p><p class="MsoNormal"><b><span lang="EN-US" style="font-size:10.0pt;font-family:"Arial",sans-serif;color:black">Christel Dedman</span></b><span lang="EN-US"></span></p><p class="MsoNormal"><b><span lang="EN-US" style="font-size:10.0pt;font-family:"Arial",sans-serif;color:black"> </span></b><span lang="EN-US"></span></p><p class="MsoNormal"><b><span lang="EN-US" style="font-size:10.0pt;font-family:"Arial",sans-serif;color:black">Financial Reporting Manager | G4S International Logistics (Germany) GmbH</span></b></p><p class="MsoNormal"><b><span lang="EN-US" style="font-size:10.0pt;font-family:"Arial",sans-serif;color:black"> </span></b></p><p class="MsoNormal"><span lang="EN-US"> </span></p><p class="MsoNormal"><span lang="EN-US" style="font-size:10.0pt;font-family:"Arial",sans-serif;color:black">Rathenaustrasse 53, 63263 Neu – Isenburg, Office Tel: +49 (0) 6102 / 4393 623 | Fax: +49 (0) 6102 / 4393 619 | Mobile: +49 (0) 172 / 5687367</span><span lang="EN-US"></span></p><p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"><span lang="EN-US" style="font-size:10.0pt;font-family:"Arial",sans-serif;color:black">Email:</span><span lang="EN-US" style="font-size:10.0pt;font-family:"Arial",sans-serif"> </span><a href="mailto:christel.dedman@g4si.com"><span lang="EN-US" style="font-size:10.0pt;font-family:"Arial",sans-serif">christel.dedman@g4si.com</span></a><span lang="EN-US" style="font-size:10.0pt;font-family:"Arial",sans-serif"> <b>|</b> <span style="color:black">Web site</span>: </span><a href="http://www.g4si.com/" target="_blank"><span lang="EN-US" style="font-size:10.0pt;font-family:"Arial",sans-serif">www.g4si.com</span></a><span lang="EN-US" style="font-size:10.0pt;font-family:"Arial",sans-serif"> / </span><a href="http://www.g4s.com/"><span lang="EN-US" style="font-size:10.0pt;font-family:"Arial",sans-serif">www.g4s.com</span></a><span lang="EN-US" style="font-size:12.0pt;font-family:"Times New Roman",serif"></span></p><p class="MsoNormal" style="margin-bottom:12.0pt"><span lang="EN-US" style="font-size:9.0pt;font-family:"Arial",sans-serif;color:black">Disclaimer: G4S International Logistics (G4Si) is a division of the G4S plc group of companies. This communication contains information which may be confidential, personal and/or privileged. It is for the exclusive use of the intended recipient(s).<br>If you are not the intended recipient(s), please note that any distribution, forwarding, copying or use of this communication or the information in it is strictly prohibited. Any personal views expressed in this e-mail are those of the individual sender and G4Si does not endorse or accept responsibility for them. Prior to taking any action based upon this e-mail message, you should seek appropriate confirmation of its authenticity.</span><span lang="EN-US" style="font-size:12.0pt;font-family:"Times New Roman",serif;color:black"></span></p><p class="MsoNormal"> </p></div></body></html>
|
||||
@@ -0,0 +1,14 @@
|
||||
##START_TAG##
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam luctus semper diam et fermentum. Cras nisi mauris, rutrum id turpis at,
|
||||
sagittis tempus erat. Sed tempus vel purus id sagittis. Suspendisse ullamcorper eros vel semper malesuada. Vivamus malesuada tellus quis
|
||||
nisi consequat, quis tristique magna eleifend. Quisque eget turpis lacinia, vehicula turpis vel, aliquet diam. Aenean eu nunc ac velit
|
||||
condimentum posuere. Vivamus congue velit cursus eros mollis, vitae eleifend urna finibus.
|
||||
|
||||
In accumsan sed sem nec sollicitudin. Sed pretium, neque et rhoncus volutpat, urna massa semper ex, et faucibus mauris sapien eu libero.
|
||||
Sed vel accumsan nibh, tempus accumsan mi. Maecenas gravida imperdiet leo id euismod. Mauris pharetra mattis facilisis. Suspendisse
|
||||
dictum vel orci ac luctus. Proin ultricies erat sit amet leo sollicitudin, quis lacinia felis volutpat. Praesent molestie quam et magna
|
||||
tempor aliquet. Sed quam nisi, dictum ac gravida et, suscipit et augue. Fusce ac purus eget leo scelerisque bibendum. Proin in semper
|
||||
erat, eu congue diam. Vivamus purus eros, consectetur laoreet gravida in, ultricies eget nibh. Mauris hendrerit euismod ex at facilisis.
|
||||
Integer lacus eros, posuere finibus libero facilisis, eleifend gravida neque. Integer feugiat elit vel leo aliquet suscipit. Etiam
|
||||
auctor ligula sed eros vulputate tristique ac eget magna.
|
||||
##END_TAG##
|
||||
@@ -0,0 +1,3 @@
|
||||
<h1>Test with lots of JS scripts to filter !</h1>
|
||||
|
||||
<p><img src="http://toto.invalid/"></p>
|
||||
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" version="1.1" baseProfile="full"><rect width="300" height="100" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)"/></svg>
|
||||
|
After Width: | Height: | Size: 305 B |
@@ -0,0 +1,12 @@
|
||||
<div>
|
||||
<p><span>Test mit nur Unterschrift</span></p>
|
||||
<p><span>Kein bild</span></p>
|
||||
<p><span> </span></p>
|
||||
<p><span> </span></p>
|
||||
<p><b><span style='font-size:10.0pt;font-family:"Arial",sans-serif;color:black'>Christel Dedman</span></b><span></span></p>
|
||||
<p><b><span style='font-size:10.0pt;font-family:"Arial",sans-serif;color:black'> </span></b><span></span></p>
|
||||
<p><b><span style='font-size:10.0pt;font-family:"Arial",sans-serif;color:black'>Financial Reporting Manager | G4S International Logistics (Germany) GmbH</span></b></p>
|
||||
<p><b><span style='font-size:10.0pt;font-family:"Arial",sans-serif;color:black'> </span></b></p>
|
||||
<p><span> </span></p>
|
||||
<p><span style='font-size:10.0pt;font-family:"Arial",sans-serif;color:black'>Rathenaustrasse 53, 63263 Neu </span></p>
|
||||
</div>
|
||||
@@ -0,0 +1,310 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by Bruno DA SILVA, working for Combodo
|
||||
* Date: 21/11/2019
|
||||
* Time: 09:14
|
||||
*/
|
||||
|
||||
namespace coreExtensions;
|
||||
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use UserLocal;
|
||||
|
||||
/**
|
||||
* test class for UserLocal class
|
||||
*
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class UserLocalTest extends ItopDataTestCase
|
||||
{
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
require_once(APPROOT.'tests/php-unit-tests/tests/datamodels/2.x/authent-local/UserLocalTest/UserLocalPasswordPolicyMock.php');
|
||||
require_once(APPROOT.'env-production/authent-local/model.authent-local.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider ProviderValidatePassword
|
||||
*/
|
||||
public function testValidatePassword($sPassword, $aValidatorNames, $aConfigValueMap, $bExpectedCheckStatus, $expectedCheckIssues = null, $sUserLanguage = null)
|
||||
{
|
||||
$configMock = $this->createMock(\Config::class);
|
||||
|
||||
$configMock
|
||||
->method('GetModuleSetting')
|
||||
->willReturnMap($aConfigValueMap);
|
||||
|
||||
if (isset($sUserLanguage))
|
||||
{
|
||||
\Dict::SetUserLanguage($sUserLanguage);
|
||||
}
|
||||
|
||||
/** @var UserLocal $oUserLocal */
|
||||
$oUserLocal = \MetaModel::NewObject('UserLocal', array('login' => 'john'));
|
||||
/** @var \ormLinkSet $oProfileSet */
|
||||
$oProfileSet = $oUserLocal->Get('profile_list');
|
||||
|
||||
$oProfileSet->AddItem(
|
||||
\MetaModel::NewObject('URP_UserProfile', array('profileid' => 1))
|
||||
);
|
||||
|
||||
$aValidatorCollection = array();
|
||||
foreach ($aValidatorNames as $class)
|
||||
{
|
||||
$aValidatorCollection[] = new $class();
|
||||
}
|
||||
|
||||
$oUserLocal->ValidatePassword($sPassword, $configMock, $aValidatorCollection);
|
||||
|
||||
list($bCheckStatus, $aCheckIssues, $aSecurityIssues) = $oUserLocal->CheckToWrite();
|
||||
|
||||
$this->assertSame($bExpectedCheckStatus, $bCheckStatus);
|
||||
|
||||
if (isset($expectedCheckIssues))
|
||||
{
|
||||
$this->assertContains($expectedCheckIssues, $aCheckIssues);
|
||||
}
|
||||
}
|
||||
|
||||
public function ProviderValidatePassword()
|
||||
{
|
||||
return array(
|
||||
'validPattern' => array(
|
||||
'password' => 'foo',
|
||||
'aValidatorCollection' => array(
|
||||
'UserPasswordPolicyRegex',
|
||||
),
|
||||
'valueMap' => array(
|
||||
array('authent-local', 'password_validation.pattern', null, '.{1,10}')
|
||||
),
|
||||
'expectedCheckStatus' => true,
|
||||
),
|
||||
'notValidPattern' => array(
|
||||
'password' => 'foo',
|
||||
'aValidatorCollection' => array(
|
||||
'UserPasswordPolicyRegex',
|
||||
),
|
||||
'valueMap' => array(
|
||||
array('authent-local', 'password_validation.pattern', null, '.{6,10}')
|
||||
),
|
||||
'expectedCheckStatus' => false,
|
||||
),
|
||||
'noPattern' => array(
|
||||
'password' => 'foo',
|
||||
'aValidatorCollection' => array(
|
||||
'UserPasswordPolicyRegex',
|
||||
),
|
||||
'valueMap' => array(
|
||||
array('authent-local', 'password_validation.pattern', null, '')
|
||||
),
|
||||
'expectedCheckStatus' => true,
|
||||
),
|
||||
'validClass' => array(
|
||||
'password' => 'foo',
|
||||
'aValidatorCollection' => array(
|
||||
'UserLocalPasswordPolicyMockValid',
|
||||
),
|
||||
'valueMap' => array(),
|
||||
'expectedCheckStatus' => true,
|
||||
),
|
||||
'notValidClass' => array(
|
||||
'password' => 'foo',
|
||||
'aValidatorCollection' => array(
|
||||
'UserLocalPasswordPolicyMockNotValid',
|
||||
),
|
||||
'valueMap' => array(),
|
||||
'expectedCheckStatus' => false,
|
||||
),
|
||||
|
||||
'validation_composition_10' => array(
|
||||
'password' => 'foo',
|
||||
'aValidatorCollection' => array(
|
||||
'UserLocalPasswordPolicyMockValid',
|
||||
'UserLocalPasswordPolicyMockNotValid',
|
||||
),
|
||||
'valueMap' => array(),
|
||||
'expectedCheckStatus' => false,
|
||||
'expectedCheckIssues' => 'UserLocalPasswordPolicyMockNotValid',
|
||||
),
|
||||
|
||||
|
||||
'validation_composition_01' => array(
|
||||
'password' => 'foo',
|
||||
'aValidatorCollection' => array(
|
||||
'UserLocalPasswordPolicyMockNotValid',
|
||||
'UserLocalPasswordPolicyMockValid',
|
||||
),
|
||||
'valueMap' => array(),
|
||||
'expectedCheckStatus' => false,
|
||||
'expectedCheckIssues' => 'UserLocalPasswordPolicyMockNotValid',
|
||||
),
|
||||
|
||||
'validation_composition_11' => array(
|
||||
'password' => 'foo',
|
||||
'aValidatorCollection' => array(
|
||||
'UserLocalPasswordPolicyMockValid',
|
||||
'UserLocalPasswordPolicyMockValidBis',
|
||||
),
|
||||
'valueMap' => array(),
|
||||
'expectedCheckStatus' => true,
|
||||
),
|
||||
'validation_composition_00' => array(
|
||||
'password' => 'foo',
|
||||
'aValidatorCollection' => array(
|
||||
'UserLocalPasswordPolicyMockNotValid',
|
||||
'UserLocalPasswordPolicyMockNotValidBis',
|
||||
),
|
||||
'valueMap' => array(),
|
||||
'expectedCheckStatus' => false,
|
||||
'expectedCheckIssues' => 'UserLocalPasswordPolicyMockNotValid',
|
||||
),
|
||||
|
||||
'notValidPattern custom message FR' => array(
|
||||
'password' => 'foo',
|
||||
'aValidatorCollection' => array(
|
||||
'UserPasswordPolicyRegex',
|
||||
),
|
||||
'valueMap' => array(
|
||||
array('authent-local', 'password_validation.pattern', null, '.{6,10}'),
|
||||
array('authent-local', 'password_validation.message', null, array('FR FR' => 'fr message', 'EN US' => 'en message')),
|
||||
|
||||
),
|
||||
'expectedCheckStatus' => false,
|
||||
'expectedCheckIssues' => 'fr message',
|
||||
'userLanguage' => 'FR FR',
|
||||
),
|
||||
'notValidPattern custom message EN' => array(
|
||||
'password' => 'foo',
|
||||
'aValidatorCollection' => array(
|
||||
'UserPasswordPolicyRegex',
|
||||
),
|
||||
'valueMap' => array(
|
||||
array('authent-local', 'password_validation.pattern', null, '.{6,10}'),
|
||||
array('authent-local', 'password_validation.message', null, array('FR FR' => 'fr message', 'EN US' => 'en message')),
|
||||
|
||||
),
|
||||
'expectedCheckStatus' => false,
|
||||
'expectedCheckIssues' => 'en message',
|
||||
'userLanguage' => 'EN US',
|
||||
),
|
||||
'notValidPattern custom message Fallback' => array(
|
||||
'password' => 'foo',
|
||||
'aValidatorCollection' => array(
|
||||
'UserPasswordPolicyRegex',
|
||||
),
|
||||
'valueMap' => array(
|
||||
array('authent-local', 'password_validation.pattern', null, '.{6,10}'),
|
||||
array('authent-local', 'password_validation.message', null, array('EN US' => 'en message')),
|
||||
|
||||
),
|
||||
'expectedCheckStatus' => false,
|
||||
'expectedCheckIssues' => 'en message',
|
||||
'userLanguage' => 'FR FR',
|
||||
),
|
||||
'notValidPattern custom message empty array' => array(
|
||||
'password' => 'foo',
|
||||
'aValidatorCollection' => array(
|
||||
'UserPasswordPolicyRegex',
|
||||
),
|
||||
'valueMap' => array(
|
||||
array('authent-local', 'password_validation.pattern', null, '.{6,10}'),
|
||||
array('authent-local', 'password_validation.message', null, array()),
|
||||
|
||||
),
|
||||
'expectedCheckStatus' => false,
|
||||
'expectedCheckIssues' => 'Password must be at least 8 characters and include uppercase, lowercase, numeric and special characters.',
|
||||
'userLanguage' => 'EN US',
|
||||
),
|
||||
'notValidPattern custom message string not array' => array(
|
||||
'password' => 'foo',
|
||||
'aValidatorCollection' => array(
|
||||
'UserPasswordPolicyRegex',
|
||||
),
|
||||
'valueMap' => array(
|
||||
array('authent-local', 'password_validation.pattern', null, '.{6,10}'),
|
||||
array('authent-local', 'password_validation.message', null, 'not an array'),
|
||||
|
||||
),
|
||||
'expectedCheckStatus' => false,
|
||||
'expectedCheckIssues' => 'not an array',
|
||||
'userLanguage' => 'EN US',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @dataProvider ProviderPasswordRenewal
|
||||
*
|
||||
*/
|
||||
public function testPasswordRenewal($sBefore, $sExpectedAfter)
|
||||
{
|
||||
$oBefore = is_null($sBefore) ? null : date(\AttributeDate::GetInternalFormat(), strtotime($sBefore));
|
||||
$oExpectedAfter = is_null($sExpectedAfter) ? null : date(\AttributeDate::GetInternalFormat(), strtotime($sExpectedAfter));
|
||||
|
||||
$aUserLocalValues = array('login' => 'john');
|
||||
if (!is_null($oBefore))
|
||||
{
|
||||
$aUserLocalValues['password_renewed_date'] = $oBefore;
|
||||
}
|
||||
|
||||
/** @var UserLocal $oUserLocal */
|
||||
$oUserLocal = \MetaModel::NewObject('UserLocal', $aUserLocalValues);
|
||||
/** @var \ormLinkSet $oProfileSet */
|
||||
$oProfileSet = $oUserLocal->Get('profile_list');
|
||||
|
||||
$oProfileSet->AddItem(
|
||||
\MetaModel::NewObject('URP_UserProfile', array('profileid' => 1))
|
||||
);
|
||||
|
||||
|
||||
$this->assertEquals($oBefore, $oUserLocal->Get('password_renewed_date'));
|
||||
|
||||
//INSERT
|
||||
$oUserLocal->Set('password', 'fooBar1???');
|
||||
$oUserLocal->DBWrite();
|
||||
$this->assertEquals($oBefore, $oUserLocal->Get('password_renewed_date'), 'INSERT changes the "password_renewed_date"');
|
||||
|
||||
//UPDATE password_renewed_date
|
||||
$oUserLocal->Set('password_renewed_date', $oBefore);
|
||||
$oUserLocal->DBWrite();
|
||||
$this->assertEquals($oBefore, $oUserLocal->Get('password_renewed_date'), 'UPDATE can target and change the "password_renewed_date"');
|
||||
|
||||
//UPDATE password
|
||||
$oUserLocal->Set('password', 'fooBar1???1');
|
||||
$oUserLocal->DBWrite();
|
||||
$this->assertEquals($oExpectedAfter, $oUserLocal->Get('password_renewed_date'), 'UPDATE "password" fields trigger automatic change of the "password_renewed_date" field');
|
||||
|
||||
|
||||
//UPDATE both password & password_renewed_date
|
||||
$oUserLocal->Set('password', 'fooBar1???2');
|
||||
$oUserLocal->Set('password_renewed_date', $oBefore);
|
||||
$oUserLocal->DBWrite();
|
||||
$this->assertEquals($oBefore, $oUserLocal->Get('password_renewed_date'), 'UPDATE can target and change both "password" and "password_renewed_date"');
|
||||
}
|
||||
|
||||
public function ProviderPasswordRenewal()
|
||||
{
|
||||
return array(
|
||||
'nominal case' => array(
|
||||
'oExpectedBefore' => null,
|
||||
'oExpectedAfter' => 'now',
|
||||
),
|
||||
'date initiated' => array(
|
||||
'oBefore' => '-1 day',
|
||||
'oExpectedAfter' => 'now',
|
||||
),
|
||||
'date initiated in the future' => array(
|
||||
'oBefore' => '+1 day',
|
||||
'oExpectedAfter' => 'now',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
class UserLocalPasswordPolicyMockValid implements \UserLocalPasswordValidator
|
||||
{
|
||||
const CHECK_STATUS = true;
|
||||
const MESSAGE = null;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $proposedValue
|
||||
* @param UserLocal $oUserLocal
|
||||
* @param $config
|
||||
*
|
||||
* @return UserLocalPasswordValidity
|
||||
*/
|
||||
public function ValidatePassword($proposedValue, UserLocal $oUserLocal, $config)
|
||||
{
|
||||
return new UserLocalPasswordValidity(static::CHECK_STATUS, static::MESSAGE);
|
||||
}
|
||||
}
|
||||
|
||||
class UserLocalPasswordPolicyMockNotValid extends UserLocalPasswordPolicyMockValid
|
||||
{
|
||||
const CHECK_STATUS = false;
|
||||
const MESSAGE = 'UserLocalPasswordPolicyMockNotValid';
|
||||
}
|
||||
|
||||
class UserLocalPasswordPolicyMockValidBis extends UserLocalPasswordPolicyMockValid
|
||||
{
|
||||
}
|
||||
|
||||
class UserLocalPasswordPolicyMockNotValidBis extends UserLocalPasswordPolicyMockNotValid
|
||||
{
|
||||
const MESSAGE = 'UserLocalPasswordPolicyMockNotValidBis';
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by Bruno DA SILVA, working for Combodo
|
||||
* Date: 31/12/2019
|
||||
* Time: 12:31
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Config\Test\Validator;
|
||||
|
||||
use Combodo\iTop\Config\Validator\iTopConfigAstValidator;
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\PrettyPrinter\Standard;
|
||||
|
||||
class iTopConfigAstValidatorTest extends ItopTestCase
|
||||
{
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
require_once __DIR__.'/../../../env-production/itop-config/src/Validator/ConfigNodesVisitor.php';
|
||||
require_once __DIR__.'/../../../env-production/itop-config/src/Validator/iTopConfigAstValidator.php';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @dataProvider InvalidDataProvider
|
||||
* @param $sConf
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function testInvalid($sConf)
|
||||
{
|
||||
$oiTopConfigValidator = new iTopConfigAstValidator();
|
||||
$this->expectException(\Exception::class);
|
||||
try{
|
||||
$oiTopConfigValidator->Validate($sConf);
|
||||
}catch (\Exception $e)
|
||||
{
|
||||
$this->assertStringStartsWith('Invalid configuration:', $e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function InvalidDataProvider()
|
||||
{
|
||||
return array(
|
||||
'invalid PHP' => array(
|
||||
'sConf' => '<?php fiction Method(){}'
|
||||
),
|
||||
'function call' => array(
|
||||
'sConf' => '<?php FunctionCall();'
|
||||
),
|
||||
'function declaration' => array(
|
||||
'sConf' => '<?php function foo() {};'
|
||||
),
|
||||
'class instantiation' => array(
|
||||
'sConf' => '<?php new Class {};'
|
||||
),
|
||||
'Class declaration' => array(
|
||||
'sConf' => '<?php class foo {};'
|
||||
),
|
||||
'echo' => array(
|
||||
'sConf' => '<?php echo "toto"; ?>'
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @dataProvider ValidDataProvider
|
||||
* @doesNotPerformAssertions
|
||||
*
|
||||
* @param $sConf
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function testValid($sConf)
|
||||
{
|
||||
$oiTopConfigValidator = new iTopConfigAstValidator();
|
||||
|
||||
$oiTopConfigValidator->Validate($sConf);
|
||||
}
|
||||
|
||||
public function ValidDataProvider()
|
||||
{
|
||||
return array(
|
||||
'simple code' => array(
|
||||
'sConf' => '<?php $var = array("toto"); ?>'
|
||||
),
|
||||
'class constant' => array(
|
||||
'sConf' => '<?php $var = array(foo::bar);'
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by Bruno DA SILVA, working for Combodo
|
||||
* Date: 31/12/2019
|
||||
* Time: 12:31
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Config\Test\Validator;
|
||||
|
||||
use Combodo\iTop\Config\Validator\iTopConfigAstValidator;
|
||||
use Combodo\iTop\Config\Validator\iTopConfigSyntaxValidator;
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\PrettyPrinter\Standard;
|
||||
|
||||
class iTopConfigSyntaxValidatorTest extends ItopTestCase
|
||||
{
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
require_once __DIR__.'/../../../env-production/itop-config/src/Validator/ConfigNodesVisitor.php';
|
||||
require_once __DIR__.'/../../../env-production/itop-config/src/Validator/iTopConfigSyntaxValidator.php';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
* @doesNotPerformAssertions
|
||||
*/
|
||||
public function testValidCode()
|
||||
{
|
||||
$oiTopConfigValidator = new iTopConfigSyntaxValidator();
|
||||
$oiTopConfigValidator->Validate("<?php \n echo 'foo'; ");
|
||||
}
|
||||
|
||||
public function testThrowOnInvalidCode()
|
||||
{
|
||||
$oiTopConfigValidator = new iTopConfigSyntaxValidator();
|
||||
|
||||
$this->expectException(\Exception::class);
|
||||
try{
|
||||
$oiTopConfigValidator->Validate("<?php \n zef;zefzef \n zdadz = azdazd \n zerfgzaezerfgzef>");
|
||||
}catch (\Exception $e)
|
||||
{
|
||||
$this->assertStringStartsWith('Error in configuration: syntax error, unexpected \'zdadz\' (T_STRING)', $e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,922 @@
|
||||
<?php
|
||||
// Copyright (c) 2010-2017 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/>
|
||||
//
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Eric
|
||||
* Date: 18/12/2017
|
||||
* Time: 13:34
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\iTopTickets;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use Exception;
|
||||
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class ItopTicketTest extends ItopDataTestCase
|
||||
{
|
||||
const CREATE_TEST_ORG = true;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* Given:
|
||||
*
|
||||
* Server1+---->Hypervisor1+---->Person1
|
||||
*
|
||||
* Ticket+---->Server1 (manual)
|
||||
*
|
||||
* Result:
|
||||
*
|
||||
* Ticket+====>Server1,Hypervisor1
|
||||
* |
|
||||
* +====>Person1
|
||||
* </pre>
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testUpdateImpactedItems_Basic()
|
||||
{
|
||||
$oTicket = $this->CreateTicket(1);
|
||||
$oServer1 = $this->CreateServer(1);
|
||||
$oHypervisor1 = $this->CreateHypervisor(1, $oServer1);
|
||||
$oPerson1 = $this->CreatePerson(1);
|
||||
$this->AddContactToCI($oPerson1, $oHypervisor1);
|
||||
$oHypervisor1->DBUpdate();
|
||||
|
||||
$aAwaitedCIs = $this->AddCIToTicket($oServer1, $oTicket, 'manual');
|
||||
$oTicket->DBUpdate(); // trigger the impact update
|
||||
$this->ReloadObject($oTicket); // reload the links
|
||||
|
||||
// Add the computed CIs
|
||||
$aAwaitedCIs = $aAwaitedCIs + array($oHypervisor1->GetKey() => 'computed');
|
||||
|
||||
$this->CheckFunctionalCIList($oTicket, $aAwaitedCIs);
|
||||
|
||||
// Computed Contacts
|
||||
$aAwaitedContacts = array($oPerson1->GetKey() => array('role_code' => 'computed'));
|
||||
$this->CheckContactList($oTicket, $aAwaitedContacts);
|
||||
$this->assertEquals(2, $oTicket->Get('functionalcis_list')->Count());
|
||||
$this->assertEquals(1, $oTicket->Get('contacts_list')->Count());
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* Given:
|
||||
*
|
||||
* Server1+---->Hypervisor1+---->Person1
|
||||
*
|
||||
* Ticket+---->Server1 (manual)
|
||||
*
|
||||
* Result:
|
||||
*
|
||||
* Ticket+====>Server1,Hypervisor1
|
||||
* |
|
||||
* +====>Person1
|
||||
* </pre>
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testUpdateImpactedItems_Basic2()
|
||||
{
|
||||
$oTicket = $this->CreateTicket(1);
|
||||
$oServer1 = $this->CreateServer(1);
|
||||
$oHypervisor1 = $this->CreateHypervisor(1, $oServer1);
|
||||
$oPerson1 = $this->CreatePerson(1);
|
||||
$this->AddContactToCI($oPerson1, $oHypervisor1);
|
||||
$oHypervisor1->DBUpdate();
|
||||
|
||||
$this->AddCIToTicket($oServer1, $oTicket, 'manual');
|
||||
$oTicket->DBUpdate(); // trigger the impact update
|
||||
|
||||
$this->ReloadObject($oTicket); // reload the links
|
||||
|
||||
$this->CheckFunctionalCIList($oTicket);
|
||||
$this->CheckContactList($oTicket);
|
||||
$this->assertEquals(2, $oTicket->Get('functionalcis_list')->Count());
|
||||
$this->assertEquals(1, $oTicket->Get('contacts_list')->Count());
|
||||
|
||||
// Try removing computed entries
|
||||
$this->RemoveCIFromTicket($oHypervisor1, $oTicket);
|
||||
$this->RemoveContactFromTicket($oPerson1, $oTicket);
|
||||
$oTicket->DBUpdate(); // trigger the impact update
|
||||
$this->ReloadObject($oTicket); // reload the links
|
||||
|
||||
$this->CheckFunctionalCIList($oTicket);
|
||||
$this->CheckContactList($oTicket);
|
||||
$this->assertEquals(2, $oTicket->Get('functionalcis_list')->Count());
|
||||
$this->assertEquals(1, $oTicket->Get('contacts_list')->Count());
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* Given:
|
||||
*
|
||||
* Server1+---->Hypervisor1+---->Person1
|
||||
*
|
||||
* Server2 Person2
|
||||
*
|
||||
* Ticket+---->Server1 (manual), Server2 (computed)
|
||||
*
|
||||
* Result:
|
||||
*
|
||||
* Ticket+====>Server1,Hypervisor1
|
||||
* |
|
||||
* +====>Person1
|
||||
* </pre>
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testUpdateImpactedItems_RemoveUnecessaryEntries()
|
||||
{
|
||||
$oTicket = $this->CreateTicket(1);
|
||||
$oServer1 = $this->CreateServer(1);
|
||||
$oHypervisor1 = $this->CreateHypervisor(1, $oServer1);
|
||||
$oPerson1 = $this->CreatePerson(1);
|
||||
$this->AddContactToCI($oPerson1, $oHypervisor1);
|
||||
$oHypervisor1->DBUpdate();
|
||||
|
||||
$oServer2 = $this->CreateServer(2);
|
||||
$oPerson2 = $this->CreatePerson(2);
|
||||
|
||||
$this->AddCIToTicket($oServer1, $oTicket, 'manual');
|
||||
$this->AddCIToTicket($oServer2, $oTicket, 'computed');
|
||||
$this->AddContactToTicket($oPerson2, $oTicket, 'computed');
|
||||
$oTicket->DBUpdate(); // trigger the impact update
|
||||
$this->ReloadObject($oTicket); // reload the links
|
||||
|
||||
$this->CheckFunctionalCIList($oTicket);
|
||||
$this->CheckContactList($oTicket);
|
||||
$this->assertEquals(2, $oTicket->Get('functionalcis_list')->Count());
|
||||
$this->assertEquals(1, $oTicket->Get('contacts_list')->Count());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a first impact chain then remove the root cause, all the chain should be removed.
|
||||
*
|
||||
* <pre>
|
||||
* Given:
|
||||
*
|
||||
* Server1+---->Hypervisor1+---->Person1
|
||||
*
|
||||
* Ticket+---->Server1 (manual)
|
||||
*
|
||||
* Result:
|
||||
*
|
||||
* Ticket+====>Server1,Hypervisor1
|
||||
* |
|
||||
* +====>Person1
|
||||
*
|
||||
* Then remove Server1
|
||||
*
|
||||
* Result:
|
||||
*
|
||||
* Ticket+====>
|
||||
* |
|
||||
* +====>
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testUpdateImpactedItems_RemoveUnecessaryEntries2()
|
||||
{
|
||||
$oTicket = $this->CreateTicket(1);
|
||||
$oServer1 = $this->CreateServer(1);
|
||||
$oHypervisor1 = $this->CreateHypervisor(1, $oServer1);
|
||||
$oPerson1 = $this->CreatePerson(1);
|
||||
$this->AddContactToCI($oPerson1, $oHypervisor1);
|
||||
$oHypervisor1->DBUpdate();
|
||||
|
||||
$this->AddCIToTicket($oServer1, $oTicket, 'manual');
|
||||
$oTicket->DBUpdate(); // trigger the impact update
|
||||
$this->ReloadObject($oTicket); // reload the links
|
||||
|
||||
$this->CheckFunctionalCIList($oTicket);
|
||||
$this->CheckContactList($oTicket);
|
||||
$this->assertEquals(2, $oTicket->Get('functionalcis_list')->Count());
|
||||
$this->assertEquals(1, $oTicket->Get('contacts_list')->Count());
|
||||
|
||||
$this->RemoveCIFromTicket($oServer1, $oTicket);
|
||||
$oTicket->DBUpdate(); // trigger the impact update
|
||||
$this->ReloadObject($oTicket); // reload the links
|
||||
|
||||
$this->CheckFunctionalCIList($oTicket);
|
||||
$this->CheckContactList($oTicket);
|
||||
$this->assertEquals(0, $oTicket->Get('functionalcis_list')->Count());
|
||||
$this->assertEquals(0, $oTicket->Get('contacts_list')->Count());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
*
|
||||
* Server2+---->Hypervisor2+---->Person2
|
||||
*
|
||||
* Ticket+---->(empty)
|
||||
*
|
||||
* Result:
|
||||
*
|
||||
* Ticket+====>(empty)
|
||||
* </pre>
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testUpdateImpactedItems_NoImpact()
|
||||
{
|
||||
$oTicket = $this->CreateTicket(1);
|
||||
$oServer2 = $this->CreateServer(2);
|
||||
$oPerson2 = $this->CreatePerson(2);
|
||||
$oHypervisor2 = $this->CreateHypervisor(2, $oServer2);
|
||||
$this->AddContactToCI($oPerson2, $oHypervisor2);
|
||||
$oHypervisor2->DBUpdate();
|
||||
|
||||
$oTicket->DBUpdate(); // trigger the impact update
|
||||
$this->ReloadObject($oTicket); // reload the links
|
||||
|
||||
$this->CheckFunctionalCIList($oTicket);
|
||||
$this->CheckContactList($oTicket);
|
||||
$this->assertEquals(0, $oTicket->Get('functionalcis_list')->Count());
|
||||
$this->assertEquals(0, $oTicket->Get('contacts_list')->Count());
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* Server1
|
||||
*
|
||||
* Server2+---->Hypervisor2+---->Person2
|
||||
*
|
||||
* Ticket+---->Server1 (manual)
|
||||
*
|
||||
* Result:
|
||||
*
|
||||
* Ticket+====>Server1
|
||||
* </pre>
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testUpdateImpactedItems_NoImpact2()
|
||||
{
|
||||
$oTicket = $this->CreateTicket(1);
|
||||
$oServer1 = $this->CreateServer(1);
|
||||
$oServer2 = $this->CreateServer(2);
|
||||
$oPerson2 = $this->CreatePerson(2);
|
||||
$oHypervisor2 = $this->CreateHypervisor(2, $oServer2);
|
||||
$this->AddContactToCI($oPerson2, $oHypervisor2);
|
||||
$oHypervisor2->DBUpdate();
|
||||
|
||||
$this->AddCIToTicket($oServer1, $oTicket, 'manual');
|
||||
$oTicket->DBUpdate(); // trigger the impact update
|
||||
$this->ReloadObject($oTicket); // reload the links
|
||||
|
||||
$this->CheckFunctionalCIList($oTicket);
|
||||
$this->CheckContactList($oTicket);
|
||||
$this->assertEquals(1, $oTicket->Get('functionalcis_list')->Count());
|
||||
$this->assertEquals(0, $oTicket->Get('contacts_list')->Count());
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* +-->Person1
|
||||
* |
|
||||
* +
|
||||
* Server1+---->Hypervisor1+--+
|
||||
* |
|
||||
* v
|
||||
* Farm (1)
|
||||
* ^
|
||||
* |
|
||||
* Server2+---->Hypervisor2+--+
|
||||
* +
|
||||
* |
|
||||
* +-->Person2
|
||||
*
|
||||
* Ticket+---->Server1 (manual)
|
||||
*
|
||||
* Result:
|
||||
*
|
||||
* Ticket+====>Server1,Hypervisor1
|
||||
* |
|
||||
* +====>Person1
|
||||
* </pre>
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testUpdateImpactedItems_Redundancy()
|
||||
{
|
||||
$oFarm = $this->CreateFarm(1);
|
||||
|
||||
$oServer1 = $this->CreateServer(1);
|
||||
$oHypervisor1 = $this->CreateHypervisor(1, $oServer1, $oFarm);
|
||||
$oContact1 = $this->CreatePerson(1);
|
||||
$this->AddContactToCI($oContact1, $oHypervisor1);
|
||||
$oHypervisor1->DBUpdate();
|
||||
|
||||
$oServer2 = $this->CreateServer(2);
|
||||
$oHypervisor2 = $this->CreateHypervisor(2, $oServer2, $oFarm);
|
||||
$oContact2 = $this->CreatePerson(2);
|
||||
$this->AddContactToCI($oContact2, $oHypervisor2);
|
||||
$oHypervisor2->DBUpdate();
|
||||
|
||||
$oTicket = $this->CreateTicket(1);
|
||||
$this->AddCIToTicket($oServer1, $oTicket, 'manual');
|
||||
$oTicket->DBUpdate(); // trigger the impact update
|
||||
$this->ReloadObject($oTicket); // reload the links
|
||||
|
||||
$this->CheckFunctionalCIList($oTicket);
|
||||
$this->CheckContactList($oTicket);
|
||||
$this->assertEquals(2, $oTicket->Get('functionalcis_list')->Count());
|
||||
$this->assertEquals(1, $oTicket->Get('contacts_list')->Count());
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* +-->Person1
|
||||
* |
|
||||
* +
|
||||
* Server1+---->Hypervisor1+--+
|
||||
* |
|
||||
* v
|
||||
* Farm (1)
|
||||
* ^
|
||||
* |
|
||||
* Server2+---->Hypervisor2+--+
|
||||
* +
|
||||
* |
|
||||
* +-->Person2
|
||||
*
|
||||
* Ticket+---->Server1 (manual), Hypervisor2 (manual)
|
||||
*
|
||||
* Result:
|
||||
*
|
||||
* Ticket+====>Server1,Hypervisor1,Farm,Hypervisor2
|
||||
* |
|
||||
* +====>Person1,Person2
|
||||
* </pre>
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testUpdateImpactedItems_Redundancy2()
|
||||
{
|
||||
$oFarm = $this->CreateFarm(1);
|
||||
|
||||
$oServer1 = $this->CreateServer(1);
|
||||
$oHypervisor1 = $this->CreateHypervisor(1, $oServer1, $oFarm);
|
||||
$oContact1 = $this->CreatePerson(1);
|
||||
$this->AddContactToCI($oContact1, $oHypervisor1);
|
||||
$oHypervisor1->DBUpdate();
|
||||
|
||||
$oServer2 = $this->CreateServer(2);
|
||||
$oHypervisor2 = $this->CreateHypervisor(2, $oServer2, $oFarm);
|
||||
$oContact2 = $this->CreatePerson(2);
|
||||
$this->AddContactToCI($oContact2, $oHypervisor2);
|
||||
$oHypervisor2->DBUpdate();
|
||||
|
||||
$oTicket = $this->CreateTicket(1);
|
||||
$this->AddCIToTicket($oServer1, $oTicket, 'manual');
|
||||
$this->AddCIToTicket($oHypervisor2, $oTicket, 'manual');
|
||||
$oTicket->DBUpdate(); // trigger the impact update
|
||||
$this->ReloadObject($oTicket); // reload the links
|
||||
|
||||
$this->CheckFunctionalCIList($oTicket);
|
||||
$this->CheckContactList($oTicket);
|
||||
$this->assertEquals(4, $oTicket->Get('functionalcis_list')->Count());
|
||||
$this->assertEquals(2, $oTicket->Get('contacts_list')->Count());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* +-->Person1
|
||||
* |
|
||||
* +
|
||||
* Server1+---->Hypervisor1+--+ +-->VM1
|
||||
* | |
|
||||
* v +
|
||||
* Farm (1)
|
||||
* ^ +
|
||||
* | |
|
||||
* Server2+---->Hypervisor2+--+ +-->VM2
|
||||
* +
|
||||
* |
|
||||
* +-->Person2
|
||||
*
|
||||
* Ticket+---->Server1 (manual), Hypervisor2 (manual)
|
||||
*
|
||||
* Result:
|
||||
*
|
||||
* Ticket+====>Server1,Hypervisor1,Farm,Hypervisor2,VM1,VM2
|
||||
* |
|
||||
* +====>Person1,Person2
|
||||
* </pre>
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testUpdateImpactedItems_Redundancy3()
|
||||
{
|
||||
$oFarm = $this->CreateFarm(1);
|
||||
|
||||
$oServer1 = $this->CreateServer(1);
|
||||
$oHypervisor1 = $this->CreateHypervisor(1, $oServer1, $oFarm);
|
||||
$oContact1 = $this->CreatePerson(1);
|
||||
$this->AddContactToCI($oContact1, $oHypervisor1);
|
||||
$oHypervisor1->DBUpdate();
|
||||
|
||||
$oServer2 = $this->CreateServer(2);
|
||||
$oHypervisor2 = $this->CreateHypervisor(2, $oServer2, $oFarm);
|
||||
$oContact2 = $this->CreatePerson(2);
|
||||
$this->AddContactToCI($oContact2, $oHypervisor2);
|
||||
$oHypervisor2->DBUpdate();
|
||||
|
||||
$this->CreateVirtualMachine(1, $oFarm);
|
||||
$this->CreateVirtualMachine(2, $oFarm);
|
||||
|
||||
$oTicket = $this->CreateTicket(1);
|
||||
$this->AddCIToTicket($oServer1, $oTicket, 'manual');
|
||||
$this->AddCIToTicket($oHypervisor2, $oTicket, 'manual');
|
||||
$oTicket->DBUpdate(); // trigger the impact update
|
||||
$this->ReloadObject($oTicket); // reload the links
|
||||
|
||||
$this->CheckFunctionalCIList($oTicket);
|
||||
$this->CheckContactList($oTicket);
|
||||
$this->assertEquals(6, $oTicket->Get('functionalcis_list')->Count());
|
||||
$this->assertEquals(2, $oTicket->Get('contacts_list')->Count());
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* +-->Person1
|
||||
* |
|
||||
* +
|
||||
* Server1+---->Hypervisor1+--+ +-->VM1
|
||||
* | |
|
||||
* v +
|
||||
* Farm (1)
|
||||
* ^ +
|
||||
* | |
|
||||
* Server2+---->Hypervisor2+--+ +-->VM2
|
||||
* +
|
||||
* |
|
||||
* +-->Person2
|
||||
*
|
||||
* Ticket+---->Server1 (manual), Server2 (manual), Hypervisor2 (not_impacted)
|
||||
*
|
||||
* Result:
|
||||
*
|
||||
* Ticket+====>Server1,Hypervisor1,Server2,Hypervisor2
|
||||
* |
|
||||
* +====>Person1
|
||||
* </pre>
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testUpdateImpactedItems_Exclusion()
|
||||
{
|
||||
$oFarm = $this->CreateFarm(1);
|
||||
|
||||
$oServer1 = $this->CreateServer(1);
|
||||
$oHypervisor1 = $this->CreateHypervisor(1, $oServer1, $oFarm);
|
||||
$oContact1 = $this->CreatePerson(1);
|
||||
$this->AddContactToCI($oContact1, $oHypervisor1);
|
||||
$oHypervisor1->DBUpdate();
|
||||
|
||||
$oServer2 = $this->CreateServer(2);
|
||||
$oHypervisor2 = $this->CreateHypervisor(2, $oServer2, $oFarm);
|
||||
$oContact2 = $this->CreatePerson(2);
|
||||
$this->AddContactToCI($oContact2, $oHypervisor2);
|
||||
$oHypervisor2->DBUpdate();
|
||||
|
||||
$this->CreateVirtualMachine(1, $oFarm);
|
||||
$this->CreateVirtualMachine(2, $oFarm);
|
||||
|
||||
$oTicket = $this->CreateTicket(1);
|
||||
$this->AddCIToTicket($oServer1, $oTicket, 'manual');
|
||||
$this->AddCIToTicket($oServer2, $oTicket, 'manual');
|
||||
$this->AddCIToTicket($oHypervisor2, $oTicket, 'not_impacted');
|
||||
$oTicket->DBUpdate(); // trigger the impact update
|
||||
$this->ReloadObject($oTicket); // reload the links
|
||||
|
||||
$this->CheckFunctionalCIList($oTicket);
|
||||
$this->CheckContactList($oTicket);
|
||||
$this->assertEquals(4, $oTicket->Get('functionalcis_list')->Count());
|
||||
$this->assertEquals(1, $oTicket->Get('contacts_list')->Count());
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* +-->Person1
|
||||
* |
|
||||
* +
|
||||
* Server1+---->Hypervisor1+--+ +-->VM1
|
||||
* | |
|
||||
* v +
|
||||
* Farm (1)
|
||||
* ^ +
|
||||
* | |
|
||||
* Server2+---->Hypervisor2+--+ +-->VM2
|
||||
* +
|
||||
* |
|
||||
* +-->Person2
|
||||
*
|
||||
* Ticket+---->Server1 (manual), Server2 (manual)
|
||||
* |
|
||||
* +---->Person2 (do_not_notify)
|
||||
*
|
||||
* Result:
|
||||
*
|
||||
* Ticket+====>Server1,Hypervisor1,Server2,Hypervisor2,Farm,VM1,VM2
|
||||
* |
|
||||
* +====>Person1,Person2 (do_not_notify)
|
||||
* </pre>
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testUpdateImpactedItems_Exclusion2()
|
||||
{
|
||||
$oFarm = $this->CreateFarm(1);
|
||||
|
||||
$oServer1 = $this->CreateServer(1);
|
||||
$oHypervisor1 = $this->CreateHypervisor(1, $oServer1, $oFarm);
|
||||
$oContact1 = $this->CreatePerson(1);
|
||||
$this->AddContactToCI($oContact1, $oHypervisor1);
|
||||
$oHypervisor1->DBUpdate();
|
||||
|
||||
$oServer2 = $this->CreateServer(2);
|
||||
$oHypervisor2 = $this->CreateHypervisor(2, $oServer2, $oFarm);
|
||||
$oContact2 = $this->CreatePerson(2);
|
||||
$this->AddContactToCI($oContact2, $oHypervisor2);
|
||||
$oHypervisor2->DBUpdate();
|
||||
|
||||
$this->CreateVirtualMachine(1, $oFarm);
|
||||
$this->CreateVirtualMachine(2, $oFarm);
|
||||
|
||||
$oTicket = $this->CreateTicket(1);
|
||||
$this->AddCIToTicket($oServer1, $oTicket, 'manual');
|
||||
$this->AddCIToTicket($oServer2, $oTicket, 'manual');
|
||||
$this->AddContactToTicket($oContact2, $oTicket, 'do_not_notify');
|
||||
$oTicket->DBUpdate(); // trigger the impact update
|
||||
$this->ReloadObject($oTicket); // reload the links
|
||||
|
||||
$this->CheckFunctionalCIList($oTicket);
|
||||
$this->CheckContactList($oTicket);
|
||||
$this->assertEquals(7, $oTicket->Get('functionalcis_list')->Count());
|
||||
$this->assertEquals(2, $oTicket->Get('contacts_list')->Count());
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* +-->Person1
|
||||
* |
|
||||
* +
|
||||
* Server1+---->Hypervisor1+--+ +-->VM1
|
||||
* | |
|
||||
* v +
|
||||
* Farm (1)
|
||||
* ^ +
|
||||
* | |
|
||||
* Server2+---->Hypervisor2+--+ +-->VM2
|
||||
* +
|
||||
* |
|
||||
* +-->Person2
|
||||
*
|
||||
* Ticket+---->Server1 (manual), Server2 (manual), Hypervisor2 (not_impacted)
|
||||
* |
|
||||
* +---->Person2 (do_not_notify)
|
||||
*
|
||||
* Result:
|
||||
*
|
||||
* Ticket+====>Server1,Hypervisor1,Server2,Hypervisor2
|
||||
* |
|
||||
* +====>Person1,Person2 (do_not_notify)
|
||||
* </pre>
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testUpdateImpactedItems_Exclusion3()
|
||||
{
|
||||
$oFarm = $this->CreateFarm(1);
|
||||
|
||||
$oServer1 = $this->CreateServer(1);
|
||||
$oHypervisor1 = $this->CreateHypervisor(1, $oServer1, $oFarm);
|
||||
$oContact1 = $this->CreatePerson(1);
|
||||
$this->AddContactToCI($oContact1, $oHypervisor1);
|
||||
$oHypervisor1->DBUpdate();
|
||||
|
||||
$oServer2 = $this->CreateServer(2);
|
||||
$oHypervisor2 = $this->CreateHypervisor(2, $oServer2, $oFarm);
|
||||
$oContact2 = $this->CreatePerson(2);
|
||||
$this->AddContactToCI($oContact2, $oHypervisor2);
|
||||
$oHypervisor2->DBUpdate();
|
||||
|
||||
$this->CreateVirtualMachine(1, $oFarm);
|
||||
$this->CreateVirtualMachine(2, $oFarm);
|
||||
|
||||
$oTicket = $this->CreateTicket(1);
|
||||
$this->AddCIToTicket($oServer1, $oTicket, 'manual');
|
||||
$this->AddCIToTicket($oServer2, $oTicket, 'manual');
|
||||
$this->AddCIToTicket($oHypervisor2, $oTicket, 'not_impacted');
|
||||
$this->AddContactToTicket($oContact2, $oTicket, 'do_not_notify');
|
||||
$oTicket->DBUpdate(); // trigger the impact update
|
||||
$this->ReloadObject($oTicket); // reload the links
|
||||
|
||||
$this->CheckFunctionalCIList($oTicket);
|
||||
$this->CheckContactList($oTicket);
|
||||
$this->assertEquals(4, $oTicket->Get('functionalcis_list')->Count());
|
||||
$this->assertEquals(2, $oTicket->Get('contacts_list')->Count());
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* +-->Person1
|
||||
* |
|
||||
* +
|
||||
* Server1+---->Hypervisor1+--+ +-->VM1
|
||||
* | |
|
||||
* v +
|
||||
* Farm (1)
|
||||
* ^ +
|
||||
* | |
|
||||
* Server2+---->Hypervisor2+--+ +-->VM2
|
||||
* +
|
||||
* |
|
||||
* +-->Person2
|
||||
*
|
||||
* Ticket+---->Server1 (manual), Hypervisor2 (not_impacted)
|
||||
*
|
||||
* Result:
|
||||
*
|
||||
* Ticket+====>Server1,Hypervisor1, Hypervisor2 (not_impacted)
|
||||
* |
|
||||
* +====>Person1
|
||||
* </pre>
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testUpdateImpactedItems_Exclusion4()
|
||||
{
|
||||
$oFarm = $this->CreateFarm(1);
|
||||
|
||||
$oServer1 = $this->CreateServer(1);
|
||||
$oHypervisor1 = $this->CreateHypervisor(1, $oServer1, $oFarm);
|
||||
$oContact1 = $this->CreatePerson(1);
|
||||
$this->AddContactToCI($oContact1, $oHypervisor1);
|
||||
$oHypervisor1->DBUpdate();
|
||||
|
||||
$oServer2 = $this->CreateServer(2);
|
||||
$oHypervisor2 = $this->CreateHypervisor(2, $oServer2, $oFarm);
|
||||
$oContact2 = $this->CreatePerson(2);
|
||||
$this->AddContactToCI($oContact2, $oHypervisor2);
|
||||
$oHypervisor2->DBUpdate();
|
||||
|
||||
$this->CreateVirtualMachine(1, $oFarm);
|
||||
$this->CreateVirtualMachine(2, $oFarm);
|
||||
|
||||
$oTicket = $this->CreateTicket(1);
|
||||
$this->AddCIToTicket($oServer1, $oTicket, 'manual');
|
||||
$this->AddCIToTicket($oHypervisor2, $oTicket, 'not_impacted');
|
||||
$oTicket->DBUpdate(); // trigger the impact update
|
||||
$this->ReloadObject($oTicket); // reload the links
|
||||
|
||||
$this->CheckFunctionalCIList($oTicket);
|
||||
$this->CheckContactList($oTicket);
|
||||
$this->assertEquals(3, $oTicket->Get('functionalcis_list')->Count());
|
||||
$this->assertEquals(1, $oTicket->Get('contacts_list')->Count());
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* +-->Person1
|
||||
* |
|
||||
* +
|
||||
* Server1+---->Hypervisor1+--+ +-->VM1
|
||||
* | |
|
||||
* v +
|
||||
* Farm (1)
|
||||
* ^ +
|
||||
* | |
|
||||
* Server2+---->Hypervisor2+--+ +-->VM2
|
||||
* +
|
||||
* |
|
||||
* +-->Person2
|
||||
*
|
||||
* Ticket1+---->Server1 (manual)
|
||||
*
|
||||
* Result:
|
||||
*
|
||||
* Ticket1+====>Server1,Hypervisor1
|
||||
* |
|
||||
* +====>Person1
|
||||
*
|
||||
* Then:
|
||||
*
|
||||
* Ticket2+---->Server2 (manual)
|
||||
*
|
||||
* Result:
|
||||
*
|
||||
* Ticket2+====>Server2,Hypervisor2,Farm,VM1,VM2
|
||||
* |
|
||||
* +====>Person2
|
||||
* </pre>
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testUpdateImpactedItems_Redundancy_two_tickets()
|
||||
{
|
||||
$oFarm = $this->CreateFarm(1);
|
||||
|
||||
$oServer1 = $this->CreateServer(1);
|
||||
$oHypervisor1 = $this->CreateHypervisor(1, $oServer1, $oFarm);
|
||||
$oContact1 = $this->CreatePerson(1);
|
||||
$this->AddContactToCI($oContact1, $oHypervisor1);
|
||||
$oHypervisor1->DBUpdate();
|
||||
|
||||
$oServer2 = $this->CreateServer(2);
|
||||
$oHypervisor2 = $this->CreateHypervisor(2, $oServer2, $oFarm);
|
||||
$oContact2 = $this->CreatePerson(2);
|
||||
$this->AddContactToCI($oContact2, $oHypervisor2);
|
||||
$oHypervisor2->DBUpdate();
|
||||
|
||||
$oVM1 = $this->CreateVirtualMachine(1, $oFarm);
|
||||
$oVM2 = $this->CreateVirtualMachine(2, $oFarm);
|
||||
|
||||
// Ticket1+---->Server1 (manual)
|
||||
$oTicket1 = $this->CreateTicket(1);
|
||||
$this->AddCIToTicket($oServer1, $oTicket1, 'manual');
|
||||
$oTicket1->DBUpdate(); // trigger the impact update
|
||||
$this->ReloadObject($oTicket1); // reload the links
|
||||
|
||||
// Ticket1+====>Server1,Hypervisor1
|
||||
// |
|
||||
// +====>Person1
|
||||
$this->CheckFunctionalCIList($oTicket1);
|
||||
$this->CheckContactList($oTicket1);
|
||||
$this->assertEquals(2, $oTicket1->Get('functionalcis_list')->Count());
|
||||
$this->assertEquals(1, $oTicket1->Get('contacts_list')->Count());
|
||||
|
||||
// Ticket2+---->Hypervisor2 (manual)
|
||||
$oTicket2 = $this->CreateTicket(2);
|
||||
$this->AddCIToTicket($oServer2, $oTicket2, 'manual');
|
||||
$oTicket2->DBUpdate(); // trigger the impact update
|
||||
$this->ReloadObject($oTicket2); // reload the links
|
||||
|
||||
// Ticket2+====>Farm,Hypervisor2,VM1,VM2,Server2
|
||||
// |
|
||||
// +====>Person2
|
||||
$aWaitedCIList = array(
|
||||
$oFarm->GetKey() => 'computed',
|
||||
$oVM1->GetKey() => 'computed',
|
||||
$oVM2->GetKey() => 'computed',
|
||||
$oHypervisor2->GetKey() => 'computed',
|
||||
$oServer2->GetKey() => 'manual');
|
||||
$this->CheckFunctionalCIList($oTicket2, $aWaitedCIList);
|
||||
$this->CheckContactList($oTicket2);
|
||||
$this->assertEquals(2, $oTicket2->Get('functionalcis_list')->Count());
|
||||
$this->assertEquals(1, $oTicket2->Get('contacts_list')->Count());
|
||||
|
||||
// The first ticket is not impacted
|
||||
$this->debug("\nCheck that the first ticket has not changed.");
|
||||
$this->ReloadObject($oTicket1); // reload the links
|
||||
|
||||
// Ticket1+====>Server1,Hypervisor1
|
||||
// |
|
||||
// +====>Person1
|
||||
$this->CheckFunctionalCIList($oTicket1);
|
||||
$this->CheckContactList($oTicket1);
|
||||
$this->assertEquals(2, $oTicket1->Get('functionalcis_list')->Count());
|
||||
$this->assertEquals(1, $oTicket1->Get('contacts_list')->Count());
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* +-->Person1
|
||||
* |
|
||||
* +
|
||||
* Server1+---->Hypervisor1+--+ +-->VM1
|
||||
* | |
|
||||
* v +
|
||||
* Server3+---->Hypervisor3+->Farm (1)
|
||||
* ^ +
|
||||
* | |
|
||||
* Server2+---->Hypervisor2+--+ +-->VM2
|
||||
* +
|
||||
* |
|
||||
* +-->Person2
|
||||
*
|
||||
* Ticket1+---->Server1 (manual), Hypervisor2(manual)
|
||||
*
|
||||
* Result:
|
||||
*
|
||||
* Ticket1+====>Server1,Hypervisor1, Hypervisor2
|
||||
* |
|
||||
* +====>Person1, Person2
|
||||
*
|
||||
* Then:
|
||||
*
|
||||
* Ticket2+---->Server2 (manual), Hypervisor3 (manual)
|
||||
*
|
||||
* Result:
|
||||
*
|
||||
* Ticket2+====>Server2,Hypervisor2,Hypervisor3,Farm,VM1,VM2
|
||||
* |
|
||||
* +====>Person2
|
||||
* </pre>
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testUpdateImpactedItems_Redundancy_two_tickets2()
|
||||
{
|
||||
$oFarm = $this->CreateFarm(1);
|
||||
|
||||
$oServer1 = $this->CreateServer(1);
|
||||
$oHypervisor1 = $this->CreateHypervisor(1, $oServer1, $oFarm);
|
||||
$oContact1 = $this->CreatePerson(1);
|
||||
$this->AddContactToCI($oContact1, $oHypervisor1);
|
||||
$oHypervisor1->DBUpdate();
|
||||
|
||||
$oServer2 = $this->CreateServer(2);
|
||||
$oHypervisor2 = $this->CreateHypervisor(2, $oServer2, $oFarm);
|
||||
$oContact2 = $this->CreatePerson(2);
|
||||
$this->AddContactToCI($oContact2, $oHypervisor2);
|
||||
$oHypervisor2->DBUpdate();
|
||||
|
||||
$oServer3 = $this->CreateServer(3);
|
||||
$oHypervisor3 = $this->CreateHypervisor(3, $oServer3, $oFarm);
|
||||
|
||||
|
||||
$oVM1 = $this->CreateVirtualMachine(1, $oFarm);
|
||||
$oVM2 = $this->CreateVirtualMachine(2, $oFarm);
|
||||
|
||||
// Ticket1+---->Server1 (manual), Hypervisor2(manual)
|
||||
$oTicket1 = $this->CreateTicket(1);
|
||||
$this->AddCIToTicket($oServer1, $oTicket1, 'manual');
|
||||
$this->AddCIToTicket($oHypervisor2, $oTicket1, 'manual');
|
||||
$oTicket1->DBUpdate(); // trigger the impact update
|
||||
$this->ReloadObject($oTicket1); // reload the links
|
||||
|
||||
// Ticket1+====>Server1,Hypervisor1,Hypervisor2
|
||||
// |
|
||||
// +====>Person1,Person2
|
||||
$this->CheckFunctionalCIList($oTicket1);
|
||||
$this->CheckContactList($oTicket1);
|
||||
$this->assertEquals(3, $oTicket1->Get('functionalcis_list')->Count());
|
||||
$this->assertEquals(2, $oTicket1->Get('contacts_list')->Count());
|
||||
|
||||
// Ticket2+---->Server2 (manual)
|
||||
$oTicket2 = $this->CreateTicket(2);
|
||||
$this->AddCIToTicket($oServer2, $oTicket2, 'manual');
|
||||
$this->AddCIToTicket($oHypervisor3, $oTicket2, 'manual');
|
||||
$oTicket2->DBUpdate(); // trigger the impact update
|
||||
$this->ReloadObject($oTicket2); // reload the links
|
||||
|
||||
// Ticket2+====>Farm,Hypervisor2,VM1,VM2,Server2
|
||||
// |
|
||||
// +====>Person2
|
||||
$aWaitedCIList = array(
|
||||
$oFarm->GetKey() => 'computed',
|
||||
$oVM1->GetKey() => 'computed',
|
||||
$oVM2->GetKey() => 'computed',
|
||||
$oHypervisor2->GetKey() => 'computed',
|
||||
$oHypervisor3->GetKey() => 'manual',
|
||||
$oServer2->GetKey() => 'manual');
|
||||
$this->CheckFunctionalCIList($oTicket2, $aWaitedCIList);
|
||||
$this->CheckContactList($oTicket2);
|
||||
$this->assertEquals(3, $oTicket2->Get('functionalcis_list')->Count());
|
||||
$this->assertEquals(1, $oTicket2->Get('contacts_list')->Count());
|
||||
|
||||
// The first ticket is not impacted
|
||||
$this->debug("\nCheck that the first ticket has not changed.");
|
||||
$this->ReloadObject($oTicket1); // reload the links
|
||||
|
||||
// Ticket1+====>Server1,Hypervisor1,Hypervisor2
|
||||
// |
|
||||
// +====>Person1,Person2
|
||||
$this->CheckFunctionalCIList($oTicket1);
|
||||
$this->CheckContactList($oTicket1);
|
||||
$this->assertEquals(3, $oTicket1->Get('functionalcis_list')->Count());
|
||||
$this->assertEquals(2, $oTicket1->Get('contacts_list')->Count());
|
||||
}
|
||||
|
||||
}
|
||||
87
tests/php-unit-tests/unitary-tests/setup/DBBackupTest.php
Normal file
87
tests/php-unit-tests/unitary-tests/setup/DBBackupTest.php
Normal file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Core;
|
||||
|
||||
use CMDBSource;
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
use DBBackup;
|
||||
use utils;
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class DBBackupTest extends ItopTestCase
|
||||
{
|
||||
/**
|
||||
* @throws \CoreException
|
||||
* @throws \MySQLException
|
||||
* @throws \ConfigException
|
||||
*/
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
require_once(APPROOT.'setup/backup.class.inc.php');
|
||||
|
||||
// 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();
|
||||
CMDBSource::InitFromConfig($oConfigOnDisk);
|
||||
}
|
||||
|
||||
/**
|
||||
* No TLS connection = no additional CLI args !
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \ConfigException
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
public function testGetMysqlCliTlsOptionsNoTls()
|
||||
{
|
||||
$oConfigToTest = utils::GetConfig();
|
||||
|
||||
$oConfigToTest->Set('db_tls.enabled', false);
|
||||
$sCliArgsNoTls = DBBackup::GetMysqlCliTlsOptions($oConfigToTest);
|
||||
|
||||
$this->assertEmpty($sCliArgsNoTls);
|
||||
}
|
||||
|
||||
/**
|
||||
* TLS connection configured = we need one CLI arg
|
||||
*
|
||||
* @return void
|
||||
* @throws \ConfigException
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function testGetMysqlCliTlsOptionsWithTlsNoCa()
|
||||
{
|
||||
$oConfigToTest = utils::GetConfig();
|
||||
$oConfigToTest->Set('db_tls.enabled', true);
|
||||
$sCliArgsMinCfg = DBBackup::GetMysqlCliTlsOptions($oConfigToTest);
|
||||
|
||||
// depending on the MySQL version, we would have `--ssl` or `--ssl-mode=VERIFY_CA`
|
||||
$this->assertStringStartsWith(' --ssl', $sCliArgsMinCfg);
|
||||
}
|
||||
|
||||
/**
|
||||
* TLS connection configured + CA option = we need multiple CLI args
|
||||
*
|
||||
* @return void
|
||||
* @throws \ConfigException
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function testGetMysqlCliTlsOptionsWithTlsAndCa()
|
||||
{
|
||||
$oConfigToTest = utils::GetConfig();
|
||||
$sTestCa = 'my_test_ca';
|
||||
|
||||
$oConfigToTest->Set('db_tls.enabled', true);
|
||||
$oConfigToTest->Set('db_tls.ca', $sTestCa);
|
||||
$sCliArgsCapathCfg = DBBackup::GetMysqlCliTlsOptions($oConfigToTest);
|
||||
|
||||
$this->assertStringStartsWith(' --ssl', $sCliArgsCapathCfg);
|
||||
$this->assertStringEndsWith('--ssl-ca='.DBBackup::EscapeShellArg($sTestCa), $sCliArgsCapathCfg);
|
||||
}
|
||||
}
|
||||
68
tests/php-unit-tests/unitary-tests/setup/SetupUtilsTest.php
Normal file
68
tests/php-unit-tests/unitary-tests/setup/SetupUtilsTest.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Setup;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
use SetupUtils;
|
||||
|
||||
|
||||
/**
|
||||
* Class SetupUtilsTest
|
||||
*
|
||||
* @covers SetupUtils
|
||||
*
|
||||
* @since 2.7.4 N°3412
|
||||
* @package Combodo\iTop\Test\UnitTest\Setup
|
||||
*/
|
||||
class SetupUtilsTest extends ItopTestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
require_once APPROOT.'setup/setuputils.class.inc.php';
|
||||
require_once APPROOT.'setup/setuppage.class.inc.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider CheckGraphvizProvider
|
||||
*/
|
||||
public function testCheckGraphviz($sScriptPath, $iSeverity, $sLabel){
|
||||
/** @var \CheckResult $oCheck */
|
||||
$oCheck = SetupUtils::CheckGraphviz($sScriptPath);
|
||||
$this->assertEquals($iSeverity, $oCheck->iSeverity);
|
||||
$this->assertContains($sLabel, $oCheck->sLabel);
|
||||
}
|
||||
|
||||
public function CheckGraphvizProvider(){
|
||||
if (substr(PHP_OS,0,3) === 'WIN'){
|
||||
return [];
|
||||
}
|
||||
|
||||
return [
|
||||
"bash injection" => [
|
||||
"touch /tmp/toto",
|
||||
1,
|
||||
"could not be executed: Please make sure it is installed and in the path",
|
||||
],
|
||||
"command ok" => [
|
||||
"/usr/bin/whereis",
|
||||
2,
|
||||
"",
|
||||
],
|
||||
"empty command => dot by default" => [
|
||||
"",
|
||||
2,
|
||||
"",
|
||||
],
|
||||
"command failed" => [
|
||||
"/bin/ls",
|
||||
1,
|
||||
"dot could not be executed (retcode=2): Please make sure it is installed and in the path",
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.6">
|
||||
<menus>
|
||||
<menu id="WelcomeMenuLink1" xsi:type="WebPageMenuNode" _delta="define">
|
||||
<rank>100</rank>
|
||||
<parent>WelcomeMenu</parent>
|
||||
<url>$$http://fr.wikipedia.org/</url>
|
||||
</menu>
|
||||
<menu id="WelcomeMenuLink2" xsi:type="WebPageMenuNode" _delta="define">
|
||||
<rank>100</rank>
|
||||
<parent>WelcomeMenu</parent>
|
||||
<url>$$http://fr.wikipedia.org/</url>
|
||||
</menu>
|
||||
</menus>
|
||||
</itop_design>
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.7">
|
||||
<menus>
|
||||
<menu id="WelcomeMenuLink1" xsi:type="WebPageMenuNode" _delta="define">
|
||||
<rank>100</rank>
|
||||
<parent>WelcomeMenu</parent>
|
||||
<url>$$http://fr.wikipedia.org/</url>
|
||||
<in_new_window>true</in_new_window>
|
||||
</menu>
|
||||
<menu id="WelcomeMenuLink2" xsi:type="WebPageMenuNode" _delta="define">
|
||||
<rank>100</rank>
|
||||
<parent>WelcomeMenu</parent>
|
||||
<url>$$http://fr.wikipedia.org/</url>
|
||||
</menu>
|
||||
</menus>
|
||||
</itop_design>
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Setup;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
use DOMDocument;
|
||||
use iTopDesignFormat;
|
||||
|
||||
|
||||
/**
|
||||
* @covers iTopDesignFormat
|
||||
*
|
||||
* @since 2.7.0 N°2586
|
||||
* @package Combodo\iTop\Test\UnitTest\Setup
|
||||
*/
|
||||
class iTopDesignFormatTest extends ItopTestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
require_once APPROOT.'setup/modelfactory.class.inc.php';
|
||||
require_once APPROOT.'setup/itopdesignformat.class.inc.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers iTopDesignFormat::Convert
|
||||
* @dataProvider MigrationMethodProvider
|
||||
*
|
||||
* @param string $sTargetVersion
|
||||
* @param string $sInputXmlFileName example "1.7_to_1.6.input"
|
||||
* @param string $sExpectedXmlFileName example "1.7_to_1.6.expected"
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function testMigrationMethod($sTargetVersion, $sInputXmlFileName, $sExpectedXmlFileName)
|
||||
{
|
||||
$sInputXml = $this->GetFileContent($sInputXmlFileName);
|
||||
$sExpectedXml = $this->GetFileContent($sExpectedXmlFileName);
|
||||
|
||||
$oInputDocument = new DOMDocument();
|
||||
libxml_clear_errors();
|
||||
$oInputDocument->preserveWhiteSpace = false;
|
||||
$oInputDocument->loadXML($sInputXml);
|
||||
$oInputDocument->formatOutput = true;
|
||||
$oDesignFormat = new iTopDesignFormat($oInputDocument);
|
||||
$oDesignFormat->Convert($sTargetVersion);
|
||||
|
||||
$sConvertedXml = $oInputDocument->saveXML();
|
||||
|
||||
$this->assertEquals($sExpectedXml, $sConvertedXml);
|
||||
}
|
||||
|
||||
private function GetFileContent($sFileName)
|
||||
{
|
||||
$sCurrentPath = __DIR__;
|
||||
|
||||
return file_get_contents($sCurrentPath.DIRECTORY_SEPARATOR.$sFileName.'.xml');
|
||||
}
|
||||
|
||||
public function MigrationMethodProvider()
|
||||
{
|
||||
return array(
|
||||
'1.7 to 1.6' => array('1.6', '1.7_to_1.6.input', '1.7_to_1.6.expected'),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
<?php
|
||||
|
||||
use Combodo\iTop\Composer\iTopComposer;
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
|
||||
/**
|
||||
* Copyright (C) 2010-2020 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/>
|
||||
*
|
||||
*/
|
||||
class iTopComposerTest extends ItopTestCase
|
||||
{
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
clearstatcache();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider IsTestDirProvider
|
||||
* @return void
|
||||
*/
|
||||
public function testIsTestDir($sDirName, $bIsTest)
|
||||
{
|
||||
$isTestDir = iTopComposer::IsTestDir($sDirName);
|
||||
$this->assertIsInt($isTestDir);
|
||||
if (true === $bIsTest) {
|
||||
$this->assertTrue(($isTestDir > 0));
|
||||
} else {
|
||||
$this->assertSame(0, $isTestDir);
|
||||
}
|
||||
}
|
||||
|
||||
public function IsTestDirProvider()
|
||||
{
|
||||
return [
|
||||
'test' => ['test', true],
|
||||
'Test' => ['Test', true],
|
||||
'tests' => ['tests', true],
|
||||
'Tests' => ['Tests', true],
|
||||
'testaa' => ['testaa', false],
|
||||
'Testaa' => ['Testaa', false],
|
||||
'testsaa' => ['testsaa', false],
|
||||
'Testsaa' => ['Testsaa', false],
|
||||
];
|
||||
}
|
||||
|
||||
public function testListAllTestDir()
|
||||
{
|
||||
$oiTopComposer = new iTopComposer();
|
||||
$aDirs = $oiTopComposer->ListAllTestDir();
|
||||
|
||||
$this->assertTrue(is_array($aDirs));
|
||||
|
||||
foreach ($aDirs as $sDir) {
|
||||
$sDirName = basename($sDir);
|
||||
$this->assertRegExp(iTopComposer::TEST_DIR_REGEXP, $sDirName, "Directory not matching test dir : $sDir");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function testListDeniedTestDir()
|
||||
{
|
||||
$oiTopComposer = new iTopComposer();
|
||||
$aDirs = $oiTopComposer->ListDeniedTestDir();
|
||||
|
||||
$this->assertTrue(is_array($aDirs));
|
||||
|
||||
$aDeniedDirWrongFormat = [];
|
||||
foreach ($aDirs as $sDir) {
|
||||
if (false === iTopComposer::IsTestDir($sDir)) {
|
||||
$aDeniedDirWrongFormat[] = $sDir;
|
||||
}
|
||||
}
|
||||
|
||||
$this->assertEmpty($aDeniedDirWrongFormat,
|
||||
'There are elements in \Combodo\iTop\Composer\iTopComposer::ListDeniedTestDir that are not test dirs :'.var_export($aDeniedDirWrongFormat, true));
|
||||
}
|
||||
|
||||
public function testListAllowedTestDir()
|
||||
{
|
||||
$oiTopComposer = new iTopComposer();
|
||||
$aDirs = $oiTopComposer->ListAllowedTestDir();
|
||||
|
||||
$this->assertTrue(is_array($aDirs));
|
||||
}
|
||||
|
||||
/**
|
||||
* This is NOT a unit test, this test the iTop instance running the test ...
|
||||
*/
|
||||
public function testNoDeniedDirIsPresentForNow()
|
||||
{
|
||||
$oiTopComposer = new iTopComposer();
|
||||
|
||||
$aDeniedButStillPresent = $oiTopComposer->ListDeniedButStillPresent();
|
||||
|
||||
$this->assertEmpty(
|
||||
$aDeniedButStillPresent,
|
||||
'The iTop instance running this test must not contain any denied test directory, found: '.var_export($aDeniedButStillPresent, true)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This is NOT a unit test, this test the iTop instance running the test ...
|
||||
*/
|
||||
public function testAllDirCovered()
|
||||
{
|
||||
$oiTopComposer = new iTopComposer();
|
||||
$aAllowedAndDeniedDirs = array_merge(
|
||||
$oiTopComposer->ListAllowedTestDir(),
|
||||
$oiTopComposer->ListDeniedTestDir()
|
||||
);
|
||||
|
||||
$aExistingDirs = $oiTopComposer->ListAllTestDir();
|
||||
|
||||
$aMissing = array_diff($aExistingDirs, $aAllowedAndDeniedDirs);
|
||||
$aExtra = array_diff($aAllowedAndDeniedDirs, $aExistingDirs);
|
||||
|
||||
$this->assertEmpty(
|
||||
$aMissing,
|
||||
'Test dirs exists in /lib !'."\n"
|
||||
.' They must be declared either in the allowed or denied list in '.iTopComposer::class." (see N°2651).\n"
|
||||
.' List of dirs:'."\n".var_export($aMissing, true)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
namespace Combodo\iTop\Test\UnitTest;
|
||||
|
||||
use Combodo\iTop\Portal\Twig\AppExtension;
|
||||
use Twig_Environment;
|
||||
use Twig_Loader_Array;
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class TwigTest extends ItopDataTestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
require_once __DIR__.'/../../core/config.class.inc.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the fix for ticket N°4384
|
||||
*
|
||||
* @dataProvider TemplateProvider
|
||||
*
|
||||
*/
|
||||
public function testTemplate($sFileName, $sExpected)
|
||||
{
|
||||
$sId = 'TestTwig';
|
||||
$oAppExtension = new AppExtension();
|
||||
|
||||
// Creating sandbox twig env. to load and test the custom form template
|
||||
$oTwig = new Twig_Environment(new Twig_Loader_Array([$sId => $sFileName]));
|
||||
|
||||
// Manually registering filters and functions as we didn't find how to do it automatically
|
||||
$aFilters = $oAppExtension->getFilters();
|
||||
foreach ($aFilters as $oFilter)
|
||||
{
|
||||
$oTwig->addFilter($oFilter);
|
||||
}
|
||||
$aFunctions = $oAppExtension->getFunctions();
|
||||
foreach ($aFunctions as $oFunction)
|
||||
{
|
||||
$oTwig->addFunction($oFunction);
|
||||
}
|
||||
|
||||
$sHtml = $oTwig->render($sId, ['AttackerURL' => 'file://'.__DIR__.'/attacker']);
|
||||
|
||||
$this->assertEquals($sExpected, $sHtml);
|
||||
}
|
||||
|
||||
public static function TemplateProvider()
|
||||
{
|
||||
$aReturn = array();
|
||||
$aReturn['filter_system'] = [
|
||||
'sFileName' => file_get_contents(__DIR__.'/test.html.twig'),
|
||||
'expected' => file_get_contents(__DIR__.'/test.html'),
|
||||
];
|
||||
|
||||
return $aReturn;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<div>User Name</div>
|
||||
|
||||
<div>['id']|filter('system')|join</div>
|
||||
["id"]
|
||||
|
||||
<div>['echo']|filter('passthru')|join</div>
|
||||
["echo"]
|
||||
|
||||
<div>['echo']|filter('popen')|join</div>
|
||||
["echo"]
|
||||
|
||||
<div>['echo']|filter('exec')|join</div>
|
||||
["echo"]
|
||||
|
||||
<div>['id']|filter('SysteM')|join</div>
|
||||
["id"]
|
||||
|
||||
<div>['touch+/tmp/test+']|filter('system')|join(',')</div>
|
||||
["touch+\/tmp\/test+"]
|
||||
|
||||
<div>[34, 36, 38, 40, 42]|filter(v => v > 38)|join(', ')</div>
|
||||
[34,36,38,40,42]
|
||||
|
||||
<div>app.request.server.all|join(',')</div>
|
||||
|
||||
|
||||
<div>self</div>
|
||||
|
||||
|
||||
<div>[0]|reduce('system','echo')</div>
|
||||
0
|
||||
|
||||
<div>[1, 2, 3]|reduce((carry, v) => carry + v)</div>
|
||||
1, 2, 3
|
||||
|
||||
<div>['echo']|map('system')|join</div>
|
||||
echo
|
||||
|
||||
<div>{"Bob": "Smith", "Alice": "Dupond"}|map((value, key) => "#{key} #{value}")|join(', ')</div>
|
||||
Smith, Dupond
|
||||
|
||||
<div>['echo',1]|sort('system')|join</div>
|
||||
echo1
|
||||
|
||||
POST /subscribe?0=cat+/etc/passwd HTTP/1.1
|
||||
email=""@attacker.tld
|
||||
@@ -0,0 +1,51 @@
|
||||
<div>{{ 'UI:Login:UserNamePrompt'|dict_s }}</div>
|
||||
|
||||
<div>['id']|filter('system')|join</div>
|
||||
{{ ['id']|filter('system')|join }}
|
||||
|
||||
<div>['echo']|filter('passthru')|join</div>
|
||||
{{ ['echo']|filter('passthru')|join }}
|
||||
|
||||
<div>['echo']|filter('popen')|join</div>
|
||||
{{ ['echo']|filter('popen')|join }}
|
||||
|
||||
<div>['echo']|filter('exec')|join</div>
|
||||
{{ ['echo']|filter('exec')|join }}
|
||||
|
||||
<div>['id']|filter('SysteM')|join</div>
|
||||
{{ ['id']|filter('SysteM')|join }}
|
||||
|
||||
<div>['touch+/tmp/test+']|filter('system')|join(',')</div>
|
||||
{{ ['touch+/tmp/test+']|filter('system')|join(',') }}
|
||||
|
||||
<div>[34, 36, 38, 40, 42]|filter(v => v > 38)|join(', ')</div>
|
||||
{{ [34, 36, 38, 40, 42]|filter(v => v > 38)|join(', ') }}
|
||||
|
||||
<div>app.request.server.all|join(',')</div>
|
||||
{{ app.request.server.all|join(',')}}
|
||||
|
||||
<div>self</div>
|
||||
{{ self }}
|
||||
|
||||
<div>[0]|reduce('system','echo')</div>
|
||||
{{ [0]|reduce('system','echo')|join(', ') }}
|
||||
|
||||
<div>[1, 2, 3]|reduce((carry, v) => carry + v)</div>
|
||||
{% set numbers = [1, 2, 3] %}
|
||||
{{ numbers|reduce((carry, v) => carry + v)|join(', ') }}
|
||||
|
||||
<div>['echo']|map('system')|join</div>
|
||||
{{ ['echo']|map('system')|join }}
|
||||
|
||||
<div>{"Bob": "Smith", "Alice": "Dupond"}|map((value, key) => "#{key} #{value}")|join(', ')</div>
|
||||
{% set people = {
|
||||
"Bob": "Smith",
|
||||
"Alice": "Dupond",
|
||||
} %}
|
||||
{{ people|map((value, key) => "#{key} #{value}")|join(', ') }}
|
||||
|
||||
<div>['echo',1]|sort('system')|join</div>
|
||||
{{ ['echo',1]|sort('system')|join }}
|
||||
|
||||
POST /subscribe?0=cat+/etc/passwd HTTP/1.1
|
||||
email="{{ app.request.query.filter(0,0,1024,{'options':'system'}) }}"@attacker.tld
|
||||
@@ -0,0 +1,729 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2010-2018 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/>
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Eric
|
||||
* Date: 08/03/2018
|
||||
* Time: 16:46
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Application\Search;
|
||||
|
||||
use AttributeDate;
|
||||
use AttributeDateTime;
|
||||
use AttributeDefinition;
|
||||
use Combodo\iTop\Application\Search\CriterionConversion\CriterionToOQL;
|
||||
use Combodo\iTop\Application\Search\CriterionConversion\CriterionToSearchForm;
|
||||
use Combodo\iTop\Application\Search\CriterionParser;
|
||||
use Combodo\iTop\Application\Search\SearchForm;
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use DBObjectSearch;
|
||||
use DBObjectSet;
|
||||
use DBSearch;
|
||||
use Dict;
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class CriterionConversionTest extends ItopDataTestCase
|
||||
{
|
||||
const CREATE_TEST_ORG = true;
|
||||
|
||||
/**
|
||||
* @dataProvider ToOqlProvider
|
||||
*
|
||||
* @param $sClass
|
||||
* @param $sJSONCriterion
|
||||
* @param $sExpectedOQL
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function testToOql($sClass, $sJSONCriterion, $sExpectedOQL)
|
||||
{
|
||||
$oSearch = new DBObjectSearch($sClass);
|
||||
$sOql = CriterionToOQL::Convert(
|
||||
$oSearch, json_decode($sJSONCriterion, true)
|
||||
);
|
||||
|
||||
$this->debug($sOql);
|
||||
$this->assertEquals($sExpectedOQL, $sOql);
|
||||
}
|
||||
|
||||
public function ToOqlProvider()
|
||||
{
|
||||
return array(
|
||||
'>' => array(
|
||||
'UserRequest',
|
||||
'{
|
||||
"ref": "UserRequest.start_date",
|
||||
"values": [
|
||||
{
|
||||
"value": "2017-01-01",
|
||||
"label": "2017-01-01 00:00:00"
|
||||
}
|
||||
],
|
||||
"operator": ">",
|
||||
"oql": ""
|
||||
}',
|
||||
"(`UserRequest`.`start_date` > '2017-01-01')"
|
||||
),
|
||||
'contains' => array(
|
||||
'Contact',
|
||||
'{
|
||||
"ref": "Contact.name",
|
||||
"values": [
|
||||
{
|
||||
"value": "toto",
|
||||
"label": "toto"
|
||||
}
|
||||
],
|
||||
"operator": "contains",
|
||||
"oql": ""
|
||||
}',
|
||||
"(`Contact`.`name` LIKE '%toto%')"
|
||||
),
|
||||
'starts_with' => array(
|
||||
'Contact',
|
||||
'{
|
||||
"ref": "Contact.name",
|
||||
"values": [
|
||||
{
|
||||
"value": "toto",
|
||||
"label": "toto"
|
||||
}
|
||||
],
|
||||
"operator": "starts_with",
|
||||
"oql": ""
|
||||
}',
|
||||
"(`Contact`.`name` LIKE 'toto%')"
|
||||
),
|
||||
'ends_with' => array(
|
||||
'Contact',
|
||||
'{
|
||||
"ref": "Contact.name",
|
||||
"values": [
|
||||
{
|
||||
"value": "toto",
|
||||
"label": "toto"
|
||||
}
|
||||
],
|
||||
"operator": "ends_with",
|
||||
"oql": ""
|
||||
}',
|
||||
"(`Contact`.`name` LIKE '%toto')"
|
||||
),
|
||||
'empty' => array(
|
||||
'Contact',
|
||||
'{
|
||||
"ref": "Contact.name",
|
||||
"values": [
|
||||
{
|
||||
"value": "",
|
||||
"label": ""
|
||||
}
|
||||
],
|
||||
"operator": "empty",
|
||||
"oql": ""
|
||||
}',
|
||||
"(`Contact`.`name` = '')"
|
||||
),
|
||||
'not_empty' => array(
|
||||
'Contact',
|
||||
'{
|
||||
"ref": "Contact.name",
|
||||
"values": [
|
||||
{
|
||||
"value": "",
|
||||
"label": ""
|
||||
}
|
||||
],
|
||||
"operator": "not_empty",
|
||||
"oql": ""
|
||||
}',
|
||||
"(`Contact`.`name` != '')"
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider ToSearchFormProvider
|
||||
*
|
||||
* @param $aCriterion
|
||||
* @param $sExpectedOperator
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
function testToSearchForm($aCriterion, $sExpectedOperator)
|
||||
{
|
||||
$oSearchForm = new SearchForm();
|
||||
/** @var \DBObjectSearch $oSearch */
|
||||
$oSearch = DBSearch::FromOQL("SELECT Contact");
|
||||
$aFields = $oSearchForm->GetFields(new DBObjectSet($oSearch));
|
||||
$aRes = CriterionToSearchForm::Convert($aCriterion, $aFields, $oSearch->GetJoinedClasses());
|
||||
$this->debug($aRes);
|
||||
$this->assertEquals($sExpectedOperator, $aRes[0]['operator']);
|
||||
}
|
||||
|
||||
function ToSearchFormProvider()
|
||||
{
|
||||
return array(
|
||||
'=' => array(
|
||||
json_decode('[
|
||||
{
|
||||
"ref": "Contact.name",
|
||||
"widget": "string",
|
||||
"values": [
|
||||
{
|
||||
"value": "toto",
|
||||
"label": "toto"
|
||||
}
|
||||
],
|
||||
"operator": "=",
|
||||
"oql": "(`Contact`.`name` = \'toto\')"
|
||||
}
|
||||
]', true),
|
||||
'='
|
||||
),
|
||||
'starts_with' => array(
|
||||
json_decode('[
|
||||
{
|
||||
"ref": "Contact.name",
|
||||
"widget": "string",
|
||||
"values": [
|
||||
{
|
||||
"value": "toto%",
|
||||
"label": "toto%"
|
||||
}
|
||||
],
|
||||
"operator": "LIKE",
|
||||
"oql": "(`Contact`.`name` LIKE \'toto%\')"
|
||||
}
|
||||
]', true),
|
||||
'starts_with'
|
||||
),
|
||||
'ends_with' => array(
|
||||
json_decode('[
|
||||
{
|
||||
"ref": "Contact.name",
|
||||
"widget": "string",
|
||||
"values": [
|
||||
{
|
||||
"value": "%toto",
|
||||
"label": "%toto"
|
||||
}
|
||||
],
|
||||
"operator": "LIKE",
|
||||
"oql": "(`Contact`.`name` LIKE \'%toto\')"
|
||||
}
|
||||
]', true),
|
||||
'ends_with'
|
||||
),
|
||||
'contains' => array(
|
||||
json_decode('[
|
||||
{
|
||||
"widget": "string",
|
||||
"ref": "Contact.name",
|
||||
"values": [
|
||||
{
|
||||
"value": "%toto%",
|
||||
"label": "%toto%"
|
||||
}
|
||||
],
|
||||
"operator": "LIKE",
|
||||
"oql": "(`Contact`.`name` LIKE \'%toto%\')"
|
||||
}
|
||||
]', true),
|
||||
'contains'
|
||||
),
|
||||
'empty1' => array(
|
||||
json_decode('[
|
||||
{
|
||||
"widget": "string",
|
||||
"ref": "Contact.name",
|
||||
"values": [
|
||||
{
|
||||
"value": "",
|
||||
"label": ""
|
||||
}
|
||||
],
|
||||
"operator": "LIKE",
|
||||
"oql": "(`Contact`.`name` LIKE \'\')"
|
||||
}
|
||||
]', true),
|
||||
'empty'
|
||||
),
|
||||
'empty2' => array(
|
||||
json_decode('[
|
||||
{
|
||||
"widget": "string",
|
||||
"ref": "Contact.name",
|
||||
"values": [
|
||||
{
|
||||
"value": "",
|
||||
"label": ""
|
||||
}
|
||||
],
|
||||
"operator": "=",
|
||||
"oql": "(`Contact`.`name` = \'\')"
|
||||
}
|
||||
]', true),
|
||||
'empty'
|
||||
),
|
||||
'not_empty' => array(
|
||||
json_decode('[
|
||||
{
|
||||
"widget": "string",
|
||||
"ref": "Contact.name",
|
||||
"values": [
|
||||
{
|
||||
"value": "",
|
||||
"label": ""
|
||||
}
|
||||
],
|
||||
"operator": "!=",
|
||||
"oql": "(`Contact`.`name` != \'\')"
|
||||
}
|
||||
]', true),
|
||||
'not_empty'
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider OqlProvider
|
||||
*
|
||||
* @param $sOQL
|
||||
*
|
||||
* @param $sExpectedOQL
|
||||
*
|
||||
* @param $aExpectedCriterion
|
||||
*
|
||||
* @throws \DictExceptionUnknownLanguage
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \OQLException
|
||||
* @throws \CoreException
|
||||
*/
|
||||
function testOqlToSearchToOql($sOQL, $sExpectedOQL, $aExpectedCriterion)
|
||||
{
|
||||
// For tests on tags
|
||||
$this->CreateTagData(TAG_CLASS, TAG_ATTCODE, 'tag1', 'First');
|
||||
$this->CreateTagData(TAG_CLASS, TAG_ATTCODE, 'tag2', 'Second');
|
||||
|
||||
$this->OqlToSearchToOqlAltLanguage($sOQL, $sExpectedOQL, $aExpectedCriterion, "EN US");
|
||||
}
|
||||
|
||||
function OqlProvider()
|
||||
{
|
||||
return array(
|
||||
'no criteria' => array(
|
||||
'OQL' => 'SELECT WebApplication',
|
||||
'ExpectedOQL' => "SELECT `WebApplication` FROM WebApplication AS `WebApplication` WHERE 1",
|
||||
'ExpectedCriterion' => array(),
|
||||
),
|
||||
'string starts' => array(
|
||||
'OQL' => "SELECT Contact WHERE name LIKE 'toto%'",
|
||||
'ExpectedOQL' => "SELECT `Contact` FROM Contact AS `Contact` WHERE (`Contact`.`name` LIKE 'toto%')",
|
||||
'ExpectedCriterion' => array(array('widget' => 'string', 'operator' => 'starts_with', 'values' => array(array('value' => 'toto')))),
|
||||
),
|
||||
'string ends' => array(
|
||||
'OQL' => "SELECT Contact WHERE name LIKE '%toto'",
|
||||
'ExpectedOQL' => "SELECT `Contact` FROM Contact AS `Contact` WHERE (`Contact`.`name` LIKE '%toto')",
|
||||
'ExpectedCriterion' => array(array('widget' => 'string', 'operator' => 'ends_with', 'values' => array(array('value' => 'toto')))),
|
||||
),
|
||||
'string contains 1' => array(
|
||||
'OQL' => "SELECT Contact WHERE name LIKE '%toto%'",
|
||||
'ExpectedOQL' => "SELECT `Contact` FROM Contact AS `Contact` WHERE (`Contact`.`name` LIKE '%toto%')",
|
||||
'ExpectedCriterion' => array(array('widget' => 'string', 'operator' => 'contains', 'values' => array(array('value' => 'toto')))),
|
||||
),
|
||||
'string contains 2' => array(
|
||||
'OQL' => "SELECT Person AS B WHERE B.name LIKE '%A%'",
|
||||
'ExpectedOQL' => "SELECT `B` FROM Person AS `B` WHERE (`B`.`name` LIKE '%A%')",
|
||||
'ExpectedCriterion' => array(array('widget' => 'string', 'operator' => 'contains', 'values' => array(array('value' => 'A')))),
|
||||
),
|
||||
'string NOT contains' => array(
|
||||
'OQL' => "SELECT Person AS B WHERE B.name NOT LIKE '%A%'",
|
||||
'ExpectedOQL' => "SELECT `B` FROM Person AS `B` WHERE (`B`.`name` NOT LIKE '%A%')",
|
||||
'ExpectedCriterion' => array(array('widget' => 'string', 'operator' => 'NOT LIKE', 'values' => array(array('value' => '%A%')))),
|
||||
),
|
||||
'string regexp' => array(
|
||||
'OQL' => "SELECT Server WHERE name REGEXP '^dbserver[0-9]+\\\\\\\\..+\\\\\\\\.[a-z]{2,3}$'",
|
||||
'ExpectedOQL' => "SELECT `Server` FROM Server AS `Server` WHERE (`Server`.`name` REGEXP '^dbserver[0-9]+\\\\\\\\..+\\\\\\\\.[a-z]{2,3}$')",
|
||||
'ExpectedCriterion' => array(array('widget' => 'string', 'operator' => 'REGEXP')),
|
||||
),
|
||||
'enum + key =' => array(
|
||||
'OQL' => "SELECT Contact WHERE status = 'active' AND org_id = 3",
|
||||
'ExpectedOQL' => "SELECT `Contact` FROM Contact AS `Contact` JOIN Organization AS `Organization` ON `Contact`.org_id = `Organization`.id JOIN Organization AS `Organization1` ON `Organization`.parent_id BELOW `Organization1`.id WHERE ((`Organization1`.`id` = '3') AND (`Contact`.`status` = 'active'))",
|
||||
'ExpectedCriterion' => array(array('widget' => 'hierarchical_key', 'operator' => 'IN'), array('widget' => 'enum', 'operator' => 'IN')),
|
||||
),
|
||||
'enum =' => array(
|
||||
'OQL' => "SELECT Contact WHERE status = 'active'",
|
||||
'ExpectedOQL' => "SELECT `Contact` FROM Contact AS `Contact` WHERE (`Contact`.`status` = 'active')",
|
||||
'ExpectedCriterion' => array(array('widget' => 'enum', 'operator' => 'IN', 'values' => array(array('value' => 'active')))),
|
||||
),
|
||||
'enum IN' => array(
|
||||
'OQL' => "SELECT Contact WHERE status IN ('active', 'inactive')",
|
||||
'ExpectedOQL' => "SELECT `Contact` FROM Contact AS `Contact` WHERE 1",
|
||||
'ExpectedCriterion' => array(array('widget' => 'enum', 'operator' => 'IN', 'values' => array(array('value' => 'active'), array('value' => 'inactive')))),
|
||||
),
|
||||
'enum NOT IN 1' => array(
|
||||
'OQL' => "SELECT Contact WHERE status NOT IN ('active')",
|
||||
'ExpectedOQL' => "SELECT `Contact` FROM Contact AS `Contact` WHERE (`Contact`.`status` = 'inactive')",
|
||||
'ExpectedCriterion' => array(array('widget' => 'enum', 'operator' => 'IN', 'values' => array(array('value' => 'inactive')))),
|
||||
),
|
||||
'enum NOT IN 2' => array(
|
||||
'OQL' => "SELECT Person AS p JOIN UserRequest AS u ON u.agent_id = p.id WHERE u.status != 'closed'",
|
||||
'ExpectedOQL' => "SELECT `p` FROM Person AS `p` JOIN UserRequest AS `u` ON `u`.agent_id = `p`.id WHERE (`u`.`status` != 'closed')",
|
||||
'ExpectedCriterion' => array(array('widget' => 'raw')),
|
||||
),
|
||||
'enum undefined 1' => array(
|
||||
'OQL' => "SELECT FunctionalCI WHERE ((business_criticity = 'high') OR ISNULL(business_criticity)) AND 1",
|
||||
'ExpectedOQL' => "SELECT `FunctionalCI` FROM FunctionalCI AS `FunctionalCI` WHERE (((`FunctionalCI`.`business_criticity` = 'high') OR ISNULL(`FunctionalCI`.`business_criticity`)) AND 1)",
|
||||
'ExpectedCriterion' => array(array('widget' => 'enum', 'has_undefined' => true, 'operator' => 'IN', 'values' => array(array('value' => 'high'), array('value' => 'null')))),
|
||||
),
|
||||
'enum undefined 2' => array(
|
||||
'OQL' => "SELECT FunctionalCI WHERE ((business_criticity IN ('high', 'medium')) OR ISNULL(business_criticity)) AND 1",
|
||||
'ExpectedOQL' => "SELECT `FunctionalCI` FROM FunctionalCI AS `FunctionalCI` WHERE (((`FunctionalCI`.`business_criticity` IN ('high', 'medium')) OR ISNULL(`FunctionalCI`.`business_criticity`)) AND 1)",
|
||||
'ExpectedCriterion' => array(array('widget' => 'enum', 'has_undefined' => true, 'operator' => 'IN', 'values' => array(array('value' => 'high'), array('value' => 'medium'), array('value' => 'null')))),
|
||||
),
|
||||
'enum undefined 3' => array(
|
||||
'OQL' => "SELECT FunctionalCI WHERE ISNULL(business_criticity)",
|
||||
'ExpectedOQL' => "SELECT `FunctionalCI` FROM FunctionalCI AS `FunctionalCI` WHERE ISNULL(`FunctionalCI`.`business_criticity`)",
|
||||
'ExpectedCriterion' => array(array('widget' => 'enum', 'has_undefined' => true, 'operator' => 'IN', 'values' => array(array('value' => 'null')))),
|
||||
),
|
||||
'key NOT IN' => array(
|
||||
'OQL' => "SELECT Contact WHERE org_id NOT IN ('1')",
|
||||
'ExpectedOQL' => "SELECT `Contact` FROM Contact AS `Contact` WHERE (`Contact`.`org_id` NOT IN ('1'))",
|
||||
'ExpectedCriterion' => array(array('widget' => 'raw', 'operator' => 'NOT IN')),
|
||||
),
|
||||
'key IN' => array(
|
||||
'OQL' => "SELECT Contact WHERE org_id IN ('1')",
|
||||
'ExpectedOQL' => "SELECT `Contact` FROM Contact AS `Contact` JOIN Organization AS `Organization` ON `Contact`.org_id = `Organization`.id JOIN Organization AS `Organization1` ON `Organization`.parent_id BELOW `Organization1`.id WHERE (`Organization1`.`id` = '1')",
|
||||
'ExpectedCriterion' => array(array('widget' => 'hierarchical_key', 'operator' => 'IN')),
|
||||
),
|
||||
'key IN 2' => array(
|
||||
'OQL' => "SELECT Contact WHERE org_id IN ('1', '999999')",
|
||||
'ExpectedOQL' => "SELECT `Contact` FROM Contact AS `Contact` JOIN Organization AS `Organization` ON `Contact`.org_id = `Organization`.id JOIN Organization AS `Organization1` ON `Organization`.parent_id BELOW `Organization1`.id WHERE (`Organization1`.`id` = '1')",
|
||||
'ExpectedCriterion' => array(array('widget' => 'hierarchical_key', 'operator' => 'IN')),
|
||||
),
|
||||
'key empty' => array(
|
||||
'OQL' => "SELECT Person WHERE location_id = '0'",
|
||||
'ExpectedOQL' => "SELECT `Person` FROM Person AS `Person` WHERE (`Person`.`location_id` = '0')",
|
||||
'ExpectedCriterion' => array(array('widget' => 'external_key', 'operator' => 'IN', 'values' => array(array('value' => '0')))),
|
||||
),
|
||||
'Double field' => array(
|
||||
'OQL' => "SELECT UserRequest AS u WHERE u.close_date > u.start_date",
|
||||
'ExpectedOQL' => "SELECT `u` FROM UserRequest AS `u` WHERE (`u`.`close_date` > `u`.`start_date`)",
|
||||
'ExpectedCriterion' => array(array('widget' => 'raw')),
|
||||
),
|
||||
'Num between 1' => array(
|
||||
'OQL' => "SELECT Server WHERE nb_u >= 0 AND 1 >= nb_u",
|
||||
'ExpectedOQL' => "SELECT `Server` FROM Server AS `Server` WHERE ((`Server`.`nb_u` >= '0') AND (`Server`.`nb_u` <= '1'))",
|
||||
'ExpectedCriterion' => array(array('widget' => 'numeric', 'operator' => 'between')),
|
||||
),
|
||||
'Num ISNULL' => array(
|
||||
'OQL' => "SELECT Server WHERE ISNULL(nb_u)",
|
||||
'ExpectedOQL' => "SELECT `Server` FROM Server AS `Server` WHERE ISNULL(`Server`.`nb_u`)",
|
||||
'ExpectedCriterion' => array(array('widget' => 'numeric', 'operator' => 'empty')),
|
||||
),
|
||||
'Hierarchical below 1' => array(
|
||||
'OQL' => "SELECT Person AS P JOIN Organization AS Node ON P.org_id = Node.id JOIN Organization AS Root ON Node.parent_id BELOW Root.id WHERE Root.id=1",
|
||||
'ExpectedOQL' => "SELECT `P` FROM Person AS `P` JOIN Organization AS `Node` ON `P`.org_id = `Node`.id JOIN Organization AS `Root` ON `Node`.parent_id BELOW `Root`.id WHERE (`Root`.`id` = '1')",
|
||||
'ExpectedCriterion' => array(array('widget' => 'hierarchical_key')),
|
||||
),
|
||||
'Hierarchical below 2' => array(
|
||||
'OQL' => "SELECT `Organization` FROM Organization AS `Organization` JOIN Organization AS `Organization1` ON `Organization`.parent_id = `Organization1`.id JOIN Organization AS `Organization11` ON `Organization1`.parent_id BELOW `Organization11`.id WHERE (((`Organization11`.`id` IN ('1', '2')) OR (`Organization`.`parent_id` = '0')) AND 1)",
|
||||
'ExpectedOQL' => "SELECT `Organization` FROM Organization AS `Organization` JOIN Organization AS `Organization1` ON `Organization`.parent_id = `Organization1`.id JOIN Organization AS `Organization11` ON `Organization1`.parent_id BELOW `Organization11`.id WHERE (((`Organization11`.`id` IN ('1', '2')) OR (`Organization`.`parent_id` = '0')) AND 1)",
|
||||
'ExpectedCriterion' => array(array('widget' => 'hierarchical_key')),
|
||||
),
|
||||
'IP range' => array(
|
||||
'OQL' => "SELECT DatacenterDevice AS dev WHERE INET_ATON(dev.managementip) > INET_ATON('10.22.32.224') AND INET_ATON(dev.managementip) < INET_ATON('10.22.32.255')",
|
||||
'ExpectedOQL' => "SELECT `dev` FROM DatacenterDevice AS `dev` WHERE ((INET_ATON(`dev`.`managementip`) < INET_ATON('10.22.32.255')) AND (INET_ATON(`dev`.`managementip`) > INET_ATON('10.22.32.224')))",
|
||||
'ExpectedCriterion' => array(array('widget' => 'raw')),
|
||||
),
|
||||
'TagSet Matches' => array(
|
||||
'OQL' => "SELECT ".TAG_CLASS." WHERE ".TAG_ATTCODE." MATCHES 'tag1'",
|
||||
'ExpectedOQL' => "SELECT `".TAG_CLASS."` FROM ".TAG_CLASS." AS `".TAG_CLASS."` WHERE `".TAG_CLASS."`.`".TAG_ATTCODE.'` MATCHES \'tag1 _\'',
|
||||
'ExpectedCriterion' => array(array('widget' => 'tag_set')),
|
||||
),
|
||||
'TagSet Matches2' => array(
|
||||
'OQL' => "SELECT ".TAG_CLASS." WHERE ".TAG_ATTCODE." MATCHES 'tag1 tag2'",
|
||||
'ExpectedOQL' => "SELECT `".TAG_CLASS."` FROM ".TAG_CLASS." AS `".TAG_CLASS."` WHERE `".TAG_CLASS."`.`".TAG_ATTCODE.'` MATCHES \'tag1 tag2 _\'',
|
||||
'ExpectedCriterion' => array(array('widget' => 'tag_set')),
|
||||
),
|
||||
'TagSet Undefined' => array(
|
||||
'OQL' => "SELECT ".TAG_CLASS." WHERE ".TAG_ATTCODE." = ''",
|
||||
'ExpectedOQL' => "SELECT `".TAG_CLASS."` FROM ".TAG_CLASS." AS `".TAG_CLASS."` WHERE (`".TAG_CLASS."`.`".TAG_ATTCODE."` = '')",
|
||||
'ExpectedCriterion' => array(array('widget' => 'tag_set')),
|
||||
),
|
||||
'TagSet Undefined and tag' => array(
|
||||
'OQL' => "SELECT ".TAG_CLASS." WHERE (((".TAG_ATTCODE." MATCHES 'tag1 tag2') OR (".TAG_ATTCODE." = '')) AND 1)",
|
||||
'ExpectedOQL' => "SELECT `".TAG_CLASS."` FROM ".TAG_CLASS." AS `".TAG_CLASS."` WHERE ((`".TAG_CLASS."`.`".TAG_ATTCODE.'` MATCHES \'tag1 tag2 _\' OR (`'.TAG_CLASS."`.`".TAG_ATTCODE."` = '')) AND 1)",
|
||||
'ExpectedCriterion' => array(array('widget' => 'tag_set')),
|
||||
),
|
||||
'TagSet equals' => array(
|
||||
'OQL' => "SELECT ".TAG_CLASS." WHERE ".TAG_ATTCODE." = 'tag1 tag2'",
|
||||
'ExpectedOQL' => "SELECT `".TAG_CLASS."` FROM ".TAG_CLASS." AS `".TAG_CLASS."` WHERE (`".TAG_CLASS."`.`".TAG_ATTCODE.'` MATCHES \'tag1 _\' AND `'.TAG_CLASS."`.`".TAG_ATTCODE.'` MATCHES \'tag2 _\')',
|
||||
'ExpectedCriterion' => array(array('widget' => 'tag_set')),
|
||||
),
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider OqlProviderDates
|
||||
*
|
||||
* @param $sOQL
|
||||
*
|
||||
* @param $sExpectedOQL
|
||||
*
|
||||
* @param $aExpectedCriterion
|
||||
*
|
||||
* @throws \DictExceptionUnknownLanguage
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \OQLException
|
||||
* @throws \CoreException
|
||||
*/
|
||||
function testOqlToForSearchToOqlAltLanguageFR($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");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @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(
|
||||
|
||||
'Date relative 1' => array(
|
||||
'OQL' => "SELECT UserRequest WHERE DATE_SUB(NOW(), INTERVAL 14 DAY) < start_date",
|
||||
'ExpectedOQL' => "SELECT `UserRequest` FROM UserRequest AS `UserRequest` WHERE (DATE_SUB(NOW(), INTERVAL 14 DAY) < `UserRequest`.`start_date`)",
|
||||
'ExpectedCriterion' => array(array('widget' => 'raw')),
|
||||
),
|
||||
'Date relative 2' => array(
|
||||
'OQL' => "SELECT Contract AS c WHERE c.end_date > NOW() AND c.end_date < DATE_ADD(NOW(), INTERVAL 30 DAY)",
|
||||
'ExpectedOQL' => "SELECT `c` FROM Contract AS `c` WHERE ((`c`.`end_date` < DATE_ADD(NOW(), INTERVAL 30 DAY)) AND (`c`.`end_date` > NOW()))",
|
||||
'ExpectedCriterion' => array(array('widget' => 'raw'), array('widget' => 'raw')),
|
||||
),
|
||||
'Date relative 3' => array(
|
||||
'OQL' => "SELECT UserRequest AS u WHERE u.close_date > DATE_ADD(u.start_date, INTERVAL 8 HOUR)",
|
||||
'ExpectedOQL' => "SELECT `u` FROM UserRequest AS `u` WHERE (`u`.`close_date` > DATE_ADD(`u`.`start_date`, INTERVAL 8 HOUR))",
|
||||
'ExpectedCriterion' => array(),
|
||||
),
|
||||
'Date relative 4' => array(
|
||||
'OQL' => "SELECT UserRequest AS u WHERE u.start_date < DATE_SUB(NOW(), INTERVAL 60 MINUTE) AND u.status = 'new'",
|
||||
'ExpectedOQL' => "SELECT `u` FROM UserRequest AS `u` WHERE ((`u`.`start_date` < DATE_SUB(NOW(), INTERVAL 60 MINUTE)) AND (`u`.`status` = 'new'))",
|
||||
'ExpectedCriterion' => array(array('widget' => 'raw')),
|
||||
),
|
||||
'Date between 1' => array(
|
||||
'OQL' => "SELECT UserRequest WHERE start_date > '2017-01-01 00:00:00' AND '2018-01-01 00:00:00' >= start_date",
|
||||
'ExpectedOQL' => "SELECT `UserRequest` FROM UserRequest AS `UserRequest` WHERE ((`UserRequest`.`start_date` >= '2017-01-01 00:00:01') AND (`UserRequest`.`start_date` <= '2018-01-01 00:00:00'))",
|
||||
'ExpectedCriterion' => array(array('widget' => 'date_time', 'operator' => 'between_dates')),
|
||||
),
|
||||
'Date between 2' => array(
|
||||
'OQL' => "SELECT UserRequest WHERE start_date > '2017-01-01 00:00:00' AND status = 'active' AND org_id = 3 AND '2018-01-01 00:00:00' >= start_date",
|
||||
'ExpectedOQL' => "SELECT `UserRequest` FROM UserRequest AS `UserRequest` JOIN Organization AS `Organization` ON `UserRequest`.org_id = `Organization`.id JOIN Organization AS `Organization1` ON `Organization`.parent_id BELOW `Organization1`.id WHERE ((((`Organization1`.`id` = '3') AND (`UserRequest`.`start_date` >= '2017-01-01 00:00:01')) AND (`UserRequest`.`start_date` <= '2018-01-01 00:00:00')) AND (`UserRequest`.`status` = 'active'))",
|
||||
'ExpectedCriterion' => array(array('widget' => 'hierarchical_key', 'operator' => 'IN'), array('widget' => 'date_time', 'operator' => 'between_dates'), array('widget' => 'enum', 'operator' => 'IN')),
|
||||
),
|
||||
'Date between 3' => array(
|
||||
'OQL' => "SELECT UserRequest WHERE start_date >= '2017-01-01 00:00:00' AND '2017-01-01 00:00:00' >= start_date",
|
||||
'ExpectedOQL' => "SELECT `UserRequest` FROM UserRequest AS `UserRequest` WHERE ((`UserRequest`.`start_date` >= '2017-01-01 00:00:00') AND (`UserRequest`.`start_date` <= '2017-01-01 00:00:00'))",
|
||||
'ExpectedCriterion' => array(array('widget' => 'date_time', 'operator' => 'between_dates')),
|
||||
),
|
||||
'Date between 4' => array(
|
||||
'OQL' => "SELECT UserRequest WHERE start_date >= '2017-01-01 00:00:00' AND '2017-01-01 01:00:00' > start_date",
|
||||
'ExpectedOQL' => "SELECT `UserRequest` FROM UserRequest AS `UserRequest` WHERE ((`UserRequest`.`start_date` >= '2017-01-01 00:00:00') AND (`UserRequest`.`start_date` <= '2017-01-01 00:59:59'))",
|
||||
'ExpectedCriterion' => array(array('widget' => 'date_time', 'operator' => 'between_dates')),
|
||||
),
|
||||
'Date between 5' => array(
|
||||
'OQL' => "SELECT UserRequest WHERE start_date >= '2017-01-01 00:00:00' AND '2017-01-02 00:00:00' > start_date",
|
||||
'ExpectedOQL' => "SELECT `UserRequest` FROM UserRequest AS `UserRequest` WHERE ((`UserRequest`.`start_date` >= '2017-01-01 00:00:00') AND (`UserRequest`.`start_date` <= '2017-01-01 23:59:59'))",
|
||||
'ExpectedCriterion' => array(array('widget' => 'date_time', 'operator' => 'between_dates')),
|
||||
),
|
||||
'Date between 6' => array(
|
||||
'OQL' => "SELECT UserRequest WHERE start_date >= '2017-01-01' AND '2017-01-02' >= start_date",
|
||||
'ExpectedOQL' => "SELECT `UserRequest` FROM UserRequest AS `UserRequest` WHERE ((`UserRequest`.`start_date` >= '2017-01-01 00:00:00') AND (`UserRequest`.`start_date` <= '2017-01-02 00:00:00'))",
|
||||
'ExpectedCriterion' => array(array('widget' => 'date_time', 'operator' => 'between_dates')),
|
||||
),
|
||||
'Date between 7' => array(
|
||||
'OQL' => "SELECT CustomerContract WHERE ((start_date >= '2018-03-01') AND (start_date < '2018-04-01'))",
|
||||
'ExpectedOQL' => "SELECT `CustomerContract` FROM CustomerContract AS `CustomerContract` WHERE ((`CustomerContract`.`start_date` >= '2018-03-01') AND (`CustomerContract`.`start_date` <= '2018-03-31'))",
|
||||
'ExpectedCriterion' => array(array('widget' => 'date', 'operator' => 'between_dates')),
|
||||
),
|
||||
'Date =' => array(
|
||||
'OQL' => "SELECT CustomerContract WHERE (start_date = '2018-03-01')",
|
||||
'ExpectedOQL' => "SELECT `CustomerContract` FROM CustomerContract AS `CustomerContract` WHERE ((`CustomerContract`.`start_date` >= '2018-03-01') AND (`CustomerContract`.`start_date` <= '2018-03-01'))",
|
||||
'ExpectedCriterion' => array(array('widget' => 'date', 'operator' => 'between_dates')),
|
||||
),
|
||||
'Date =2' => array(
|
||||
'OQL' => "SELECT UserRequest WHERE (DATE_FORMAT(start_date, '%Y-%m-%d') = '2018-03-21')",
|
||||
'ExpectedOQL' => "SELECT `UserRequest` FROM UserRequest AS `UserRequest` WHERE ((`UserRequest`.`start_date` >= '2018-03-21 00:00:00') AND (`UserRequest`.`start_date` <= '2018-03-21 23:59:59'))",
|
||||
'ExpectedCriterion' => array(array('widget' => 'date_time', 'operator' => 'between_dates')),
|
||||
),
|
||||
'Date =3' => array(
|
||||
'OQL' => "SELECT UserRequest WHERE (DATE_FORMAT(`UserRequest`.`start_date`, '%w') = '4')",
|
||||
'ExpectedOQL' => "SELECT `UserRequest` FROM UserRequest AS `UserRequest` WHERE (DATE_FORMAT(`UserRequest`.`start_date`, '%w') = '4')",
|
||||
'ExpectedCriterion' => array(array('widget' => 'raw')),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param $sOQL
|
||||
*
|
||||
* @param $sExpectedOQL
|
||||
*
|
||||
* @param $aExpectedCriterion
|
||||
*
|
||||
* @param $sLanguageCode
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \DictExceptionUnknownLanguage
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \OQLException
|
||||
*/
|
||||
function OqlToSearchToOqlAltLanguage($sOQL, $sExpectedOQL, $aExpectedCriterion, $sLanguageCode )
|
||||
{
|
||||
$this->debug($sOQL);
|
||||
|
||||
|
||||
Dict::SetUserLanguage($sLanguageCode);
|
||||
|
||||
|
||||
$oSearchForm = new SearchForm();
|
||||
$oSearch = DBSearch::FromOQL($sOQL);
|
||||
$aFields = $oSearchForm->GetFields(new DBObjectSet($oSearch));
|
||||
/** @var \DBObjectSearch $oSearch */
|
||||
$aCriterion = $oSearchForm->GetCriterion($oSearch, $aFields);
|
||||
|
||||
$aAndCriterion = $aCriterion['or'][0]['and'];
|
||||
|
||||
$aNewCriterion = array();
|
||||
foreach($aAndCriterion as $aCriteria)
|
||||
{
|
||||
if ($aCriteria['widget'] != AttributeDefinition::SEARCH_WIDGET_TYPE_RAW)
|
||||
{
|
||||
unset($aCriteria['oql']);
|
||||
foreach($aFields as $aCatFields)
|
||||
{
|
||||
if (isset($aCatFields[$aCriteria['ref']]))
|
||||
{
|
||||
$aField = $aCatFields[$aCriteria['ref']];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isset($aField))
|
||||
{
|
||||
$aCriteria['code'] = $aField['code'];
|
||||
$aCriteria['class'] = $aField['class'];
|
||||
}
|
||||
}
|
||||
|
||||
if ($aCriteria['widget'] == AttributeDefinition::SEARCH_WIDGET_TYPE_DATE_TIME || $aCriteria['widget'] == AttributeDefinition::SEARCH_WIDGET_TYPE_DATE)
|
||||
{
|
||||
$sAttributeClass = ($aCriteria['widget'] == AttributeDefinition::SEARCH_WIDGET_TYPE_DATE_TIME) ? AttributeDateTime::class : AttributeDate::class;
|
||||
|
||||
/** @var \AttributeDateTime $sAttributeClass */
|
||||
/** @var \DateTimeFormat $oFormat */
|
||||
$oFormat = $sAttributeClass::GetFormat();
|
||||
|
||||
foreach($aCriteria['values'] as $i => $aValue)
|
||||
{
|
||||
if (!empty($aValue['value'])) {
|
||||
$aCriteria['values'][$i]['value'] = $oFormat->Format($aValue['value']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$aNewCriterion[] = $aCriteria;
|
||||
}
|
||||
$this->debug($aNewCriterion);
|
||||
|
||||
$this->assertFalse($this->array_diff_assoc_recursive($aExpectedCriterion, $aNewCriterion), 'Criterion array contains critical parts');
|
||||
|
||||
$aCriterion['or'][0]['and'] = $aNewCriterion;
|
||||
|
||||
$oSearch->ResetCondition();
|
||||
$oFilter = CriterionParser::Parse($oSearch->ToOQL(), $aCriterion);
|
||||
|
||||
$sResultOQL = $oFilter->ToOQL();
|
||||
$this->debug($sResultOQL);
|
||||
|
||||
$this->assertEquals($sExpectedOQL, $sResultOQL);
|
||||
}
|
||||
|
||||
|
||||
function array_diff_assoc_recursive($array1, $array2)
|
||||
{
|
||||
foreach($array1 as $key => $value)
|
||||
{
|
||||
if (is_array($value))
|
||||
{
|
||||
if (!isset($array2[$key]))
|
||||
{
|
||||
$difference[$key] = $value;
|
||||
}
|
||||
elseif (!is_array($array2[$key]))
|
||||
{
|
||||
$difference[$key] = $value;
|
||||
}
|
||||
else
|
||||
{
|
||||
$new_diff = $this->array_diff_assoc_recursive($value, $array2[$key]);
|
||||
if ($new_diff !== false)
|
||||
{
|
||||
$difference[$key] = $new_diff;
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif (!array_key_exists($key, $array2) || $array2[$key] != $value)
|
||||
{
|
||||
$difference[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return !isset($difference) ? false : $difference;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2010-2018 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/>
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Eric
|
||||
* Date: 08/03/2018
|
||||
* Time: 11:28
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Application\Search;
|
||||
|
||||
use Combodo\iTop\Application\Search\CriterionParser;
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class CriterionParserTest extends ItopDataTestCase
|
||||
{
|
||||
public function testParse()
|
||||
{
|
||||
$sBaseOql = 'SELECT UserRequest';
|
||||
$aCriterion = json_decode('{
|
||||
"or": [
|
||||
{
|
||||
"and": [
|
||||
{
|
||||
"ref": "UserRequest.start_date",
|
||||
"values": [
|
||||
{
|
||||
"value": "2017-01-01",
|
||||
"label": "2017-01-01 00:00:00"
|
||||
}
|
||||
],
|
||||
"operator": ">",
|
||||
"oql": ""
|
||||
},
|
||||
{
|
||||
"ref": "UserRequest.start_date",
|
||||
"values": [
|
||||
{
|
||||
"value": "2018-01-01",
|
||||
"label": "2018-01-01 00:00:00"
|
||||
}
|
||||
],
|
||||
"operator": "<",
|
||||
"oql": "(`UserRequest`.`start_date` < \'2018-01-01\')"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
', true);
|
||||
$oSearch = CriterionParser::Parse($sBaseOql, $aCriterion);
|
||||
|
||||
//$this->debug($oSearch);
|
||||
|
||||
$this->assertEquals("SELECT `UserRequest` FROM UserRequest AS `UserRequest` WHERE ((`UserRequest`.`start_date` > '2017-01-01') AND (`UserRequest`.`start_date` < '2018-01-01'))", $oSearch->ToOQL());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2010-2018 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/>
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Application\Search;
|
||||
|
||||
use Combodo\iTop\Application\Search\SearchForm;
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use DBObjectSearch;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class SearchFormTest extends ItopDataTestCase
|
||||
{
|
||||
const CREATE_TEST_ORG = true;
|
||||
|
||||
/**
|
||||
* @dataProvider GetFieldsProvider
|
||||
* @throws \OQLException
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function testGetFields($sOQL)
|
||||
{
|
||||
$oSearchForm = new SearchForm();
|
||||
$oSearch = \DBSearch::FromOQL($sOQL);
|
||||
$aFields = $oSearchForm->GetFields(new \DBObjectSet($oSearch));
|
||||
$this->debug($sOQL);
|
||||
$this->debug(json_encode($aFields, JSON_PRETTY_PRINT));
|
||||
$this->assertTrue(count($aFields['zlist']) > 0);
|
||||
$this->assertTrue(count($aFields['others']) > 0);
|
||||
}
|
||||
|
||||
public function GetFieldsProvider()
|
||||
{
|
||||
return array(
|
||||
array("SELECT Contact"),
|
||||
array("SELECT Contact AS C WHERE C.status = 'active'"),
|
||||
array("SELECT Person"),
|
||||
array(
|
||||
"SELECT Person AS p JOIN UserRequest AS u ON u.agent_id = p.id WHERE u.status != 'closed'",
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @dataProvider GetCriterionProvider
|
||||
*
|
||||
* @param $sOQL
|
||||
* @param $iOrCount
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \MissingQueryArgument
|
||||
*/
|
||||
public function testGetCriterion($sOQL, $iOrCount)
|
||||
{
|
||||
$oSearchForm = new SearchForm();
|
||||
try
|
||||
{
|
||||
$oSearch = \DBSearch::FromOQL($sOQL);
|
||||
$aFields = $oSearchForm->GetFields(new \DBObjectSet($oSearch));
|
||||
/** @var DBObjectSearch $oSearch */
|
||||
$aCriterion = $oSearchForm->GetCriterion($oSearch, $aFields);
|
||||
} catch (\OQLException $e)
|
||||
{
|
||||
$this->assertTrue(false);
|
||||
|
||||
return;
|
||||
}
|
||||
$aRes = array('base_oql' => $sOQL, 'criterion' => $aCriterion);
|
||||
$this->debug(json_encode($aRes));
|
||||
$this->debug($sOQL);
|
||||
$this->debug(json_encode($aCriterion, JSON_PRETTY_PRINT));
|
||||
$this->assertCount($iOrCount, $aCriterion['or']);
|
||||
}
|
||||
|
||||
public function GetCriterionProvider()
|
||||
{
|
||||
return array(
|
||||
array('OQL' => "SELECT Contact", 1),
|
||||
array('OQL' => "SELECT Contact WHERE status = 'active'", 1),
|
||||
array('OQL' => "SELECT Contact AS C WHERE C.status = 'active'", 1),
|
||||
array('OQL' => "SELECT Contact WHERE status = 'active' AND name LIKE 'toto%'", 1),
|
||||
array('OQL' => "SELECT Contact WHERE status = 'active' AND org_id = 3", 1),
|
||||
array('OQL' => "SELECT Contact WHERE status IN ('active', 'inactive')", 1),
|
||||
array('OQL' => "SELECT Contact WHERE status NOT IN ('active')", 1),
|
||||
array('OQL' => "SELECT Contact WHERE status NOT IN ('active', 'inactive')", 1),
|
||||
array('OQL' => "SELECT Contact WHERE status = 'active' OR name LIKE 'toto%'", 2),
|
||||
array('OQL' => "SELECT UserRequest WHERE DATE_SUB(NOW(), INTERVAL 14 DAY) < start_date", 1),
|
||||
array('OQL' => "SELECT UserRequest WHERE start_date > '2017-01-01 00:00:00' AND '2018-01-01 00:00:00' >= start_date", 1),
|
||||
array('OQL' => "SELECT UserRequest WHERE start_date > '2017-01-01 00:00:00' AND status = 'active' AND org_id = 3 AND '2018-01-01 00:00:00' >= start_date", 1),
|
||||
array('OQL' => "SELECT UserRequest WHERE start_date >= '2017-01-01 00:00:00' AND '2017-01-01 00:00:00' >= start_date", 1),
|
||||
array('OQL' => "SELECT UserRequest WHERE start_date >= '2017-01-01 00:00:00' AND '2017-01-01 01:00:00' > start_date", 1),
|
||||
array('OQL' => "SELECT UserRequest WHERE start_date >= '2017-01-01 00:00:00' AND '2017-01-02 00:00:00' > start_date", 1),
|
||||
array(
|
||||
'OQL' => "SELECT FunctionalCI WHERE ((business_criticity IN ('high', 'medium')) OR ISNULL(business_criticity)) AND 1",
|
||||
1
|
||||
),
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
116
tests/php-unit-tests/unitary-tests/status/StatusIncTest.php
Normal file
116
tests/php-unit-tests/unitary-tests/status/StatusIncTest.php
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* User: Guy Couronné (guy.couronne@gmail.com)
|
||||
* Date: 25/01/2019
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Status;
|
||||
|
||||
/**
|
||||
* User: Guy Couronné (guy.couronne@gmail.com)
|
||||
* Date: 25/01/2019
|
||||
*/
|
||||
|
||||
use Config;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use function Combodo\iTop\Application\Status\StatusCheckConfigFile;
|
||||
use function Combodo\iTop\Application\Status\StatusGetAppRoot;
|
||||
use function Combodo\iTop\Application\Status\StatusStartup;
|
||||
|
||||
if (!defined('DEBUG_UNIT_TEST')) {
|
||||
define('DEBUG_UNIT_TEST', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class StatusIncTest extends TestCase {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $sAppRoot = '';
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
//AppRoot is the directory containing the directory
|
||||
//Assume getcwd() is runned inside APPROOT/test
|
||||
$this->sAppRoot = __DIR__.'/../../sources/application/status';
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Exception
|
||||
*/
|
||||
public function testStatusGetAppRootWrongPath() {
|
||||
include_once($this->sAppRoot . '/status.inc.php');
|
||||
|
||||
$sAppRootFilenamewrong = 'approot.inc.php_wrong';
|
||||
|
||||
StatusGetAppRoot($sAppRootFilenamewrong);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function testStatusGetAppRootGood() {
|
||||
include_once($this->sAppRoot . '/status.inc.php');
|
||||
|
||||
StatusGetAppRoot();
|
||||
|
||||
$this->assertNotEmpty(APPROOT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Exception
|
||||
*/
|
||||
public function testStatusCheckConfigFileWrongPath() {
|
||||
include_once($this->sAppRoot . '/status.inc.php');
|
||||
|
||||
$sConfigFilenamewrong = 'config-itop.php_wrong';
|
||||
|
||||
StatusCheckConfigFile($sConfigFilenamewrong);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function testStatusCheckConfigFileGood() {
|
||||
include_once($this->sAppRoot . '/status.inc.php');
|
||||
|
||||
StatusCheckConfigFile();
|
||||
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \MySQLException
|
||||
*/
|
||||
public function testStatusStartupWrongDbPwd() {
|
||||
include_once($this->sAppRoot . '/status.inc.php');
|
||||
|
||||
StatusCheckConfigFile();
|
||||
require_once(APPROOT . '/core/cmdbobject.class.inc.php');
|
||||
require_once(APPROOT . '/application/utils.inc.php');
|
||||
require_once(APPROOT . '/core/contexttag.class.inc.php');
|
||||
|
||||
$oConfigWrong = new Config(ITOP_DEFAULT_CONFIG_FILE);
|
||||
$oConfigWrong->Set('db_pwd', $oConfigWrong->Get('db_pwd') . '_unittest');
|
||||
|
||||
StatusStartup($oConfigWrong);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function testStatusStartupGood() {
|
||||
include_once($this->sAppRoot . '/status.inc.php');
|
||||
|
||||
StatusStartup();
|
||||
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user