diff --git a/lib/behat/classes/util.php b/lib/behat/classes/util.php index c8504fe3b9f..57e56b0f927 100644 --- a/lib/behat/classes/util.php +++ b/lib/behat/classes/util.php @@ -85,6 +85,10 @@ class behat_util extends testing_util { install_cli_database($options, false); + // We need to keep the installed dataroot filedir files. + // So each time we reset the dataroot before running a test, the default files are still installed. + self::save_original_data_files(); + $frontpagesummary = new admin_setting_special_frontpagedesc(); $frontpagesummary->write_setting(self::BEHATSITENAME); diff --git a/lib/phpunit/classes/util.php b/lib/phpunit/classes/util.php old mode 100644 new mode 100755 index 28d7ea5dffa..ed8d632f433 --- a/lib/phpunit/classes/util.php +++ b/lib/phpunit/classes/util.php @@ -384,6 +384,10 @@ class phpunit_util extends testing_util { install_cli_database($options, false); + // We need to keep the installed dataroot filedir files. + // So each time we reset the dataroot before running a test, the default files are still installed. + self::save_original_data_files(); + // install timezone info $timezones = get_records_csv($CFG->libdir.'/timezone.txt', 'timezone'); update_timezone_records($timezones); diff --git a/lib/testing/classes/util.php b/lib/testing/classes/util.php old mode 100644 new mode 100755 index 41a4243318a..deec3100cd4 --- a/lib/testing/classes/util.php +++ b/lib/testing/classes/util.php @@ -34,6 +34,11 @@ */ abstract class testing_util { + /** + * @var string dataroot (likely to be $CFG->dataroot). + */ + private static $dataroot = null; + /** * @var int last value of db writes counter, used for db resetting */ @@ -64,6 +69,53 @@ abstract class testing_util { */ protected static $sequencenames = null; + /** + * @var string name of the json file where we store the list of dataroot files to not reset during reset_dataroot. + */ + private static $originaldatafilesjson = 'originaldatafiles.json'; + + /** + * @var boolean set to true once $originaldatafilesjson file is created. + */ + private static $originaldatafilesjsonadded = false; + + /** + * Return the name of the JSON file containing the init filenames. + * + * @static + * @return string + */ + public static function get_originaldatafilesjson() { + return self::$originaldatafilesjson; + } + + /** + * Return the dataroot. It's useful when mocking the dataroot when unit testing this class itself. + * + * @static + * @return string the dataroot. + */ + public static function get_dataroot() { + global $CFG; + + // By default it's the test framework dataroot. + if (empty(self::$dataroot)) { + self::$dataroot = $CFG->dataroot; + } + + return self::$dataroot; + } + + /** + * Set the dataroot. It's useful when mocking the dataroot when unit testing this class itself. + * + * @param string $dataroot the dataroot of the test framework. + * @static + */ + public static function set_dataroot($dataroot) { + self::$dataroot = $dataroot; + } + /** * Returns the testing framework name * @static @@ -99,7 +151,7 @@ abstract class testing_util { $framework = self::get_framework(); - if (!file_exists($CFG->dataroot . '/' . $framework . 'testdir.txt')) { + if (!file_exists(self::get_dataroot() . '/' . $framework . 'testdir.txt')) { // this is already tested in bootstrap script, // but anyway presence of this file means the dataroot is for testing return false; @@ -128,7 +180,7 @@ abstract class testing_util { $framework = self::get_framework(); - $datarootpath = $CFG->dataroot . '/' . $framework; + $datarootpath = self::get_dataroot() . '/' . $framework; if (!file_exists($datarootpath . '/tabledata.ser') or !file_exists($datarootpath . '/tablestructure.ser')) { return false; } @@ -178,12 +230,12 @@ abstract class testing_util { } } $data = serialize($data); - $datafile = $CFG->dataroot . '/' . $framework . '/tabledata.ser'; + $datafile = self::get_dataroot() . '/' . $framework . '/tabledata.ser'; file_put_contents($datafile, $data); testing_fix_file_permissions($datafile); $structure = serialize($structure); - $structurefile = $CFG->dataroot . '/' . $framework . '/tablestructure.ser'; + $structurefile = self::get_dataroot() . '/' . $framework . '/tablestructure.ser'; file_put_contents($structurefile, $structure); testing_fix_file_permissions($structurefile); } @@ -201,7 +253,7 @@ abstract class testing_util { set_config($framework . 'test', $hash); // hash all plugin versions - helps with very fast detection of db structure changes - $hashfile = $CFG->dataroot . '/' . $framework . '/versionshash.txt'; + $hashfile = self::get_dataroot() . '/' . $framework . '/versionshash.txt'; file_put_contents($hashfile, $hash); testing_fix_file_permissions($hashfile); } @@ -216,7 +268,7 @@ abstract class testing_util { $framework = self::get_framework(); - $datafile = $CFG->dataroot . '/' . $framework . '/tabledata.ser'; + $datafile = self::get_dataroot() . '/' . $framework . '/tabledata.ser'; if (!file_exists($datafile)) { // Not initialised yet. return array(); @@ -244,7 +296,7 @@ abstract class testing_util { $framework = self::get_framework(); - $structurefile = $CFG->dataroot . '/' . $framework . '/tablestructure.ser'; + $structurefile = self::get_dataroot() . '/' . $framework . '/tablestructure.ser'; if (!file_exists($structurefile)) { // Not initialised yet. return array(); @@ -584,18 +636,39 @@ abstract class testing_util { $childclassname = self::get_framework() . '_util'; - $handle = opendir($CFG->dataroot); + // Do not delete automatically installed files. + self::skip_original_data_files($childclassname); + + // Clean up the dataroot folder. + $handle = opendir(self::get_dataroot()); while (false !== ($item = readdir($handle))) { if (in_array($item, $childclassname::$datarootskiponreset)) { continue; } - if (is_dir("$CFG->dataroot/$item")) { - remove_dir("$CFG->dataroot/$item", false); + if (is_dir(self::get_dataroot()."/$item")) { + remove_dir(self::get_dataroot()."/$item", false); } else { - unlink("$CFG->dataroot/$item"); + unlink(self::get_dataroot()."/$item"); } } closedir($handle); + + // Clean up the dataroot/filedir folder. + if (file_exists(self::get_dataroot() . '/filedir')) { + $handle = opendir(self::get_dataroot() . '/filedir'); + while (false !== ($item = readdir($handle))) { + if (in_array('filedir/' . $item, $childclassname::$datarootskiponreset)) { + continue; + } + if (is_dir(self::get_dataroot()."/filedir/$item")) { + remove_dir(self::get_dataroot()."/filedir/$item", false); + } else { + unlink(self::get_dataroot()."/filedir/$item"); + } + } + closedir($handle); + } + make_temp_directory(''); make_cache_directory(''); make_localcache_directory(''); @@ -725,17 +798,83 @@ abstract class testing_util { $framework = self::get_framework(); $childclassname = $framework . '_util'; - $files = scandir($CFG->dataroot . '/' . $framework); + $files = scandir(self::get_dataroot() . '/' . $framework); foreach ($files as $file) { if (in_array($file, $childclassname::$datarootskipondrop)) { continue; } - $path = $CFG->dataroot . '/' . $framework . '/' . $file; + $path = self::get_dataroot() . '/' . $framework . '/' . $file; if (is_dir($path)) { remove_dir($path, false); } else { unlink($path); } } + + $jsonfilepath = self::get_dataroot() . '/' . self::$originaldatafilesjson; + if (file_exists($jsonfilepath)) { + // Delete the json file. + unlink($jsonfilepath); + // Delete the dataroot filedir. + remove_dir(self::get_dataroot() . '/filedir', false); + } + } + + /** + * Skip the original dataroot files to not been reset. + * + * @static + * @param string $utilclassname the util class name.. + */ + protected static function skip_original_data_files($utilclassname) { + $jsonfilepath = self::get_dataroot() . '/' . self::$originaldatafilesjson; + if (file_exists($jsonfilepath)) { + + $listfiles = file_get_contents($jsonfilepath); + + // Mark each files as to not be reset. + if (!empty($listfiles) && !self::$originaldatafilesjsonadded) { + $originaldatarootfiles = json_decode($listfiles); + // Keep the json file. Only drop_dataroot() should delete it. + $originaldatarootfiles[] = self::$originaldatafilesjson; + $utilclassname::$datarootskiponreset = array_merge($utilclassname::$datarootskiponreset, + $originaldatarootfiles); + self::$originaldatafilesjsonadded = true; + } + } + } + + /** + * Save the list of the original dataroot files into a json file. + */ + protected static function save_original_data_files() { + global $CFG; + + $jsonfilepath = self::get_dataroot() . '/' . self::$originaldatafilesjson; + + // Save the original dataroot files if not done (only executed the first time). + if (!file_exists($jsonfilepath)) { + + $listfiles = array(); + $listfiles[] = 'filedir/.'; + $listfiles[] = 'filedir/..'; + + $filedir = self::get_dataroot() . '/filedir'; + if (file_exists($filedir)) { + $directory = new RecursiveDirectoryIterator($filedir); + foreach (new RecursiveIteratorIterator($directory) as $file) { + if ($file->isDir()) { + $listfiles[] = substr($file->getPath(), strlen(self::get_dataroot() . '/')); + } else { + $listfiles[] = substr($file->getPathName(), strlen(self::get_dataroot() . '/')); + } + } + } + + // Save the file list in a JSON file. + $fp = fopen($jsonfilepath, 'w'); + fwrite($fp, json_encode($listfiles)); + fclose($fp); + } } }