mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-13 07:24:13 +01:00
225 lines
8.4 KiB
PHP
225 lines
8.4 KiB
PHP
<?php
|
|
|
|
namespace Combodo\iTop\Test\UnitTest\Core;
|
|
|
|
use CMDBSource;
|
|
use Combodo\iTop\Core\DbConnectionWrapper;
|
|
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
|
use Exception;
|
|
use IssueLog;
|
|
use LogChannels;
|
|
use utils;
|
|
|
|
/**
|
|
* @since 2.7.0
|
|
*
|
|
* @package Combodo\iTop\Test\UnitTest\Core
|
|
*/
|
|
|
|
class CMDBSourceTest extends ItopTestCase
|
|
{
|
|
protected function setUp(): void
|
|
{
|
|
|
|
parent::setUp();
|
|
$this->RequireOnceItopFile('/core/cmdbsource.class.inc.php');
|
|
}
|
|
|
|
protected function tearDown(): void
|
|
{
|
|
DbConnectionWrapper::SetDbConnectionMockForQuery();
|
|
|
|
parent::tearDown();
|
|
}
|
|
|
|
/**
|
|
* @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 [
|
|
'same datetime types' => [true, 'DATETIME', 'DATETIME'],
|
|
'different types' => [false, 'VARCHAR(255)', 'INT(11)'],
|
|
'different types, same type options' => [false, 'VARCHAR(11)', 'INT(11)'],
|
|
'same int declaration, same case' => [true, 'INT(11)', 'INT(11)'],
|
|
'same int declaration, different case on data type' => [true, 'INT(11)', 'int(11)'],
|
|
'same enum declaration, same case' => [
|
|
true,
|
|
"ENUM('error','idle','planned','running')",
|
|
"ENUM('error','idle','planned','running')",
|
|
],
|
|
'same enum declaration, different case on data type' => [
|
|
true,
|
|
"ENUM('error','idle','planned','running')",
|
|
"enum('error','idle','planned','running')",
|
|
],
|
|
'same enum declaration, different case on type options' => [
|
|
false,
|
|
"ENUM('ERROR','IDLE','planned','running')",
|
|
"ENUM('error','idle','planned','running')",
|
|
],
|
|
'same enum declaration, different case on both data type and type options' => [
|
|
false,
|
|
"ENUM('ERROR','IDLE','planned','running')",
|
|
"enum('error','idle','planned','running')",
|
|
],
|
|
'MariaDB 10.2 nullable datetime' => [
|
|
true,
|
|
'DATETIME',
|
|
"datetime DEFAULT 'NULL'",
|
|
],
|
|
'MariaDB 10.2 nullable text' => [
|
|
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' => [
|
|
true,
|
|
'INT(11) UNSIGNED',
|
|
"int(11) unsigned DEFAULT 'NULL'",
|
|
],
|
|
'MariaDB 10.2 varchar with default value' => [
|
|
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' => [
|
|
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' => [
|
|
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' => [
|
|
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' => [
|
|
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' => [
|
|
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
|
|
*
|
|
* @runInSeparateProcess Resetting DB connection, thus making other tests to fail!
|
|
*/
|
|
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
|
|
DbConnectionWrapper::SetDbConnection(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);
|
|
}
|
|
|
|
/**
|
|
* @dataProvider InitServerAndPortProvider
|
|
* @since 2.7.10 3.0.4 3.1.2 3.2.0 N°6889 method creation to keep track of the behavior change (port will return null)
|
|
*/
|
|
public function testInitServerAndPort(string $sDbHost, string $sExpectedServer, ?int $iExpectedPort)
|
|
{
|
|
$sActualServer = null;
|
|
$iActualPort = null;
|
|
CMDBSource::InitServerAndPort($sDbHost, $sActualServer, $iActualPort);
|
|
|
|
$this->assertNotNull($sActualServer);
|
|
$this->assertEquals($sExpectedServer, $sActualServer);
|
|
$this->assertEquals($iExpectedPort, $iActualPort);
|
|
}
|
|
|
|
public function InitServerAndPortProvider()
|
|
{
|
|
return [
|
|
'localhost no port' => ['localhost', 'localhost', null],
|
|
'localhost with port' => ['localhost:333306', 'localhost', 333306],
|
|
'persistent localhost no port' => ['p:localhost', 'p:localhost', null],
|
|
'persistent localhost with port' => ['p:localhost:333306', 'p:localhost', 333306],
|
|
'ip no port' => ['192.168.1.10', '192.168.1.10', null],
|
|
'ip with port' => ['192.168.1.10:333306', '192.168.1.10', 333306],
|
|
'persistent ip no port' => ['p:192.168.1.10', 'p:192.168.1.10', null],
|
|
'persistent ip with port' => ['p:192.168.1.10:333306', 'p:192.168.1.10', 333306],
|
|
'domain no port' => ['dbserver.mycompany.com', 'dbserver.mycompany.com', null],
|
|
'domain with port' => ['dbserver.mycompany.com:333306', 'dbserver.mycompany.com', 333306],
|
|
'persistent domain no port' => ['p:dbserver.mycompany.com', 'p:dbserver.mycompany.com', null],
|
|
'persistent domain with port' => ['p:dbserver.mycompany.com:333306', 'p:dbserver.mycompany.com', 333306],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @since 2.7.10 3.0.4 3.1.1 3.2.0 N°6643 Checks writing in IssueLog is really done
|
|
*/
|
|
public function testLogDeadLock(): void
|
|
{
|
|
$sExceptionMessage = 'Test exception for deadlock';
|
|
$oDeadlockException = new Exception($sExceptionMessage);
|
|
|
|
// \CMDBSource::LogDeadLock uses mysqli::errno and mysqli::query()
|
|
// I didn't achieve mocking the errno property by either of the following means :
|
|
// - PHPUnit mock => property is read only error
|
|
// - DbConnectionWrapper::SetDbConnectionMockForQuery with a custom mysqli children
|
|
// - override of errno property with an assignment (public $errno = ...;) => property is read only error
|
|
// - override of __get() for the errno property => no error but no change
|
|
// Solution for errno was to add a new parameter to disable errno read :/
|
|
/** @noinspection PhpDeprecationInspection */
|
|
$oMockMysqli = $this->getMockBuilder('mysqli')
|
|
->setMethods(['query'])
|
|
->getMock();
|
|
$oMockMysqli->expects($this->any())
|
|
->method('query')
|
|
->willReturnCallback(function () {
|
|
return false;
|
|
});
|
|
DbConnectionWrapper::SetDbConnectionMockForQuery($oMockMysqli);
|
|
|
|
$sTestErrorLogPath = APPROOT.'log/error.phpunit.log';
|
|
IssueLog::Enable($sTestErrorLogPath);
|
|
try {
|
|
$this->InvokeNonPublicStaticMethod(CMDBSource::class, 'LogDeadLock', [$oDeadlockException, true, false]);
|
|
$sLastErrorLogLine = $this->GetErrorLogLastLines($sTestErrorLogPath, 10); // we are getting multiple lines as the context log introduced multiple lines per log
|
|
$this->assertStringContainsString(LogChannels::DEADLOCK, $sLastErrorLogLine);
|
|
$this->assertStringContainsString($sExceptionMessage, $sLastErrorLogLine);
|
|
} finally {
|
|
if (file_exists($sTestErrorLogPath)) {
|
|
unlink($sTestErrorLogPath);
|
|
}
|
|
}
|
|
}
|
|
|
|
private function GetErrorLogLastLines(string $sErrorLogPath, int $iLineNumbers = 1): string
|
|
{
|
|
return trim(implode("", array_slice(file($sErrorLogPath), -$iLineNumbers)));
|
|
}
|
|
}
|