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
6 changed files with 293 additions and 145 deletions

View File

@@ -582,26 +582,16 @@ class UserRightsProfile extends UserRightsAddOnAPI
*/
public function ListProfiles($oUser)
{
if (count($oUser->ListChanges()) === 0) { // backward compatibility
$aRet = [];
$oSearch = new DBObjectSearch('URP_UserProfile');
$oSearch->AllowAllData();
$oSearch->NoContextParameters();
$oSearch->Addcondition('userid', $oUser->GetKey(), '=');
$oProfiles = new DBObjectSet($oSearch);
while ($oUserProfile = $oProfiles->Fetch()) {
$aRet[$oUserProfile->Get('profileid')] = $oUserProfile->Get('profileid_friendlyname');
}
return $aRet;
} else {
$aRet = [];
$oProfilesSet = $oUser->Get('profile_list');
foreach ($oProfilesSet as $oUserProfile) {
$aRet[$oUserProfile->Get('profileid')] = $oUserProfile->Get('profileid_friendlyname');
}
return $aRet;
$aRet = [];
$oSearch = new DBObjectSearch('URP_UserProfile');
$oSearch->AllowAllData();
$oSearch->NoContextParameters();
$oSearch->Addcondition('userid', $oUser->GetKey(), '=');
$oProfiles = new DBObjectSet($oSearch);
while ($oUserProfile = $oProfiles->Fetch()) {
$aRet[$oUserProfile->Get('profileid')] = $oUserProfile->Get('profileid_friendlyname');
}
return $aRet;
}
public function GetSelectFilter($oUser, $sClass, $aSettings = [])
@@ -715,23 +705,26 @@ class UserRightsProfile extends UserRightsAddOnAPI
protected function GetUserActionGrant($oUser, $sClass, $iActionCode)
{
$this->LoadCache();
if (count($oUser->ListChanges()) === 0) {
// load and cache permissions for the current user on the given class
if (isset($this->m_aObjectActionGrants[$oUser->GetKey()][$sClass][$iActionCode])) {
$aTest = $this->m_aObjectActionGrants[$oUser->GetKey()][$sClass][$iActionCode];
if (is_array($aTest)) {
return $aTest;
}
// load and cache permissions for the current user on the given class
//
$iUser = $oUser->GetKey();
if (isset($this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode])) {
$aTest = $this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode];
if (is_array($aTest)) {
return $aTest;
}
}
$sAction = self::$m_aActionCodes[$iActionCode];
$bStatus = null;
$aProfileList = $this->GetProfileList($oUser);
// Cache user's profiles
if (false === array_key_exists($iUser, $this->aUsersProfilesList)) {
$this->aUsersProfilesList[$iUser] = UserRights::ListProfiles($oUser);
}
// Call the API of UserRights because it caches the list for us
foreach ($aProfileList as $iProfile => $oProfile) {
foreach ($this->aUsersProfilesList[$iUser] as $iProfile => $oProfile) {
$bGrant = $this->GetProfileActionGrant($iProfile, $sClass, $sAction);
if (!is_null($bGrant)) {
if ($bGrant) {
@@ -749,9 +742,7 @@ class UserRightsProfile extends UserRightsAddOnAPI
$aRes = [
'permission' => $iPermission,
];
if (count($oUser->ListChanges()) === 0) {
$this->m_aObjectActionGrants[$oUser->GetKey()][$sClass][$iActionCode] = $aRes;
}
$this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode] = $aRes;
return $aRes;
}
@@ -833,14 +824,18 @@ class UserRightsProfile extends UserRightsAddOnAPI
{
$this->LoadCache();
// Note: this code is VERY close to the code of IsActionAllowed()
$iUser = $oUser->GetKey();
$aProfileList = $this->GetProfileList($oUser);
// Cache user's profiles
if (false === array_key_exists($iUser, $this->aUsersProfilesList)) {
$this->aUsersProfilesList[$iUser] = UserRights::ListProfiles($oUser);
}
// Note: The object set is ignored because it was interesting to optimize for huge data sets
// and acceptable to consider only the root class of the object set
$bStatus = null;
// Call the API of UserRights because it caches the list for us
foreach ($aProfileList as $iProfile => $oProfile) {
foreach ($this->aUsersProfilesList[$iUser] as $iProfile => $oProfile) {
$bGrant = $this->GetClassStimulusGrant($iProfile, $sClass, $sStimulusCode);
if (!is_null($bGrant)) {
if ($bGrant) {
@@ -898,25 +893,6 @@ class UserRightsProfile extends UserRightsAddOnAPI
}
return $bHasSharing;
}
/**
* @param \User $oUser
*
* @return array
* @throws \Exception
*/
public function GetProfileList(User $oUser): array
{
if (count($oUser->ListChanges()) === 0) { // if user is already in db and not changed
$iUser = $oUser->GetKey();
if (false === array_key_exists($iUser, $this->aUsersProfilesList)) {
$aProfiles = UserRights::ListProfiles($oUser);
$this->aUsersProfilesList[$iUser] = $aProfiles;
}
return $this->aUsersProfilesList[$iUser];
}
return UserRights::ListProfiles($oUser);
}
}
UserRights::SelectModule('UserRightsProfile');

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'],

View File

@@ -81,16 +81,6 @@ class UserRightsTest extends ItopDataTestCase
return $oUser;
}
public function testIsActionAllowedWithNonInstantiatedUserObject()
{
$oUser = $this->GivenUserWithProfiles('test1', [self::$aURP_Profiles['Configuration Manager']]); // not a readonly profile
$oAdminUser = $this->GivenUserWithProfiles('test2', [self::$aURP_Profiles['Administrator']]);
$oAdminUser->DBInsert();
$_SESSION = [];
UserRights::Login($oAdminUser->Get('login'));
self::assertTrue(UserRights::IsActionAllowed('Server', UR_ACTION_MODIFY, null, $oUser) === UR_ALLOWED_YES);
}
protected function GivenUserWithProfiles(string $sLogin, array $aProfileIds): DBObject
{
$oProfiles = new \ormLinkSet(\UserLocal::class, 'profile_list', \DBObjectSet::FromScratch(\URP_UserProfile::class));