Merge branch 'MDL-66550-master' of git://github.com/andrewnicols/moodle
[moodle.git] / course / tests / restore_test.php
blob4f659902ffb505a44b1ef5c2276e26712f891acf
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.
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 * Course restore tests.
20 * @package core_course
21 * @copyright 2016 Frédéric Massart - FMCorz.net
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 defined('MOODLE_INTERNAL') || die();
26 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 * Course restore testcase.
34 * @package core_course
35 * @copyright 2016 Frédéric Massart - FMCorz.net
36 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
38 class core_course_restore_testcase extends advanced_testcase {
40 /**
41 * Backup a course and return its backup ID.
43 * @param int $courseid The course ID.
44 * @param int $userid The user doing the backup.
45 * @return string
47 protected function backup_course($courseid, $userid = 2) {
48 $backuptempdir = make_backup_temp_directory('');
49 $packer = get_file_packer('application/vnd.moodle.backup');
51 $bc = new backup_controller(backup::TYPE_1COURSE, $courseid, backup::FORMAT_MOODLE, backup::INTERACTIVE_NO,
52 backup::MODE_GENERAL, $userid);
53 $bc->execute_plan();
55 $results = $bc->get_results();
56 $results['backup_destination']->extract_to_pathname($packer, "$backuptempdir/core_course_testcase");
58 $bc->destroy();
59 unset($bc);
60 return 'core_course_testcase';
63 /**
64 * Create a role with capabilities and permissions.
66 * @param string|array $caps Capability names.
67 * @param int $perm Constant CAP_* to apply to the capabilities.
68 * @return int The new role ID.
70 protected function create_role_with_caps($caps, $perm) {
71 $caps = (array) $caps;
72 $dg = $this->getDataGenerator();
73 $roleid = $dg->create_role();
74 foreach ($caps as $cap) {
75 assign_capability($cap, $perm, $roleid, context_system::instance()->id, true);
77 accesslib_clear_all_caches_for_unit_testing();
78 return $roleid;
81 /**
82 * Restore a course.
84 * @param int $backupid The backup ID.
85 * @param int $courseid The course ID to restore in, or 0.
86 * @param int $userid The ID of the user performing the restore.
87 * @return stdClass The updated course object.
89 protected function restore_course($backupid, $courseid, $userid) {
90 global $DB;
92 $target = backup::TARGET_CURRENT_ADDING;
93 if (!$courseid) {
94 $target = backup::TARGET_NEW_COURSE;
95 $categoryid = $DB->get_field_sql("SELECT MIN(id) FROM {course_categories}");
96 $courseid = restore_dbops::create_new_course('Tmp', 'tmp', $categoryid);
99 $rc = new restore_controller($backupid, $courseid, backup::INTERACTIVE_NO, backup::MODE_GENERAL, $userid, $target);
100 $target == backup::TARGET_NEW_COURSE ?: $rc->get_plan()->get_setting('overwrite_conf')->set_value(true);
101 $this->assertTrue($rc->execute_precheck());
102 $rc->execute_plan();
104 $course = $DB->get_record('course', array('id' => $rc->get_courseid()));
106 $rc->destroy();
107 unset($rc);
108 return $course;
112 * Restore a course to an existing course.
114 * @param int $backupid The backup ID.
115 * @param int $courseid The course ID to restore in.
116 * @param int $userid The ID of the user performing the restore.
117 * @return stdClass The updated course object.
119 protected function restore_to_existing_course($backupid, $courseid, $userid = 2) {
120 return $this->restore_course($backupid, $courseid, $userid);
124 * Restore a course to a new course.
126 * @param int $backupid The backup ID.
127 * @param int $userid The ID of the user performing the restore.
128 * @return stdClass The new course object.
130 protected function restore_to_new_course($backupid, $userid = 2) {
131 return $this->restore_course($backupid, 0, $userid);
135 * Restore a course.
137 * @param int $backupid The backup ID.
138 * @param int $courseid The course ID to restore in, or 0.
139 * @param int $userid The ID of the user performing the restore.
140 * @param int $target THe target of the restore.
142 * @return stdClass The updated course object.
144 protected function async_restore_course($backupid, $courseid, $userid, $target) {
145 global $DB;
147 if (!$courseid) {
148 $target = backup::TARGET_NEW_COURSE;
149 $categoryid = $DB->get_field_sql("SELECT MIN(id) FROM {course_categories}");
150 $courseid = restore_dbops::create_new_course('Tmp', 'tmp', $categoryid);
153 $rc = new restore_controller($backupid, $courseid, backup::INTERACTIVE_NO, backup::MODE_ASYNC, $userid, $target);
154 $target == backup::TARGET_NEW_COURSE ?: $rc->get_plan()->get_setting('overwrite_conf')->set_value(true);
155 $this->assertTrue($rc->execute_precheck());
157 $restoreid = $rc->get_restoreid();
158 $rc->destroy();
160 // Create the adhoc task.
161 $asynctask = new \core\task\asynchronous_restore_task();
162 $asynctask->set_blocking(false);
163 $asynctask->set_custom_data(array('backupid' => $restoreid));
164 \core\task\manager::queue_adhoc_task($asynctask);
166 // We are expecting trace output during this test.
167 $this->expectOutputRegex("/$restoreid/");
169 // Execute adhoc task.
170 $now = time();
171 $task = \core\task\manager::get_next_adhoc_task($now);
172 $this->assertInstanceOf('\\core\\task\\asynchronous_restore_task', $task);
173 $task->execute();
174 \core\task\manager::adhoc_task_complete($task);
176 $course = $DB->get_record('course', array('id' => $rc->get_courseid()));
178 return $course;
182 * Restore a course to an existing course.
184 * @param int $backupid The backup ID.
185 * @param int $courseid The course ID to restore in.
186 * @param int $userid The ID of the user performing the restore.
187 * @param int $target The type of restore we are performing.
188 * @return stdClass The updated course object.
190 protected function async_restore_to_existing_course($backupid, $courseid,
191 $userid = 2, $target = backup::TARGET_CURRENT_ADDING) {
192 return $this->async_restore_course($backupid, $courseid, $userid, $target);
196 * Restore a course to a new course.
198 * @param int $backupid The backup ID.
199 * @param int $userid The ID of the user performing the restore.
200 * @return stdClass The new course object.
202 protected function async_restore_to_new_course($backupid, $userid = 2) {
203 return $this->async_restore_course($backupid, 0, $userid, 0);
206 public function test_async_restore_existing_idnumber_in_new_course() {
207 $this->resetAfterTest();
209 $dg = $this->getDataGenerator();
210 $c1 = $dg->create_course(['idnumber' => 'ABC']);
211 $backupid = $this->backup_course($c1->id);
212 $c2 = $this->async_restore_to_new_course($backupid);
214 // The ID number is set empty.
215 $this->assertEquals('', $c2->idnumber);
218 public function test_async_restore_course_info_in_existing_course() {
219 global $DB;
220 $this->resetAfterTest();
221 $dg = $this->getDataGenerator();
223 $this->assertEquals(1, get_config('restore', 'restore_merge_course_shortname'));
224 $this->assertEquals(1, get_config('restore', 'restore_merge_course_fullname'));
225 $this->assertEquals(1, get_config('restore', 'restore_merge_course_startdate'));
227 $startdate = mktime(12, 0, 0, 7, 1, 2016); // 01-Jul-2016.
229 // Create two courses with different start dates,in each course create a chat that opens 1 week after the course start date.
230 $c1 = $dg->create_course(['shortname' => 'SN', 'fullname' => 'FN', 'summary' => 'DESC', 'summaryformat' => FORMAT_MOODLE,
231 'startdate' => $startdate]);
232 $chat1 = $dg->create_module('chat', ['name' => 'First', 'course' => $c1->id, 'chattime' => $c1->startdate + 1 * WEEKSECS]);
233 $c2 = $dg->create_course(['shortname' => 'A', 'fullname' => 'B', 'summary' => 'C', 'summaryformat' => FORMAT_PLAIN,
234 'startdate' => $startdate + 2 * WEEKSECS]);
235 $chat2 = $dg->create_module('chat', ['name' => 'Second', 'course' => $c2->id, 'chattime' => $c2->startdate + 1 * WEEKSECS]);
236 $backupid = $this->backup_course($c1->id);
238 // The information is restored but adapted because names are already taken.
239 $c2 = $this->async_restore_to_existing_course($backupid, $c2->id);
240 $this->assertEquals('SN_1', $c2->shortname);
241 $this->assertEquals('FN copy 1', $c2->fullname);
242 $this->assertEquals('DESC', $c2->summary);
243 $this->assertEquals(FORMAT_MOODLE, $c2->summaryformat);
244 $this->assertEquals($startdate, $c2->startdate);
246 // Now course c2 has two chats - one ('Second') was already there and one ('First') was restored from the backup.
247 // Their dates are exactly the same as they were in the original modules.
248 $restoredchat1 = $DB->get_record('chat', ['name' => 'First', 'course' => $c2->id]);
249 $restoredchat2 = $DB->get_record('chat', ['name' => 'Second', 'course' => $c2->id]);
250 $this->assertEquals($chat1->chattime, $restoredchat1->chattime);
251 $this->assertEquals($chat2->chattime, $restoredchat2->chattime);
254 public function test_async_restore_course_info_in_existing_course_delete_first() {
255 global $DB;
256 $this->resetAfterTest();
257 $dg = $this->getDataGenerator();
259 $this->assertEquals(1, get_config('restore', 'restore_merge_course_shortname'));
260 $this->assertEquals(1, get_config('restore', 'restore_merge_course_fullname'));
261 $this->assertEquals(1, get_config('restore', 'restore_merge_course_startdate'));
263 $startdate = mktime(12, 0, 0, 7, 1, 2016); // 01-Jul-2016.
265 // Create two courses with different start dates,in each course create a chat that opens 1 week after the course start date.
266 $c1 = $dg->create_course(['shortname' => 'SN', 'fullname' => 'FN', 'summary' => 'DESC', 'summaryformat' => FORMAT_MOODLE,
267 'startdate' => $startdate]);
268 $chat1 = $dg->create_module('chat', ['name' => 'First', 'course' => $c1->id, 'chattime' => $c1->startdate + 1 * WEEKSECS]);
269 $c2 = $dg->create_course(['shortname' => 'A', 'fullname' => 'B', 'summary' => 'C', 'summaryformat' => FORMAT_PLAIN,
270 'startdate' => $startdate + 2 * WEEKSECS]);
271 $chat2 = $dg->create_module('chat', ['name' => 'Second', 'course' => $c2->id, 'chattime' => $c2->startdate + 1 * WEEKSECS]);
272 $backupid = $this->backup_course($c1->id);
274 // The information is restored and the existing course settings is modified.
275 $c2 = $this->async_restore_to_existing_course($backupid, $c2->id, 2, backup::TARGET_CURRENT_DELETING);
276 $this->assertEquals(FORMAT_MOODLE, $c2->summaryformat);
278 // Now course2 should have a new forum with the original forum deleted.
279 $restoredchat1 = $DB->get_record('chat', ['name' => 'First', 'course' => $c2->id]);
280 $restoredchat2 = $DB->get_record('chat', ['name' => 'Second', 'course' => $c2->id]);
281 $this->assertEquals($chat1->chattime, $restoredchat1->chattime);
282 $this->assertEmpty($restoredchat2);
285 public function test_restore_existing_idnumber_in_new_course() {
286 $this->resetAfterTest();
288 $dg = $this->getDataGenerator();
289 $c1 = $dg->create_course(['idnumber' => 'ABC']);
290 $backupid = $this->backup_course($c1->id);
291 $c2 = $this->restore_to_new_course($backupid);
293 // The ID number is set empty.
294 $this->assertEquals('', $c2->idnumber);
297 public function test_restore_non_existing_idnumber_in_new_course() {
298 global $DB;
299 $this->resetAfterTest();
301 $dg = $this->getDataGenerator();
302 $c1 = $dg->create_course(['idnumber' => 'ABC']);
303 $backupid = $this->backup_course($c1->id);
305 $c1->idnumber = 'BCD';
306 $DB->update_record('course', $c1);
308 // The ID number changed.
309 $c2 = $this->restore_to_new_course($backupid);
310 $this->assertEquals('ABC', $c2->idnumber);
313 public function test_restore_existing_idnumber_in_existing_course() {
314 global $DB;
315 $this->resetAfterTest();
317 $dg = $this->getDataGenerator();
318 $c1 = $dg->create_course(['idnumber' => 'ABC']);
319 $c2 = $dg->create_course(['idnumber' => 'DEF']);
320 $backupid = $this->backup_course($c1->id);
322 // The ID number does not change.
323 $c2 = $this->restore_to_existing_course($backupid, $c2->id);
324 $this->assertEquals('DEF', $c2->idnumber);
326 $c1 = $DB->get_record('course', array('id' => $c1->id));
327 $this->assertEquals('ABC', $c1->idnumber);
330 public function test_restore_non_existing_idnumber_in_existing_course() {
331 global $DB;
332 $this->resetAfterTest();
334 $dg = $this->getDataGenerator();
335 $c1 = $dg->create_course(['idnumber' => 'ABC']);
336 $c2 = $dg->create_course(['idnumber' => 'DEF']);
337 $backupid = $this->backup_course($c1->id);
339 $c1->idnumber = 'XXX';
340 $DB->update_record('course', $c1);
342 // The ID number has changed.
343 $c2 = $this->restore_to_existing_course($backupid, $c2->id);
344 $this->assertEquals('ABC', $c2->idnumber);
347 public function test_restore_idnumber_in_existing_course_without_permissions() {
348 global $DB;
349 $this->resetAfterTest();
350 $dg = $this->getDataGenerator();
351 $u1 = $dg->create_user();
353 $managers = get_archetype_roles('manager');
354 $manager = array_shift($managers);
355 $roleid = $this->create_role_with_caps('moodle/course:changeidnumber', CAP_PROHIBIT);
356 $dg->role_assign($manager->id, $u1->id);
357 $dg->role_assign($roleid, $u1->id);
359 $c1 = $dg->create_course(['idnumber' => 'ABC']);
360 $c2 = $dg->create_course(['idnumber' => 'DEF']);
361 $backupid = $this->backup_course($c1->id);
363 $c1->idnumber = 'XXX';
364 $DB->update_record('course', $c1);
366 // The ID number does not change.
367 $c2 = $this->restore_to_existing_course($backupid, $c2->id, $u1->id);
368 $this->assertEquals('DEF', $c2->idnumber);
371 public function test_restore_course_info_in_new_course() {
372 global $DB;
373 $this->resetAfterTest();
374 $dg = $this->getDataGenerator();
376 $startdate = mktime(12, 0, 0, 7, 1, 2016); // 01-Jul-2016.
378 $c1 = $dg->create_course(['shortname' => 'SN', 'fullname' => 'FN', 'startdate' => $startdate,
379 'summary' => 'DESC', 'summaryformat' => FORMAT_MOODLE]);
380 $backupid = $this->backup_course($c1->id);
382 // The information is restored but adapted because names are already taken.
383 $c2 = $this->restore_to_new_course($backupid);
384 $this->assertEquals('SN_1', $c2->shortname);
385 $this->assertEquals('FN copy 1', $c2->fullname);
386 $this->assertEquals('DESC', $c2->summary);
387 $this->assertEquals(FORMAT_MOODLE, $c2->summaryformat);
388 $this->assertEquals($startdate, $c2->startdate);
391 public function test_restore_course_info_in_existing_course() {
392 global $DB;
393 $this->resetAfterTest();
394 $dg = $this->getDataGenerator();
396 $this->assertEquals(1, get_config('restore', 'restore_merge_course_shortname'));
397 $this->assertEquals(1, get_config('restore', 'restore_merge_course_fullname'));
398 $this->assertEquals(1, get_config('restore', 'restore_merge_course_startdate'));
400 $startdate = mktime(12, 0, 0, 7, 1, 2016); // 01-Jul-2016.
402 // Create two courses with different start dates,in each course create a chat that opens 1 week after the course start date.
403 $c1 = $dg->create_course(['shortname' => 'SN', 'fullname' => 'FN', 'summary' => 'DESC', 'summaryformat' => FORMAT_MOODLE,
404 'startdate' => $startdate]);
405 $chat1 = $dg->create_module('chat', ['name' => 'First', 'course' => $c1->id, 'chattime' => $c1->startdate + 1 * WEEKSECS]);
406 $c2 = $dg->create_course(['shortname' => 'A', 'fullname' => 'B', 'summary' => 'C', 'summaryformat' => FORMAT_PLAIN,
407 'startdate' => $startdate + 2 * WEEKSECS]);
408 $chat2 = $dg->create_module('chat', ['name' => 'Second', 'course' => $c2->id, 'chattime' => $c2->startdate + 1 * WEEKSECS]);
409 $backupid = $this->backup_course($c1->id);
411 // The information is restored but adapted because names are already taken.
412 $c2 = $this->restore_to_existing_course($backupid, $c2->id);
413 $this->assertEquals('SN_1', $c2->shortname);
414 $this->assertEquals('FN copy 1', $c2->fullname);
415 $this->assertEquals('DESC', $c2->summary);
416 $this->assertEquals(FORMAT_MOODLE, $c2->summaryformat);
417 $this->assertEquals($startdate, $c2->startdate);
419 // Now course c2 has two chats - one ('Second') was already there and one ('First') was restored from the backup.
420 // Their dates are exactly the same as they were in the original modules.
421 $restoredchat1 = $DB->get_record('chat', ['name' => 'First', 'course' => $c2->id]);
422 $restoredchat2 = $DB->get_record('chat', ['name' => 'Second', 'course' => $c2->id]);
423 $this->assertEquals($chat1->chattime, $restoredchat1->chattime);
424 $this->assertEquals($chat2->chattime, $restoredchat2->chattime);
427 public function test_restore_course_shortname_in_existing_course_without_permissions() {
428 global $DB;
429 $this->resetAfterTest();
430 $dg = $this->getDataGenerator();
431 $u1 = $dg->create_user();
433 $managers = get_archetype_roles('manager');
434 $manager = array_shift($managers);
435 $roleid = $this->create_role_with_caps('moodle/course:changeshortname', CAP_PROHIBIT);
436 $dg->role_assign($manager->id, $u1->id);
437 $dg->role_assign($roleid, $u1->id);
439 $c1 = $dg->create_course(['shortname' => 'SN', 'fullname' => 'FN', 'summary' => 'DESC', 'summaryformat' => FORMAT_MOODLE]);
440 $c2 = $dg->create_course(['shortname' => 'A1', 'fullname' => 'B1', 'summary' => 'C1', 'summaryformat' => FORMAT_PLAIN]);
442 // The shortname does not change.
443 $backupid = $this->backup_course($c1->id);
444 $restored = $this->restore_to_existing_course($backupid, $c2->id, $u1->id);
445 $this->assertEquals($c2->shortname, $restored->shortname);
446 $this->assertEquals('FN copy 1', $restored->fullname);
447 $this->assertEquals('DESC', $restored->summary);
448 $this->assertEquals(FORMAT_MOODLE, $restored->summaryformat);
451 public function test_restore_course_fullname_in_existing_course_without_permissions() {
452 global $DB;
453 $this->resetAfterTest();
454 $dg = $this->getDataGenerator();
455 $u1 = $dg->create_user();
457 $managers = get_archetype_roles('manager');
458 $manager = array_shift($managers);
459 $roleid = $this->create_role_with_caps('moodle/course:changefullname', CAP_PROHIBIT);
460 $dg->role_assign($manager->id, $u1->id);
461 $dg->role_assign($roleid, $u1->id);
463 $c1 = $dg->create_course(['shortname' => 'SN', 'fullname' => 'FN', 'summary' => 'DESC', 'summaryformat' => FORMAT_MOODLE]);
464 $c2 = $dg->create_course(['shortname' => 'A1', 'fullname' => 'B1', 'summary' => 'C1', 'summaryformat' => FORMAT_PLAIN]);
466 // The fullname does not change.
467 $backupid = $this->backup_course($c1->id);
468 $restored = $this->restore_to_existing_course($backupid, $c2->id, $u1->id);
469 $this->assertEquals('SN_1', $restored->shortname);
470 $this->assertEquals($c2->fullname, $restored->fullname);
471 $this->assertEquals('DESC', $restored->summary);
472 $this->assertEquals(FORMAT_MOODLE, $restored->summaryformat);
475 public function test_restore_course_summary_in_existing_course_without_permissions() {
476 global $DB;
477 $this->resetAfterTest();
478 $dg = $this->getDataGenerator();
479 $u1 = $dg->create_user();
481 $managers = get_archetype_roles('manager');
482 $manager = array_shift($managers);
483 $roleid = $this->create_role_with_caps('moodle/course:changesummary', CAP_PROHIBIT);
484 $dg->role_assign($manager->id, $u1->id);
485 $dg->role_assign($roleid, $u1->id);
487 $c1 = $dg->create_course(['shortname' => 'SN', 'fullname' => 'FN', 'summary' => 'DESC', 'summaryformat' => FORMAT_MOODLE]);
488 $c2 = $dg->create_course(['shortname' => 'A1', 'fullname' => 'B1', 'summary' => 'C1', 'summaryformat' => FORMAT_PLAIN]);
490 // The summary and format do not change.
491 $backupid = $this->backup_course($c1->id);
492 $restored = $this->restore_to_existing_course($backupid, $c2->id, $u1->id);
493 $this->assertEquals('SN_1', $restored->shortname);
494 $this->assertEquals('FN copy 1', $restored->fullname);
495 $this->assertEquals($c2->summary, $restored->summary);
496 $this->assertEquals($c2->summaryformat, $restored->summaryformat);
499 public function test_restore_course_startdate_in_existing_course_without_permissions() {
500 global $DB;
501 $this->resetAfterTest();
502 $dg = $this->getDataGenerator();
504 $u1 = $dg->create_user();
505 $managers = get_archetype_roles('manager');
506 $manager = array_shift($managers);
507 $roleid = $this->create_role_with_caps('moodle/restore:rolldates', CAP_PROHIBIT);
508 $dg->role_assign($manager->id, $u1->id);
509 $dg->role_assign($roleid, $u1->id);
511 // Create two courses with different start dates,in each course create a chat that opens 1 week after the course start date.
512 $startdate1 = mktime(12, 0, 0, 7, 1, 2016); // 01-Jul-2016.
513 $startdate2 = mktime(12, 0, 0, 1, 13, 2000); // 13-Jan-2000.
514 $c1 = $dg->create_course(['shortname' => 'SN', 'fullname' => 'FN', 'summary' => 'DESC', 'summaryformat' => FORMAT_MOODLE,
515 'startdate' => $startdate1]);
516 $chat1 = $dg->create_module('chat', ['name' => 'First', 'course' => $c1->id, 'chattime' => $c1->startdate + 1 * WEEKSECS]);
517 $c2 = $dg->create_course(['shortname' => 'A', 'fullname' => 'B', 'summary' => 'C', 'summaryformat' => FORMAT_PLAIN,
518 'startdate' => $startdate2]);
519 $chat2 = $dg->create_module('chat', ['name' => 'Second', 'course' => $c2->id, 'chattime' => $c2->startdate + 1 * WEEKSECS]);
521 // The startdate does not change.
522 $backupid = $this->backup_course($c1->id);
523 $restored = $this->restore_to_existing_course($backupid, $c2->id, $u1->id);
524 $this->assertEquals('SN_1', $restored->shortname);
525 $this->assertEquals('FN copy 1', $restored->fullname);
526 $this->assertEquals('DESC', $restored->summary);
527 $this->assertEquals(FORMAT_MOODLE, $restored->summaryformat);
528 $this->assertEquals($startdate2, $restored->startdate);
530 // Now course c2 has two chats - one ('Second') was already there and one ('First') was restored from the backup.
531 // Start date of the restored chat ('First') was changed to be 1 week after the c2 start date.
532 $restoredchat1 = $DB->get_record('chat', ['name' => 'First', 'course' => $c2->id]);
533 $restoredchat2 = $DB->get_record('chat', ['name' => 'Second', 'course' => $c2->id]);
534 $this->assertNotEquals($chat1->chattime, $restoredchat1->chattime);
535 $this->assertEquals($chat2->chattime, $restoredchat2->chattime);
536 $this->assertEquals($c2->startdate + 1 * WEEKSECS, $restoredchat2->chattime);