Compare commits

...

2 Commits

Author SHA1 Message Date
v-dumas
01f32086ec Fix tests for CI with 3.0 sample data and for commit on dev 2026-06-24 11:57:58 +02:00
v-dumas
5c59fdebaf Fix tests for CI with 3.0 sample data and for commit on dev 2026-06-24 11:01:48 +02:00
4 changed files with 264 additions and 82 deletions

View File

@@ -82,6 +82,8 @@ class BulkChangeTest extends ItopDataTestCase
*/
public function testBulkChangeWithoutInitData($aCSVData, $aAttributes, $aExtKeys, $aReconcilKeys, $aResult, ?array $aResultHTML = null)
{
[$aCSVData, $aResult, $aResultHTML] = $this->ResolveBulkChangeWithoutInitDataFixtures($aCSVData, $aResult, $aResultHTML);
$this->debug("aReconcilKeys:".$aReconcilKeys[0]);
$oBulk = new BulkChange(
"Server",
@@ -124,7 +126,7 @@ class BulkChangeTest extends ItopDataTestCase
return [
"Case 3, 5 et 8 : unchanged" => [
"csvData" =>
[["IT Department", "Server1", "1", "production", ""]],
[["{{ORG_NAME}}", "{{SERVER_NAME}}", "{{SERVER_ID}}", "production", ""]],
"attributes" =>
["name" => 1, "id" => 2, "status" => 3, "purchase_date" => 4],
"extKeys" =>
@@ -132,13 +134,13 @@ class BulkChangeTest extends ItopDataTestCase
"reconciliation Keys" =>
["id"],
"expectedResult" =>
[0 => "IT Department", "org_id" => "6", 1 => "Server1", 2 => "1", 3 => "production", 4 => "", "id" => 1, "__STATUS__" => "unchanged"],
[0 => "{{ORG_NAME}}", "org_id" => "{{ORG_ID}}", 1 => "{{SERVER_NAME}}", 2 => "{{SERVER_ID}}", 3 => "production", 4 => "", "id" => "{{SERVER_ID}}", "__STATUS__" => "unchanged"],
"expectedResultHTML" =>
[0 => "IT Department", "org_id" => "6", 1 => "Server1", 2 => "1", 3 => "production", 4 => "", "id" => 1, "__STATUS__" => "unchanged"],
[0 => "{{ORG_NAME}}", "org_id" => "{{ORG_ID}}", 1 => "{{SERVER_NAME}}", 2 => "{{SERVER_ID}}", 3 => "production", 4 => "", "id" => "{{SERVER_ID}}", "__STATUS__" => "unchanged"],
],
"Case 9 : wrong date format" => [
"csvData" =>
[["Demo", "Server1", "1", "production", "<date"]],
[["{{ORG_NAME}}", "{{SERVER_NAME}}", "{{SERVER_ID}}", "production", "<date"]],
"attributes" =>
["name" => 1, "id" => 2, "status" => 3, "purchase_date" => 4],
"extKeys" =>
@@ -146,13 +148,13 @@ class BulkChangeTest extends ItopDataTestCase
"reconciliation Keys" =>
["id"],
"expectedResult" =>
[ 0 => "Demo", "org_id" => "n/a", 1 => "Server1", 2 => "1", 3 => "production", 4 => "'<date' is an invalid value", "id" => 1, "__STATUS__" => "Issue: wrong date format"],
[ 0 => "{{ORG_NAME}}", "org_id" => "n/a", 1 => "{{SERVER_NAME}}", 2 => "{{SERVER_ID}}", 3 => "production", 4 => "'<date' is an invalid value", "id" => "{{SERVER_ID}}", "__STATUS__" => "Issue: wrong date format"],
"expectedResultHTML" =>
[ 0 => "Demo", "org_id" => "n/a", 1 => "Server1", 2 => "1", 3 => "production", 4 => "'&lt;date' is an invalid value", "id" => 1, "__STATUS__" => "Issue: wrong date format"],
[ 0 => "{{ORG_NAME}}", "org_id" => "n/a", 1 => "{{SERVER_NAME}}", 2 => "{{SERVER_ID}}", 3 => "production", 4 => "'&lt;date' is an invalid value", "id" => "{{SERVER_ID}}", "__STATUS__" => "Issue: wrong date format"],
],
"Case 1 : no match" => [
"csvData" =>
[["<Bad", "Server1", "1", "production", ""]],
[["<Bad", "{{SERVER_NAME}}", "{{SERVER_ID}}", "production", ""]],
"attributes" =>
["name" => 1, "id" => 2, "status" => 3, "purchase_date" => 4],
"extKeys" =>
@@ -160,13 +162,13 @@ class BulkChangeTest extends ItopDataTestCase
"reconciliation Keys" =>
["id"],
"expectedResult" =>
[0 => '<Bad', "org_id" => "No match for value '<Bad'",1 => "Server1",2 => "1", 3 => "production", 4 => "", "id" => 1, "__STATUS__" => "Issue: Unexpected attribute value(s)"],
[0 => '<Bad', "org_id" => "No match for value '<Bad'",1 => "{{SERVER_NAME}}",2 => "{{SERVER_ID}}", 3 => "production", 4 => "", "id" => "{{SERVER_ID}}", "__STATUS__" => "Issue: Unexpected attribute value(s)"],
"expectedResultHTML" =>
[0 => '&lt;Bad', "org_id" => "No match for value &apos;&lt;Bad&apos;",1 => "Server1",2 => "1", 3 => "production", 4 => "", "id" => 1, "__STATUS__" => "Issue: Unexpected attribute value(s)"],
[0 => '&lt;Bad', "org_id" => "No match for value &apos;&lt;Bad&apos;",1 => "{{SERVER_NAME}}",2 => "{{SERVER_ID}}", 3 => "production", 4 => "", "id" => "{{SERVER_ID}}", "__STATUS__" => "Issue: Unexpected attribute value(s)"],
],
"Case 10 : Missing mandatory value" => [
"csvData" =>
[["", "Server1", "1", "production", ""]],
[["", "{{SERVER_NAME}}", "{{SERVER_ID}}", "production", ""]],
"attributes" =>
["name" => 1, "id" => 2, "status" => 3, "purchase_date" => 4],
"extKeys" =>
@@ -174,13 +176,13 @@ class BulkChangeTest extends ItopDataTestCase
"reconciliation Keys" =>
["id"],
"expectedResult" =>
[0 => null, "org_id" => "Invalid value for attribute", 1 => "Server1", 2 => "1", 3 => "production", 4 => "", "id" => 1, "__STATUS__" => "Issue: Unexpected attribute value(s)"],
[0 => null, "org_id" => "Invalid value for attribute", 1 => "{{SERVER_NAME}}", 2 => "{{SERVER_ID}}", 3 => "production", 4 => "", "id" => "{{SERVER_ID}}", "__STATUS__" => "Issue: Unexpected attribute value(s)"],
"expectedResultHTML" =>
[0 => null, "org_id" => "Invalid value for attribute", 1 => "Server1", 2 => "1", 3 => "production", 4 => "", "id" => 1, "__STATUS__" => "Issue: Unexpected attribute value(s)"],
[0 => null, "org_id" => "Invalid value for attribute", 1 => "{{SERVER_NAME}}", 2 => "{{SERVER_ID}}", 3 => "production", 4 => "", "id" => "{{SERVER_ID}}", "__STATUS__" => "Issue: Unexpected attribute value(s)"],
],
"Case 6 : Unexpected value" => [
"csvData" =>
[["Demo", "Server1", "1", "<svg onclick\"alert(1)\">", ""]],
[["{{ORG_NAME}}", "{{SERVER_NAME}}", "{{SERVER_ID}}", "<svg onclick\"alert(1)\">", ""]],
"attributes" =>
["name" => 1, "id" => 2, "status" => 3, "purchase_date" => 4],
"extKeys" =>
@@ -189,25 +191,25 @@ class BulkChangeTest extends ItopDataTestCase
["id"],
"expectedResult" =>
[
0 => "Demo",
"org_id" => "3",
1 => "Server1",
2 => "1",
0 => "{{ORG_NAME}}",
"org_id" => "{{ORG_ID}}",
1 => "{{SERVER_NAME}}",
2 => "{{SERVER_ID}}",
3 => '\'<svg onclick"alert(1)">\' is an invalid value',
4 => "",
"id" => 1,
"id" => "{{SERVER_ID}}",
"__STATUS__" => "Issue: Unexpected attribute value(s)",
"__ERRORS__" => "Unexpected value for attribute 'status': no match found, check spelling",
],
"expectedResultHTML" =>
[
0 => "Demo",
"org_id" => "3",
1 => "Server1",
2 => "1",
0 => "{{ORG_NAME}}",
"org_id" => "{{ORG_ID}}",
1 => "{{SERVER_NAME}}",
2 => "{{SERVER_ID}}",
3 => '\'&lt;svg onclick&quot;alert(1)&quot;&gt;\' is an invalid value',
4 => "",
"id" => 1,
"id" => "{{SERVER_ID}}",
"__STATUS__" => "Issue: Unexpected attribute value(s)",
"__ERRORS__" => "Unexpected value for attribute 'status': no match found, check spelling",
],
@@ -215,6 +217,50 @@ class BulkChangeTest extends ItopDataTestCase
];
}
private function ResolveBulkChangeWithoutInitDataFixtures(array $aCSVData, array $aResult, ?array $aResultHTML): array
{
$sSuffix = uniqid('bulk_', false);
$iOrgId = $this->getTestOrgId();
$sServerName = 'Bulk Server '.$sSuffix;
$iServerId = (string) $this->GivenObjectInDB('Server', [
'name' => $sServerName,
'status' => 'production',
'org_id' => $iOrgId,
]);
$aTokens = [
'{{ORG_NAME}}' => 'UnitTestOrganization',
'{{ORG_ID}}' => $iOrgId,
'{{SERVER_NAME}}' => $sServerName,
'{{SERVER_ID}}' => $iServerId,
];
$aCSVData = $this->ReplaceFixtureTokens($aCSVData, $aTokens);
$aResult = $this->ReplaceFixtureTokens($aResult, $aTokens);
if ($aResultHTML !== null) {
$aResultHTML = $this->ReplaceFixtureTokens($aResultHTML, $aTokens);
}
return [$aCSVData, $aResult, $aResultHTML];
}
private function ReplaceFixtureTokens($mValue, array $aTokens)
{
if (is_array($mValue)) {
$aResult = [];
foreach ($mValue as $sKey => $mItem) {
$aResult[$sKey] = $this->ReplaceFixtureTokens($mItem, $aTokens);
}
return $aResult;
}
if (is_string($mValue) && array_key_exists($mValue, $aTokens)) {
return $aTokens[$mValue];
}
return $mValue;
}
/**
* test $oBulk->Process with new server datas
*

View File

@@ -260,34 +260,41 @@ class DBObjectTest extends ItopDataTestCase
*/
public function testAttributeRefresh_ExternalKeysAndFields()
{
$this->assertDBQueryCount(0, function () use (&$oObject) {
$oObject = \MetaModel::NewObject('Person', ['name' => 'Foo', 'first_name' => 'John', 'org_id' => 3, 'location_id' => 2]);
$aFixture = $this->GivenTwoOrganizationsWithLocations();
$this->assertDBQueryCount(0, function () use (&$oObject, $aFixture) {
$oObject = \MetaModel::NewObject('Person', [
'name' => 'Foo',
'first_name' => 'John',
'org_id' => $aFixture['org1_id'],
'location_id' => $aFixture['location1_id'],
]);
});
$this->assertDBQueryCount(2, function () use (&$oObject) {
static::assertEquals('Demo', $oObject->Get('org_id_friendlyname'));
static::assertEquals('Grenoble', $oObject->Get('location_id_friendlyname'));
$this->assertDBQueryCount(2, function () use (&$oObject, $aFixture) {
static::assertEquals($aFixture['org1_name'], $oObject->Get('org_id_friendlyname'));
static::assertEquals($aFixture['location1_name'], $oObject->Get('location_id_friendlyname'));
});
// External key given as an id
$this->assertDBQueryCount(1, function () use (&$oObject) {
$oObject->Set('org_id', 6);
static::assertEquals('IT Department', $oObject->Get('org_id_friendlyname'));
$this->assertDBQueryCount(1, function () use (&$oObject, $aFixture) {
$oObject->Set('org_id', $aFixture['org2_id']);
static::assertEquals($aFixture['org2_name'], $oObject->Get('org_id_friendlyname'));
});
// External key given as an object
$this->assertDBQueryCount(1, function () use (&$oBordeaux) {
$oBordeaux = \MetaModel::GetObject('Location', 1);
$this->assertDBQueryCount(1, function () use (&$oBordeaux, $aFixture) {
$oBordeaux = \MetaModel::GetObject('Location', $aFixture['location2_id']);
});
$this->assertDBQueryCount(0, function () use (&$oBordeaux, &$oObject) {
$this->assertDBQueryCount(0, function () use (&$oBordeaux, &$oObject, $aFixture) {
/** @var DBObject $oObject */
$oObject->Set('location_id', $oBordeaux);
static::assertEquals('IT Department', $oObject->Get('org_id_friendlyname'));
static::assertEquals('IT Department', $oObject->Get('org_name'));
static::assertEquals('Bordeaux', $oObject->Get('location_id_friendlyname'));
static::assertEquals($aFixture['org2_name'], $oObject->Get('org_id_friendlyname'));
static::assertEquals($aFixture['org2_name'], $oObject->Get('org_name'));
static::assertEquals($aFixture['location2_name'], $oObject->Get('location_id_friendlyname'));
});
static::assertEquals('Bordeaux', $oObject->Get('location_id_friendlyname'));
static::assertEquals($aFixture['location2_name'], $oObject->Get('location_id_friendlyname'));
// static::assertEquals('toto', $oObject->EvaluateExpression(\Expression::FromOQL("CONCAT(org_name, '-', location_id_friendlyname)")));
}
@@ -299,9 +306,15 @@ class DBObjectTest extends ItopDataTestCase
public function testInsertNoReloadAttributeRefresh_ExternalKeysAndFields()
{
$this->ResetReloadCount();
$aFixture = $this->GivenTwoOrganizationsWithLocations();
$this->assertDBQueryCount(0, function () use (&$oObject) {
$oObject = \MetaModel::NewObject('Person', ['name' => 'Foo', 'first_name' => 'John', 'org_id' => 3, 'location_id' => 2]);
$this->assertDBQueryCount(0, function () use (&$oObject, $aFixture) {
$oObject = \MetaModel::NewObject('Person', [
'name' => 'Foo',
'first_name' => 'John',
'org_id' => $aFixture['org1_id'],
'location_id' => $aFixture['location1_id'],
]);
});
// The number of queries depends on the installed modules so it varies on CI
$oObject->DBInsertNoReload();
@@ -310,31 +323,31 @@ class DBObjectTest extends ItopDataTestCase
$this->debug("Created $sClass::$sKey");
$this->DebugReloadCount("Person::DBInsertNoReload()");
$this->assertDBQueryCount(0, function () use (&$oObject) {
static::assertEquals('Demo', $oObject->Get('org_id_friendlyname'));
static::assertEquals('Grenoble', $oObject->Get('location_id_friendlyname'));
$this->assertDBQueryCount(0, function () use (&$oObject, $aFixture) {
static::assertEquals($aFixture['org1_name'], $oObject->Get('org_id_friendlyname'));
static::assertEquals($aFixture['location1_name'], $oObject->Get('location_id_friendlyname'));
});
$this->DebugReloadCount("Get('org_id_friendlyname') and Get('location_id_friendlyname')");
// External key given as an id
$this->assertDBQueryCount(1, function () use (&$oObject) {
$oObject->Set('org_id', 6);
static::assertEquals('IT Department', $oObject->Get('org_id_friendlyname'));
$this->assertDBQueryCount(1, function () use (&$oObject, $aFixture) {
$oObject->Set('org_id', $aFixture['org2_id']);
static::assertEquals($aFixture['org2_name'], $oObject->Get('org_id_friendlyname'));
});
$this->assertEquals(0, $this->GetObjectReloadCount($sClass, $sKey));
$this->DebugReloadCount("Set('org_id', 2) and Get('org_id_friendlyname')");
// External key given as an object
$this->assertDBQueryCount(1, function () use (&$oBordeaux) {
$oBordeaux = MetaModel::GetObject('Location', 1);
$this->assertDBQueryCount(1, function () use (&$oBordeaux, $aFixture) {
$oBordeaux = MetaModel::GetObject('Location', $aFixture['location2_id']);
});
$this->DebugReloadCount("GetObject('Location', 1)");
$this->assertDBQueryCount(0, function () use (&$oBordeaux, &$oObject) {
$this->assertDBQueryCount(0, function () use (&$oBordeaux, &$oObject, $aFixture) {
$oObject->Set('location_id', $oBordeaux);
static::assertEquals('IT Department', $oObject->Get('org_id_friendlyname'));
static::assertEquals('IT Department', $oObject->Get('org_name'));
static::assertEquals('Bordeaux', $oObject->Get('location_id_friendlyname'));
static::assertEquals($aFixture['org2_name'], $oObject->Get('org_id_friendlyname'));
static::assertEquals($aFixture['org2_name'], $oObject->Get('org_name'));
static::assertEquals($aFixture['location2_name'], $oObject->Get('location_id_friendlyname'));
});
$this->DebugReloadCount("Set('location_id',...) Get('org_id_friendlyname') Get('org_name') Get('location_id_friendlyname')");
}
@@ -347,9 +360,15 @@ class DBObjectTest extends ItopDataTestCase
public function testInsertNoReloadAttributeLinkSet()
{
$this->ResetReloadCount();
$aFixture = $this->GivenTwoOrganizationsWithLocations();
$this->assertDBQueryCount(0, function () use (&$oPerson) {
$oPerson = MetaModel::NewObject('Person', ['name' => 'Foo', 'first_name' => 'John', 'org_id' => 3, 'location_id' => 2]);
$this->assertDBQueryCount(0, function () use (&$oPerson, $aFixture) {
$oPerson = MetaModel::NewObject('Person', [
'name' => 'Foo',
'first_name' => 'John',
'org_id' => $aFixture['org1_id'],
'location_id' => $aFixture['location1_id'],
]);
});
// The number of queries depends on the installed modules so it varies on CI
$oPerson->DBInsertNoReload();
@@ -358,8 +377,8 @@ class DBObjectTest extends ItopDataTestCase
$this->debug("Created $sPersonClass::$sPersonKey");
$this->DebugReloadCount("Person::DBInsertNoReload()");
$this->assertDBQueryCount(1, function () use (&$oTeam, &$oPerson) {
$oTeam = MetaModel::NewObject('Team', ['name' => 'Team Foo', 'org_id' => 3]);
$this->assertDBQueryCount(1, function () use (&$oTeam, &$oPerson, $aFixture) {
$oTeam = MetaModel::NewObject('Team', ['name' => 'Team Foo', 'org_id' => $aFixture['org1_id']]);
// Add person to team
$oNewLink = new lnkPersonToTeam();
$oNewLink->Set('person_id', $oPerson->GetKey());
@@ -384,9 +403,9 @@ class DBObjectTest extends ItopDataTestCase
$this->assertCount(0, $oTeam->ListChanges());
// External key given as an id
$this->assertDBQueryCount(1, function () use (&$oTeam) {
$oTeam->Set('org_id', 6);
static::assertEquals('IT Department', $oTeam->Get('org_id_friendlyname'));
$this->assertDBQueryCount(1, function () use (&$oTeam, $aFixture) {
$oTeam->Set('org_id', $aFixture['org2_id']);
static::assertEquals($aFixture['org2_name'], $oTeam->Get('org_id_friendlyname'));
});
$this->DebugReloadCount("Set('org_id', 2) and Get('org_id_friendlyname')");
$this->assertCount(1, $oTeam->ListChanges());
@@ -581,15 +600,10 @@ class DBObjectTest extends ItopDataTestCase
{
//--- Preparing data...
$this->bIsUsingSilo = true;
/** @var Organization $oCustomerOrg */
$oCustomerOrg = MetaModel::GetObjectByName(Organization::class, 'Customer');
/** @var Person $oPersonOnItDepartmentOrg */
$oPersonOnItDepartmentOrg = MetaModel::GetObjectByName(Person::class, 'Anna Gavalda');
/** @var Person $oPersonOnCustomerOrg */
$oPersonOnCustomerOrg = MetaModel::GetObjectByName(Person::class, 'Camille Cottin');
$aFixture = $this->GivenAllowedAndDeniedPersonsByOrg();
$sConfigManagerProfileId = 3; // access to Team and Contact objects
$sLogin = $this->GivenUserRestrictedToAnOrganizationInDB($oCustomerOrg->GetKey(), $sConfigManagerProfileId);
$sLogin = $this->GivenUserRestrictedToAnOrganizationInDB($aFixture['allowed_org_id'], $sConfigManagerProfileId);
//--- Now we can do some tests !
UserRights::Login($sLogin);
@@ -597,7 +611,7 @@ class DBObjectTest extends ItopDataTestCase
$oTeam = MetaModel::NewObject(Team::class, [
'name' => 'The A Team',
'org_id' => $oCustomerOrg->GetKey(),
'org_id' => $aFixture['allowed_org_id'],
]);
// Part 1 - Test with an invalid id (non-existing object)
@@ -629,7 +643,7 @@ class DBObjectTest extends ItopDataTestCase
//
$oPersonLinks = \DBObjectSet::FromScratch(lnkPersonToTeam::class);
$oPersonLinks->AddObject(MetaModel::NewObject(lnkPersonToTeam::class, [
'person_id' => $oPersonOnCustomerOrg->GetKey(),
'person_id' => $aFixture['allowed_person_id'],
'team_id' => $oTeam->GetKey(),
]));
$oTeam->Set('persons_list', $oPersonLinks);
@@ -651,7 +665,7 @@ class DBObjectTest extends ItopDataTestCase
//
$oPersonLinks = \DBObjectSet::FromScratch(lnkPersonToTeam::class);
$oPersonLinks->AddObject(MetaModel::NewObject(lnkPersonToTeam::class, [
'person_id' => $oPersonOnItDepartmentOrg->GetKey(),
'person_id' => $aFixture['denied_person_id'],
'team_id' => $oTeam->GetKey(),
]));
$oTeam->Set('persons_list', $oPersonLinks);
@@ -684,15 +698,10 @@ class DBObjectTest extends ItopDataTestCase
{
//--- Preparing data...
$this->bIsUsingSilo = true;
/** @var Organization $oCustomerOrg */
$oCustomerOrg = MetaModel::GetObjectByName(Organization::class, 'Customer');
/** @var Person $oPersonOnItDepartmentOrg */
$oPersonOnItDepartmentOrg = MetaModel::GetObjectByName(Person::class, 'Anna Gavalda');
/** @var Person $oPersonOnCustomerOrg */
$oPersonOnCustomerOrg = MetaModel::GetObjectByName(Person::class, 'Camille Cottin');
$aFixture = $this->GivenAllowedAndDeniedPersonsByOrg();
$sConfigManagerProfileId = 3; // access to Team and Contact objects
$sLogin = $this->GivenUserRestrictedToAnOrganizationInDB($oCustomerOrg->GetKey(), $sConfigManagerProfileId);
$sLogin = $this->GivenUserRestrictedToAnOrganizationInDB($aFixture['allowed_org_id'], $sConfigManagerProfileId);
//--- Now we can do some tests !
UserRights::Login($sLogin);
@@ -700,7 +709,7 @@ class DBObjectTest extends ItopDataTestCase
$oAttachment = MetaModel::NewObject(Attachment::class, [
'item_class' => Person::class,
'item_id' => $oPersonOnCustomerOrg->GetKey(),
'item_id' => $aFixture['allowed_person_id'],
]);
try {
$oAttachment->CheckChangedExtKeysValues();
@@ -710,7 +719,7 @@ class DBObjectTest extends ItopDataTestCase
$oAttachment = MetaModel::NewObject(Attachment::class, [
'item_class' => Person::class,
'item_id' => $oPersonOnItDepartmentOrg->GetKey(),
'item_id' => $aFixture['denied_person_id'],
]);
$this->ResetMetaModelQueyCacheGetObject();
try {
@@ -718,10 +727,71 @@ class DBObjectTest extends ItopDataTestCase
$this->fail('There should be an error on attachment pointing to a non allowed org object');
} catch (InvalidExternalKeyValueException $e) {
$this->assertEquals('item_id', $e->GetAttCode(), 'Should report the object key attribute');
$this->assertEquals($oPersonOnItDepartmentOrg->GetKey(), $e->GetAttValue(), 'Should report the object key value');
$this->assertEquals($aFixture['denied_person_id'], $e->GetAttValue(), 'Should report the object key value');
}
}
private function GivenTwoOrganizationsWithLocations(): array
{
$sSuffix = uniqid('dbobj_', false);
$sOrg1Name = 'DBObject Org 1 '.$sSuffix;
$sOrg2Name = 'DBObject Org 2 '.$sSuffix;
$sLocation1Name = 'DBObject Location 1 '.$sSuffix;
$sLocation2Name = 'DBObject Location 2 '.$sSuffix;
$iOrg1 = (int) $this->GivenObjectInDB(Organization::class, ['name' => $sOrg1Name]);
$iOrg2 = (int) $this->GivenObjectInDB(Organization::class, ['name' => $sOrg2Name]);
$iLocation1 = (int) $this->GivenObjectInDB('Location', ['name' => $sLocation1Name, 'org_id' => $iOrg1]);
$iLocation2 = (int) $this->GivenObjectInDB('Location', ['name' => $sLocation2Name, 'org_id' => $iOrg2]);
return [
'org1_id' => $iOrg1,
'org1_name' => $sOrg1Name,
'org2_id' => $iOrg2,
'org2_name' => $sOrg2Name,
'location1_id' => $iLocation1,
'location1_name' => $sLocation1Name,
'location2_id' => $iLocation2,
'location2_name' => $sLocation2Name,
];
}
private function GivenAllowedAndDeniedPersonsByOrg(): array
{
$sSuffix = uniqid('dbobj_silo_', false);
$iAllowedOrg = (int) $this->GivenObjectInDB(Organization::class, ['name' => 'Allowed Org '.$sSuffix]);
$iDeniedOrg = (int) $this->GivenObjectInDB(Organization::class, ['name' => 'Denied Org '.$sSuffix]);
$iAllowedLocation = (int) $this->GivenObjectInDB('Location', [
'name' => 'Allowed Location '.$sSuffix,
'org_id' => $iAllowedOrg,
]);
$iDeniedLocation = (int) $this->GivenObjectInDB('Location', [
'name' => 'Denied Location '.$sSuffix,
'org_id' => $iDeniedOrg,
]);
$iAllowedPerson = (int) $this->GivenObjectInDB(Person::class, [
'name' => 'Allowed Person '.$sSuffix,
'first_name' => 'Unit',
'org_id' => $iAllowedOrg,
'location_id' => $iAllowedLocation,
]);
$iDeniedPerson = (int) $this->GivenObjectInDB(Person::class, [
'name' => 'Denied Person '.$sSuffix,
'first_name' => 'Unit',
'org_id' => $iDeniedOrg,
'location_id' => $iDeniedLocation,
]);
return [
'allowed_org_id' => $iAllowedOrg,
'denied_org_id' => $iDeniedOrg,
'allowed_person_id' => $iAllowedPerson,
'denied_person_id' => $iDeniedPerson,
];
}
/**
* Test attribute integer incrementation.
*

View File

@@ -9,6 +9,9 @@ use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
class DBUnionSearchTest extends ItopDataTestCase
{
/** @var array<string, int>|null */
private ?array $aUnionSearchFixtureIds = null;
/**
* @dataProvider UnionSearchProvider
*
@@ -20,6 +23,7 @@ class DBUnionSearchTest extends ItopDataTestCase
*/
public function testUnionSearch($sOQL)
{
$sOQL = $this->ResolveUnionSearchFixtureOql($sOQL);
$oSearch = DBSearch::FromOQL($sOQL);
$oSet = new DBObjectSet($oSearch);
@@ -50,11 +54,72 @@ class DBUnionSearchTest extends ItopDataTestCase
'Same class' => ["SELECT Server UNION SELECT Server"],
'different class same alias' => ['SELECT Server AS fci UNION SELECT VirtualMachine AS fci'],
'different class no alias' => ['SELECT Server UNION SELECT VirtualMachine'],
'multiple classes same alias' => ['SELECT `L`, `P` FROM Location AS `L` JOIN Person AS `P` ON `P`.location_id = `L`.id WHERE (`L`.`org_id` = 7) UNION SELECT `L`, `P` FROM Location AS `L` JOIN Person AS `P` ON `P`.location_id = `L`.id WHERE (`L`.`org_id` = 2)'],
'multiple classes' => ['SELECT `L`, `P` FROM Location AS `L` JOIN Person AS `P` ON `P`.location_id = `L`.id WHERE (`L`.`org_id` = 7) UNION SELECT `L1`, `P1` FROM Person AS `P1` JOIN Location AS `L1` ON `P1`.location_id = `L1`.id WHERE (`P1`.`org_id` = 2)'],
'multiple classes same alias' => [
'SELECT `L`, `P` FROM Location AS `L` JOIN Person AS `P` ON `P`.location_id = `L`.id WHERE (`L`.`org_id` = {{ORG1_ID}}) UNION SELECT `L`, `P` FROM Location AS `L` JOIN Person AS `P` ON `P`.location_id = `L`.id WHERE (`L`.`org_id` = {{ORG2_ID}})',
],
'multiple classes' => [
'SELECT `L`, `P` FROM Location AS `L` JOIN Person AS `P` ON `P`.location_id = `L`.id WHERE (`L`.`org_id` = {{ORG1_ID}}) UNION SELECT `L1`, `P1` FROM Person AS `P1` JOIN Location AS `L1` ON `P1`.location_id = `L1`.id WHERE (`P1`.`org_id` = {{ORG2_ID}})',
],
];
}
private function ResolveUnionSearchFixtureOql(string $sOQL): string
{
if (strpos($sOQL, '{{ORG') === false) {
return $sOQL;
}
$aFixtures = $this->GetUnionSearchFixtureIds();
return strtr($sOQL, [
'{{ORG1_ID}}' => (string) $aFixtures['org1_id'],
'{{ORG2_ID}}' => (string) $aFixtures['org2_id'],
]);
}
/**
* Create the minimum fixture set for UNION tests once per test instance.
*/
private function GetUnionSearchFixtureIds(): array
{
if ($this->aUnionSearchFixtureIds !== null) {
return $this->aUnionSearchFixtureIds;
}
$sSuffix = uniqid('dbunion_', false);
$iOrg1 = (int) $this->GivenObjectInDB('Organization', ['name' => 'Union Org 1 '.$sSuffix]);
$iOrg2 = (int) $this->GivenObjectInDB('Organization', ['name' => 'Union Org 2 '.$sSuffix]);
$iLocation1 = (int) $this->GivenObjectInDB('Location', [
'name' => 'Union Location 1 '.$sSuffix,
'org_id' => $iOrg1,
]);
$iLocation2 = (int) $this->GivenObjectInDB('Location', [
'name' => 'Union Location 2 '.$sSuffix,
'org_id' => $iOrg2,
]);
$this->GivenObjectInDB('Person', [
'name' => 'Union Person 1 '.$sSuffix,
'first_name' => 'Test',
'org_id' => $iOrg1,
'location_id' => $iLocation1,
]);
$this->GivenObjectInDB('Person', [
'name' => 'Union Person 2 '.$sSuffix,
'first_name' => 'Test',
'org_id' => $iOrg2,
'location_id' => $iLocation2,
]);
$this->aUnionSearchFixtureIds = [
'org1_id' => $iOrg1,
'org2_id' => $iOrg2,
];
return $this->aUnionSearchFixtureIds;
}
public function testFilterOnFirstSelectedClass()
{
$sSourceOQL = 'SELECT `Person`, `Location` FROM Person AS `Person` JOIN Location AS `Location` ON `Person`.location_id = `Location`.id WHERE (`Location`.`id` = 1)';

View File

@@ -315,7 +315,8 @@ class ExpressionEvaluateTest extends ItopDataTestCase
['URP_UserProfile', ['profileid' => 2], 'friendlyname', ''],
['Location', ['name' => 'Grenoble', 'org_id' => 2], 'name', 'Grenoble'],
['Location', ['name' => 'Grenoble', 'org_id' => 2], 'friendlyname', ''],
['Location', ['name' => 'Grenoble', 'org_id' => 6], 'org_name', 'IT Department'],
// ['Location', ['name' => 'Grenoble', 'org_id' => 6], 'org_name', 'IT Department'], // Compatible with 3.3 sample data
// ['Location', ['name' => 'Grenoble', 'org_id' => 2], 'org_name', 'Demo'], // Compatible with sample data before 3.3.0
['Location', ['name' => 'Grenoble', 'org_id' => 2], 'org_id_friendlyname', ''],
['Location', ['name' => 'Grenoble', 'org_id' => 2], 'org_id', 2],
['Location', ['name' => 'Grenoble', 'org_id' => 2], 'CONCAT(SUBSTR(name, 4), " cause")', 'noble cause'],