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/>.
17 namespace core_completion
;
20 * Test completion criteria.
22 * @package core_completion
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
{
32 public function setUp(): void
{
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();
45 * Test that activity completion dates are used when activity criteria is marked as completed.
47 public function test_completion_criteria_activity(): void
{
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) [
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());
82 * Test that enrolment timestart are used when duration criteria is marked as completed.
84 public function test_completion_criteria_duration_timestart(): void
{
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) [
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/");
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.
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
{
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) [
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/");
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.
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
{
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) [
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/");
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.
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
{
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) [
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;
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;
237 // Run completion scheduled task.
238 $task = new \core\task\
completion_regular_task();
239 $this->expectOutputRegex("/Marking complete/");
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.
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());