diff --git a/datamodels/2.x/combodo-data-feature-removal/src/Controller/DataFeatureRemovalController.php b/datamodels/2.x/combodo-data-feature-removal/src/Controller/DataFeatureRemovalController.php index e233cfc580..342d8c02fc 100644 --- a/datamodels/2.x/combodo-data-feature-removal/src/Controller/DataFeatureRemovalController.php +++ b/datamodels/2.x/combodo-data-feature-removal/src/Controller/DataFeatureRemovalController.php @@ -8,7 +8,6 @@ namespace Combodo\iTop\DataFeatureRemoval\Controller; require_once APPROOT.'setup/feature_removal/SetupAudit.php'; -require_once APPROOT.'setup/feature_removal/DryRemovalRuntimeEnvironment.php'; use Combodo\iTop\Application\Helper\Session; use Combodo\iTop\Application\TwigBase\Controller\Controller; @@ -20,7 +19,6 @@ use Combodo\iTop\DataFeatureRemoval\Service\DataFeatureRemoverExtensionService; use Combodo\iTop\DataFeatureRemoval\Service\StaticDeletionPlan; use Combodo\iTop\Service\Session\SessionParameters; -use Combodo\iTop\Setup\FeatureRemoval\DryRemovalRuntimeEnvironment; use Combodo\iTop\Setup\FeatureRemoval\SetupAudit; use ContextTag; use CoreException; @@ -39,10 +37,10 @@ class DataFeatureRemovalController extends Controller private array $aCountClassesToCleanup = []; private array $aAnalysisDataTable = []; private array $aDeletionExecutionSummary = []; - private ?RuntimeEnvironment $oRuntimeEnvironment = null; private int $iCount = 0; private int $iColumnCount = 2; + private RunTimeEnvironment $oRuntimeEnvironment; public function OperationMain($sErrorMessage = null): void { @@ -131,8 +129,6 @@ public function OperationAnalysisResult(): void $aHiddenInputs['removed_extensions'] = $this->ConvertIntoSetupFormat($aRemovedExtensions); } - $aRemoveExtensionCodes = array_keys($aRemovedExtensions); - $aParams['aAddedExtensions'] = $aAddedExtensions; $aParams['aRemovedExtensions'] = $aRemovedExtensions; @@ -144,9 +140,24 @@ public function OperationAnalysisResult(): void $aParams['iColumnCount'] = $this->iColumnCount; $aParams['aAvailableExtensions'] = $this->SplitArrayIntoColumns($this->GetExtensionsDiff($aAddedExtensions, $aRemovedExtensions), $this->iColumnCount); - $bForceCompilation = Session::Get('bForceCompilation', false); + //to make setup redirection work, we need to pass complex data structures to setup wizards (ie extension/module lists) + $sSourceEnv = MetaModel::GetEnvironment(); + $this->oRuntimeEnvironment = new RunTimeEnvironment($sSourceEnv, false); + + if ('[]' === $aHiddenInputs['selected_modules']) { + $oConfig = MetaModel::GetConfig(); + $aSelectedExtensions = DataFeatureRemoverExtensionService::GetInstance()->GetExtensionMap()->GetSelectedExtensions($oConfig, array_keys($aAddedExtensions), array_keys($aRemovedExtensions)); + $aHiddenInputs['selected_extensions'] = $this->ConvertIntoSetupFormat($aSelectedExtensions); + + $aSelectedModules = []; // keep it to compile method + } else { + $aSelectedExtensions = json_decode($aHiddenInputs['selected_extensions'], true); + $aSelectedModules = json_decode($aHiddenInputs['selected_modules'], true); + } + try { - $this->Compile($aAddedExtensions, $aRemoveExtensionCodes, $bForceCompilation); + $this->Compile($aSelectedExtensions, array_keys($aRemovedExtensions), $aSelectedModules); + $aHiddenInputs['selected_modules'] = $this->ConvertIntoSetupFormat($aSelectedModules); } catch (CoreException $e) { $aParams['DataFeatureRemovalErrorMessage'] = $e->getHtmlDesc(); $this->DisplayPage($aParams, 'AnalysisResult'); @@ -157,19 +168,6 @@ public function OperationAnalysisResult(): void return; } - if ("[]" === $aHiddenInputs['selected_modules']) { - //to make setup redirection work, we need to pass complex data structures to setup wizards (ie extension/module lists) - $oConfig = MetaModel::GetConfig(); - $aSelectedExtensions = DataFeatureRemoverExtensionService::GetInstance()->GetExtensionMap()->GetSelectedExtensions($oConfig, array_keys($aAddedExtensions), array_keys($aRemovedExtensions)); - $aHiddenInputs['selected_extensions'] = $this->ConvertIntoSetupFormat($aSelectedExtensions); - - $oRunTimeEnvironment = $this->GetRuntimeEnvironment($aAddedExtensions, $aRemovedExtensions); - $aSearchDirs = [$oRunTimeEnvironment->GetBuildDir()]; - $aSelectedModules = $oRunTimeEnvironment->GetModulesToLoadFromChoices($oConfig, $aSelectedExtensions, $aSearchDirs); - $aHiddenInputs['selected_modules'] = $this->ConvertIntoSetupFormat($aSelectedModules); - } - - $sSourceEnv = MetaModel::GetEnvironment(); $oSetupAudit = new SetupAudit($sSourceEnv); $aGetRemovedClasses = array_keys($oSetupAudit->RunDataAudit()); DataFeatureRemovalLog::Debug(__METHOD__, null, ['aGetRemovedClasses' => $aGetRemovedClasses]); @@ -211,15 +209,15 @@ private function ConvertIntoSetupFormat(array $aData): string } /** - * @param array $aAddedExtensions + * @param array $aSelectedExtensions * @param array $aRemovedExtensions - * @param bool $bForceCompilation + * @param array $aSelectedModules * * @return void * @throws \ConfigException * @throws \CoreException */ - private function Compile(array $aAddedExtensions, array $aRemovedExtensions, bool $bForceCompilation = true): void + private function Compile(array $aSelectedExtensions, array $aRemovedExtensions, array &$aSelectedModules): void { $sSourceEnv = MetaModel::GetEnvironment(); $sBuildDir = APPROOT."/env-$sSourceEnv-build"; @@ -227,26 +225,26 @@ private function Compile(array $aAddedExtensions, array $aRemovedExtensions, boo SetupUtils::builddir($sBuildDir); } $bIsDirEmpty = count(scandir($sBuildDir)) === 2; + $bForceCompilation = Session::Get('bForceCompilation', false); + $oConfig = MetaModel::GetConfig(); if ($bIsDirEmpty || $bForceCompilation) { Session::Unset('bForceCompilation'); + $this->oRuntimeEnvironment->CopySetupFiles(); + if (count($aSelectedModules) === 0) { + $aSelectedModules = $this->oRuntimeEnvironment->GetModulesToLoadFromChoices($oConfig, $aSelectedExtensions); + } DataFeatureRemovalLog::Debug( __METHOD__, null, ['sSourceEnv' => $sSourceEnv, 'sBuildDir' => $sBuildDir, 'bIsDirEmpty' => $bIsDirEmpty, glob("$sBuildDir/*")] ); - $this->GetRuntimeEnvironment($aAddedExtensions, $aRemovedExtensions)->CompileFrom($sSourceEnv); - } - } - - private function GetRuntimeEnvironment(array $aAddedExtensions, array $aRemovedExtensions): RunTimeEnvironment - { - if (is_null($this->oRuntimeEnvironment)) { - $sSourceEnv = MetaModel::GetEnvironment(); - $this->oRuntimeEnvironment = new DryRemovalRuntimeEnvironment($sSourceEnv, $aAddedExtensions, $aRemovedExtensions); + $this->oRuntimeEnvironment->DoCompile($aSelectedExtensions, $aRemovedExtensions, $aSelectedModules, MFCompiler::CanUseSymbolicLinks()); + } else { + if (count($aSelectedModules) === 0) { + $aSelectedModules = $this->oRuntimeEnvironment->GetModulesToLoadFromChoices($oConfig, $aSelectedExtensions); + } } - - return $this->oRuntimeEnvironment; } private function GetExecutionSummaryTable(): array diff --git a/datamodels/2.x/itop-hub-connector/src/Controller/HubController.php b/datamodels/2.x/itop-hub-connector/src/Controller/HubController.php index c091f1e094..a205a98ffd 100644 --- a/datamodels/2.x/itop-hub-connector/src/Controller/HubController.php +++ b/datamodels/2.x/itop-hub-connector/src/Controller/HubController.php @@ -133,8 +133,7 @@ public function LaunchCompile() throw new Exception('Sorry the installation of extensions is not allowed in demo mode'); } - $aSelectModules = $oRuntimeEnv->CompileFrom('production'); // WARNING symlinks does not seem to be compatible with manual Commit - + $oRuntimeEnv->CompileFrom('production'); // WARNING symlinks does not seem to be compatible with manual Commit $oRuntimeEnv->UpdateIncludes($oConfig); $oRuntimeEnv->InitDataModel($oConfig, true /* model only */); diff --git a/setup/extensionsmap.class.inc.php b/setup/extensionsmap.class.inc.php index b5d603797a..0f378d48f7 100644 --- a/setup/extensionsmap.class.inc.php +++ b/setup/extensionsmap.class.inc.php @@ -763,4 +763,49 @@ public function GetScannedModulesRootDirs(): array { return $this->aScannedDirs; } + + /** + * Validate extensions if an invalid extension is marked as chosen, then throw an exception + * + * @return bool true if all extensions are valid + * @throws \CoreException + */ + public function CheckExtensionsValidity(): bool + { + $bSetupFailure = false; + $aNoCodeExtensionSourceDirs = []; + $aNoCodeExtensionLabelsThatBreakSetup = []; + + /** @var iTopExtension $oExtension */ + foreach ($this->aExtensions as $oExtension) { + if (!$oExtension->HasCode()) { + if ($oExtension->HasLabel()) { + $sExtensionLabel = $oExtension->sLabel; + $aNoCodeExtensionSourceDirs [$sExtensionLabel] = $oExtension->sSourceDir; + } else { + $sExtensionLabel = $oExtension->sSourceDir; + $aNoCodeExtensionSourceDirs [] = $oExtension->sSourceDir; + } + + if ($oExtension->IsMarkedAsChosen()) { + $aNoCodeExtensionLabelsThatBreakSetup[] = $sExtensionLabel; + $bSetupFailure = true; + } + } + } + + if (count($aNoCodeExtensionSourceDirs) > 0) { + if ($bSetupFailure) { + $sErrorMessage = sprintf('Selected extension(s) cannot be installed: Missing extension code (%s)', implode(',', $aNoCodeExtensionLabelsThatBreakSetup)); + $e = new CoreException($sErrorMessage); + SetupLog::Exception($sErrorMessage, $e, null, $aNoCodeExtensionSourceDirs); + throw $e; + } else { + SetupLog::Warning('Non selected extension(s) cannot be installed: Missing extension code', null, $aNoCodeExtensionSourceDirs); + return false; + } + } + + return true; + } } diff --git a/setup/feature_removal/DryRemovalRuntimeEnvironment.php b/setup/feature_removal/DryRemovalRuntimeEnvironment.php deleted file mode 100644 index fc4ffd84c2..0000000000 --- a/setup/feature_removal/DryRemovalRuntimeEnvironment.php +++ /dev/null @@ -1,80 +0,0 @@ -aExtensionCodesToAddByCode = $aExtensionCodesToAdd; - $this->aExtensionsToRemoveByCode = $aExtensionCodesToRemove; - $this->Prepare($sSourceEnv, $this->sBuildEnv); - } - - /** - * @param string $sSourceEnv - * @param string $sBuildEnv - * @return void - * @throws \MissingDependencyException - */ - private function Prepare(string $sSourceEnv, string $sBuildEnv) - { - $this->Cleanup(); - SetupUtils::copydir(APPROOT."/data/$sSourceEnv-modules", APPROOT."/data/$sBuildEnv-modules"); - SetupUtils::copydir(APPROOT."/conf/$sSourceEnv", APPROOT."/conf/$sBuildEnv"); - - $oSourceConfig = new Config(APPCONF.$sSourceEnv.'/'.ITOP_CONFIG_FILE); - $sSourceDir = $oSourceConfig->Get('source_dir'); - list($aExtraDirs, ) = $this->GetDirsToCompile($sSourceDir, $sSourceEnv); - - $this->InitExtensionMap($aExtraDirs, $oSourceConfig); - $this->GetExtensionMap()->DeclareExtensionAsRemoved($this->aExtensionsToRemoveByCode); - - foreach ($this->GetExtensionMap()->GetAllExtensions() as $oExtension) { - if (array_key_exists($oExtension->sCode, $this->aExtensionCodesToAddByCode)) { - $oExtension->MarkAsChosen(); - } - } - } - - public function Cleanup(): void - { - $sEnv = $this->sBuildEnv; - - //keep this folder empty - SetupUtils::tidydir(APPROOT."/env-$sEnv"); - - $aFolders = [ - APPROOT."/data/$sEnv-modules", - APPROOT."/data/cache-$sEnv", - APPROOT."/conf/$sEnv", - ]; - foreach ($aFolders as $sFolder) { - SetupUtils::tidydir($sFolder); - SetupUtils::rmdir_safe($sFolder); - } - - $sFiles = [ - APPROOT."/data/datamodel-$sEnv.xml", - APPROOT."/data/$sEnv.delta.prev.xml", - ]; - foreach ($sFiles as $sFile) { - if (is_file($sFile)) { - @unlink($sFile); - } - } - } -} diff --git a/setup/feature_removal/InplaceSetupAudit.php b/setup/feature_removal/InplaceSetupAudit.php deleted file mode 100644 index b49a46540a..0000000000 --- a/setup/feature_removal/InplaceSetupAudit.php +++ /dev/null @@ -1,40 +0,0 @@ -aClassesBefore = $aClassesBefore; - $this->sEnvAfter = $sEnvAfter; - } - - public function ComputeClasses(): void - { - if ($this->bClassesInitialized) { - return; - } - - $sCurrentEnvt = MetaModel::GetEnvironment(); - - if ($sCurrentEnvt === $this->sEnvAfter) { - $this->aClassesAfter = MetaModel::GetClasses(); - } else { - $this->aClassesAfter = ModelReflectionSerializer::GetInstance()->GetModelFromEnvironment($this->sEnvAfter); - } - - $this->bClassesInitialized = true; - } -} diff --git a/setup/itopextension.class.inc.php b/setup/itopextension.class.inc.php index 681f8e4850..a84b69deb4 100644 --- a/setup/itopextension.class.inc.php +++ b/setup/itopextension.class.inc.php @@ -190,4 +190,14 @@ public function MarkAsChosen(bool $bMarkedAsChosen = true): void { $this->bMarkedAsChosen = $bMarkedAsChosen; } + + public function HasCode(): bool + { + return $this->sCode !== ''; + } + + public function HasLabel(): bool + { + return $this->sLabel !== ''; + } } diff --git a/setup/runtimeenv.class.inc.php b/setup/runtimeenv.class.inc.php index b7cd585739..bbe65ae6f2 100644 --- a/setup/runtimeenv.class.inc.php +++ b/setup/runtimeenv.class.inc.php @@ -24,11 +24,9 @@ * @license http://opensource.org/licenses/AGPL-3.0 */ -use Combodo\iTop\PhpParser\Evaluation\PhpExpressionEvaluator; use Combodo\iTop\Setup\FeatureRemoval\SetupAudit; use Combodo\iTop\Setup\ModuleDependency\Module; use Combodo\iTop\Setup\ModuleDiscovery\ModuleFileReader; -use Combodo\iTop\Setup\ModuleDiscovery\ModuleFileReaderException; require_once APPROOT."setup/modulediscovery.class.inc.php"; require_once APPROOT.'setup/modelfactory.class.inc.php'; @@ -71,27 +69,7 @@ protected function GetExtensionMap(): ?iTopExtensionsMap return $this->oExtensionsMap; } - protected function GetDirsToCompile(string $sSourceDir, string $sSourceEnv): array - { - $sSourceDirFull = APPROOT.$sSourceDir; - if (!is_dir($sSourceDirFull)) { - throw new Exception("The source directory '$sSourceDirFull' does not exist (or could not be read)"); - } - $aDirsToCompile = [$sSourceDirFull]; - if (is_dir(APPROOT.'extensions')) { - $aDirsToCompile[] = APPROOT.'extensions'; - } - $sExtraDir = utils::GetDataPath().$this->sBuildEnv.'-modules/'; - if (is_dir($sExtraDir)) { - $aDirsToCompile[] = $sExtraDir; - } - - $aExtraDirs = $this->GetExtraDirsToScan($aDirsToCompile); - $aDirsToCompile = array_merge($aDirsToCompile, $aExtraDirs); - return [$aExtraDirs, $aDirsToCompile]; - } - - public function InitExtensionMap(array $aExtraDirs, Config $oSourceConfig) + protected function InitExtensionMap(Config $oSourceConfig) { if (is_null($this->oExtensionsMap)) { // Actually read the modules available for the build environment, @@ -425,16 +403,6 @@ public function WriteConfigFileSafe($oConfig) chmod($sBuildConfigFile, 0440); // Read-only for owner and group, nothing for others } - /** - * Return an array with extra directories to scan for extensions/modules to install - * @return string[] - */ - protected function GetExtraDirsToScan($aDirs = []) - { - // Do nothing, overload this method if needed - return []; - } - /** * Decide whether or not the given extension is selected for installation * @param iTopExtension $oExtension @@ -465,81 +433,12 @@ public function GetExtraDirsToCompile(string $sSourceDir): array } /** - * Get the installed modules (only the installed ones) + * Get additional modules to compile just before delta * @return \MFModule[] */ - protected function GetMFModulesToCompile($sSourceEnv, $sSourceDir): array + protected function GetAdditionalMFModulesBeforeFinalDeltaToCompile(string $sSourceEnv, array $aScannedModulesRootDirs): array { - list($aExtraDirs, $aDirsToCompile) = $this->GetDirsToCompile($sSourceDir, $sSourceEnv); - $oSourceConfig = new Config(APPCONF.$sSourceEnv.'/'.ITOP_CONFIG_FILE); - $this->InitExtensionMap($aExtraDirs, $oSourceConfig); - $this->GetExtensionMap()->LoadChoicesFromDatabase($oSourceConfig); - foreach ($this->GetExtensionMap()->GetAllExtensions() as $oExtension) { - if ($this->IsExtensionSelected($oExtension)) { - $this->GetExtensionMap()->MarkAsChosen($oExtension->sCode); - } - } - $aModulesToLoad = $this->GetModulesToLoad($this->sFinalEnv, $aDirsToCompile); - $aAvailableModules = $this->AnalyzeInstallation($oSourceConfig, $aDirsToCompile, true, $aModulesToLoad); - - // Do load the required modules - $oDictModule = new MFDictModule('dictionaries', 'iTop Dictionaries', APPROOT.'dictionaries'); - - $aRet = []; - $aRet[$oDictModule->GetName()] = $oDictModule; - - $oFactory = new ModelFactory($aDirsToCompile); - $sDeltaFile = APPROOT.'core/datamodel.core.xml'; - if (file_exists($sDeltaFile)) { - $oCoreModule = new MFCoreModule('core', 'Core Module', $sDeltaFile); - $aRet[$oCoreModule->GetName()] = $oCoreModule; - } - $sDeltaFile = APPROOT.'application/datamodel.application.xml'; - if (file_exists($sDeltaFile)) { - $oApplicationModule = new MFCoreModule('application', 'Application Module', $sDeltaFile); - $aRet[$oApplicationModule->GetName()] = $oApplicationModule; - } - - $aModules = $oFactory->FindModules(); - foreach ($aModules as $oModule) { - $sModule = $oModule->GetName(); - $bIsExtra = $this->GetExtensionMap()->ModuleIsChosenAsPartOfAnExtension($sModule, iTopExtension::SOURCE_REMOTE); - if (array_key_exists($sModule, $aAvailableModules)) { - if (($aAvailableModules[$sModule]['installed_version'] != '') || $bIsExtra && !$oModule->IsAutoSelect()) { //Extra modules are always unless they are 'AutoSelect' - $aRet[$oModule->GetName()] = $oModule; - } - } - } - - $oPhpExpressionEvaluator = new PhpExpressionEvaluator([], ModuleFileReader::STATIC_CALL_AUTOSELECT_WHITELIST); - - // Now process the 'AutoSelect' modules - do { - // Loop while new modules are added... - $bModuleAdded = false; - foreach ($aModules as $oModule) { - if (!array_key_exists($oModule->GetName(), $aRet) && $oModule->IsAutoSelect()) { - SetupInfo::SetSelectedModules($aRet); - try { - $bSelected = $oPhpExpressionEvaluator->ParseAndEvaluateBooleanExpression($oModule->GetAutoSelect()); - if ($bSelected) { - $aRet[$oModule->GetName()] = $oModule; // store the Id of the selected module - $bModuleAdded = true; - } - } catch (ModuleFileReaderException $e) { - //do nothing. logged already - } - } - } - } while ($bModuleAdded); - - $sDeltaFile = utils::GetDataPath().$this->sBuildEnv.'.delta.xml'; - if (file_exists($sDeltaFile)) { - $oDelta = new MFDeltaModule($sDeltaFile); - $aRet[$oDelta->GetName()] = $oDelta; - } - - return $aRet; + return []; } /** @@ -1379,41 +1278,11 @@ public function CopySetupFiles(): void */ public function CompileFrom($sSourceEnv, $bUseSymLinks = null) { - $oSourceConfig = new Config(utils::GetConfigFilePath($sSourceEnv)); - $sSourceDir = $oSourceConfig->Get('source_dir'); - - $sSourceDirFull = APPROOT.$sSourceDir; - // Do load the required modules - // - $oFactory = new ModelFactory($sSourceDirFull); - $aModulesToCompile = $this->GetMFModulesToCompile($sSourceEnv, $sSourceDir); - $oModule = null; - foreach ($aModulesToCompile as $oModule) { - if ($oModule instanceof MFDeltaModule) { - // Just before loading the delta, let's save an image of the datamodel - // in case there is no delta the operation will be done after the end of the loop - $oFactory->SaveToFile(utils::GetDataPath().'datamodel-'.$this->sBuildEnv.'.xml'); - } - $oFactory->LoadModule($oModule); - } - - if (!is_null($oModule) && ($oModule instanceof MFDeltaModule)) { - // A delta was loaded, let's save a second copy of the datamodel - $oFactory->SaveToFile(utils::GetDataPath().'datamodel-'.$this->sBuildEnv.'-with-delta.xml'); - } else { - // No delta was loaded, let's save the datamodel now - $oFactory->SaveToFile(utils::GetDataPath().'datamodel-'.$this->sBuildEnv.'.xml'); - } - - $sBuildDir = APPROOT.'env-'.$this->sBuildEnv; - self::MakeDirSafe($sBuildDir); - $bSkipTempDir = ($this->sFinalEnv != $this->sBuildEnv); // No need for a temporary directory if sBuildEnv is already a temporary directory - $oMFCompiler = new MFCompiler($oFactory, $this->sFinalEnv); - $oMFCompiler->Compile($sBuildDir, $bUseSymLinks, $bSkipTempDir); - - MetaModel::ResetAllCaches($this->sBuildEnv); - - return array_keys($aModulesToCompile); + $oConfig = new Config(utils::GetConfigFilePath($sSourceEnv)); + $this->InitExtensionMap($oConfig); + $aSelectedExtensions = $this->GetExtensionMap()->GetSelectedExtensions($oConfig, [], []); + $aSelectedModules = $this->GetModulesToLoadFromChoices($oConfig, $aSelectedExtensions); + return $this->DoCompile($aSelectedExtensions, [], $aSelectedModules, $bUseSymLinks ?? false); } /** @@ -1422,12 +1291,12 @@ public function CompileFrom($sSourceEnv, $bUseSymLinks = null) * @param array $aSelectedModules * @param boolean $bUseSymbolicLinks * - * @return void + * @return string[] * @throws \ConfigException * @throws \CoreException * */ - public function DoCompile(array $aSelectedExtensionCodes, array $aRemovedExtensionCodes, array $aSelectedModules, bool $bUseSymbolicLinks = false): void + public function DoCompile(array $aSelectedExtensionCodes, array $aRemovedExtensionCodes, array $aSelectedModules, bool $bUseSymbolicLinks = false): array { SetupLog::Info('Compiling data model.'); @@ -1450,45 +1319,16 @@ public function DoCompile(array $aSelectedExtensionCodes, array $aRemovedExtensi SetupUtils::tidydir($sBuildPath); } - $oExtensionsMap = iTopExtensionsMap::GetExtensionsMap($this->GetFinalEnv()); + $oExtensionsMap = iTopExtensionsMap::GetExtensionsMap($this->GetBuildEnv()); // Removed modules are stored as static for FindModules() $oExtensionsMap->DeclareExtensionAsRemoved($aRemovedExtensionCodes); - // Check that all the extensions have a code - $aNoCodeExtensionSourceDirs = []; - $bSetupFailure = false; - $aNoCodeExtensionLabelsThatBreakSetup = []; foreach ($oExtensionsMap->GetAllExtensions() as $oExtension) { - if (in_array($oExtension->sCode, $aSelectedExtensionCodes)) { - $oExtension->MarkAsChosen(); - } - - if (empty($oExtension->sCode)) { - if (empty($oExtension->sLabel)) { - $sExtensionLabel = $oExtension->sSourceDir; - $aNoCodeExtensionSourceDirs [] = $oExtension->sSourceDir; - } else { - $sExtensionLabel = $oExtension->sLabel; - $aNoCodeExtensionSourceDirs [$sExtensionLabel] = $oExtension->sSourceDir; - } - - if ($oExtension->IsMarkedAsChosen()) { - $aNoCodeExtensionLabelsThatBreakSetup[] = $sExtensionLabel; - $bSetupFailure = true; - } - } + $oExtension->MarkAsChosen(in_array($oExtension->sCode, $aSelectedExtensionCodes)); } - if (count($aNoCodeExtensionSourceDirs) > 0) { - if ($bSetupFailure) { - $sErrorMessage = sprintf('Selected extension(s) cannot be installed: Missing extension code (%s)', implode(',', $aNoCodeExtensionLabelsThatBreakSetup)); - $e = new CoreException($sErrorMessage); - SetupLog::Exception($sErrorMessage, $e, null, $aNoCodeExtensionSourceDirs); - throw $e; - } else { - SetupLog::Warning("Non selected extension(s) cannot be installed: Missing extension code", null, $aNoCodeExtensionSourceDirs); - } - } + // Check that all the extensions have a code + $oExtensionsMap->CheckExtensionsValidity(); $oFactory = new ModelFactory($oExtensionsMap->GetScannedModulesRootDirs()); @@ -1507,7 +1347,6 @@ public function DoCompile(array $aSelectedExtensionCodes, array $aRemovedExtensi } $aModules = $oFactory->FindModules(); - foreach ($aModules as $oModule) { $sModule = $oModule->GetName(); if (in_array($sModule, $aSelectedModules)) { @@ -1515,6 +1354,12 @@ public function DoCompile(array $aSelectedExtensionCodes, array $aRemovedExtensi } } + // For unit tests + $aModulesToCompile = $this->GetAdditionalMFModulesBeforeFinalDeltaToCompile($sEnvironment, $oExtensionsMap->GetScannedModulesRootDirs()); + foreach ($aModulesToCompile as $oModule) { + $oFactory->LoadModule($oModule); + } + // Dump the "reference" model, just before loading any actual delta $oFactory->SaveToFile(utils::GetDataPath().'datamodel-'.$sEnvironment.'.xml'); @@ -1540,6 +1385,8 @@ public function DoCompile(array $aSelectedExtensionCodes, array $aRemovedExtensi $sInstanceUUID = utils::CreateUUID('filesystem'); file_put_contents($sInstanceUUIDFile, $sInstanceUUID); } + + return $aSelectedModules; } /** @@ -1637,40 +1484,22 @@ protected static function StartsWith(string $sHaystack, string $sNeedle): bool } /** - * @param string $sSourceEnv - * @param array $aSearchDirs : module/extension dirs to load if they are included in choices + * Return modules based on installation choices+package * - * @return array| null - * @throws \ConfigException - * @throws \CoreException + * @param \Config $oConfig + * @param array|bool $aChoices + * + * @return array|null * @throws \ModuleInstallationException */ - protected function GetModulesToLoad(string $sSourceEnv, array $aSearchDirs): ?array - { - if (is_null($this->GetExtensionMap())) { - return null; - } - - $oSourceConfig = new Config(utils::GetConfigFilePath($sSourceEnv)); - - $aChoices = $this->GetExtensionMap()->GetChoicesFromDatabase($oSourceConfig); - return $this->GetModulesToLoadFromChoices($oSourceConfig, $aChoices, $aSearchDirs); - } - - /** - * Return modules based on installation choices+package -* @param \Config $oConfig -* @param array|bool $aChoices -* @param array $aSearchDirs -* @return array|null -* @throws \ModuleInstallationException - */ - public function GetModulesToLoadFromChoices(Config $oConfig, array|bool $aChoices, array $aSearchDirs): ?array + public function GetModulesToLoadFromChoices(Config $oConfig, array|bool $aChoices): ?array { if (false === $aChoices) { return null; } + $this->InitExtensionMap($oConfig); + $aSearchDirs = $this->GetExtensionMap()->GetScannedModulesRootDirs(); $sSourceDir = $oConfig->Get('source_dir'); $sInstallFilePath = APPROOT.$sSourceDir.'/installation.xml'; @@ -1681,7 +1510,7 @@ public function GetModulesToLoadFromChoices(Config $oConfig, array|bool $aChoice $aExtensionDirs = []; $aFromSelectedExtensionModules = []; foreach ($this->GetExtensionMap()->GetAllExtensions() as $oExtension) { - if ($oExtension->IsMarkedAsChosen() && is_dir($oExtension->sSourceDir)) { + if (in_array($oExtension->sCode, $aChoices) && is_dir($oExtension->sSourceDir)) { $aExtensionDirs [] = $oExtension->sSourceDir; $aFromSelectedExtensionModules = array_merge($aFromSelectedExtensionModules, $oExtension->aModules); } @@ -1697,11 +1526,8 @@ public function GetModulesToLoadFromChoices(Config $oConfig, array|bool $aChoice $aModulesToLoad[] = $sModuleName; } - foreach ($aFromSelectedExtensionModules as $sModuleName) { - if (! in_array($sModuleName, $aModulesToLoad)) { - $aModulesToLoad[] = $sModuleName; - } - } + $this->AnalyzeInstallation($oConfig, $aSearchDirs, true, $aModulesToLoad); + return $aModulesToLoad; } diff --git a/setup/sequencers/DataAuditSequencer.php b/setup/sequencers/DataAuditSequencer.php index 6786be0e88..9abed8272b 100644 --- a/setup/sequencers/DataAuditSequencer.php +++ b/setup/sequencers/DataAuditSequencer.php @@ -64,8 +64,6 @@ public function ExecuteStep($sStep = '', $sInstallComment = null): array case 'compile': $aSelectedModules = $this->oParams->Get('selected_modules', []); - $sSourceDir = $this->oParams->Get('source_dir', 'datamodels/latest'); - $sExtensionDir = $this->oParams->Get('extensions_dir', 'extensions'); $aRemovedExtensionCodes = $this->oParams->Get('removed_extensions', []); $aSelectedExtensionCodes = $this->oParams->Get('selected_extensions', []); $bUseSymbolicLinks = $this->oParams->Get('use_symbolic_links', null) === 'on'; diff --git a/tests/php-unit-tests/src/BaseTestCase/ItopCustomDatamodelTestCase.php b/tests/php-unit-tests/src/BaseTestCase/ItopCustomDatamodelTestCase.php index 7034cb5b5a..a9377efd6c 100644 --- a/tests/php-unit-tests/src/BaseTestCase/ItopCustomDatamodelTestCase.php +++ b/tests/php-unit-tests/src/BaseTestCase/ItopCustomDatamodelTestCase.php @@ -57,7 +57,7 @@ abstract public function GetDatamodelDeltaAbsPath(): string; /** * @return array : dict extensions folders by their code */ - public function GetAdditionalFeaturePaths(): array + public function GetAdditionalExtensionsPaths(): array { return []; } diff --git a/tests/php-unit-tests/src/BaseTestCase/ItopTestCase.php b/tests/php-unit-tests/src/BaseTestCase/ItopTestCase.php index e5e406f33d..2e1b767609 100644 --- a/tests/php-unit-tests/src/BaseTestCase/ItopTestCase.php +++ b/tests/php-unit-tests/src/BaseTestCase/ItopTestCase.php @@ -191,6 +191,7 @@ protected function tearDown(): void } foreach ($this->aFileToClean as $sPath) { + echo "aFileToClean: $sPath \n"; if (is_file($sPath)) { @unlink($sPath); continue; diff --git a/tests/php-unit-tests/src/Service/UnitTestRunTimeEnvironment.php b/tests/php-unit-tests/src/Service/UnitTestRunTimeEnvironment.php index 72d6c2cbf1..2f8c328304 100644 --- a/tests/php-unit-tests/src/Service/UnitTestRunTimeEnvironment.php +++ b/tests/php-unit-tests/src/Service/UnitTestRunTimeEnvironment.php @@ -8,6 +8,7 @@ namespace Combodo\iTop\Test\UnitTest\Service; use Combodo\iTop\Test\UnitTest\ItopCustomDatamodelTestCase; +use Config; use DOMFormatException; use MFCoreModule; use RecursiveDirectoryIterator; @@ -57,17 +58,23 @@ public function CompileFrom($sSourceEnv, $bUseSymLinks = null) SetupUtils::copydir(APPROOT.'/data/'.$sSourceEnv.'-modules', $sDestModulesDir, (true === $bUseSymLinks)); + $aAddedExtensions = []; if ($this->bUseAdditionalFeatures) { foreach ($this->GetExtensionFoldersToAdd() as $sExtensionCode => $sFolderPath) { \SetupLog::Info("ExtensionFoldersToAdd: $sExtensionCode => $sFolderPath"); $sFolderName = basename($sFolderPath); @mkdir($sDestModulesDir.DIRECTORY_SEPARATOR.$sFolderName); SetupUtils::copydir($sFolderPath, $sDestModulesDir.DIRECTORY_SEPARATOR.$sFolderName, (true === $bUseSymLinks)); + $aAddedExtensions[] = $sExtensionCode; } } try { - parent::CompileFrom($sSourceEnv, $bUseSymLinks); + $oConfig = new Config(utils::GetConfigFilePath($sSourceEnv)); + $this->InitExtensionMap($oConfig); + $aSelectedExtensions = $this->GetExtensionMap()->GetSelectedExtensions($oConfig, $aAddedExtensions, []); + $aSelectedModules = $this->GetModulesToLoadFromChoices($oConfig, $aSelectedExtensions); + return $this->DoCompile(array_keys($aSelectedExtensions), [], $aSelectedModules, $bUseSymLinks ?? false); } catch (DOMFormatException $e) { $sFileName = $sSourceEnv.'.delta.xml'; SetupLog::Error(__METHOD__, null, [$sFileName => @file_get_contents(APPROOT.'data/'.$sFileName)]); @@ -108,11 +115,10 @@ public function IsUpToDate() /** * @inheritDoc */ - protected function GetMFModulesToCompile($sSourceEnv, $sSourceDir): array + protected function GetAdditionalMFModulesBeforeFinalDeltaToCompile(string $sSourceEnv, array $aScannedModulesRootDirs): array { \SetupLog::Info(__METHOD__); - $aRet = parent::GetMFModulesToCompile($sSourceEnv, $sSourceDir); - + $aRet = []; if ($this->bUseDelta) { foreach ($this->GetCustomDatamodelFiles() as $sDeltaFile) { $sDeltaId = preg_replace('/[^\d\w]/', '', $sDeltaFile); @@ -214,8 +220,8 @@ public function InitViaItopCustomDatamodelTestCaseClasses() } } - $aExtensionsPaths = $oTestClassInstance->GetAdditionalFeaturePaths(); - $this->aAdditionExtensionFoldersByCode = array_merge($this->aAdditionExtensionFoldersByCode, $aExtensionsPaths); + // Add additional extension paths + $this->aAdditionExtensionFoldersByCode = array_merge($this->aAdditionExtensionFoldersByCode, $oTestClassInstance->GetAdditionalExtensionsPaths()); } } } diff --git a/tests/php-unit-tests/unitary-tests/datamodels/2.x/combodo-data-feature-removal/DataCleanupServiceTest.php b/tests/php-unit-tests/unitary-tests/datamodels/2.x/combodo-data-feature-removal/DataCleanupServiceTest.php index 0d3d04062c..cbf3b54f2e 100644 --- a/tests/php-unit-tests/unitary-tests/datamodels/2.x/combodo-data-feature-removal/DataCleanupServiceTest.php +++ b/tests/php-unit-tests/unitary-tests/datamodels/2.x/combodo-data-feature-removal/DataCleanupServiceTest.php @@ -15,6 +15,8 @@ use Combodo\iTop\Test\UnitTest\ItopDataTestCase; use PHPUnit\Framework\MockObject\MockObject; +require_once __DIR__."/AbstractCleanup.php"; + /** * Unit tests for the CleanupService cf the Combodo Data Feature Removal module. * diff --git a/tests/php-unit-tests/unitary-tests/datamodels/2.x/combodo-data-feature-removal/StaticDeletionPlanTest.php b/tests/php-unit-tests/unitary-tests/datamodels/2.x/combodo-data-feature-removal/StaticDeletionPlanTest.php index 643974c95f..bd0e00a470 100644 --- a/tests/php-unit-tests/unitary-tests/datamodels/2.x/combodo-data-feature-removal/StaticDeletionPlanTest.php +++ b/tests/php-unit-tests/unitary-tests/datamodels/2.x/combodo-data-feature-removal/StaticDeletionPlanTest.php @@ -11,6 +11,7 @@ use Combodo\iTop\DataFeatureRemoval\Service\StaticDeletionPlan; use MetaModel; +require_once __DIR__."/AbstractCleanup.php"; class StaticDeletionPlanTest extends \AbstractCleanup { public function GetDatamodelDeltaAbsPath(): string diff --git a/tests/php-unit-tests/unitary-tests/setup/ExtensionsMapTest.php b/tests/php-unit-tests/unitary-tests/setup/ExtensionsMapTest.php index 1ca9554881..8211cb9953 100644 --- a/tests/php-unit-tests/unitary-tests/setup/ExtensionsMapTest.php +++ b/tests/php-unit-tests/unitary-tests/setup/ExtensionsMapTest.php @@ -3,6 +3,7 @@ namespace Combodo\iTop\Test\UnitTest\Integration; use Combodo\iTop\Test\UnitTest\ItopTestCase; +use CoreException; use iTopExtension; use ItopExtensionsMap; use ModuleDiscovery; @@ -177,6 +178,125 @@ public function testGetScannedModulesRootDirs() self::assertEquals($aExpectedDirs, $oiTopExtensionsMap->GetScannedModulesRootDirs()); } + public function testCheckExtensionsValidityReturnsFalseWhenSelectedExtensionCodeAndLabelAreMissing(): void + { + [$sEnvironment, $sExtensionsDirRelative] = $this->CreateFixtureContext('env-missing-label-'); + + $sInvalidExtensionXml = << + + Test extension without code and label + 1.0.0 + false + + +XML; + $sExtensionsDirAbsolute = APPROOT.$sExtensionsDirRelative; + file_put_contents($sExtensionsDirAbsolute.'/extension.xml', $sInvalidExtensionXml); + + $oExtensionMap = ItopExtensionsMap::GetExtensionsMap($sEnvironment); + + //echo json_encode(array_keys($oExtensionMap->GetAllExtensions()), JSON_PRETTY_PRINT); + + // $this->expectException(CoreException::class); + // $this->expectExceptionMessage("Selected extension(s) cannot be installed: Missing extension code ($sExtensionsDirAbsolute)"); + + self::assertFalse($oExtensionMap->CheckExtensionsValidity(), 'Check extensions validity should have detected an extension without code.'); + } + + public function testCheckExtensionsValidityReturnsFalseWhenSelectedExtensionCodeIsMissing(): void + { + [$sEnvironment, $sExtensionsDirRelative] = $this->CreateFixtureContext('env-missing-label-'); + + $sInvalidExtensionXml = << + + + Test extension without code and label + 1.0.0 + false + + +XML; + $sExtensionsDirAbsolute = APPROOT.$sExtensionsDirRelative; + file_put_contents($sExtensionsDirAbsolute.'/extension.xml', $sInvalidExtensionXml); + + $oExtensionMap = ItopExtensionsMap::GetExtensionsMap($sEnvironment); + + //echo json_encode(array_keys($oExtensionMap->GetAllExtensions()), JSON_PRETTY_PRINT); + + // $this->expectException(CoreException::class); + // $this->expectExceptionMessage("Selected extension(s) cannot be installed: Missing extension code ($sExtensionsDirAbsolute)"); + + self::assertFalse($oExtensionMap->CheckExtensionsValidity(), 'Check extensions validity should have detected an extension without code.'); + } + + public function testCheckExtensionsValidityThrowExceptionWhenSelectedExtensionCodeAndLabelAreMissingAndExtensionIsChosen(): void + { + [$sEnvironment, $sExtensionsDirRelative] = $this->CreateFixtureContext('env-missing-label-'); + + $sInvalidExtensionXml = << + + Test extension without code and label + 1.0.0 + false + + +XML; + $sExtensionsDirAbsolute = APPROOT.$sExtensionsDirRelative; + file_put_contents($sExtensionsDirAbsolute.'/extension.xml', $sInvalidExtensionXml); + + $oExtensionMap = ItopExtensionsMap::GetExtensionsMap($sEnvironment); + $oExtensionMap->MarkAsChosen(''); + + //echo json_encode(array_keys($oExtensionMap->GetAllExtensions()), JSON_PRETTY_PRINT); + + $this->expectException(CoreException::class); + $this->expectExceptionMessage("Selected extension(s) cannot be installed: Missing extension code ($sExtensionsDirAbsolute)"); + + $oExtensionMap->CheckExtensionsValidity(); + } + + public function testCheckExtensionsValidityThrowExceptionWhenSelectedExtensionCodeIsMissingAndExtensionIsChosen(): void + { + [$sEnvironment, $sExtensionsDirRelative] = $this->CreateFixtureContext('env-missing-label-'); + + $sInvalidExtensionXml = << + + + Test extension without code and label + 1.0.0 + false + + +XML; + $sExtensionsDirAbsolute = APPROOT.$sExtensionsDirRelative; + file_put_contents($sExtensionsDirAbsolute.'/extension.xml', $sInvalidExtensionXml); + + $oExtensionMap = ItopExtensionsMap::GetExtensionsMap($sEnvironment); + $oExtensionMap->MarkAsChosen(''); + + //echo json_encode(array_keys($oExtensionMap->GetAllExtensions()), JSON_PRETTY_PRINT); + + $this->expectException(CoreException::class); + $this->expectExceptionMessage("Selected extension(s) cannot be installed: Missing extension code (Broken extension)"); + + $oExtensionMap->CheckExtensionsValidity(); + } + + private function CreateFixtureContext(string $sEnvPrefix): array + { + $sEnvironment = str_replace('.', '-', uniqid($sEnvPrefix, true)); + $sExtensionsDirRelative = 'data/'.$sEnvironment.'-modules'; + + mkdir(APPROOT.$sExtensionsDirRelative, 0777, true); + $this->aFileToClean[] = APPROOT.$sExtensionsDirRelative; + + return [$sEnvironment, $sExtensionsDirRelative]; + } + public function SerializeExtensionMap(iTopExtensionsMap $oiTopExtensionsMap): array { $aRes = []; diff --git a/tests/php-unit-tests/unitary-tests/setup/RunTimeEnvironmentTest.php b/tests/php-unit-tests/unitary-tests/setup/RunTimeEnvironmentTest.php index fee866700d..81301843ba 100644 --- a/tests/php-unit-tests/unitary-tests/setup/RunTimeEnvironmentTest.php +++ b/tests/php-unit-tests/unitary-tests/setup/RunTimeEnvironmentTest.php @@ -2,10 +2,15 @@ namespace Combodo\iTop\Test\UnitTest\Setup; +use Combodo\iTop\DataFeatureRemoval\Service\DataFeatureRemoverExtensionService; use Combodo\iTop\Test\UnitTest\ItopTestCase; +use Config; +use CoreException; use DOMFormatException; use Exception; +use iTopExtensionsMap; use RunTimeEnvironment; +use utils; class RunTimeEnvironmentTest extends ItopTestCase { @@ -15,52 +20,7 @@ protected function setUp(): void $this->RequireOnceItopFile('/setup/runtimeenv.class.inc.php'); } - public function testDoCompileDoesNotThrowWhenUnselectedExtensionCodeIsMissing(): void - { - [$sEnvironment, $sExtensionsDirRelative] = $this->CreateFixtureContext('env-missing-code-'); - - $sInvalidExtensionXml = << - - - Test extension without code - 1.0.0 - false - - -XML; - file_put_contents(APPROOT.$sExtensionsDirRelative.'/extension.xml', $sInvalidExtensionXml); - $oRunTimeEnvironment = $this->CreateRunTimeEnvironment($sEnvironment); - - //early DOMFormatException to avoid any real compilation - $this->expectException(DOMFormatException::class); - $oRunTimeEnvironment->DoCompile([], [], []); - } - - public function testDoCompileThrowsWhenSelectedExtensionCodeIsMissing(): void - { - [$sEnvironment, $sExtensionsDirRelative] = $this->CreateFixtureContext('env-missing-code-'); - - $sInvalidExtensionXml = << - - - Test extension without code - 1.0.0 - false - - -XML; - file_put_contents(APPROOT.$sExtensionsDirRelative.'/extension.xml', $sInvalidExtensionXml); - $oRunTimeEnvironment = $this->CreateRunTimeEnvironment($sEnvironment); - - $this->expectException(Exception::class); - $this->expectExceptionMessage("Selected extension(s) cannot be installed: Missing extension code (Broken extension)"); - - $oRunTimeEnvironment->DoCompile([""], [], []); - } - - public function testDoCompileThrowsWhenSelectedExtensionCodeAndLabelAreMissing(): void + public function testDoCompileCallCheckExtensionsValidity(): void { [$sEnvironment, $sExtensionsDirRelative] = $this->CreateFixtureContext('env-missing-label-'); @@ -75,12 +35,17 @@ public function testDoCompileThrowsWhenSelectedExtensionCodeAndLabelAreMissing() XML; $sExtensionsDirAbsolute = APPROOT.$sExtensionsDirRelative; file_put_contents($sExtensionsDirAbsolute.'/extension.xml', $sInvalidExtensionXml); - $oRunTimeEnvironment = $this->CreateRunTimeEnvironment($sEnvironment); - $this->expectException(Exception::class); - $this->expectExceptionMessage("Selected extension(s) cannot be installed: Missing extension code ($sExtensionsDirAbsolute)"); + $oRuntimeEnvironment = $this->CreateRunTimeEnvironment($sEnvironment); + $oExtensionMap = $this->createMock(ItopExtensionsMap::class); + $oExtensionMap->expects($this->once())->method('GetAllExtensions')->willReturn([]); + + $this->SetNonPublicStaticProperty(iTopExtensionsMap::class, 'aInstancesByEnvironment', [$oRuntimeEnvironment->GetBuildEnv() => $oExtensionMap]); + + $this->expectException(CoreException::class); - $oRunTimeEnvironment->DoCompile([""], [], [], false); + $oExtensionMap->expects($this->once())->method('CheckExtensionsValidity')->willThrowException(new CoreException('')); + $oRuntimeEnvironment->DoCompile([""], [], [], false); } private function CreateFixtureContext(string $sEnvPrefix): array diff --git a/tests/php-unit-tests/unitary-tests/setup/feature_removal/SetupAuditTest.php b/tests/php-unit-tests/unitary-tests/setup/feature_removal/SetupAuditTest.php index 7fa90bc60b..383d9a3986 100644 --- a/tests/php-unit-tests/unitary-tests/setup/feature_removal/SetupAuditTest.php +++ b/tests/php-unit-tests/unitary-tests/setup/feature_removal/SetupAuditTest.php @@ -2,28 +2,28 @@ namespace Combodo\iTop\Test\UnitTest\Setup\FeatureRemoval; -use Combodo\iTop\Setup\FeatureRemoval\DryRemovalRuntimeEnvironment; -use Combodo\iTop\Setup\FeatureRemoval\InplaceSetupAudit; +use Combodo\iTop\DataFeatureRemoval\Service\DataFeatureRemoverExtensionService; use Combodo\iTop\Setup\FeatureRemoval\ModelReflectionSerializer; use Combodo\iTop\Setup\FeatureRemoval\SetupAudit; use Combodo\iTop\Test\UnitTest\ItopCustomDatamodelTestCase; use Combodo\iTop\Test\UnitTest\Service\UnitTestRunTimeEnvironment; +use Config; use MetaModel; +use RunTimeEnvironment; use SetupUtils; +use utils; class SetupAuditTest extends ItopCustomDatamodelTestCase { public const ENVT = 'php-unit-extensionremoval-tests'; - private ?string $sDirPathToRemoveFromExtensionFolder = null; - public function GetDatamodelDeltaAbsPath(): string { //no delta: empty path provided return ""; } - public function GetAdditionalFeaturePaths(): array + public function GetAdditionalExtensionsPaths(): array { $aFeaturePaths = []; foreach (glob(__DIR__."/additional_features/*", GLOB_ONLYDIR) as $aFeaturePath) { @@ -34,25 +34,21 @@ public function GetAdditionalFeaturePaths(): array return $aFeaturePaths; } + protected function tearDown(): void + { + parent::tearDown(); + } + protected function setUp(): void { static::LoadRequiredItopFiles(); $this->oEnvironment = new UnitTestRunTimeEnvironment(self::ENVT); $this->oEnvironment->bUseDelta = false; $this->oEnvironment->bUseAdditionalFeatures = true; + parent::setUp(); $this->RequireOnceItopFile('/setup/feature_removal/SetupAudit.php'); - $this->RequireOnceItopFile('/setup/feature_removal/InplaceSetupAudit.php'); - $this->RequireOnceItopFile('/setup/feature_removal/DryRemovalRuntimeEnvironment.php'); - } - - protected function tearDown(): void - { - parent::tearDown(); - if (!is_null($this->sDirPathToRemoveFromExtensionFolder) && is_dir($this->sDirPathToRemoveFromExtensionFolder)) { - SetupUtils::rrmdir($this->sDirPathToRemoveFromExtensionFolder); - } } public function GetTestEnvironment(): string @@ -60,14 +56,22 @@ public function GetTestEnvironment(): string return self::ENVT; } - public function testComputeDryRemoval() + public function testRemovedExtensionsAreListedInSetupAudit() { - $this->sDirPathToRemoveFromExtensionFolder = APPROOT.'/extensions/finalclass_ext3'; - SetupUtils::copydir(__DIR__.'/other_features/finalclass_ext3', $this->sDirPathToRemoveFromExtensionFolder); + $sAdditionalExtensionDir = APPROOT.'/extensions/finalclass_ext3'; + SetupUtils::copydir(__DIR__.'/other_features/finalclass_ext3', $sAdditionalExtensionDir); + $this->aFileToClean[] = $sAdditionalExtensionDir; + clearstatcache(); - $oDryRemovalRuntimeEnvt = new DryRemovalRuntimeEnvironment($this->GetTestEnvironment(), ['finalclass_ext3' => 'Ext For Test3'], ['nominal_ext1', 'finalclass_ext2']); - $oDryRemovalRuntimeEnvt->CompileFrom($this->GetTestEnvironment()); + $oRuntimeEnvironment = new RunTimeEnvironment($this->GetTestEnvironment(), false); + $oRuntimeEnvironment->CopySetupFiles(); + $oConfig = new Config(utils::GetConfigFilePath($this->GetTestEnvironment())); + $aRemovedExtensions = ['nominal_ext1', 'finalclass_ext2']; + $aSelectedExtensions = DataFeatureRemoverExtensionService::GetInstance()->GetExtensionMap()->GetSelectedExtensions($oConfig, ['finalclass_ext1', 'finalclass_ext3'], $aRemovedExtensions); + $aSelectedModules = $oRuntimeEnvironment->GetModulesToLoadFromChoices($oConfig, $aSelectedExtensions); + + $oRuntimeEnvironment->DoCompile($aSelectedExtensions, $aRemovedExtensions, $aSelectedModules); $oSetupAudit = new SetupAudit($this->GetTestEnvironment()); @@ -97,25 +101,13 @@ public function testComputeDryRemoval() } } - public function testGetRemovedClassesFromSetupWizard() - { - $sEnv = MetaModel::GetEnvironment(); - - $aClassesBeforeRemoval = ModelReflectionSerializer::GetInstance()->GetModelFromEnvironment($sEnv); - $aClassesBeforeRemoval[] = "GabuZomeu"; - - $oSetupAudit = new InplaceSetupAudit($aClassesBeforeRemoval, $sEnv); - $oSetupAudit->ComputeClasses(); - $this->assertEquals(["GabuZomeu"], $oSetupAudit->GetRemovedClasses()); - } - public function testGetIssues() { $sUID = "AuditExtensionsCleanupRules_".uniqid(); $oOrg = $this->CreateOrganization($sUID); $this->createObject('FinalClassFeature1Module1MyFinalClassFromLocation', ['org_id' => $oOrg->GetKey(), 'name' => $sUID, 'name2' => uniqid()]); - $oSetupAudit = new SetupAudit(MetaModel::GetEnvironment()); + $oSetupAudit = new SetupAudit($this->GetTestEnvironment()); $aRemovedClasses = [ "Feature1Module1MyClass", "FinalClassFeature1Module1MyClass", @@ -141,7 +133,7 @@ public function testAuditExtensionsCleanupRulesFailASAP() $this->createObject('FinalClassFeature1Module1MyFinalClassFromLocation', ['org_id' => $oOrg->GetKey(), 'name' => $sUID, 'name2' => uniqid()]); $this->createObject('FinalClassFeature2Module1MyFinalClassFromLocation', ['org_id' => $oOrg->GetKey(), 'name' => $sUID, 'name2' => uniqid()]); - $oSetupAudit = new SetupAudit(MetaModel::GetEnvironment()); + $oSetupAudit = new SetupAudit($this->GetTestEnvironment()); $aRemovedClasses = [ "Feature1Module1MyClass", "FinalClassFeature1Module1MyClass",