Differences Between: [Versions 400 and 402] [Versions 401 and 402]
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 18 namespace mod_h5pactivity; 19 20 use advanced_testcase; 21 use mod_h5pactivity\local\manager; 22 23 /** 24 * Unit tests for (some of) mod/h5pactivity/lib.php. 25 * 26 * @package mod_h5pactivity 27 * @copyright 2021 Ilya Tregubov <ilya@moodle.com> 28 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 29 */ 30 class lib_test extends advanced_testcase { 31 32 /** 33 * Load required test libraries 34 */ 35 public static function setUpBeforeClass(): void { 36 global $CFG; 37 require_once("{$CFG->dirroot}/mod/h5pactivity/lib.php"); 38 } 39 40 /** 41 * Test that h5pactivity_delete_instance removes data. 42 * 43 * @covers ::h5pactivity_delete_instance 44 */ 45 public function test_h5pactivity_delete_instance() { 46 global $DB; 47 $this->resetAfterTest(); 48 $this->setAdminUser(); 49 50 $course = $this->getDataGenerator()->create_course(); 51 $user = $this->getDataGenerator()->create_and_enrol($course, 'student'); 52 $activity = $this->getDataGenerator()->create_module('h5pactivity', ['course' => $course]); 53 $this->setUser($user); 54 55 /** @var \mod_h5pactivity_generator $generator */ 56 $generator = $this->getDataGenerator()->get_plugin_generator('mod_h5pactivity'); 57 58 /** @var \core_h5p_generator $h5pgenerator */ 59 $h5pgenerator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); 60 61 // Add an attempt to the H5P activity. 62 $attemptinfo = [ 63 'userid' => $user->id, 64 'h5pactivityid' => $activity->id, 65 'attempt' => 1, 66 'interactiontype' => 'compound', 67 'rawscore' => 2, 68 'maxscore' => 2, 69 'duration' => 1, 70 'completion' => 1, 71 'success' => 0, 72 ]; 73 $generator->create_attempt($attemptinfo); 74 75 // Add also a xAPI state to the H5P activity. 76 $filerecord = [ 77 'contextid' => \context_module::instance($activity->cmid)->id, 78 'component' => 'mod_h5pactivity', 79 'filearea' => 'package', 80 'itemid' => 0, 81 'filepath' => '/', 82 'filepath' => '/', 83 'filename' => 'dummy.h5p', 84 'addxapistate' => true, 85 ]; 86 $h5pgenerator->generate_h5p_data(false, $filerecord); 87 88 // Check the H5P activity exists and the attempt has been created. 89 $this->assertNotEmpty($DB->get_record('h5pactivity', ['id' => $activity->id])); 90 $this->assertEquals(2, $DB->count_records('grade_items')); 91 $this->assertEquals(2, $DB->count_records('grade_grades')); 92 $this->assertEquals(1, $DB->count_records('xapi_states')); 93 94 // Check nothing happens when given activity id doesn't exist. 95 h5pactivity_delete_instance($activity->id + 1); 96 $this->assertNotEmpty($DB->get_record('h5pactivity', ['id' => $activity->id])); 97 $this->assertEquals(2, $DB->count_records('grade_items')); 98 $this->assertEquals(2, $DB->count_records('grade_grades')); 99 $this->assertEquals(1, $DB->count_records('xapi_states')); 100 101 // Check the H5P instance and its associated data is removed. 102 h5pactivity_delete_instance($activity->id); 103 $this->assertEmpty($DB->get_record('h5pactivity', ['id' => $activity->id])); 104 $this->assertEquals(1, $DB->count_records('grade_items')); 105 $this->assertEquals(1, $DB->count_records('grade_grades')); 106 $this->assertEquals(0, $DB->count_records('xapi_states')); 107 } 108 109 /** 110 * Test that assign_print_recent_activity shows ungraded submitted assignments. 111 * 112 * @covers ::h5pactivity_print_recent_activity 113 */ 114 public function test_print_recent_activity() { 115 $this->resetAfterTest(); 116 $this->setAdminUser(); 117 118 $course = $this->getDataGenerator()->create_course(); 119 $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); 120 $activity = $this->getDataGenerator()->create_module('h5pactivity', 121 ['course' => $course, 'enabletracking' => 1, 'grademethod' => manager::GRADEHIGHESTATTEMPT]); 122 123 $generator = $this->getDataGenerator()->get_plugin_generator('mod_h5pactivity'); 124 125 $manager = manager::create_from_instance($activity); 126 $cm = $manager->get_coursemodule(); 127 128 $user = $student; 129 $params = ['cmid' => $cm->id, 'userid' => $user->id]; 130 $generator->create_content($activity, $params); 131 $this->setUser($student); 132 $this->expectOutputRegex('/submitted:/'); 133 h5pactivity_print_recent_activity($course, true, time() - 3600); 134 } 135 136 /** 137 * Test that h5pactivity_print_recent_activity does not display any warnings when a custom fullname has been configured. 138 * 139 * @covers ::h5pactivity_print_recent_activity 140 */ 141 public function test_print_recent_activity_fullname() { 142 $this->resetAfterTest(); 143 $this->setAdminUser(); 144 145 $course = $this->getDataGenerator()->create_course(); 146 $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'); 147 $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); 148 $activity = $this->getDataGenerator()->create_module('h5pactivity', 149 ['course' => $course, 'enabletracking' => 1, 'grademethod' => manager::GRADEHIGHESTATTEMPT]); 150 151 $generator = $this->getDataGenerator()->get_plugin_generator('mod_h5pactivity'); 152 153 $manager = manager::create_from_instance($activity); 154 $cm = $manager->get_coursemodule(); 155 156 $user = $student; 157 $params = ['cmid' => $cm->id, 'userid' => $user->id]; 158 $generator->create_content($activity, $params); 159 160 $this->setUser($teacher); 161 162 $this->expectOutputRegex('/submitted:/'); 163 set_config('fullnamedisplay', 'firstname, lastnamephonetic'); 164 h5pactivity_print_recent_activity($course, false, time() - 3600); 165 } 166 167 /** 168 * Test that h5pactivity_get_recent_mod_activity fetches the h5pactivity correctly. 169 * 170 * @covers ::h5pactivity_get_recent_mod_activity 171 */ 172 public function test_h5pactivity_get_recent_mod_activity() { 173 $this->resetAfterTest(); 174 $this->setAdminUser(); 175 176 $course = $this->getDataGenerator()->create_course(); 177 $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'); 178 $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); 179 $activity = $this->getDataGenerator()->create_module('h5pactivity', 180 ['course' => $course, 'enabletracking' => 1, 'grademethod' => manager::GRADEHIGHESTATTEMPT]); 181 182 $generator = $this->getDataGenerator()->get_plugin_generator('mod_h5pactivity'); 183 184 $manager = manager::create_from_instance($activity); 185 $cm = $manager->get_coursemodule(); 186 187 $user = $student; 188 $params = ['cmid' => $cm->id, 'userid' => $user->id]; 189 $generator->create_content($activity, $params); 190 191 $index = 1; 192 $activities = [ 193 $index => (object) [ 194 'type' => 'h5pactivity', 195 'cmid' => $cm->id, 196 ], 197 ]; 198 199 $this->setUser($teacher); 200 h5pactivity_get_recent_mod_activity($activities, $index, time() - HOURSECS, $course->id, $cm->id); 201 202 $activity = $activities[1]; 203 $this->assertEquals("h5pactivity", $activity->type); 204 $this->assertEquals($student->id, $activity->user->id); 205 } 206 207 /** 208 * Test that h5pactivity_get_recent_mod_activity fetches activity correctly. 209 * 210 * @covers ::h5pactivity_fetch_recent_activity 211 */ 212 public function test_h5pactivity_fetch_recent_activity() { 213 global $DB; 214 215 $this->resetAfterTest(); 216 $this->setAdminUser(); 217 218 $course = $this->getDataGenerator()->create_course(); 219 220 // Create users and groups. 221 $students = array(); 222 $groups = array(); 223 $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'); 224 225 for ($i = 1; $i < 6; $i++) { 226 $students[$i] = $this->getDataGenerator()->create_and_enrol($course, 'student'); 227 $groups[$i] = $this->getDataGenerator()->create_group(array('courseid' => $course->id)); 228 } 229 $groups[$i] = $this->getDataGenerator()->create_group(array('courseid' => $course->id, 'participation' => 0)); 230 231 // Update the course set the groupmode SEPARATEGROUPS and forced. 232 update_course((object)array('id' => $course->id, 'groupmode' => SEPARATEGROUPS, 'groupmodeforce' => true)); 233 234 // Student 1 is in groups 1 and 3. 235 groups_add_member($groups[1], $students[1]); 236 groups_add_member($groups[3], $students[1]); 237 238 // Student 2 is in groups 1 and 2. 239 groups_add_member($groups[1], $students[2]); 240 groups_add_member($groups[2], $students[2]); 241 242 // Student 3 is only in group 3. 243 groups_add_member($groups[3], $students[3]); 244 245 // Student 4 is only in group 5 (non-participation). 246 groups_add_member($groups[6], $students[4]); 247 248 // Student 5 is not in any groups. 249 250 // Grader is only in group 3. 251 groups_add_member($groups[3], $teacher); 252 253 $timestart = time() - 1; 254 // Create h5pactivity. 255 $activity = $this->getDataGenerator()->create_module('h5pactivity', 256 ['course' => $course->id, 'enabletracking' => 1, 'grademethod' => manager::GRADEHIGHESTATTEMPT, 257 'groupmode' => SEPARATEGROUPS]); 258 259 $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher')); 260 $cmcontext = \context_module::instance($activity->cmid); 261 assign_capability('moodle/site:accessallgroups', CAP_PROHIBIT, $teacherrole->id, $cmcontext, true); 262 263 $manager = manager::create_from_instance($activity); 264 $cm = $manager->get_coursemodule(); 265 266 // Create attempts. 267 $generator = $this->getDataGenerator()->get_plugin_generator('mod_h5pactivity'); 268 foreach ($students as $student) { 269 $params = ['cmid' => $cm->id, 'userid' => $student->id]; 270 $generator->create_content($activity, $params); 271 } 272 273 // Get all attempts. 274 $dbparams = [$timestart, $course->id, 'h5pactivity']; 275 $userfieldsapi = \core_user\fields::for_userpic(); 276 $namefields = $userfieldsapi->get_sql('u', false, '', 'userid', false)->selects;; 277 278 $sql = "SELECT h5pa.id, h5pa.timemodified, cm.id as cmid, $namefields 279 FROM {h5pactivity_attempts} h5pa 280 JOIN {h5pactivity} h5p ON h5p.id = h5pa.h5pactivityid 281 JOIN {course_modules} cm ON cm.instance = h5p.id 282 JOIN {modules} md ON md.id = cm.module 283 JOIN {user} u ON u.id = h5pa.userid 284 WHERE h5pa.timemodified > ? 285 AND h5p.course = ? 286 AND md.name = ? 287 ORDER BY h5pa.timemodified ASC"; 288 289 $submissions = $DB->get_records_sql($sql, $dbparams); 290 $this->assertCount(count($students), $submissions); 291 292 // Fetch activity for student (only his own). 293 $this->setUser($students[1]); 294 $recentactivity = h5pactivity_fetch_recent_activity($submissions, $course->id); 295 $this->assertCount(1, $recentactivity); 296 $this->assertEquals($students[1]->id, $recentactivity[$students[1]->id]->userid); 297 298 // Fetch users group info for grader. 299 $this->setUser($teacher); 300 $recentactivity = h5pactivity_fetch_recent_activity($submissions, $course->id); 301 $this->assertCount(2, $recentactivity); 302 // Grader, Student 1 and 3 are in Group 3. 303 $this->assertEquals($students[1]->id, $recentactivity[$students[1]->id]->userid); 304 $this->assertEquals($students[3]->id, $recentactivity[$students[3]->id]->userid); 305 306 // Grader is in Group 2. 307 groups_remove_member($groups[3], $teacher); 308 groups_add_member($groups[2], $teacher); 309 get_fast_modinfo($course->id, 0, true); 310 $recentactivity = h5pactivity_fetch_recent_activity($submissions, $course->id); 311 $this->assertCount(1, $recentactivity); 312 // Grader, Student 2 are in Group 2. 313 $this->assertEquals($students[2]->id, $recentactivity[$students[2]->id]->userid); 314 315 // Grader is in Group 1. 316 groups_remove_member($groups[2], $teacher); 317 groups_add_member($groups[1], $teacher); 318 get_fast_modinfo($course->id, 0, true); 319 $recentactivity = h5pactivity_fetch_recent_activity($submissions, $course->id); 320 $this->assertCount(2, $recentactivity); 321 // Grader, Student 1 and 2 are in Group 1. 322 $this->assertEquals($students[1]->id, $recentactivity[$students[1]->id]->userid); 323 $this->assertEquals($students[2]->id, $recentactivity[$students[2]->id]->userid); 324 325 // Grader is in no group. 326 groups_remove_member($groups[1], $teacher); 327 get_fast_modinfo($course->id, 0, true); 328 $recentactivity = h5pactivity_fetch_recent_activity($submissions, $course->id); 329 // Student 4 and Student 5 have submissions, but they are not in a participation group, so they do not show up in recent 330 // activity for separate groups mode. 331 $this->assertCount(0, $recentactivity); 332 } 333 334 /** 335 * Test that h5pactivity_reset_userdata reset user data. 336 * 337 * @covers ::h5pactivity_reset_userdata 338 */ 339 public function test_h5pactivity_reset_userdata() { 340 global $DB; 341 $this->resetAfterTest(); 342 $this->setAdminUser(); 343 344 $course = $this->getDataGenerator()->create_course(); 345 $user = $this->getDataGenerator()->create_and_enrol($course, 'student'); 346 $activity = $this->getDataGenerator()->create_module('h5pactivity', ['course' => $course]); 347 $this->setUser($user); 348 349 /** @var \mod_h5pactivity_generator $generator */ 350 $generator = $this->getDataGenerator()->get_plugin_generator('mod_h5pactivity'); 351 352 /** @var \core_h5p_generator $h5pgenerator */ 353 $h5pgenerator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); 354 355 // Add an attempt to the H5P activity. 356 $attemptinfo = [ 357 'userid' => $user->id, 358 'h5pactivityid' => $activity->id, 359 'attempt' => 1, 360 'interactiontype' => 'compound', 361 'rawscore' => 2, 362 'maxscore' => 2, 363 'duration' => 1, 364 'completion' => 1, 365 'success' => 0, 366 ]; 367 $generator->create_attempt($attemptinfo); 368 369 // Add also a xAPI state to the H5P activity. 370 $filerecord = [ 371 'contextid' => \context_module::instance($activity->cmid)->id, 372 'component' => 'mod_h5pactivity', 373 'filearea' => 'package', 374 'itemid' => 0, 375 'filepath' => '/', 376 'filepath' => '/', 377 'filename' => 'dummy.h5p', 378 'addxapistate' => true, 379 ]; 380 $h5pgenerator->generate_h5p_data(false, $filerecord); 381 382 // Check the H5P activity exists and the attempt has been created with the expected data. 383 $this->assertNotEmpty($DB->get_record('h5pactivity', ['id' => $activity->id])); 384 $this->assertEquals(2, $DB->count_records('grade_items')); 385 $this->assertEquals(2, $DB->count_records('grade_grades')); 386 $this->assertEquals(1, $DB->count_records('xapi_states')); 387 388 // Check nothing happens when reset_h5pactivity is not set. 389 $data = new \stdClass(); 390 h5pactivity_reset_userdata($data); 391 $this->assertNotEmpty($DB->get_record('h5pactivity', ['id' => $activity->id])); 392 $this->assertEquals(2, $DB->count_records('grade_items')); 393 $this->assertEquals(2, $DB->count_records('grade_grades')); 394 $this->assertEquals(1, $DB->count_records('xapi_states')); 395 $this->assertEquals(1, $DB->count_records('xapi_states')); 396 397 // Check nothing happens when reset_h5pactivity is not set. 398 $data = (object) [ 399 'courseid' => $course->id, 400 ]; 401 h5pactivity_reset_userdata($data); 402 $this->assertNotEmpty($DB->get_record('h5pactivity', ['id' => $activity->id])); 403 $this->assertEquals(2, $DB->count_records('grade_items')); 404 $this->assertEquals(2, $DB->count_records('grade_grades')); 405 $this->assertEquals(1, $DB->count_records('xapi_states')); 406 $this->assertEquals(1, $DB->count_records('xapi_states')); 407 408 // Check nothing happens when the given course doesn't exist. 409 $data = (object) [ 410 'reset_h5pactivity' => true, 411 'courseid' => $course->id + 1, 412 ]; 413 h5pactivity_reset_userdata($data); 414 $this->assertNotEmpty($DB->get_record('h5pactivity', ['id' => $activity->id])); 415 $this->assertEquals(2, $DB->count_records('grade_items')); 416 $this->assertEquals(2, $DB->count_records('grade_grades')); 417 $this->assertEquals(1, $DB->count_records('xapi_states')); 418 $this->assertEquals(1, $DB->count_records('xapi_states')); 419 420 // Check the H5P instance and its associated data is reset. 421 $data = (object) [ 422 'reset_h5pactivity' => true, 423 'courseid' => $course->id, 424 ]; 425 h5pactivity_reset_userdata($data); 426 $this->assertNotEmpty($DB->get_record('h5pactivity', ['id' => $activity->id])); 427 $this->assertEquals(2, $DB->count_records('grade_items')); 428 $this->assertEquals(1, $DB->count_records('grade_grades')); 429 $this->assertEquals(0, $DB->count_records('xapi_states')); 430 } 431 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body