Skip to content

Commit

Permalink
MDL-60978 testing: Support ability to run phpunit in isolated process
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewnicols committed Jun 21, 2019
1 parent 3cb2c56 commit af1a436
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 35 deletions.
2 changes: 0 additions & 2 deletions lib/phpunit/bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,6 @@
}
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');
Expand Down
15 changes: 1 addition & 14 deletions lib/phpunit/classes/advanced_testcase.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ final public function __construct($name = null, array $data = array(), $dataName

$this->setBackupGlobals(false);
$this->setBackupStaticAttributes(false);
$this->setRunTestInSeparateProcess(false);
$this->setPreserveGlobalState(false);
}

/**
Expand Down Expand Up @@ -490,19 +490,6 @@ public function redirectEvents() {
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.
*
Expand Down
12 changes: 12 additions & 0 deletions lib/phpunit/classes/util.php
Original file line number Diff line number Diff line change
Expand Up @@ -881,4 +881,16 @@ public static function call_internal_method($object, $methodname, array $params
$method->setAccessible(true);
return $method->invokeArgs($object, $params);
}

/**
* 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');
}
}
4 changes: 4 additions & 0 deletions lib/phpunit/tests/advanced_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,10 @@ public function test_message_redirection() {
* @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();

Expand Down
8 changes: 6 additions & 2 deletions lib/setup.php
Original file line number Diff line number Diff line change
Expand Up @@ -620,8 +620,12 @@
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'))) {
Expand Down
58 changes: 41 additions & 17 deletions lib/testing/classes/test_lock.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -62,36 +64,58 @@ public static function acquire($framework) {
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);
}

}

0 comments on commit af1a436

Please sign in to comment.