[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
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 * SCORM module external functions tests 19 * 20 * @package mod_scorm 21 * @category external 22 * @copyright 2015 Juan Leyva <juan@moodle.com> 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 * @since Moodle 3.0 25 */ 26 27 defined('MOODLE_INTERNAL') || die(); 28 29 global $CFG; 30 31 require_once($CFG->dirroot . '/webservice/tests/helpers.php'); 32 require_once($CFG->dirroot . '/mod/scorm/lib.php'); 33 34 /** 35 * SCORM module external functions tests 36 * 37 * @package mod_scorm 38 * @category external 39 * @copyright 2015 Juan Leyva <juan@moodle.com> 40 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 41 * @since Moodle 3.0 42 */ 43 class mod_scorm_external_testcase extends externallib_advanced_testcase { 44 45 /** 46 * Set up for every test 47 */ 48 public function setUp() { 49 global $DB; 50 $this->resetAfterTest(); 51 $this->setAdminUser(); 52 53 // Setup test data. 54 $this->course = $this->getDataGenerator()->create_course(); 55 $this->scorm = $this->getDataGenerator()->create_module('scorm', array('course' => $this->course->id)); 56 $this->context = context_module::instance($this->scorm->cmid); 57 $this->cm = get_coursemodule_from_instance('scorm', $this->scorm->id); 58 59 // Create users. 60 $this->student = self::getDataGenerator()->create_user(); 61 $this->teacher = self::getDataGenerator()->create_user(); 62 63 // Users enrolments. 64 $this->studentrole = $DB->get_record('role', array('shortname' => 'student')); 65 $this->teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher')); 66 $this->getDataGenerator()->enrol_user($this->student->id, $this->course->id, $this->studentrole->id, 'manual'); 67 $this->getDataGenerator()->enrol_user($this->teacher->id, $this->course->id, $this->teacherrole->id, 'manual'); 68 } 69 70 /** 71 * Test view_scorm 72 */ 73 public function test_view_scorm() { 74 global $DB; 75 76 // Test invalid instance id. 77 try { 78 mod_scorm_external::view_scorm(0); 79 $this->fail('Exception expected due to invalid mod_scorm instance id.'); 80 } catch (moodle_exception $e) { 81 $this->assertEquals('invalidrecord', $e->errorcode); 82 } 83 84 // Test not-enrolled user. 85 $user = self::getDataGenerator()->create_user(); 86 $this->setUser($user); 87 try { 88 mod_scorm_external::view_scorm($this->scorm->id); 89 $this->fail('Exception expected due to not enrolled user.'); 90 } catch (moodle_exception $e) { 91 $this->assertEquals('requireloginerror', $e->errorcode); 92 } 93 94 // Test user with full capabilities. 95 $this->studentrole = $DB->get_record('role', array('shortname' => 'student')); 96 $this->getDataGenerator()->enrol_user($user->id, $this->course->id, $this->studentrole->id); 97 98 // Trigger and capture the event. 99 $sink = $this->redirectEvents(); 100 101 $result = mod_scorm_external::view_scorm($this->scorm->id); 102 $result = external_api::clean_returnvalue(mod_scorm_external::view_scorm_returns(), $result); 103 104 $events = $sink->get_events(); 105 $this->assertCount(1, $events); 106 $event = array_shift($events); 107 108 // Checking that the event contains the expected values. 109 $this->assertInstanceOf('\mod_scorm\event\course_module_viewed', $event); 110 $this->assertEquals($this->context, $event->get_context()); 111 $moodleurl = new \moodle_url('/mod/scorm/view.php', array('id' => $this->cm->id)); 112 $this->assertEquals($moodleurl, $event->get_url()); 113 $this->assertEventContextNotUsed($event); 114 $this->assertNotEmpty($event->get_name()); 115 } 116 117 /** 118 * Test get scorm attempt count 119 */ 120 public function test_mod_scorm_get_scorm_attempt_count_own_empty() { 121 // Set to the student user. 122 self::setUser($this->student); 123 124 // Retrieve my attempts (should be 0). 125 $result = mod_scorm_external::get_scorm_attempt_count($this->scorm->id, $this->student->id); 126 $result = external_api::clean_returnvalue(mod_scorm_external::get_scorm_attempt_count_returns(), $result); 127 $this->assertEquals(0, $result['attemptscount']); 128 } 129 130 public function test_mod_scorm_get_scorm_attempt_count_own_with_complete() { 131 // Set to the student user. 132 self::setUser($this->student); 133 134 // Create attempts. 135 $scoes = scorm_get_scoes($this->scorm->id); 136 $sco = array_shift($scoes); 137 scorm_insert_track($this->student->id, $this->scorm->id, $sco->id, 1, 'cmi.core.lesson_status', 'completed'); 138 scorm_insert_track($this->student->id, $this->scorm->id, $sco->id, 2, 'cmi.core.lesson_status', 'completed'); 139 140 $result = mod_scorm_external::get_scorm_attempt_count($this->scorm->id, $this->student->id); 141 $result = external_api::clean_returnvalue(mod_scorm_external::get_scorm_attempt_count_returns(), $result); 142 $this->assertEquals(2, $result['attemptscount']); 143 } 144 145 public function test_mod_scorm_get_scorm_attempt_count_own_incomplete() { 146 // Set to the student user. 147 self::setUser($this->student); 148 149 // Create a complete attempt, and an incomplete attempt. 150 $scoes = scorm_get_scoes($this->scorm->id); 151 $sco = array_shift($scoes); 152 scorm_insert_track($this->student->id, $this->scorm->id, $sco->id, 1, 'cmi.core.lesson_status', 'completed'); 153 scorm_insert_track($this->student->id, $this->scorm->id, $sco->id, 2, 'cmi.core.credit', '0'); 154 155 $result = mod_scorm_external::get_scorm_attempt_count($this->scorm->id, $this->student->id, true); 156 $result = external_api::clean_returnvalue(mod_scorm_external::get_scorm_attempt_count_returns(), $result); 157 $this->assertEquals(1, $result['attemptscount']); 158 } 159 160 public function test_mod_scorm_get_scorm_attempt_count_others_as_teacher() { 161 // As a teacher. 162 self::setUser($this->teacher); 163 164 // Create a completed attempt for student. 165 $scoes = scorm_get_scoes($this->scorm->id); 166 $sco = array_shift($scoes); 167 scorm_insert_track($this->student->id, $this->scorm->id, $sco->id, 1, 'cmi.core.lesson_status', 'completed'); 168 169 // I should be able to view the attempts for my students. 170 $result = mod_scorm_external::get_scorm_attempt_count($this->scorm->id, $this->student->id); 171 $result = external_api::clean_returnvalue(mod_scorm_external::get_scorm_attempt_count_returns(), $result); 172 $this->assertEquals(1, $result['attemptscount']); 173 } 174 175 /** 176 * @expectedException required_capability_exception 177 */ 178 public function test_mod_scorm_get_scorm_attempt_count_others_as_student() { 179 // Create a second student. 180 $student2 = self::getDataGenerator()->create_user(); 181 $this->getDataGenerator()->enrol_user($student2->id, $this->course->id, $this->studentrole->id, 'manual'); 182 183 // As a student. 184 self::setUser($student2); 185 186 // I should not be able to view the attempts of another student. 187 mod_scorm_external::get_scorm_attempt_count($this->scorm->id, $this->student->id); 188 } 189 190 /** 191 * @expectedException moodle_exception 192 */ 193 public function test_mod_scorm_get_scorm_attempt_count_invalid_instanceid() { 194 // As student. 195 self::setUser($this->student); 196 197 // Test invalid instance id. 198 mod_scorm_external::get_scorm_attempt_count(0, $this->student->id); 199 } 200 201 /** 202 * @expectedException moodle_exception 203 */ 204 public function test_mod_scorm_get_scorm_attempt_count_invalid_userid() { 205 // As student. 206 self::setUser($this->student); 207 208 mod_scorm_external::get_scorm_attempt_count($this->scorm->id, -1); 209 } 210 211 /** 212 * Test get scorm scoes 213 */ 214 public function test_mod_scorm_get_scorm_scoes() { 215 global $DB; 216 217 $this->resetAfterTest(true); 218 219 // Create users. 220 $student = self::getDataGenerator()->create_user(); 221 $teacher = self::getDataGenerator()->create_user(); 222 223 // Set to the student user. 224 self::setUser($student); 225 226 // Create courses to add the modules. 227 $course = self::getDataGenerator()->create_course(); 228 229 // First scorm, dates restriction. 230 $record = new stdClass(); 231 $record->course = $course->id; 232 $record->timeopen = time() + DAYSECS; 233 $record->timeclose = $record->timeopen + DAYSECS; 234 $scorm = self::getDataGenerator()->create_module('scorm', $record); 235 236 // Users enrolments. 237 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 238 $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher')); 239 $this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id, 'manual'); 240 $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id, 'manual'); 241 242 // Retrieve my scoes, warning!. 243 try { 244 mod_scorm_external::get_scorm_scoes($scorm->id); 245 $this->fail('Exception expected due to invalid dates.'); 246 } catch (moodle_exception $e) { 247 $this->assertEquals('notopenyet', $e->errorcode); 248 } 249 250 $scorm->timeopen = time() - DAYSECS; 251 $scorm->timeclose = time() - HOURSECS; 252 $DB->update_record('scorm', $scorm); 253 254 try { 255 mod_scorm_external::get_scorm_scoes($scorm->id); 256 $this->fail('Exception expected due to invalid dates.'); 257 } catch (moodle_exception $e) { 258 $this->assertEquals('expired', $e->errorcode); 259 } 260 261 // Retrieve my scoes, user with permission. 262 self::setUser($teacher); 263 $result = mod_scorm_external::get_scorm_scoes($scorm->id); 264 $result = external_api::clean_returnvalue(mod_scorm_external::get_scorm_scoes_returns(), $result); 265 $this->assertCount(2, $result['scoes']); 266 $this->assertCount(0, $result['warnings']); 267 268 $scoes = scorm_get_scoes($scorm->id); 269 $sco = array_shift($scoes); 270 $sco->extradata = array(); 271 $this->assertEquals((array) $sco, $result['scoes'][0]); 272 273 $sco = array_shift($scoes); 274 $sco->extradata = array(); 275 $sco->extradata[] = array( 276 'element' => 'isvisible', 277 'value' => $sco->isvisible 278 ); 279 $sco->extradata[] = array( 280 'element' => 'parameters', 281 'value' => $sco->parameters 282 ); 283 unset($sco->isvisible); 284 unset($sco->parameters); 285 286 // Sort the array (if we don't sort tests will fails for Postgres). 287 usort($result['scoes'][1]['extradata'], function($a, $b) { 288 return strcmp($a['element'], $b['element']); 289 }); 290 291 $this->assertEquals((array) $sco, $result['scoes'][1]); 292 293 // Use organization. 294 $organization = 'golf_sample_default_org'; 295 $result = mod_scorm_external::get_scorm_scoes($scorm->id, $organization); 296 $result = external_api::clean_returnvalue(mod_scorm_external::get_scorm_scoes_returns(), $result); 297 $this->assertCount(1, $result['scoes']); 298 $this->assertEquals($organization, $result['scoes'][0]['organization']); 299 $this->assertCount(0, $result['warnings']); 300 301 // Test invalid instance id. 302 try { 303 mod_scorm_external::get_scorm_scoes(0); 304 $this->fail('Exception expected due to invalid instance id.'); 305 } catch (moodle_exception $e) { 306 $this->assertEquals('invalidrecord', $e->errorcode); 307 } 308 309 } 310 311 /** 312 * Test get scorm scoes (with a complex SCORM package) 313 */ 314 public function test_mod_scorm_get_scorm_scoes_complex_package() { 315 global $CFG; 316 317 // As student. 318 self::setUser($this->student); 319 320 $record = new stdClass(); 321 $record->course = $this->course->id; 322 $record->packagefilepath = $CFG->dirroot.'/mod/scorm/tests/packages/complexscorm.zip'; 323 $scorm = self::getDataGenerator()->create_module('scorm', $record); 324 325 $result = mod_scorm_external::get_scorm_scoes($scorm->id); 326 $result = external_api::clean_returnvalue(mod_scorm_external::get_scorm_scoes_returns(), $result); 327 $this->assertCount(9, $result['scoes']); 328 $this->assertCount(0, $result['warnings']); 329 330 $expectedscoes = array(); 331 $scoreturnstructure = mod_scorm_external::get_scorm_scoes_returns(); 332 $scoes = scorm_get_scoes($scorm->id); 333 foreach ($scoes as $sco) { 334 $sco->extradata = array(); 335 foreach ($sco as $element => $value) { 336 // Add the extra data to the extradata array and remove the object element. 337 if (!isset($scoreturnstructure->keys['scoes']->content->keys[$element])) { 338 $sco->extradata[] = array( 339 'element' => $element, 340 'value' => $value 341 ); 342 unset($sco->{$element}); 343 } 344 } 345 $expectedscoes[] = (array) $sco; 346 } 347 348 $this->assertEquals($expectedscoes, $result['scoes']); 349 } 350 351 /* 352 * Test get scorm user data 353 */ 354 public function test_mod_scorm_get_scorm_user_data() { 355 global $DB; 356 357 $this->resetAfterTest(true); 358 359 // Create users. 360 $student1 = self::getDataGenerator()->create_user(); 361 $teacher = self::getDataGenerator()->create_user(); 362 363 // Set to the student user. 364 self::setUser($student1); 365 366 // Create courses to add the modules. 367 $course = self::getDataGenerator()->create_course(); 368 369 // First scorm. 370 $record = new stdClass(); 371 $record->course = $course->id; 372 $scorm = self::getDataGenerator()->create_module('scorm', $record); 373 374 // Users enrolments. 375 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 376 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); 377 $this->getDataGenerator()->enrol_user($student1->id, $course->id, $studentrole->id, 'manual'); 378 $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id, 'manual'); 379 380 // Create attempts. 381 $scoes = scorm_get_scoes($scorm->id); 382 $sco = array_shift($scoes); 383 scorm_insert_track($student1->id, $scorm->id, $sco->id, 1, 'cmi.core.lesson_status', 'completed'); 384 scorm_insert_track($student1->id, $scorm->id, $sco->id, 1, 'cmi.core.score.raw', '80'); 385 scorm_insert_track($student1->id, $scorm->id, $sco->id, 2, 'cmi.core.lesson_status', 'completed'); 386 387 $result = mod_scorm_external::get_scorm_user_data($scorm->id, 1); 388 $result = external_api::clean_returnvalue(mod_scorm_external::get_scorm_user_data_returns(), $result); 389 $this->assertCount(2, $result['data']); 390 // Find our tracking data. 391 $found = 0; 392 foreach ($result['data'] as $scodata) { 393 foreach ($scodata['userdata'] as $userdata) { 394 if ($userdata['element'] == 'cmi.core.lesson_status' and $userdata['value'] == 'completed') { 395 $found++; 396 } 397 if ($userdata['element'] == 'cmi.core.score.raw' and $userdata['value'] == '80') { 398 $found++; 399 } 400 } 401 } 402 $this->assertEquals(2, $found); 403 404 // Test invalid instance id. 405 try { 406 mod_scorm_external::get_scorm_user_data(0, 1); 407 $this->fail('Exception expected due to invalid instance id.'); 408 } catch (moodle_exception $e) { 409 $this->assertEquals('invalidrecord', $e->errorcode); 410 } 411 } 412 413 /** 414 * Test insert scorm tracks 415 */ 416 public function test_mod_scorm_insert_scorm_tracks() { 417 global $DB; 418 419 $this->resetAfterTest(true); 420 421 // Create users. 422 $student = self::getDataGenerator()->create_user(); 423 424 // Set to the student user. 425 self::setUser($student); 426 427 // Create courses to add the modules. 428 $course = self::getDataGenerator()->create_course(); 429 430 // First scorm, dates restriction. 431 $record = new stdClass(); 432 $record->course = $course->id; 433 $record->timeopen = time() + DAYSECS; 434 $record->timeclose = $record->timeopen + DAYSECS; 435 $scorm = self::getDataGenerator()->create_module('scorm', $record); 436 437 // Get a SCO. 438 $scoes = scorm_get_scoes($scorm->id); 439 $sco = array_shift($scoes); 440 441 // Tracks. 442 $tracks = array(); 443 $tracks[] = array( 444 'element' => 'cmi.core.lesson_status', 445 'value' => 'completed' 446 ); 447 $tracks[] = array( 448 'element' => 'cmi.core.score.raw', 449 'value' => '80' 450 ); 451 452 // Users enrolments. 453 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 454 $this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id, 'manual'); 455 456 // Exceptions first. 457 try { 458 mod_scorm_external::insert_scorm_tracks($sco->id, 1, $tracks); 459 $this->fail('Exception expected due to dates'); 460 } catch (moodle_exception $e) { 461 $this->assertEquals('notopenyet', $e->errorcode); 462 } 463 464 $scorm->timeopen = time() - DAYSECS; 465 $scorm->timeclose = time() - HOURSECS; 466 $DB->update_record('scorm', $scorm); 467 468 try { 469 mod_scorm_external::insert_scorm_tracks($sco->id, 1, $tracks); 470 $this->fail('Exception expected due to dates'); 471 } catch (moodle_exception $e) { 472 $this->assertEquals('expired', $e->errorcode); 473 } 474 475 // Test invalid instance id. 476 try { 477 mod_scorm_external::insert_scorm_tracks(0, 1, $tracks); 478 $this->fail('Exception expected due to invalid sco id.'); 479 } catch (moodle_exception $e) { 480 $this->assertEquals('cannotfindsco', $e->errorcode); 481 } 482 483 $scorm->timeopen = 0; 484 $scorm->timeclose = 0; 485 $DB->update_record('scorm', $scorm); 486 487 // Retrieve my tracks. 488 $result = mod_scorm_external::insert_scorm_tracks($sco->id, 1, $tracks); 489 $result = external_api::clean_returnvalue(mod_scorm_external::insert_scorm_tracks_returns(), $result); 490 $this->assertCount(0, $result['warnings']); 491 492 $trackids = $DB->get_records('scorm_scoes_track', array('userid' => $student->id, 'scoid' => $sco->id, 493 'scormid' => $scorm->id, 'attempt' => 1)); 494 // We use asort here to prevent problems with ids ordering. 495 $expectedkeys = array_keys($trackids); 496 $this->assertEquals(asort($expectedkeys), asort($result['trackids'])); 497 } 498 499 /** 500 * Test get scorm sco tracks 501 */ 502 public function test_mod_scorm_get_scorm_sco_tracks() { 503 global $DB; 504 505 $this->resetAfterTest(true); 506 507 // Create users. 508 $student = self::getDataGenerator()->create_user(); 509 $otherstudent = self::getDataGenerator()->create_user(); 510 $teacher = self::getDataGenerator()->create_user(); 511 512 // Set to the student user. 513 self::setUser($student); 514 515 // Create courses to add the modules. 516 $course = self::getDataGenerator()->create_course(); 517 518 // First scorm. 519 $record = new stdClass(); 520 $record->course = $course->id; 521 $scorm = self::getDataGenerator()->create_module('scorm', $record); 522 523 // Users enrolments. 524 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 525 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); 526 $this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id, 'manual'); 527 $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id, 'manual'); 528 529 // Create attempts. 530 $scoes = scorm_get_scoes($scorm->id); 531 $sco = array_shift($scoes); 532 scorm_insert_track($student->id, $scorm->id, $sco->id, 1, 'cmi.core.lesson_status', 'completed'); 533 scorm_insert_track($student->id, $scorm->id, $sco->id, 1, 'cmi.core.score.raw', '80'); 534 scorm_insert_track($student->id, $scorm->id, $sco->id, 2, 'cmi.core.lesson_status', 'completed'); 535 536 $result = mod_scorm_external::get_scorm_sco_tracks($sco->id, $student->id, 1); 537 $result = external_api::clean_returnvalue(mod_scorm_external::get_scorm_sco_tracks_returns(), $result); 538 // 7 default elements + 2 custom ones. 539 $this->assertCount(9, $result['data']['tracks']); 540 $this->assertEquals(1, $result['data']['attempt']); 541 $this->assertCount(0, $result['warnings']); 542 // Find our tracking data. 543 $found = 0; 544 foreach ($result['data']['tracks'] as $userdata) { 545 if ($userdata['element'] == 'cmi.core.lesson_status' and $userdata['value'] == 'completed') { 546 $found++; 547 } 548 if ($userdata['element'] == 'cmi.core.score.raw' and $userdata['value'] == '80') { 549 $found++; 550 } 551 } 552 $this->assertEquals(2, $found); 553 554 // Try invalid attempt. 555 $result = mod_scorm_external::get_scorm_sco_tracks($sco->id, $student->id, 10); 556 $result = external_api::clean_returnvalue(mod_scorm_external::get_scorm_sco_tracks_returns(), $result); 557 $this->assertCount(0, $result['data']['tracks']); 558 $this->assertEquals(10, $result['data']['attempt']); 559 $this->assertCount(1, $result['warnings']); 560 $this->assertEquals('notattempted', $result['warnings'][0]['warningcode']); 561 562 // Capabilities check. 563 try { 564 mod_scorm_external::get_scorm_sco_tracks($sco->id, $otherstudent->id); 565 $this->fail('Exception expected due to invalid instance id.'); 566 } catch (required_capability_exception $e) { 567 $this->assertEquals('nopermissions', $e->errorcode); 568 } 569 570 self::setUser($teacher); 571 // Ommit the attempt parameter, the function should calculate the last attempt. 572 $result = mod_scorm_external::get_scorm_sco_tracks($sco->id, $student->id); 573 $result = external_api::clean_returnvalue(mod_scorm_external::get_scorm_sco_tracks_returns(), $result); 574 // 7 default elements + 1 custom one. 575 $this->assertCount(8, $result['data']['tracks']); 576 $this->assertEquals(2, $result['data']['attempt']); 577 578 // Test invalid instance id. 579 try { 580 mod_scorm_external::get_scorm_sco_tracks(0, 1); 581 $this->fail('Exception expected due to invalid instance id.'); 582 } catch (moodle_exception $e) { 583 $this->assertEquals('cannotfindsco', $e->errorcode); 584 } 585 // Invalid user. 586 try { 587 mod_scorm_external::get_scorm_sco_tracks($sco->id, 0); 588 $this->fail('Exception expected due to invalid instance id.'); 589 } catch (moodle_exception $e) { 590 $this->assertEquals('invaliduser', $e->errorcode); 591 } 592 } 593 594 /* 595 * Test get scorms by courses 596 */ 597 public function test_mod_scorm_get_scorms_by_courses() { 598 global $DB; 599 600 $this->resetAfterTest(true); 601 602 // Create users. 603 $student = self::getDataGenerator()->create_user(); 604 $teacher = self::getDataGenerator()->create_user(); 605 606 // Set to the student user. 607 self::setUser($student); 608 609 // Create courses to add the modules. 610 $course1 = self::getDataGenerator()->create_course(); 611 $course2 = self::getDataGenerator()->create_course(); 612 613 // First scorm. 614 $record = new stdClass(); 615 $record->introformat = FORMAT_HTML; 616 $record->course = $course1->id; 617 $record->hidetoc = 2; 618 $record->displayattemptstatus = 2; 619 $record->skipview = 2; 620 $scorm1 = self::getDataGenerator()->create_module('scorm', $record); 621 622 // Second scorm. 623 $record = new stdClass(); 624 $record->introformat = FORMAT_HTML; 625 $record->course = $course2->id; 626 $scorm2 = self::getDataGenerator()->create_module('scorm', $record); 627 628 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 629 $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher')); 630 631 // Users enrolments. 632 $this->getDataGenerator()->enrol_user($student->id, $course1->id, $studentrole->id, 'manual'); 633 $this->getDataGenerator()->enrol_user($teacher->id, $course1->id, $teacherrole->id, 'manual'); 634 635 // Execute real Moodle enrolment as we'll call unenrol() method on the instance later. 636 $enrol = enrol_get_plugin('manual'); 637 $enrolinstances = enrol_get_instances($course2->id, true); 638 foreach ($enrolinstances as $courseenrolinstance) { 639 if ($courseenrolinstance->enrol == "manual") { 640 $instance2 = $courseenrolinstance; 641 break; 642 } 643 } 644 $enrol->enrol_user($instance2, $student->id, $studentrole->id); 645 646 $returndescription = mod_scorm_external::get_scorms_by_courses_returns(); 647 648 // Test open/close dates. 649 650 $timenow = time(); 651 $scorm1->timeopen = $timenow - DAYSECS; 652 $scorm1->timeclose = $timenow - HOURSECS; 653 $DB->update_record('scorm', $scorm1); 654 655 $result = mod_scorm_external::get_scorms_by_courses(array($course1->id)); 656 $result = external_api::clean_returnvalue($returndescription, $result); 657 $this->assertCount(1, $result['warnings']); 658 // Only 'id', 'coursemodule', 'course', 'name', 'intro', 'introformat', 'introfiles'. 659 $this->assertCount(7, $result['scorms'][0]); 660 $this->assertEquals('expired', $result['warnings'][0]['warningcode']); 661 662 $scorm1->timeopen = $timenow + DAYSECS; 663 $scorm1->timeclose = $scorm1->timeopen + DAYSECS; 664 $DB->update_record('scorm', $scorm1); 665 666 $result = mod_scorm_external::get_scorms_by_courses(array($course1->id)); 667 $result = external_api::clean_returnvalue($returndescription, $result); 668 $this->assertCount(1, $result['warnings']); 669 // Only 'id', 'coursemodule', 'course', 'name', 'intro', 'introformat', 'introfiles'. 670 $this->assertCount(7, $result['scorms'][0]); 671 $this->assertEquals('notopenyet', $result['warnings'][0]['warningcode']); 672 673 // Reset times. 674 $scorm1->timeopen = 0; 675 $scorm1->timeclose = 0; 676 $DB->update_record('scorm', $scorm1); 677 678 // Create what we expect to be returned when querying the two courses. 679 // First for the student user. 680 $expectedfields = array('id', 'coursemodule', 'course', 'name', 'intro', 'introformat', 'version', 'maxgrade', 681 'grademethod', 'whatgrade', 'maxattempt', 'forcecompleted', 'forcenewattempt', 'lastattemptlock', 682 'displayattemptstatus', 'displaycoursestructure', 'sha1hash', 'md5hash', 'revision', 'launch', 683 'skipview', 'hidebrowse', 'hidetoc', 'nav', 'navpositionleft', 'navpositiontop', 'auto', 684 'popup', 'width', 'height', 'timeopen', 'timeclose', 'displayactivityname', 'packagesize', 685 'packageurl', 'scormtype', 'reference'); 686 687 // Add expected coursemodule and data. 688 $scorm1->coursemodule = $scorm1->cmid; 689 $scorm1->section = 0; 690 $scorm1->visible = true; 691 $scorm1->groupmode = 0; 692 $scorm1->groupingid = 0; 693 694 $scorm2->coursemodule = $scorm2->cmid; 695 $scorm2->section = 0; 696 $scorm2->visible = true; 697 $scorm2->groupmode = 0; 698 $scorm2->groupingid = 0; 699 700 // SCORM size. The same package is used in both SCORMs. 701 $scormcontext1 = context_module::instance($scorm1->cmid); 702 $scormcontext2 = context_module::instance($scorm2->cmid); 703 $fs = get_file_storage(); 704 $packagefile = $fs->get_file($scormcontext1->id, 'mod_scorm', 'package', 0, '/', $scorm1->reference); 705 $packagesize = $packagefile->get_filesize(); 706 707 $packageurl1 = moodle_url::make_webservice_pluginfile_url( 708 $scormcontext1->id, 'mod_scorm', 'package', 0, '/', $scorm1->reference)->out(false); 709 $packageurl2 = moodle_url::make_webservice_pluginfile_url( 710 $scormcontext2->id, 'mod_scorm', 'package', 0, '/', $scorm2->reference)->out(false); 711 712 $scorm1->packagesize = $packagesize; 713 $scorm1->packageurl = $packageurl1; 714 $scorm2->packagesize = $packagesize; 715 $scorm2->packageurl = $packageurl2; 716 717 // Forced to boolean as it is returned as PARAM_BOOL. 718 $protectpackages = (bool)get_config('scorm', 'protectpackagedownloads'); 719 $expected1 = array('protectpackagedownloads' => $protectpackages); 720 $expected2 = array('protectpackagedownloads' => $protectpackages); 721 foreach ($expectedfields as $field) { 722 723 // Since we return the fields used as boolean as PARAM_BOOL instead PARAM_INT we need to force casting here. 724 // From the returned fields definition we obtain the type expected for the field. 725 if (empty($returndescription->keys['scorms']->content->keys[$field]->type)) { 726 continue; 727 } 728 $fieldtype = $returndescription->keys['scorms']->content->keys[$field]->type; 729 if ($fieldtype == PARAM_BOOL) { 730 $expected1[$field] = (bool) $scorm1->{$field}; 731 $expected2[$field] = (bool) $scorm2->{$field}; 732 } else { 733 $expected1[$field] = $scorm1->{$field}; 734 $expected2[$field] = $scorm2->{$field}; 735 } 736 } 737 $expected1['introfiles'] = []; 738 $expected2['introfiles'] = []; 739 740 $expectedscorms = array(); 741 $expectedscorms[] = $expected2; 742 $expectedscorms[] = $expected1; 743 744 // Call the external function passing course ids. 745 $result = mod_scorm_external::get_scorms_by_courses(array($course2->id, $course1->id)); 746 $result = external_api::clean_returnvalue($returndescription, $result); 747 $this->assertEquals($expectedscorms, $result['scorms']); 748 749 // Call the external function without passing course id. 750 $result = mod_scorm_external::get_scorms_by_courses(); 751 $result = external_api::clean_returnvalue($returndescription, $result); 752 $this->assertEquals($expectedscorms, $result['scorms']); 753 754 // Unenrol user from second course and alter expected scorms. 755 $enrol->unenrol_user($instance2, $student->id); 756 array_shift($expectedscorms); 757 758 // Call the external function without passing course id. 759 $result = mod_scorm_external::get_scorms_by_courses(); 760 $result = external_api::clean_returnvalue($returndescription, $result); 761 $this->assertEquals($expectedscorms, $result['scorms']); 762 763 // Call for the second course we unenrolled the user from, expected warning. 764 $result = mod_scorm_external::get_scorms_by_courses(array($course2->id)); 765 $this->assertCount(1, $result['warnings']); 766 $this->assertEquals('1', $result['warnings'][0]['warningcode']); 767 $this->assertEquals($course2->id, $result['warnings'][0]['itemid']); 768 769 // Now, try as a teacher for getting all the additional fields. 770 self::setUser($teacher); 771 772 $additionalfields = array('updatefreq', 'timemodified', 'options', 773 'completionstatusrequired', 'completionscorerequired', 'autocommit', 774 'section', 'visible', 'groupmode', 'groupingid'); 775 776 foreach ($additionalfields as $field) { 777 $fieldtype = $returndescription->keys['scorms']->content->keys[$field]->type; 778 779 if ($fieldtype == PARAM_BOOL) { 780 $expectedscorms[0][$field] = (bool) $scorm1->{$field}; 781 } else { 782 $expectedscorms[0][$field] = $scorm1->{$field}; 783 } 784 } 785 786 $result = mod_scorm_external::get_scorms_by_courses(); 787 $result = external_api::clean_returnvalue($returndescription, $result); 788 $this->assertEquals($expectedscorms, $result['scorms']); 789 790 // Even with the SCORM closed in time teacher should retrieve the info. 791 $scorm1->timeopen = $timenow - DAYSECS; 792 $scorm1->timeclose = $timenow - HOURSECS; 793 $DB->update_record('scorm', $scorm1); 794 795 $expectedscorms[0]['timeopen'] = $scorm1->timeopen; 796 $expectedscorms[0]['timeclose'] = $scorm1->timeclose; 797 798 $result = mod_scorm_external::get_scorms_by_courses(); 799 $result = external_api::clean_returnvalue($returndescription, $result); 800 $this->assertEquals($expectedscorms, $result['scorms']); 801 802 // Admin also should get all the information. 803 self::setAdminUser(); 804 805 $result = mod_scorm_external::get_scorms_by_courses(array($course1->id)); 806 $result = external_api::clean_returnvalue($returndescription, $result); 807 $this->assertEquals($expectedscorms, $result['scorms']); 808 } 809 810 /** 811 * Test launch_sco 812 */ 813 public function test_launch_sco() { 814 global $DB; 815 816 // Test invalid instance id. 817 try { 818 mod_scorm_external::launch_sco(0); 819 $this->fail('Exception expected due to invalid mod_scorm instance id.'); 820 } catch (moodle_exception $e) { 821 $this->assertEquals('invalidrecord', $e->errorcode); 822 } 823 824 // Test not-enrolled user. 825 $user = self::getDataGenerator()->create_user(); 826 $this->setUser($user); 827 try { 828 mod_scorm_external::launch_sco($this->scorm->id); 829 $this->fail('Exception expected due to not enrolled user.'); 830 } catch (moodle_exception $e) { 831 $this->assertEquals('requireloginerror', $e->errorcode); 832 } 833 834 // Test user with full capabilities. 835 $this->setUser($this->student); 836 837 // Trigger and capture the event. 838 $sink = $this->redirectEvents(); 839 840 $scoes = scorm_get_scoes($this->scorm->id); 841 foreach ($scoes as $sco) { 842 // Find launchable SCO. 843 if ($sco->launch != '') { 844 break; 845 } 846 } 847 848 $result = mod_scorm_external::launch_sco($this->scorm->id, $sco->id); 849 $result = external_api::clean_returnvalue(mod_scorm_external::launch_sco_returns(), $result); 850 851 $events = $sink->get_events(); 852 $this->assertCount(1, $events); 853 $event = array_shift($events); 854 855 // Checking that the event contains the expected values. 856 $this->assertInstanceOf('\mod_scorm\event\sco_launched', $event); 857 $this->assertEquals($this->context, $event->get_context()); 858 $moodleurl = new \moodle_url('/mod/scorm/player.php', array('id' => $this->cm->id, 'scoid' => $sco->id)); 859 $this->assertEquals($moodleurl, $event->get_url()); 860 $this->assertEventContextNotUsed($event); 861 $this->assertNotEmpty($event->get_name()); 862 863 // Invalid SCO. 864 try { 865 mod_scorm_external::launch_sco($this->scorm->id, -1); 866 $this->fail('Exception expected due to invalid SCO id.'); 867 } catch (moodle_exception $e) { 868 $this->assertEquals('cannotfindsco', $e->errorcode); 869 } 870 } 871 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |