See Release Notes
Long Term Support Release
Differences Between: [Versions 311 and 401] [Versions 401 and 402] [Versions 401 and 403]
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/>. 16 17 namespace core_course\backup; 18 19 use backup; 20 use backup_controller; 21 use restore_controller; 22 use restore_dbops; 23 24 defined('MOODLE_INTERNAL') || die(); 25 global $CFG; 26 27 require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php'); 28 require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php'); 29 require_once($CFG->dirroot . '/course/format/tests/fixtures/format_theunittest.php'); 30 31 /** 32 * Course restore testcase. 33 * 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 37 */ 38 class restore_test extends \advanced_testcase { 39 40 /** 41 * Backup a course and return its backup ID. 42 * 43 * @param int $courseid The course ID. 44 * @param int $userid The user doing the backup. 45 * @return string 46 */ 47 protected function backup_course($courseid, $userid = 2) { 48 $backuptempdir = make_backup_temp_directory(''); 49 $packer = get_file_packer('application/vnd.moodle.backup'); 50 51 $bc = new backup_controller(backup::TYPE_1COURSE, $courseid, backup::FORMAT_MOODLE, backup::INTERACTIVE_NO, 52 backup::MODE_GENERAL, $userid); 53 $bc->execute_plan(); 54 55 $results = $bc->get_results(); 56 $results['backup_destination']->extract_to_pathname($packer, "$backuptempdir/core_course_testcase"); 57 58 $bc->destroy(); 59 unset($bc); 60 return 'core_course_testcase'; 61 } 62 63 /** 64 * Create a role with capabilities and permissions. 65 * 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. 69 */ 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); 76 } 77 accesslib_clear_all_caches_for_unit_testing(); 78 return $roleid; 79 } 80 81 /** 82 * Restore a course. 83 * 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. 88 */ 89 protected function restore_course($backupid, $courseid, $userid) { 90 global $DB; 91 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); 97 } 98 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(); 103 104 $course = $DB->get_record('course', array('id' => $rc->get_courseid())); 105 106 $rc->destroy(); 107 unset($rc); 108 return $course; 109 } 110 111 /** 112 * Restore a course to an existing course. 113 * 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. 118 */ 119 protected function restore_to_existing_course($backupid, $courseid, $userid = 2) { 120 return $this->restore_course($backupid, $courseid, $userid); 121 } 122 123 /** 124 * Restore a course to a new course. 125 * 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. 129 */ 130 protected function restore_to_new_course($backupid, $userid = 2) { 131 return $this->restore_course($backupid, 0, $userid); 132 } 133 134 /** 135 * Restore a course. 136 * 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. 141 * 142 * @return stdClass The updated course object. 143 */ 144 protected function async_restore_course($backupid, $courseid, $userid, $target) { 145 global $DB; 146 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); 151 } 152 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()); 156 157 $restoreid = $rc->get_restoreid(); 158 $rc->destroy(); 159 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); 165 166 // We are expecting trace output during this test. 167 $this->expectOutputRegex("/$restoreid/"); 168 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); 175 176 $course = $DB->get_record('course', array('id' => $rc->get_courseid())); 177 178 return $course; 179 } 180 181 /** 182 * Restore a course to an existing course. 183 * 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. 189 */ 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); 193 } 194 195 /** 196 * Restore a course to a new course. 197 * 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. 201 */ 202 protected function async_restore_to_new_course($backupid, $userid = 2) { 203 return $this->async_restore_course($backupid, 0, $userid, 0); 204 } 205 206 public function test_async_restore_existing_idnumber_in_new_course() { 207 $this->resetAfterTest(); 208 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); 213 214 // The ID number is set empty. 215 $this->assertEquals('', $c2->idnumber); 216 } 217 218 public function test_async_restore_course_info_in_existing_course() { 219 global $DB; 220 $this->resetAfterTest(); 221 $dg = $this->getDataGenerator(); 222 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')); 226 227 $startdate = mktime(12, 0, 0, 7, 1, 2016); // 01-Jul-2016. 228 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); 237 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); 245 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); 252 } 253 254 public function test_async_restore_course_info_in_existing_course_delete_first() { 255 global $DB; 256 $this->resetAfterTest(); 257 $dg = $this->getDataGenerator(); 258 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')); 262 263 $startdate = mktime(12, 0, 0, 7, 1, 2016); // 01-Jul-2016. 264 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); 273 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); 277 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); 283 } 284 285 public function test_restore_existing_idnumber_in_new_course() { 286 $this->resetAfterTest(); 287 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); 292 293 // The ID number is set empty. 294 $this->assertEquals('', $c2->idnumber); 295 } 296 297 public function test_restore_non_existing_idnumber_in_new_course() { 298 global $DB; 299 $this->resetAfterTest(); 300 301 $dg = $this->getDataGenerator(); 302 $c1 = $dg->create_course(['idnumber' => 'ABC']); 303 $backupid = $this->backup_course($c1->id); 304 305 $c1->idnumber = 'BCD'; 306 $DB->update_record('course', $c1); 307 308 // The ID number changed. 309 $c2 = $this->restore_to_new_course($backupid); 310 $this->assertEquals('ABC', $c2->idnumber); 311 } 312 313 public function test_restore_existing_idnumber_in_existing_course() { 314 global $DB; 315 $this->resetAfterTest(); 316 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); 321 322 // The ID number does not change. 323 $c2 = $this->restore_to_existing_course($backupid, $c2->id); 324 $this->assertEquals('DEF', $c2->idnumber); 325 326 $c1 = $DB->get_record('course', array('id' => $c1->id)); 327 $this->assertEquals('ABC', $c1->idnumber); 328 } 329 330 public function test_restore_non_existing_idnumber_in_existing_course() { 331 global $DB; 332 $this->resetAfterTest(); 333 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); 338 339 $c1->idnumber = 'XXX'; 340 $DB->update_record('course', $c1); 341 342 // The ID number has changed. 343 $c2 = $this->restore_to_existing_course($backupid, $c2->id); 344 $this->assertEquals('ABC', $c2->idnumber); 345 } 346 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(); 352 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); 358 359 $c1 = $dg->create_course(['idnumber' => 'ABC']); 360 $c2 = $dg->create_course(['idnumber' => 'DEF']); 361 $backupid = $this->backup_course($c1->id); 362 363 $c1->idnumber = 'XXX'; 364 $DB->update_record('course', $c1); 365 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); 369 } 370 371 public function test_restore_course_info_in_new_course() { 372 global $DB; 373 $this->resetAfterTest(); 374 $dg = $this->getDataGenerator(); 375 376 $startdate = mktime(12, 0, 0, 7, 1, 2016); // 01-Jul-2016. 377 378 $c1 = $dg->create_course(['shortname' => 'SN', 'fullname' => 'FN', 'startdate' => $startdate, 379 'summary' => 'DESC', 'summaryformat' => FORMAT_MOODLE]); 380 $backupid = $this->backup_course($c1->id); 381 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); 389 } 390 391 public function test_restore_course_info_in_existing_course() { 392 global $DB; 393 $this->resetAfterTest(); 394 $dg = $this->getDataGenerator(); 395 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')); 399 400 $startdate = mktime(12, 0, 0, 7, 1, 2016); // 01-Jul-2016. 401 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); 410 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); 418 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); 425 } 426 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(); 432 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); 438 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]); 441 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); 449 } 450 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(); 456 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); 462 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]); 465 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); 473 } 474 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(); 480 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); 486 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]); 489 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); 497 } 498 499 public function test_restore_course_startdate_in_existing_course_without_permissions() { 500 global $DB; 501 $this->resetAfterTest(); 502 $dg = $this->getDataGenerator(); 503 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); 510 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]); 520 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); 529 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); 537 } 538 539 /** 540 * Tests course restore with editor in course format. 541 * 542 * @author Matthew Hilton 543 * @covers \core_courseformat 544 */ 545 public function test_restore_editor_courseformat() { 546 $this->resetAfterTest(); 547 548 // Setup user with restore permissions. 549 $dg = $this->getDataGenerator(); 550 $u1 = $dg->create_user(); 551 552 $managers = get_archetype_roles('manager'); 553 $manager = array_shift($managers); 554 $dg->role_assign($manager->id, $u1->id); 555 556 // Create a course with an editor item in the course format. 557 $courseformatoptiondata = (object) [ 558 "hideoddsections" => 1, 559 'summary_editor' => [ 560 'text' => '<p>Somewhere over the rainbow</p><p>The <b>quick</b> brown fox jumpos over the lazy dog.</p>', 561 'format' => 1 562 ] 563 ]; 564 $course1 = $dg->create_course(['format' => 'theunittest']); 565 $course2 = $dg->create_course(['format' => 'theunittest']); 566 $this->assertEquals('theunittest', $course1->format); 567 course_create_sections_if_missing($course1, array(0, 1)); 568 569 // Set the course format. 570 $courseformat = course_get_format($course1); 571 $courseformat->update_course_format_options($courseformatoptiondata); 572 573 // Backup and restore the course. 574 $backupid = $this->backup_course($course1->id); 575 $this->restore_to_existing_course($backupid, $course2->id, $u1->id); 576 577 // Get the restored course format. 578 $restoredformat = course_get_format($course2); 579 $restoredformatoptions = $restoredformat->get_format_options(); 580 581 $this->assertEqualsCanonicalizing($courseformatoptiondata, (object) $restoredformatoptions); 582 } 583 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body