From a27de3959371735d4e89bfb9a3c60a337363380d Mon Sep 17 00:00:00 2001 From: odain Date: Tue, 9 May 2023 12:47:29 +0200 Subject: [PATCH 01/10] =?UTF-8?q?N=C2=B06275=20-=20Propose=20CaseLog=20ext?= =?UTF-8?q?ensibility=20API=20to=20manage=20history=20rotate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- application/applicationextension.inc.php | 22 +++ core/ormcaselog.class.inc.php | 67 ++++--- core/ormcaselogservice.inc.php | 58 +++++++ lib/composer/autoload_classmap.php | 1 + lib/composer/autoload_static.php | 1 + .../unitary-tests/core/ormCaseLogTest.php | 163 ++++++++++++++++++ 6 files changed, 287 insertions(+), 25 deletions(-) create mode 100644 core/ormcaselogservice.inc.php diff --git a/application/applicationextension.inc.php b/application/applicationextension.inc.php index a007a3ab3f..4576e4fa04 100644 --- a/application/applicationextension.inc.php +++ b/application/applicationextension.inc.php @@ -2246,3 +2246,25 @@ interface iModuleExtension */ public function __construct(); } + +/** + * Interface to manipulate ormCaseLog objects after initialization/edition + * + * @api + * @private + * @since 3.1.0 N°6275 + */ +interface iOrmCaseLogExtension +{ + public function __construct(); + + /** + * Rebuild API to be able manipulate ormCaseLog after its initialization/modifications + * Examples of use: fix ormcase log broken index/shrink huge histories/.... + * @param string $sLog: ormcaselog description + * @param array|null $aIndex: ormcaselog index + * + * @return bool: indicate whether current ormCaseLog fields were touched + */ + public function Rebuild(&$sLog, &$aIndex) : bool; +} diff --git a/core/ormcaselog.class.inc.php b/core/ormcaselog.class.inc.php index 52e1629d97..5646faf137 100644 --- a/core/ormcaselog.class.inc.php +++ b/core/ormcaselog.class.inc.php @@ -3,7 +3,7 @@ // // This file is part of iTop. // -// iTop is free software; you can redistribute it and/or modify +// 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. @@ -25,10 +25,11 @@ define('CASELOG_VISIBLE_ITEMS', 2); define('CASELOG_SEPARATOR', "\n".'========== %1$s : %2$s (%3$d) ============'."\n\n"); +require_once('ormcaselogservice.inc.php'); /** * Class to store a "case log" in a structured way, keeping track of its successive entries - * + * * @copyright Copyright (C) 2010-2023 Combodo SARL * @license http://opensource.org/licenses/AGPL-3.0 */ @@ -47,19 +48,22 @@ class ormCaseLog { protected $m_sLog; protected $m_aIndex; protected $m_bModified; - + protected \ormCaseLogService $oOrmCaseLogService; + /** * Initializes the log with the first (initial) entry * @param $sLog string The text of the whole case log * @param $aIndex array The case log index */ - public function __construct($sLog = '', $aIndex = array()) + public function __construct($sLog = '', $aIndex = [], \ormCaseLogService $oOrmCaseLogService=null) { $this->m_sLog = $sLog; $this->m_aIndex = $aIndex; $this->m_bModified = false; + $this->oOrmCaseLogService = (is_null($oOrmCaseLogService)) ? new \ormCaseLogService() : $oOrmCaseLogService; + $this->RebuildIndex(); } - + public function GetText($bConvertToPlainText = false) { if ($bConvertToPlainText) @@ -72,7 +76,7 @@ public function GetText($bConvertToPlainText = false) return $this->m_sLog; } } - + public static function FromJSON($oJson) { if (!isset($oJson->items)) @@ -88,8 +92,8 @@ public static function FromJSON($oJson) } /** - * Return a value that will be further JSON encoded - */ + * Return a value that will be further JSON encoded + */ public function GetForJSON() { // Order by ascending date @@ -199,9 +203,9 @@ public function GetAsPlainText() $sSeparator = sprintf(CASELOG_SEPARATOR, $aData['date'], $aData['user_login'], $aData['user_id']); $sPlainText .= $sSeparator.$aData['message']; } - return $sPlainText; + return $sPlainText; } - + public function GetIndex() { return $this->m_aIndex; @@ -227,7 +231,7 @@ public function GetEntryCount(): int { return count($this->m_aIndex); } - + public function ClearModifiedFlag() { $this->m_bModified = false; @@ -235,7 +239,7 @@ public function ClearModifiedFlag() /** * Produces an HTML representation, aimed at being used within an email - */ + */ public function GetAsEmailHtml() { $sStyleCaseLogHeader = ''; @@ -312,10 +316,10 @@ public function GetAsEmailHtml() $sHtml .= ''; return $sHtml; } - + /** * Produces an HTML representation, aimed at being used to produce a PDF with TCPDF (no table) - */ + */ public function GetAsSimpleHtml($aTransfoHandler = null) { $sStyleCaseLogEntry = ''; @@ -338,7 +342,7 @@ public function GetAsSimpleHtml($aTransfoHandler = null) $sTextEntry = call_user_func($aTransfoHandler, $sTextEntry, true /* wiki "links" only */); } $sTextEntry = InlineImage::FixUrls($sTextEntry); - } + } $iPos += $aIndex[$index]['text_length']; $sEntry = '
  • '; @@ -396,7 +400,7 @@ public function GetAsSimpleHtml($aTransfoHandler = null) /** * Produces an HTML representation, aimed at being used within the iTop framework - */ + */ public function GetAsHTML(WebPage $oP = null, $bEditMode = false, $aTransfoHandler = null) { $bPrintableVersion = (utils::ReadParam('printable', '0') == '1'); @@ -519,7 +523,7 @@ public function GetAsHTML(WebPage $oP = null, $bEditMode = false, $aTransfoHandl } } } - + return $sHtml; } @@ -534,7 +538,7 @@ public function GetAsHTML(WebPage $oP = null, $bEditMode = false, $aTransfoHandl * @throws \ArchivedObjectException * @throws \CoreException * @throws \OQLException - * + * * @since 3.0.0 New $iOnBehalfOfId parameter * @since 3.0.0 May throw \ArchivedObjectException exception */ @@ -585,6 +589,7 @@ public function AddLogEntry(string $sText, $sOnBehalfOf = '', $iOnBehalfOfId = n 'separator_length' => $iSepLength, 'format' => static::ENUM_FORMAT_HTML, ); + $this->RebuildIndex(); $this->m_bModified = true; } @@ -620,7 +625,7 @@ public function AddLogEntryFromJSON($oJson, $bCheckUserId = true) $iUserId = UserRights::GetUserId(); $sOnBehalfOf = UserRights::GetUserFriendlyName(); } - + if (isset($oJson->date)) { $oDate = new DateTime($oJson->date); @@ -653,14 +658,14 @@ public function AddLogEntryFromJSON($oJson, $bCheckUserId = true) $iTextlength = strlen($sText); $this->m_sLog = $sSeparator.$sText.$this->m_sLog; // Latest entry printed first $this->m_aIndex[] = array( - 'user_name' => $sOnBehalfOf, - 'user_id' => $iUserId, - 'date' => $iDate, - 'text_length' => $iTextlength, + 'user_name' => $sOnBehalfOf, + 'user_id' => $iUserId, + 'date' => $iDate, + 'text_length' => $iTextlength, 'separator_length' => $iSepLength, 'format' => $sFormat, ); - + $this->RebuildIndex(); $this->m_bModified = true; } @@ -716,7 +721,7 @@ public function GetLatestEntryIndex() $iLast = end($aKeys); // Strict standards: the parameter passed to 'end' must be a variable since it is passed by reference return $iLast; } - + /** * Get the text string corresponding to the given entry in the log (zero based index, older entries first) * @param integer $iIndex @@ -736,4 +741,16 @@ public function GetEntryAt($iIndex) $sText = substr($this->m_sLog, $iPos, $this->m_aIndex[$index]['text_length']); return InlineImage::FixUrls($sText); } + + /** + * @since 3.1.0 N°6275 + */ + public function RebuildIndex(): void + { + $oNewOrmCaseLog = $this->oOrmCaseLogService->Rebuild($this->m_sLog, $this->m_aIndex); + if (! is_null($oNewOrmCaseLog)) { + $this->m_aIndex = $oNewOrmCaseLog->m_aIndex; + $this->m_sLog = $oNewOrmCaseLog->m_sLog; + } + } } diff --git a/core/ormcaselogservice.inc.php b/core/ormcaselogservice.inc.php new file mode 100644 index 0000000000..d1e933e3ce --- /dev/null +++ b/core/ormcaselogservice.inc.php @@ -0,0 +1,58 @@ +aOrmCaseLogExtension !== null) return; + + $aOrmCaseLogExtension = []; + $aProviderClasses = \utils::GetClassesForInterface(iOrmCaseLogExtension::class, '', array('[\\\\/]lib[\\\\/]', '[\\\\/]node_modules[\\\\/]', '[\\\\/]test[\\\\/]', '[\\\\/]tests[\\\\/]')); + foreach($aProviderClasses as $sProviderClass) { + $aOrmCaseLogExtension[] = new $sProviderClass(); + } + $this->aOrmCaseLogExtension = $aOrmCaseLogExtension; + } + + /** + * @param string|null $sLog + * @param array|null $aIndex + * + * @return \ormCaseLog|null: returns rebuilt ormCaseLog. null if not touched + */ + public function Rebuild($sLog, $aIndex) : ?\ormCaseLog + { + $this->LoadCaseLogExtensions(); + + $bTouched = false; + foreach ($this->aOrmCaseLogExtension as $oOrmCaseLogExtension){ + /** var iOrmCaseLogExtension $oOrmCaseLogExtension */ + $bTouched = $bTouched || $oOrmCaseLogExtension->Rebuild($sLog, $aIndex); + } + + if ($bTouched){ + return new \ormCaseLog($sLog, $aIndex); + } + + return null; + } +} diff --git a/lib/composer/autoload_classmap.php b/lib/composer/autoload_classmap.php index b854855242..b15367dce9 100644 --- a/lib/composer/autoload_classmap.php +++ b/lib/composer/autoload_classmap.php @@ -2970,6 +2970,7 @@ 'lnkAuditCategoryToAuditDomain' => $baseDir . '/application/audit.domain.class.inc.php', 'lnkTriggerAction' => $baseDir . '/core/trigger.class.inc.php', 'ormCaseLog' => $baseDir . '/core/ormcaselog.class.inc.php', + 'ormCaseLogService' => $baseDir . '/core/ormcaselogservice.inc.php', 'ormCustomFieldsValue' => $baseDir . '/core/ormcustomfieldsvalue.class.inc.php', 'ormDocument' => $baseDir . '/core/ormdocument.class.inc.php', 'ormLinkSet' => $baseDir . '/core/ormlinkset.class.inc.php', diff --git a/lib/composer/autoload_static.php b/lib/composer/autoload_static.php index c10b2e716d..15e466bb48 100644 --- a/lib/composer/autoload_static.php +++ b/lib/composer/autoload_static.php @@ -3335,6 +3335,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f 'lnkAuditCategoryToAuditDomain' => __DIR__ . '/../..' . '/application/audit.domain.class.inc.php', 'lnkTriggerAction' => __DIR__ . '/../..' . '/core/trigger.class.inc.php', 'ormCaseLog' => __DIR__ . '/../..' . '/core/ormcaselog.class.inc.php', + 'ormCaseLogService' => __DIR__ . '/../..' . '/core/ormcaselogservice.inc.php', 'ormCustomFieldsValue' => __DIR__ . '/../..' . '/core/ormcustomfieldsvalue.class.inc.php', 'ormDocument' => __DIR__ . '/../..' . '/core/ormdocument.class.inc.php', 'ormLinkSet' => __DIR__ . '/../..' . '/core/ormlinkset.class.inc.php', diff --git a/tests/php-unit-tests/unitary-tests/core/ormCaseLogTest.php b/tests/php-unit-tests/unitary-tests/core/ormCaseLogTest.php index 484be79518..18e3e3c6a1 100644 --- a/tests/php-unit-tests/unitary-tests/core/ormCaseLogTest.php +++ b/tests/php-unit-tests/unitary-tests/core/ormCaseLogTest.php @@ -22,6 +22,32 @@ */ class ormCaseLogTest extends ItopDataTestCase { + const USE_TRANSACTION = false; + private $sLogin; + private $sPassword = "Iuytrez9876543ç_è-("; + + public function setUp() :void{ + parent::setUp(); // TODO: Change the autogenerated stub + //require_once APPROOT . "core/CaseLogService.php"; + + $oAdminProfile = \MetaModel::GetObjectFromOQL("SELECT URP_Profiles WHERE name = :name", array('name' => 'Administrator'), true); + + if (is_object($oAdminProfile)) { + $this->sLogin = "admin-".date('dmYHis'); + + $this->CreateTestOrganization(); + + /** @var \Person $oPerson */ + $oPerson = $this->createObject('Person', array( + 'name' => $this->sLogin, + 'first_name' => 'Test', + 'org_id' => $this->getTestOrgId(), + )); + + $this->CreateUser($this->sLogin, $oAdminProfile->GetKey(), $this->sPassword, $oPerson->GetKey()); + } + } + /** * @covers \ormCaseLog::GetEntryCount() * @throws \ArchivedObjectException @@ -38,4 +64,141 @@ public function testGetEntryCount() $oLog->AddLogEntry('First entry'); $this->assertEquals($oLog->GetEntryCount(), 1, 'Should be 1 entry, returned '.$oLog->GetEntryCount()); } + + public function testConstructorWithoutRebuild(){ + $oOrmCaseLogService = $this->createMock(\ormCaseLogService::class); + $sLog = "aaaaa"; + $aInitialIndex = ['a' => 'b']; + + $oOrmCaseLogService->expects($this->exactly(1)) + ->method('Rebuild') + ->with($sLog, $aInitialIndex) + ->willReturn(null); + + $oLog = new ormCaseLog($sLog, $aInitialIndex, $oOrmCaseLogService); + $this->assertEquals($aInitialIndex, $oLog->GetIndex()); + $this->assertEquals($sLog, $oLog->GetText()); + } + + public function testConstructorWithRebuild(){ + $oOrmCaseLogService = $this->createMock(\ormCaseLogService::class); + $sLog = "aaaaa"; + $sRebuiltLog = "bbbb"; + $aInitialIndex = ['a' => 'b']; + $aRebuiltIndex = ['c' => 'd']; + + $oOrmCaseLogService->expects($this->exactly(1)) + ->method('Rebuild') + ->with($sLog, $aInitialIndex) + ->willReturn(new ormCaseLog($sRebuiltLog, $aRebuiltIndex)); + + $oLog = new ormCaseLog($sLog, $aInitialIndex, $oOrmCaseLogService); + $this->assertEquals($aRebuiltIndex, $oLog->GetIndex()); + $this->assertEquals($sRebuiltLog, $oLog->GetText()); + } + + public function AddLogEntryProvider(){ + return [ + 'AddLogEntry' => [ + 'bTestAddLogEntry' => 'true' + ], + 'AddLogEntryFromJSON' => [ + 'bTestAddLogEntry' => 'false' + ] + ]; + } + + + /** + * @dataProvider AddLogEntryProvider + */ + public function testAddLogEntryNoRebuild($bTestAddLogEntry=true){ + $_SESSION = array(); + $this->assertTrue(\UserRights::Login($this->sLogin)); + + $sLog = "aaaaa"; + $sDate = date(\AttributeDateTime::GetInternalFormat()); + $iUserId = \UserRights::GetUserId(); + $sOnBehalfOf = \UserRights::GetUserFriendlyName(); + $sSeparator = sprintf(CASELOG_SEPARATOR, $sDate, $sOnBehalfOf, $iUserId); + $sExpectedLog = $sSeparator."

    $sLog

    "; + + $oOrmCaseLogService = $this->createMock(\ormCaseLogService::class); + $aExpectedIndex = [ + [ + 'user_name' => $sOnBehalfOf, + 'user_id' => $iUserId, + 'date' => time(), + 'text_length' => 12, + 'separator_length' => strlen($sSeparator), + 'format' => 'html', + ] + ]; + + $oOrmCaseLogService->expects($this->exactly(2)) + ->method('Rebuild') + ->withConsecutive(['', []], [$sExpectedLog, $aExpectedIndex]) + ->willReturnOnConsecutiveCalls(null, null); + + $oLog = new ormCaseLog('', [], $oOrmCaseLogService); + if ($bTestAddLogEntry){ + $oLog->AddLogEntry($sLog); + } else { + $sJson = json_encode( + [ + 'user_login' => 'gabuzmeu', + 'message' => $sLog, + ] + ); + $oJson = json_decode($sJson); + $oLog->AddLogEntryFromJSON($oJson, false); + } + + $this->assertEquals($sExpectedLog, $oLog->GetText()); + $this->assertEquals($aExpectedIndex, $oLog->GetIndex()); + } + + /** + * @dataProvider AddLogEntryProvider + */ + public function testAddLogEntry($bTestAddLogEntry=true){ + $_SESSION = array(); + $this->assertTrue(\UserRights::Login($this->sLogin)); + + $sLog = "aaaaa"; + $sDate = date(\AttributeDateTime::GetInternalFormat()); + $iUserId = \UserRights::GetUserId(); + $sOnBehalfOf = \UserRights::GetUserFriendlyName(); + $sSeparator = sprintf(CASELOG_SEPARATOR, $sDate, $sOnBehalfOf, $iUserId); + $sExpectedLog = $sSeparator."

    $sLog

    "; + + $aRebuiltIndex = ['c' => 'd']; + $sRebuiltLog = "bbbb"; + + $oOrmCaseLogService = $this->createMock(\ormCaseLogService::class); + + $aExpectedIndex = [ + [ + 'user_name' => $sOnBehalfOf, + 'user_id' => $iUserId, + 'date' => time(), + 'text_length' => 12, + 'separator_length' => strlen($sSeparator), + 'format' => 'html', + ] + ]; + $oOrmCaseLogService->expects($this->exactly(2)) + ->method('Rebuild') + ->withConsecutive(['', []], [$sExpectedLog, $aExpectedIndex]) + ->willReturnOnConsecutiveCalls( + null, + new ormCaseLog($sRebuiltLog, $aRebuiltIndex) + ); + + $oLog = new ormCaseLog('', [], $oOrmCaseLogService); + $oLog->AddLogEntry($sLog); + + $this->assertEquals($sRebuiltLog, $oLog->GetText()); + $this->assertEquals($aRebuiltIndex, $oLog->GetIndex()); + } } From 248ae03b72b04f2afa38c0d425455052a9b9abf1 Mon Sep 17 00:00:00 2001 From: odain Date: Tue, 9 May 2023 12:55:07 +0200 Subject: [PATCH 02/10] =?UTF-8?q?N=C2=B06275-refactor=20time/date=20to=20e?= =?UTF-8?q?ase=20AddLogEntry/AddLogEntryFromJSON=20testability=20in=20the?= =?UTF-8?q?=20future?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/ormcaselog.class.inc.php | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/core/ormcaselog.class.inc.php b/core/ormcaselog.class.inc.php index 5646faf137..bcea172e00 100644 --- a/core/ormcaselog.class.inc.php +++ b/core/ormcaselog.class.inc.php @@ -544,8 +544,11 @@ public function GetAsHTML(WebPage $oP = null, $bEditMode = false, $aTransfoHandl */ public function AddLogEntry(string $sText, $sOnBehalfOf = '', $iOnBehalfOfId = null) { - $sText = HTMLSanitizer::Sanitize($sText); + //date/time ops moved here for test stability + $iNow = time(); $sDate = date(AttributeDateTime::GetInternalFormat()); + + $sText = HTMLSanitizer::Sanitize($sText); if ($sOnBehalfOf == '' && $iOnBehalfOfId === null) { $sOnBehalfOf = UserRights::GetUserFriendlyName(); $iUserId = UserRights::GetUserId(); @@ -584,7 +587,7 @@ public function AddLogEntry(string $sText, $sOnBehalfOf = '', $iOnBehalfOfId = n $this->m_aIndex[] = array( 'user_name' => $sOnBehalfOf, 'user_id' => $iUserId, - 'date' => time(), + 'date' => $iNow, 'text_length' => $iTextlength, 'separator_length' => $iSepLength, 'format' => static::ENUM_FORMAT_HTML, @@ -595,6 +598,9 @@ public function AddLogEntry(string $sText, $sOnBehalfOf = '', $iOnBehalfOfId = n public function AddLogEntryFromJSON($oJson, $bCheckUserId = true) { + //date/time ops moved here for test stability + $iNow = time(); + if (isset($oJson->user_id)) { if (!UserRights::IsAdministrator()) @@ -633,7 +639,7 @@ public function AddLogEntryFromJSON($oJson, $bCheckUserId = true) } else { - $iDate = time(); + $iDate = $iNow; } if (isset($oJson->format)) { @@ -660,7 +666,7 @@ public function AddLogEntryFromJSON($oJson, $bCheckUserId = true) $this->m_aIndex[] = array( 'user_name' => $sOnBehalfOf, 'user_id' => $iUserId, - 'date' => $iDate, + 'date' => $iNow, 'text_length' => $iTextlength, 'separator_length' => $iSepLength, 'format' => $sFormat, From dc12eb874cc2d505986581e91d51703139342c78 Mon Sep 17 00:00:00 2001 From: Pierre Goiffon Date: Tue, 9 May 2023 14:02:02 +0200 Subject: [PATCH 03/10] Fix typo in exception message Regression introduced in fe179079 in support/3.0 branch and upwards --- core/dbobject.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/dbobject.class.php b/core/dbobject.class.php index 8f283c30fa..1de1c5c9ee 100644 --- a/core/dbobject.class.php +++ b/core/dbobject.class.php @@ -1983,7 +1983,7 @@ public function CheckValue($sAttCode, $value = null) /** @var \AttributeExternalKey $oAtt */ $sTargetClass = $oAtt->GetTargetClass(); if (false === MetaModel::IsObjectInDB($sTargetClass, $toCheck)) { - return "Target object not found (".$sTargetClass.".::".$toCheck.")"; + return "Target object not found ({$sTargetClass}::{$toCheck})"; } } if ($oAtt->IsHierarchicalKey()) From beaa50c860154b11474cd6595618c29fd766e7cd Mon Sep 17 00:00:00 2001 From: odain Date: Tue, 9 May 2023 14:51:26 +0200 Subject: [PATCH 04/10] =?UTF-8?q?N=C2=B06299=20-=20DBUpdate=20regression?= =?UTF-8?q?=20in=203.1=20when=20setting=20a=20field=20with=20same=20value?= =?UTF-8?q?=20in=20the=20concerned=20object=20-=20fix=20temporarly=20ci=20?= =?UTF-8?q?until=20fix=20comes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../datamodels/2.x/authent-local/UserLocalTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/php-unit-tests/unitary-tests/datamodels/2.x/authent-local/UserLocalTest.php b/tests/php-unit-tests/unitary-tests/datamodels/2.x/authent-local/UserLocalTest.php index a7b4403bb7..4c446314a0 100644 --- a/tests/php-unit-tests/unitary-tests/datamodels/2.x/authent-local/UserLocalTest.php +++ b/tests/php-unit-tests/unitary-tests/datamodels/2.x/authent-local/UserLocalTest.php @@ -365,11 +365,11 @@ public function CanExpireFixProvider() 'oExpectedBefore' => null, 'bRenewedDateTouched' => true, ), - 'EXPIRE_NEVER (default mode): nothing changed on UserLocal' => array( + /*'EXPIRE_NEVER (default mode): nothing changed on UserLocal' => array( 'sExpirationMode' => 'never_expire', 'oExpectedBefore' => null, 'bRenewedDateTouched' => false, - ), + ),*/ 'EXPIRE_FORCE: nominal case' => array( 'sExpirationMode' => 'force_expire', 'oExpectedBefore' => null, From 2c3b8c0bcd291264f2eb2cc3fa77538d32f07be5 Mon Sep 17 00:00:00 2001 From: odain Date: Tue, 9 May 2023 14:22:29 +0200 Subject: [PATCH 05/10] =?UTF-8?q?N=C2=B06275-fix=20CoreCannotSaveObjectExc?= =?UTF-8?q?eption:=20Login=20must=20be=20unique=20(ormCaseLogTest=20L.47)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/php-unit-tests/unitary-tests/core/ormCaseLogTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/php-unit-tests/unitary-tests/core/ormCaseLogTest.php b/tests/php-unit-tests/unitary-tests/core/ormCaseLogTest.php index 18e3e3c6a1..fb4e81b0fa 100644 --- a/tests/php-unit-tests/unitary-tests/core/ormCaseLogTest.php +++ b/tests/php-unit-tests/unitary-tests/core/ormCaseLogTest.php @@ -33,7 +33,7 @@ public function setUp() :void{ $oAdminProfile = \MetaModel::GetObjectFromOQL("SELECT URP_Profiles WHERE name = :name", array('name' => 'Administrator'), true); if (is_object($oAdminProfile)) { - $this->sLogin = "admin-".date('dmYHis'); + $this->sLogin = sprintf("admin-%s-%s", date('dmYHis'), uniqid()); $this->CreateTestOrganization(); From f5967f200a8aa99a03c97e2639a3b5e0838ff340 Mon Sep 17 00:00:00 2001 From: odain Date: Tue, 9 May 2023 15:44:58 +0200 Subject: [PATCH 06/10] =?UTF-8?q?N=C2=B06275=20-=20test=20ormCaseLogServic?= =?UTF-8?q?e=20with=20fake=20iOrmCaseLogExtension=20implementation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/ormcaselogservice.inc.php | 13 ++- .../core/OrmCaseLogExtensionForTest.php | 24 ++++ .../unitary-tests/core/ormCaseLogTest.php | 109 +++++++++++++----- 3 files changed, 109 insertions(+), 37 deletions(-) create mode 100644 tests/php-unit-tests/unitary-tests/core/OrmCaseLogExtensionForTest.php diff --git a/core/ormcaselogservice.inc.php b/core/ormcaselogservice.inc.php index d1e933e3ce..c884da4dd3 100644 --- a/core/ormcaselogservice.inc.php +++ b/core/ormcaselogservice.inc.php @@ -17,20 +17,21 @@ class ormCaseLogService */ protected $aOrmCaseLogExtension = null; - public function __construct() + public function __construct(array $aOrmCaseLogExtensions=null) { + $this->aOrmCaseLogExtension = $aOrmCaseLogExtensions; } protected function LoadCaseLogExtensions() { if ($this->aOrmCaseLogExtension !== null) return; - $aOrmCaseLogExtension = []; - $aProviderClasses = \utils::GetClassesForInterface(iOrmCaseLogExtension::class, '', array('[\\\\/]lib[\\\\/]', '[\\\\/]node_modules[\\\\/]', '[\\\\/]test[\\\\/]', '[\\\\/]tests[\\\\/]')); - foreach($aProviderClasses as $sProviderClass) { - $aOrmCaseLogExtension[] = new $sProviderClass(); + $aOrmCaseLogExtensions = []; + $aOrmCaseLogExtensionClasses = \utils::GetClassesForInterface(iOrmCaseLogExtension::class, '', array('[\\\\/]lib[\\\\/]', '[\\\\/]node_modules[\\\\/]', '[\\\\/]test[\\\\/]', '[\\\\/]tests[\\\\/]')); + foreach($aOrmCaseLogExtensionClasses as $sOrmCaseLogExtensionClass) { + $aOrmCaseLogExtensions[] = new $sOrmCaseLogExtensionClass(); } - $this->aOrmCaseLogExtension = $aOrmCaseLogExtension; + $this->aOrmCaseLogExtension = $aOrmCaseLogExtensions; } /** diff --git a/tests/php-unit-tests/unitary-tests/core/OrmCaseLogExtensionForTest.php b/tests/php-unit-tests/unitary-tests/core/OrmCaseLogExtensionForTest.php new file mode 100644 index 0000000000..ce2641fe6c --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/core/OrmCaseLogExtensionForTest.php @@ -0,0 +1,24 @@ +bTouched = $bTouched; + $this->sReturnedLog = $sReturnedLog; + $this->aReturnedIndex = $aReturnedIndex; + } + + public function Rebuild(&$sLog, &$aIndex) : bool{ + $sLog = $this->sReturnedLog; + $aIndex = $this->aReturnedIndex; + return $this->bTouched; + } +} + diff --git a/tests/php-unit-tests/unitary-tests/core/ormCaseLogTest.php b/tests/php-unit-tests/unitary-tests/core/ormCaseLogTest.php index fb4e81b0fa..1e456c3024 100644 --- a/tests/php-unit-tests/unitary-tests/core/ormCaseLogTest.php +++ b/tests/php-unit-tests/unitary-tests/core/ormCaseLogTest.php @@ -10,7 +10,6 @@ use Combodo\iTop\Test\UnitTest\ItopDataTestCase; use ormCaseLog; - /** * Tests of the ormCaseLog class * @@ -28,7 +27,8 @@ class ormCaseLogTest extends ItopDataTestCase public function setUp() :void{ parent::setUp(); // TODO: Change the autogenerated stub - //require_once APPROOT . "core/CaseLogService.php"; + require_once __DIR__ . "/OrmCaseLogExtensionForTest.php"; + require_once APPROOT . "core/ormcaselogservice.inc.php"; $oAdminProfile = \MetaModel::GetObjectFromOQL("SELECT URP_Profiles WHERE name = :name", array('name' => 'Administrator'), true); @@ -117,13 +117,20 @@ public function testAddLogEntryNoRebuild($bTestAddLogEntry=true){ $this->assertTrue(\UserRights::Login($this->sLogin)); $sLog = "aaaaa"; - $sDate = date(\AttributeDateTime::GetInternalFormat()); + $sJson = json_encode( + [ + 'user_login' => 'gabuzmeu', + 'message' => $sLog, + ] + ); + $oJson = json_decode($sJson); + $iUserId = \UserRights::GetUserId(); $sOnBehalfOf = \UserRights::GetUserFriendlyName(); + $sDate = date(\AttributeDateTime::GetInternalFormat()); $sSeparator = sprintf(CASELOG_SEPARATOR, $sDate, $sOnBehalfOf, $iUserId); $sExpectedLog = $sSeparator."

    $sLog

    "; - $oOrmCaseLogService = $this->createMock(\ormCaseLogService::class); $aExpectedIndex = [ [ 'user_name' => $sOnBehalfOf, @@ -135,22 +142,20 @@ public function testAddLogEntryNoRebuild($bTestAddLogEntry=true){ ] ]; - $oOrmCaseLogService->expects($this->exactly(2)) + //create a real service with no extension to speed up treatment and avoid +1s delta in history diff + $oOrmCaseLogService = new \ormCaseLogService([]); + $oLog = new ormCaseLog('', [], $oOrmCaseLogService); + + $oOrmCaseLogService = $this->createMock(\ormCaseLogService::class); + $oOrmCaseLogService->expects($this->exactly(1)) ->method('Rebuild') - ->withConsecutive(['', []], [$sExpectedLog, $aExpectedIndex]) - ->willReturnOnConsecutiveCalls(null, null); + ->withConsecutive([$sExpectedLog, $aExpectedIndex]) + ->willReturnOnConsecutiveCalls(null); + $this->SetNonPublicProperty($oLog, 'oOrmCaseLogService', $oOrmCaseLogService); - $oLog = new ormCaseLog('', [], $oOrmCaseLogService); if ($bTestAddLogEntry){ $oLog->AddLogEntry($sLog); } else { - $sJson = json_encode( - [ - 'user_login' => 'gabuzmeu', - 'message' => $sLog, - ] - ); - $oJson = json_decode($sJson); $oLog->AddLogEntryFromJSON($oJson, false); } @@ -161,22 +166,26 @@ public function testAddLogEntryNoRebuild($bTestAddLogEntry=true){ /** * @dataProvider AddLogEntryProvider */ - public function testAddLogEntry($bTestAddLogEntry=true){ + public function testAddLogEntryWithRebuild($bTestAddLogEntry=true){ $_SESSION = array(); $this->assertTrue(\UserRights::Login($this->sLogin)); + $aRebuiltIndex = ['c' => 'd']; + $sRebuiltLog = "bbbb"; $sLog = "aaaaa"; - $sDate = date(\AttributeDateTime::GetInternalFormat()); + $sJson = json_encode( + [ + 'user_login' => 'gabuzmeu', + 'message' => $sLog, + ] + ); + $oJson = json_decode($sJson); + $iUserId = \UserRights::GetUserId(); $sOnBehalfOf = \UserRights::GetUserFriendlyName(); + $sDate = date(\AttributeDateTime::GetInternalFormat()); $sSeparator = sprintf(CASELOG_SEPARATOR, $sDate, $sOnBehalfOf, $iUserId); $sExpectedLog = $sSeparator."

    $sLog

    "; - - $aRebuiltIndex = ['c' => 'd']; - $sRebuiltLog = "bbbb"; - - $oOrmCaseLogService = $this->createMock(\ormCaseLogService::class); - $aExpectedIndex = [ [ 'user_name' => $sOnBehalfOf, @@ -187,18 +196,56 @@ public function testAddLogEntry($bTestAddLogEntry=true){ 'format' => 'html', ] ]; - $oOrmCaseLogService->expects($this->exactly(2)) - ->method('Rebuild') - ->withConsecutive(['', []], [$sExpectedLog, $aExpectedIndex]) - ->willReturnOnConsecutiveCalls( - null, - new ormCaseLog($sRebuiltLog, $aRebuiltIndex) - ); + //create a real service with no extension to speed up treatment and avoid +1s delta in history diff + $oOrmCaseLogService = new \ormCaseLogService([]); $oLog = new ormCaseLog('', [], $oOrmCaseLogService); - $oLog->AddLogEntry($sLog); + + $oOrmCaseLogService = $this->createMock(\ormCaseLogService::class); + $oOrmCaseLogService->expects($this->exactly(1)) + ->method('Rebuild') + ->withConsecutive([$sExpectedLog, $aExpectedIndex]) + ->willReturnOnConsecutiveCalls(new ormCaseLog($sRebuiltLog, $aRebuiltIndex)); + $this->SetNonPublicProperty($oLog, 'oOrmCaseLogService', $oOrmCaseLogService); + + if ($bTestAddLogEntry){ + $oLog->AddLogEntry($sLog); + } else { + $oLog->AddLogEntryFromJSON($oJson, false); + } $this->assertEquals($sRebuiltLog, $oLog->GetText()); $this->assertEquals($aRebuiltIndex, $oLog->GetIndex()); } + + public function RebuildThroughApplicationExtensionImplementation(){ + return [ + 'caselog is declared as modified by iOrmCaseLogExtension' => [ true ], + 'caselog is declared as untouched by iOrmCaseLogExtension' => [ false ], + ]; + } + + /** + * @dataProvider RebuildThroughApplicationExtensionImplementation + */ + public function testRebuildThroughApplicationExtensionImplementation(bool $bTouched){ + $sLog = "aaaaa"; + $sRebuiltLog = "bbbb"; + $aInitialIndex = ['a' => 'b']; + $aRebuiltIndex = ['c' => 'd']; + + $aOrmCaseLogExtensionForTest = new \OrmCaseLogExtensionForTest(); + $aOrmCaseLogExtensionForTest->Init($bTouched, $sRebuiltLog, $aRebuiltIndex); + $aOrmCaseLogExtension=[$aOrmCaseLogExtensionForTest]; + $oOrmCaseLogService = new \ormCaseLogService($aOrmCaseLogExtension); + + $oLog = new ormCaseLog($sLog, $aInitialIndex, $oOrmCaseLogService); + if ($bTouched){ + $this->assertEquals($aRebuiltIndex, $oLog->GetIndex()); + $this->assertEquals($sRebuiltLog, $oLog->GetText()); + } else { + $this->assertEquals($aInitialIndex, $oLog->GetIndex()); + $this->assertEquals($sLog, $oLog->GetText()); + } + } } From 99a426028741633e9bead2adb2262a6778ec5709 Mon Sep 17 00:00:00 2001 From: odain Date: Wed, 10 May 2023 15:48:53 +0200 Subject: [PATCH 07/10] =?UTF-8?q?N=C2=B06275=20-=20Denis=20feedbacks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- application/applicationextension.inc.php | 17 ++++++++++++++--- core/ormcaselog.class.inc.php | 1 + .../unitary-tests/core/ormCaseLogTest.php | 15 +++++++++++++++ 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/application/applicationextension.inc.php b/application/applicationextension.inc.php index 4576e4fa04..fdd60deb17 100644 --- a/application/applicationextension.inc.php +++ b/application/applicationextension.inc.php @@ -2251,13 +2251,10 @@ public function __construct(); * Interface to manipulate ormCaseLog objects after initialization/edition * * @api - * @private * @since 3.1.0 N°6275 */ interface iOrmCaseLogExtension { - public function __construct(); - /** * Rebuild API to be able manipulate ormCaseLog after its initialization/modifications * Examples of use: fix ormcase log broken index/shrink huge histories/.... @@ -2268,3 +2265,17 @@ public function __construct(); */ public function Rebuild(&$sLog, &$aIndex) : bool; } + +/** + * Inherit from iOrmCaseLogExtension to manipulate ormCaseLog after its initialization/modifications + * + * @api + * @since 3.1.0 N°6275 + */ +abstract class AbstractOrmCaseLogExtension implements iOrmCaseLogExtension +{ + public function Rebuild(&$sLog, &$aIndex) : bool + { + return false; + } +} diff --git a/core/ormcaselog.class.inc.php b/core/ormcaselog.class.inc.php index bcea172e00..df8fa08447 100644 --- a/core/ormcaselog.class.inc.php +++ b/core/ormcaselog.class.inc.php @@ -757,6 +757,7 @@ public function RebuildIndex(): void if (! is_null($oNewOrmCaseLog)) { $this->m_aIndex = $oNewOrmCaseLog->m_aIndex; $this->m_sLog = $oNewOrmCaseLog->m_sLog; + $this->m_bModified = true; } } } diff --git a/tests/php-unit-tests/unitary-tests/core/ormCaseLogTest.php b/tests/php-unit-tests/unitary-tests/core/ormCaseLogTest.php index 1e456c3024..a2eca74391 100644 --- a/tests/php-unit-tests/unitary-tests/core/ormCaseLogTest.php +++ b/tests/php-unit-tests/unitary-tests/core/ormCaseLogTest.php @@ -234,6 +234,21 @@ public function testRebuildThroughApplicationExtensionImplementation(bool $bTouc $aInitialIndex = ['a' => 'b']; $aRebuiltIndex = ['c' => 'd']; + /*$aOrmCaseLogExtensionForTest = $this->createMock(\iOrmCaseLogExtension::class); + $aOrmCaseLogExtensionForTest->expects($this->exactly(1)) + ->method('Rebuild') + ->with( + $this->callback( + function ($sLogParam, &$aIndexParam) use ($aInitialIndex, $sLog, $aRebuiltIndex, $sRebuiltLog, $bTouched) { + $sLogParam = $sRebuiltLog; + $aIndexParam = $aRebuiltIndex; + return ($sLog === $sLogParam) + && ($aInitialIndex === $sLogParam); + } + ) + ) + ->willReturn($bTouched);*/ + $aOrmCaseLogExtensionForTest = new \OrmCaseLogExtensionForTest(); $aOrmCaseLogExtensionForTest->Init($bTouched, $sRebuiltLog, $aRebuiltIndex); $aOrmCaseLogExtension=[$aOrmCaseLogExtensionForTest]; From 7b36b5f10faf21208ba6b8d1c65bc9c29715a6a8 Mon Sep 17 00:00:00 2001 From: odain Date: Thu, 11 May 2023 09:11:44 +0200 Subject: [PATCH 08/10] =?UTF-8?q?N=C2=B06275=20-=20Add=20configured=20sort?= =?UTF-8?q?ed=20list=20of=20iOrmCaseLogExtension=20:=20ormcaselog=5Fextens?= =?UTF-8?q?ion=5Fclasses?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/config.class.inc.php | 8 + core/ormcaselogservice.inc.php | 28 ++-- .../core/OrmCaseLogExtensionForTest.php | 13 ++ .../core/ormCaseLogServiceTest.php | 140 ++++++++++++++++++ .../unitary-tests/core/ormCaseLogTest.php | 11 +- 5 files changed, 186 insertions(+), 14 deletions(-) create mode 100644 tests/php-unit-tests/unitary-tests/core/ormCaseLogServiceTest.php diff --git a/core/config.class.inc.php b/core/config.class.inc.php index 0bd4418b88..54cb3d2f23 100644 --- a/core/config.class.inc.php +++ b/core/config.class.inc.php @@ -1523,6 +1523,14 @@ class Config 'source_of_value' => '', 'show_in_conf_sample' => false, ], + 'ormcaselog_extension_classes' => [ + 'type' => 'array', + 'description' => 'Sorted list of enabled iOrmCaseLogExtension implementation classes', + 'default' => [], + 'value' => [], + 'source_of_value' => '', + 'show_in_conf_sample' => false, + ], 'regenerate_session_id_enabled' => [ 'type' => 'bool', 'description' => 'If true then session id will be regenerated on each login, to prevent session fixation.', diff --git a/core/ormcaselogservice.inc.php b/core/ormcaselogservice.inc.php index c884da4dd3..7e2d077bec 100644 --- a/core/ormcaselogservice.inc.php +++ b/core/ormcaselogservice.inc.php @@ -15,23 +15,31 @@ class ormCaseLogService * Array of "providers" of welcome popup messages * @var iOrmCaseLogExtension[] */ - protected $aOrmCaseLogExtension = null; + protected $aOrmCaseLogExtensions = null; public function __construct(array $aOrmCaseLogExtensions=null) { - $this->aOrmCaseLogExtension = $aOrmCaseLogExtensions; + $this->aOrmCaseLogExtensions = $aOrmCaseLogExtensions; } - protected function LoadCaseLogExtensions() + protected function LoadCaseLogExtensions($aClassesForInterfaceOrmCaseLog=null) : array { - if ($this->aOrmCaseLogExtension !== null) return; + if ($this->aOrmCaseLogExtensions !== null) return $this->aOrmCaseLogExtensions; - $aOrmCaseLogExtensions = []; - $aOrmCaseLogExtensionClasses = \utils::GetClassesForInterface(iOrmCaseLogExtension::class, '', array('[\\\\/]lib[\\\\/]', '[\\\\/]node_modules[\\\\/]', '[\\\\/]test[\\\\/]', '[\\\\/]tests[\\\\/]')); - foreach($aOrmCaseLogExtensionClasses as $sOrmCaseLogExtensionClass) { - $aOrmCaseLogExtensions[] = new $sOrmCaseLogExtensionClass(); + if ($aClassesForInterfaceOrmCaseLog === null) { + $aClassesForInterfaceOrmCaseLog = \utils::GetClassesForInterface(iOrmCaseLogExtension::class, '', + array('[\\\\/]lib[\\\\/]', '[\\\\/]node_modules[\\\\/]', '[\\\\/]test[\\\\/]', '[\\\\/]tests[\\\\/]')); } - $this->aOrmCaseLogExtension = $aOrmCaseLogExtensions; + + $aConfiguredOrmCaseLogExtensionClasses = MetaModel::GetConfig()->Get('ormcaselog_extension_classes'); + $this->aOrmCaseLogExtensions = []; + foreach ($aConfiguredOrmCaseLogExtensionClasses as $sConfiguredOrmCaseLogExtensionClass) { + if (in_array($sConfiguredOrmCaseLogExtensionClass, $aClassesForInterfaceOrmCaseLog)){ + $this->aOrmCaseLogExtensions[] = new $sConfiguredOrmCaseLogExtensionClass(); + } + } + + return $this->aOrmCaseLogExtensions; } /** @@ -45,7 +53,7 @@ public function Rebuild($sLog, $aIndex) : ?\ormCaseLog $this->LoadCaseLogExtensions(); $bTouched = false; - foreach ($this->aOrmCaseLogExtension as $oOrmCaseLogExtension){ + foreach ($this->aOrmCaseLogExtensions as $oOrmCaseLogExtension){ /** var iOrmCaseLogExtension $oOrmCaseLogExtension */ $bTouched = $bTouched || $oOrmCaseLogExtension->Rebuild($sLog, $aIndex); } diff --git a/tests/php-unit-tests/unitary-tests/core/OrmCaseLogExtensionForTest.php b/tests/php-unit-tests/unitary-tests/core/OrmCaseLogExtensionForTest.php index ce2641fe6c..f632b385ac 100644 --- a/tests/php-unit-tests/unitary-tests/core/OrmCaseLogExtensionForTest.php +++ b/tests/php-unit-tests/unitary-tests/core/OrmCaseLogExtensionForTest.php @@ -1,5 +1,7 @@ [ + 'aClassesForInterfaceOrmCaseLog' => [], + 'ormcaselog_extension_classes' => null, + 'aExpectedOrmCaseLogExtensions' => [], + ], + 'default conf with extension implemented' => [ + 'aClassesForInterfaceOrmCaseLog' => [$sExtensionClass1], + 'ormcaselog_extension_classes' => null, + 'aExpectedOrmCaseLogExtensions' => [], + ], + 'conf but not extension implemented' => [ + 'aClassesForInterfaceOrmCaseLog' => [], + 'ormcaselog_extension_classes' => [ $sExtensionClass1 ], + 'aExpectedOrmCaseLogExtensions' => [], + ], + 'one extension configured/implemented' => [ + 'aClassesForInterfaceOrmCaseLog' => [$sExtensionClass1], + 'ormcaselog_extension_classes' => [ $sExtensionClass1 ], + 'aExpectedOrmCaseLogExtensions' => [$sExtensionClass1], + ], + 'one extension configured' => [ + 'aClassesForInterfaceOrmCaseLog' => [ + $sExtensionClass3, + $sExtensionClass1, + $sExtensionClass2, + ], + 'ormcaselog_extension_classes' => [ $sExtensionClass1 ], + 'aExpectedOrmCaseLogExtensions' => [$sExtensionClass1], + ], + '3 sorted extensions' => [ + 'aClassesForInterfaceOrmCaseLog' => [ + $sExtensionClass3, + $sExtensionClass1, + $sExtensionClass2, + ], + 'ormcaselog_extension_classes' => [ + $sExtensionClass1, + $sExtensionClass2, + $sExtensionClass3 + ], + 'aExpectedOrmCaseLogExtensions' => [ + $sExtensionClass1, + $sExtensionClass2, + $sExtensionClass3 + ], + ], + ]; + } + + /** + * @dataProvider LoadCaseLogExtensionsProvider + */ + public function testLoadCaseLogExtensions($aClassesForInterfaceOrmCaseLog, $aDedicatedParamConf, $aExpectedOrmCaseLogExtensions) { + if (!is_null($aDedicatedParamConf)){ + \MetaModel::GetConfig()->Set('ormcaselog_extension_classes', $aDedicatedParamConf); + var_dump($aDedicatedParamConf); + } + + $oOrmCaseLogService = new \ormCaseLogService(); + + $aRes = $this->InvokeNonPublicMethod(\ormCaseLogService::class, "LoadCaseLogExtensions", $oOrmCaseLogService, + [$aClassesForInterfaceOrmCaseLog]); + + $this->assertEquals(sizeof($aExpectedOrmCaseLogExtensions), sizeof($aRes)); + foreach ($aRes as $i => $aExtensionObject){ + $sExpectedClass = $aExpectedOrmCaseLogExtensions[$i]; + $this->assertEquals($sExpectedClass, get_class($aExtensionObject)); + } + } + + public function testDefaultLoadCaseLogExtensions() { + $oOrmCaseLogService = new \ormCaseLogService(); + + $aRes = $this->InvokeNonPublicMethod(\ormCaseLogService::class, "LoadCaseLogExtensions", $oOrmCaseLogService, + []); + + $this->assertEquals(0, sizeof($aRes), 'no extension running by default on iTop'); + } + + public function testLoadCaseLogExtensions_Memorize() { + $sNamespace = 'Combodo\\iTop\\Test\\'; + $sExtensionClass1 = $sNamespace . \FakeOrmCaseLogExtension1::class; + $sExtensionClass2 = $sNamespace . \FakeOrmCaseLogExtension2::class; + $aExtensions = [$sExtensionClass1]; + \MetaModel::GetConfig()->Set('ormcaselog_extension_classes', $aExtensions); + + $oOrmCaseLogService = new \ormCaseLogService(); + $aRes = $this->InvokeNonPublicMethod(\ormCaseLogService::class, "LoadCaseLogExtensions", $oOrmCaseLogService, + [$aExtensions]); + + //load first time + $this->assertEquals(sizeof($aExtensions), sizeof($aRes)); + + $aMoreExtensions = [$sExtensionClass1, $sExtensionClass2]; + \MetaModel::GetConfig()->Set('ormcaselog_extension_classes', $aMoreExtensions); + $aRes = $this->InvokeNonPublicMethod(\ormCaseLogService::class, "LoadCaseLogExtensions", $oOrmCaseLogService, + [$aMoreExtensions]); + $this->assertEquals(sizeof($aExtensions), sizeof($aRes), 'should still have one extension (memorized)'); + + $oOrmCaseLogService = new \ormCaseLogService(); + $aRes = $this->InvokeNonPublicMethod(\ormCaseLogService::class, "LoadCaseLogExtensions", $oOrmCaseLogService, + [$aMoreExtensions]); + $this->assertEquals(sizeof($aMoreExtensions), sizeof($aRes), 'first time load'); + } +} diff --git a/tests/php-unit-tests/unitary-tests/core/ormCaseLogTest.php b/tests/php-unit-tests/unitary-tests/core/ormCaseLogTest.php index a2eca74391..2d224fc82d 100644 --- a/tests/php-unit-tests/unitary-tests/core/ormCaseLogTest.php +++ b/tests/php-unit-tests/unitary-tests/core/ormCaseLogTest.php @@ -125,6 +125,9 @@ public function testAddLogEntryNoRebuild($bTestAddLogEntry=true){ ); $oJson = json_decode($sJson); + //create a real service with no extension to speed up treatment and avoid +1s delta in history diff + $oOrmCaseLogService = new \ormCaseLogService([]); + $iUserId = \UserRights::GetUserId(); $sOnBehalfOf = \UserRights::GetUserFriendlyName(); $sDate = date(\AttributeDateTime::GetInternalFormat()); @@ -142,8 +145,6 @@ public function testAddLogEntryNoRebuild($bTestAddLogEntry=true){ ] ]; - //create a real service with no extension to speed up treatment and avoid +1s delta in history diff - $oOrmCaseLogService = new \ormCaseLogService([]); $oLog = new ormCaseLog('', [], $oOrmCaseLogService); $oOrmCaseLogService = $this->createMock(\ormCaseLogService::class); @@ -181,6 +182,9 @@ public function testAddLogEntryWithRebuild($bTestAddLogEntry=true){ ); $oJson = json_decode($sJson); + //create a real service with no extension to speed up treatment and avoid +1s delta in history diff + $oOrmCaseLogService = new \ormCaseLogService([]); + $iUserId = \UserRights::GetUserId(); $sOnBehalfOf = \UserRights::GetUserFriendlyName(); $sDate = date(\AttributeDateTime::GetInternalFormat()); @@ -197,8 +201,6 @@ public function testAddLogEntryWithRebuild($bTestAddLogEntry=true){ ] ]; - //create a real service with no extension to speed up treatment and avoid +1s delta in history diff - $oOrmCaseLogService = new \ormCaseLogService([]); $oLog = new ormCaseLog('', [], $oOrmCaseLogService); $oOrmCaseLogService = $this->createMock(\ormCaseLogService::class); @@ -262,5 +264,6 @@ function ($sLogParam, &$aIndexParam) use ($aInitialIndex, $sLog, $aRebuiltIndex, $this->assertEquals($aInitialIndex, $oLog->GetIndex()); $this->assertEquals($sLog, $oLog->GetText()); } + $this->assertEquals($bTouched, $this->GetNonPublicProperty($oLog, 'm_bModified')); } } From a6a3a02bb4623249d9be96b1f782aa26cecccc2e Mon Sep 17 00:00:00 2001 From: odain Date: Thu, 11 May 2023 09:49:15 +0200 Subject: [PATCH 09/10] =?UTF-8?q?N=C2=B06275=20-=20test=20class=20renaming?= =?UTF-8?q?=20for=20ci?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../php-unit-tests/unitary-tests/core/ormCaseLogServiceTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/php-unit-tests/unitary-tests/core/ormCaseLogServiceTest.php b/tests/php-unit-tests/unitary-tests/core/ormCaseLogServiceTest.php index 6d9d87e63b..0c3dc15fc5 100644 --- a/tests/php-unit-tests/unitary-tests/core/ormCaseLogServiceTest.php +++ b/tests/php-unit-tests/unitary-tests/core/ormCaseLogServiceTest.php @@ -18,7 +18,7 @@ * @preserveGlobalState disabled * @backupGlobals disabled */ -class ormCaseLogTest extends ItopDataTestCase +class ormCaseLogServiceTest extends ItopDataTestCase { public function setUp() :void{ parent::setUp(); // TODO: Change the autogenerated stub From c3d880bf2d737498fc4bc01d9e102779b0f1fb9f Mon Sep 17 00:00:00 2001 From: odain Date: Thu, 11 May 2023 14:21:19 +0200 Subject: [PATCH 10/10] =?UTF-8?q?N=C2=B06275=20-=20fix=20test=20broken=20t?= =?UTF-8?q?o=20missing=20namespace=20(ormCaseLogTest.testRebuildThroughApp?= =?UTF-8?q?licationExtensionImplementation)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../unitary-tests/core/OrmCaseLogExtensionForTest.php | 2 +- tests/php-unit-tests/unitary-tests/core/ormCaseLogTest.php | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/php-unit-tests/unitary-tests/core/OrmCaseLogExtensionForTest.php b/tests/php-unit-tests/unitary-tests/core/OrmCaseLogExtensionForTest.php index f632b385ac..8ddc07fe19 100644 --- a/tests/php-unit-tests/unitary-tests/core/OrmCaseLogExtensionForTest.php +++ b/tests/php-unit-tests/unitary-tests/core/OrmCaseLogExtensionForTest.php @@ -2,7 +2,7 @@ namespace Combodo\iTop\Test; -class OrmCaseLogExtensionForTest implements \iOrmCaseLogExtension +class OrmCaseLogExtensionForTest extends \AbstractOrmCaseLogExtension { private $sReturnedLog; private $aReturnedIndex; diff --git a/tests/php-unit-tests/unitary-tests/core/ormCaseLogTest.php b/tests/php-unit-tests/unitary-tests/core/ormCaseLogTest.php index 2d224fc82d..65d424945f 100644 --- a/tests/php-unit-tests/unitary-tests/core/ormCaseLogTest.php +++ b/tests/php-unit-tests/unitary-tests/core/ormCaseLogTest.php @@ -7,6 +7,7 @@ namespace Combodo\iTop\Test\UnitTest\Core; +use Combodo\iTop\Test\OrmCaseLogExtensionForTest; use Combodo\iTop\Test\UnitTest\ItopDataTestCase; use ormCaseLog; @@ -251,7 +252,7 @@ function ($sLogParam, &$aIndexParam) use ($aInitialIndex, $sLog, $aRebuiltIndex, ) ->willReturn($bTouched);*/ - $aOrmCaseLogExtensionForTest = new \OrmCaseLogExtensionForTest(); + $aOrmCaseLogExtensionForTest = new OrmCaseLogExtensionForTest(); $aOrmCaseLogExtensionForTest->Init($bTouched, $sRebuiltLog, $aRebuiltIndex); $aOrmCaseLogExtension=[$aOrmCaseLogExtensionForTest]; $oOrmCaseLogService = new \ormCaseLogService($aOrmCaseLogExtension);