|
| 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 tool_mergeusers; |
| 18 | + |
| 19 | +use advanced_testcase; |
| 20 | +use coding_exception; |
| 21 | +use completion_completion; |
| 22 | +use dml_exception; |
| 23 | +use stdClass; |
| 24 | +use tool_mergeusers\local\user_merger; |
| 25 | + |
| 26 | +defined('MOODLE_INTERNAL') || die(); |
| 27 | + |
| 28 | +global $CFG; |
| 29 | +require_once($CFG->libdir.'/completionlib.php'); |
| 30 | + |
| 31 | +/** |
| 32 | + * Testing reaggregation of courses completion. |
| 33 | + * |
| 34 | + * This test covers the case of positive reaggregation of courses completion. |
| 35 | + * Check assign_test.php for the case when no reaggregation exists. |
| 36 | + * Check them out with --group=tool_mergeusers_reaggregate. |
| 37 | + * |
| 38 | + * @package tool_mergeusers |
| 39 | + * @author Jordi Pujol Ahulló <jordi.pujol@urv.cat> |
| 40 | + * @copyright 2025 Universitat Rovira i Virgili (https://www.urv.cat) |
| 41 | + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
| 42 | + */ |
| 43 | +final class reaggregate_course_completion_test extends advanced_testcase { |
| 44 | + /** |
| 45 | + * Tests reaggregate field is set for courses completion. |
| 46 | + * |
| 47 | + * @group tool_mergeusers |
| 48 | + * @group tool_mergeusers_reaggregate |
| 49 | + * @throws dml_exception |
| 50 | + * @throws coding_exception |
| 51 | + */ |
| 52 | + public function test_reaggregate_field_is_updated(): void { |
| 53 | + // Inspired by lib/tests/completionlib_test.php::test_aggregate_completions(). |
| 54 | + global $DB, $CFG; |
| 55 | + require_once($CFG->dirroot.'/completion/criteria/completion_criteria_activity.php'); |
| 56 | + $this->resetAfterTest(true); |
| 57 | + $time = time(); |
| 58 | + |
| 59 | + $course = $this->getDataGenerator()->create_course(['enablecompletion' => 1]); |
| 60 | + |
| 61 | + $fromstudent = $this->getDataGenerator()->create_user(); |
| 62 | + $tostudent = $this->getDataGenerator()->create_user(); |
| 63 | + $teacher = $this->getDataGenerator()->create_user(); |
| 64 | + $studentrole = $DB->get_record('role', ['shortname' => 'student']); |
| 65 | + $teacherrole = $DB->get_record('role', ['shortname' => 'editingteacher']); |
| 66 | + $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id); |
| 67 | + $this->getDataGenerator()->enrol_user($fromstudent->id, $course->id, $studentrole->id); |
| 68 | + $this->getDataGenerator()->enrol_user($tostudent->id, $course->id, $studentrole->id); |
| 69 | + |
| 70 | + $data = $this->getDataGenerator()->create_module('data', ['course' => $course->id], ['completion' => 1]); |
| 71 | + $cmdata = get_coursemodule_from_id('data', $data->cmid); |
| 72 | + |
| 73 | + // Add activity completion criteria. |
| 74 | + $criteriadata = new stdClass(); |
| 75 | + $criteriadata->id = $course->id; |
| 76 | + $criteriadata->criteria_activity = []; |
| 77 | + // Some activities. |
| 78 | + $criteriadata->criteria_activity[$cmdata->id] = 1; |
| 79 | + $class = 'completion_criteria_activity'; |
| 80 | + $criterion = new $class(); |
| 81 | + $criterion->update_config($criteriadata); |
| 82 | + |
| 83 | + $this->setUser($teacher); |
| 84 | + |
| 85 | + // Mark activity incomplete for one of the students. |
| 86 | + $cm = get_coursemodule_from_instance('data', $data->id); |
| 87 | + $completioncriteria = $DB->get_record('course_completion_criteria', []); |
| 88 | + $cmcompletionrecord = (object)[ |
| 89 | + 'coursemoduleid' => $cm->id, |
| 90 | + 'userid' => $fromstudent->id, |
| 91 | + 'completionstate' => 1, |
| 92 | + 'viewed' => 0, |
| 93 | + 'overrideby' => null, |
| 94 | + 'timemodified' => 0, |
| 95 | + ]; |
| 96 | + |
| 97 | + $usercompletion = (object)[ |
| 98 | + 'criteriaid' => $completioncriteria->id, |
| 99 | + 'userid' => $fromstudent->id, |
| 100 | + 'timecompleted' => 0, |
| 101 | + ]; |
| 102 | + |
| 103 | + $cc = array( |
| 104 | + 'course' => $course->id, |
| 105 | + 'userid' => $fromstudent->id |
| 106 | + ); |
| 107 | + $ccompletion = new completion_completion($cc); |
| 108 | + $completion = $ccompletion->mark_inprogress($time); |
| 109 | + |
| 110 | + $DB->insert_records('course_modules_completion', [$cmcompletionrecord]); |
| 111 | + $DB->insert_records('course_completion_crit_compl', [$usercompletion]); |
| 112 | + |
| 113 | + // MDL-33320: for instant completions we need aggregate to work in a single run. |
| 114 | + $DB->set_field('course_completions', 'reaggregate', $time - 2); |
| 115 | + |
| 116 | + $result = $DB->get_record('course_completions', ['userid' => $fromstudent->id]); |
| 117 | + $this->assertIsObject($result); |
| 118 | + $result = $DB->get_record('course_completions', ['userid' => $tostudent->id]); |
| 119 | + $this->assertFalse($result); |
| 120 | + aggregate_completions(0); |
| 121 | + |
| 122 | + |
| 123 | + $mut = new user_merger(); |
| 124 | + // This merge already invokes the callback for reaggregate course completion. |
| 125 | + [$success, $logs, $logid] = $mut->merge($tostudent->id, $fromstudent->id); |
| 126 | + $this->assertTrue($success); |
| 127 | + // Check that there is reaggregation of course completion. |
| 128 | + $found = ''; |
| 129 | + foreach ($logs as $logline) { |
| 130 | + $found = strstr($logline, 'Course completion reaggregated for user'); |
| 131 | + if (!empty($found)) { |
| 132 | + break; |
| 133 | + } |
| 134 | + } |
| 135 | + $this->assertNotEmpty($found); |
| 136 | + |
| 137 | + $this->assertFalse($DB->get_record('course_completions', ['userid' => $fromstudent->id])); |
| 138 | + $record = $DB->get_record('course_completions', ['userid' => $tostudent->id]); |
| 139 | + $this->assertIsObject($record); |
| 140 | + $this->assertEquals(0, $record->reaggregate); |
| 141 | + } |
| 142 | +} |
0 commit comments