weekly release 2.6dev
[moodle.git] / backup / util / dbops / tests / dbops_test.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * @package    core_backup
19  * @category   phpunit
20  * @copyright  2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
21  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
22  */
24 defined('MOODLE_INTERNAL') || die();
26 // Include all the needed stuff
27 global $CFG;
28 require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
29 require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
31 /**
32  * Restore dbops tests (all).
33  */
34 class restore_dbops_testcase extends advanced_testcase {
36     /**
37      * Verify the xxx_ids_cached (in-memory backup_ids cache) stuff works as expected.
38      *
39      * Note that those private implementations are tested here by using the public
40      * backup_ids API and later performing low-level tests.
41      */
42     public function test_backup_ids_cached() {
43         global $DB;
44         $dbman = $DB->get_manager(); // We are going to use database_manager services.
46         $this->resetAfterTest(true); // Playing with temp tables, better reset once finished.
48         // Some variables and objects for testing.
49         $restoreid = 'testrestoreid';
51         $mapping = new stdClass();
52         $mapping->itemname = 'user';
53         $mapping->itemid = 1;
54         $mapping->newitemid = 2;
55         $mapping->parentitemid = 3;
56         $mapping->info = 'info';
58         // Create the backup_ids temp tables used by restore.
59         restore_controller_dbops::create_restore_temp_tables($restoreid);
61         // Send one mapping using the public api with defaults.
62         restore_dbops::set_backup_ids_record($restoreid, $mapping->itemname, $mapping->itemid);
63         // Get that mapping and verify everything is returned as expected.
64         $result = restore_dbops::get_backup_ids_record($restoreid, $mapping->itemname, $mapping->itemid);
65         $this->assertSame($mapping->itemname, $result->itemname);
66         $this->assertSame($mapping->itemid, $result->itemid);
67         $this->assertSame(0, $result->newitemid);
68         $this->assertSame(null, $result->parentitemid);
69         $this->assertSame(null, $result->info);
71         // Drop the backup_xxx_temp temptables manually, so memory cache won't be invalidated.
72         $dbman->drop_table(new xmldb_table('backup_ids_temp'));
73         $dbman->drop_table(new xmldb_table('backup_files_temp'));
75         // Verify the mapping continues returning the same info,
76         // now from cache (the table does not exist).
77         $result = restore_dbops::get_backup_ids_record($restoreid, $mapping->itemname, $mapping->itemid);
78         $this->assertSame($mapping->itemname, $result->itemname);
79         $this->assertSame($mapping->itemid, $result->itemid);
80         $this->assertSame(0, $result->newitemid);
81         $this->assertSame(null, $result->parentitemid);
82         $this->assertSame(null, $result->info);
84         // Recreate the temp table, just to drop it using the restore API in
85         // order to check that, then, the cache becomes invalid for the same request.
86         restore_controller_dbops::create_restore_temp_tables($restoreid);
87         restore_controller_dbops::drop_restore_temp_tables($restoreid);
89         // No cached info anymore, so the mapping request will arrive to
90         // DB leading to error (temp table does not exist).
91         try {
92             $result = restore_dbops::get_backup_ids_record($restoreid, $mapping->itemname, $mapping->itemid);
93             $this->fail('Expecting an exception, none occurred');
94         } catch (Exception $e) {
95             $this->assertTrue($e instanceof dml_exception);
96             $this->assertSame('Table "backup_ids_temp" does not exist', $e->getMessage());
97         }
99         // Create the backup_ids temp tables once more.
100         restore_controller_dbops::create_restore_temp_tables($restoreid);
102         // Send one mapping using the public api with complete values.
103         restore_dbops::set_backup_ids_record($restoreid, $mapping->itemname, $mapping->itemid,
104                 $mapping->newitemid, $mapping->parentitemid, $mapping->info);
105         // Get that mapping and verify everything is returned as expected.
106         $result = restore_dbops::get_backup_ids_record($restoreid, $mapping->itemname, $mapping->itemid);
107         $this->assertSame($mapping->itemname, $result->itemname);
108         $this->assertSame($mapping->itemid, $result->itemid);
109         $this->assertSame($mapping->newitemid, $result->newitemid);
110         $this->assertSame($mapping->parentitemid, $result->parentitemid);
111         $this->assertSame($mapping->info, $result->info);
113         // Finally, drop the temp tables properly and get the DB error again (memory caches empty).
114         restore_controller_dbops::drop_restore_temp_tables($restoreid);
115         try {
116             $result = restore_dbops::get_backup_ids_record($restoreid, $mapping->itemname, $mapping->itemid);
117             $this->fail('Expecting an exception, none occurred');
118         } catch (Exception $e) {
119             $this->assertTrue($e instanceof dml_exception);
120             $this->assertSame('Table "backup_ids_temp" does not exist', $e->getMessage());
121         }
122     }
125 /**
126  * Backup dbops tests (all).
127  */
128 class backup_dbops_testcase extends advanced_testcase {
130     protected $moduleid;  // course_modules id used for testing
131     protected $sectionid; // course_sections id used for testing
132     protected $courseid;  // course id used for testing
133     protected $userid;      // user record used for testing
135     protected function setUp() {
136         global $DB, $CFG;
137         parent::setUp();
139         $this->resetAfterTest(true);
141         $course = $this->getDataGenerator()->create_course();
142         $page = $this->getDataGenerator()->create_module('page', array('course'=>$course->id), array('section'=>3));
143         $coursemodule = $DB->get_record('course_modules', array('id'=>$page->cmid));
145         $this->moduleid  = $coursemodule->id;
146         $this->sectionid = $DB->get_field("course_sections", 'id', array("section"=>$coursemodule->section, "course"=>$course->id));
147         $this->courseid  = $coursemodule->course;
148         $this->userid = 2; // admin
150         $CFG->backup_error_log_logger_level = backup::LOG_NONE;
151         $CFG->backup_output_indented_logger_level = backup::LOG_NONE;
152         $CFG->backup_file_logger_level = backup::LOG_NONE;
153         $CFG->backup_database_logger_level = backup::LOG_NONE;
154         unset($CFG->backup_file_logger_extra);
155         $CFG->backup_file_logger_level_extra = backup::LOG_NONE;
156     }
158     /*
159      * test backup_ops class
160      */
161     function test_backup_dbops() {
162         // Nothing to do here, abstract class + exception, will be tested by the rest
163     }
165     /*
166      * test backup_controller_dbops class
167      */
168     function test_backup_controller_dbops() {
169         global $DB;
171         $dbman = $DB->get_manager(); // Going to use some database_manager services for testing
173         // Instantiate non interactive backup_controller
174         $bc = new mock_backup_controller4dbops(backup::TYPE_1ACTIVITY, $this->moduleid, backup::FORMAT_MOODLE,
175             backup::INTERACTIVE_NO, backup::MODE_GENERAL, $this->userid);
176         $this->assertTrue($bc instanceof backup_controller);
177         // Calculate checksum
178         $checksum = $bc->calculate_checksum();
179         $this->assertEquals(strlen($checksum), 32); // is one md5
181         // save controller
182         $recid = backup_controller_dbops::save_controller($bc, $checksum);
183         $this->assertNotEmpty($recid);
184         // save it again (should cause update to happen)
185         $recid2 = backup_controller_dbops::save_controller($bc, $checksum);
186         $this->assertNotEmpty($recid2);
187         $this->assertEquals($recid, $recid2); // Same record in both save operations
189         // Try incorrect checksum
190         $bc = new mock_backup_controller4dbops(backup::TYPE_1ACTIVITY, $this->moduleid, backup::FORMAT_MOODLE,
191             backup::INTERACTIVE_NO, backup::MODE_GENERAL, $this->userid);
192         $checksum = $bc->calculate_checksum();
193         try {
194             $recid = backup_controller_dbops::save_controller($bc, 'lalala');
195             $this->assertTrue(false, 'backup_dbops_exception expected');
196         } catch (exception $e) {
197             $this->assertTrue($e instanceof backup_dbops_exception);
198             $this->assertEquals($e->errorcode, 'backup_controller_dbops_saving_checksum_mismatch');
199         }
201         // Try to save non backup_controller object
202         $bc = new stdclass();
203         try {
204             $recid = backup_controller_dbops::save_controller($bc, 'lalala');
205             $this->assertTrue(false, 'backup_controller_exception expected');
206         } catch (exception $e) {
207             $this->assertTrue($e instanceof backup_controller_exception);
208             $this->assertEquals($e->errorcode, 'backup_controller_expected');
209         }
211         // save and load controller (by backupid). Then compare
212         $bc = new mock_backup_controller4dbops(backup::TYPE_1ACTIVITY, $this->moduleid, backup::FORMAT_MOODLE,
213             backup::INTERACTIVE_NO, backup::MODE_GENERAL, $this->userid);
214         $checksum = $bc->calculate_checksum(); // Calculate checksum
215         $backupid = $bc->get_backupid();
216         $this->assertEquals(strlen($backupid), 32); // is one md5
217         $recid = backup_controller_dbops::save_controller($bc, $checksum); // save controller
218         $newbc = backup_controller_dbops::load_controller($backupid); // load controller
219         $this->assertTrue($newbc instanceof backup_controller);
220         $newchecksum = $newbc->calculate_checksum();
221         $this->assertEquals($newchecksum, $checksum);
223         // try to load non-existing controller
224         try {
225             $bc = backup_controller_dbops::load_controller('1234567890');
226             $this->assertTrue(false, 'backup_dbops_exception expected');
227         } catch (exception $e) {
228             $this->assertTrue($e instanceof backup_dbops_exception);
229             $this->assertEquals($e->errorcode, 'backup_controller_dbops_nonexisting');
230         }
232         // backup_ids_temp table tests
233         // If, for any reason table exists, drop it
234         if ($dbman->table_exists('backup_ids_temp')) {
235             $dbman->drop_table(new xmldb_table('backup_ids_temp'));
236         }
237         // Check backup_ids_temp table doesn't exist
238         $this->assertFalse($dbman->table_exists('backup_ids_temp'));
239         // Create and check it exists
240         backup_controller_dbops::create_backup_ids_temp_table('testingid');
241         $this->assertTrue($dbman->table_exists('backup_ids_temp'));
242         // Drop and check it doesn't exists anymore
243         backup_controller_dbops::drop_backup_ids_temp_table('testingid');
244         $this->assertFalse($dbman->table_exists('backup_ids_temp'));
245     }
248 class mock_backup_controller4dbops extends backup_controller {
250     /**
251      * Change standard behavior so the checksum is also stored and not onlt calculated
252      */
253     public function calculate_checksum() {
254         $this->checksum = parent::calculate_checksum();
255         return $this->checksum;
256     }