2 // This file is part of Moodle - http://moodle.org/
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.
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/>.
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();
28 require_once($CFG->dirroot
. '/backup/util/includes/backup_includes.php');
29 require_once($CFG->dirroot
. '/backup/util/includes/restore_includes.php');
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
{
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.
47 protected function backup_course($courseid, $userid = 2) {
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);
55 $results = $bc->get_results();
56 $results['backup_destination']->extract_to_pathname($packer, "$CFG->tempdir/backup/core_course_testcase");
60 return 'core_course_testcase';
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();
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) {
92 $target = backup
::TARGET_CURRENT_ADDING
;
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 $rc->execute_precheck();
104 $course = $DB->get_record('course', array('id' => $rc->get_courseid()));
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);
134 public function test_restore_existing_idnumber_in_new_course() {
135 $this->resetAfterTest();
137 $dg = $this->getDataGenerator();
138 $c1 = $dg->create_course(['idnumber' => 'ABC']);
139 $backupid = $this->backup_course($c1->id
);
140 $c2 = $this->restore_to_new_course($backupid);
142 // The ID number is set empty.
143 $this->assertEquals('', $c2->idnumber
);
146 public function test_restore_non_existing_idnumber_in_new_course() {
148 $this->resetAfterTest();
150 $dg = $this->getDataGenerator();
151 $c1 = $dg->create_course(['idnumber' => 'ABC']);
152 $backupid = $this->backup_course($c1->id
);
154 $c1->idnumber
= 'BCD';
155 $DB->update_record('course', $c1);
157 // The ID number changed.
158 $c2 = $this->restore_to_new_course($backupid);
159 $this->assertEquals('ABC', $c2->idnumber
);
162 public function test_restore_existing_idnumber_in_existing_course() {
164 $this->resetAfterTest();
166 $dg = $this->getDataGenerator();
167 $c1 = $dg->create_course(['idnumber' => 'ABC']);
168 $c2 = $dg->create_course(['idnumber' => 'DEF']);
169 $backupid = $this->backup_course($c1->id
);
171 // The ID number does not change.
172 $c2 = $this->restore_to_existing_course($backupid, $c2->id
);
173 $this->assertEquals('DEF', $c2->idnumber
);
175 $c1 = $DB->get_record('course', array('id' => $c1->id
));
176 $this->assertEquals('ABC', $c1->idnumber
);
179 public function test_restore_non_existing_idnumber_in_existing_course() {
181 $this->resetAfterTest();
183 $dg = $this->getDataGenerator();
184 $c1 = $dg->create_course(['idnumber' => 'ABC']);
185 $c2 = $dg->create_course(['idnumber' => 'DEF']);
186 $backupid = $this->backup_course($c1->id
);
188 $c1->idnumber
= 'XXX';
189 $DB->update_record('course', $c1);
191 // The ID number has changed.
192 $c2 = $this->restore_to_existing_course($backupid, $c2->id
);
193 $this->assertEquals('ABC', $c2->idnumber
);
196 public function test_restore_idnumber_in_existing_course_without_permissions() {
198 $this->resetAfterTest();
199 $dg = $this->getDataGenerator();
200 $u1 = $dg->create_user();
202 $managers = get_archetype_roles('manager');
203 $manager = array_shift($managers);
204 $roleid = $this->create_role_with_caps('moodle/course:changeidnumber', CAP_PROHIBIT
);
205 $dg->role_assign($manager->id
, $u1->id
);
206 $dg->role_assign($roleid, $u1->id
);
208 $c1 = $dg->create_course(['idnumber' => 'ABC']);
209 $c2 = $dg->create_course(['idnumber' => 'DEF']);
210 $backupid = $this->backup_course($c1->id
);
212 $c1->idnumber
= 'XXX';
213 $DB->update_record('course', $c1);
215 // The ID number does not change.
216 $c2 = $this->restore_to_existing_course($backupid, $c2->id
, $u1->id
);
217 $this->assertEquals('DEF', $c2->idnumber
);
220 public function test_restore_course_info_in_new_course() {
222 $this->resetAfterTest();
223 $dg = $this->getDataGenerator();
225 $c1 = $dg->create_course(['shortname' => 'SN', 'fullname' => 'FN', 'summary' => 'DESC', 'summaryformat' => FORMAT_MOODLE
]);
226 $backupid = $this->backup_course($c1->id
);
228 // The information is restored but adapted because names are already taken.
229 $c2 = $this->restore_to_new_course($backupid);
230 $this->assertEquals('SN_1', $c2->shortname
);
231 $this->assertEquals('FN copy 1', $c2->fullname
);
232 $this->assertEquals('DESC', $c2->summary
);
233 $this->assertEquals(FORMAT_MOODLE
, $c2->summaryformat
);
236 public function test_restore_course_info_in_existing_course() {
238 $this->resetAfterTest();
239 $dg = $this->getDataGenerator();
241 $c1 = $dg->create_course(['shortname' => 'SN', 'fullname' => 'FN', 'summary' => 'DESC', 'summaryformat' => FORMAT_MOODLE
]);
242 $c2 = $dg->create_course(['shortname' => 'A', 'fullname' => 'B', 'summary' => 'C', 'summaryformat' => FORMAT_PLAIN
]);
243 $backupid = $this->backup_course($c1->id
);
245 // The information is restored but adapted because names are already taken.
246 $c2 = $this->restore_to_existing_course($backupid, $c2->id
);
247 $this->assertEquals('SN_1', $c2->shortname
);
248 $this->assertEquals('FN copy 1', $c2->fullname
);
249 $this->assertEquals('DESC', $c2->summary
);
250 $this->assertEquals(FORMAT_MOODLE
, $c2->summaryformat
);
253 public function test_restore_course_shortname_in_existing_course_without_permissions() {
255 $this->resetAfterTest();
256 $dg = $this->getDataGenerator();
257 $u1 = $dg->create_user();
259 $managers = get_archetype_roles('manager');
260 $manager = array_shift($managers);
261 $roleid = $this->create_role_with_caps('moodle/course:changeshortname', CAP_PROHIBIT
);
262 $dg->role_assign($manager->id
, $u1->id
);
263 $dg->role_assign($roleid, $u1->id
);
265 $c1 = $dg->create_course(['shortname' => 'SN', 'fullname' => 'FN', 'summary' => 'DESC', 'summaryformat' => FORMAT_MOODLE
]);
266 $c2 = $dg->create_course(['shortname' => 'A1', 'fullname' => 'B1', 'summary' => 'C1', 'summaryformat' => FORMAT_PLAIN
]);
268 // The shortname does not change.
269 $backupid = $this->backup_course($c1->id
);
270 $restored = $this->restore_to_existing_course($backupid, $c2->id
, $u1->id
);
271 $this->assertEquals($c2->shortname
, $restored->shortname
);
272 $this->assertEquals('FN copy 1', $restored->fullname
);
273 $this->assertEquals('DESC', $restored->summary
);
274 $this->assertEquals(FORMAT_MOODLE
, $restored->summaryformat
);
277 public function test_restore_course_fullname_in_existing_course_without_permissions() {
279 $this->resetAfterTest();
280 $dg = $this->getDataGenerator();
281 $u1 = $dg->create_user();
283 $managers = get_archetype_roles('manager');
284 $manager = array_shift($managers);
285 $roleid = $this->create_role_with_caps('moodle/course:changefullname', CAP_PROHIBIT
);
286 $dg->role_assign($manager->id
, $u1->id
);
287 $dg->role_assign($roleid, $u1->id
);
289 $c1 = $dg->create_course(['shortname' => 'SN', 'fullname' => 'FN', 'summary' => 'DESC', 'summaryformat' => FORMAT_MOODLE
]);
290 $c2 = $dg->create_course(['shortname' => 'A1', 'fullname' => 'B1', 'summary' => 'C1', 'summaryformat' => FORMAT_PLAIN
]);
292 // The fullname does not change.
293 $backupid = $this->backup_course($c1->id
);
294 $restored = $this->restore_to_existing_course($backupid, $c2->id
, $u1->id
);
295 $this->assertEquals('SN_1', $restored->shortname
);
296 $this->assertEquals($c2->fullname
, $restored->fullname
);
297 $this->assertEquals('DESC', $restored->summary
);
298 $this->assertEquals(FORMAT_MOODLE
, $restored->summaryformat
);
301 public function test_restore_course_summary_in_existing_course_without_permissions() {
303 $this->resetAfterTest();
304 $dg = $this->getDataGenerator();
305 $u1 = $dg->create_user();
307 $managers = get_archetype_roles('manager');
308 $manager = array_shift($managers);
309 $roleid = $this->create_role_with_caps('moodle/course:changesummary', CAP_PROHIBIT
);
310 $dg->role_assign($manager->id
, $u1->id
);
311 $dg->role_assign($roleid, $u1->id
);
313 $c1 = $dg->create_course(['shortname' => 'SN', 'fullname' => 'FN', 'summary' => 'DESC', 'summaryformat' => FORMAT_MOODLE
]);
314 $c2 = $dg->create_course(['shortname' => 'A1', 'fullname' => 'B1', 'summary' => 'C1', 'summaryformat' => FORMAT_PLAIN
]);
316 // The summary and format do not change.
317 $backupid = $this->backup_course($c1->id
);
318 $restored = $this->restore_to_existing_course($backupid, $c2->id
, $u1->id
);
319 $this->assertEquals('SN_1', $restored->shortname
);
320 $this->assertEquals('FN copy 1', $restored->fullname
);
321 $this->assertEquals($c2->summary
, $restored->summary
);
322 $this->assertEquals($c2->summaryformat
, $restored->summaryformat
);