2 // This file is part of Moodle - http://moodle.org/
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.
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.
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/>.
18 * Tests for the sync_members scheduled task class.
21 * @copyright 2016 Jun Pataleta <jun@moodle.com>
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 use enrol_lti\data_connector
;
27 use enrol_lti\task\sync_members
;
28 use enrol_lti\tool_provider
;
29 use IMSGlobal\LTI\ToolProvider\Context
;
30 use IMSGlobal\LTI\ToolProvider\ResourceLink
;
31 use IMSGlobal\LTI\ToolProvider\ToolConsumer
;
32 use IMSGlobal\LTI\ToolProvider\User
;
34 defined('MOODLE_INTERNAL') ||
die();
37 * Tests for the sync_members scheduled task class.
40 * @copyright 2016 Jun Pataleta <jun@moodle.com>
41 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
43 class sync_members_testcase
extends advanced_testcase
{
44 /** @var dummy_sync_members_task $task */
47 /** @var stdClass $tool The published tool. */
50 /** @var User[] $members */
53 /** @var ToolConsumer $consumer */
56 /** @var Context $context */
59 /** @var ResourceLink $resourcelink */
60 protected $resourcelink;
62 public function setUp(): void
{
63 $this->resetAfterTest();
65 // Set this user as the admin.
66 $this->setAdminUser();
68 $this->task
= new dummy_sync_members_task();
70 $generator = $this->getDataGenerator();
71 $course = $generator->create_course();
73 'courseid' => $course->id
,
74 'membersyncmode' => helper
::MEMBER_SYNC_ENROL_AND_UNENROL
,
77 $tool = $generator->create_lti_tool((object)$tooldata);
78 $this->tool
= helper
::get_lti_tool($tool->id
);
80 $dataconnector = $this->task
->get_dataconnector();
81 $this->consumer
= new ToolConsumer('Consumer1Key', $dataconnector);
82 $this->consumer
->name
= 'Consumer1';
83 $this->consumer
->secret
= 'Consumer1Secret';
84 $this->consumer
->save();
86 $toolprovider = new tool_provider($this->tool
->id
);
87 $toolprovider->consumer
= $this->consumer
;
88 $toolprovider->map_tool_to_consumer();
90 $imageurl = $this->getExternalTestFileUrl('test.jpg');
93 for ($i = 1; $i <= $count; $i++
) {
95 $user->firstname
= 'Firstname' . $i;
96 $user->lastname
= 'Lastname' . $i;
97 $user->ltiUserId
= 'user' . $i;
98 // Set user image values for some users.
100 $user->image
= $imageurl;
102 $this->members
[] = $user;
105 $this->context
= Context
::fromConsumer($this->consumer
, 'testlticontextid');
106 $this->context
->save();
108 $this->resourcelink
= ResourceLink
::fromContext($this->context
, 'testresourcelinkid');
109 $this->resourcelink
->save();
113 * Test for sync_members::do_context_membership_request().
115 public function test_do_context_membership_request() {
118 $members = $this->task
->do_context_membership_request($this->context
);
120 $this->assertFalse($members);
124 * Test for sync_members::do_resourcelink_membership_request().
126 public function test_do_resourcelink_membership_request() {
127 $members = $this->task
->do_resourcelink_membership_request($this->resourcelink
);
128 $this->assertFalse($members);
132 * Test for sync_members::execute() when auth_lti is disabled.
134 public function test_execute_authdisabled() {
136 $this->task
->execute();
137 $output = ob_get_clean();
138 $message = 'Skipping task - ' . get_string('pluginnotenabled', 'auth', get_string('pluginname', 'auth_lti'));
139 $this->assertContains($message, $output);
143 * Test for sync_members::execute() when enrol_lti is disabled.
145 public function test_execute_enroldisabled() {
147 $this->enable_auth();
150 $this->task
->execute();
151 $output = ob_get_clean();
152 $message = 'Skipping task - ' . get_string('enrolisdisabled', 'enrol_lti');
153 $this->assertContains($message, $output);
157 * Test for sync_members::execute().
159 public function test_execute() {
161 $this->enable_auth();
164 $this->enable_enrol();
167 $this->task
->execute();
168 $output = ob_get_clean();
170 $membersyncmessage = "Completed - Synced members for tool '{$this->tool->id}' in the course '{$this->tool->courseid}'";
171 $this->assertContains($membersyncmessage, $output);
173 $imagesyncmessage = "Completed - Synced 0 profile images.";
174 $this->assertContains($imagesyncmessage, $output);
178 * Test for sync_members::fetch_members_from_consumer() with no resource link nor context associated with the consumer.
180 public function test_fetch_members_from_consumer_noresourcelink_nocontext() {
183 $members = $this->task
->fetch_members_from_consumer($this->consumer
);
185 $this->assertFalse($members);
189 * Test for sync_members::get_name().
191 public function test_get_name() {
192 $this->assertEquals(get_string('tasksyncmembers', 'enrol_lti'), $this->task
->get_name());
196 * Test for sync_members::should_sync_enrol().
198 public function test_should_sync_enrol() {
199 $this->assertTrue($this->task
->should_sync_enrol(helper
::MEMBER_SYNC_ENROL_AND_UNENROL
));
200 $this->assertTrue($this->task
->should_sync_enrol(helper
::MEMBER_SYNC_ENROL_NEW
));
201 $this->assertFalse($this->task
->should_sync_enrol(helper
::MEMBER_SYNC_UNENROL_MISSING
));
205 * Test for sync_members::should_sync_unenrol().
207 public function test_should_sync_unenrol() {
208 $this->assertTrue($this->task
->should_sync_unenrol(helper
::MEMBER_SYNC_ENROL_AND_UNENROL
));
209 $this->assertFalse($this->task
->should_sync_unenrol(helper
::MEMBER_SYNC_ENROL_NEW
));
210 $this->assertTrue($this->task
->should_sync_unenrol(helper
::MEMBER_SYNC_UNENROL_MISSING
));
214 * Test for sync_members::sync_member_information().
216 public function test_sync_member_information() {
217 list($totalcount, $enrolledcount) = $this->task
->sync_member_information($this->tool
, $this->consumer
, $this->members
);
218 $membercount = count($this->members
);
219 $this->assertCount(10, $this->members
);
220 $this->assertEquals($membercount, $totalcount);
221 $this->assertEquals($membercount, $enrolledcount);
225 * Test for sync_members::sync_profile_images().
227 public function test_sync_profile_images() {
229 list($totalcount, $enrolledcount) = $task->sync_member_information($this->tool
, $this->consumer
, $this->members
);
230 $membercount = count($this->members
);
231 $this->assertCount(10, $this->members
);
232 $this->assertEquals($membercount, $totalcount);
233 $this->assertEquals($membercount, $enrolledcount);
237 $this->assertEquals(3, $task->sync_profile_images());
242 * Test for sync_members::sync_unenrol().
244 public function test_sync_unenrol() {
248 $task->sync_member_information($tool, $this->consumer
, $this->members
);
250 // Simulate that the fetched list of current users has been reduced by 3.
252 for ($i = 0; $i < $unenrolcount; $i++
) {
253 $task->pop_current_users();
255 $this->assertEquals($unenrolcount, $task->sync_unenrol($tool));
259 * Enable auth_lti plugin.
261 protected function enable_auth() {
262 $auths = get_enabled_auth_plugins(true);
263 if (!in_array('lti', $auths)) {
266 set_config('auth', implode(',', $auths));
270 * Enable enrol_lti plugin.
272 protected function enable_enrol() {
273 $enabled = enrol_get_plugins(true);
274 $enabled['lti'] = true;
275 $enabled = array_keys($enabled);
276 set_config('enrol_plugins_enabled', implode(',', $enabled));
281 * Class dummy_sync_members_task.
283 * A class that extends sync_members so that we can expose the protected methods that we would like to test.
285 * @copyright 2016 Jun Pataleta <jun@moodle.com>
286 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
288 class dummy_sync_members_task
extends sync_members
{
290 * Exposes/generates the dataconnector property.
292 * @return data_connector
294 public function get_dataconnector() {
295 if (!$this->dataconnector
) {
296 $this->dataconnector
= new data_connector();
298 return $this->dataconnector
;
302 * Helper method that removes an element in the array of current users.
304 public function pop_current_users() {
305 array_pop($this->currentusers
);
309 * Exposes sync_members::do_context_membership_request()
311 * @param Context $context The context object.
312 * @param ResourceLink $resourcelink The resource link object.
313 * @param string $membershipsurltemplate The memberships endpoint URL template.
314 * @return bool|User[] Array of User objects upon successful membership service request. False, otherwise.
316 public function do_context_membership_request(Context
$context, ResourceLink
$resourcelink = null,
317 $membershipsurltemplate = '') {
318 $members = parent
::do_context_membership_request($context, $resourcelink, $membershipsurltemplate);
324 * Exposes sync_members::do_resourcelink_membership_request()
326 * @param ResourceLink $resourcelink
327 * @return bool|User[]
329 public function do_resourcelink_membership_request(ResourceLink
$resourcelink) {
330 $members = parent
::do_resourcelink_membership_request($resourcelink);
335 * Exposes sync_members::fetch_members_from_consumer()
337 * @param ToolConsumer $consumer
338 * @return bool|User[]
340 public function fetch_members_from_consumer(ToolConsumer
$consumer) {
341 $members = parent
::fetch_members_from_consumer($consumer);
346 * Exposes sync_members::should_sync_unenrol()
348 * @param int $syncmode The tool's membersyncmode.
351 public function should_sync_unenrol($syncmode) {
352 $shouldsync = parent
::should_sync_unenrol($syncmode);
357 * Exposes sync_members::should_sync_enrol()
359 * @param int $syncmode The tool's membersyncmode.
362 public function should_sync_enrol($syncmode) {
363 $shouldsync = parent
::should_sync_enrol($syncmode);
368 * Exposes sync_members::sync_member_information()
370 * @param stdClass $tool
371 * @param ToolConsumer $consumer
372 * @param User[] $members
375 public function sync_member_information(stdClass
$tool, ToolConsumer
$consumer, $members) {
376 $result = parent
::sync_member_information($tool, $consumer, $members);
381 * Exposes sync_members::sync_profile_images()
385 public function sync_profile_images() {
386 $count = parent
::sync_profile_images();
391 * Exposes sync_members::sync_unenrol()
393 * @param stdClass $tool
396 public function sync_unenrol(stdClass
$tool) {
397 $count = parent
::sync_unenrol($tool);