Differences Between: [Versions 401 and 402] [Versions 402 and 403]
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 declare(strict_types=1); 18 19 namespace core_course\reportbuilder\datasource; 20 21 use completion_completion; 22 use core_reportbuilder\local\filters\boolean_select; 23 use core_reportbuilder\local\filters\date; 24 use core_reportbuilder\local\filters\select; 25 use core_reportbuilder_generator; 26 use core_reportbuilder_testcase; 27 use grade_item; 28 29 defined('MOODLE_INTERNAL') || die(); 30 31 global $CFG; 32 require_once("{$CFG->dirroot}/reportbuilder/tests/helpers.php"); 33 require_once("{$CFG->libdir}/gradelib.php"); 34 35 /** 36 * Course participants datasource tests 37 * 38 * @package core_course 39 * @covers \core_course\reportbuilder\datasource\participants 40 * @covers \core_course\reportbuilder\local\formatters\completion 41 * @covers \core_course\reportbuilder\local\formatters\enrolment 42 * @copyright 2022 David Matamoros <davidmc@moodle.com> 43 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 44 */ 45 class participants_test extends core_reportbuilder_testcase { 46 47 /** 48 * Test participants datasource 49 */ 50 public function test_participants_datasource(): void { 51 global $DB; 52 $this->resetAfterTest(); 53 54 $timestart = time() - DAYSECS; 55 $timeend = $timestart + 3 * DAYSECS; 56 $timecompleted = $timestart + 2 * DAYSECS; 57 $timelastaccess = time() + 4 * DAYSECS; 58 59 $category = $this->getDataGenerator()->create_category(['name' => 'Music']); 60 $course = $this->getDataGenerator()->create_course([ 61 'category' => $category->id, 62 'fullname' => 'All about Lionel at the work place', 63 'enablecompletion' => true, 64 'startdate' => $timestart, 65 'enddate' => $timeend, 66 ]); 67 68 $user1 = self::getDataGenerator()->create_user(); 69 $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student', 70 'manual', $timestart, $timeend, ENROL_USER_ACTIVE); 71 72 // Add them to a group. 73 $group = self::getDataGenerator()->create_group(['courseid' => $course->id]); 74 self::getDataGenerator()->create_group_member(['groupid' => $group->id, 'userid' => $user1->id]); 75 76 // Mark course as completed for the user. 77 $ccompletion = new completion_completion(array('course' => $course->id, 'userid' => $user1->id)); 78 $ccompletion->mark_enrolled($timestart); 79 $ccompletion->mark_complete($timecompleted); 80 81 // Update final grade for the user. 82 $courseitem = grade_item::fetch_course_item($course->id); 83 $courseitem->update_final_grade($user1->id, 42.5); 84 85 // Set some last access value for the user in the course. 86 $DB->insert_record('user_lastaccess', 87 ['userid' => $user1->id, 'courseid' => $course->id, 'timeaccess' => $timelastaccess]); 88 89 /** @var core_reportbuilder_generator $generator */ 90 $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); 91 $report = $generator->create_report(['name' => 'Courses', 'source' => participants::class, 'default' => false]); 92 93 $generator->create_column(['reportid' => $report->get('id'), 94 'uniqueidentifier' => 'course:fullname']); 95 $generator->create_column(['reportid' => $report->get('id'), 96 'uniqueidentifier' => 'course_category:name']); 97 $generator->create_column(['reportid' => $report->get('id'), 98 'uniqueidentifier' => 'user:fullname']); 99 // Order by enrolment method. 100 $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'enrolment:method', 'sortenabled' => 1]); 101 $generator->create_column(['reportid' => $report->get('id'), 102 'uniqueidentifier' => 'group:name']); 103 $generator->create_column(['reportid' => $report->get('id'), 104 'uniqueidentifier' => 'completion:completed']); 105 $generator->create_column(['reportid' => $report->get('id'), 106 'uniqueidentifier' => 'access:timeaccess']); 107 $generator->create_column(['reportid' => $report->get('id'), 108 'uniqueidentifier' => 'completion:progresspercent']); 109 $generator->create_column(['reportid' => $report->get('id'), 110 'uniqueidentifier' => 'completion:timeenrolled']); 111 $generator->create_column(['reportid' => $report->get('id'), 112 'uniqueidentifier' => 'completion:timestarted']); 113 $generator->create_column(['reportid' => $report->get('id'), 114 'uniqueidentifier' => 'completion:timecompleted']); 115 $generator->create_column(['reportid' => $report->get('id'), 116 'uniqueidentifier' => 'completion:reaggregate']); 117 $generator->create_column(['reportid' => $report->get('id'), 118 'uniqueidentifier' => 'completion:dayscourse']); 119 $generator->create_column(['reportid' => $report->get('id'), 120 'uniqueidentifier' => 'completion:daysuntilcompletion']); 121 $generator->create_column(['reportid' => $report->get('id'), 122 'uniqueidentifier' => 'completion:grade']); 123 124 // Add filter to the report. 125 $generator->create_filter(['reportid' => $report->get('id'), 'uniqueidentifier' => 'enrolment:method']); 126 127 $content = $this->get_custom_report_content($report->get('id')); 128 129 // It should get 3 records (manual enrolment, self and guest). 130 $this->assertCount(3, $content); 131 132 // Filter by Manual enrolment method. 133 $content = $this->get_custom_report_content($report->get('id'), 30, [ 134 'enrolment:method_operator' => select::EQUAL_TO, 135 'enrolment:method_value' => 'manual', 136 ]); 137 138 $this->assertCount(1, $content); 139 140 $this->assertEquals([ 141 'All about Lionel at the work place', // Course name. 142 'Music', // Course category name. 143 fullname($user1), // User fullname. 144 'Manual enrolments', // Enrolment method. 145 $group->name, // Group name. 146 'Yes', // Course completed. 147 userdate($timelastaccess), // Time last access. 148 '100.0%', // Progress percentage. 149 userdate($timestart), // Time enrolled. 150 '', // Time started. 151 userdate($timecompleted), // Time completed. 152 '', // Reagreggate. 153 '2', // Days taking course. 154 '2', // Days until completion. 155 '42.50', // Grade. 156 ], array_values($content[0])); 157 } 158 159 /** 160 * Data provider for {@see test_report_filters} 161 * 162 * @return array 163 */ 164 public function filters_data_provider(): array { 165 return [ 166 [ 167 'enrolment:status', 168 [ 169 'enrolment:status_operator' => select::EQUAL_TO, 170 'enrolment:status_value' => 1, 171 ], 172 'Luna' 173 ], 174 [ 175 'enrolment:timecreated', 176 [ 177 'enrolment:timecreated_operator' => date::DATE_CURRENT, 178 'enrolment:timecreated_unit' => date::DATE_UNIT_DAY, 179 ], 180 'Kira' 181 ], 182 [ 183 'enrolment:timestarted', 184 [ 185 'enrolment:timestarted_operator' => date::DATE_CURRENT, 186 'enrolment:timecreated_unit' => date::DATE_UNIT_DAY, 187 ], 188 'Luna' 189 ], 190 [ 191 'enrolment:timeended', 192 [ 193 'enrolment:timeended_operator' => date::DATE_CURRENT, 194 'enrolment:timeended_unit' => date::DATE_UNIT_DAY, 195 ], 196 'Luna' 197 ], 198 [ 199 'completion:completed', 200 [ 201 'completion:completed_operator' => boolean_select::CHECKED, 202 'completion:completed_unit' => 1, 203 ], 204 'Lionel' 205 ], 206 [ 207 'completion:timecompleted', 208 [ 209 'completion:timecompleted_operator' => date::DATE_NOT_EMPTY, 210 ], 211 'Lionel' 212 ], 213 [ 214 'completion:timeenrolled', 215 [ 216 'completion:timeenrolled_operator' => date::DATE_NOT_EMPTY, 217 ], 218 'Lionel' 219 ], 220 [ 221 'completion:timestarted', 222 [ 223 'completion:timestarted_operator' => date::DATE_NOT_EMPTY, 224 ], 225 'Lionel' 226 ], 227 [ 228 'completion:reaggregate', 229 [ 230 'completion:reaggregate_operator' => date::DATE_NOT_EMPTY, 231 ], 232 'Lionel' 233 ], 234 ]; 235 } 236 237 /** 238 * Test getting filter SQL 239 * 240 * @param string $filter 241 * @param array $filtervalues 242 * @param string $expected 243 * 244 * @dataProvider filters_data_provider 245 */ 246 public function test_report_filters(string $filter, array $filtervalues, string $expected): void { 247 global $DB; 248 $this->resetAfterTest(); 249 250 $timestart = time() - DAYSECS; 251 $timeend = $timestart + 3 * DAYSECS; 252 $timecompleted = $timestart + 2 * DAYSECS; 253 $timelastaccess = time() + 4 * DAYSECS; 254 255 $category = $this->getDataGenerator()->create_category(['name' => 'Music']); 256 $course = $this->getDataGenerator()->create_course([ 257 'category' => $category->id, 258 'fullname' => 'All about Lionel at the work place', 259 'enablecompletion' => true, 260 'startdate' => $timestart, 261 'enddate' => $timeend, 262 ]); 263 264 $user1 = self::getDataGenerator()->create_user(['firstname' => 'Lionel']); 265 $user2 = self::getDataGenerator()->create_user(['firstname' => 'Kira']); 266 $user3 = self::getDataGenerator()->create_user(['firstname' => 'Luna']); 267 268 $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student', 269 'manual', $timestart - 8 * DAYSECS, $timeend, ENROL_USER_ACTIVE); 270 $this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student', 271 'manual', $timestart, $timeend, ENROL_USER_ACTIVE); 272 $this->getDataGenerator()->enrol_user($user3->id, $course->id, 'student', 273 'manual', time(), time(), ENROL_USER_SUSPENDED); 274 275 // Mark course as completed for the user. 276 $ccompletion = new completion_completion(array('course' => $course->id, 'userid' => $user1->id)); 277 $ccompletion->mark_enrolled($timestart); 278 $ccompletion->mark_inprogress($timestart); 279 $ccompletion->mark_complete($timecompleted); 280 281 // Set some last access value for the user in the course. 282 $DB->insert_record('user_lastaccess', 283 ['userid' => $user1->id, 'courseid' => $course->id, 'timeaccess' => $timelastaccess]); 284 285 /** @var core_reportbuilder_generator $generator */ 286 $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); 287 $report = $generator->create_report(['name' => 'Courses', 'source' => participants::class, 'default' => false]); 288 289 // Add user firstname column to the report. 290 $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:firstname']); 291 292 $DB->set_field('user_enrolments', 'timecreated', 0, ['userid' => $user1->id]); 293 $DB->set_field('user_enrolments', 'timecreated', 0, ['userid' => $user3->id]); 294 295 // Add filters to the report. 296 $generator->create_filter(['reportid' => $report->get('id'), 'uniqueidentifier' => 'enrolment:method']); 297 $generator->create_filter(['reportid' => $report->get('id'), 'uniqueidentifier' => $filter]); 298 299 // Apply filters. 300 $filtermanual = ['enrolment:method_operator' => select::EQUAL_TO, 'enrolment:method_value' => 'manual']; 301 $content = $this->get_custom_report_content($report->get('id'), 30, $filtermanual + $filtervalues); 302 303 $this->assertCount(1, $content); 304 $this->assertEquals($expected, $content[0]['c0_firstname']); 305 } 306 307 /** 308 * Stress test datasource 309 * 310 * In order to execute this test PHPUNIT_LONGTEST should be defined as true in phpunit.xml or directly in config.php 311 */ 312 public function test_stress_datasource(): void { 313 if (!PHPUNIT_LONGTEST) { 314 $this->markTestSkipped('PHPUNIT_LONGTEST is not defined'); 315 } 316 317 $this->resetAfterTest(); 318 319 $course = $this->getDataGenerator()->create_course(); 320 $this->getDataGenerator()->create_and_enrol($course); 321 322 $this->datasource_stress_test_columns(participants::class); 323 $this->datasource_stress_test_columns_aggregation(participants::class); 324 $this->datasource_stress_test_conditions(participants::class, 'course:idnumber'); 325 } 326 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body