Skip to content

Commit

Permalink
MDL-74691 enrol_lti: add coverage of lti-ags claim variations to service
Browse files Browse the repository at this point in the history
This test verifies how the service handles changes in the lti-ags claim
sent over several launches - ensuring the claim data is updated each
time.
  • Loading branch information
snake committed Jun 16, 2022
1 parent 006b322 commit 9b8ce4d
Show file tree
Hide file tree
Showing 4 changed files with 243 additions and 21 deletions.
29 changes: 17 additions & 12 deletions enrol/lti/tests/local/ltiadvantage/lti_advantage_testcase.php
Expand Up @@ -126,15 +126,15 @@ protected function get_mock_launch_users_with_ids(array $ids, bool $includepictu
* @param \stdClass $resource the resource record, allowing the mock to generate a link to this.
* @param array $mockuser the user on the platform who is performing the launch.
* @param string|null $resourcelinkid the id of resource link in the platform, if desired.
* @param bool $ags whether to include a mock AGS claim or not.
* @param array|null $ags array representing the lti-ags claim info. Pass null to omit, empty array to use a default.
* @param bool $nrps whether to include a mock NRPS claim or not.
* @param array|null $migrationclaiminfo contains consumer key, secret and any fields which are sent in the claim.
* @param array|null $customparams an array of custom params to send, or null to just use defaults.
* @param mixed $aud the array or string value of aud to use in the mock launch data.
* @return LtiMessageLaunch the mock launch object with test launch data.
*/
protected function get_mock_launch(\stdClass $resource, array $mockuser,
?string $resourcelinkid = null, bool $ags = true, bool $nrps = true, ?array $migrationclaiminfo = null,
?string $resourcelinkid = null, ?array $ags = [], bool $nrps = true, ?array $migrationclaiminfo = null,
?array $customparams = null, $aud = '123'): LtiMessageLaunch {

$mocklaunch = $this->getMockBuilder(LtiMessageLaunch::class)
Expand Down Expand Up @@ -184,16 +184,21 @@ function()
];
}

if ($ags) {
$data["https://purl.imsglobal.org/spec/lti-ags/claim/endpoint"] = [
"scope" => [
"https://purl.imsglobal.org/spec/lti-ags/scope/lineitem",
"https://purl.imsglobal.org/spec/lti-ags/scope/result.readonly",
"https://purl.imsglobal.org/spec/lti-ags/scope/score"
],
"lineitems" => "https://platform.example.com/10/lineitems/",
"lineitem" => "https://platform.example.com/10/lineitems/45/lineitem"
];
if (is_array($ags)) {
if (empty($ags)) {
$agsclaim = [
"scope" => [
"https://purl.imsglobal.org/spec/lti-ags/scope/lineitem",
"https://purl.imsglobal.org/spec/lti-ags/scope/result.readonly",
"https://purl.imsglobal.org/spec/lti-ags/scope/score"
],
"lineitems" => "https://platform.example.com/10/lineitems/",
"lineitem" => "https://platform.example.com/10/lineitems/45/lineitem"
];
} else {
$agsclaim = $ags;
}
$data["https://purl.imsglobal.org/spec/lti-ags/claim/endpoint"] = $agsclaim;
}

if ($nrps) {
Expand Down
Expand Up @@ -72,7 +72,7 @@ public function test_user_launches_tool(?array $legacydata, ?array $launchdata,
}

// Get a mock 1.3 launch, optionally including the lti1p1 migration claim based on a legacy tool secret.
$mocklaunch = $this->get_mock_launch($modresource, $launchdata['user'], null, true, true,
$mocklaunch = $this->get_mock_launch($modresource, $launchdata['user'], null, [], true,
$launchdata['launch_migration_claim']);

// Call the service.
Expand Down Expand Up @@ -278,7 +278,7 @@ public function test_user_launches_tool_missing_custom_id() {
$instructoruser = $this->getDataGenerator()->create_user();
$launchservice = $this->get_tool_launch_service();
$mockuser = $this->get_mock_launch_users_with_ids(['1p3_1'])[0];
$mocklaunch = $this->get_mock_launch($modresource, $mockuser, null, false, false, null, []);
$mocklaunch = $this->get_mock_launch($modresource, $mockuser, null, null, false, null, []);

$this->expectException(\moodle_exception::class);
$this->expectExceptionMessage(get_string('ltiadvlauncherror:missingid', 'enrol_lti'));
Expand All @@ -296,7 +296,7 @@ public function test_user_launches_tool_invalid_custom_id() {
$instructoruser = $this->getDataGenerator()->create_user();
$launchservice = $this->get_tool_launch_service();
$mockuser = $this->get_mock_launch_users_with_ids(['1p3_1'])[0];
$mocklaunch = $this->get_mock_launch($modresource, $mockuser, null, false, false, null, ['id' => 999999]);
$mocklaunch = $this->get_mock_launch($modresource, $mockuser, null, null, false, null, ['id' => 999999]);

$this->expectException(\moodle_exception::class);
$this->expectExceptionMessage(get_string('ltiadvlauncherror:invalidid', 'enrol_lti', 999999));
Expand Down Expand Up @@ -501,11 +501,11 @@ public function test_user_launches_tool_force_embedding_custom_param() {
$learneruser = $this->getDataGenerator()->create_user();
$mockinstructoruser = $this->get_mock_launch_users_with_ids(['1'])[0];
$mocklearneruser = $this->get_mock_launch_users_with_ids(['1'], false, '')[0];
$mockinstructorlaunch = $this->get_mock_launch($modresource, $mockinstructoruser, null, false, false, null, [
$mockinstructorlaunch = $this->get_mock_launch($modresource, $mockinstructoruser, null, null, false, null, [
'id' => $modresource->uuid,
'forcedembed' => true
]);
$mocklearnerlaunch = $this->get_mock_launch($modresource, $mocklearneruser, null, false, false, null, [
$mocklearnerlaunch = $this->get_mock_launch($modresource, $mocklearneruser, null, null, false, null, [
'id' => $modresource->uuid,
'forcedembed' => true
]);
Expand Down Expand Up @@ -534,7 +534,7 @@ public function test_user_launches_tool_aud_variations($aud, array $expected) {
[$course, $modresource] = $this->create_test_environment();
$instructoruser = $this->getDataGenerator()->create_user();
$mockinstructoruser = $this->get_mock_launch_users_with_ids(['1'])[0];
$mockinstructorlaunch = $this->get_mock_launch($modresource, $mockinstructoruser, null, false, false, null, [
$mockinstructorlaunch = $this->get_mock_launch($modresource, $mockinstructoruser, null, null, false, null, [
'id' => $modresource->uuid,
], $aud);

Expand Down Expand Up @@ -608,4 +608,221 @@ public function aud_data_provider(): array {
],
];
}

/**
* Test verifying how changes to lti-ags claim information is handled across different launches.
*
* @param array $agsclaim1 the lti-ags claim data to use in the first launch.
* @param array $agsclaim2 the lti-ags claim data to use in the second launch.
* @param array $expected the array of test case expectations.
* @dataProvider ags_claim_provider
* @covers ::user_launches_tool
*/
public function test_user_launches_tool_ags_claim_handling(array $agsclaim1, array $agsclaim2, array $expected) {
$this->resetAfterTest();
[$course, $modresource] = $this->create_test_environment();
$instructoruser = $this->getDataGenerator()->create_user();
$mockinstructoruser = $this->get_mock_launch_users_with_ids(['1'])[0];
$userrepo = new user_repository();
$resourcelinkrepo = new resource_link_repository();
$launchservice = $this->get_tool_launch_service();

// Launch the first time.
$mockinstructorlaunch = $this->get_mock_launch($modresource, $mockinstructoruser, null, $agsclaim1, false, null, [
'id' => $modresource->uuid,
]);
[$userid, $resource] = $launchservice->user_launches_tool($instructoruser, $mockinstructorlaunch);

$ltiuser = $userrepo->find_single_user_by_resource($userid, $resource->id);
$resourcelink = $resourcelinkrepo->find_by_resource_and_user($resource->id, $ltiuser->get_id())[0];
$gradeservice = $resourcelink->get_grade_service();
$lineitemurl = $agsclaim1['lineitem'] ?? null;
$lineitemsurl = $agsclaim1['lineitems'] ?? null;
$this->assertEquals($agsclaim1['scope'], $gradeservice->get_scopes());
$this->assertEquals($lineitemurl, $gradeservice->get_lineitemurl());
$this->assertEquals($lineitemsurl, $gradeservice->get_lineitemsurl());

// Launch again, with a new lti-ags claim.
$mockinstructorlaunch = $this->get_mock_launch($modresource, $mockinstructoruser, null, $agsclaim2, false, null, [
'id' => $modresource->uuid,
]);
[$userid, $resource] = $launchservice->user_launches_tool($instructoruser, $mockinstructorlaunch);
$ltiuser = $userrepo->find_single_user_by_resource($userid, $resource->id);
$resourcelink = $resourcelinkrepo->find_by_resource_and_user($resource->id, $ltiuser->get_id())[0];
$gradeservice = $resourcelink->get_grade_service();
$lineitemurl = $expected['lineitem'] ?? null;
$lineitemsurl = $expected['lineitems'] ?? null;
$this->assertEquals($expected['scope'], $gradeservice->get_scopes());
$this->assertEquals($lineitemurl, $gradeservice->get_lineitemurl());
$this->assertEquals($lineitemsurl, $gradeservice->get_lineitemsurl());
}

/**
* Data provider for testing user_launches tool with varying mocked lti-ags claim data over several launches.
*
* @return array the array of test case data.
*/
public function ags_claim_provider(): array {
return [
'Coupled line item with score post only, no change to scopes on subsequent launch' => [
'agsclaim1' => [
"scope" => [
"https://purl.imsglobal.org/spec/lti-ags/scope/score"
],
"lineitem" => "https://platform.example.com/10/lineitems/45/lineitem"
],
'agsclaim2' => [
"scope" => [
"https://purl.imsglobal.org/spec/lti-ags/scope/score"
],
"lineitem" => "https://platform.example.com/10/lineitems/45/lineitem"
],
'expected' => [
"scope" => [
"https://purl.imsglobal.org/spec/lti-ags/scope/score"
],
"lineitem" => "https://platform.example.com/10/lineitems/45/lineitem"
]
],
'Coupled line item with score post only, addition to scopes on subsequent launch' => [
'agsclaim1' => [
"scope" => [
"https://purl.imsglobal.org/spec/lti-ags/scope/score"
],
"lineitem" => "https://platform.example.com/10/lineitems/45/lineitem"
],
'agsclaim2' => [
"scope" => [
"https://purl.imsglobal.org/spec/lti-ags/scope/result.readonly",
"https://purl.imsglobal.org/spec/lti-ags/scope/score",
],
"lineitem" => "https://platform.example.com/10/lineitems/45/lineitem"
],
'expected' => [
"scope" => [
"https://purl.imsglobal.org/spec/lti-ags/scope/result.readonly",
"https://purl.imsglobal.org/spec/lti-ags/scope/score",
],
"lineitem" => "https://platform.example.com/10/lineitems/45/lineitem"
]
],
'Coupled line item with score post + result read, removal of scopes on subsequent launch' => [
'agsclaim1' => [
"scope" => [
"https://purl.imsglobal.org/spec/lti-ags/scope/result.readonly",
"https://purl.imsglobal.org/spec/lti-ags/scope/score"
],
"lineitem" => "https://platform.example.com/10/lineitems/45/lineitem"
],
'agsclaim2' => [
"scope" => [
"https://purl.imsglobal.org/spec/lti-ags/scope/score",
],
"lineitem" => "https://platform.example.com/10/lineitems/45/lineitem"
],
'expected' => [
"scope" => [
"https://purl.imsglobal.org/spec/lti-ags/scope/score",
],
"lineitem" => "https://platform.example.com/10/lineitems/45/lineitem"
]
],
'Decoupled line items with all capabilities, change and removal of scopes on subsequent launch' => [
'agsclaim1' => [
"scope" => [
"https://purl.imsglobal.org/spec/lti-ags/scope/lineitem",
"https://purl.imsglobal.org/spec/lti-ags/scope/result.readonly",
"https://purl.imsglobal.org/spec/lti-ags/scope/score"
],
"lineitems" => "https://platform.example.com/10/lineitems/",
],
'agsclaim2' => [
"scope" => [
"https://purl.imsglobal.org/spec/lti-ags/scope/lineitem.readonly",
"https://purl.imsglobal.org/spec/lti-ags/scope/score"
],
"lineitems" => "https://platform.example.com/10/lineitems/",
],
'expected' => [
"scope" => [
"https://purl.imsglobal.org/spec/lti-ags/scope/lineitem.readonly",
"https://purl.imsglobal.org/spec/lti-ags/scope/score"
],
"lineitems" => "https://platform.example.com/10/lineitems/",
]
],
'Decoupled line items with all capabilities, removal of scopes on subsequent launch' => [
'agsclaim1' => [
"scope" => [
"https://purl.imsglobal.org/spec/lti-ags/scope/lineitem",
"https://purl.imsglobal.org/spec/lti-ags/scope/result.readonly",
"https://purl.imsglobal.org/spec/lti-ags/scope/score"
],
"lineitems" => "https://platform.example.com/10/lineitems/",
],
'agsclaim2' => [
"scope" => [
"https://purl.imsglobal.org/spec/lti-ags/scope/lineitem",
"https://purl.imsglobal.org/spec/lti-ags/scope/score"
],
"lineitems" => "https://platform.example.com/10/lineitems/",
],
'expected' => [
"scope" => [
"https://purl.imsglobal.org/spec/lti-ags/scope/lineitem",
"https://purl.imsglobal.org/spec/lti-ags/scope/score"
],
"lineitems" => "https://platform.example.com/10/lineitems/",
]
],
'Coupled line items with score post only, addition of lineitemsurl and all capabilities on subsequent launch' => [
'agsclaim1' => [
"scope" => [
"https://purl.imsglobal.org/spec/lti-ags/scope/score"
],
"lineitem" => "https://platform.example.com/10/lineitems/45/lineitem"
],
'agsclaim2' => [
"scope" => [
"https://purl.imsglobal.org/spec/lti-ags/scope/lineitem",
"https://purl.imsglobal.org/spec/lti-ags/scope/result.readonly",
"https://purl.imsglobal.org/spec/lti-ags/scope/score"
],
"lineitems" => "https://platform.example.com/10/lineitems/",
"lineitem" => "https://platform.example.com/10/lineitems/45/lineitem"
],
'expected' => [
"scope" => [
"https://purl.imsglobal.org/spec/lti-ags/scope/lineitem",
"https://purl.imsglobal.org/spec/lti-ags/scope/result.readonly",
"https://purl.imsglobal.org/spec/lti-ags/scope/score"
],
"lineitems" => "https://platform.example.com/10/lineitems/",
"lineitem" => "https://platform.example.com/10/lineitems/45/lineitem"
]
],
'Decoupled line items with all capabilities, change to coupled line item with score post only on subsequent launch' => [
'agsclaim1' => [
"scope" => [
"https://purl.imsglobal.org/spec/lti-ags/scope/lineitem",
"https://purl.imsglobal.org/spec/lti-ags/scope/result.readonly",
"https://purl.imsglobal.org/spec/lti-ags/scope/score"
],
"lineitems" => "https://platform.example.com/10/lineitems/",
],
'agsclaim2' => [
"scope" => [
"https://purl.imsglobal.org/spec/lti-ags/scope/score"
],
"lineitem" => "https://platform.example.com/10/lineitems/45/lineitem"
],
'expected' => [
"scope" => [
"https://purl.imsglobal.org/spec/lti-ags/scope/score"
],
"lineitem" => "https://platform.example.com/10/lineitems/45/lineitem"
]
],
];
}
}
Expand Up @@ -394,7 +394,7 @@ public function test_sync_grades_no_service_endpoint() {

// Launch the resource for an instructor which will create the domain objects needed for service calls.
$teachermocklaunch = $this->get_mock_launch($resource, $this->get_mock_launch_users_with_ids(['1'], false)[0],
null, false);
null, null);
$instructoruser = $this->getDataGenerator()->create_user();
[$userid] = $launchservice->user_launches_tool($instructoruser, $teachermocklaunch);

Expand Down
4 changes: 2 additions & 2 deletions enrol/lti/tests/local/ltiadvantage/task/sync_members_test.php
Expand Up @@ -621,7 +621,7 @@ public function test_sync_no_nrps_support() {

// Launch the tool for a user.
$mockinstructor = $this->get_mock_launch_users_with_ids([1])[0];
$mocklaunch = $this->get_mock_launch($resource, $mockinstructor, null, false, false);
$mocklaunch = $this->get_mock_launch($resource, $mockinstructor, null, null, false);
$launchservice = $this->get_tool_launch_service();
$instructoruser = $this->lti_advantage_user_authenticates('1');
$launchservice->user_launches_tool($instructoruser, $mocklaunch);
Expand Down Expand Up @@ -708,7 +708,7 @@ public function test_sync_enrolments_and_migration(?array $legacydata, ?array $r
}

// Mock the launch for the specified user.
$mocklaunch = $this->get_mock_launch($resource, $launchdata['user'], null, true, true,
$mocklaunch = $this->get_mock_launch($resource, $launchdata['user'], null, [], true,
$launchdata['launch_migration_claim']);

// Perform the launch.
Expand Down

0 comments on commit 9b8ce4d

Please sign in to comment.