$baseurl = $CFG->wwwroot . '/admin/report/simpletest/index.php';
// Add unittest prefix to config.php if needed
-if ($addconfigprefix && !isset($CFG->unittest_prefix)) {
+if ($addconfigprefix && !isset($CFG->unittestprefix)) {
// Open config file, search for $CFG->prefix and append a new line under it
$handle = fopen($CFG->dirroot.'/config.php', 'r+');
$prefix_line = null;
if (preg_match('/CFG\-\>prefix/', $line, $matches)) {
- $prefix_line = "\$CFG->unittest_prefix = '$addconfigprefix';\n";
+ $prefix_line = "\$CFG->unittestprefix = '$addconfigprefix';\n";
}
$new_file .= $line;
$handle = fopen($CFG->dirroot.'/config.php', 'w');
fwrite($handle, $new_file);
fclose($handle);
- $CFG->unittest_prefix = $addconfigprefix;
+ $CFG->unittestprefix = $addconfigprefix;
}
-if (empty($CFG->unittest_prefix)) {
+if (empty($CFG->unittestprefix)) {
// TODO replace error with proper admin dialog
print_box_start('generalbox', 'notice');
echo '<p>'.get_string("prefixnotset", 'simpletest').'</p>';
$CFG->dbpass = $real_cfg->dbpass;
$CFG->dbname = $real_cfg->dbname;
$CFG->dbpersist = $real_cfg->dbpersist;
-$CFG->unittest_prefix = $real_cfg->unittest_prefix;
+$CFG->unittestprefix = $real_cfg->unittestprefix;
$CFG->wwwroot = $real_cfg->wwwroot;
$CFG->dirroot = $real_cfg->dirroot;
$CFG->libdir = $real_cfg->libdir;
$CFG->debug = $real_cfg->debug;
$DB = moodle_database::get_driver_instance($CFG->dbtype, $CFG->dblibrary);
-$DB->connect($CFG->dbhost, $CFG->dbuser, $CFG->dbpass, $CFG->dbname, $CFG->dbpersist, $CFG->unittest_prefix);
+$DB->connect($CFG->dbhost, $CFG->dbuser, $CFG->dbpass, $CFG->dbname, $CFG->dbpersist, $CFG->unittestprefix);
if ($config = $DB->get_records('config')) {
foreach ($config as $conf) {
class MoodleUnitTestCase extends UnitTestCase {
public $real_db;
public $tables = array();
+ public $pkfile;
+ public $cfg;
+ /**
+ * In the constructor, record the max(id) of each test table into a csv file.
+ * If this file already exists, it means that a previous run of unit tests
+ * did not complete, and has left data undeleted in the DB. This data is then
+ * deleted and the file is retained. Otherwise it is created.
+ * @throws moodle_exception if CSV file cannot be created
+ */
public function __construct($label = false) {
parent::UnitTestCase($label);
+ // MDL-16483 Get PKs and save data to text file
+ global $DB, $CFG;
+ $this->pkfile = $CFG->dataroot.'/testtablespks.csv';
+ $this->cfg = $CFG;
+
+ $tables = $DB->get_tables();
+
+ // The file exists, so use it to truncate tables (tests aborted before test data could be removed)
+ if (file_exists($this->pkfile)) {
+ $this->truncate_test_tables($this->get_table_data($this->pkfile));
+
+ } else { // Create the file
+ $tabledata = '';
+
+ foreach ($tables as $table) {
+ if ($table != 'sessions2') {
+ if (!$max_id = $DB->get_field_sql("SELECT MAX(id) FROM {$CFG->unittestprefix}{$table}")) {
+ $max_id = 0;
+ }
+ $tabledata .= "$table, $max_id\n";
+ }
+ }
+ if (!file_put_contents($this->pkfile, $tabledata)) {
+ throw new moodle_exception('testtablescsvfileunwritable', 'error');
+ }
+ }
+ }
+
+ /**
+ * Given an array of tables and their max id, truncates all test table records whose id is higher than the ones in the $tabledata array.
+ * @param array $tabledata
+ */
+ private function truncate_test_tables($tabledata) {
+ global $CFG, $DB;
+
+ $tables = $DB->get_tables();
+
+ foreach ($tables as $table) {
+ if ($table != 'sessions2' && isset($tabledata[$table])) {
+ $DB->delete_records_select($table, "id > ?", array($tabledata[$table]));
+ }
+ }
}
+ /**
+ * Given a filename, opens it and parses the csv contained therein. It expects two fields per line:
+ * 1. Table name
+ * 2. Max id
+ * @param string $filename
+ * @throws moodle_exception if file doesn't exist
+ */
+ public function get_table_data($filename) {
+ if (file_exists($this->pkfile)) {
+ $handle = fopen($this->pkfile, 'r');
+ $tabledata = array();
+
+ while (($data = fgetcsv($handle, 1000, ",")) !== false) {
+ $tabledata[$data[0]] = $data[1];
+ }
+ return $tabledata;
+ } else {
+ throw new moodle_exception('testtablescsvfilemissing', 'error');
+ return false;
+ }
+ }
+
+ /**
+ * Method called before each test method. Replaces the real $DB with the one configured for unit tests (different prefix, $CFG->unittestprefix).
+ * Also detects if this config setting is properly set, and if the user table exists.
+ * TODO Improve detection of incorrectly built DB test tables (e.g. detect version discrepancy and offer to upgrade/rebuild)
+ */
public function setUp() {
global $CFG, $DB;
parent::setUp();
$this->real_db = $DB;
- if (empty($CFG->unittest_prefix)) {
+ if (empty($CFG->unittestprefix)) {
print_error("prefixnotset", 'simpletest');
}
$DB = moodle_database::get_driver_instance($CFG->dbtype, $CFG->dblibrary);
- $DB->connect($CFG->dbhost, $CFG->dbuser, $CFG->dbpass, $CFG->dbname, $CFG->dbpersist, $CFG->unittest_prefix);
+ $DB->connect($CFG->dbhost, $CFG->dbuser, $CFG->dbpass, $CFG->dbname, $CFG->dbpersist, $CFG->unittestprefix);
$manager = $DB->get_manager();
- $tables = $DB->get_tables();
-
if (!$manager->table_exists('user')) {
print_error('tablesnotsetup', 'simpletest');
}
-
- $this->tables = $DB->get_tables();
-
- foreach ($this->tables as $key => $table) {
- if ($table == 'sessions2') {
- unset($this->tables[$key]);
- continue;
- }
-
- if ($max_id = $DB->get_field_sql("SELECT MAX(id) FROM {$CFG->unittest_prefix}{$table}")) {
- $this->tables[$table] = $max_id;
- } else {
- $this->tables[$table] = 0;
- }
- }
}
+ /**
+ * Method called after each test method. Doesn't do anything extraordinary except restore the global $DB to the real one.
+ */
public function tearDown() {
global $DB;
parent::tearDown();
- // Truncate all data created during unit tests
- foreach ($this->tables as $table => $max_pk) {
- $DB->delete_records_select($table, "id > $max_pk");
- }
-
$DB = $this->real_db;
}
/**
* This will execute once all the tests have been run. It should delete the text file holding info about database contents prior to the tests
+ * It should also detect if data is missing from the original tables.
*/
public function __destruct() {
-
+ global $CFG;
+ $CFG = $this->cfg;
+ $this->truncate_test_tables($this->get_table_data($this->pkfile));
+ fulldelete($this->pkfile);
}
}