mirror of
https://github.com/Combodo/iTop.git
synced 2026-04-25 11:38:44 +02:00
save tmp work before trying to fetch other wml deps
This commit is contained in:
66
tests/php-unit-tests/integration-tests/XmlModule.php
Normal file
66
tests/php-unit-tests/integration-tests/XmlModule.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest;
|
||||
|
||||
class XmlModule {
|
||||
public string $sModuleName;
|
||||
public array $aDependencyModulesNames=[];
|
||||
public array $aAllDependencyModulesNames=[];
|
||||
public array $aXMlMetaInfosByModuleNames=[];
|
||||
|
||||
public function __construct(string $sModuleName)
|
||||
{
|
||||
$this->sModuleName = $sModuleName;
|
||||
}
|
||||
|
||||
public function AddDependency(string $sXmlMetaInfoUID, string $sDefiningModuleName, array $aModules)
|
||||
{
|
||||
if ($sDefiningModuleName===$this->sModuleName){
|
||||
return;
|
||||
}
|
||||
|
||||
/*$aLog = ['itop-bridge-datacenter-mgmt-services', 'itop-datacenter-mgmt'];
|
||||
if (in_array($sDefiningModuleName, $aLog) && in_array($this->sModuleName, $aLog)){
|
||||
echo $this->sModuleName . " => $sDefiningModuleName === " . $sXmlMetaInfoUID . "\n";
|
||||
}*/
|
||||
|
||||
if (! array_key_exists($sDefiningModuleName, $this->aXMlMetaInfosByModuleNames)){
|
||||
$this->aXMlMetaInfosByModuleNames[$sDefiningModuleName]=[$sXmlMetaInfoUID];
|
||||
} else {
|
||||
if (! in_array($sXmlMetaInfoUID, $this->aXMlMetaInfosByModuleNames[$sDefiningModuleName])){
|
||||
$this->aXMlMetaInfosByModuleNames[$sDefiningModuleName][]=$sXmlMetaInfoUID;
|
||||
}
|
||||
}
|
||||
|
||||
if (! array_key_exists($sDefiningModuleName, $this->aDependencyModulesNames)){
|
||||
/** @var XmlModule $oXmlModule */
|
||||
$oXmlModule = $aModules[$sDefiningModuleName];
|
||||
$this->aDependencyModulesNames[$sDefiningModuleName]=$oXmlModule;
|
||||
}
|
||||
}
|
||||
|
||||
public function Depends(string $sModuleName) : bool
|
||||
{
|
||||
return array_key_exists($sModuleName, $this->aDependencyModulesNames) || array_key_exists($sModuleName, $this->aXMlMetaInfosByModuleNames);
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return sprintf("%s (%s)", $this->sModuleName, implode('|', array_keys($this->aDependencyModulesNames)));
|
||||
}
|
||||
|
||||
public function CompleteModuleDependencies(array $aAllModules) : void
|
||||
{
|
||||
foreach ($this->aDependencyModulesNames as $sDirectDependency => $oXmlMod){
|
||||
/** @var \Combodo\iTop\Test\UnitTest\XmlModule $oDirectDepXmlModule */
|
||||
$oDirectDepXmlModule = $aAllModules[$sDirectDependency];
|
||||
foreach ($oDirectDepXmlModule->aDependencyModulesNames as $sDirectDependency2 => $oXmlMod2){
|
||||
if (! array_key_exists($sDirectDependency2, $this->aDependencyModulesNames) && ! in_array($sDirectDependency2, $this->aAllDependencyModulesNames)){
|
||||
$this->aAllDependencyModulesNames[]=$sDirectDependency2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
29
tests/php-unit-tests/integration-tests/XmlModuleMetaInfo.php
Normal file
29
tests/php-unit-tests/integration-tests/XmlModuleMetaInfo.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest;
|
||||
|
||||
class XmlModuleMetaInfo {
|
||||
public string $sLastNodeId;
|
||||
public string $sNodeName;
|
||||
public string $sPath;
|
||||
public string $sDelta;
|
||||
|
||||
public function __construct(string $sLastNodeId, string $sNodeName, string $sPath, string $sDelta)
|
||||
{
|
||||
$this->sLastNodeId = $sLastNodeId;
|
||||
$this->sNodeName = $sNodeName;
|
||||
$this->sPath = $sPath;
|
||||
$this->sDelta = $sDelta;
|
||||
}
|
||||
|
||||
public function IsDefine() : bool {
|
||||
return
|
||||
$this->sDelta === 'define_if_not_exists'
|
||||
|| $this->sDelta === 'define';
|
||||
}
|
||||
|
||||
public function GetUID() : string
|
||||
{
|
||||
return $this->sNodeName . '_' . $this->sLastNodeId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,309 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2024 Combodo SAS
|
||||
* This file is part of iTop.
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Integration;
|
||||
|
||||
use ApplicationException;
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
use Combodo\iTop\Test\UnitTest\XmlModule;
|
||||
use Combodo\iTop\Test\UnitTest\XmlModuleMetaInfo;
|
||||
use utils;
|
||||
|
||||
require_once __DIR__ . '/XmlModuleMetaInfo.php';
|
||||
require_once __DIR__ . '/XmlModule.php';
|
||||
|
||||
use ModuleInstallerAPI;
|
||||
/**
|
||||
* @package Combodo\iTop\Test\UnitTest\Setup
|
||||
* @group beforeSetup
|
||||
*/
|
||||
class iTopModulesDependencyTest extends ItopTestCase {
|
||||
/**
|
||||
* define
|
||||
* define_if_not_exists
|
||||
* delete
|
||||
* force
|
||||
* if_exists
|
||||
* must_exist
|
||||
* redefine
|
||||
*/
|
||||
|
||||
private array $aFilesToRemove = [];
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp(); // TODO: Change the autogenerated stub
|
||||
|
||||
require_once APPROOT."setup/modulediscovery.class.inc.php";
|
||||
require_once(APPROOT.'/setup/moduleinstaller.class.inc.php');
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
parent::tearDown(); // TODO: Change the autogenerated stub
|
||||
foreach ($this->aFilesToRemove as $sTmpFile){
|
||||
@unlink($sTmpFile);
|
||||
}
|
||||
}
|
||||
|
||||
private array $aAllDmFiles=[];
|
||||
public function ListDatamodelFiles() : array
|
||||
{
|
||||
if (count($this->aAllDmFiles)==0){
|
||||
$aGlobPAtterns = [
|
||||
APPROOT.'datamodels/2.x/*/datamodel.*.xml',
|
||||
APPROOT.'application/*.xml',
|
||||
APPROOT.'core/*.xml',
|
||||
];
|
||||
|
||||
foreach ($aGlobPAtterns as $sPattern) {
|
||||
$this->aAllDmFiles = array_merge($this->aAllDmFiles, glob($sPattern));
|
||||
}
|
||||
}
|
||||
return $this->aAllDmFiles;
|
||||
}
|
||||
|
||||
private array $aModules=[];
|
||||
|
||||
public function FetchAllDependenciesViaDM()
|
||||
{
|
||||
foreach ($this->ListDatamodelFiles() as $sFile) {
|
||||
$this->FetchXmlMetaInfo($sFile);
|
||||
}
|
||||
|
||||
foreach ($this->aDefineNodes as $sKey => $aModules){
|
||||
foreach ($aModules as $sModuleName){
|
||||
if (! array_key_exists($sModuleName, $this->aModules)){
|
||||
$this->aModules[$sModuleName] = new XmlModule($sModuleName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->aDependencyNodes as $sKey => $aModules){
|
||||
foreach ($aModules as $sModuleName){
|
||||
/** @var XmlModule $oCurrentXmlModule */
|
||||
$oCurrentXmlModule = $this->aModules[$sModuleName] ?? null;
|
||||
if (is_null($oCurrentXmlModule)){
|
||||
$oCurrentXmlModule = new XmlModule($sModuleName);
|
||||
$this->aModules[$sModuleName] = $oCurrentXmlModule;
|
||||
}
|
||||
|
||||
$aDefiningModules = $this->aDefineNodes[$sKey] ?? null;
|
||||
if (is_null($aDefiningModules)){
|
||||
//throw new \Exception("weard behaviour $sKey");
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($aDefiningModules as $sDefiningModuleName){
|
||||
$oCurrentXmlModule->AddDependency($sKey, $sDefiningModuleName, $this->aModules);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->OrderModules();
|
||||
$this->CompleteModuleDependencies();
|
||||
}
|
||||
|
||||
private array $aModulesDepsByModuleName=[];
|
||||
public function testModules()
|
||||
{
|
||||
$this->FetchAllDependenciesViaDM();
|
||||
|
||||
$aDirsToScan = [
|
||||
APPROOT.'datamodels/2.x',
|
||||
APPROOT.'extensions',
|
||||
APPROOT.'data/production-modules',
|
||||
];
|
||||
|
||||
foreach(\ModuleDiscovery::GetAvailableModules($aDirsToScan) as $sModuleId => $aData) {
|
||||
list($sModuleName, $sVersion) = \ModuleDiscovery::GetModuleName($sModuleId);
|
||||
$aCurrentDeps = $aData['dependencies'] ?? [];
|
||||
$this->aModulesDepsByModuleName[$sModuleName] = $aCurrentDeps;
|
||||
}
|
||||
|
||||
$aErrors=[];
|
||||
/** @var XmlModule $oXmlModule */
|
||||
foreach ($this->aModules as $sModuleName => $oXmlModule) {
|
||||
$aCurrentDeps = $this->aModulesDepsByModuleName[$sModuleName] ?? [];
|
||||
$aModuleErrors=[];
|
||||
foreach ($oXmlModule->aDependencyModulesNames as $sDepModuleName => $oXmlModule2){
|
||||
if ($sDepModuleName==="core"||$sDepModuleName==="application"){
|
||||
continue;
|
||||
}
|
||||
|
||||
$sXmlUIDs = implode('|', $oXmlModule->aXMlMetaInfosByModuleNames[$sDepModuleName]);
|
||||
foreach ($aCurrentDeps as $sDepString){
|
||||
$oModuleDependency = new \ModuleDependency($sDepString);
|
||||
if (! in_array($sDepModuleName, $oModuleDependency->GetPotentialPrerequisiteModuleNames())){
|
||||
$bResolved=false;
|
||||
foreach ($oModuleDependency->GetPotentialPrerequisiteModuleNames() as $sPotentialDepModuleName){
|
||||
/** @var XmlModule $oXmlModule2 */
|
||||
$oXmlModule2 = $this->aModules[$sPotentialDepModuleName]??null;
|
||||
|
||||
if (! is_null($oXmlModule2) && $oXmlModule2->Depends($sDepModuleName)){
|
||||
$bResolved=true;
|
||||
}
|
||||
}
|
||||
if (! $bResolved){
|
||||
$aModuleErrors []= "$sModuleName depends on $sDepModuleName but missing in module dependencies: " . implode('|', $aCurrentDeps) . ". ($sXmlUIDs)";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count($aModuleErrors)){
|
||||
$aErrors[$sModuleName]=$aModuleErrors;
|
||||
}
|
||||
}
|
||||
|
||||
$this->assertEquals(0, count($aErrors), var_export($aErrors, true));
|
||||
|
||||
}
|
||||
|
||||
public function testGetMetaInfo()
|
||||
{
|
||||
$this->FetchXmlMetaInfo(APPROOT . 'core/datamodel.core.xml');
|
||||
|
||||
$this->assertEquals("core", $this->sCurrentModule);
|
||||
$this->assertEquals(22, count($this->aDefineNodes));
|
||||
$this->assertEquals(0, count($this->aDependencyNodes));
|
||||
//var_dump($this->aDefineNodes);
|
||||
$this->assertEquals([], $this->aDefineNodes);
|
||||
$this->assertEquals([], $this->aDependencyNodes);
|
||||
}
|
||||
|
||||
private string $sCurrentModule;
|
||||
private array $aDefineNodes;
|
||||
private array $aDependencyNodes;
|
||||
|
||||
private function GetModuleSuffix($sFile) : string
|
||||
{
|
||||
if (! preg_match('|.*datamodel\.([^\.]+)\.xml|', $sFile, $aMatches)){
|
||||
throw new \Exception("Regexp issue: $sFile");
|
||||
}
|
||||
return $aMatches[1];
|
||||
}
|
||||
|
||||
public function FetchXmlMetaInfo($sFile) : void {
|
||||
$oDomDoc = new \DOMDocument('1.0', 'UTF-8');
|
||||
libxml_clear_errors();
|
||||
$oDomDoc->loadXml(file_get_contents($sFile));
|
||||
$aErrors = libxml_get_errors();
|
||||
if (count($aErrors) > 0)
|
||||
{
|
||||
throw new \Exception("Malformed XML");
|
||||
}
|
||||
|
||||
$this->sCurrentModule = $this->GetModuleSuffix($sFile);
|
||||
|
||||
if (! isset($this->aDefineNodes)){
|
||||
$this->aDefineNodes=[];
|
||||
}
|
||||
|
||||
if (! isset($this->aDependencyNodes)){
|
||||
$this->aDependencyNodes=[];
|
||||
}
|
||||
|
||||
foreach ($oDomDoc->childNodes as $oDomNode){
|
||||
$this->FetchMetaInfo($oDomDoc->childNodes);
|
||||
}
|
||||
}
|
||||
|
||||
private function FetchMetaInfo(\DOMNodeList $oDomNodeList, ?string $sPath=null)
|
||||
{
|
||||
/** @var \DOMNode $oDomNode */
|
||||
foreach ($oDomNodeList as $oDomNode) {
|
||||
/** @var \DOMAttr $oDelta */
|
||||
$oDelta = $oDomNode->attributes['_delta'] ?? null;
|
||||
/** @var \DOMAttr $oId */
|
||||
$oId = $oDomNode->attributes['id'] ?? null;
|
||||
|
||||
if (!is_null($oDelta) && ! is_null($oId)) {
|
||||
$sId = $oId->nodeValue;
|
||||
$sPath = $sPath ? $sPath . "->" . $sId : $sId;
|
||||
$oXmlModuleMetaInfo = new XmlModuleMetaInfo($sId, $oDomNode->nodeName, $sPath, $oDelta->nodeValue);
|
||||
$sKey = $oXmlModuleMetaInfo->GetUID();
|
||||
if ($oXmlModuleMetaInfo->IsDefine()){
|
||||
if (array_key_exists($sKey, $this->aDefineNodes)){
|
||||
$this->aDefineNodes[$sKey][]=$this->sCurrentModule;
|
||||
} else {
|
||||
$this->aDefineNodes[$sKey]=[ $this->sCurrentModule ];
|
||||
}
|
||||
} else {
|
||||
if (array_key_exists($sKey, $this->aDependencyNodes)){
|
||||
$this->aDependencyNodes[$sKey][]=$this->sCurrentModule;
|
||||
} else {
|
||||
$this->aDependencyNodes[$sKey]=[ $this->sCurrentModule ];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->FetchMetaInfo($oDomNode->childNodes, $sPath);
|
||||
}
|
||||
}
|
||||
|
||||
private function OrderModules()
|
||||
{
|
||||
$aModuleDepsCount = [];
|
||||
/** @var XmlModule $oXmlModule */
|
||||
foreach ($this->aModules as $oXmlModule) {
|
||||
$aModuleDepsCount[$oXmlModule->sModuleName] = count($oXmlModule->aDependencyModulesNames);
|
||||
}
|
||||
|
||||
$aOrderModules=[];
|
||||
while (count($aModuleDepsCount)>0) {
|
||||
asort($aModuleDepsCount);
|
||||
|
||||
foreach ($aModuleDepsCount as $sModuleName => $iCount){
|
||||
if ($iCount>0){
|
||||
/** @var XmlModule $oXmlModule */
|
||||
$oXmlModule = $this->aModules[$sModuleName];
|
||||
/*var_dump((string)$oXmlModule);
|
||||
var_dump((string)$this->aModules['itop-datacenter-mgmt']);
|
||||
var_dump((string)$this->aModules['itop-config-mgmt']);
|
||||
var_dump($aModuleDepsCount);*/
|
||||
//var_dump($this->aModules['itop-bridge-cmdb-services']->aXMlMetaInfosByModuleNames["itop-bridge-cmdb-ticket"]);
|
||||
//var_dump($this->aModules['itop-bridge-cmdb-ticket']->aXMlMetaInfosByModuleNames["itop-bridge-cmdb-services"]);
|
||||
throw new \Exception("still deps with $sModuleName");
|
||||
}
|
||||
|
||||
unset($aModuleDepsCount[$sModuleName]);
|
||||
$aOrderModules[$sModuleName] = $this->aModules[$sModuleName];
|
||||
break;
|
||||
}
|
||||
|
||||
//echo "$sModuleName\n";
|
||||
foreach ($aModuleDepsCount as $sStillToProcessModuleName => $c){
|
||||
/** @var XmlModule $oXmlStillToProcessModule */
|
||||
$oXmlStillToProcessModule = $this->aModules[$sStillToProcessModuleName];
|
||||
if ($oXmlStillToProcessModule->Depends($sModuleName)){
|
||||
$aModuleDepsCount[$sStillToProcessModuleName] = $c - 1 ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->aModules = $aOrderModules;
|
||||
}
|
||||
|
||||
private function CompleteModuleDependencies()
|
||||
{
|
||||
/** @var XmlModule $oXmlModule */
|
||||
foreach ($this->aModules as $oXmlModule) {
|
||||
$oXmlModule->CompleteModuleDependencies($this->aModules);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user