RequireOnceItopFile('setup/setuputils.class.inc.php'); $this->RequireOnceItopFile('setup/setuppage.class.inc.php'); $this->RequireOnceItopFile('setup/wizardcontroller.class.inc.php'); } protected function tearDown(): void { parent::tearDown(); ModuleDiscovery::ResetCache(); } /** * @dataProvider CheckGraphvizProvider */ public function testCheckGraphviz($sScriptPath, $iSeverity, $sLabel) { /** @var \CheckResult $oCheck */ $aCheck = SetupUtils::CheckGraphviz($sScriptPath); $bLabelFound = false; foreach ($aCheck as $oCheck) { $this->assertGreaterThanOrEqual($iSeverity, $oCheck->iSeverity); if (!$bLabelFound && (empty($sLabel) || strpos($oCheck->sLabel, $sLabel) !== false)) { $bLabelFound = true; } } $this->assertTrue($bLabelFound, "label '$sLabel' not found"); } public function CheckGraphvizProvider() { if (substr(PHP_OS, 0, 3) === 'WIN') { return []; } return [ "bash injection" => [ "touch /tmp/toto", self::WARNING, "could not be executed: Please make sure it is installed and in the path", ], "command ok" => [ "/usr/bin/whereis", self::INFO, "", ], "empty command => dot by default" => [ "", self::INFO, "", ], "command failed" => [ "/bin/ls", self::WARNING, "dot could not be executed (retcode=2): Please make sure it is installed and in the path", ], ]; } /** * @dataProvider HumanReadableSizeProvider */ public function testHumanReadableSize($fBytes, $sExpected) { $sOutput = SetupUtils::HumanReadableSize($fBytes); $this->assertEquals($sExpected, $sOutput); } public function HumanReadableSizeProvider(): array { return [ '10 bytes' => [ 10, '10 bytes', ], '10 kilobytes' => [ 10 * 1024, '10.24 kB', ], '10 megabytes' => [ 10 * 1024 * 1024, '10.49 MB', ], '10 gigabytes' => [ 10 * 1024 * 1024 * 1024, '10.74 GB', ], '10 terabytes' => [ 10 * 1024 * 1024 * 1024 * 1024, '11.00 TB', ], '10 petabytes' => [ 10 * 1024 * 1024 * 1024 * 1024 * 1024, '11.26 PB', ], '10 exabytes' => [ 10 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024, '11.53 EB', ], ]; } /** * @covers SetupUtils::PHP_MIN_VERSION * @covers SetupUtils::PHP_NOT_VALIDATED_VERSION * @covers composer.json * @group composerJson */ public function testPhpMinVersionConsistency() { $sPHPMinVersion = SetupUtils::PHP_MIN_VERSION; $sPHPNotValidatedVersion = SetupUtils::PHP_NOT_VALIDATED_VERSION; // Ensure that not validated version is greater than min. supported version $this->assertTrue(version_compare($sPHPMinVersion, $sPHPNotValidatedVersion, '<'), "SetupUtils::PHP_MIN_VERSION ($sPHPMinVersion) is not strictly lower than SetupUtils::PHP_NOT_VALIDATED_VERSION ($sPHPNotValidatedVersion)"); if (file_exists(APPROOT.'composer.json')) { $oComposerConfig = json_decode(file_get_contents(APPROOT.'composer.json')); // Platform/PHP must be set to the minimum to ensure dependancies are compatible with the min. version $sComposerPlatformPhp = $oComposerConfig->config->platform->php; $this->assertEquals($sPHPMinVersion, $oComposerConfig->config->platform->php, "SetupUtils::PHP_MIN_VERSION ($sPHPMinVersion) is not equals composer.json > config > platform ($sComposerPlatformPhp)"); // Require/PHP must be set to the supported PHP versions range in order to keep our package constraints up-to-date $sComposerRequirePhp = $oComposerConfig->require->php; $this->assertEquals( ">=$sPHPMinVersion <$sPHPNotValidatedVersion", $oComposerConfig->require->php, "SetupUtils::PHP_MIN_VERSION ($sPHPMinVersion) and SetupUtils::PHP_NOT_VALIDATED_VERSION ($sPHPNotValidatedVersion) is not equals composer.json > require > php ($sComposerRequirePhp)" ); } } public function testCheckCliPhpVersionIsOk() { $this->RequireOnceItopFile('/setup/feature_removal/ModelReflectionSerializer.php'); SetupUtils::CheckCliPhpVersionIsOk(ModelReflectionSerializer::ERROR_LABEL); $this->assertTrue(true); } public function CheckOKProvider() { return [ ["7.4 7.2 7.3.33"], ["PHP 7.4.33 (cli) (built: Aug 2 2024 16:22:28) ( NTS )", "7.4.33"], ["PHP 7.4.33 PHP 7.33.22", "7.4.33"], ["version: 7.4.33 stable", "7.4.33"], ]; } /** * @dataProvider CheckOKProvider */ public function testCheckCliPhpVersionFromOutputFail($sOutput, $sFoundVersion = '7.4') { $this->RequireOnceItopFile('/setup/feature_removal/ModelReflectionSerializer.php'); $this->expectException(\CoreException::class); $sDetails = sprintf('The current CLI PHP Version (%s) is lower than the minimum version required to run %s, which is (%s). You may change the CLI PHP executable path by setting the "php_path" config parameter.', $sFoundVersion, ITOP_APPLICATION, SetupUtils::PHP_MIN_VERSION); $this->expectException(\CoreException::class); $this->expectExceptionMessage("Data consistency check failed: $sDetails"); $this->InvokeNonPublicStaticMethod(SetupUtils::class, 'CheckCliPhpVersionFromOutput', [ModelReflectionSerializer::ERROR_LABEL, 'sPHPExec', [$sOutput]]); } public function testCheckCliPhpVersionFromOutputOK() { $sOutput = <<RequireOnceItopFile('/setup/feature_removal/ModelReflectionSerializer.php'); $this->InvokeNonPublicStaticMethod(SetupUtils::class, 'CheckCliPhpVersionFromOutput', [ModelReflectionSerializer::ERROR_LABEL, 'sPHPExec', [$sOutput]]); $this->assertTrue(true); } public function testCheckPhpVersionIsOK() { $aRes = []; $this->InvokeNonPublicStaticMethod(SetupUtils::class, 'CheckPhpVersion', [&$aRes]); $this->ValidateCheckResults([], $aRes); } public function testCheckPhpVersionIsNotValidatedYet() { $aRes = []; $this->InvokeNonPublicStaticMethod(SetupUtils::class, 'CheckPhpVersion', [&$aRes, '100.0']); $expected = [ 'The current PHP Version (100.0) is not yet validated by Combodo. You may experience some incompatibility issues.', ]; $this->ValidateCheckResults($expected, $aRes); } public function testCheckPhpVersionIsNOK() { $aRes = []; $this->InvokeNonPublicStaticMethod(SetupUtils::class, 'CheckPhpVersion', [&$aRes, '1.0']); $expected = [ sprintf('Error: The current PHP Version (1.0) is lower than the minimum version required to run %s, which is (%s)', ITOP_APPLICATION, SetupUtils::PHP_MIN_VERSION), ]; $this->ValidateCheckResults($expected, $aRes); } /** * Bug N°10045 */ public function testAnalyzeInstallationDoesNotAutomaticallySetModulesInProductionModulesVisibilityToFalse() { $this->RequireOnceItopFile('setup/moduleinstallation/AnalyzeInstallation.php'); $this->SetNonPublicProperty(AnalyzeInstallation::GetInstance(), 'aAvailableModules', null); $sRemoteEnv = 'production-temp'; $sExtraDir = \utils::GetDataPath().$sRemoteEnv.'-modules/'; $sExtraModuleName = 'extra-module'; $this->createModule($sExtraDir, $sExtraModuleName, '1.0.0'); $oWizard = new WizardController('WizStepWelcome'); $oWizard->SetParameter('source_dir', APPROOT.'datamodels/2.x'); $oWizard->SetParameter('remote_env', $sRemoteEnv); $aModules = SetupUtils::AnalyzeInstallation($oWizard); $this->assertContains($sExtraModuleName, array_keys($aModules), 'Module discovery should have found the extra module'); $this->assertTrue($aModules[$sExtraModuleName]['visible'], 'AnalyzeInstallation should not have automatically set the extra module visibility to false'); } private function ValidateCheckResults(array $expected, array $aActualCheckResults) { $aActual = []; foreach ($aActualCheckResults as $oCheckRes) { /** @var CheckResult $oCheckRes */ if ($oCheckRes->iSeverity <= CheckResult::WARNING) { $aActual [] = $oCheckRes->sLabel; } } self::assertEquals($expected, $aActual); } protected function createModule($sDirectory, $sModuleName, $sModuleVersion, $bMandatory = false, $bVisible = true) { $sModuleDir = $sDirectory.'/'.$sModuleName; SetupUtils::builddir($sModuleDir); $this->aFileToClean[] = $sDirectory; $sModuleFileName = $sModuleDir.'/module.'.$sModuleName.'.php'; $sMandatory = var_export($bMandatory, true); $sVisible = var_export($bVisible, true); file_put_contents( $sModuleFileName, << "$sModuleName", 'dependencies' => [], 'mandatory' => $sMandatory, 'visible' => $sVisible, 'datamodel' => [], 'data.struct' => [], 'data.sample' => [], 'doc.manual_setup' => '', 'doc.more_information' => '', ] ); PHP ); } }