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 310 and 401] [Versions 39 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  namespace enrol_lti;
  18  
  19  /**
  20   * Test the helper functionality.
  21   *
  22   * @package enrol_lti
  23   * @copyright 2016 Mark Nelson <markn@moodle.com>
  24   * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  25   */
  26  class helper_test extends \advanced_testcase {
  27  
  28      /**
  29       * @var \stdClass $user1 A user.
  30       */
  31      public $user1;
  32  
  33      /**
  34       * @var \stdClass $user2 A user.
  35       */
  36      public $user2;
  37  
  38      /**
  39       * Test set up.
  40       *
  41       * This is executed before running any test in this file.
  42       */
  43      public function setUp(): void {
  44          $this->resetAfterTest();
  45  
  46          // Set this user as the admin.
  47          $this->setAdminUser();
  48  
  49          // Get some of the information we need.
  50          $this->user1 = self::getDataGenerator()->create_user();
  51          $this->user2 = self::getDataGenerator()->create_user();
  52      }
  53  
  54      /**
  55       * Test the update user profile image function.
  56       */
  57      public function test_update_user_profile_image() {
  58          global $DB, $CFG;
  59  
  60          // Set the profile image.
  61          \enrol_lti\helper::update_user_profile_image($this->user1->id, $this->getExternalTestFileUrl('/test.jpg'));
  62  
  63          // Get the new user record.
  64          $this->user1 = $DB->get_record('user', array('id' => $this->user1->id));
  65  
  66          // Set the page details.
  67          $page = new \moodle_page();
  68          $page->set_url('/user/profile.php');
  69          $page->set_context(\context_system::instance());
  70          $renderer = $page->get_renderer('core');
  71          $usercontext = \context_user::instance($this->user1->id);
  72  
  73          // Get the user's profile picture and make sure it is correct.
  74          $userpicture = new \user_picture($this->user1);
  75          $this->assertSame($CFG->wwwroot . '/pluginfile.php/' . $usercontext->id . '/user/icon/boost/f2?rev=' .$this->user1->picture,
  76              $userpicture->get_url($page, $renderer)->out(false));
  77      }
  78  
  79      /**
  80       * Test that we can not enrol past the maximum number of users allowed.
  81       */
  82      public function test_enrol_user_max_enrolled() {
  83          global $DB;
  84  
  85          // Set up the LTI enrolment tool.
  86          $data = new \stdClass();
  87          $data->maxenrolled = 1;
  88          $tool = $this->getDataGenerator()->create_lti_tool($data);
  89  
  90          // Now get all the information we need.
  91          $tool = \enrol_lti\helper::get_lti_tool($tool->id);
  92  
  93          // Enrol a user.
  94          $result = \enrol_lti\helper::enrol_user($tool, $this->user1->id);
  95  
  96          // Check that the user was enrolled.
  97          $this->assertEquals(true, $result);
  98          $this->assertEquals(1, $DB->count_records('user_enrolments', array('enrolid' => $tool->enrolid)));
  99  
 100          // Try and enrol another user - should not happen.
 101          $result = \enrol_lti\helper::enrol_user($tool, $this->user2->id);
 102  
 103          // Check that this user was not enrolled and we are told why.
 104          $this->assertEquals(\enrol_lti\helper::ENROLMENT_MAX_ENROLLED, $result);
 105          $this->assertEquals(1, $DB->count_records('user_enrolments', array('enrolid' => $tool->enrolid)));
 106      }
 107  
 108      /**
 109       * Test that we can not enrol when the enrolment has not started.
 110       */
 111      public function test_enrol_user_enrolment_not_started() {
 112          global $DB;
 113  
 114          // Set up the LTI enrolment tool.
 115          $data = new \stdClass();
 116          $data->enrolstartdate = time() + DAYSECS; // Make sure it is in the future.
 117          $tool = $this->getDataGenerator()->create_lti_tool($data);
 118  
 119          // Now get all the information we need.
 120          $tool = \enrol_lti\helper::get_lti_tool($tool->id);
 121  
 122          // Try and enrol a user - should not happen.
 123          $result = \enrol_lti\helper::enrol_user($tool, $this->user1->id);
 124  
 125          // Check that this user was not enrolled and we are told why.
 126          $this->assertEquals(\enrol_lti\helper::ENROLMENT_NOT_STARTED, $result);
 127          $this->assertEquals(0, $DB->count_records('user_enrolments', array('enrolid' => $tool->enrolid)));
 128      }
 129  
 130      /**
 131       * Test that we can not enrol when the enrolment has finished.
 132       */
 133      public function test_enrol_user_enrolment_finished() {
 134          global $DB;
 135  
 136          // Set up the LTI enrolment tool.
 137          $data = new \stdClass();
 138          $data->enrolenddate = time() - DAYSECS; // Make sure it is in the past.
 139          $tool = $this->getDataGenerator()->create_lti_tool($data);
 140  
 141          // Now get all the information we need.
 142          $tool = \enrol_lti\helper::get_lti_tool($tool->id);
 143  
 144          // Try and enrol a user - should not happen.
 145          $result = \enrol_lti\helper::enrol_user($tool, $this->user1->id);
 146  
 147          // Check that this user was not enrolled and we are told why.
 148          $this->assertEquals(\enrol_lti\helper::ENROLMENT_FINISHED, $result);
 149          $this->assertEquals(0, $DB->count_records('user_enrolments', array('enrolid' => $tool->enrolid)));
 150      }
 151  
 152      /**
 153       * Test returning the number of available tools.
 154       */
 155      public function test_count_lti_tools() {
 156          $generator = $this->getDataGenerator();
 157          // Create two tools belonging to the same course.
 158          $course1 = $generator->create_course();
 159          $data = new \stdClass();
 160          $data->courseid = $course1->id;
 161          $generator->create_lti_tool($data);
 162          $generator->create_lti_tool($data);
 163  
 164          // Create two more tools in a separate course.
 165          $course2 = $this->getDataGenerator()->create_course();
 166          $data = new \stdClass();
 167          $data->courseid = $course2->id;
 168          $generator->create_lti_tool($data);
 169  
 170          // Set the next tool to disabled.
 171          $data->status = ENROL_INSTANCE_DISABLED;
 172          $generator->create_lti_tool($data);
 173  
 174          // Count all the tools.
 175          $count = \enrol_lti\helper::count_lti_tools();
 176          $this->assertEquals(4, $count);
 177  
 178          // Count all the tools in course 1.
 179          $count = \enrol_lti\helper::count_lti_tools(array('courseid' => $course1->id));
 180          $this->assertEquals(2, $count);
 181  
 182          // Count all the tools in course 2 that are disabled.
 183          $count = \enrol_lti\helper::count_lti_tools(array('courseid' => $course2->id, 'status' => ENROL_INSTANCE_DISABLED));
 184          $this->assertEquals(1, $count);
 185  
 186          // Count all the tools that are enabled.
 187          $count = \enrol_lti\helper::count_lti_tools(array('status' => ENROL_INSTANCE_ENABLED));
 188          $this->assertEquals(3, $count);
 189      }
 190  
 191      /**
 192       * Test returning the list of available tools.
 193       */
 194      public function test_get_lti_tools() {
 195          $generator = $this->getDataGenerator();
 196          // Create two tools belonging to the same course.
 197          $course1 = $generator->create_course();
 198          $data = new \stdClass();
 199          $data->courseid = $course1->id;
 200          $tool1 = $generator->create_lti_tool($data);
 201          $tool2 = $generator->create_lti_tool($data);
 202  
 203          // Create two more tools in a separate course.
 204          $course2 = $generator->create_course();
 205          $data = new \stdClass();
 206          $data->courseid = $course2->id;
 207          $tool3 = $generator->create_lti_tool($data);
 208  
 209          // Set the next tool to disabled.
 210          $data->status = ENROL_INSTANCE_DISABLED;
 211          $tool4 = $generator->create_lti_tool($data);
 212  
 213          // Get all the tools.
 214          $tools = \enrol_lti\helper::get_lti_tools();
 215  
 216          // Check that we got all the tools.
 217          $this->assertEquals(4, count($tools));
 218  
 219          // Get all the tools in course 1.
 220          $tools = \enrol_lti\helper::get_lti_tools(array('courseid' => $course1->id));
 221  
 222          // Check that we got all the tools in course 1.
 223          $this->assertEquals(2, count($tools));
 224          $this->assertTrue(isset($tools[$tool1->id]));
 225          $this->assertTrue(isset($tools[$tool2->id]));
 226  
 227          // Get all the tools in course 2 that are disabled.
 228          $tools = \enrol_lti\helper::get_lti_tools(array('courseid' => $course2->id, 'status' => ENROL_INSTANCE_DISABLED));
 229  
 230          // Check that we got all the tools in course 2 that are disabled.
 231          $this->assertEquals(1, count($tools));
 232          $this->assertTrue(isset($tools[$tool4->id]));
 233  
 234          // Get all the tools that are enabled.
 235          $tools = \enrol_lti\helper::get_lti_tools(array('status' => ENROL_INSTANCE_ENABLED));
 236  
 237          // Check that we got all the tools that are enabled.
 238          $this->assertEquals(3, count($tools));
 239          $this->assertTrue(isset($tools[$tool1->id]));
 240          $this->assertTrue(isset($tools[$tool2->id]));
 241          $this->assertTrue(isset($tools[$tool3->id]));
 242      }
 243  
 244      /**
 245       * Test getting the launch url of a tool.
 246       */
 247      public function test_get_launch_url() {
 248          $course1 = $this->getDataGenerator()->create_course();
 249          $data = new \stdClass();
 250          $data->courseid = $course1->id;
 251          $tool1 = $this->getDataGenerator()->create_lti_tool($data);
 252  
 253          $id = $tool1->id;
 254          $launchurl = \enrol_lti\helper::get_launch_url($id);
 255          $this->assertEquals('https://www.example.com/moodle/enrol/lti/tool.php?id=' . $id, $launchurl->out());
 256      }
 257  
 258      /**
 259       * Test getting the cartridge url of a tool.
 260       */
 261      public function test_get_cartridge_url() {
 262          global $CFG;
 263  
 264          $slasharguments = $CFG->slasharguments;
 265  
 266          $CFG->slasharguments = false;
 267  
 268          $course1 = $this->getDataGenerator()->create_course();
 269          $data = new \stdClass();
 270          $data->courseid = $course1->id;
 271          $tool1 = $this->getDataGenerator()->create_lti_tool($data);
 272  
 273          $id = $tool1->id;
 274          $token = \enrol_lti\helper::generate_cartridge_token($id);
 275          $launchurl = \enrol_lti\helper::get_cartridge_url($tool1);
 276          $this->assertEquals('https://www.example.com/moodle/enrol/lti/cartridge.php?id=' . $id . '&amp;token=' . $token,
 277                              $launchurl->out());
 278  
 279          $CFG->slasharguments = true;
 280  
 281          $launchurl = \enrol_lti\helper::get_cartridge_url($tool1);
 282          $this->assertEquals('https://www.example.com/moodle/enrol/lti/cartridge.php/' . $id . '/' . $token . '/cartridge.xml',
 283                              $launchurl->out());
 284  
 285          $CFG->slasharguments = $slasharguments;
 286      }
 287  
 288      /**
 289       * Test getting the cartridge url of a tool.
 290       */
 291      public function test_get_proxy_url() {
 292          global $CFG;
 293  
 294          $slasharguments = $CFG->slasharguments;
 295  
 296          $CFG->slasharguments = false;
 297  
 298          $course1 = $this->getDataGenerator()->create_course();
 299          $data = new \stdClass();
 300          $data->courseid = $course1->id;
 301          $tool1 = $this->getDataGenerator()->create_lti_tool($data);
 302  
 303          $id = $tool1->id;
 304          $token = \enrol_lti\helper::generate_proxy_token($id);
 305          $launchurl = \enrol_lti\helper::get_proxy_url($tool1);
 306          $this->assertEquals('https://www.example.com/moodle/enrol/lti/proxy.php?id=' . $id . '&amp;token=' . $token,
 307                              $launchurl->out());
 308  
 309          $CFG->slasharguments = true;
 310  
 311          $launchurl = \enrol_lti\helper::get_proxy_url($tool1);
 312          $this->assertEquals('https://www.example.com/moodle/enrol/lti/proxy.php/' . $id . '/' . $token . '/',
 313                              $launchurl->out());
 314  
 315          $CFG->slasharguments = $slasharguments;
 316      }
 317  
 318      /**
 319       * Test getting the name of a tool.
 320       */
 321      public function test_get_name() {
 322          $course1 = $this->getDataGenerator()->create_course();
 323          $data = new \stdClass();
 324          $data->courseid = $course1->id;
 325          $tool1 = $this->getDataGenerator()->create_lti_tool($data);
 326  
 327          $name = \enrol_lti\helper::get_name($tool1);
 328          $this->assertEquals('Course: Test course 1', $name);
 329  
 330          $tool1->name = 'Shared course';
 331          $name = \enrol_lti\helper::get_name($tool1);
 332          $this->assertEquals('Shared course', $name);
 333      }
 334  
 335      /**
 336       * Test getting the description of a tool.
 337       */
 338      public function test_get_description() {
 339          $generator = $this->getDataGenerator();
 340          $course1 = $generator->create_course();
 341          $data = new \stdClass();
 342          $data->courseid = $course1->id;
 343          $tool1 = $generator->create_lti_tool($data);
 344  
 345          $description = \enrol_lti\helper::get_description($tool1);
 346          $this->assertStringContainsString('Test course 1 Lorem ipsum dolor sit amet', $description);
 347  
 348          $module1 = $generator->create_module('assign', array(
 349                  'course' => $course1->id
 350              ));
 351          $data = new \stdClass();
 352          $data->cmid = $module1->cmid;
 353          $tool2 = $generator->create_lti_tool($data);
 354          $description = \enrol_lti\helper::get_description($tool2);
 355          $this->assertStringContainsString('Test assign 1', $description);
 356      }
 357  
 358      /**
 359       * Test getting the icon of a tool.
 360       */
 361      public function test_get_icon() {
 362          global $CFG;
 363  
 364          $course1 = $this->getDataGenerator()->create_course();
 365          $data = new \stdClass();
 366          $data->courseid = $course1->id;
 367          $tool = $this->getDataGenerator()->create_lti_tool($data);
 368  
 369          $icon = \enrol_lti\helper::get_icon($tool);
 370          $icon = $icon->out();
 371          // Only local icons are supported by the LTI framework.
 372          $this->assertStringContainsString($CFG->wwwroot, $icon);
 373  
 374      }
 375  
 376      /**
 377       * Test verifying a cartridge token.
 378       */
 379      public function test_verify_cartridge_token() {
 380          $course1 = $this->getDataGenerator()->create_course();
 381          $data = new \stdClass();
 382          $data->courseid = $course1->id;
 383          $tool1 = $this->getDataGenerator()->create_lti_tool($data);
 384  
 385          $token = \enrol_lti\helper::generate_cartridge_token($tool1->id);
 386          $this->assertTrue(\enrol_lti\helper::verify_cartridge_token($tool1->id, $token));
 387          $this->assertFalse(\enrol_lti\helper::verify_cartridge_token($tool1->id, 'incorrect token!'));
 388      }
 389  
 390      /**
 391       * Test verifying a proxy token.
 392       */
 393      public function test_verify_proxy_token() {
 394          $course1 = $this->getDataGenerator()->create_course();
 395          $data = new \stdClass();
 396          $data->courseid = $course1->id;
 397          $tool1 = $this->getDataGenerator()->create_lti_tool($data);
 398  
 399          $token = \enrol_lti\helper::generate_proxy_token($tool1->id);
 400          $this->assertTrue(\enrol_lti\helper::verify_proxy_token($tool1->id, $token));
 401          $this->assertFalse(\enrol_lti\helper::verify_proxy_token($tool1->id, 'incorrect token!'));
 402      }
 403  
 404      /**
 405       * Data provider for the set_xpath test.
 406       */
 407      public function set_xpath_provider() {
 408          return [
 409              "Correct structure" => [
 410                  "parameters" => [
 411                      "/root" => [
 412                          "/firstnode" => "Content 1",
 413                          "/parentnode" => [
 414                              "/childnode" => "Content 2"
 415                          ]
 416                      ]
 417                  ],
 418                  "expected" => "test_correct_xpath-expected.xml"
 419              ],
 420              "A null value, but no node to remove" => [
 421                  "parameters" => [
 422                      "/root" => [
 423                          "/nonexistant" => null,
 424                          "/firstnode" => "Content 1"
 425                      ]
 426                  ],
 427                  "expected" => "test_missing_node-expected.xml"
 428              ],
 429              "A string value, but no node existing to set" => [
 430                  "parameters" => [
 431                      "/root" => [
 432                          "/nonexistant" => "This will not be set",
 433                          "/firstnode" => "Content 1"
 434                      ]
 435                  ],
 436                  "expected" => "test_missing_node-expected.xml"
 437              ],
 438              "Array but no children exist" => [
 439                  "parameters" => [
 440                      "/root" => [
 441                          "/nonexistant" => [
 442                              "/alsononexistant" => "This will not be set"
 443                          ],
 444                          "/firstnode" => "Content 1"
 445                      ]
 446                  ],
 447                  "expected" => "test_missing_node-expected.xml"
 448              ],
 449              "Remove nodes" => [
 450                  "parameters" => [
 451                      "/root" => [
 452                          "/parentnode" => [
 453                              "/childnode" => null
 454                          ],
 455                          "/firstnode" => null
 456                      ]
 457                  ],
 458                  "expected" => "test_nodes_removed-expected.xml"
 459              ],
 460              "Get by attribute" => [
 461                  "parameters" => [
 462                      "/root" => [
 463                          "/ambiguous[@id='1']" => 'Content 1'
 464                      ]
 465                  ],
 466                  "expected" => "test_ambiguous_nodes-expected.xml"
 467              ]
 468          ];
 469      }
 470  
 471      /**
 472       * Test set_xpath.
 473       * @dataProvider set_xpath_provider
 474       * @param array $parameters A hash of parameters represented by a heirarchy of xpath expressions
 475       * @param string $expected The name of the fixture file containing the expected result.
 476       */
 477      public function test_set_xpath($parameters, $expected) {
 478          $helper = new \ReflectionClass('enrol_lti\\helper');
 479          $function = $helper->getMethod('set_xpath');
 480          $function->setAccessible(true);
 481  
 482          $document = new \DOMDocument();
 483          $document->load(realpath(__DIR__ . '/fixtures/input.xml'));
 484          $xpath = new \DOMXpath($document);
 485          $function->invokeArgs(null, [$xpath, $parameters]);
 486          $result = $document->saveXML();
 487          $expected = file_get_contents(realpath(__DIR__ . '/fixtures/' . $expected));
 488          $this->assertEquals($expected, $result);
 489      }
 490  
 491      /**
 492       * Test set_xpath when an incorrect xpath expression is given.
 493       */
 494      public function test_set_xpath_incorrect_xpath() {
 495          $parameters = [
 496              "/root" => [
 497                  "/firstnode" => null,
 498                  "/parentnode*&#^*#(" => [
 499                      "/childnode" => null
 500                  ],
 501              ]
 502          ];
 503          $helper = new \ReflectionClass('enrol_lti\\helper');
 504          $function = $helper->getMethod('set_xpath');
 505          $function->setAccessible(true);
 506  
 507          $document = new \DOMDocument();
 508          $document->load(realpath(__DIR__ . '/fixtures/input.xml'));
 509          $xpath = new \DOMXpath($document);
 510  
 511          $this->expectException('coding_exception');
 512          $function->invokeArgs(null, [$xpath, $parameters]);
 513      }
 514  
 515      /**
 516       * Test create cartridge.
 517       */
 518      public function test_create_cartridge() {
 519          global $CFG;
 520  
 521          $course1 = $this->getDataGenerator()->create_course();
 522          $data = new \stdClass();
 523          $data->courseid = $course1->id;
 524          $tool1 = $this->getDataGenerator()->create_lti_tool($data);
 525  
 526          $cartridge = \enrol_lti\helper::create_cartridge($tool1->id);
 527          $this->assertStringContainsString('<blti:title>Test LTI</blti:title>', $cartridge);
 528          $this->assertStringContainsString("<blti:icon>$CFG->wwwroot/theme/image.php/_s/boost/theme/1/favicon</blti:icon>", $cartridge);
 529          $this->assertStringContainsString("<blti:launch_url>$CFG->wwwroot/enrol/lti/tool.php?id=$tool1->id</blti:launch_url>", $cartridge);
 530      }
 531  }