diff --git a/application/exceptions/mysql/MySQLTransactionNotClosedException.php b/application/exceptions/mysql/MySQLTransactionNotClosedException.php new file mode 100644 index 000000000..b24824a38 --- /dev/null +++ b/application/exceptions/mysql/MySQLTransactionNotClosedException.php @@ -0,0 +1,13 @@ + path - * @psalm-var array + * @psalm-return array */ public function getClassMap() { diff --git a/lib/composer/autoload_classmap.php b/lib/composer/autoload_classmap.php index 2b15a43a4..0137d277d 100644 --- a/lib/composer/autoload_classmap.php +++ b/lib/composer/autoload_classmap.php @@ -2,7 +2,7 @@ // autoload_classmap.php @generated by Composer -$vendorDir = dirname(dirname(__FILE__)); +$vendorDir = dirname(__DIR__); $baseDir = dirname($vendorDir); return array( @@ -1018,6 +1018,7 @@ return array( 'MySQLHasGoneAwayException' => $baseDir . '/application/exceptions/mysql/MySQLHasGoneAwayException.php', 'MySQLNoTransactionException' => $baseDir . '/application/exceptions/mysql/MySQLNoTransactionException.php', 'MySQLQueryHasNoResultException' => $baseDir . '/application/exceptions/mysql/MySQLQueryHasNoResultException.php', + 'MySQLTransactionNotClosedException' => $baseDir . '/application/exceptions/mysql/MySQLTransactionNotClosedException.php', 'NestedQueryExpression' => $baseDir . '/core/oql/expression.class.inc.php', 'NestedQueryOqlExpression' => $baseDir . '/core/oql/oqlquery.class.inc.php', 'NewObjectMenuNode' => $baseDir . '/application/menunode.class.inc.php', @@ -1388,6 +1389,7 @@ return array( 'RotatingLogFileNameBuilder' => $baseDir . '/core/log.class.inc.php', 'RowStatus' => $baseDir . '/core/bulkchange.class.inc.php', 'RowStatus_Disappeared' => $baseDir . '/core/bulkchange.class.inc.php', + 'RowStatus_Error' => $baseDir . '/core/bulkchange.class.inc.php', 'RowStatus_Issue' => $baseDir . '/core/bulkchange.class.inc.php', 'RowStatus_Modify' => $baseDir . '/core/bulkchange.class.inc.php', 'RowStatus_NewObj' => $baseDir . '/core/bulkchange.class.inc.php', diff --git a/lib/composer/autoload_files.php b/lib/composer/autoload_files.php index 9ca87aae9..cbe23f179 100644 --- a/lib/composer/autoload_files.php +++ b/lib/composer/autoload_files.php @@ -2,24 +2,24 @@ // autoload_files.php @generated by Composer -$vendorDir = dirname(dirname(__FILE__)); +$vendorDir = dirname(__DIR__); $baseDir = dirname($vendorDir); return array( - '6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php', 'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php', + '6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php', '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php', '320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php', - '0d59ee240a4cd96ddbb4ff164fccea4d' => $vendorDir . '/symfony/polyfill-php73/bootstrap.php', '23c18046f52bef3eea034657bafda50f' => $vendorDir . '/symfony/polyfill-php81/bootstrap.php', + '0d59ee240a4cd96ddbb4ff164fccea4d' => $vendorDir . '/symfony/polyfill-php73/bootstrap.php', '667aeda72477189d0494fecd327c3641' => $vendorDir . '/symfony/var-dumper/Resources/functions/dump.php', - 'e69f7f6ee287b969198c3c9d6777bd38' => $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php', - 'c9d07b32a2e02bc0fc582d4f0c1b56cc' => $vendorDir . '/laminas/laminas-servicemanager/src/autoload.php', '7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php', - '8825ede83f2f289127722d4e842cf7e8' => $vendorDir . '/symfony/polyfill-intl-grapheme/bootstrap.php', 'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php', - 'b6b991a57620e2fb6b2f66f03fe9ddc2' => $vendorDir . '/symfony/string/Resources/functions.php', + 'e69f7f6ee287b969198c3c9d6777bd38' => $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php', '37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php', + 'c9d07b32a2e02bc0fc582d4f0c1b56cc' => $vendorDir . '/laminas/laminas-servicemanager/src/autoload.php', + '8825ede83f2f289127722d4e842cf7e8' => $vendorDir . '/symfony/polyfill-intl-grapheme/bootstrap.php', '25072dd6e2470089de65ae7bf11d3109' => $vendorDir . '/symfony/polyfill-php72/bootstrap.php', 'f598d06aa772fa33d905e87be6398fb1' => $vendorDir . '/symfony/polyfill-intl-idn/bootstrap.php', + 'b6b991a57620e2fb6b2f66f03fe9ddc2' => $vendorDir . '/symfony/string/Resources/functions.php', ); diff --git a/lib/composer/autoload_namespaces.php b/lib/composer/autoload_namespaces.php index 1db5bf646..6629b7e09 100644 --- a/lib/composer/autoload_namespaces.php +++ b/lib/composer/autoload_namespaces.php @@ -2,7 +2,7 @@ // autoload_namespaces.php @generated by Composer -$vendorDir = dirname(dirname(__FILE__)); +$vendorDir = dirname(__DIR__); $baseDir = dirname($vendorDir); return array( diff --git a/lib/composer/autoload_psr4.php b/lib/composer/autoload_psr4.php index eb2c95ace..3b30be01d 100644 --- a/lib/composer/autoload_psr4.php +++ b/lib/composer/autoload_psr4.php @@ -2,7 +2,7 @@ // autoload_psr4.php @generated by Composer -$vendorDir = dirname(dirname(__FILE__)); +$vendorDir = dirname(__DIR__); $baseDir = dirname($vendorDir); return array( diff --git a/lib/composer/autoload_real.php b/lib/composer/autoload_real.php index cc554d8d1..dda4f956d 100644 --- a/lib/composer/autoload_real.php +++ b/lib/composer/autoload_real.php @@ -25,33 +25,20 @@ class ComposerAutoloaderInit7f81b4a2a468a061c306af5e447a9a9f require __DIR__ . '/platform_check.php'; spl_autoload_register(array('ComposerAutoloaderInit7f81b4a2a468a061c306af5e447a9a9f', 'loadClassLoader'), true, true); - self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__))); + self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__)); spl_autoload_unregister(array('ComposerAutoloaderInit7f81b4a2a468a061c306af5e447a9a9f', 'loadClassLoader')); $includePaths = require __DIR__ . '/include_paths.php'; $includePaths[] = get_include_path(); set_include_path(implode(PATH_SEPARATOR, $includePaths)); - $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); - if ($useStaticLoader) { - require __DIR__ . '/autoload_static.php'; - - call_user_func(\Composer\Autoload\ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f::getInitializer($loader)); - } else { - $classMap = require __DIR__ . '/autoload_classmap.php'; - if ($classMap) { - $loader->addClassMap($classMap); - } - } + require __DIR__ . '/autoload_static.php'; + call_user_func(\Composer\Autoload\ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f::getInitializer($loader)); $loader->setClassMapAuthoritative(true); $loader->register(true); - if ($useStaticLoader) { - $includeFiles = Composer\Autoload\ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f::$files; - } else { - $includeFiles = require __DIR__ . '/autoload_files.php'; - } + $includeFiles = \Composer\Autoload\ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f::$files; foreach ($includeFiles as $fileIdentifier => $file) { composerRequire7f81b4a2a468a061c306af5e447a9a9f($fileIdentifier, $file); } @@ -60,11 +47,16 @@ class ComposerAutoloaderInit7f81b4a2a468a061c306af5e447a9a9f } } +/** + * @param string $fileIdentifier + * @param string $file + * @return void + */ function composerRequire7f81b4a2a468a061c306af5e447a9a9f($fileIdentifier, $file) { if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { - require $file; - $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; + + require $file; } } diff --git a/lib/composer/autoload_static.php b/lib/composer/autoload_static.php index 84624a0ba..6866fc9e7 100644 --- a/lib/composer/autoload_static.php +++ b/lib/composer/autoload_static.php @@ -7,22 +7,22 @@ namespace Composer\Autoload; class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f { public static $files = array ( - '6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php', 'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php', + '6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php', '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php', '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php', - '0d59ee240a4cd96ddbb4ff164fccea4d' => __DIR__ . '/..' . '/symfony/polyfill-php73/bootstrap.php', '23c18046f52bef3eea034657bafda50f' => __DIR__ . '/..' . '/symfony/polyfill-php81/bootstrap.php', + '0d59ee240a4cd96ddbb4ff164fccea4d' => __DIR__ . '/..' . '/symfony/polyfill-php73/bootstrap.php', '667aeda72477189d0494fecd327c3641' => __DIR__ . '/..' . '/symfony/var-dumper/Resources/functions/dump.php', - 'e69f7f6ee287b969198c3c9d6777bd38' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/bootstrap.php', - 'c9d07b32a2e02bc0fc582d4f0c1b56cc' => __DIR__ . '/..' . '/laminas/laminas-servicemanager/src/autoload.php', '7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php', - '8825ede83f2f289127722d4e842cf7e8' => __DIR__ . '/..' . '/symfony/polyfill-intl-grapheme/bootstrap.php', 'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php', - 'b6b991a57620e2fb6b2f66f03fe9ddc2' => __DIR__ . '/..' . '/symfony/string/Resources/functions.php', + 'e69f7f6ee287b969198c3c9d6777bd38' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/bootstrap.php', '37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php', + 'c9d07b32a2e02bc0fc582d4f0c1b56cc' => __DIR__ . '/..' . '/laminas/laminas-servicemanager/src/autoload.php', + '8825ede83f2f289127722d4e842cf7e8' => __DIR__ . '/..' . '/symfony/polyfill-intl-grapheme/bootstrap.php', '25072dd6e2470089de65ae7bf11d3109' => __DIR__ . '/..' . '/symfony/polyfill-php72/bootstrap.php', 'f598d06aa772fa33d905e87be6398fb1' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/bootstrap.php', + 'b6b991a57620e2fb6b2f66f03fe9ddc2' => __DIR__ . '/..' . '/symfony/string/Resources/functions.php', ); public static $prefixLengthsPsr4 = array ( @@ -1383,6 +1383,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f 'MySQLHasGoneAwayException' => __DIR__ . '/../..' . '/application/exceptions/mysql/MySQLHasGoneAwayException.php', 'MySQLNoTransactionException' => __DIR__ . '/../..' . '/application/exceptions/mysql/MySQLNoTransactionException.php', 'MySQLQueryHasNoResultException' => __DIR__ . '/../..' . '/application/exceptions/mysql/MySQLQueryHasNoResultException.php', + 'MySQLTransactionNotClosedException' => __DIR__ . '/../..' . '/application/exceptions/mysql/MySQLTransactionNotClosedException.php', 'NestedQueryExpression' => __DIR__ . '/../..' . '/core/oql/expression.class.inc.php', 'NestedQueryOqlExpression' => __DIR__ . '/../..' . '/core/oql/oqlquery.class.inc.php', 'NewObjectMenuNode' => __DIR__ . '/../..' . '/application/menunode.class.inc.php', @@ -1753,6 +1754,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f 'RotatingLogFileNameBuilder' => __DIR__ . '/../..' . '/core/log.class.inc.php', 'RowStatus' => __DIR__ . '/../..' . '/core/bulkchange.class.inc.php', 'RowStatus_Disappeared' => __DIR__ . '/../..' . '/core/bulkchange.class.inc.php', + 'RowStatus_Error' => __DIR__ . '/../..' . '/core/bulkchange.class.inc.php', 'RowStatus_Issue' => __DIR__ . '/../..' . '/core/bulkchange.class.inc.php', 'RowStatus_Modify' => __DIR__ . '/../..' . '/core/bulkchange.class.inc.php', 'RowStatus_NewObj' => __DIR__ . '/../..' . '/core/bulkchange.class.inc.php', diff --git a/lib/composer/include_paths.php b/lib/composer/include_paths.php index d4fb96718..af33c1491 100644 --- a/lib/composer/include_paths.php +++ b/lib/composer/include_paths.php @@ -2,7 +2,7 @@ // include_paths.php @generated by Composer -$vendorDir = dirname(dirname(__FILE__)); +$vendorDir = dirname(__DIR__); $baseDir = dirname($vendorDir); return array( diff --git a/test/ItopDataTestCase.php b/test/ItopDataTestCase.php index 63a82b11a..b2a2bde13 100644 --- a/test/ItopDataTestCase.php +++ b/test/ItopDataTestCase.php @@ -127,12 +127,13 @@ class ItopDataTestCase extends ItopTestCase $this->debug("Removing $sClass::$iKey"); $oObject->DBDelete(); } - catch (Exception $e) - { - $this->debug($e->getMessage()); + catch (Exception $e) { + $this->debug("Error when removing created objects : $sClass::$iKey. Exception message: ".$e->getMessage()); } } } + + parent::tearDown(); } /** diff --git a/test/ItopTestCase.php b/test/ItopTestCase.php index 8c81c40b6..203a4c886 100644 --- a/test/ItopTestCase.php +++ b/test/ItopTestCase.php @@ -25,6 +25,8 @@ namespace Combodo\iTop\Test\UnitTest; * Time: 11:21 */ +use CMDBSource; +use MySQLTransactionNotClosedException; use PHPUnit\Framework\TestCase; use SetupUtils; @@ -48,15 +50,26 @@ class ItopTestCase extends TestCase @include_once getcwd().'/approot.inc.php'; // this is when launching phpunit from within the IDE } + /** + * @throws \MySQLTransactionNotClosedException see N°5538 + * @since 2.7.8 3.0.3 3.1.0 N°5538 + */ + protected function tearDown(): void + { + parent::tearDown(); + + if (CMDBSource::IsInsideTransaction()) { + // Nested transactions were opened but not finished ! + throw new MySQLTransactionNotClosedException('Some DB transactions were opened but not closed ! Fix the code by adding ROLLBACK or COMMIT statements !', []); + } + } + protected function debug($sMsg) - { - if (DEBUG_UNIT_TEST) - { - if (is_string($sMsg)) - { - echo "$sMsg\n"; - } - else { + { + if (DEBUG_UNIT_TEST) { + if (is_string($sMsg)) { + echo "$sMsg\n"; + } else { /** @noinspection ForgottenDebugOutputInspection */ print_r($sMsg); } diff --git a/test/core/CMDBSource/TransactionsTest.php b/test/core/CMDBSource/TransactionsTest.php index 00f9872d8..8882ab59f 100644 --- a/test/core/CMDBSource/TransactionsTest.php +++ b/test/core/CMDBSource/TransactionsTest.php @@ -11,6 +11,7 @@ use Combodo\iTop\Core\DbConnectionWrapper; use Combodo\iTop\Test\UnitTest\ItopTestCase; use Exception; use MetaModel; +use MySQLTransactionNotClosedException; /** * @runTestsInSeparateProcesses @@ -231,22 +232,56 @@ class TransactionsTest extends ItopTestCase public function DBUpdateProvider() { return [ - "Normal case" => ['iFailAt' => -1, 'bIsModified' => false], - "ticket_request" => ['iFailAt' => 1, 'bIsModified' => true], + "Normal case" => ['iFailAt' => -1, 'bIsModified' => false], + "ticket_request" => ['iFailAt' => 1, 'bIsModified' => true], "lnkcontacttoticket" => ['iFailAt' => 2, 'bIsModified' => true], - "History 1" => ['iFailAt' => 3, 'bIsModified' => true], - "History 2" => ['iFailAt' => 4, 'bIsModified' => true], - "History 3" => ['iFailAt' => 5, 'bIsModified' => true], - "History 4" => ['iFailAt' => 6, 'bIsModified' => true], - "History 5" => ['iFailAt' => 7, 'bIsModified' => true], - "History 6" => ['iFailAt' => 8, 'bIsModified' => true], - "History 7" => ['iFailAt' => 9, 'bIsModified' => true], - "History 8" => ['iFailAt' => 10, 'bIsModified' => true], - "History 9" => ['iFailAt' => 11, 'bIsModified' => true], - "History 10" => ['iFailAt' => 12, 'bIsModified' => true], - "History 11" => ['iFailAt' => 13, 'bIsModified' => true], - "History 12" => ['iFailAt' => 14, 'bIsModified' => true], - "History 13" => ['iFailAt' => 15, 'bIsModified' => true], + "History 1" => ['iFailAt' => 3, 'bIsModified' => true], + "History 2" => ['iFailAt' => 4, 'bIsModified' => true], + "History 3" => ['iFailAt' => 5, 'bIsModified' => true], + "History 4" => ['iFailAt' => 6, 'bIsModified' => true], + "History 5" => ['iFailAt' => 7, 'bIsModified' => true], + "History 6" => ['iFailAt' => 8, 'bIsModified' => true], + "History 7" => ['iFailAt' => 9, 'bIsModified' => true], + "History 8" => ['iFailAt' => 10, 'bIsModified' => true], + "History 9" => ['iFailAt' => 11, 'bIsModified' => true], + "History 10" => ['iFailAt' => 12, 'bIsModified' => true], + "History 11" => ['iFailAt' => 13, 'bIsModified' => true], + "History 12" => ['iFailAt' => 14, 'bIsModified' => true], + "History 13" => ['iFailAt' => 15, 'bIsModified' => true], ]; } -} + + /** + * @return void + * @doesNotPerformAssertions + */ + public function testTransactionOpenedThenClosed() + { + CMDBSource::Query('START TRANSACTION;'); + CMDBSource::Query('COMMIT;'); + } + + /** + * This will throw an exception in the tearDown method. + * This cannot be detected nor by `@expectedException` nor `expectException` method, so we have a specific tearDown impl + * + * @return void + * @doesNotPerformAssertions + */ + public function testTransactionOpenedNotClosed() + { + CMDBSource::Query('START TRANSACTION;'); + } + + protected function tearDown(): void + { + try { + parent::tearDown(); + } + catch (MySQLTransactionNotClosedException $e) { + if ($this->getName() === 'testTransactionOpenedNotClosed') { + $this->debug('Executing the testTransactionOpenNoClose method throws a '.MySQLTransactionNotClosedException::class.' exception in tearDown'); + } + } + } +} \ No newline at end of file diff --git a/test/core/apcEmulationTest.php b/test/core/apcEmulationTest.php index 1e44faa55..912554fee 100644 --- a/test/core/apcEmulationTest.php +++ b/test/core/apcEmulationTest.php @@ -50,6 +50,7 @@ class apcEmulationTest extends ItopTestCase public function tearDown(): void { apc_clear_cache(); + parent::tearDown(); } public function testBasic() diff --git a/test/core/dictApcuTest.php b/test/core/dictApcuTest.php index c7f74e899..332bab81e 100644 --- a/test/core/dictApcuTest.php +++ b/test/core/dictApcuTest.php @@ -115,6 +115,8 @@ PHP; } rmdir(APPROOT."env-$this->sEnvName".DIRECTORY_SEPARATOR."dictionaries"); rmdir(APPROOT."env-$this->sEnvName"); + + parent::tearDown(); } public function InitLangIfNeeded_NoApcProvider(){ diff --git a/test/core/dictTest.php b/test/core/dictTest.php index 6c6588db7..96ec0a923 100644 --- a/test/core/dictTest.php +++ b/test/core/dictTest.php @@ -80,6 +80,8 @@ PHP; } rmdir(APPROOT."env-$this->sEnvName".DIRECTORY_SEPARATOR."dictionaries"); rmdir(APPROOT."env-$this->sEnvName"); + + parent::tearDown(); } /**