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/timecreated are used when duration criteria is marked as completed.
84 public function test_completion_criteria_duration(): void
{
86 $timestarted = 1610000000;
87 $timecreated = 1620000000;
88 $durationperiod = DAYSECS
;
90 // Create a course and users.
91 $course = $this->getDataGenerator()->create_course(['enablecompletion' => 1]);
92 $user1 = $this->getDataGenerator()->create_user();
93 $user2 = $this->getDataGenerator()->create_user();
94 $studentrole = $DB->get_record('role', ['shortname' => 'student']);
96 // Enrol User 1 with time start = $timestarted.
97 $this->getDataGenerator()->enrol_user($user1->id
, $course->id
, $studentrole->id
, 'manual', $timestarted);
99 // Enrol User 2 with an empty time start, but update the record like it was created at $timecreated.
100 $this->getDataGenerator()->enrol_user($user2->id
, $course->id
, $studentrole->id
);
101 $DB->set_field('user_enrolments', 'timecreated', $timecreated, ['userid' => $user2->id
]);
103 // Set completion criteria.
104 $criteriadata = (object) [
106 'criteria_duration' => 1,
107 'criteria_duration_days' => $durationperiod,
109 $criterion = new \
completion_criteria_duration();
110 $criterion->update_config($criteriadata);
112 // Run completion scheduled task.
113 $task = new \core\task\
completion_regular_task();
114 $this->expectOutputRegex("/Marking complete/");
116 // Hopefully, some day MDL-33320 will be fixed and all these sleeps
117 // and double cron calls in behat and unit tests will be removed.
121 // The course for User 1 is supposed to be marked as completed at $timestarted + $durationperiod.
122 $ccompletion = new \
completion_completion(['userid' => $user1->id
, 'course' => $course->id
]);
123 $this->assertEquals($timestarted +
$durationperiod, $ccompletion->timecompleted
);
124 $this->assertTrue($ccompletion->is_complete());
126 // The course for User 2 is supposed to be marked as completed at $timecreated + $durationperiod.
127 $ccompletion = new \
completion_completion(['userid' => $user2->id
, 'course' => $course->id
]);
128 $this->assertEquals($timecreated +
$durationperiod, $ccompletion->timecompleted
);
129 $this->assertTrue($ccompletion->is_complete());
133 * Test that criteria date is used as a course completion date.
135 public function test_completion_criteria_date(): void
{
137 $timeend = 1610000000;
139 // Create a course and enrol a user.
140 $course = $this->getDataGenerator()->create_course(['enablecompletion' => 1]);
141 $user = $this->getDataGenerator()->create_user();
142 $studentrole = $DB->get_record('role', ['shortname' => 'student']);
143 $this->getDataGenerator()->enrol_user($user->id
, $course->id
, $studentrole->id
);
145 // Set completion criteria.
146 $criteriadata = (object) [
148 'criteria_date' => 1,
149 'criteria_date_value' => $timeend,
151 $criterion = new \
completion_criteria_date();
152 $criterion->update_config($criteriadata);
154 // Run completion scheduled task.
155 $task = new \core\task\
completion_regular_task();
156 $this->expectOutputRegex("/Marking complete/");
158 // Hopefully, some day MDL-33320 will be fixed and all these sleeps
159 // and double cron calls in behat and unit tests will be removed.
163 // The course is supposed to be marked as completed at $timeend.
164 $ccompletion = new \
completion_completion(['userid' => $user->id
, 'course' => $course->id
]);
165 $this->assertEquals($timeend, $ccompletion->timecompleted
);
166 $this->assertTrue($ccompletion->is_complete());
170 * Test that grade timemodified is used when grade criteria is marked as completed.
172 public function test_completion_criteria_grade(): void
{
174 $timegraded = 1610000000;
176 // Create a course and enrol a couple of users.
177 $course = $this->getDataGenerator()->create_course(['enablecompletion' => 1]);
178 $user1 = $this->getDataGenerator()->create_user();
179 $user2 = $this->getDataGenerator()->create_user();
180 $studentrole = $DB->get_record('role', ['shortname' => 'student']);
181 $this->getDataGenerator()->enrol_user($user1->id
, $course->id
, $studentrole->id
);
182 $this->getDataGenerator()->enrol_user($user2->id
, $course->id
, $studentrole->id
);
184 // Set completion criteria.
185 $criteriadata = (object) [
187 'criteria_grade' => 1,
188 'criteria_grade_value' => 66,
190 $criterion = new \
completion_criteria_grade();
191 $criterion->update_config($criteriadata);
193 $coursegradeitem = \grade_item
::fetch_course_item($course->id
);
195 // Grade User 1 with a passing grade.
196 $grade1 = new \
grade_grade();
197 $grade1->itemid
= $coursegradeitem->id
;
198 $grade1->timemodified
= $timegraded;
199 $grade1->userid
= $user1->id
;
200 $grade1->finalgrade
= 80;
203 // Grade User 2 with a non-passing grade.
204 $grade2 = new \
grade_grade();
205 $grade2->itemid
= $coursegradeitem->id
;
206 $grade2->timemodified
= $timegraded;
207 $grade2->userid
= $user2->id
;
208 $grade2->finalgrade
= 40;
211 // Run completion scheduled task.
212 $task = new \core\task\
completion_regular_task();
213 $this->expectOutputRegex("/Marking complete/");
215 // Hopefully, some day MDL-33320 will be fixed and all these sleeps
216 // and double cron calls in behat and unit tests will be removed.
220 // The course for User 1 is supposed to be marked as completed when the user was graded.
221 $ccompletion = new \
completion_completion(['userid' => $user1->id
, 'course' => $course->id
]);
222 $this->assertEquals($timegraded, $ccompletion->timecompleted
);
223 $this->assertTrue($ccompletion->is_complete());
225 // The course for User 2 is supposed to be marked as not completed.
226 $ccompletion = new \
completion_completion(['userid' => $user2->id
, 'course' => $course->id
]);
227 $this->assertFalse($ccompletion->is_complete());