Merge branch 'support/3.1' into support/3.2

# Conflicts:
#	tests/php-unit-tests/src/Hook/TestsRunStartHook.php
This commit is contained in:
Romain Quetiez
2024-05-16 19:05:03 +02:00
9 changed files with 183 additions and 241 deletions

View File

@@ -7,7 +7,6 @@
namespace Combodo\iTop\Test\UnitTest;
use CMDBSource;
use Combodo\iTop\Test\UnitTest\Hook\TestsRunStartHook;
use Combodo\iTop\Test\UnitTest\Service\UnitTestRunTimeEnvironment;
use Config;
use Exception;
@@ -30,9 +29,9 @@ use utils;
abstract class ItopCustomDatamodelTestCase extends ItopDataTestCase
{
/**
* @var bool[]
*/
protected static $aReadyCustomEnvironments = [];
* @var UnitTestRunTimeEnvironment
*/
protected $oEnvironment = null;
/**
* @inheritDoc
@@ -50,11 +49,19 @@ abstract class ItopCustomDatamodelTestCase extends ItopDataTestCase
$this->setRunClassInSeparateProcess(true);
}
/**
/**
* @return string Abs path to the XML delta to use for the tests of that class
*/
abstract public function GetDatamodelDeltaAbsPath(): string;
protected function setUp(): void
{
static::LoadRequiredItopFiles();
$this->oEnvironment = new UnitTestRunTimeEnvironment('production', $this->GetTestEnvironment());
parent::setUp();
}
/**
* @inheritDoc
*/
@@ -92,40 +99,16 @@ abstract class ItopCustomDatamodelTestCase extends ItopDataTestCase
}
/**
* Mark {@see \Combodo\iTop\Test\UnitTest\ItopDataTestCase::GetTestEnvironment()} as ready (compiled)
*
* @return void
*/
private function MarkEnvironmentReady(): void
{
if (false === $this->IsEnvironmentReady()) {
touch(static::GetTestEnvironmentFolderAbsPath());
}
}
/**
* @return bool True if the {@see \Combodo\iTop\Test\UnitTest\ItopDataTestCase::GetTestEnvironment()} is ready (compiled, but not started)
*
* @details Having the environment ready means that it has been compiled for this global tests run, not that it is a relic from a previous global tests run
* @return bool True if the {@see \Combodo\iTop\Test\UnitTest\ItopDataTestCase::GetTestEnvironment()} is ready (compiled, up-to-date, but not necessarily started)
*/
final protected function IsEnvironmentReady(): bool
{
// As these test cases run in separate processes, the best way we found to let know a process if its environment was already prepared for **this run** was to compare the modification times of:
// - its own env-<ENV> folder
// - a file generated at the beginning of the global test run {@see \Combodo\iTop\Test\UnitTest\Hook\TestsRunStartHook}
$sRunStartedFilePath = TestsRunStartHook::GetRunStartedFileAbsPath();
$sEnvFolderPath = static::GetTestEnvironmentFolderAbsPath();
clearstatcache();
if (false === file_exists($sRunStartedFilePath) || false === file_exists($sEnvFolderPath)) {
if (false === file_exists($this->GetTestEnvironmentFolderAbsPath())) {
return false;
}
$iRunStartedFileModificationTime = filemtime($sRunStartedFilePath);
$iEnvFolderModificationTime = filemtime($sEnvFolderPath);
return $iEnvFolderModificationTime >= $iRunStartedFileModificationTime;
}
return $this->oEnvironment->IsUpToDate();
}
/**
* @inheritDoc
@@ -140,6 +123,12 @@ abstract class ItopCustomDatamodelTestCase extends ItopDataTestCase
// Note: To improve performances, we compile all XML deltas from test cases derived from this class and make a single environment where everything will be ran at once.
// This requires XML deltas to be compatible, but it is a known and accepted trade-off. See PR #457
if (false === $this->IsEnvironmentReady()) {
$this->debug("Preparing custom environment '$sTestEnv' with the following datamodel files:");
foreach ($this->oEnvironment->GetCustomDatamodelFiles() as $sCustomDatamodelFile) {
$this->debug(" - $sCustomDatamodelFile");
}
//----------------------------------------------------
// Clear any previous "$sTestEnv" environment
//----------------------------------------------------
@@ -152,14 +141,6 @@ abstract class ItopCustomDatamodelTestCase extends ItopDataTestCase
SetupUtils::tidydir($sConfFolder);
}
// - Datamodel delta files
// - Cache folder
// - Compiled folder
// We don't need to clean them as they are already by the compilation
// - Drop database
// We don't do that now, it will be done before re-creating the DB, once the metamodel is started
//----------------------------------------------------
// Prepare "$sTestEnv" environment
//----------------------------------------------------
@@ -178,7 +159,7 @@ abstract class ItopCustomDatamodelTestCase extends ItopDataTestCase
$oTestConfig->Set('db_name', $oTestConfig->Get('db_name').'_'.$sTestEnvSanitizedForDBName);
// - Compile env. based on the existing 'production' env.
$oEnvironment = new UnitTestRunTimeEnvironment($sTestEnv);
$oEnvironment = new UnitTestRunTimeEnvironment($sSourceEnv, $sTestEnv);
$oEnvironment->WriteConfigFileSafe($oTestConfig);
$oEnvironment->CompileFrom($sSourceEnv);
@@ -192,8 +173,7 @@ abstract class ItopCustomDatamodelTestCase extends ItopDataTestCase
// N°7446 For some reason we need to create the DB schema before starting the MM, then only we can create the tables.
MetaModel::DBCreate();
$this->MarkEnvironmentReady();
$this->debug('Preparation of custom environment "'.$sTestEnv.'" done.');
$this->debug("Custom environment '$sTestEnv' is ready!");
}
parent::PrepareEnvironment();

View File

@@ -50,7 +50,7 @@ abstract class ItopTestCase extends TestCase
static::$DEBUG_UNIT_TEST = getenv('DEBUG_UNIT_TEST');
require_once static::GetAppRoot() . 'approot.inc.php';
require_once __DIR__.'/../../../../approot.inc.php';
if ((static::DISABLE_DEPRECATEDCALLSLOG_ERRORHANDLER)
&& (false === defined(ITOP_PHPUNIT_RUNNING_CONSTANT_NAME))) {
@@ -78,6 +78,7 @@ abstract class ItopTestCase extends TestCase
}
}
/**
* @param array $args
* @param string $sExportFileName relative to log folder
@@ -93,43 +94,41 @@ abstract class ItopTestCase extends TestCase
* @return string
* @throws \ReflectionException
*/
public static function ExportFunctionParameterValues(array $args, string $sExportFileName, array $aExcludedParams = []): string
{
public static function ExportFunctionParameterValues(array $args, string $sExportFileName, array $aExcludedParams = []): string
{
// get sclass et function dans la callstrack
// in the callstack get the call function name
$aCallStack = debug_backtrace();
$sCallFunction = $aCallStack[1]['function'];
// in the casll stack get the call class name
$sCallClass = $aCallStack[1]['class'];
$reflectionFunc = new ReflectionMethod($sCallClass, $sCallFunction);
$parameters = $reflectionFunc->getParameters();
// in the callstack get the call function name
$aCallStack = debug_backtrace();
$sCallFunction = $aCallStack[1]['function'];
// in the casll stack get the call class name
$sCallClass = $aCallStack[1]['class'];
$reflectionFunc = new ReflectionMethod($sCallClass, $sCallFunction);
$parameters = $reflectionFunc->getParameters();
$aParamValues = [];
foreach ($parameters as $index => $param) {
$aParamValues[$param->getName()] = $args[$index] ?? null;
}
$aParamValues = [];
foreach ($parameters as $index => $param) {
$aParamValues[$param->getName()] = $args[$index] ?? null;
}
$paramValues = $aParamValues;
foreach ($aExcludedParams as $sExcludedParam) {
unset($paramValues[$sExcludedParam]);
}
$paramValues = $aParamValues;
foreach ($aExcludedParams as $sExcludedParam) {
unset($paramValues[$sExcludedParam]);
}
// extract oPage from the array in parameters and make a foreach on exlucded parameters
foreach ($aExcludedParams as $sExcludedParam) {
unset($paramValues[$sExcludedParam]);
}
// extract oPage from the array in parameters and make a foreach on exlucded parameters
foreach ($aExcludedParams as $sExcludedParam) {
unset($paramValues[$sExcludedParam]);
}
$var_export = var_export($paramValues, true);
file_put_contents(APPROOT.'/log/' .$sExportFileName, $var_export);
$var_export = var_export($paramValues, true);
file_put_contents(APPROOT.'/log/' .$sExportFileName, $var_export);
return $var_export;
}
}
protected function setUp(): void {
protected function setUp(): void {
parent::setUp();
$this->debug("\n----------\n---------- ".$this->getName()."\n----------\n");
$this->LoadRequiredItopFiles();
$this->LoadRequiredTestFiles();
}
@@ -178,8 +177,9 @@ abstract class ItopTestCase extends TestCase
*/
protected function LoadRequiredItopFiles(): void
{
// Empty until we actually need to require some files in the class
}
// At least make sure that the autoloader will be loaded, and that the APPROOT constant is defined
require_once __DIR__.'/../../../../approot.inc.php';
}
/**
* Overload this method to require necessary files through {@see \Combodo\iTop\Test\UnitTest\ItopTestCase::RequireOnceUnitTestFile()}