N°797 - Delete of DataSynchro incomplete

This commit is contained in:
Benjamin Dalsass
2024-03-06 17:05:35 +01:00
parent 4d1f8e5704
commit 34c4d753d3
5 changed files with 55 additions and 16 deletions

View File

@@ -73,6 +73,11 @@ define('DEL_SILENT', 2);
*/
define('DEL_MOVEUP', 3);
/**
* Do nothing at least automatically
*/
define('DEL_NONE', 4);
/**
* For Link sets: tracking_level

View File

@@ -5361,16 +5361,19 @@ abstract class DBObject implements iDisplay
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
*/
protected function GetReferencingObjects($bAllowAllData = false)
protected function GetReferencingObjectsForDeletion($bAllowAllData = false)
{
$aDependentObjects = array();
$aRererencingMe = MetaModel::EnumReferencingClasses(get_class($this));
foreach($aRererencingMe as $sRemoteClass => $aExtKeys)
{
/** @var \AttributeExternalKey $oExtKeyAttDef */
foreach($aExtKeys as $sExtKeyAttCode => $oExtKeyAttDef)
{
// skip if external key doesn't require the deletion cascading
if($oExtKeyAttDef->GetDeletionPropagationOption() === DEL_NONE) continue;
// skip if this external key is behind an external field
/** @var \AttributeDefinition $oExtKeyAttDef */
if (!$oExtKeyAttDef->IsExternalKey(EXTKEY_ABSOLUTE)) continue;
$oSearch = new DBObjectSearch($sRemoteClass);
@@ -5434,13 +5437,11 @@ abstract class DBObject implements iDisplay
$this->CheckToWriteForTargetObjects(true);
$oDeletionPlan->SetDeletionIssues($this, $this->m_aDeleteIssues, $this->m_bSecurityIssue);
$aDependentObjects = $this->GetReferencingObjects(true /* allow all data */);
// Getting and setting time limit are not symmetric:
// www.php.net/manual/fr/function.set-time-limit.php#72305
$iPreviousTimeLimit = ini_get('max_execution_time');
foreach ($aDependentObjects as $aPotentialDeletes)
foreach ($this->GetReferencingObjectsForDeletion(true /* allow all data */) as $aPotentialDeletes)
{
foreach ($aPotentialDeletes as $aData)
{

View File

@@ -2953,7 +2953,7 @@ CSS;
if (($sAttType == 'AttributeExternalKey') || ($sAttType == 'AttributeHierarchicalKey'))
{
$sOnTargetDel = $oField->GetChildText('on_target_delete');
if (($sOnTargetDel == 'DEL_AUTO') || ($sOnTargetDel == 'DEL_SILENT'))
if (($sOnTargetDel == 'DEL_AUTO') || ($sOnTargetDel == 'DEL_SILENT') || ($sOnTargetDel == 'DEL_NONE'))
{
$sTargetClass = $oField->GetChildText('target_class');
$aLinkToClasses[$oClass->getAttribute('id')][] = $sTargetClass;

View File

@@ -1037,6 +1037,11 @@ EOF
$sDropTable = "DROP TABLE IF EXISTS `$sTable`"; // Do not fail if the table is already deleted (corrupted database)
CMDBSource::Query($sDropTable);
// TO DO - check that triggers get dropped with the table
$sSyncReplicaTable = MetaModel::DBGetTable(SynchroReplica::class);
$sSyncSourceIDColumn = MetaModel::GetAttributeDef(SynchroReplica::class, 'sync_source_id');
$sSqlDeleteReplica = "DELETE FROM `$sSyncReplicaTable` WHERE {$sSyncSourceIDColumn->Get('sql')} = '{$this->GetKey()}'";
CMDBSource::Query($sSqlDeleteReplica);
}
/**
@@ -1991,7 +1996,7 @@ class SynchroReplica extends DBObject implements iDisplay
'allowed_values' => null,
'sql' => 'sync_source_id',
'is_null_allowed' => false,
'on_target_delete' => DEL_SILENT,
'on_target_delete' => DEL_NONE,
'depends_on' => array(),
)));
MetaModel::Init_AddAttribute(new AttributeExternalField('base_class',
@@ -2156,13 +2161,9 @@ class SynchroReplica extends DBObject implements iDisplay
}
// Overload the deletion -> the replica has been created by the mean of a trigger,
// it will be deleted by the mean of a trigger too
// it will be deleted by SynchroDataSource::AfterDelete
protected function DBDeleteSingleObject()
{
$oKPI = new ExecutionKPI();
$this->OnDelete();
$oKPI->ComputeStatsForExtension($this, 'OnDelete');
if (!MetaModel::DBIsReadOnly())
{
$oDataSource = MetaModel::GetObject('SynchroDataSource', $this->Get('sync_source_id'), false);
@@ -2176,10 +2177,7 @@ class SynchroReplica extends DBObject implements iDisplay
// else the whole datasource has probably been already deleted
}
$this->AfterDelete();
$this->m_bIsInDB = false;
$this->m_iKey = null;
parent::DBDeleteSingleObject();
}
public function SetLastError($sMessage, $oException = null)

View File

@@ -15,6 +15,7 @@
namespace Combodo\iTop\Test\UnitTest\Synchro;
use CMDBSource;
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
use DBObjectSearch;
use DBObjectSet;
@@ -363,6 +364,8 @@ class DataSynchroTest extends ItopDataTestCase
}
}
}
return $oDataSource;
}
private function GetNominalUsecaseData(){
@@ -423,6 +426,38 @@ class DataSynchroTest extends ItopDataTestCase
$this->RunDataSynchroTest($aUserLoginUsecase);
}
public function testDataSynchroDeletionCleanup(){
// run test data synchro
$oDataSource = $this->RunDataSynchroTest($this->GetNominalUsecaseData());
// QUERY to check data table for the new data source
$sDataSourceTable = $oDataSource->Get('database_table_name');
$sShowTable = "SHOW TABLES LIKE '$sDataSourceTable'";
// AFTER CREATION TEST A: Verify that replicas have been created
$oObjects = new DBObjectSet(DBObjectSearch::FromOQL("SELECT SynchroReplica WHERE sync_source_id='{$oDataSource->GetKey()}'"));
$aCountReplicaBeforeDelete = count($oObjects->ToArray());
$this->assertEquals(1, $aCountReplicaBeforeDelete);
// AFTER CREATION TEST B: Verify that data source table exist
$aResult = CMDBSource::Query($sShowTable);
$this->assertEquals(1, $aResult->num_rows, 'We must have a table in the database for the datasource');
// AFTER CREATION TEST C: Verify that data source table have one row
$sCountRows = CMDBSource::QueryToScalar("SELECT count(*) FROM $sDataSourceTable");
$this->assertEquals(1, $sCountRows, 'We must have a one row in datasource table');
// datasource deletion
$oDataSource->DBDelete();
// AFTER DELETION TEST A: Verify that replicas have been deleted
$oObjects = new DBObjectSet(DBObjectSearch::FromOQL("SELECT SynchroReplica WHERE sync_source_id='{$oDataSource->GetKey()}'"));
$aCountReplicaAfterDelete = count($oObjects->ToArray());
$this->assertEquals(0, $aCountReplicaAfterDelete);
// AFTER DELETION TEST B: Verify that data source table have been dropped
$aResult = CMDBSource::Query($sShowTable);
$this->assertEquals(0, $aResult->num_rows, 'The database datasource table must have been deleted');
}
/*public function testWithDeleteOption(){
$aUserLoginUsecase = array(
'desc' => 'Simple scenario with delete option (and extkey given as org/name)',