Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 311 and 401] [Versions 400 and 401] [Versions 401 and 403]

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  18   * Base class for unit tests for mod_scorm.
  19   *
  20   * @package    mod_scorm
  21   * @category   test
  22   * @copyright  2018 Sara Arjona <sara@moodle.com>
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  namespace mod_scorm\privacy;
  26  
  27  defined('MOODLE_INTERNAL') || die();
  28  
  29  use mod_scorm\privacy\provider;
  30  use core_privacy\local\request\approved_contextlist;
  31  use core_privacy\local\request\approved_userlist;
  32  use core_privacy\local\request\writer;
  33  use core_privacy\tests\provider_testcase;
  34  
  35  /**
  36   * Unit tests for mod\scorm\classes\privacy\provider.php
  37   *
  38   * @copyright  2018 Sara Arjona <sara@moodle.com>
  39   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  40   */
  41  class provider_test extends provider_testcase {
  42  
  43      /** @var stdClass User without any AICC/SCORM attempt. */
  44      protected $student0;
  45  
  46      /** @var stdClass User with some AICC/SCORM attempt. */
  47      protected $student1;
  48  
  49      /** @var stdClass User with some AICC/SCORM attempt. */
  50      protected $student2;
  51  
  52      /** @var context context_module of the SCORM activity. */
  53      protected $context;
  54  
  55      /**
  56       * Test getting the context for the user ID related to this plugin.
  57       */
  58      public function test_get_contexts_for_userid() {
  59          $this->resetAfterTest(true);
  60          $this->setAdminUser();
  61          $this->scorm_setup_test_scenario_data();
  62  
  63          // The student0 hasn't any attempt.
  64          $contextlist = provider::get_contexts_for_userid($this->student0->id);
  65          $this->assertCount(0, (array) $contextlist->get_contextids());
  66  
  67          // The student1 has data in the SCORM context.
  68          $contextlist = provider::get_contexts_for_userid($this->student1->id);
  69          $this->assertCount(1, (array) $contextlist->get_contextids());
  70          $this->assertContainsEquals($this->context->id, $contextlist->get_contextids());
  71      }
  72  
  73      /**
  74       * Test getting the user IDs for the context related to this plugin.
  75       */
  76      public function test_get_users_in_context() {
  77          $this->resetAfterTest(true);
  78          $this->setAdminUser();
  79          $this->scorm_setup_test_scenario_data();
  80          $component = 'mod_scorm';
  81  
  82          $userlist = new \core_privacy\local\request\userlist($this->context, $component);
  83          provider::get_users_in_context($userlist);
  84  
  85          // Students 1 and 2 have attempts in the SCORM context, student 0 does not.
  86          $this->assertCount(2, $userlist);
  87  
  88          $expected = [$this->student1->id, $this->student2->id];
  89          $actual = $userlist->get_userids();
  90          sort($expected);
  91          sort($actual);
  92          $this->assertEquals($expected, $actual);
  93      }
  94  
  95      /**
  96       * Test that data is exported correctly for this plugin.
  97       */
  98      public function test_export_user_data() {
  99          $this->resetAfterTest(true);
 100          $this->setAdminUser();
 101          $this->scorm_setup_test_scenario_data();
 102  
 103          // Validate exported data for student0 (without any AICC/SCORM attempt).
 104          $this->setUser($this->student0);
 105          $writer = writer::with_context($this->context);
 106  
 107          $this->export_context_data_for_user($this->student0->id, $this->context, 'mod_scorm');
 108          $subcontextattempt1 = [
 109              get_string('myattempts', 'scorm'),
 110              get_string('attempt', 'scorm'). " 1"
 111          ];
 112          $subcontextaicc = [
 113              get_string('myaiccsessions', 'scorm')
 114          ];
 115          $data = $writer->get_data($subcontextattempt1);
 116          $this->assertEmpty($data);
 117          $data = $writer->get_data($subcontextaicc);
 118          $this->assertEmpty($data);
 119  
 120          // Validate exported data for student1.
 121          writer::reset();
 122          $this->setUser($this->student1);
 123          $writer = writer::with_context($this->context);
 124          $this->assertFalse($writer->has_any_data());
 125          $this->export_context_data_for_user($this->student1->id, $this->context, 'mod_scorm');
 126  
 127          $data = $writer->get_data([]);
 128          $this->assertEquals('SCORM1', $data->name);
 129  
 130          $data = (array)$writer->get_data($subcontextattempt1);
 131          $this->assertCount(1, $data);
 132          $this->assertCount(2, (array) reset($data));
 133          $subcontextattempt2 = [
 134              get_string('myattempts', 'scorm'),
 135              get_string('attempt', 'scorm'). " 2"
 136          ];
 137          $data = (array)$writer->get_data($subcontextattempt2);
 138          $this->assertCount(2, (array) reset($data));
 139          // The student1 has only 2 scoes_track attempts.
 140          $subcontextattempt3 = [
 141              get_string('myattempts', 'scorm'),
 142              get_string('attempt', 'scorm'). " 3"
 143          ];
 144          $data = $writer->get_data($subcontextattempt3);
 145          $this->assertEmpty($data);
 146          // The student1 has only 1 aicc_session.
 147          $data = $writer->get_data($subcontextaicc);
 148          $this->assertCount(1, (array) $data);
 149      }
 150  
 151      /**
 152       * Test for provider::delete_data_for_all_users_in_context().
 153       */
 154      public function test_delete_data_for_all_users_in_context() {
 155          global $DB;
 156  
 157          $this->resetAfterTest(true);
 158          $this->setAdminUser();
 159          $this->scorm_setup_test_scenario_data();
 160  
 161          // Before deletion, we should have 8 entries in the scorm_scoes_track table.
 162          $count = $DB->count_records('scorm_scoes_track');
 163          $this->assertEquals(8, $count);
 164          // Before deletion, we should have 4 entries in the scorm_aicc_session table.
 165          $count = $DB->count_records('scorm_aicc_session');
 166          $this->assertEquals(4, $count);
 167  
 168          // Delete data based on the context.
 169          provider::delete_data_for_all_users_in_context($this->context);
 170  
 171          // After deletion, the scorm_scoes_track entries should have been deleted.
 172          $count = $DB->count_records('scorm_scoes_track');
 173          $this->assertEquals(0, $count);
 174          // After deletion, the scorm_aicc_session entries should have been deleted.
 175          $count = $DB->count_records('scorm_aicc_session');
 176          $this->assertEquals(0, $count);
 177      }
 178  
 179      /**
 180       * Test for provider::delete_data_for_user().
 181       */
 182      public function test_delete_data_for_user() {
 183          global $DB;
 184  
 185          $this->resetAfterTest(true);
 186          $this->setAdminUser();
 187          $this->scorm_setup_test_scenario_data();
 188  
 189          // Before deletion, we should have 8 entries in the scorm_scoes_track table.
 190          $count = $DB->count_records('scorm_scoes_track');
 191          $this->assertEquals(8, $count);
 192          // Before deletion, we should have 4 entries in the scorm_aicc_session table.
 193          $count = $DB->count_records('scorm_aicc_session');
 194          $this->assertEquals(4, $count);
 195  
 196          $approvedcontextlist = new approved_contextlist($this->student1, 'scorm', [$this->context->id]);
 197          provider::delete_data_for_user($approvedcontextlist);
 198  
 199          // After deletion, the scorm_scoes_track entries for the first student should have been deleted.
 200          $count = $DB->count_records('scorm_scoes_track', ['userid' => $this->student1->id]);
 201          $this->assertEquals(0, $count);
 202          $count = $DB->count_records('scorm_scoes_track');
 203          $this->assertEquals(4, $count);
 204          // After deletion, the scorm_aicc_session entries for the first student should have been deleted.
 205          $count = $DB->count_records('scorm_aicc_session', ['userid' => $this->student1->id]);
 206          $this->assertEquals(0, $count);
 207          $count = $DB->count_records('scorm_aicc_session');
 208          $this->assertEquals(2, $count);
 209  
 210          // Confirm that the SCORM hasn't been removed.
 211          $scormcount = $DB->get_records('scorm');
 212          $this->assertCount(1, (array) $scormcount);
 213  
 214          // Delete scoes_track for student0 (nothing has to be removed).
 215          $approvedcontextlist = new approved_contextlist($this->student0, 'scorm', [$this->context->id]);
 216          provider::delete_data_for_user($approvedcontextlist);
 217          $count = $DB->count_records('scorm_scoes_track');
 218          $this->assertEquals(4, $count);
 219          $count = $DB->count_records('scorm_aicc_session');
 220          $this->assertEquals(2, $count);
 221      }
 222  
 223      /**
 224       * Test for provider::delete_data_for_users().
 225       */
 226      public function test_delete_data_for_users() {
 227          global $DB;
 228          $component = 'mod_scorm';
 229  
 230          $this->resetAfterTest(true);
 231          $this->setAdminUser();
 232          $this->scorm_setup_test_scenario_data();
 233  
 234          // Before deletion, we should have 8 entries in the scorm_scoes_track table.
 235          $count = $DB->count_records('scorm_scoes_track');
 236          $this->assertEquals(8, $count);
 237          // Before deletion, we should have 4 entries in the scorm_aicc_session table.
 238          $count = $DB->count_records('scorm_aicc_session');
 239          $this->assertEquals(4, $count);
 240  
 241          // Delete only student 1's data, retain student 2's data.
 242          $approveduserids = [$this->student1->id];
 243          $approvedlist = new approved_userlist($this->context, $component, $approveduserids);
 244          provider::delete_data_for_users($approvedlist);
 245  
 246          // After deletion, the scorm_scoes_track entries for the first student should have been deleted.
 247          $count = $DB->count_records('scorm_scoes_track', ['userid' => $this->student1->id]);
 248          $this->assertEquals(0, $count);
 249          $count = $DB->count_records('scorm_scoes_track');
 250          $this->assertEquals(4, $count);
 251  
 252          // After deletion, the scorm_aicc_session entries for the first student should have been deleted.
 253          $count = $DB->count_records('scorm_aicc_session', ['userid' => $this->student1->id]);
 254          $this->assertEquals(0, $count);
 255          $count = $DB->count_records('scorm_aicc_session');
 256          $this->assertEquals(2, $count);
 257  
 258          // Confirm that the SCORM hasn't been removed.
 259          $scormcount = $DB->get_records('scorm');
 260          $this->assertCount(1, (array) $scormcount);
 261  
 262          // Delete scoes_track for student0 (nothing has to be removed).
 263          $approveduserids = [$this->student0->id];
 264          $approvedlist = new approved_userlist($this->context, $component, $approveduserids);
 265          provider::delete_data_for_users($approvedlist);
 266  
 267          $count = $DB->count_records('scorm_scoes_track');
 268          $this->assertEquals(4, $count);
 269          $count = $DB->count_records('scorm_aicc_session');
 270          $this->assertEquals(2, $count);
 271      }
 272  
 273      /**
 274       * Helper function to setup 3 users and 2 SCORM attempts for student1 and student2.
 275       * $this->student0 is always created without any attempt.
 276       */
 277      protected function scorm_setup_test_scenario_data() {
 278          global $DB;
 279  
 280          set_config('allowaicchacp', 1, 'scorm');
 281  
 282          // Setup test data.
 283          $course = $this->getDataGenerator()->create_course();
 284          $params = array('course' => $course->id, 'name' => 'SCORM1');
 285          $scorm = $this->getDataGenerator()->create_module('scorm', $params);
 286          $this->context = \context_module::instance($scorm->cmid);
 287  
 288          // Users enrolments.
 289          $studentrole = $DB->get_record('role', array('shortname' => 'student'));
 290  
 291          // Create student0 withot any SCORM attempt.
 292          $this->student0 = self::getDataGenerator()->create_user();
 293          $this->getDataGenerator()->enrol_user($this->student0->id, $course->id, $studentrole->id, 'manual');
 294  
 295          // Create student1 with 2 SCORM attempts and 1 AICC session.
 296          $this->student1 = self::getDataGenerator()->create_user();
 297          $this->getDataGenerator()->enrol_user($this->student1->id, $course->id, $studentrole->id, 'manual');
 298          static::scorm_insert_attempt($scorm, $this->student1->id, 1);
 299          static::scorm_insert_attempt($scorm, $this->student1->id, 2);
 300  
 301          // Create student2 with 2 SCORM attempts and 1 AICC session.
 302          $this->student2 = self::getDataGenerator()->create_user();
 303          $this->getDataGenerator()->enrol_user($this->student2->id, $course->id, $studentrole->id, 'manual');
 304          static::scorm_insert_attempt($scorm, $this->student2->id, 1);
 305          static::scorm_insert_attempt($scorm, $this->student2->id, 2);
 306      }
 307  
 308      /**
 309       * Create a SCORM attempt.
 310       *
 311       * @param  object $scorm SCORM activity.
 312       * @param  int $userid  Userid who is doing the attempt.
 313       * @param  int $attempt Number of attempt.
 314       */
 315      protected function scorm_insert_attempt($scorm, $userid, $attempt) {
 316          global $DB;
 317  
 318          $newattempt = 'on';
 319          $mode = 'normal';
 320          scorm_check_mode($scorm, $newattempt, $attempt, $userid, $mode);
 321          $scoes = scorm_get_scoes($scorm->id);
 322          $sco = array_pop($scoes);
 323          scorm_insert_track($userid, $scorm->id, $sco->id, $attempt, 'cmi.core.lesson_status', 'completed');
 324          scorm_insert_track($userid, $scorm->id, $sco->id, $attempt, 'cmi.score.min', '0');
 325          $now = time();
 326          $hacpsession = [
 327              'scormid' => $scorm->id,
 328              'attempt' => $attempt,
 329              'hacpsession' => random_string(20),
 330              'userid' => $userid,
 331              'timecreated' => $now,
 332              'timemodified' => $now
 333          ];
 334          $DB->insert_record('scorm_aicc_session', $hacpsession);
 335      }
 336  }