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\resource_link; 19 use enrol_lti\local\ltiadvantage\entity\application_registration; 20 21 /** 22 * Tests for resource_link_repository objects. 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\resource_link_repository 28 */ 29 class resource_link_repository_test extends \advanced_testcase { 30 /** 31 * Helper to generate a new resource_link instance. 32 * 33 * @param string $id the id to use for this the resource link. 34 * @return resource_link the resource_link instance. 35 */ 36 protected function generate_resource_link($id = 'res-link-1'): resource_link { 37 $registration = application_registration::create( 38 'Test', 39 'a2c94a2c94', 40 new \moodle_url('http://lms.example.org'), 41 'clientid_123', 42 new \moodle_url('https://example.org/authrequesturl'), 43 new \moodle_url('https://example.org/jwksurl'), 44 new \moodle_url('https://example.org/accesstokenurl') 45 ); 46 $registrationrepo = new application_registration_repository(); 47 $createdregistration = $registrationrepo->save($registration); 48 49 $deployment = $createdregistration->add_tool_deployment('Deployment 1', 'DeployID123'); 50 $deploymentrepo = new deployment_repository(); 51 $saveddeployment = $deploymentrepo->save($deployment); 52 53 $contextrepo = new context_repository(); 54 $context = $saveddeployment->add_context( 55 'CTX123', 56 ['http://purl.imsglobal.org/vocab/lis/v2/course#CourseSection'] 57 ); 58 $savedcontext = $contextrepo->save($context); 59 60 $resourcelink = $saveddeployment->add_resource_link($id, $savedcontext->get_id()); 61 $resourcelink->add_grade_service( 62 new \moodle_url('https://lms.example.com/context/24/lineitems'), 63 new \moodle_url('https://lms.example.com/context/24/lineitem/3'), 64 [ 65 'https://purl.imsglobal.org/spec/lti-ags/scope/lineitem', 66 'https://purl.imsglobal.org/spec/lti-ags/scope/lineitem.readonly', 67 'https://purl.imsglobal.org/spec/lti-ags/scope/result.readonly', 68 'https://purl.imsglobal.org/spec/lti-ags/scope/score' 69 ] 70 ); 71 $resourcelink->add_names_and_roles_service( 72 new \moodle_url('https://lms.example.com/context/24/memberships'), 73 [1.0, 2.0] 74 ); 75 76 return $resourcelink; 77 } 78 79 /** 80 * Helper to assert that all the key elements of two resource_links (i.e. excluding id) are equal. 81 * 82 * @param resource_link $expected the resource_link whose values are deemed correct. 83 * @param resource_link $check the resource_link to check. 84 */ 85 protected function assert_same_resourcelink_values(resource_link $expected, resource_link $check): void { 86 $this->assertEquals($expected->get_resourcelinkid(), $check->get_resourcelinkid()); 87 $this->assertEquals($expected->get_deploymentid(), $check->get_deploymentid()); 88 $this->assertEquals($expected->get_contextid(), $check->get_contextid()); 89 $this->assertEquals($expected->get_grade_service(), $check->get_grade_service()); 90 $this->assertEquals($expected->get_names_and_roles_service(), $check->get_names_and_roles_service()); 91 } 92 93 /** 94 * Helper to assert that all the key elements of a resource_link are present in the DB. 95 * 96 * @param resource_link $expected the resource_link whose values are deemed correct. 97 */ 98 protected function assert_resourcelink_db_values(resource_link $expected) { 99 global $DB; 100 $checkrecord = $DB->get_record('enrol_lti_resource_link', ['id' => $expected->get_id()]); 101 $gradeservice = $expected->get_grade_service(); 102 $this->assertEquals($expected->get_id(), $checkrecord->id); 103 $this->assertEquals($expected->get_deploymentid(), $checkrecord->ltideploymentid); 104 $this->assertEquals($expected->get_resourcelinkid(), $checkrecord->resourcelinkid); 105 $this->assertEquals($expected->get_contextid(), $checkrecord->lticontextid); 106 $this->assertEquals($gradeservice ? $gradeservice->get_lineitemsurl() : null, $checkrecord->lineitemsservice); 107 $this->assertEquals($gradeservice ? $gradeservice->get_lineitemurl() : null, $checkrecord->lineitemservice); 108 $this->assertEquals($gradeservice ? json_encode($gradeservice->get_lineitemscope()) : null, 109 $checkrecord->lineitemscope); 110 $this->assertEquals($gradeservice ? $gradeservice->get_resultscope() : null, $checkrecord->resultscope); 111 $this->assertEquals($gradeservice ? $gradeservice->get_scorescope() : null, $checkrecord->scorescope); 112 $this->assertNotEmpty($checkrecord->timecreated); 113 $this->assertNotEmpty($checkrecord->timemodified); 114 } 115 116 /** 117 * Tests adding a resource_link to the store. 118 * 119 * @covers ::save 120 */ 121 public function test_save_new() { 122 $this->resetAfterTest(); 123 $resourcelink = $this->generate_resource_link(); 124 $repository = new resource_link_repository(); 125 $savedresourcelink = $repository->save($resourcelink); 126 127 $this->assertIsInt($savedresourcelink->get_id()); 128 $this->assert_same_resourcelink_values($resourcelink, $savedresourcelink); 129 $this->assert_resourcelink_db_values($savedresourcelink); 130 } 131 132 /** 133 * Test that we cannot add two resource_links with the same resourcelinkid for a given deploymentid. 134 * 135 * @covers ::save 136 */ 137 public function test_add_uniqueness_constraints() { 138 $this->resetAfterTest(); 139 $reslink1 = $this->generate_resource_link(); 140 $reslink2 = clone $reslink1; 141 $repository = new resource_link_repository(); 142 $createdresource1 = $repository->save($reslink1); 143 $this->assertIsInt($createdresource1->get_id()); 144 $this->expectException(\dml_exception::class); 145 $repository->save($reslink2); 146 } 147 148 /** 149 * Test fetching an object from the store. 150 * 151 * @covers ::find 152 */ 153 public function test_find() { 154 $this->resetAfterTest(); 155 $resourcelink = $this->generate_resource_link(); 156 $repository = new resource_link_repository(); 157 $newreslink = $repository->save($resourcelink); 158 159 $locatedreslink = $repository->find($newreslink->get_id()); 160 $this->assertEquals($newreslink, $locatedreslink); 161 $repository->delete($locatedreslink->get_id()); 162 $this->assertEmpty($repository->find($locatedreslink->get_id())); 163 } 164 165 /** 166 * Test finding a collection of resource links by resource. 167 * 168 * @covers ::find_by_resource 169 */ 170 public function test_find_by_resource() { 171 $this->resetAfterTest(); 172 $resourcelink = $this->generate_resource_link(); 173 $repository = new resource_link_repository(); 174 $newreslink = $repository->save($resourcelink); 175 $resourcelink2 = resource_link::create('another-res-link-1', $newreslink->get_deploymentid(), 176 $newreslink->get_resourceid()); 177 $newreslink2 = $repository->save($resourcelink2); 178 $resourcelink3 = resource_link::create('another-res-link-2', $newreslink->get_deploymentid(), 179 $newreslink->get_resourceid() + 1); 180 $newreslink3 = $repository->save($resourcelink3); 181 182 $locatedreslinks = $repository->find_by_resource($newreslink->get_resourceid()); 183 $this->assertCount(2, $locatedreslinks); 184 usort($locatedreslinks, function($a, $b) { 185 return strcmp($b->get_resourcelinkid(), $a->get_resourcelinkid()); 186 }); 187 $this->assertEquals([$newreslink, $newreslink2], $locatedreslinks); 188 $locatedreslinks = $repository->find_by_resource($newreslink->get_resourceid() + 1); 189 $this->assertCount(1, $locatedreslinks); 190 $this->assertEquals([$newreslink3], $locatedreslinks); 191 $this->assertEmpty($repository->find_by_resource(0)); 192 } 193 194 /** 195 * Test finding a collection of resource links by resource and user. 196 * 197 * @covers ::find_by_resource_and_user 198 */ 199 public function test_find_by_resource_and_user() { 200 global $CFG; 201 $this->resetAfterTest(); 202 $resourcelink = $this->generate_resource_link(); 203 $repository = new resource_link_repository(); 204 $newreslink = $repository->save($resourcelink); 205 $resourcelink2 = resource_link::create('another-res-link-1', $newreslink->get_deploymentid(), 206 $newreslink->get_resourceid()); 207 $newreslink2 = $repository->save($resourcelink2); 208 $resourcelink3 = resource_link::create('another-res-link-2', $newreslink->get_deploymentid(), 209 $newreslink->get_resourceid()); 210 $newreslink3 = $repository->save($resourcelink3); 211 $user1 = $this->getDataGenerator()->create_user(); 212 $user2 = $this->getDataGenerator()->create_user(); 213 214 $userrepo = new user_repository(); 215 $user = $newreslink->add_user( 216 $user1->id, 217 'platform-user-id-123', 218 $CFG->lang, 219 'Sydney', 220 'AU', 221 'Test university', 222 '99' 223 ); 224 $createduser = $userrepo->save($user); 225 $createduser->set_resourcelinkid($newreslink2->get_id()); 226 $userrepo->save($createduser); 227 228 $user2 = $newreslink3->add_user( 229 $user2->id, 230 'platform-user-id-777', 231 $CFG->lang, 232 'Melbourne', 233 'AU', 234 'Test university', 235 '99' 236 ); 237 $createduser2 = $userrepo->save($user2); 238 239 $locatedreslinks = $repository->find_by_resource_and_user($newreslink->get_resourceid(), 240 $createduser->get_id()); 241 $this->assertCount(2, $locatedreslinks); 242 usort($locatedreslinks, function($a, $b) { 243 return strcmp($b->get_resourcelinkid(), $a->get_resourcelinkid()); 244 }); 245 $this->assertEquals([$newreslink, $newreslink2], $locatedreslinks); 246 $locatedreslinks = $repository->find_by_resource_and_user($newreslink->get_resourceid(), 247 $createduser2->get_id()); 248 $this->assertCount(1, $locatedreslinks); 249 $this->assertEquals([$newreslink3], $locatedreslinks); 250 $this->assertEmpty($repository->find_by_resource_and_user($newreslink->get_resourceid(), 0)); 251 } 252 253 /** 254 * Test deletion from the store. 255 * 256 * @covers ::delete 257 */ 258 public function test_delete() { 259 global $CFG; 260 $this->resetAfterTest(); 261 $resourcelink = $this->generate_resource_link(); 262 $repository = new resource_link_repository(); 263 $newreslink = $repository->save($resourcelink); 264 $this->assertTrue($repository->exists($newreslink->get_id())); 265 266 // Also create a user from this resource link so we get some test user_resource_link mappings. 267 $user = $newreslink->add_user( 268 2, 269 'source-id-123', 270 $CFG->lang, 271 'Perth', 272 'AU', 273 'An Example Institution', 274 '99', 275 2, 276 ); 277 $userrepo = new user_repository(); 278 $userrepo->save($user); 279 global $DB; 280 $this->assertTrue($DB->record_exists('enrol_lti_user_resource_link', 281 ['resourcelinkid' => $newreslink->get_id()])); 282 283 $repository->delete($newreslink->get_id()); 284 $this->assertFalse($repository->exists($newreslink->get_id())); 285 $this->assertEmpty($repository->find($newreslink->get_id())); 286 $this->assertFalse($DB->record_exists('enrol_lti_user_resource_link', 287 ['resourcelinkid' => $newreslink->get_id()])); 288 289 $this->assertNull($repository->delete($newreslink->get_id())); 290 } 291 292 /** 293 * Test deleting a group of resource links by resource. 294 * 295 * @covers ::delete_by_resource 296 */ 297 public function test_delete_by_resource() { 298 global $CFG; 299 $this->resetAfterTest(); 300 $resourcelink = $this->generate_resource_link(); 301 $repository = new resource_link_repository(); 302 $newreslink = $repository->save($resourcelink); 303 304 // Also create a user from this resource link so we get some test user_resource_link mappings. 305 $user = $newreslink->add_user( 306 2, 307 'source-id-123', 308 $CFG->lang, 309 'Perth', 310 'AU', 311 'An Example Institution', 312 '99', 313 2, 314 ); 315 $userrepo = new user_repository(); 316 $userrepo->save($user); 317 global $DB; 318 $this->assertTrue($DB->record_exists('enrol_lti_user_resource_link', 319 ['resourcelinkid' => $newreslink->get_id()])); 320 321 // Create a resource link under the same deployment for another resource. 322 $resourcelink2 = resource_link::create('another-res-link-1', $newreslink->get_deploymentid(), 323 $newreslink->get_resourceid() + 1); 324 $newreslink2 = $repository->save($resourcelink2); 325 326 $repository->delete_by_resource($newreslink->get_resourceid()); 327 $this->assertFalse($repository->exists($newreslink->get_id())); 328 $this->assertEmpty($repository->find($newreslink->get_id())); 329 $this->assertFalse($DB->record_exists('enrol_lti_user_resource_link', 330 ['resourcelinkid' => $newreslink->get_id()])); 331 $this->assertTrue($repository->exists($newreslink2->get_id())); 332 $this->assertInstanceOf(resource_link::class, $repository->find($newreslink2->get_id())); 333 334 $this->assertNull($repository->delete_by_deployment($newreslink->get_deploymentid())); 335 } 336 337 /** 338 * Test deleting a resource links by their deployment container. 339 * 340 * @covers ::delete_by_deployment 341 */ 342 public function test_delete_by_deployment() { 343 global $CFG; 344 $this->resetAfterTest(); 345 $resourcelink = $this->generate_resource_link(); 346 $repository = new resource_link_repository(); 347 $newreslink = $repository->save($resourcelink); 348 $this->assertTrue($repository->exists($newreslink->get_id())); 349 350 // Also create a user from this resource link so we get some test user_resource_link mappings. 351 $user = $newreslink->add_user( 352 2, 353 'source-id-123', 354 $CFG->lang, 355 'Perth', 356 'AU', 357 'An Example Institution', 358 '99', 359 2, 360 ); 361 $userrepo = new user_repository(); 362 $userrepo->save($user); 363 global $DB; 364 $this->assertTrue($DB->record_exists('enrol_lti_user_resource_link', 365 ['resourcelinkid' => $newreslink->get_id()])); 366 367 $repository->delete_by_deployment($newreslink->get_deploymentid()); 368 $this->assertFalse($repository->exists($newreslink->get_id())); 369 $this->assertEmpty($repository->find($newreslink->get_id())); 370 $this->assertFalse($DB->record_exists('enrol_lti_user_resource_link', 371 ['resourcelinkid' => $newreslink->get_id()])); 372 373 $this->assertNull($repository->delete_by_deployment($newreslink->get_deploymentid())); 374 } 375 376 /** 377 * Test checking existence in the store. 378 * 379 * @covers ::exists 380 */ 381 public function test_exists() { 382 $this->resetAfterTest(); 383 $resourcelink = $this->generate_resource_link(); 384 $repository = new resource_link_repository(); 385 $newreslink = $repository->save($resourcelink); 386 $this->assertTrue($repository->exists($newreslink->get_id())); 387 $repository->delete($newreslink->get_id()); 388 $this->assertFalse($repository->exists($newreslink->get_id())); 389 } 390 391 /** 392 * Test update of an existing resource_link. 393 * 394 * @covers ::save 395 */ 396 public function test_save_existing() { 397 $this->resetAfterTest(); 398 $resourcelink = $this->generate_resource_link(); 399 $repository = new resource_link_repository(); 400 $newreslink = $repository->save($resourcelink); 401 $newreslink->add_grade_service( 402 new \moodle_url('https://lms.example.org/context/lineitems') 403 ); 404 405 $updatedreslink = $repository->save($newreslink); 406 $this->assertEquals($newreslink, $updatedreslink); 407 } 408 409 /** 410 * Test update with a stale object which is no longer present in the store. 411 * 412 * @covers ::save 413 */ 414 public function test_update_stale() { 415 $this->resetAfterTest(); 416 $resourcelink = $this->generate_resource_link(); 417 $repository = new resource_link_repository(); 418 $newreslink = $repository->save($resourcelink); 419 $repository->delete($newreslink->get_id()); 420 421 $newreslink->add_grade_service( 422 new \moodle_url('https://lms.example.org/context/lineitems') 423 ); 424 $this->expectException(\coding_exception::class); 425 $repository->save($newreslink); 426 } 427 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body