Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.0.x will end 8 May 2023 (12 months).
  • Bug fixes for security issues in 4.0.x will end 13 November 2023 (18 months).
  • PHP version: minimum PHP 7.3.0 Note: the minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is also supported.
   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\local\ltiadvantage\repository;
  18  use enrol_lti\local\ltiadvantage\entity\application_registration;
  19  use enrol_lti\local\ltiadvantage\entity\deployment;
  20  
  21  /**
  22   * Tests for the application_registration_repository.
  23   *
  24   * @package enrol_lti
  25   * @copyright 2021 Jake Dallimore <jrhdallimore@gmail.com>
  26   * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  27   * @coversDefaultClass \enrol_lti\local\ltiadvantage\repository\application_registration_repository
  28   */
  29  class application_registration_repository_test extends \advanced_testcase {
  30      /**
  31       * Helper to generate a new application_registration object.
  32       *
  33       * @param string|null $issuer the issuer of the application, or null to use a default.
  34       * @param string|null $uniqueid unique id for the tool registration, or null to use a default.
  35       * @param string|null $clientid the clientid of the platform's tool registration, or null to use a default.
  36       * @return application_registration the application_registration instance.
  37       */
  38      protected function generate_application_registration(string $issuer = null, string $uniqueid = null,
  39              string $clientid = null): application_registration {
  40  
  41          $issuer = $issuer ?? 'https://lms.example.org';
  42          $uniqueid = $uniqueid ?? 'a2c94a2c94';
  43          $clientid = $clientid ?? 'clientid_123';
  44          return application_registration::create(
  45              'Example LMS application',
  46              $uniqueid,
  47              new \moodle_url($issuer),
  48              $clientid,
  49              new \moodle_url('https://example.org/authrequesturl'),
  50              new \moodle_url('https://example.org/jwksurl'),
  51              new \moodle_url('https://example.org/accesstokenurl')
  52          );
  53      }
  54  
  55      /**
  56       * Helper to assert that all the key elements of two registrations (i.e. excluding id) are equal.
  57       *
  58       * @param application_registration $expected the registration whose values are deemed correct.
  59       * @param application_registration $check the registration to check.
  60       */
  61      protected function assert_same_registration_values(application_registration $expected,
  62              application_registration $check): void {
  63          $this->assertEquals($expected->get_name(), $check->get_name());
  64          $this->assertEquals($expected->get_platformid(), $check->get_platformid());
  65          $this->assertEquals($expected->get_clientid(), $check->get_clientid());
  66          $this->assertEquals($expected->get_authenticationrequesturl(),
  67              $check->get_authenticationrequesturl());
  68          $this->assertEquals($expected->get_jwksurl(), $check->get_jwksurl());
  69          $this->assertEquals($expected->get_accesstokenurl(), $check->get_accesstokenurl());
  70          $this->assertEquals($expected->is_complete(), $check->is_complete());
  71          $this->assertEquals($expected->get_uniqueid(), $check->get_uniqueid());
  72      }
  73  
  74      /**
  75       * Helper to assert that all the key elements of an application_registration are present in the DB.
  76       *
  77       * @param application_registration $registration
  78       */
  79      protected function assert_registration_db_values(application_registration $registration) {
  80          global $DB;
  81          $record = $DB->get_record('enrol_lti_app_registration', ['id' => $registration->get_id()]);
  82          $this->assertEquals($registration->get_id(), $record->id);
  83          $this->assertEquals($registration->get_name(), $record->name);
  84          $this->assertEquals($registration->get_platformid(), $record->platformid);
  85          $this->assertEquals($registration->get_clientid(), $record->clientid);
  86          $this->assertEquals($registration->get_authenticationrequesturl(), $record->authenticationrequesturl);
  87          $this->assertEquals($registration->get_jwksurl(), $record->jwksurl);
  88          $this->assertEquals($registration->get_accesstokenurl(), $record->accesstokenurl);
  89          $expectedstatus = $registration->is_complete() ? application_registration::REGISTRATION_STATUS_COMPLETE
  90              : application_registration::REGISTRATION_STATUS_INCOMPLETE;
  91          $this->assertEquals($expectedstatus, $record->status);
  92          $this->assertNotEmpty($record->timecreated);
  93          $this->assertNotEmpty($record->timemodified);
  94      }
  95  
  96      /**
  97       * Tests saving application_registration instances using the repository.
  98       *
  99       * @dataProvider save_data_provider
 100       * @covers ::save
 101       * @param array $regdata the registration data
 102       */
 103      public function test_save_new(array $regdata) {
 104          $this->resetAfterTest();
 105  
 106          $reg = application_registration::create_draft($regdata['name'], $regdata['uniqueid']);
 107          if (isset($regdata['platformid'])) {
 108              $reg->set_platformid($regdata['platformid']);
 109          }
 110          if (isset($regdata['clientid'])) {
 111              $reg->set_clientid($regdata['clientid']);
 112          }
 113          if (isset($regdata['authenticationrequesturl'])) {
 114              $reg->set_authenticationrequesturl($regdata['authenticationrequesturl']);
 115          }
 116          if (isset($regdata['jwksurl'])) {
 117              $reg->set_jwksurl($regdata['jwksurl']);
 118          }
 119          if (isset($regdata['accesstokenurl'])) {
 120              $reg->set_accesstokenurl($regdata['accesstokenurl']);
 121          }
 122          if (!empty($regdata['setcomplete'])) {
 123              $reg->complete_registration();
 124          }
 125          $repository = new application_registration_repository();
 126          $createdregistration = $repository->save($reg);
 127  
 128          $this->assert_same_registration_values($reg, $createdregistration);
 129          $this->assert_registration_db_values($createdregistration);
 130  
 131      }
 132  
 133      /**
 134       * Provides registrations in different states for use in test_save_new.
 135       *
 136       * @return array the array of test data.
 137       */
 138      public function save_data_provider(): array {
 139          return [
 140              'minimal draft' => [
 141                  'registrationdata' => [
 142                      'name' => 'My test platform',
 143                      'uniqueid' => 'acbhd4355',
 144                  ]
 145              ],
 146              'draft with only some properties completed' => [
 147                  'registrationdata' => [
 148                      'name' => 'My test platform',
 149                      'uniqueid' => 'acbhd4355',
 150                      'platformid' => new \moodle_url('https://lms.example.com'),
 151                      'clientid' => 'abc345',
 152                  ]
 153              ],
 154              'draft with all fields completed, not marked complete' => [
 155                  'registrationdata' => [
 156                      'name' => 'My test platform',
 157                      'uniqueid' => 'acbhd4355',
 158                      'platformid' => new \moodle_url('https://lms.example.com'),
 159                      'clientid' => 'abc345',
 160                      'authenticationrequesturl' => new \moodle_url('https://lms.example.com/auth'),
 161                      'jwksurl' => new \moodle_url('https://lms.example.com/jwks'),
 162                      'accesstokenurl' => new \moodle_url('https://lms.example.com/token'),
 163                  ]
 164              ],
 165              'draft with all fields completed, marked complete' => [
 166                  'registrationdata' => [
 167                      'name' => 'My test platform',
 168                      'uniqueid' => 'acbhd4355',
 169                      'platformid' => new \moodle_url('https://lms.example.com'),
 170                      'clientid' => 'abc345',
 171                      'authenticationrequesturl' => new \moodle_url('https://lms.example.com/auth'),
 172                      'jwksurl' => new \moodle_url('https://lms.example.com/jwks'),
 173                      'accesstokenurl' => new \moodle_url('https://lms.example.com/token'),
 174                      'setcomplete' => true,
 175                  ]
 176              ],
 177          ];
 178      }
 179  
 180      /**
 181       * Test saving an application_registration that is already present in the store.
 182       *
 183       * @covers ::save
 184       */
 185      public function test_save_existing() {
 186          $this->resetAfterTest();
 187          $repository = new application_registration_repository();
 188  
 189          // Modifying a draft registration.
 190          $draftreg = application_registration::create_draft('My test platform', 'bcvd34gs');
 191          $createddraft = $repository->save($draftreg);
 192          $createddraft->set_platformid(new \moodle_url('https://lms.example.com'));
 193          $createddraft->set_clientid(new \moodle_url('clientid_test_33333'));
 194          $createddraft->set_name('Something else');
 195          $createddraft->set_jwksurl(new \moodle_url('https://lms.example.com/jwks'));
 196          $createddraft->set_authenticationrequesturl(new \moodle_url('https://lms.example.com/auth'));
 197          $createddraft->set_accesstokenurl(new \moodle_url('https://lms.example.com/token'));
 198          $createddraft->complete_registration();
 199          $updateddraft = $repository->save($createddraft);
 200  
 201          $this->assertEquals($createddraft->get_id(), $updateddraft->get_id());
 202          $this->assert_same_registration_values($createddraft, $updateddraft);
 203          $this->assert_registration_db_values($updateddraft);
 204  
 205          // Modifying a complete registration.
 206          $registration = application_registration::create(
 207              'My platform name',
 208              'a2c94a2c94',
 209              new \moodle_url('https://updated-lms.example.org/'),
 210              'Updated-client-id',
 211              new \moodle_url('https://updated-lms.example.org/auth'),
 212              new \moodle_url('https://updated-lms.example.org/jwks'),
 213              new \moodle_url('https://updated-lms.example.org/token'),
 214          );
 215          $createdregistration = $repository->save($registration);
 216          $createdregistration->set_name('Something else');
 217          $createdregistration->set_clientid('hhh444');
 218          $updatedregistration = $repository->save($createdregistration);
 219  
 220          $this->assertEquals($createdregistration->get_id(), $updatedregistration->get_id());
 221          $this->assert_same_registration_values($createdregistration, $updatedregistration);
 222          $this->assert_registration_db_values($updatedregistration);
 223      }
 224  
 225      /**
 226       * Tests trying to persist two as-yet-unpersisted objects having identical makeup.
 227       *
 228       * @covers ::save
 229       */
 230      public function test_save_duplicate_unique_constraints() {
 231          $this->resetAfterTest();
 232          $testregistration = $this->generate_application_registration();
 233          $testregistration2 = $this->generate_application_registration();
 234          $repository = new application_registration_repository();
 235  
 236          $this->assertInstanceOf(application_registration::class, $repository->save($testregistration));
 237          $this->expectException(\dml_exception::class);
 238          $repository->save($testregistration2);
 239      }
 240  
 241      /**
 242       * Test finding an application_registration in the repository.
 243       *
 244       * @covers ::find
 245       */
 246      public function test_find() {
 247          $this->resetAfterTest();
 248          $testregistration = $this->generate_application_registration();
 249          $repository = new application_registration_repository();
 250          $createdregistration = $repository->save($testregistration);
 251          $foundregistration = $repository->find($createdregistration->get_id());
 252  
 253          $this->assertEquals($createdregistration->get_id(), $foundregistration->get_id());
 254          $this->assert_same_registration_values($testregistration, $foundregistration);
 255          $this->assertNull($repository->find(0));
 256      }
 257  
 258      /**
 259       * Test finding an application registration by its unique id.
 260       *
 261       * @covers ::find_by_uniqueid
 262       */
 263      public function test_find_by_uniqueid() {
 264          $this->resetAfterTest();
 265          $testregistration = $this->generate_application_registration('https://lms.example.org', 'abc12345');
 266          $repository = new application_registration_repository();
 267          $createdregistration = $repository->save($testregistration);
 268          $foundregistration = $repository->find_by_uniqueid($createdregistration->get_uniqueid());
 269  
 270          $this->assertEquals($createdregistration->get_id(), $foundregistration->get_id());
 271          $this->assert_same_registration_values($testregistration, $foundregistration);
 272          $this->assertNull($repository->find_by_uniqueid('cccc'));
 273      }
 274  
 275      /**
 276       * Test finding an application registration by its platform and unique id combination.
 277       *
 278       * @covers ::find_by_platform_uniqueid
 279       */
 280      public function test_find_by_platform_uniqueid() {
 281          $this->resetAfterTest();
 282          $repository = new application_registration_repository();
 283  
 284          $testregistration = $this->generate_application_registration('https://lms.example.org', 'abc12345');
 285          $createdregistration = $repository->save($testregistration);
 286          $foundregistration = $repository->find_by_platform_uniqueid($createdregistration->get_platformid(),
 287              $createdregistration->get_uniqueid());
 288  
 289          $this->assertEquals($createdregistration->get_id(), $foundregistration->get_id());
 290          $this->assert_same_registration_values($testregistration, $foundregistration);
 291  
 292          // Same platformid, empty uniqueid.
 293          $this->assertNull($repository->find_by_platform_uniqueid('https://lms.example.org', ''));
 294  
 295          // Same platformid, different uniqueid.
 296          $this->assertNull($repository->find_by_platform_uniqueid('https://lms.example.org', 'bbbbb'));
 297  
 298          // Different platformid, empty uniqueid.
 299          $this->assertNull($repository->find_by_platform_uniqueid('https://lms-two.example.org', ''));
 300  
 301          // Different platformid, same uniqueid.
 302          $this->assertNull($repository->find_by_platform_uniqueid('https://lms-two.example.org', 'abc12345'));
 303      }
 304  
 305      /**
 306       * Test verifying that find_all() returns all registrations.
 307       *
 308       * @covers ::find_all
 309       */
 310      public function test_find_all() {
 311          $this->resetAfterTest();
 312          // None to begin with.
 313          $repository = new application_registration_repository();
 314          $this->assertEquals([], $repository->find_all());
 315  
 316          // Add two registrations.
 317          $reg1 = $this->generate_application_registration('https://some.platform.org', '123');
 318          $reg2 = $this->generate_application_registration('https://another.platform.org', '456');
 319          $reg1 = $repository->save($reg1);
 320          $regns[$reg1->get_id()] = $reg1;
 321          $reg2 = $repository->save($reg2);
 322          $regns[$reg2->get_id()] = $reg2;
 323  
 324          // Verify 2 found.
 325          $found = $repository->find_all();
 326          $this->assertCount(2, $found);
 327          foreach ($found as $reg) {
 328              $check = $regns[$reg->get_id()];
 329              $this->assertEquals($check, $reg);
 330          }
 331      }
 332  
 333      /**
 334       * Test confirming that registrations can be found by their platform string.
 335       *
 336       * @covers ::find_by_platform
 337       */
 338      public function test_find_by_platform() {
 339          $this->resetAfterTest();
 340          // None to begin with.
 341          $repository = new application_registration_repository();
 342          $this->assertNull($repository->find_by_platform('https://some.platform.org', 'abc'));
 343  
 344          // Create 2 registrations.
 345          $reg1 = $this->generate_application_registration('https://some.platform.org', '123', 'abc');
 346          $reg2 = $this->generate_application_registration('https://another.platform.org', '456', 'def');
 347          $reg1 = $repository->save($reg1);
 348          $reg2 = $repository->save($reg2);
 349  
 350          // Verify that we can find the registrations by their platform string.
 351          $found = $repository->find_by_platform('https://some.platform.org', 'abc');
 352          $this->assertEquals($reg1, $found);
 353          $found2 = $repository->find_by_platform('https://another.platform.org', 'def');
 354          $this->assertEquals($reg2, $found2);
 355      }
 356  
 357      /**
 358       * Test checking existence of an application_registration within the repository.
 359       *
 360       * @covers ::exists
 361       */
 362      public function test_exists() {
 363          $this->resetAfterTest();
 364          $testregistration = $this->generate_application_registration();
 365          $repository = new application_registration_repository();
 366          $createdregistration = $repository->save($testregistration);
 367  
 368          $this->assertTrue($repository->exists($createdregistration->get_id()));
 369          $this->assertFalse($repository->exists(0));
 370      }
 371  
 372      /**
 373       * Test confirming that delete removes items from the repository.
 374       *
 375       * @covers ::delete
 376       */
 377      public function test_delete() {
 378          $this->resetAfterTest();
 379          global $DB;
 380          $reg = $this->generate_application_registration();
 381          $repository = new application_registration_repository();
 382          $reg = $repository->save($reg);
 383  
 384          $repository->delete($reg->get_id());
 385          $this->assertEquals(0, $DB->count_records('enrol_lti_app_registration'));
 386          $this->assertFalse($repository->exists($reg->get_id()));
 387  
 388          // Deletion of nonexistent registration will not result in errors.
 389          $this->assertNull($repository->delete('000000'));
 390      }
 391  
 392      /**
 393       * Verify that application registrations can be found through their linked deployments.
 394       *
 395       * @covers ::find_by_deployment
 396       */
 397      public function test_find_by_deployment() {
 398          $this->resetAfterTest();
 399          $appregrepo = new application_registration_repository();
 400          $deploymentrepo = new deployment_repository();
 401  
 402          // Deployment linked to a registration.
 403          $testregistration = $this->generate_application_registration();
 404          $createdregistration = $appregrepo->save($testregistration);
 405          $deployment1 = $createdregistration->add_tool_deployment('Deployment 1', '12345');
 406          $createddeployment = $deploymentrepo->save($deployment1);
 407  
 408          // Deployment not linked to a registration.
 409          $deployment2 = deployment::create('000', '56789', 'unlinked deployment');
 410          $createddeployment2 = $deploymentrepo->save($deployment2);
 411  
 412          // Should be able to find the registration from the linked deployment.
 413          $foundreg = $appregrepo->find_by_deployment($createddeployment->get_id());
 414          $this->assertEquals($createdregistration, $foundreg);
 415  
 416          // But not for the deployment which isn't linked.
 417          $this->assertNull($appregrepo->find_by_deployment($createddeployment2->get_id()));
 418      }
 419  }