Merge branch 'MDL-72887-M311' of https://github.com/michael-milette/moodle into MOODL...
[moodle.git] / backup / tests / automated_backup_test.php
blobc2fb61e4ad8017155bbab80940de4be46ba4e1b4
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 * Automated backup tests.
20 * @package core_backup
21 * @copyright 2019 John Yao <johnyao@catalyst-au.net>
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 defined('MOODLE_INTERNAL') || die();
27 global $CFG;
28 require_once($CFG->dirroot . '/backup/util/helper/backup_cron_helper.class.php');
29 require_once($CFG->libdir.'/cronlib.php');
30 require_once($CFG->libdir . '/completionlib.php');
32 /**
33 * Automated backup tests.
35 * @copyright 2019 John Yao <johnyao@catalyst-au.net>
36 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
38 class core_backup_automated_backup_testcase extends advanced_testcase {
39 /**
40 * @var \backup_cron_automated_helper
42 protected $backupcronautomatedhelper;
44 /**
45 * @var stdClass $course
47 protected $course;
49 protected function setUp(): void {
50 global $DB, $CFG;
52 $this->resetAfterTest(true);
53 $this->setAdminUser();
54 $CFG->enableavailability = true;
55 $CFG->enablecompletion = true;
57 // Getting a testable backup_cron_automated_helper class.
58 $this->backupcronautomatedhelper = new test_backup_cron_automated_helper();
60 $generator = $this->getDataGenerator();
61 $this->course = $generator->create_course(
62 array('format' => 'topics', 'numsections' => 3,
63 'enablecompletion' => COMPLETION_ENABLED),
64 array('createsections' => true));
65 $forum = $generator->create_module('forum', array(
66 'course' => $this->course->id));
67 $forum2 = $generator->create_module('forum', array(
68 'course' => $this->course->id, 'completion' => COMPLETION_TRACKING_MANUAL));
70 // We need a grade, easiest is to add an assignment.
71 $assignrow = $generator->create_module('assign', array(
72 'course' => $this->course->id));
73 $assign = new assign(context_module::instance($assignrow->cmid), false, false);
74 $item = $assign->get_grade_item();
76 // Make a test grouping as well.
77 $grouping = $generator->create_grouping(array('courseid' => $this->course->id,
78 'name' => 'Grouping!'));
80 $availability = '{"op":"|","show":false,"c":[' .
81 '{"type":"completion","cm":' . $forum2->cmid .',"e":1},' .
82 '{"type":"grade","id":' . $item->id . ',"min":4,"max":94},' .
83 '{"type":"grouping","id":' . $grouping->id . '}' .
84 ']}';
85 $DB->set_field('course_modules', 'availability', $availability, array(
86 'id' => $forum->cmid));
87 $DB->set_field('course_sections', 'availability', $availability, array(
88 'course' => $this->course->id, 'section' => 1));
91 /**
92 * Tests the automated backup run when the there is course backup should be skipped.
94 public function test_automated_backup_skipped_run() {
95 global $DB;
97 // Enable automated back up.
98 set_config('backup_auto_active', true, 'backup');
99 set_config('backup_auto_weekdays', '1111111', 'backup');
101 // Start backup process.
102 $admin = get_admin();
104 // Backup entry should not exist.
105 $backupcourse = $DB->get_record('backup_courses', array('courseid' => $this->course->id));
106 $this->assertFalse($backupcourse);
107 $this->assertInstanceOf(
108 backup_cron_automated_helper::class,
109 $this->backupcronautomatedhelper->return_this()
112 $classobject = $this->backupcronautomatedhelper->return_this();
114 $method = new ReflectionMethod('\backup_cron_automated_helper', 'get_courses');
115 $method->setAccessible(true); // Allow accessing of private method.
116 $courses = $method->invoke($classobject);
118 $method = new ReflectionMethod('\backup_cron_automated_helper', 'check_and_push_automated_backups');
119 $method->setAccessible(true); // Allow accessing of private method.
120 $emailpending = $method->invokeArgs($classobject, [$courses, $admin]);
122 $coursename = $this->course->fullname;
123 $this->expectOutputRegex("/Skipping $coursename \(Not scheduled for backup until/");
124 $this->assertFalse($emailpending);
126 $backupcourse = $DB->get_record('backup_courses', array('courseid' => $this->course->id));
127 $this->assertNotNull($backupcourse->laststatus);
131 * Tests the automated backup run when the there is course backup can be pushed to adhoc task.
133 public function test_automated_backup_push_run() {
134 global $DB;
136 // Enable automated back up.
137 set_config('backup_auto_active', true, 'backup');
138 set_config('backup_auto_weekdays', '1111111', 'backup');
140 $admin = get_admin();
142 $classobject = $this->backupcronautomatedhelper->return_this();
144 $method = new ReflectionMethod('\backup_cron_automated_helper', 'get_courses');
145 $method->setAccessible(true); // Allow accessing of private method.
146 $courses = $method->invoke($classobject);
148 // Create this backup course.
149 $backupcourse = new stdClass;
150 $backupcourse->courseid = $this->course->id;
151 $backupcourse->laststatus = backup_cron_automated_helper::BACKUP_STATUS_NOTYETRUN;
152 $DB->insert_record('backup_courses', $backupcourse);
153 $backupcourse = $DB->get_record('backup_courses', array('courseid' => $this->course->id));
155 // We now manually trigger a backup pushed to adhoc task.
156 // Make sure is in the past, which means should run now.
157 $backupcourse->nextstarttime = time() - 10;
158 $DB->update_record('backup_courses', $backupcourse);
160 $method = new ReflectionMethod('\backup_cron_automated_helper', 'check_and_push_automated_backups');
161 $method->setAccessible(true); // Allow accessing of private method.
162 $emailpending = $method->invokeArgs($classobject, [$courses, $admin]);
163 $this->assertTrue($emailpending);
165 $coursename = $this->course->fullname;
166 $this->expectOutputRegex("/Putting backup of $coursename in adhoc task queue/");
168 $backupcourse = $DB->get_record('backup_courses', array('courseid' => $this->course->id));
169 // Now this backup course status should be queued.
170 $this->assertEquals(backup_cron_automated_helper::BACKUP_STATUS_QUEUED, $backupcourse->laststatus);
174 * Tests the automated backup inactive run.
176 public function test_inactive_run() {
177 backup_cron_automated_helper::run_automated_backup();
178 $this->expectOutputString("Checking automated backup status...INACTIVE\n");
182 * Tests the invisible course being skipped.
184 public function test_should_skip_invisible_course() {
185 global $DB;
187 set_config('backup_auto_active', true, 'backup');
188 set_config('backup_auto_skip_hidden', true, 'backup');
189 set_config('backup_auto_weekdays', '1111111', 'backup');
190 // Create this backup course.
191 $backupcourse = new stdClass;
192 $backupcourse->courseid = $this->course->id;
193 // This is the status we believe last run was OK.
194 $backupcourse->laststatus = backup_cron_automated_helper::BACKUP_STATUS_SKIPPED;
195 $DB->insert_record('backup_courses', $backupcourse);
196 $backupcourse = $DB->get_record('backup_courses', array('courseid' => $this->course->id));
198 $this->assertTrue(course_change_visibility($this->course->id, false));
199 $course = $DB->get_record('course', array('id' => $this->course->id));
200 $this->assertEquals('0', $course->visible);
201 $classobject = $this->backupcronautomatedhelper->return_this();
202 $nextstarttime = backup_cron_automated_helper::calculate_next_automated_backup(null, time());
204 $method = new ReflectionMethod('\backup_cron_automated_helper', 'should_skip_course_backup');
205 $method->setAccessible(true); // Allow accessing of private method.
206 $skipped = $method->invokeArgs($classobject, [$backupcourse, $course, $nextstarttime]);
208 $this->assertTrue($skipped);
209 $this->expectOutputRegex("/Skipping $course->fullname \(Not visible\)/");
213 * Tests the not modified course being skipped.
215 public function test_should_skip_not_modified_course_in_days() {
216 global $DB;
218 set_config('backup_auto_active', true, 'backup');
219 // Skip if not modified in two days.
220 set_config('backup_auto_skip_modif_days', 2, 'backup');
221 set_config('backup_auto_weekdays', '1111111', 'backup');
223 // Create this backup course.
224 $backupcourse = new stdClass;
225 $backupcourse->courseid = $this->course->id;
226 // This is the status we believe last run was OK.
227 $backupcourse->laststatus = backup_cron_automated_helper::BACKUP_STATUS_SKIPPED;
228 $backupcourse->laststarttime = time() - 2 * DAYSECS;
229 $backupcourse->lastendtime = time() - 1 * DAYSECS;
230 $DB->insert_record('backup_courses', $backupcourse);
231 $backupcourse = $DB->get_record('backup_courses', array('courseid' => $this->course->id));
232 $course = $DB->get_record('course', array('id' => $this->course->id));
234 $course->timemodified = time() - 2 * DAYSECS - 1;
236 $classobject = $this->backupcronautomatedhelper->return_this();
237 $nextstarttime = backup_cron_automated_helper::calculate_next_automated_backup(null, time());
239 $method = new ReflectionMethod('\backup_cron_automated_helper', 'should_skip_course_backup');
240 $method->setAccessible(true); // Allow accessing of private method.
241 $skipped = $method->invokeArgs($classobject, [$backupcourse, $course, $nextstarttime]);
243 $this->assertTrue($skipped);
244 $this->expectOutputRegex("/Skipping $course->fullname \(Not modified in the past 2 days\)/");
248 * Tests the backup not modified course being skipped.
250 public function test_should_skip_not_modified_course_since_prev() {
251 global $DB;
253 set_config('backup_auto_active', true, 'backup');
254 // Skip if not modified in two days.
255 set_config('backup_auto_skip_modif_prev', 2, 'backup');
256 set_config('backup_auto_weekdays', '1111111', 'backup');
258 // Create this backup course.
259 $backupcourse = new stdClass;
260 $backupcourse->courseid = $this->course->id;
261 // This is the status we believe last run was OK.
262 $backupcourse->laststatus = backup_cron_automated_helper::BACKUP_STATUS_SKIPPED;
263 $backupcourse->laststarttime = time() - 2 * DAYSECS;
264 $backupcourse->lastendtime = time() - 1 * DAYSECS;
265 $DB->insert_record('backup_courses', $backupcourse);
266 $backupcourse = $DB->get_record('backup_courses', array('courseid' => $this->course->id));
267 $course = $DB->get_record('course', array('id' => $this->course->id));
269 $course->timemodified = time() - 2 * DAYSECS - 1;
271 $classobject = $this->backupcronautomatedhelper->return_this();
272 $nextstarttime = backup_cron_automated_helper::calculate_next_automated_backup(null, time());
274 $method = new ReflectionMethod('\backup_cron_automated_helper', 'should_skip_course_backup');
275 $method->setAccessible(true); // Allow accessing of private method.
276 $skipped = $method->invokeArgs($classobject, [$backupcourse, $course, $nextstarttime]);
278 $this->assertTrue($skipped);
279 $this->expectOutputRegex("/Skipping $course->fullname \(Not modified since previous backup\)/");
283 * Test the task completes when coureid is missing.
285 public function test_task_complete_when_courseid_is_missing() {
286 global $DB;
287 $admin = get_admin();
288 $classobject = $this->backupcronautomatedhelper->return_this();
290 // Create this backup course.
291 $backupcourse = new stdClass;
292 $backupcourse->courseid = $this->course->id;
293 $backupcourse->laststatus = backup_cron_automated_helper::BACKUP_STATUS_NOTYETRUN;
294 $DB->insert_record('backup_courses', $backupcourse);
295 $backupcourse = $DB->get_record('backup_courses', ['courseid' => $this->course->id]);
297 // Create a backup task.
298 $method = new ReflectionMethod('\backup_cron_automated_helper', 'push_course_backup_adhoc_task');
299 $method->setAccessible(true); // Allow accessing of private method.
300 $method->invokeArgs($classobject, [$backupcourse, $admin]);
302 // Delete course for this test.
303 delete_course($this->course->id, false);
305 $task = core\task\manager::get_next_adhoc_task(time());
307 ob_start();
308 $task->execute();
309 $output = ob_get_clean();
311 $this->assertStringContainsString('Invalid course id: ' . $this->course->id . ', task aborted.', $output);
312 core\task\manager::adhoc_task_complete($task);
316 * Test the task completes when backup course is missing.
318 public function test_task_complete_when_backup_course_is_missing() {
319 global $DB;
320 $admin = get_admin();
321 $classobject = $this->backupcronautomatedhelper->return_this();
323 // Create this backup course.
324 $backupcourse = new stdClass;
325 $backupcourse->courseid = $this->course->id;
326 $backupcourse->laststatus = backup_cron_automated_helper::BACKUP_STATUS_NOTYETRUN;
327 $DB->insert_record('backup_courses', $backupcourse);
328 $backupcourse = $DB->get_record('backup_courses', ['courseid' => $this->course->id]);
330 // Create a backup task.
331 $method = new ReflectionMethod('\backup_cron_automated_helper', 'push_course_backup_adhoc_task');
332 $method->setAccessible(true); // Allow accessing of private method.
333 $method->invokeArgs($classobject, [$backupcourse, $admin]);
335 // Delete backup course for this test.
336 $DB->delete_records('backup_courses', ['courseid' => $this->course->id]);
338 $task = core\task\manager::get_next_adhoc_task(time());
340 ob_start();
341 $task->execute();
342 $output = ob_get_clean();
344 $this->assertStringContainsString('Automated backup for course: ' . $this->course->fullname . ' encounters an error.',
345 $output);
346 core\task\manager::adhoc_task_complete($task);
351 * New backup_cron_automated_helper class for testing.
353 * This class extends the helper backup_cron_automated_helper class
354 * in order to utilise abstract class for testing.
356 * @package core
357 * @copyright 2019 John Yao <johnyao@catalyst-au.net>
358 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
360 class test_backup_cron_automated_helper extends backup_cron_automated_helper {
362 * Returning this for testing.
364 public function return_this() {
365 return $this;