[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/mod/scorm/tests/ -> externallib_test.php (source)

   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  }


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1