diff --git a/enrol/lti/tests/data_connector_test.php b/enrol/lti/tests/data_connector_test.php index c8449986781..b01009e6c67 100644 --- a/enrol/lti/tests/data_connector_test.php +++ b/enrol/lti/tests/data_connector_test.php @@ -1104,4 +1104,131 @@ class enrol_lti_data_connector_testcase extends advanced_testcase { $this->assertNull($user->created); $this->assertNull($user->updated); } + + /** + * Test for data_connector::get_contexts_from_consumer(). + */ + public function test_get_contexts_from_consumer() { + $dc = new data_connector(); + $consumer = new ToolConsumer(null, $dc); + $consumer->name = 'testconsumername'; + $consumer->setKey('TestKey'); + $consumer->secret = 'testsecret'; + $consumer->save(); + + $settings = ['a', 'b', 'c']; + $lticontextid = 'testlticontextid'; + $context = Context::fromConsumer($consumer, $lticontextid); + $context->settings = $settings; + $context->save(); + $dc->loadContext($context); + + $consumer2 = new ToolConsumer(null, $dc); + $consumer2->name = 'testconsumername2'; + $consumer2->setKey('TestKey2'); + $consumer2->secret = 'testsecret2'; + $consumer2->save(); + + $context2 = Context::fromConsumer($consumer2, $lticontextid . '2'); + $context2->settings = $settings; + $consumer2->save(); + + $contexts = $dc->get_contexts_from_consumer($consumer); + $this->assertCount(1, $contexts); + $this->assertEquals($context, $contexts[0]); + } + + /** + * Test for data_connector::get_consumers_mapped_to_tool(). + */ + public function test_get_consumers_mapped_to_tool() { + $generator = $this->getDataGenerator(); + // Create two tools belonging to the same course. + $course1 = $generator->create_course(); + $data = new stdClass(); + $data->courseid = $course1->id; + $tool = $generator->create_lti_tool($data); + $tool2 = $generator->create_lti_tool($data); + + $dc = new data_connector(); + $consumer = new ToolConsumer('key1', $dc); + $consumer->name = 'testconsumername'; + $consumer->secret = 'testsecret'; + $consumer->save(); + + $tp = new \enrol_lti\tool_provider($tool->id); + $tp->consumer = $consumer; + $tp->map_tool_to_consumer(); + + $consumer2 = new ToolConsumer('key2', $dc); + $consumer2->name = 'testconsumername2'; + $consumer2->secret = 'testsecret2'; + $consumer2->save(); + + $tp2 = new \enrol_lti\tool_provider($tool2->id); + $tp2->consumer = $consumer2; + $tp2->map_tool_to_consumer(); + + $consumers = $dc->get_consumers_mapped_to_tool($tool->id); + $this->assertCount(1, $consumers); + $this->assertEquals($consumer, $consumers[0]); + + $consumers2 = $dc->get_consumers_mapped_to_tool($tool2->id); + $this->assertCount(1, $consumers2); + $this->assertEquals($consumer2, $consumers2[0]); + } + + /** + * Test for data_connector::get_resourcelink_from_consumer() + */ + public function test_get_resourcelink_from_consumer() { + $dc = new data_connector(); + + $consumer = new ToolConsumer(null, $dc); + $consumer->name = 'TestName'; + $consumer->setKey('TestKey'); + $consumer->secret = 'TestSecret'; + $consumer->save(); + + // No ResourceLink associated with the ToolConsumer yet. + $this->assertNull($dc->get_resourcelink_from_consumer($consumer)); + + // Create and save ResourceLink from ToolConsumer. + $resourcelink = ResourceLink::fromConsumer($consumer, 'testresourcelinkid'); + $resourcelink->save(); + $dc->loadResourceLink($resourcelink); + + // Assert that the resource link and the one fetched by get_resourcelink_from_consumer() are the same. + $this->assertEquals($resourcelink, $dc->get_resourcelink_from_consumer($consumer)); + } + + /** + * Test for data_connector::get_resourcelink_from_context() + */ + public function test_get_resourcelink_from_context() { + $dc = new data_connector(); + + $consumer = new ToolConsumer(null, $dc); + $consumer->name = 'TestName'; + $consumer->setKey('TestKey'); + $consumer->secret = 'TestSecret'; + $consumer->save(); + + $settings = ['a', 'b', 'c']; + $lticontextid = 'testlticontextid'; + $context = Context::fromConsumer($consumer, $lticontextid); + $context->settings = $settings; + $context->save(); + + // No ResourceLink associated with the Context yet. + $this->assertNull($dc->get_resourcelink_from_context($context)); + + // Create and save ResourceLink from the Context. + $resourcelink = ResourceLink::fromContext($context, 'testresourcelinkid'); + $resourcelink->save(); + $dc->loadResourceLink($resourcelink); + + // Assert that the resource link and the one fetched by get_resourcelink_from_context() are the same. + $this->assertEquals($resourcelink, $dc->get_resourcelink_from_context($context)); + } } diff --git a/enrol/lti/tests/sync_members_test.php b/enrol/lti/tests/sync_members_test.php new file mode 100644 index 00000000000..f9061bf6d16 --- /dev/null +++ b/enrol/lti/tests/sync_members_test.php @@ -0,0 +1,400 @@ +. + +/** + * Tests for the sync_members scheduled task class. + * + * @package enrol_lti + * @copyright 2016 Jun Pataleta + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +use enrol_lti\data_connector; +use enrol_lti\helper; +use enrol_lti\task\sync_members; +use enrol_lti\tool_provider; +use IMSGlobal\LTI\ToolProvider\Context; +use IMSGlobal\LTI\ToolProvider\ResourceLink; +use IMSGlobal\LTI\ToolProvider\ToolConsumer; +use IMSGlobal\LTI\ToolProvider\User; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Tests for the sync_members scheduled task class. + * + * @package enrol_lti + * @copyright 2016 Jun Pataleta + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class sync_members_testcase extends advanced_testcase { + /** @var dummy_sync_members_task $task */ + protected $task; + + /** @var stdClass $tool The published tool. */ + protected $tool; + + /** @var User[] $members */ + protected $members; + + /** @var ToolConsumer $consumer */ + protected $consumer; + + /** @var Context $context */ + protected $context; + + /** @var ResourceLink $resourcelink */ + protected $resourcelink; + + public function setUp() { + $this->resetAfterTest(); + + // Set this user as the admin. + $this->setAdminUser(); + + $this->task = new dummy_sync_members_task(); + + $generator = $this->getDataGenerator(); + $course = $generator->create_course(); + $tooldata = [ + 'courseid' => $course->id, + 'membersyncmode' => helper::MEMBER_SYNC_ENROL_AND_UNENROL, + 'membersync' => 1, + ]; + $tool = $generator->create_lti_tool((object)$tooldata); + $this->tool = helper::get_lti_tool($tool->id); + + $dataconnector = $this->task->get_dataconnector(); + $this->consumer = new ToolConsumer('Consumer1Key', $dataconnector); + $this->consumer->name = 'Consumer1'; + $this->consumer->secret = 'Consumer1Secret'; + $this->consumer->save(); + + $toolprovider = new tool_provider($this->tool->id); + $toolprovider->consumer = $this->consumer; + $toolprovider->map_tool_to_consumer(); + + $imageurl = $this->getExternalTestFileUrl('test.jpg'); + $count = 10; + $this->members = []; + for ($i = 1; $i <= $count; $i++) { + $user = new User(); + $user->firstname = 'Firstname' . $i; + $user->lastname = 'Lastname' . $i; + $user->ltiUserId = 'user' . $i; + // Set user image values for some users. + if ($i % 3 == 0) { + $user->image = $imageurl; + } + $this->members[] = $user; + } + + $this->context = Context::fromConsumer($this->consumer, 'testlticontextid'); + $this->context->save(); + + $this->resourcelink = ResourceLink::fromContext($this->context, 'testresourcelinkid'); + $this->resourcelink->save(); + } + + /** + * Test for sync_members::do_context_membership_request(). + */ + public function test_do_context_membership_request() { + // Suppress output. + ob_start(); + $members = $this->task->do_context_membership_request($this->context); + ob_end_clean(); + $this->assertFalse($members); + } + + /** + * Test for sync_members::do_resourcelink_membership_request(). + */ + public function test_do_resourcelink_membership_request() { + $members = $this->task->do_resourcelink_membership_request($this->resourcelink); + $this->assertFalse($members); + } + + /** + * Test for sync_members::execute() when auth_lti is disabled. + */ + public function test_execute_authdisabled() { + ob_start(); + $this->task->execute(); + $output = ob_get_clean(); + $message = 'Skipping task - ' . get_string('pluginnotenabled', 'auth', get_string('pluginname', 'auth_lti')); + $this->assertContains($message, $output); + } + + /** + * Test for sync_members::execute() when enrol_lti is disabled. + */ + public function test_execute_enroldisabled() { + // Enable auth_lti. + $this->enable_auth(); + + ob_start(); + $this->task->execute(); + $output = ob_get_clean(); + $message = 'Skipping task - ' . get_string('enrolisdisabled', 'enrol_lti'); + $this->assertContains($message, $output); + } + + /** + * Test for sync_members::execute(). + */ + public function test_execute() { + // Enable auth_lti. + $this->enable_auth(); + + // Enable enrol_lti. + $this->enable_enrol(); + + ob_start(); + $this->task->execute(); + $output = ob_get_clean(); + + $membersyncmessage = "Completed - Synced members for tool '{$this->tool->id}' in the course '{$this->tool->courseid}'"; + $this->assertContains($membersyncmessage, $output); + + $imagesyncmessage = "Completed - Synced 0 profile images."; + $this->assertContains($imagesyncmessage, $output); + } + + /** + * Test for sync_members::fetch_members_from_consumer() with no resource link nor context associated with the consumer. + */ + public function test_fetch_members_from_consumer_noresourcelink_nocontext() { + // Suppress output. + ob_start(); + $members = $this->task->fetch_members_from_consumer($this->consumer); + ob_end_clean(); + $this->assertFalse($members); + } + + /** + * Test for sync_members::get_name(). + */ + public function test_get_name() { + $this->assertEquals(get_string('tasksyncmembers', 'enrol_lti'), $this->task->get_name()); + } + + /** + * Test for sync_members::should_sync_enrol(). + */ + public function test_should_sync_enrol() { + $this->assertTrue($this->task->should_sync_enrol(helper::MEMBER_SYNC_ENROL_AND_UNENROL)); + $this->assertTrue($this->task->should_sync_enrol(helper::MEMBER_SYNC_ENROL_NEW)); + $this->assertFalse($this->task->should_sync_enrol(helper::MEMBER_SYNC_UNENROL_MISSING)); + } + + /** + * Test for sync_members::should_sync_unenrol(). + */ + public function test_should_sync_unenrol() { + $this->assertTrue($this->task->should_sync_unenrol(helper::MEMBER_SYNC_ENROL_AND_UNENROL)); + $this->assertFalse($this->task->should_sync_unenrol(helper::MEMBER_SYNC_ENROL_NEW)); + $this->assertTrue($this->task->should_sync_unenrol(helper::MEMBER_SYNC_UNENROL_MISSING)); + } + + /** + * Test for sync_members::sync_member_information(). + */ + public function test_sync_member_information() { + list($totalcount, $enrolledcount) = $this->task->sync_member_information($this->tool, $this->consumer, $this->members); + $membercount = count($this->members); + $this->assertCount(10, $this->members); + $this->assertEquals($membercount, $totalcount); + $this->assertEquals($membercount, $enrolledcount); + } + + /** + * Test for sync_members::sync_profile_images(). + */ + public function test_sync_profile_images() { + $task = $this->task; + list($totalcount, $enrolledcount) = $task->sync_member_information($this->tool, $this->consumer, $this->members); + $membercount = count($this->members); + $this->assertCount(10, $this->members); + $this->assertEquals($membercount, $totalcount); + $this->assertEquals($membercount, $enrolledcount); + + // Suppress output. + ob_start(); + $this->assertEquals(3, $task->sync_profile_images()); + ob_end_clean(); + } + + /** + * Test for sync_members::sync_unenrol(). + */ + public function test_sync_unenrol() { + $tool = $this->tool; + $task = $this->task; + + $task->sync_member_information($tool, $this->consumer, $this->members); + + // Simulate that the fetched list of current users has been reduced by 3. + $unenrolcount = 3; + for ($i = 0; $i < $unenrolcount; $i++) { + $task->pop_current_users(); + } + $this->assertEquals($unenrolcount, $task->sync_unenrol($tool)); + } + + /** + * Enable auth_lti plugin. + */ + protected function enable_auth() { + $auths = get_enabled_auth_plugins(true); + if (!in_array('lti', $auths)) { + $auths[] = 'lti'; + } + set_config('auth', implode(',', $auths)); + } + + /** + * Enable enrol_lti plugin. + */ + protected function enable_enrol() { + $enabled = enrol_get_plugins(true); + $enabled['lti'] = true; + $enabled = array_keys($enabled); + set_config('enrol_plugins_enabled', implode(',', $enabled)); + } +} + +/** + * Class dummy_sync_members_task. + * + * A class that extends sync_members so that we can expose the protected methods that we would like to test. + * + * @copyright 2016 Jun Pataleta + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class dummy_sync_members_task extends sync_members { + /** + * Exposes/generates the dataconnector property. + * + * @return data_connector + */ + public function get_dataconnector() { + if (!$this->dataconnector) { + $this->dataconnector = new data_connector(); + } + return $this->dataconnector; + } + + /** + * Helper method that removes an element in the array of current users. + */ + public function pop_current_users() { + array_pop($this->currentusers); + } + + /** + * Exposes sync_members::do_context_membership_request() + * + * @param Context $context The context object. + * @param ResourceLink $resourcelink The resource link object. + * @param string $membershipsurltemplate The memberships endpoint URL template. + * @return bool|User[] Array of User objects upon successful membership service request. False, otherwise. + */ + public function do_context_membership_request(Context $context, ResourceLink $resourcelink = null, + $membershipsurltemplate = '') { + $members = parent::do_context_membership_request($context, $resourcelink, $membershipsurltemplate); + return $members; + } + + + /** + * Exposes sync_members::do_resourcelink_membership_request() + * + * @param ResourceLink $resourcelink + * @return bool|User[] + */ + public function do_resourcelink_membership_request(ResourceLink $resourcelink) { + $members = parent::do_resourcelink_membership_request($resourcelink); + return $members; + } + + /** + * Exposes sync_members::fetch_members_from_consumer() + * + * @param ToolConsumer $consumer + * @return bool|User[] + */ + public function fetch_members_from_consumer(ToolConsumer $consumer) { + $members = parent::fetch_members_from_consumer($consumer); + return $members; + } + + /** + * Exposes sync_members::should_sync_unenrol() + * + * @param int $syncmode The tool's membersyncmode. + * @return bool + */ + public function should_sync_unenrol($syncmode) { + $shouldsync = parent::should_sync_unenrol($syncmode); + return $shouldsync; + } + + /** + * Exposes sync_members::should_sync_enrol() + * + * @param int $syncmode The tool's membersyncmode. + * @return bool + */ + public function should_sync_enrol($syncmode) { + $shouldsync = parent::should_sync_enrol($syncmode); + return $shouldsync; + } + + /** + * Exposes sync_members::sync_member_information() + * + * @param stdClass $tool + * @param ToolConsumer $consumer + * @param User[] $members + * @return array + */ + public function sync_member_information(stdClass $tool, ToolConsumer $consumer, $members) { + $result = parent::sync_member_information($tool, $consumer, $members); + return $result; + } + + /** + * Exposes sync_members::sync_profile_images() + * + * @return int + */ + public function sync_profile_images() { + $count = parent::sync_profile_images(); + return $count; + } + + /** + * Exposes sync_members::sync_unenrol() + * + * @param stdClass $tool + * @return int + */ + public function sync_unenrol(stdClass $tool) { + $count = parent::sync_unenrol($tool); + return $count; + } +}