See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401]
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. 13 // 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/>. 16 17 namespace core_completion; 18 19 /** 20 * Test completion API. 21 * 22 * @package core_completion 23 * @category test 24 * @copyright 2017 Mark Nelson <markn@moodle.com> 25 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 26 */ 27 class api_test extends \advanced_testcase { 28 29 /** 30 * Test setup. 31 */ 32 public function setUp(): void { 33 $this->resetAfterTest(); 34 } 35 36 public function test_update_completion_date_event() { 37 global $CFG, $DB; 38 39 $this->setAdminUser(); 40 41 // Create a course. 42 $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1)); 43 44 // Create an assign activity. 45 $time = time(); 46 $assign = $this->getDataGenerator()->create_module('assign', array('course' => $course->id)); 47 48 // Create the completion event. 49 $CFG->enablecompletion = true; 50 \core_completion\api::update_completion_date_event($assign->cmid, 'assign', $assign, $time); 51 52 // Check that there is now an event in the database. 53 $events = $DB->get_records('event'); 54 $this->assertCount(1, $events); 55 56 // Get the event. 57 $event = reset($events); 58 59 // Confirm the event is correct. 60 $this->assertEquals('assign', $event->modulename); 61 $this->assertEquals($assign->id, $event->instance); 62 $this->assertEquals(CALENDAR_EVENT_TYPE_ACTION, $event->type); 63 $this->assertEquals(\core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED, $event->eventtype); 64 $this->assertEquals($time, $event->timestart); 65 $this->assertEquals($time, $event->timesort); 66 67 require_once($CFG->dirroot . '/course/lib.php'); 68 // Delete the module. 69 course_delete_module($assign->cmid); 70 71 // Check we don't get a failure when called on a deleted module. 72 \core_completion\api::update_completion_date_event($assign->cmid, 'assign', null, $time); 73 } 74 75 public function test_update_completion_date_event_update() { 76 global $CFG, $DB; 77 78 $this->setAdminUser(); 79 80 // Create a course. 81 $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1)); 82 83 // Create an assign activity. 84 $time = time(); 85 $assign = $this->getDataGenerator()->create_module('assign', array('course' => $course->id)); 86 87 // Create the event. 88 $CFG->enablecompletion = true; 89 \core_completion\api::update_completion_date_event($assign->cmid, 'assign', $assign, $time); 90 91 // Call it again, but this time with a different time. 92 \core_completion\api::update_completion_date_event($assign->cmid, 'assign', $assign, $time + DAYSECS); 93 94 // Check that there is still only one event in the database. 95 $events = $DB->get_records('event'); 96 $this->assertCount(1, $events); 97 98 // Get the event. 99 $event = reset($events); 100 101 // Confirm that the event has been updated. 102 $this->assertEquals('assign', $event->modulename); 103 $this->assertEquals($assign->id, $event->instance); 104 $this->assertEquals(CALENDAR_EVENT_TYPE_ACTION, $event->type); 105 $this->assertEquals(\core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED, $event->eventtype); 106 $this->assertEquals($time + DAYSECS, $event->timestart); 107 $this->assertEquals($time + DAYSECS, $event->timesort); 108 } 109 110 public function test_update_completion_date_event_delete() { 111 global $CFG, $DB; 112 113 $this->setAdminUser(); 114 115 // Create a course. 116 $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1)); 117 118 // Create an assign activity. 119 $time = time(); 120 $assign = $this->getDataGenerator()->create_module('assign', array('course' => $course->id)); 121 122 // Create the event. 123 $CFG->enablecompletion = true; 124 \core_completion\api::update_completion_date_event($assign->cmid, 'assign', $assign, $time); 125 126 // Call it again, but the time specified as null. 127 \core_completion\api::update_completion_date_event($assign->cmid, 'assign', $assign, null); 128 129 // Check that there is no event in the database. 130 $this->assertEquals(0, $DB->count_records('event')); 131 } 132 133 public function test_update_completion_date_event_completion_disabled() { 134 global $CFG, $DB; 135 136 $this->setAdminUser(); 137 138 // Create a course. 139 $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1)); 140 141 // Create an assign activity. 142 $time = time(); 143 $assign = $this->getDataGenerator()->create_module('assign', array('course' => $course->id)); 144 145 // Try and create the completion event with completion disabled. 146 $CFG->enablecompletion = false; 147 \core_completion\api::update_completion_date_event($assign->cmid, 'assign', $assign, $time); 148 149 // Check that there is no event in the database. 150 $this->assertEquals(0, $DB->count_records('event')); 151 } 152 153 public function test_update_completion_date_event_update_completion_disabled() { 154 global $CFG, $DB; 155 156 $this->setAdminUser(); 157 158 // Create a course. 159 $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1)); 160 161 // Create an assign activity. 162 $time = time(); 163 $assign = $this->getDataGenerator()->create_module('assign', array('course' => $course->id)); 164 165 // Create the completion event. 166 $CFG->enablecompletion = true; 167 \core_completion\api::update_completion_date_event($assign->cmid, 'assign', $assign, $time); 168 169 // Disable completion. 170 $CFG->enablecompletion = false; 171 172 // Try and update the completion date. 173 \core_completion\api::update_completion_date_event($assign->cmid, 'assign', $assign, $time + DAYSECS); 174 175 // Check that there is an event in the database. 176 $events = $DB->get_records('event'); 177 $this->assertCount(1, $events); 178 179 // Get the event. 180 $event = reset($events); 181 182 // Confirm the event has not changed. 183 $this->assertEquals('assign', $event->modulename); 184 $this->assertEquals($assign->id, $event->instance); 185 $this->assertEquals(CALENDAR_EVENT_TYPE_ACTION, $event->type); 186 $this->assertEquals(\core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED, $event->eventtype); 187 $this->assertEquals($time, $event->timestart); 188 $this->assertEquals($time, $event->timesort); 189 } 190 191 public function test_update_completion_date_event_delete_completion_disabled() { 192 global $CFG, $DB; 193 194 $this->setAdminUser(); 195 196 // Create a course. 197 $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1)); 198 199 // Create an assign activity. 200 $time = time(); 201 $assign = $this->getDataGenerator()->create_module('assign', array('course' => $course->id)); 202 203 // Create the completion event. 204 $CFG->enablecompletion = true; 205 \core_completion\api::update_completion_date_event($assign->cmid, 'assign', $assign, $time); 206 207 // Disable completion. 208 $CFG->enablecompletion = false; 209 210 // Should still be able to delete completion events even when completion is disabled. 211 \core_completion\api::update_completion_date_event($assign->cmid, 'assign', $assign, null); 212 213 // Check that there is now no event in the database. 214 $this->assertEquals(0, $DB->count_records('event')); 215 } 216 217 /** 218 * Test for mark_course_completions_activity_criteria(). 219 */ 220 public function test_mark_course_completions_activity_criteria() { 221 global $DB, $CFG; 222 require_once($CFG->dirroot.'/completion/criteria/completion_criteria_activity.php'); 223 $this->resetAfterTest(true); 224 225 $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1)); 226 $student1 = $this->getDataGenerator()->create_user(); 227 $student2 = $this->getDataGenerator()->create_user(); 228 229 $teacher = $this->getDataGenerator()->create_user(); 230 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 231 $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher')); 232 233 $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id); 234 $this->getDataGenerator()->enrol_user($student1->id, $course->id, $studentrole->id); 235 $this->getDataGenerator()->enrol_user($student2->id, $course->id, $studentrole->id); 236 237 $data = $this->getDataGenerator()->create_module('data', array('course' => $course->id), 238 array('completion' => 1)); 239 $cmdata = get_coursemodule_from_id('data', $data->cmid); 240 $cm = get_coursemodule_from_instance('data', $data->id); 241 $c = new \completion_info($course); 242 243 // Add activity completion criteria. 244 $criteriadata = new \stdClass(); 245 $criteriadata->id = $course->id; 246 $criteriadata->criteria_activity = array(); 247 // Some activities. 248 $criteriadata->criteria_activity[$cmdata->id] = 1; 249 $criterion = new \completion_criteria_activity(); 250 $criterion->update_config($criteriadata); 251 252 $this->setUser($teacher); 253 254 // Mark activity complete for both users. 255 $completion = new \stdClass(); 256 $completion->coursemoduleid = $cm->id; 257 $completion->completionstate = COMPLETION_COMPLETE; 258 $completion->timemodified = time(); 259 $completion->viewed = COMPLETION_NOT_VIEWED; 260 $completion->overrideby = null; 261 262 $completion->id = 0; 263 $completion->userid = $student1->id; 264 $c->internal_set_data($cm, $completion, true); 265 266 $completion->id = 0; 267 $completion->userid = $student2->id; 268 $c->internal_set_data($cm, $completion, true); 269 270 // Run instant course completions for student1. Only student1 will be marked as completed a course. 271 $userdata = ['userid' => $student1->id, 'courseid' => $course->id]; 272 $actual = $DB->get_records('course_completions'); 273 $this->assertEmpty($actual); 274 275 $coursecompletionid = \core_completion\api::mark_course_completions_activity_criteria($userdata); 276 277 $actual = $DB->get_records('course_completions'); 278 $this->assertEquals(reset($actual)->id, $coursecompletionid); 279 $this->assertEquals(1, count($actual)); 280 $this->assertEquals($student1->id, reset($actual)->userid); 281 282 // Run course completions cron. Both students will be marked as completed a course. 283 $coursecompletionid = \core_completion\api::mark_course_completions_activity_criteria(); 284 $this->assertEquals(0, $coursecompletionid); 285 $actual = $DB->get_records('course_completions'); 286 $students = [$student1->id, $student2->id]; 287 $this->assertEquals(2, count($actual)); 288 $this->assertContains(reset($actual)->userid, $students); 289 $this->assertContains(end($actual)->userid, $students); 290 } 291 292 /** 293 * Test for mark_course_completions_activity_criteria() with different completionpassgrade settings. 294 * @covers ::mark_course_completions_activity_criteria 295 */ 296 public function test_mark_course_completions_activity_criteria_completion_states() { 297 global $DB, $CFG; 298 require_once($CFG->dirroot . '/completion/criteria/completion_criteria_activity.php'); 299 $this->resetAfterTest(true); 300 301 $courses[] = $this->getDataGenerator()->create_course(['shortname' => 'completionpassgradenotset', 302 'enablecompletion' => 1]); 303 $courses[] = $this->getDataGenerator()->create_course(['shortname' => 'completionpassgradeset', 304 'enablecompletion' => 1]); 305 306 $student1 = $this->getDataGenerator()->create_user(); 307 $student2 = $this->getDataGenerator()->create_user(); 308 309 $teacher = $this->getDataGenerator()->create_user(); 310 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 311 $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher')); 312 313 foreach ($courses as $course) { 314 $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id); 315 $this->getDataGenerator()->enrol_user($student1->id, $course->id, $studentrole->id); 316 $this->getDataGenerator()->enrol_user($student2->id, $course->id, $studentrole->id); 317 318 $completioncriteria = [ 319 'completionusegrade' => 1, 320 'gradepass' => 50 321 ]; 322 323 if ($course->shortname == 'completionpassgradeset') { 324 $completioncriteria['completionpassgrade'] = 1; 325 } 326 327 /** @var \mod_assign_generator $assigngenerator */ 328 $assigngenerator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); 329 $assign = $assigngenerator->create_instance([ 330 'course' => $course->id, 331 'completion' => COMPLETION_ENABLED, 332 ] + $completioncriteria); 333 334 $cmassing = get_coursemodule_from_id('assign', $assign->cmid); 335 $cm = get_coursemodule_from_instance('assign', $assign->id); 336 $c = new \completion_info($course); 337 338 // Add activity completion criteria. 339 $criteriadata = new \stdClass(); 340 $criteriadata->id = $course->id; 341 $criteriadata->criteria_activity = array(); 342 // Some activities. 343 $criteriadata->criteria_activity[$cmassing->id] = 1; 344 $criterion = new \completion_criteria_activity(); 345 $criterion->update_config($criteriadata); 346 347 $this->setUser($teacher); 348 349 // Mark user completions. 350 $completion = new \stdClass(); 351 $completion->coursemoduleid = $cm->id; 352 $completion->timemodified = time(); 353 $completion->viewed = COMPLETION_NOT_VIEWED; 354 $completion->overrideby = null; 355 356 // Student1 achieved passgrade. 357 $completion->id = 0; 358 $completion->completionstate = COMPLETION_COMPLETE_PASS; 359 $completion->userid = $student1->id; 360 $c->internal_set_data($cm, $completion, true); 361 362 // Student2 has not achieved passgrade. 363 $completion->id = 0; 364 $completion->completionstate = COMPLETION_COMPLETE_FAIL; 365 $completion->userid = $student2->id; 366 $c->internal_set_data($cm, $completion, true); 367 368 $actual = $DB->get_records('course_completions', ['course' => $course->id]); 369 $this->assertEmpty($actual); 370 371 // Run course completions cron. 372 $coursecompletionid = \core_completion\api::mark_course_completions_activity_criteria(); 373 $this->assertEquals(0, $coursecompletionid); 374 $actual = $DB->get_records('course_completions', ['course' => $course->id]); 375 376 if ($course->shortname == 'completionpassgradeset') { 377 // Only student1 has completed a course. 378 $this->assertEquals(1, count($actual)); 379 $this->assertEquals($student1->id, reset($actual)->userid); 380 } else { 381 // Both students completed a course. 382 $students = [$student1->id, $student2->id]; 383 $this->assertEquals(2, count($actual)); 384 $this->assertContains(reset($actual)->userid, $students); 385 $this->assertContains(end($actual)->userid, $students); 386 } 387 } 388 } 389 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body