MDL-78575 mod_lti: Add deletion support to course tools page
[moodle.git] / completion / tests / completion_criteria_test.php
blob7061d7e86e786d44ece59d25fb98c99e7b3befcc
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 namespace core_completion;
19 /**
20 * Test completion criteria.
22 * @package core_completion
23 * @category test
24 * @copyright 2021 Mikhail Golenkov <mikhailgolenkov@catalyst-au.net>
25 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
27 class completion_criteria_test extends \advanced_testcase {
29 /**
30 * Test setup.
32 public function setUp(): void {
33 global $CFG;
34 require_once($CFG->dirroot.'/completion/criteria/completion_criteria_course.php');
35 require_once($CFG->dirroot.'/completion/criteria/completion_criteria_activity.php');
36 require_once($CFG->dirroot.'/completion/criteria/completion_criteria_duration.php');
37 require_once($CFG->dirroot.'/completion/criteria/completion_criteria_grade.php');
38 require_once($CFG->dirroot.'/completion/criteria/completion_criteria_date.php');
40 $this->setAdminUser();
41 $this->resetAfterTest();
44 /**
45 * Test that activity completion dates are used when activity criteria is marked as completed.
47 public function test_completion_criteria_activity(): void {
48 global $DB;
49 $timestarted = time();
51 // Create a course, an activity and enrol a user.
52 $course = $this->getDataGenerator()->create_course(['enablecompletion' => 1]);
53 $assign = $this->getDataGenerator()->create_module('assign', ['course' => $course->id], ['completion' => 1]);
54 $user = $this->getDataGenerator()->create_user();
55 $studentrole = $DB->get_record('role', ['shortname' => 'student']);
56 $this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id);
58 // Set completion criteria and mark the user to complete the criteria.
59 $criteriadata = (object) [
60 'id' => $course->id,
61 'criteria_activity' => [$assign->cmid => 1],
63 $criterion = new \completion_criteria_activity();
64 $criterion->update_config($criteriadata);
65 $cmassign = get_coursemodule_from_id('assign', $assign->cmid);
66 $completion = new \completion_info($course);
67 $completion->update_state($cmassign, COMPLETION_COMPLETE, $user->id);
69 // Completion criteria for the user is supposed to be marked as completed at now().
70 $result = \core_completion_external::get_activities_completion_status($course->id, $user->id);
71 $actual = reset($result['statuses']);
72 $this->assertEquals(1, $actual['state']);
73 $this->assertGreaterThanOrEqual($timestarted, $actual['timecompleted']);
75 // And the whole course is marked as completed at now().
76 $ccompletion = new \completion_completion(['userid' => $user->id, 'course' => $course->id]);
77 $this->assertGreaterThanOrEqual($timestarted, $ccompletion->timecompleted);
78 $this->assertTrue($ccompletion->is_complete());
81 /**
82 * Test that enrolment timestart are used when duration criteria is marked as completed.
84 public function test_completion_criteria_duration_timestart(): void {
85 global $DB;
86 $timestarted = 1610000000;
87 $durationperiod = DAYSECS;
89 // Create a course and users.
90 $course = $this->getDataGenerator()->create_course(['enablecompletion' => 1]);
91 $user = $this->getDataGenerator()->create_and_enrol($course, 'student', null, 'manual', $timestarted);
93 // Set completion criteria.
94 $criteriadata = (object) [
95 'id' => $course->id,
96 'criteria_duration' => 1,
97 'criteria_duration_days' => $durationperiod,
99 $criterion = new \completion_criteria_duration();
100 $criterion->update_config($criteriadata);
102 // Run completion scheduled task.
103 $task = new \core\task\completion_regular_task();
104 $this->expectOutputRegex("/Marking complete/");
105 $task->execute();
106 // Hopefully, some day MDL-33320 will be fixed and all these sleeps
107 // and double cron calls in behat and unit tests will be removed.
108 sleep(1);
109 $task->execute();
111 // The course for User is supposed to be marked as completed at $timestarted + $durationperiod.
112 $ccompletion = new \completion_completion(['userid' => $user->id, 'course' => $course->id]);
113 $this->assertEquals($timestarted + $durationperiod, $ccompletion->timecompleted);
114 $this->assertTrue($ccompletion->is_complete());
118 * Test that enrolment timecreated are used when duration criteria is marked as completed.
120 public function test_completion_criteria_duration_timecreated(): void {
121 global $DB;
123 $timecreated = 1620000000;
124 $durationperiod = DAYSECS;
126 // Create a course and users.
127 $course = $this->getDataGenerator()->create_course(['enablecompletion' => 1]);
129 // Create and enrol user with an empty time start, but update the record like it was created at $timecreated.
130 $user = $this->getDataGenerator()->create_and_enrol($course);
131 $DB->set_field('user_enrolments', 'timecreated', $timecreated, ['userid' => $user->id]);
133 // Set completion criteria.
134 $criteriadata = (object) [
135 'id' => $course->id,
136 'criteria_duration' => 1,
137 'criteria_duration_days' => $durationperiod,
139 $criterion = new \completion_criteria_duration();
140 $criterion->update_config($criteriadata);
142 // Run completion scheduled task.
143 $task = new \core\task\completion_regular_task();
144 $this->expectOutputRegex("/Marking complete/");
145 $task->execute();
147 // Hopefully, some day MDL-33320 will be fixed and all these sleeps
148 // and double cron calls in behat and unit tests will be removed.
149 sleep(1);
150 $task->execute();
152 // The course for user is supposed to be marked as completed at $timecreated + $durationperiod.
153 $ccompletion = new \completion_completion(['userid' => $user->id, 'course' => $course->id]);
154 $this->assertEquals($timecreated + $durationperiod, $ccompletion->timecompleted);
155 $this->assertTrue($ccompletion->is_complete());
159 * Test that criteria date is used as a course completion date.
161 public function test_completion_criteria_date(): void {
162 global $DB;
163 $timeend = 1610000000;
165 // Create a course and enrol a user.
166 $course = $this->getDataGenerator()->create_course(['enablecompletion' => 1]);
167 $user = $this->getDataGenerator()->create_user();
168 $studentrole = $DB->get_record('role', ['shortname' => 'student']);
169 $this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id);
171 // Set completion criteria.
172 $criteriadata = (object) [
173 'id' => $course->id,
174 'criteria_date' => 1,
175 'criteria_date_value' => $timeend,
177 $criterion = new \completion_criteria_date();
178 $criterion->update_config($criteriadata);
180 // Run completion scheduled task.
181 $task = new \core\task\completion_regular_task();
182 $this->expectOutputRegex("/Marking complete/");
183 $task->execute();
184 // Hopefully, some day MDL-33320 will be fixed and all these sleeps
185 // and double cron calls in behat and unit tests will be removed.
186 sleep(1);
187 $task->execute();
189 // The course is supposed to be marked as completed at $timeend.
190 $ccompletion = new \completion_completion(['userid' => $user->id, 'course' => $course->id]);
191 $this->assertEquals($timeend, $ccompletion->timecompleted);
192 $this->assertTrue($ccompletion->is_complete());
196 * Test that grade timemodified is used when grade criteria is marked as completed.
198 public function test_completion_criteria_grade(): void {
199 global $DB;
200 $timegraded = 1610000000;
202 // Create a course and enrol a couple of users.
203 $course = $this->getDataGenerator()->create_course(['enablecompletion' => 1]);
204 $user1 = $this->getDataGenerator()->create_user();
205 $user2 = $this->getDataGenerator()->create_user();
206 $studentrole = $DB->get_record('role', ['shortname' => 'student']);
207 $this->getDataGenerator()->enrol_user($user1->id, $course->id, $studentrole->id);
208 $this->getDataGenerator()->enrol_user($user2->id, $course->id, $studentrole->id);
210 // Set completion criteria.
211 $criteriadata = (object) [
212 'id' => $course->id,
213 'criteria_grade' => 1,
214 'criteria_grade_value' => 66,
216 $criterion = new \completion_criteria_grade();
217 $criterion->update_config($criteriadata);
219 $coursegradeitem = \grade_item::fetch_course_item($course->id);
221 // Grade User 1 with a passing grade.
222 $grade1 = new \grade_grade();
223 $grade1->itemid = $coursegradeitem->id;
224 $grade1->timemodified = $timegraded;
225 $grade1->userid = $user1->id;
226 $grade1->finalgrade = 80;
227 $grade1->insert();
229 // Grade User 2 with a non-passing grade.
230 $grade2 = new \grade_grade();
231 $grade2->itemid = $coursegradeitem->id;
232 $grade2->timemodified = $timegraded;
233 $grade2->userid = $user2->id;
234 $grade2->finalgrade = 40;
235 $grade2->insert();
237 // Run completion scheduled task.
238 $task = new \core\task\completion_regular_task();
239 $this->expectOutputRegex("/Marking complete/");
240 $task->execute();
241 // Hopefully, some day MDL-33320 will be fixed and all these sleeps
242 // and double cron calls in behat and unit tests will be removed.
243 sleep(1);
244 $task->execute();
246 // The course for User 1 is supposed to be marked as completed when the user was graded.
247 $ccompletion = new \completion_completion(['userid' => $user1->id, 'course' => $course->id]);
248 $this->assertEquals($timegraded, $ccompletion->timecompleted);
249 $this->assertTrue($ccompletion->is_complete());
251 // The course for User 2 is supposed to be marked as not completed.
252 $ccompletion = new \completion_completion(['userid' => $user2->id, 'course' => $course->id]);
253 $this->assertFalse($ccompletion->is_complete());