Differences Between: [Versions 310 and 311] [Versions 311 and 402] [Versions 311 and 403] [Versions 39 and 311]
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 * External function test for get_attempts. 19 * 20 * @package mod_h5pactivity 21 * @category external 22 * @since Moodle 3.9 23 * @copyright 2020 Ferran Recio <ferran@moodle.com> 24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 25 */ 26 27 namespace mod_h5pactivity\external; 28 29 defined('MOODLE_INTERNAL') || die(); 30 31 global $CFG; 32 require_once($CFG->dirroot . '/webservice/tests/helpers.php'); 33 34 use mod_h5pactivity\local\manager; 35 use external_api; 36 use externallib_advanced_testcase; 37 38 /** 39 * External function test for get_attempts. 40 * 41 * @package mod_h5pactivity 42 * @copyright 2020 Ferran Recio <ferran@moodle.com> 43 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 44 */ 45 class get_attempts_test extends externallib_advanced_testcase { 46 47 /** 48 * Test the behaviour of get_attempts. 49 * 50 * @dataProvider execute_data 51 * @param int $grademethod the activity grading method 52 * @param string $loginuser the user which calls the webservice 53 * @param string|null $participant the user to get the data 54 * @param bool $createattempts if the student user has attempts created 55 * @param int|null $count the expected number of attempts returned (null for exception) 56 */ 57 public function test_execute(int $grademethod, string $loginuser, ?string $participant, 58 bool $createattempts, ?int $count): void { 59 60 $this->resetAfterTest(); 61 $this->setAdminUser(); 62 63 $course = $this->getDataGenerator()->create_course(); 64 $activity = $this->getDataGenerator()->create_module('h5pactivity', 65 ['course' => $course, 'enabletracking' => 1, 'grademethod' => $grademethod]); 66 67 $manager = manager::create_from_instance($activity); 68 $cm = $manager->get_coursemodule(); 69 70 // Prepare users: 1 teacher, 2 students, 1 unenroled user. 71 $users = [ 72 'editingteacher' => $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'), 73 'student' => $this->getDataGenerator()->create_and_enrol($course, 'student'), 74 'other' => $this->getDataGenerator()->create_and_enrol($course, 'student'), 75 'noenrolled' => $this->getDataGenerator()->create_user(), 76 ]; 77 78 $generator = $this->getDataGenerator()->get_plugin_generator('mod_h5pactivity'); 79 80 if ($createattempts) { 81 $user = $users['student']; 82 $params = ['cmid' => $cm->id, 'userid' => $user->id]; 83 $generator->create_content($activity, $params); 84 $generator->create_content($activity, $params); 85 } 86 87 // Create another user with 2 attempts to validate no cross attempts are returned. 88 $user = $users['other']; 89 $params = ['cmid' => $cm->id, 'userid' => $user->id]; 90 $generator->create_content($activity, $params); 91 $generator->create_content($activity, $params); 92 93 // Execute external method. 94 $this->setUser($users[$loginuser]); 95 $userids = ($participant) ? [$users[$participant]->id] : []; 96 $checkuserid = ($participant) ? $users[$participant]->id : $users[$loginuser]->id; 97 98 $result = get_attempts::execute($activity->id, $userids); 99 $result = external_api::clean_returnvalue( 100 get_attempts::execute_returns(), 101 $result 102 ); 103 104 // Validate general structure. 105 $this->assertArrayHasKey('activityid', $result); 106 $this->assertArrayHasKey('usersattempts', $result); 107 $this->assertArrayHasKey('warnings', $result); 108 109 $this->assertEquals($activity->id, $result['activityid']); 110 111 if ($count === null) { 112 $this->assertCount(1, $result['warnings']); 113 $this->assertCount(0, $result['usersattempts']); 114 return; 115 } 116 117 $this->assertCount(0, $result['warnings']); 118 $this->assertCount(1, $result['usersattempts']); 119 120 $userattempts = $result['usersattempts'][0]; 121 $this->assertEquals($checkuserid, $userattempts['userid']); 122 123 // Validate scored attempts. 124 if ($grademethod == manager::GRADEMANUAL || $grademethod == manager::GRADEAVERAGEATTEMPT || $count == 0) { 125 $this->assertArrayNotHasKey('scored', $userattempts); 126 } else { 127 $this->assertArrayHasKey('scored', $userattempts); 128 list($dbgrademethod, $title) = $manager->get_selected_attempt(); 129 $this->assertEquals($grademethod, $dbgrademethod); 130 $this->assertEquals($grademethod, $userattempts['scored']['grademethod']); 131 $this->assertEquals($title, $userattempts['scored']['title']); 132 $this->assertCount(1, $userattempts['scored']['attempts']); 133 } 134 135 // Validate returned attempts. 136 $this->assertCount($count, $userattempts['attempts']); 137 foreach ($userattempts['attempts'] as $attempt) { 138 $this->assertArrayHasKey('id', $attempt); 139 $this->assertEquals($checkuserid, $attempt['userid']); 140 $this->assertArrayHasKey('timecreated', $attempt); 141 $this->assertArrayHasKey('timemodified', $attempt); 142 $this->assertArrayHasKey('attempt', $attempt); 143 $this->assertArrayHasKey('rawscore', $attempt); 144 $this->assertArrayHasKey('maxscore', $attempt); 145 $this->assertArrayHasKey('duration', $attempt); 146 $this->assertArrayHasKey('completion', $attempt); 147 $this->assertArrayHasKey('success', $attempt); 148 $this->assertArrayHasKey('scaled', $attempt); 149 } 150 } 151 152 /** 153 * Data provider for the test_execute tests. 154 * 155 * @return array 156 */ 157 public function execute_data(): array { 158 return [ 159 // Teacher checking a user with attempts. 160 'Manual grade, Teacher asking participant with attempts' => [ 161 manager::GRADEMANUAL, 'editingteacher', 'student', true, 2 162 ], 163 'Highest grade, Teacher asking participant with attempts' => [ 164 manager::GRADEHIGHESTATTEMPT, 'editingteacher', 'student', true, 2 165 ], 166 'Average grade, Teacher asking participant with attempts' => [ 167 manager::GRADEAVERAGEATTEMPT, 'editingteacher', 'student', true, 2 168 ], 169 'Last grade, Teacher asking participant with attempts' => [ 170 manager::GRADELASTATTEMPT, 'editingteacher', 'student', true, 2 171 ], 172 'First grade, Teacher asking participant with attempts' => [ 173 manager::GRADEFIRSTATTEMPT, 'editingteacher', 'student', true, 2 174 ], 175 // Teacher checking a user without attempts. 176 'Manual grade, Teacher asking participant without attempts' => [ 177 manager::GRADEMANUAL, 'editingteacher', 'student', false, 0 178 ], 179 'Highest grade, Teacher asking participant without attempts' => [ 180 manager::GRADEHIGHESTATTEMPT, 'editingteacher', 'student', false, 0 181 ], 182 'Average grade, Teacher asking participant without attempts' => [ 183 manager::GRADEAVERAGEATTEMPT, 'editingteacher', 'student', false, 0 184 ], 185 'Last grade, Teacher asking participant without attempts' => [ 186 manager::GRADELASTATTEMPT, 'editingteacher', 'student', false, 0 187 ], 188 'First grade, Teacher asking participant without attempts' => [ 189 manager::GRADEFIRSTATTEMPT, 'editingteacher', 'student', false, 0 190 ], 191 // Student checking own attempts specifying userid. 192 'Manual grade, check same user attempts report with attempts' => [ 193 manager::GRADEMANUAL, 'student', 'student', true, 2 194 ], 195 'Highest grade, check same user attempts report with attempts' => [ 196 manager::GRADEHIGHESTATTEMPT, 'student', 'student', true, 2 197 ], 198 'Average grade, check same user attempts report with attempts' => [ 199 manager::GRADEAVERAGEATTEMPT, 'student', 'student', true, 2 200 ], 201 'Last grade, check same user attempts report with attempts' => [ 202 manager::GRADELASTATTEMPT, 'student', 'student', true, 2 203 ], 204 'First grade, check same user attempts report with attempts' => [ 205 manager::GRADEFIRSTATTEMPT, 'student', 'student', true, 2 206 ], 207 // Student checking own attempts. 208 'Manual grade, check own attempts report with attempts' => [ 209 manager::GRADEMANUAL, 'student', null, true, 2 210 ], 211 'Highest grade, check own attempts report with attempts' => [ 212 manager::GRADEHIGHESTATTEMPT, 'student', null, true, 2 213 ], 214 'Average grade, check own attempts report with attempts' => [ 215 manager::GRADEAVERAGEATTEMPT, 'student', null, true, 2 216 ], 217 'Last grade, check own attempts report with attempts' => [ 218 manager::GRADELASTATTEMPT, 'student', null, true, 2 219 ], 220 'First grade, check own attempts report with attempts' => [ 221 manager::GRADEFIRSTATTEMPT, 'student', null, true, 2 222 ], 223 // Student checking own report without attempts. 224 'Manual grade, check own attempts report without attempts' => [ 225 manager::GRADEMANUAL, 'student', 'student', false, 0 226 ], 227 'Highest grade, check own attempts report without attempts' => [ 228 manager::GRADEHIGHESTATTEMPT, 'student', 'student', false, 0 229 ], 230 'Average grade, check own attempts report without attempts' => [ 231 manager::GRADEAVERAGEATTEMPT, 'student', 'student', false, 0 232 ], 233 'Last grade, check own attempts report without attempts' => [ 234 manager::GRADELASTATTEMPT, 'student', 'student', false, 0 235 ], 236 'First grade, check own attempts report without attempts' => [ 237 manager::GRADEFIRSTATTEMPT, 'student', 'student', false, 0 238 ], 239 // Student trying to get another user attempts. 240 'Manual grade, student trying to stalk another student' => [ 241 manager::GRADEMANUAL, 'student', 'other', false, null 242 ], 243 'Highest grade, student trying to stalk another student' => [ 244 manager::GRADEHIGHESTATTEMPT, 'student', 'other', false, null 245 ], 246 'Average grade, student trying to stalk another student' => [ 247 manager::GRADEAVERAGEATTEMPT, 'student', 'other', false, null 248 ], 249 'Last grade, student trying to stalk another student' => [ 250 manager::GRADELASTATTEMPT, 'student', 'other', false, null 251 ], 252 'First grade, student trying to stalk another student' => [ 253 manager::GRADEFIRSTATTEMPT, 'student', 'other', false, null 254 ], 255 // Teacher trying to get a non enroled user attempts. 256 'Manual grade, teacher trying to get an non enrolled user attempts' => [ 257 manager::GRADEMANUAL, 'editingteacher', 'noenrolled', false, null 258 ], 259 'Highest grade, teacher trying to get an non enrolled user attempts' => [ 260 manager::GRADEHIGHESTATTEMPT, 'editingteacher', 'noenrolled', false, null 261 ], 262 'Average grade, teacher trying to get an non enrolled user attempts' => [ 263 manager::GRADEAVERAGEATTEMPT, 'editingteacher', 'noenrolled', false, null 264 ], 265 'Last grade, teacher trying to get an non enrolled user attempts' => [ 266 manager::GRADELASTATTEMPT, 'editingteacher', 'noenrolled', false, null 267 ], 268 'First grade, teacher trying to get an non enrolled user attempts' => [ 269 manager::GRADEFIRSTATTEMPT, 'editingteacher', 'noenrolled', false, null 270 ], 271 // Student trying to get a non enroled user attempts. 272 'Manual grade, student trying to get an non enrolled user attempts' => [ 273 manager::GRADEMANUAL, 'student', 'noenrolled', false, null 274 ], 275 'Highest grade, student trying to get an non enrolled user attempts' => [ 276 manager::GRADEHIGHESTATTEMPT, 'student', 'noenrolled', false, null 277 ], 278 'Average grade, student trying to get an non enrolled user attempts' => [ 279 manager::GRADEAVERAGEATTEMPT, 'student', 'noenrolled', false, null 280 ], 281 'Last grade, student trying to get an non enrolled user attempts' => [ 282 manager::GRADELASTATTEMPT, 'student', 'noenrolled', false, null 283 ], 284 'First grade, student trying to get an non enrolled user attempts' => [ 285 manager::GRADEFIRSTATTEMPT, 'student', 'noenrolled', false, null 286 ], 287 ]; 288 } 289 290 /** 291 * Test the behaviour of get_attempts when tracking is not enabled. 292 * 293 */ 294 public function test_execute_no_tracking(): void { 295 296 $this->resetAfterTest(); 297 $this->setAdminUser(); 298 299 $course = $this->getDataGenerator()->create_course(); 300 $activity = $this->getDataGenerator()->create_module('h5pactivity', 301 ['course' => $course, 'enabletracking' => 0]); 302 303 $manager = manager::create_from_instance($activity); 304 $cm = $manager->get_coursemodule(); 305 306 // Prepare users: 1 teacher, 1 student. 307 $users = [ 308 'editingteacher' => $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'), 309 'student' => $this->getDataGenerator()->create_and_enrol($course, 'student'), 310 ]; 311 312 // Execute external method. 313 $this->setUser($users['editingteacher']); 314 315 $result = get_attempts::execute($activity->id, [$users['student']->id]); 316 $result = external_api::clean_returnvalue( 317 get_attempts::execute_returns(), 318 $result 319 ); 320 321 $this->assertCount(1, $result['warnings']); 322 $this->assertCount(0, $result['usersattempts']); 323 } 324 325 /** 326 * Test the behaviour of get_attempts when own review is not allowed. 327 * 328 */ 329 public function test_execute_no_own_review(): void { 330 331 $this->resetAfterTest(); 332 $this->setAdminUser(); 333 334 $course = $this->getDataGenerator()->create_course(); 335 $activity = $this->getDataGenerator()->create_module('h5pactivity', 336 ['course' => $course, 'enabletracking' => 1, 'reviewmode' => manager::REVIEWNONE]); 337 338 $manager = manager::create_from_instance($activity); 339 $cm = $manager->get_coursemodule(); 340 341 // Prepare users: 1 student. 342 $users = [ 343 'student' => $this->getDataGenerator()->create_and_enrol($course, 'student'), 344 ]; 345 346 // Execute external method. 347 $this->setUser($users['student']); 348 349 $result = get_attempts::execute($activity->id); 350 $result = external_api::clean_returnvalue( 351 get_attempts::execute_returns(), 352 $result 353 ); 354 355 $this->assertCount(1, $result['warnings']); 356 $this->assertCount(0, $result['usersattempts']); 357 } 358 359 /** 360 * Test the behaviour of get_attempts getting more than one user at once. 361 * 362 * @dataProvider execute_multipleusers_data 363 * @param string $loginuser the user which calls the webservice 364 * @param string[] $participants the users to get the data 365 * @param string[] $warnings the expected users with warnings 366 * @param string[] $resultusers expected users in the resultusers 367 */ 368 public function test_execute_multipleusers(string $loginuser, array $participants, 369 array $warnings, array $resultusers): void { 370 371 $this->resetAfterTest(); 372 $this->setAdminUser(); 373 374 $course = $this->getDataGenerator()->create_course(); 375 $activity = $this->getDataGenerator()->create_module('h5pactivity', 376 ['course' => $course]); 377 378 $manager = manager::create_from_instance($activity); 379 $cm = $manager->get_coursemodule(); 380 381 // Prepare users: 1 teacher, 2 students with attempts, 1 student without, 1 no enrolled. 382 $users = [ 383 'editingteacher' => $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'), 384 'student1' => $this->getDataGenerator()->create_and_enrol($course, 'student'), 385 'student2' => $this->getDataGenerator()->create_and_enrol($course, 'student'), 386 'noattempts' => $this->getDataGenerator()->create_and_enrol($course, 'student'), 387 'noenrolled' => $this->getDataGenerator()->create_user(), 388 ]; 389 390 // Generate attempts (student1 with 1 attempt, student2 with 2). 391 $generator = $this->getDataGenerator()->get_plugin_generator('mod_h5pactivity'); 392 393 $user = $users['student1']; 394 $params = ['cmid' => $cm->id, 'userid' => $user->id]; 395 $generator->create_content($activity, $params); 396 397 $user = $users['student2']; 398 $params = ['cmid' => $cm->id, 'userid' => $user->id]; 399 $generator->create_content($activity, $params); 400 $generator->create_content($activity, $params); 401 402 $countattempts = [ 403 $users['editingteacher']->id => 0, 404 $users['student1']->id => 1, 405 $users['student2']->id => 2, 406 $users['noattempts']->id => 0, 407 $users['noenrolled']->id => 0, 408 ]; 409 410 // Execute external method. 411 $this->setUser($users[$loginuser]); 412 413 $userids = []; 414 foreach ($participants as $participant) { 415 $userids[] = $users[$participant]->id; 416 } 417 418 $result = get_attempts::execute($activity->id, $userids); 419 $result = external_api::clean_returnvalue( 420 get_attempts::execute_returns(), 421 $result 422 ); 423 424 $this->assertCount(count($warnings), $result['warnings']); 425 $this->assertCount(count($resultusers), $result['usersattempts']); 426 427 $expectedwarnings = []; 428 foreach ($warnings as $warninguser) { 429 $id = $users[$warninguser]->id; 430 $expectedwarnings[$id] = $warninguser; 431 } 432 433 foreach ($result['warnings'] as $warning) { 434 $this->assertEquals('user', $warning['item']); 435 $this->assertEquals(1, $warning['warningcode']); 436 $this->assertArrayHasKey($warning['itemid'], $expectedwarnings); 437 } 438 439 $expectedusers = []; 440 foreach ($resultusers as $resultuser) { 441 $id = $users[$resultuser]->id; 442 $expectedusers[$id] = $resultuser; 443 } 444 445 foreach ($result['usersattempts'] as $usersattempts) { 446 $this->assertArrayHasKey('userid', $usersattempts); 447 $userid = $usersattempts['userid']; 448 $this->assertArrayHasKey($userid, $expectedusers); 449 $this->assertCount($countattempts[$userid], $usersattempts['attempts']); 450 if ($countattempts[$userid]) { 451 $this->assertArrayHasKey('scored', $usersattempts); 452 } 453 } 454 } 455 456 /** 457 * Data provider for the test_execute_multipleusers. 458 * 459 * @return array 460 */ 461 public function execute_multipleusers_data(): array { 462 return [ 463 // Teacher checks. 464 'Teacher checking students with attempts' => [ 465 'editingteacher', ['student1', 'student2'], [], ['student1', 'student2'] 466 ], 467 'Teacher checking one student with atempts and one not' => [ 468 'editingteacher', ['student1', 'noattempts'], [], ['student1', 'noattempts'] 469 ], 470 'Teacher checking no students' => [ 471 'editingteacher', [], [], ['editingteacher'] 472 ], 473 'Teacher checking one student and a no enrolled user' => [ 474 'editingteacher', ['student1', 'noenrolled'], ['noenrolled'], ['student1'] 475 ], 476 // Student checks. 477 'Student checking self attempts and another user' => [ 478 'student1', ['student1', 'student2'], ['student2'], ['student1'] 479 ], 480 'Student checking no students' => [ 481 'student1', [], [], ['student1'] 482 ], 483 'Student checking self attempts and a no enrolled user' => [ 484 'student1', ['student1', 'noenrolled'], ['noenrolled'], ['student1'] 485 ], 486 ]; 487 } 488 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body