diff --git a/application/application.inc.php b/application/application.inc.php index c04e8d679..1a8b3f762 100644 --- a/application/application.inc.php +++ b/application/application.inc.php @@ -16,5 +16,5 @@ require_once(APPROOT.'/application/audit.category.class.inc.php'); require_once(APPROOT.'/application/audit.domain.class.inc.php'); require_once(APPROOT.'/application/audit.rule.class.inc.php'); require_once(APPROOT.'/application/query.class.inc.php'); -require_once(APPROOT.'/setup/moduleinstallation.class.inc.php'); +require_once(APPROOT.'/setup/moduleinstallation/moduleinstallation.class.inc.php'); require_once(APPROOT.'/application/utils.inc.php'); diff --git a/core/autoload.php b/core/autoload.php index 83f4e972c..b244272b8 100644 --- a/core/autoload.php +++ b/core/autoload.php @@ -24,7 +24,7 @@ MetaModel::IncludeModule('application/user.dashboard.class.inc.php'); MetaModel::IncludeModule('application/audit.rule.class.inc.php'); MetaModel::IncludeModule('application/audit.domain.class.inc.php'); MetaModel::IncludeModule('application/query.class.inc.php'); -MetaModel::IncludeModule('setup/moduleinstallation.class.inc.php'); +MetaModel::IncludeModule('setup/moduleinstallation/moduleinstallation.class.inc.php'); MetaModel::IncludeModule('core/event.class.inc.php'); MetaModel::IncludeModule('core/action.class.inc.php'); diff --git a/setup/moduledependency/dependencyexpression.class.inc.php b/setup/moduledependency/dependencyexpression.class.inc.php index 89988fb92..f1792479c 100644 --- a/setup/moduledependency/dependencyexpression.class.inc.php +++ b/setup/moduledependency/dependencyexpression.class.inc.php @@ -61,7 +61,7 @@ class DependencyExpression } } - private static function GetPhpExpressionEvaluator(): PhpExpressionEvaluator + public static function GetPhpExpressionEvaluator(): PhpExpressionEvaluator { if (!isset(self::$oPhpExpressionEvaluator)) { self::$oPhpExpressionEvaluator = new PhpExpressionEvaluator([], RunTimeEnvironment::STATIC_CALL_AUTOSELECT_WHITELIST); diff --git a/setup/modulediscovery.class.inc.php b/setup/modulediscovery.class.inc.php index d9647677e..088d74d48 100755 --- a/setup/modulediscovery.class.inc.php +++ b/setup/modulediscovery.class.inc.php @@ -253,79 +253,7 @@ class ModuleDiscovery self::$m_aRemovedExtensions = $aRemovedExtension; } - /** - * @param array<\iTopExtension> $aExtensions - * @param string $sModuleName - * @param string $sModuleVersion - * @param array $aModuleInfo - * - * @return bool - */ - private static function IsModuleInExtensionList(array $aExtensions, string $sModuleName, string $sModuleVersion, array $aModuleInfo): bool - { - if (count($aExtensions) === 0) { - return false; - } - $aNonMatchingPaths = []; - $sModuleFilePath = $aModuleInfo[ModuleFileReader::MODULE_FILE_PATH]; - - /** @var \iTopExtension $oExtension */ - foreach ($aExtensions as $oExtension) { - $sCurrentVersion = $oExtension->aModuleVersion[$sModuleName] ?? null; - if (is_null($sCurrentVersion)) { - continue; - } - - if ($sModuleVersion !== $sCurrentVersion) { - continue; - } - - $aCurrentModuleInfo = $oExtension->aModuleInfo[$sModuleName] ?? null; - if (is_null($aCurrentModuleInfo)) { - SetupLog::Warning("Missing $sModuleName in ".$oExtension->sLabel.". it should not happen"); - continue; - } - - // use case: same module coming from 2 different extensions - // we remove only the one coming from removed extensions - $sCurrentModuleFilePath = $aCurrentModuleInfo[ModuleFileReader::MODULE_FILE_PATH]; - if (realpath($sModuleFilePath) !== realpath($sCurrentModuleFilePath)) { - $aNonMatchingPaths[] = $sCurrentModuleFilePath; - continue; - } - - SetupLog::Info("Module considered as removed", null, ['extension_code' => $oExtension->sCode, 'module_name' => $sModuleName, 'module_version' => $sModuleVersion, ModuleFileReader::MODULE_FILE_PATH => $sCurrentModuleFilePath]); - return true; - } - - if (count($aNonMatchingPaths) > 0) { - //add log for support - SetupLog::Debug("Module kept as it came from non removed extensions", null, ['module_name' => $sModuleName, 'module_version' => $sModuleVersion, ModuleFileReader::MODULE_FILE_PATH => $sModuleFilePath, 'non_matching_paths' => $aNonMatchingPaths]); - } - return false; - } - - private static function GetPhpExpressionEvaluator(): PhpExpressionEvaluator - { - if (!isset(self::$oPhpExpressionEvaluator)) { - self::$oPhpExpressionEvaluator = new PhpExpressionEvaluator([], RunTimeEnvironment::STATIC_CALL_AUTOSELECT_WHITELIST); - } - - return self::$oPhpExpressionEvaluator; - } - - /** - * Search (on the disk) for all defined iTop modules, load them and returns the list (as an array) - * of the possible iTop modules to install - * - * @param $aSearchDirs array of directories to search (absolute paths) - * @param bool $bAbortOnMissingDependency ... - * @param array $aModulesToLoad List of modules to search for, defaults to all if omitted - * - * @return array A big array moduleID => ModuleData - * @throws \Exception - */ - public static function GetAvailableModules($aSearchDirs, $bAbortOnMissingDependency = false, $aModulesToLoad = null) + public static function Init($aSearchDirs): void { if (self::$m_aSearchDirs != $aSearchDirs) { self::ResetCache(); @@ -344,13 +272,45 @@ class ModuleDiscovery clearstatcache(); self::ListModuleFiles(basename($sSearchDir), dirname($sSearchDir)); } - return self::GetModules($bAbortOnMissingDependency, $aModulesToLoad); - } else { - // Reuse the previous results - return self::GetModules($bAbortOnMissingDependency, $aModulesToLoad); } } + /** + * Search (on the disk) for all defined iTop modules, load them and returns the list (as an array) + * of the possible iTop modules to install + * Compute dependency as well (compatibilities & order) + * + * @param $aSearchDirs array of directories to search (absolute paths) + * @param bool $bAbortOnMissingDependency ... + * @param array $aModulesToLoad List of modules to search for, defaults to all if omitted + * + * @return array A big array moduleID => ModuleData + * @throws \Exception + */ + public static function GetAvailableModules($aSearchDirs, $bAbortOnMissingDependency = false, $aModulesToLoad = null) + { + self::Init($aSearchDirs); + + return self::GetModules($bAbortOnMissingDependency, $aModulesToLoad); + } + + /** + * Search (on the disk) for all defined iTop modules, load them and returns the list (as an array) + * of the possible iTop modules to install + * No dependency consideration here. + * + * @param $aSearchDirs array of directories to search (absolute paths) + * + * @return array A big array moduleID => ModuleData + * @throws \Exception + */ + public static function GetAllModules($aSearchDirs) + { + self::Init($aSearchDirs); + + return self::$m_aModules; + } + public static function ResetCache() { self::$m_aSearchDirs = null; @@ -419,6 +379,59 @@ class ModuleDiscovery throw new Exception("Data directory (".$sDirectory.") not found or not readable."); } } + + /** + * @param array<\iTopExtension> $aExtensions + * @param string $sModuleName + * @param string $sModuleVersion + * @param array $aModuleInfo + * + * @return bool + */ + private static function IsModuleInExtensionList(array $aExtensions, string $sModuleName, string $sModuleVersion, array $aModuleInfo): bool + { + if (count($aExtensions) === 0) { + return false; + } + $aNonMatchingPaths = []; + $sModuleFilePath = $aModuleInfo[ModuleFileReader::MODULE_FILE_PATH]; + + /** @var \iTopExtension $oExtension */ + foreach ($aExtensions as $oExtension) { + $sCurrentVersion = $oExtension->aModuleVersion[$sModuleName] ?? null; + if (is_null($sCurrentVersion)) { + continue; + } + + if ($sModuleVersion !== $sCurrentVersion) { + continue; + } + + $aCurrentModuleInfo = $oExtension->aModuleInfo[$sModuleName] ?? null; + if (is_null($aCurrentModuleInfo)) { + SetupLog::Warning("Missing $sModuleName in ".$oExtension->sLabel.". it should not happen"); + continue; + } + + // use case: same module coming from 2 different extensions + // we remove only the one coming from removed extensions + $sCurrentModuleFilePath = $aCurrentModuleInfo[ModuleFileReader::MODULE_FILE_PATH]; + if (realpath($sModuleFilePath) !== realpath($sCurrentModuleFilePath)) { + $aNonMatchingPaths[] = $sCurrentModuleFilePath; + continue; + } + + SetupLog::Info("Module considered as removed", null, ['extension_code' => $oExtension->sCode, 'module_name' => $sModuleName, 'module_version' => $sModuleVersion, ModuleFileReader::MODULE_FILE_PATH => $sCurrentModuleFilePath]); + return true; + } + + if (count($aNonMatchingPaths) > 0) { + //add log for support + SetupLog::Debug("Module kept as it came from non removed extensions", null, ['module_name' => $sModuleName, 'module_version' => $sModuleVersion, ModuleFileReader::MODULE_FILE_PATH => $sModuleFilePath, 'non_matching_paths' => $aNonMatchingPaths]); + } + return false; + } + } // End of class /** Alias for backward compatibility with old module files in which diff --git a/setup/AnalyzeInstallation.php b/setup/moduleinstallation/AnalyzeInstallation.php similarity index 100% rename from setup/AnalyzeInstallation.php rename to setup/moduleinstallation/AnalyzeInstallation.php diff --git a/setup/moduleinstallation/InstallationChoicesService.php b/setup/moduleinstallation/InstallationChoicesService.php new file mode 100644 index 000000000..68eabbcba --- /dev/null +++ b/setup/moduleinstallation/InstallationChoicesService.php @@ -0,0 +1,190 @@ +Get('steps', []); + if (!is_array($aSteps)) { + return []; + } + } else { + $aSteps = $aInstallationChoices; + } + + $aInstalledModuleNames = $this->FindInstalledPackageModules($aPackageModules, $aInstallationChoices, $aSteps, $bInstallationFileProvided); + + $aInstalledModules = []; + foreach (array_keys($aPackageModules) as $sModuleId) { + list($sModuleName) = ModuleDiscovery::GetModuleName($sModuleId); + if (in_array($sModuleName, $aInstalledModuleNames)) { + $aInstalledModules[] = $sModuleId; + } + } + + return $aInstalledModules; + } + + private function FindInstalledPackageModules(array $aPackageModules, array $aInstallationChoices, array $aInstallationDescription, bool $bInstallationFileProvided): array + { + $aInstalledModules = []; + + $this->ProcessDefaultModules($aPackageModules, $aInstalledModules); + + if ($bInstallationFileProvided) { + $this->ProcessInstallationChoices(array_keys($aInstallationChoices), $aInstallationDescription, $aInstalledModules); + } else { + $aInstalledModules = array_merge($aInstalledModules, $aInstallationChoices); + } + + $this->ProcessAutoSelectModules($aPackageModules, $aInstalledModules); + + return array_keys($aInstalledModules); + } + + private function ProcessDefaultModules(array $aPackageModules, array &$aInstalledModules): void + { + foreach ($aPackageModules as $sModuleId => $aModule) { + if (($sModuleId != ROOT_MODULE)) { + if (isset($aModule['auto_select'])) { + continue; + } + + if (($aModule['category'] == 'authentication') || (!$aModule['visible'])) { + list($sModuleName) = ModuleDiscovery::GetModuleName($sModuleId); + $aInstalledModules[$sModuleName] = true; + } + } + } + } + + private function ProcessAutoSelectModules(array $aPackageModules, array &$aInstalledModules): void + { + foreach ($aPackageModules as $sModuleId => $aModule) { + if (($sModuleId !== ROOT_MODULE) && isset($aModule['auto_select'])) { + try { + SetupInfo::SetSelectedModules($aInstalledModules); + $bSelected = DependencyExpression::GetPhpExpressionEvaluator()->ParseAndEvaluateBooleanExpression($aModule['auto_select']); + if ($bSelected) { + list($sModuleName) = ModuleDiscovery::GetModuleName($sModuleId); + $aInstalledModules[$sModuleName] = true; + } + } catch (Exception $e) { + IssueLog::Error('Error evaluating module auto-select', null, [ + 'module' => $sModuleId, + 'error' => $e->getMessage(), + 'evaluated code' => $aModule['auto_select'], + 'stacktrace' => $e->getTraceAsString(), + ]); + } + } + } + } + + private function ProcessInstallationChoices(array $aInstallationChoices, array $aInstallationDescription, array &$aInstalledModules): void + { + foreach ($aInstallationDescription as $aStepInfo) { + $aOptions = $aStepInfo['options'] ?? null; + if (is_array($aOptions)) { + foreach ($aOptions as $aChoiceInfo) { + $this->ProcessSelectedChoice($aInstallationChoices, $aChoiceInfo, $aInstalledModules); + } + } + $aOptions = $aStepInfo['alternatives'] ?? null; + if (is_array($aOptions)) { + foreach ($aOptions as $aChoiceInfo) { + $this->ProcessSelectedChoice($aInstallationChoices, $aChoiceInfo, $aInstalledModules); + } + } + } + } + + private function ProcessSelectedChoice(array $aInstallationChoices, array $aChoiceInfo, array &$aInstalledModules) + { + if (!is_array($aChoiceInfo)) { + return; + } + + $sMandatory = $aChoiceInfo['mandatory'] ?? 'false'; + + $aCurrentModules = $aChoiceInfo['modules'] ?? []; + $sExtensionCode = $aChoiceInfo['extension_code']; + + $bSelected = ($sMandatory === 'true') || in_array($sExtensionCode, $aInstallationChoices); + + if (!$bSelected) { + return; + } + + foreach ($aCurrentModules as $sModuleId) { + $aInstalledModules[$sModuleId] = true; + } + + $aAlternatives = $aChoiceInfo['alternatives'] ?? null; + if (is_array($aAlternatives)) { + foreach ($aAlternatives as $aSubChoiceInfo) { + $this->ProcessSelectedChoice($aInstallationChoices, $aSubChoiceInfo, $aInstalledModules); + } + } + + $aSubOptionsChoiceInfo = $aChoiceInfo['sub_options'] ?? null; + if (is_array($aSubOptionsChoiceInfo)) { + $aSubOptions = $aSubOptionsChoiceInfo['options'] ?? null; + if (is_array($aSubOptions)) { + foreach ($aSubOptions as $aSubChoiceInfo) { + $this->ProcessSelectedChoice($aInstallationChoices, $aSubChoiceInfo, $aInstalledModules); + } + } + $aSubAlternatives = $aSubOptionsChoiceInfo['alternatives'] ?? null; + if (is_array($aSubAlternatives)) { + foreach ($aSubAlternatives as $aSubChoiceInfo) { + $this->ProcessSelectedChoice($aInstallationChoices, $aSubChoiceInfo, $aInstalledModules); + } + } + } + } + +} diff --git a/setup/moduleinstallation/ModuleInstallationException.php b/setup/moduleinstallation/ModuleInstallationException.php new file mode 100644 index 000000000..40fdccc83 --- /dev/null +++ b/setup/moduleinstallation/ModuleInstallationException.php @@ -0,0 +1,5 @@ +GetLoadedFile(); if (strlen($sConfigFile) > 0) { diff --git a/tests/php-unit-tests/unitary-tests/setup/AnalyzeInstallationTest.php b/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/AnalyzeInstallationTest.php similarity index 97% rename from tests/php-unit-tests/unitary-tests/setup/AnalyzeInstallationTest.php rename to tests/php-unit-tests/unitary-tests/setup/moduleinstallation/AnalyzeInstallationTest.php index 1f392ff9e..3d855e69d 100644 --- a/tests/php-unit-tests/unitary-tests/setup/AnalyzeInstallationTest.php +++ b/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/AnalyzeInstallationTest.php @@ -11,8 +11,6 @@ class AnalyzeInstallationTest extends ItopTestCase protected function setUp(): void { parent::setUp(); - $this->RequireOnceItopFile('setup/AnalyzeInstallation.php'); - $this->RequireOnceItopFile('setup/ModuleInstallationRepository.php'); $this->RequireOnceItopFile('setup/modulediscovery.class.inc.php'); $this->RequireOnceItopFile('setup/runtimeenv.class.inc.php'); } diff --git a/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/InstallationChoicesServiceTest.php b/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/InstallationChoicesServiceTest.php new file mode 100644 index 000000000..14a8d703a --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/InstallationChoicesServiceTest.php @@ -0,0 +1,211 @@ +RequireOnceItopFile('/setup/moduleinstallation/InstallationChoicesService.php'); + } + + protected function tearDown(): void + { + parent::tearDown(); + ModuleDiscovery::ResetCache(); + } + + public function NonItilExtensionProvider() + { + return [ + 'all NON ITIL extensions + INCLUDING known-error-mgt' => [ + 'aInstallationChoices' => $this->GetSelectedNonItilExtensions(true, true), + 'bKnownMgtSelected' => true, + 'bCoreMgtSelected' => true, + ], + /*'all NON ITIL extensions WITHOUT known-error-mgt' => [ + 'aInstallationChoices' => $this->GetSelectedNonItilExtensions(true, false), + 'bKnownMgtSelected' => false, + 'bCoreMgtSelected' => true, + ], + 'all NON ITIL extensions WITHOUT core mandatory ones + INCLUDING known-error-mgt' => [ + 'aInstallationChoices' => $this->GetSelectedNonItilExtensions(false, true), + 'bKnownMgtSelected' => true, + 'bCoreMgtSelected' => false, + ], + 'all NON ITIL extensions WITHOUT core mandatory ones and WITHOUT known-error-mgt' => [ + 'aInstallationChoices' => $this->GetSelectedNonItilExtensions(false, false), + 'bKnownMgtSelected' => false, + 'bCoreMgtSelected' => false, + ],*/ + ]; + } + + private function GetSelectedNonItilExtensions(bool $coreExtensionIncluded, bool $bKnownMgtIncluded): array + { + $aExtensions = [ + 'itop-config-mgmt-core', + 'itop-config-mgmt-datacenter', + 'itop-config-mgmt-end-user', + 'itop-config-mgmt-storage', + 'itop-config-mgmt-virtualization', + 'itop-service-mgmt-enterprise', + 'itop-ticket-mgmt-simple-ticket', + 'itop-ticket-mgmt-simple-ticket-enhanced-portal', + 'itop-change-mgmt-simple', + ]; + + if ($coreExtensionIncluded) { + $aExtensions[] = 'itop-config-mgmt-core'; + } + + if ($bKnownMgtIncluded) { + $aExtensions[] = 'itop-kown-error-mgmt'; + } + + return $this->TransformExtensionArrayToDictionnary($aExtensions); + } + + private function TransformExtensionArrayToDictionnary(array $aExtensions) + { + $aDict = []; + foreach ($aExtensions as $sExtId) { + $aDict[$sExtId] = []; + } + + return $aDict; + } + + /** + * @dataProvider NonItilExtensionProvider + */ + public function testGetInstalledModules(array $aInstallationChoices, bool $bKnownMgtSelected, bool $bCoreMgtSelected) + { + $aSearchDirs = $this->GivenModuleDiscoveryInit(); + + $aExpectedModulesIds = $this->GetExpectedNonItilInstalledModules($bKnownMgtSelected, $bCoreMgtSelected); + + $aInstalledModules = InstallationChoicesService::GetInstance()->GetInstalledModules( + $aInstallationChoices, + $aSearchDirs, + __DIR__.'/ressources/installation.xml' + ); + + sort($aInstalledModules); + $this->assertEquals($aExpectedModulesIds, $aInstalledModules); + } + + public function testGetInstalledModules_NoInstallationXML() + { + $aSearchDirs = $this->GivenModuleDiscoveryInit(); + + $aInstallationChoices = json_decode(file_get_contents(__DIR__."/ressources/installation_choices_when_no_xml_file.json"), true); + + $aExpectedModulesIds = [ + 'authent-cas/3.3.0', + 'authent-external/3.3.0', + 'authent-ldap/3.3.0', + 'authent-local/3.3.0', + 'combodo-backoffice-darkmoon-theme/3.3.0', + 'combodo-backoffice-fullmoon-high-contrast-theme/3.3.0', + 'combodo-backoffice-fullmoon-protanopia-deuteranopia-theme/3.3.0', + 'combodo-backoffice-fullmoon-tritanopia-theme/3.3.0', + 'combodo-db-tools/3.3.0', + 'itop-attachments/3.3.0', + 'itop-backup/3.3.0', + 'itop-bridge-cmdb-services/3.3.0', + 'itop-config-mgmt/3.3.0', + 'itop-config/3.3.0', + 'itop-core-update/3.3.0', + 'itop-faq-light/3.3.0', + 'itop-files-information/3.3.0', + 'itop-portal-base/3.3.0', + 'itop-profiles-itil/3.3.0', + 'itop-request-mgmt/3.3.0', + 'itop-service-mgmt/3.3.0', + 'itop-sla-computation/3.3.0', + 'itop-structure/3.3.0', + 'itop-welcome-itil/3.3.0', + ]; + + $aInstalledModules = InstallationChoicesService::GetInstance()->GetInstalledModules( + $aInstallationChoices, + $aSearchDirs, + null + ); + + sort($aInstalledModules); + $this->assertEquals($aExpectedModulesIds, $aInstalledModules); + } + + private function GetExpectedNonItilInstalledModules(bool $bKnownMgtSelected, bool $bCoreMgtSelected): array + { + $aExpectedInstalledModules = [ + 'itop-structure/3.3.0', + 'itop-sla-computation/3.3.0', + 'itop-portal-base/3.3.0', + 'itop-bridge-virtualization-mgmt-services/3.3.0', + 'itop-request-mgmt/3.3.0', + 'itop-welcome-itil/3.3.0', + 'itop-profiles-itil/3.3.0', + 'authent-ldap/3.3.0', + 'authent-local/3.3.0', + 'itop-oauth-client/3.3.0', + 'itop-virtualization-mgmt/3.3.0', + 'itop-core-update/3.3.0', + 'combodo-backoffice-fullmoon-high-contrast-theme/3.3.0', + 'itop-bridge-cmdb-services/3.3.0', + 'itop-files-information/3.3.0', + 'itop-attachments/3.3.0', + 'itop-bridge-endusers-devices-services/3.3.0', + 'itop-endusers-devices/3.3.0', + 'itop-backup/3.3.0', + 'itop-config/3.3.0', + 'itop-bridge-storage-mgmt-services/3.3.0', + 'combodo-backoffice-fullmoon-tritanopia-theme/3.3.0', + 'combodo-backoffice-darkmoon-theme/3.3.0', + 'itop-portal/3.3.0', + 'itop-hub-connector/3.3.0', + 'itop-bridge-datacenter-mgmt-services/3.3.0', + 'itop-themes-compat/3.3.0', + 'itop-tickets/3.3.0', + 'itop-storage-mgmt/3.3.0', + 'combodo-db-tools/3.3.0', + 'combodo-backoffice-fullmoon-protanopia-deuteranopia-theme/3.3.0', + 'authent-cas/3.3.0', + 'itop-datacenter-mgmt/3.3.0', + 'itop-bridge-virtualization-storage/3.3.0', + 'authent-external/3.3.0', + 'itop-bridge-cmdb-ticket/3.3.0', + + 'itop-change-mgmt/3.3.0', + 'itop-service-mgmt/3.3.0', + ]; + if ($bCoreMgtSelected) { + $aExpectedInstalledModules [] = 'itop-config-mgmt/3.3.0'; + } + if ($bKnownMgtSelected) { + $aExpectedInstalledModules [] = 'itop-knownerror-mgmt/3.3.0'; + $aExpectedInstalledModules [] = 'itop-faq-light/3.3.0'; + } + sort($aExpectedInstalledModules); + + return $aExpectedInstalledModules; + } + + private function GivenModuleDiscoveryInit(): array + { + $aSearchDirs = [APPROOT.'datamodels/2.x']; + $this->SetNonPublicStaticProperty(ModuleDiscovery::class, 'm_aSearchDirs', $aSearchDirs); + $aAllModules = json_decode(file_get_contents(__DIR__.'/ressources/available_modules.json'), true); + $this->SetNonPublicStaticProperty(ModuleDiscovery::class, 'm_aModules', $aAllModules); + return $aSearchDirs; + } +} diff --git a/tests/php-unit-tests/unitary-tests/setup/ressources/analyze_installation_output.json b/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/analyze_installation_output.json similarity index 100% rename from tests/php-unit-tests/unitary-tests/setup/ressources/analyze_installation_output.json rename to tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/analyze_installation_output.json diff --git a/tests/php-unit-tests/unitary-tests/setup/ressources/available_modules.json b/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/available_modules.json similarity index 100% rename from tests/php-unit-tests/unitary-tests/setup/ressources/available_modules.json rename to tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/available_modules.json diff --git a/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/installation.xml b/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/installation.xml new file mode 100644 index 000000000..e7270f896 --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/installation.xml @@ -0,0 +1,230 @@ + + + + + Configuration Management options + The options below allow you to configure the type of elements that are to be managed inside iTop.]]> + /images/icons/icons8-apps-tab.svg + + + itop-config-mgmt-core + Configuration Management Core + All the base objects that are mandatory in the iTop CMDB: Organizations, Locations, Teams, Persons, etc. + + combodo-backoffice-darkmoon-theme + combodo-backoffice-fullmoon-high-contrast-theme + combodo-backoffice-fullmoon-protanopia-deuteranopia-theme + combodo-backoffice-fullmoon-tritanopia-theme + combodo-db-tools + combodo-password-expiration + combodo-webhook-integration + itop-attachments + itop-backup + itop-config + itop-config-mgmt + itop-core-update + itop-files-information + itop-hub-connector + itop-oauth-client + itop-profiles-itil + itop-structure + itop-themes-compat + itop-tickets + itop-welcome-itil + combodo-my-account-user-info + authent-token + + true + + + itop-config-mgmt-datacenter + Data Center Devices + Manage Data Center devices such as Racks, Enclosures, PDUs, etc. + + itop-datacenter-mgmt + + true + + + itop-config-mgmt-end-user + End-User Devices + Manage devices related to end-users: PCs, Phones, Tablets, etc. + + itop-endusers-devices + + true + + + itop-config-mgmt-storage + Storage Devices + Manage storage devices such as NAS, SAN Switches, Tape Libraries and Tapes, etc. + + itop-storage-mgmt + + true + + + itop-config-mgmt-virtualization + Virtualization + Manage Hypervisors, Virtual Machines and Farms. + + itop-virtualization-mgmt + + true + + + + + Service Management options + Select the choice that best describes the relationships between the services and the IT infrastructure in your IT environment.]]> + /images/icons/icons8-services.svg + + + itop-service-mgmt-enterprise + Service Management for Enterprises + Select this option if the IT delivers services based on a shared infrastructure. For example if different organizations within your company subscribe to services (like Mail and Print services) delivered by a single shared backend. + + itop-service-mgmt + + true + + + itop-service-mgmt-service-provider + Service Management for Service Providers + Select this option if the IT manages the infrastructure of independent customers. This is the most flexible model, since the services can be delivered with a mix of shared and customer specific infrastructure devices. + + itop-service-mgmt-provider + + + + + + Tickets Management options + Select the type of tickets you want to use in order to respond to user requests and incidents.]]> + /images/icons/icons8-discussion-forum.svg + + + itop-ticket-mgmt-simple-ticket + Simple Ticket Management + Select this option to use one single type of tickets for all kind of requests. + + itop-request-mgmt + + true + + + + itop-ticket-mgmt-simple-ticket-enhanced-portal + Customer Portal + + + itop-portal + itop-portal-base + + true + + + + + + itop-ticket-mgmt-itil + ITIL Compliant Tickets Management + Select this option to have different types of ticket for managing user requests and incidents. Each type of ticket has a specific life cycle and specific fields + + + + itop-ticket-mgmt-itil-user-request + User Request Management + Manage User Request tickets in iTop + + itop-request-mgmt-itil + + + + itop-ticket-mgmt-itil-incident + Incident Management + Manage Incidents tickets in iTop + + itop-incident-mgmt-itil + + + + itop-ticket-mgmt-itil-enhanced-portal + Customer Portal + + + itop-portal + itop-portal-base + + true + + + + + + itop-ticket-mgmt-none + No Tickets Management + Don't manage incidents or user requests in iTop + + + + + + + Change Management options + Select the type of tickets you want to use in order to manage changes to the IT infrastructure.]]> + /images/icons/icons8-change.svg + + + itop-change-mgmt-simple + Simple Change Management + Select this option to use one type of ticket for all kind of changes. + + itop-change-mgmt + + true + + + itop-change-mgmt-itil + ITIL Change Management + Select this option to use Normal/Routine/Emergency change tickets. + + itop-change-mgmt-itil + + + + itop-change-mgmt-none + No Change Management + Don't manage changes in iTop + + + + + + + Additional ITIL tickets + Pick from the list below the additional ITIL processes that are to be implemented in iTop.]]> + /images/icons/icons8-important-book.svg + + + + itop-kown-error-mgmt + Known Errors Management and FAQ + Select this option to track "Known Errors" and FAQs in iTop. + + itop-faq-light + itop-knownerror-mgmt + + + + itop-problem-mgmt + Problem Management + Select this option track "Problems" in iTop. + + itop-problem-mgmt + + + + + + \ No newline at end of file diff --git a/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/installation_choices_when_no_xml_file.json b/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/installation_choices_when_no_xml_file.json new file mode 100644 index 000000000..2b455b857 --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/installation_choices_when_no_xml_file.json @@ -0,0 +1 @@ +{"itop-config-mgmt":{"label":"Configuration+Management+customized+for+Combodo+IT(CMDB)","value":"2.7.0"},"itop-icalendar-action":{"label":"Calendar+Invitations","value":"1.1.0"},"itop-fence":{"label":"iTop+Fence","value":"1.1.2"},"authent-ldap":{"label":"User+authentication+based+on+LDAP","value":"3.2.1"},"itop-faq-light":{"label":"Frequently+Asked+Questions+Database","value":"3.2.1"},"authent-local":{"label":"User+authentication+based+on+the+local+DB","value":"3.2.1"},"combodo-custom-hyperlinks":{"label":"Hyperlinks+configurator","value":"1.1.3"},"authent-token":{"label":"User+authentication+by+token","value":"2.2.1"},"itop-service-mgmt":{"label":"Service+Management+Customized+for+Combodo+IT(services,+SLAs,+contracts)","value":"2.7.0"},"combodo-impersonate":{"label":"Impersonate+user+for+support","value":"1.2.1"},"combodo-hybridauth":{"label":"oAuth\/OpenID+authentication","value":"1.2.4"},"combodo-login-page":{"label":"Combodo+login+page","value":"2.1.0"},"itop-core-update":{"label":"iTop+Core+Update","value":"3.2.1"},"itop-communications":{"label":"Communications+to+the+Customers","value":"1.3.4"},"itsm-designer-connector":{"label":"ITSM+Designer+Connector","value":"1.8.3"},"authent-external":{"label":"External+user+authentication","value":"3.2.1"},"itop-object-copier":{"label":"Object+copier","value":"1.4.5"},"combodo-backoffice-compact-themes":{"label":"Backoffice:+compact+themes","value":"1.0.1"},"data-localizer":{"label":"Data+localizer","value":"1.3.4"},"combodo-support-portal":{"label":"Combodo+Support+Portal","value":"3.0.1"},"combodo-calendar-view":{"label":"Calendar+View","value":"2.2.1"},"combodo-email-synchro":{"label":"Tickets+synchronization+via+e-mail","value":"3.8.2"},"combodo-webhook-integration":{"label":"Webhook+integrations","value":"1.4.1"},"combodo-notify-on-expiration":{"label":"Notify+on+expiration","value":"1.0.4"},"combodo-db-tools":{"label":"Database+maintenance+tools","value":"3.2.1"},"precanned-replies":{"label":"Helpdesk+Precanned+Replies","value":"1.4.0"},"combodo-dokuwiki-portal-brick":{"label":"Docuwiki+brick+(Portal)","value":"1.2.0"},"itop-rh-mgmt":{"label":"Human+Resource+Management","value":"2.7.0"},"itop-request-mgmt":{"label":"User+request+management+(Service+Desk)","value":"2.7.0"},"customer-survey":{"label":"Customer+Survey","value":"2.5.5"},"itop-standard-email-synchro":{"label":"Ticket+Creation+from+Emails+(Standard)","value":"3.8.2"},"itop-system-information":{"label":"System+information","value":"1.2.6"},"itop-sales-mgmt":{"label":"Sales+Management","value":"2.7.0"},"combodo-password-expiration":{"label":"Password+Expiration+Enforcement","value":"1.0.0"},"combodo-workflow-graphical-view":{"label":"Workflow+graphical+view","value":"1.1.3"},"combodo-itsm-master":{"label":"Data+master+for+the+ITSM+Designer","value":"2.7.0"},"combodo-email-tickets":{"label":"Tickets+Creation+from+Emails+for+Combodo","value":"2.7.0"},"itop-training-mgmt":{"label":"Training+Management","value":"2.7.0"},"precanned-replies-pro":{"label":"Helpdesk+Precanned+Replies+Extension","value":"1.2.0"},"combodo-fulltext-search":{"label":"Enhanced+global+search","value":"2.0.0"},"itop-request-template":{"label":"Customized+Request+Forms","value":"2.3.6"},"itop-rest-data-push":{"label":"Data+push+(based+on+standard+REST+services)","value":"1.0.2"},"combodo-kpi-logger":{"label":"KPI+logger","value":"1.0.3"},"itop-incident-mgmt":{"label":"Incident+Management","value":"2.7.0"},"combodo-my-account-user-info":{"label":"User+info+for+MyAccount+module","value":"1.0.0"},"email-reply":{"label":"Send+Ticket+Log+Updates+by+Email","value":"1.4.5"},"itop-attachments":{"label":"Tickets+Attachments","value":"3.2.1"},"itop-log-mgmt":{"label":"iTop+Log+management","value":"2.0.8"},"itop-ui-copypaste":{"label":"CopyPaste+UI+Component","value":"1.0.0"}} \ No newline at end of file diff --git a/tests/php-unit-tests/unitary-tests/setup/ressources/priv_modules.json b/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/priv_modules.json similarity index 100% rename from tests/php-unit-tests/unitary-tests/setup/ressources/priv_modules.json rename to tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/priv_modules.json diff --git a/tests/php-unit-tests/unitary-tests/setup/ressources/priv_modules2.json b/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/priv_modules2.json similarity index 100% rename from tests/php-unit-tests/unitary-tests/setup/ressources/priv_modules2.json rename to tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/priv_modules2.json diff --git a/tests/php-unit-tests/unitary-tests/setup/ressources/priv_modules_simpleusecase.json b/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/priv_modules_simpleusecase.json similarity index 100% rename from tests/php-unit-tests/unitary-tests/setup/ressources/priv_modules_simpleusecase.json rename to tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/priv_modules_simpleusecase.json diff --git a/tests/php-unit-tests/unitary-tests/setup/ressources/reallife_discovered_modules.json b/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/reallife_discovered_modules.json similarity index 100% rename from tests/php-unit-tests/unitary-tests/setup/ressources/reallife_discovered_modules.json rename to tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/reallife_discovered_modules.json diff --git a/tests/php-unit-tests/unitary-tests/setup/ressources/reallife_expected_ordered_modules.json b/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/reallife_expected_ordered_modules.json similarity index 100% rename from tests/php-unit-tests/unitary-tests/setup/ressources/reallife_expected_ordered_modules.json rename to tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/reallife_expected_ordered_modules.json