Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403] [Versions 39 and 310]

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