mirror of
https://github.com/moodle/moodle.git
synced 2025-06-02 14:15:11 +02:00
MDL-60978 testing: Support ability to run phpunit in isolated process
This commit is contained in:
parent
f1a8db6911
commit
fc1785b086
@ -80,8 +80,6 @@ if ($phpunitversion === '@package_version@') {
|
||||
}
|
||||
unset($phpunitversion);
|
||||
|
||||
define('NO_OUTPUT_BUFFERING', true);
|
||||
|
||||
// only load CFG from config.php, stop ASAP in lib/setup.php
|
||||
define('ABORT_AFTER_CONFIG', true);
|
||||
require(__DIR__ . '/../../config.php');
|
||||
|
@ -56,7 +56,7 @@ abstract class advanced_testcase extends base_testcase {
|
||||
|
||||
$this->setBackupGlobals(false);
|
||||
$this->setBackupStaticAttributes(false);
|
||||
$this->setRunTestInSeparateProcess(false);
|
||||
$this->setPreserveGlobalState(false);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -490,19 +490,6 @@ abstract class advanced_testcase extends base_testcase {
|
||||
return phpunit_util::start_event_redirection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup after all tests are executed.
|
||||
*
|
||||
* Note: do not forget to call this if overridden...
|
||||
*
|
||||
* @static
|
||||
* @return void
|
||||
*/
|
||||
public static function tearDownAfterClass() {
|
||||
self::resetAllData();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reset all database tables, restore global state and clear caches and optionally purge dataroot dir.
|
||||
*
|
||||
|
@ -984,4 +984,16 @@ class phpunit_util extends testing_util {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the current process is an isolated test process.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_in_isolated_process(): bool {
|
||||
// Note: There is no function to call, or much to go by in order to tell whether we are in an isolated process
|
||||
// during Bootstrap, when this function is called.
|
||||
// We can do so by testing the existence of the wrapper function, but there is nothing set until that point.
|
||||
return function_exists('__phpunit_run_isolated_test');
|
||||
}
|
||||
}
|
||||
|
@ -539,6 +539,10 @@ class core_phpunit_advanced_testcase extends advanced_testcase {
|
||||
* @depends test_message_redirection
|
||||
*/
|
||||
public function test_message_redirection_noreset($sink) {
|
||||
if ($this->isInIsolation()) {
|
||||
$this->markTestSkipped('State cannot be carried over between tests in isolated tests');
|
||||
}
|
||||
|
||||
$this->preventResetByRollback(); // Messaging is not compatible with transactions...
|
||||
$this->resetAfterTest();
|
||||
|
||||
|
@ -620,8 +620,12 @@ setup_validate_php_configuration();
|
||||
setup_DB();
|
||||
|
||||
if (PHPUNIT_TEST and !PHPUNIT_UTIL) {
|
||||
// make sure tests do not run in parallel
|
||||
test_lock::acquire('phpunit');
|
||||
// Make sure tests do not run in parallel.
|
||||
$suffix = '';
|
||||
if (phpunit_util::is_in_isolated_process()) {
|
||||
$suffix = '.isolated';
|
||||
}
|
||||
test_lock::acquire('phpunit', $suffix);
|
||||
$dbhash = null;
|
||||
try {
|
||||
if ($dbhash = $DB->get_field('config', 'value', array('name'=>'phpunittest'))) {
|
||||
|
@ -47,13 +47,15 @@ class test_lock {
|
||||
*
|
||||
* @internal
|
||||
* @static
|
||||
* @param string $framework Test framework
|
||||
* @return void
|
||||
* @param string $framework phpunit|behat
|
||||
* @param string $lockfilesuffix A sub-type used by the framework
|
||||
* @return void
|
||||
*/
|
||||
public static function acquire($framework) {
|
||||
public static function acquire(string $framework, string $lockfilesuffix = '') {
|
||||
global $CFG;
|
||||
|
||||
$datarootpath = $CFG->{$framework . '_dataroot'} . '/' . $framework;
|
||||
$lockfile = $datarootpath . '/lock';
|
||||
$lockfile = "{$datarootpath}/lock{$lockfilesuffix}";
|
||||
if (!file_exists($datarootpath)) {
|
||||
// Dataroot not initialised yet.
|
||||
return;
|
||||
@ -62,36 +64,58 @@ class test_lock {
|
||||
file_put_contents($lockfile, 'This file prevents concurrent execution of Moodle ' . $framework . ' tests');
|
||||
testing_fix_file_permissions($lockfile);
|
||||
}
|
||||
if (self::$lockhandles[$framework] = fopen($lockfile, 'r')) {
|
||||
|
||||
$lockhandlename = self::get_lock_handle_name($framework, $lockfilesuffix);
|
||||
if (self::$lockhandles[$lockhandlename] = fopen($lockfile, 'r')) {
|
||||
$wouldblock = null;
|
||||
$locked = flock(self::$lockhandles[$framework], (LOCK_EX | LOCK_NB), $wouldblock);
|
||||
$locked = flock(self::$lockhandles[$lockhandlename], (LOCK_EX | LOCK_NB), $wouldblock);
|
||||
if (!$locked) {
|
||||
if ($wouldblock) {
|
||||
echo "Waiting for other test execution to complete...\n";
|
||||
}
|
||||
$locked = flock(self::$lockhandles[$framework], LOCK_EX);
|
||||
$locked = flock(self::$lockhandles[$lockhandlename], LOCK_EX);
|
||||
}
|
||||
if (!$locked) {
|
||||
fclose(self::$lockhandles[$framework]);
|
||||
self::$lockhandles[$framework] = null;
|
||||
fclose(self::$lockhandles[$lockhandlename]);
|
||||
self::$lockhandles[$lockhandlename] = null;
|
||||
}
|
||||
}
|
||||
register_shutdown_function(array('test_lock', 'release'), $framework);
|
||||
register_shutdown_function(['test_lock', 'release'], $framework, $lockfilesuffix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: do not call manually!
|
||||
* @internal
|
||||
* @static
|
||||
* @param string $framework phpunit|behat
|
||||
* @return void
|
||||
* @param string $framework phpunit|behat
|
||||
* @param string $lockfilesuffix A sub-type used by the framework
|
||||
* @return void
|
||||
*/
|
||||
public static function release($framework) {
|
||||
if (self::$lockhandles[$framework]) {
|
||||
flock(self::$lockhandles[$framework], LOCK_UN);
|
||||
fclose(self::$lockhandles[$framework]);
|
||||
self::$lockhandles[$framework] = null;
|
||||
public static function release(string $framework, string $lockfilesuffix = '') {
|
||||
$lockhandlename = self::get_lock_handle_name($framework, $lockfilesuffix);
|
||||
|
||||
if (self::$lockhandles[$lockhandlename]) {
|
||||
flock(self::$lockhandles[$lockhandlename], LOCK_UN);
|
||||
fclose(self::$lockhandles[$lockhandlename]);
|
||||
self::$lockhandles[$lockhandlename] = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the lock handle stored in the class.
|
||||
*
|
||||
* @param string $framework
|
||||
* @param string $lockfilesuffix
|
||||
* @return string
|
||||
*/
|
||||
protected static function get_lock_handle_name(string $framework, string $lockfilesuffix): string {
|
||||
$lockhandlepieces = [$framework];
|
||||
|
||||
if (!empty($lockfilesuffix)) {
|
||||
$lockhandlepieces[] = $lockfilesuffix;
|
||||
}
|
||||
|
||||
return implode('%', $lockhandlepieces);
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user