Search moodle.org's
Developer Documentation

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.
  • Differences Between: [Versions 310 and 311] [Versions 37 and 311] [Versions 38 and 311] [Versions 39 and 311]

       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  /**
      18   * Tests for the sync_members scheduled task class.
      19   *
      20   * @package enrol_lti
      21   * @copyright 2016 Jun Pataleta <jun@moodle.com>
      22   * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
      23   */
      24  
      25  namespace enrol_lti;
      26  
      27  use enrol_lti\task\sync_members;
      28  use IMSGlobal\LTI\ToolProvider\Context;
      29  use IMSGlobal\LTI\ToolProvider\ResourceLink;
      30  use IMSGlobal\LTI\ToolProvider\ToolConsumer;
      31  use IMSGlobal\LTI\ToolProvider\User;
      32  
      33  defined('MOODLE_INTERNAL') || die();
      34  
      35  /**
      36   * Tests for the sync_members scheduled task class.
      37   *
      38   * @package enrol_lti
      39   * @copyright 2016 Jun Pataleta <jun@moodle.com>
      40   * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
      41   */
      42  class sync_members_test extends \advanced_testcase {
      43      /** @var dummy_sync_members_task $task */
      44      protected $task;
      45  
      46      /** @var  \stdClass $tool The published tool. */
      47      protected $tool;
      48  
      49      /** @var User[] $members */
      50      protected $members;
      51  
      52      /** @var  ToolConsumer $consumer */
      53      protected $consumer;
      54  
      55      /** @var  Context $context */
      56      protected $context;
      57  
      58      /** @var  ResourceLink $resourcelink */
      59      protected $resourcelink;
      60  
      61      public function setUp(): void {
      62          $this->resetAfterTest();
      63  
      64          // Set this user as the admin.
      65          $this->setAdminUser();
      66  
      67          $this->task = new dummy_sync_members_task();
      68  
      69          $generator = $this->getDataGenerator();
      70          $course = $generator->create_course();
      71          $tooldata = [
      72              'courseid' => $course->id,
      73              'membersyncmode' => helper::MEMBER_SYNC_ENROL_AND_UNENROL,
      74              'membersync' => 1,
      75          ];
      76          $tool = $generator->create_lti_tool((object)$tooldata);
      77          $this->tool = helper::get_lti_tool($tool->id);
      78  
      79          $dataconnector = $this->task->get_dataconnector();
      80          $this->consumer = new ToolConsumer('Consumer1Key', $dataconnector);
      81          $this->consumer->name = 'Consumer1';
      82          $this->consumer->secret = 'Consumer1Secret';
      83          $this->consumer->save();
      84  
      85          $toolprovider = new tool_provider($this->tool->id);
      86          $toolprovider->consumer = $this->consumer;
      87          $toolprovider->map_tool_to_consumer();
      88  
      89          $imageurl = $this->getExternalTestFileUrl('test.jpg');
      90          $count = 10;
      91          $this->members = [];
      92          for ($i = 1; $i <= $count; $i++) {
      93              $user = new User();
      94              $user->firstname = 'Firstname' . $i;
      95              $user->lastname = 'Lastname' . $i;
      96              $user->ltiUserId = 'user' . $i;
      97              // Set user image values for some users.
      98              if ($i % 3 == 0) {
      99                  $user->image = $imageurl;
     100              }
     101              $this->members[] = $user;
     102          }
     103  
     104          $this->context = Context::fromConsumer($this->consumer, 'testlticontextid');
     105          $this->context->save();
     106  
     107          $this->resourcelink = ResourceLink::fromContext($this->context, 'testresourcelinkid');
     108          $this->resourcelink->save();
     109      }
     110  
     111      /**
     112       * Test for sync_members::do_context_membership_request().
     113       */
     114      public function test_do_context_membership_request() {
     115          // Suppress output.
     116          ob_start();
     117          $members = $this->task->do_context_membership_request($this->context);
     118          ob_end_clean();
     119          $this->assertFalse($members);
     120      }
     121  
     122      /**
     123       * Test for sync_members::do_resourcelink_membership_request().
     124       */
     125      public function test_do_resourcelink_membership_request() {
     126          $members = $this->task->do_resourcelink_membership_request($this->resourcelink);
     127          $this->assertFalse($members);
     128      }
     129  
     130      /**
     131       * Test for sync_members::execute() when auth_lti is disabled.
     132       */
     133      public function test_execute_authdisabled() {
     134          ob_start();
     135          $this->task->execute();
     136          $output = ob_get_clean();
     137          $message = 'Skipping task - ' . get_string('pluginnotenabled', 'auth', get_string('pluginname', 'auth_lti'));
     138          $this->assertStringContainsString($message, $output);
     139      }
     140  
     141      /**
     142       * Test for sync_members::execute() when enrol_lti is disabled.
     143       */
     144      public function test_execute_enroldisabled() {
     145          // Enable auth_lti.
     146          $this->enable_auth();
     147  
     148          ob_start();
     149          $this->task->execute();
     150          $output = ob_get_clean();
     151          $message = 'Skipping task - ' . get_string('enrolisdisabled', 'enrol_lti');
     152          $this->assertStringContainsString($message, $output);
     153      }
     154  
     155      /**
     156       * Test for sync_members::execute().
     157       */
     158      public function test_execute() {
     159          // Enable auth_lti.
     160          $this->enable_auth();
     161  
     162          // Enable enrol_lti.
     163          $this->enable_enrol();
     164  
     165          ob_start();
     166          $this->task->execute();
     167          $output = ob_get_clean();
     168  
     169          $membersyncmessage = "Completed - Synced members for tool '{$this->tool->id}' in the course '{$this->tool->courseid}'";
     170          $this->assertStringContainsString($membersyncmessage, $output);
     171  
     172          $imagesyncmessage = "Completed - Synced 0 profile images.";
     173          $this->assertStringContainsString($imagesyncmessage, $output);
     174      }
     175  
     176      /**
     177       * Test for sync_members::fetch_members_from_consumer() with no resource link nor context associated with the consumer.
     178       */
     179      public function test_fetch_members_from_consumer_noresourcelink_nocontext() {
     180          // Suppress output.
     181          ob_start();
     182          $members = $this->task->fetch_members_from_consumer($this->consumer);
     183          ob_end_clean();
     184          $this->assertFalse($members);
     185      }
     186  
     187      /**
     188       * Test for sync_members::get_name().
     189       */
     190      public function test_get_name() {
     191          $this->assertEquals(get_string('tasksyncmembers', 'enrol_lti'), $this->task->get_name());
     192      }
     193  
     194      /**
     195       * Test for sync_members::should_sync_enrol().
     196       */
     197      public function test_should_sync_enrol() {
     198          $this->assertTrue($this->task->should_sync_enrol(helper::MEMBER_SYNC_ENROL_AND_UNENROL));
     199          $this->assertTrue($this->task->should_sync_enrol(helper::MEMBER_SYNC_ENROL_NEW));
     200          $this->assertFalse($this->task->should_sync_enrol(helper::MEMBER_SYNC_UNENROL_MISSING));
     201      }
     202  
     203      /**
     204       * Test for sync_members::should_sync_unenrol().
     205       */
     206      public function test_should_sync_unenrol() {
     207          $this->assertTrue($this->task->should_sync_unenrol(helper::MEMBER_SYNC_ENROL_AND_UNENROL));
     208          $this->assertFalse($this->task->should_sync_unenrol(helper::MEMBER_SYNC_ENROL_NEW));
     209          $this->assertTrue($this->task->should_sync_unenrol(helper::MEMBER_SYNC_UNENROL_MISSING));
     210      }
     211  
     212      /**
     213       * Test for sync_members::sync_member_information().
     214       */
     215      public function test_sync_member_information() {
     216          list($users, $enrolledcount) = $this->task->sync_member_information($this->tool, $this->consumer, $this->members);
     217          $membercount = count($this->members);
     218          $this->assertCount(10, $this->members);
     219          $this->assertCount($membercount, $users);
     220          $this->assertEquals($membercount, $enrolledcount);
     221      }
     222  
     223      /**
     224       * Test for sync_members::sync_profile_images().
     225       */
     226      public function test_sync_profile_images() {
     227          $task = $this->task;
     228          list($users, $enrolledcount) = $task->sync_member_information($this->tool, $this->consumer, $this->members);
     229          $membercount = count($this->members);
     230          $this->assertCount(10, $this->members);
     231          $this->assertCount($membercount, $users);
     232          $this->assertEquals($membercount, $enrolledcount);
     233  
     234          // Suppress output.
     235          ob_start();
     236          $this->assertEquals(3, $task->sync_profile_images());
     237          ob_end_clean();
     238      }
     239  
     240      /**
     241       * Test for sync_members::sync_unenrol().
     242       */
     243      public function test_sync_unenrol() {
     244          $tool = $this->tool;
     245          $task = $this->task;
     246  
     247          list($users) = $task->sync_member_information($tool, $this->consumer, $this->members);
     248  
     249          // Simulate that the fetched list of current users has been reduced by 3.
     250          $unenrolcount = 3;
     251          for ($i = 0; $i < $unenrolcount; $i++) {
     252              array_pop($users);
     253          }
     254          $this->assertEquals($unenrolcount, $task->sync_unenrol($tool, 'Consumer1Key', $users));
     255      }
     256  
     257      /**
     258       * Enable auth_lti plugin.
     259       */
     260      protected function enable_auth() {
     261          $auths = get_enabled_auth_plugins();
     262          if (!in_array('lti', $auths)) {
     263              $auths[] = 'lti';
     264          }
     265          set_config('auth', implode(',', $auths));
     266      }
     267  
     268      /**
     269       * Enable enrol_lti plugin.
     270       */
     271      protected function enable_enrol() {
     272          $enabled = enrol_get_plugins(true);
     273          $enabled['lti'] = true;
     274          $enabled = array_keys($enabled);
     275          set_config('enrol_plugins_enabled', implode(',', $enabled));
     276      }
     277  }
     278  
     279  /**
     280   * Class dummy_sync_members_task.
     281   *
     282   * A class that extends sync_members so that we can expose the protected methods that we would like to test.
     283   *
     284   * @copyright 2016 Jun Pataleta <jun@moodle.com>
     285   * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
     286   */
     287  class dummy_sync_members_task extends sync_members {
     288      /**
     289       * Exposes/generates the dataconnector property.
     290       *
     291       * @return data_connector
     292       */
     293      public function get_dataconnector() {
     294          if (!$this->dataconnector) {
     295              $this->dataconnector = new data_connector();
     296          }
     297          return $this->dataconnector;
     298      }
     299  
     300      /**
     301       * Exposes sync_members::do_context_membership_request()
     302       *
     303       * @param Context $context The context object.
     304       * @param ResourceLink $resourcelink The resource link object.
     305       * @param string $membershipsurltemplate The memberships endpoint URL template.
     306       * @return bool|User[] Array of User objects upon successful membership service request. False, otherwise.
     307       */
     308      public function do_context_membership_request(Context $context, ResourceLink $resourcelink = null,
     309                                                    $membershipsurltemplate = '') {
     310          $members = parent::do_context_membership_request($context, $resourcelink, $membershipsurltemplate);
     311          return $members;
     312      }
     313  
     314  
     315      /**
     316       * Exposes sync_members::do_resourcelink_membership_request()
     317       *
     318       * @param ResourceLink $resourcelink
     319       * @return bool|User[]
     320       */
     321      public function do_resourcelink_membership_request(ResourceLink $resourcelink) {
     322          $members = parent::do_resourcelink_membership_request($resourcelink);
     323          return $members;
     324      }
     325  
     326      /**
     327       * Exposes sync_members::fetch_members_from_consumer()
     328       *
     329       * @param ToolConsumer $consumer
     330       * @return bool|User[]
     331       */
     332      public function fetch_members_from_consumer(ToolConsumer $consumer) {
     333          $members = parent::fetch_members_from_consumer($consumer);
     334          return $members;
     335      }
     336  
     337      /**
     338       * Exposes sync_members::should_sync_unenrol()
     339       *
     340       * @param int $syncmode The tool's membersyncmode.
     341       * @return bool
     342       */
     343      public function should_sync_unenrol($syncmode) {
     344          $shouldsync = parent::should_sync_unenrol($syncmode);
     345          return $shouldsync;
     346      }
     347  
     348      /**
     349       * Exposes sync_members::should_sync_enrol()
     350       *
     351       * @param int $syncmode The tool's membersyncmode.
     352       * @return bool
     353       */
     354      public function should_sync_enrol($syncmode) {
     355          $shouldsync = parent::should_sync_enrol($syncmode);
     356          return $shouldsync;
     357      }
     358  
     359      /**
     360       * Exposes sync_members::sync_member_information()
     361       *
     362       * @param \stdClass $tool
     363       * @param ToolConsumer $consumer
     364       * @param User[] $members
     365       * @return array
     366       */
     367      public function sync_member_information(\stdClass $tool, ToolConsumer $consumer, $members) {
     368          $result = parent::sync_member_information($tool, $consumer, $members);
     369          return $result;
     370      }
     371  
     372      /**
     373       * Exposes sync_members::sync_profile_images()
     374       *
     375       * @return int
     376       */
     377      public function sync_profile_images() {
     378          $count = parent::sync_profile_images();
     379          return $count;
     380      }
     381  
     382      /**
     383       * Exposes sync_members::sync_unenrol()
     384       *
     385       * @param \stdClass $tool
     386       * @param string $consumerkey
     387       * @param array $currentusers
     388       * @return int
     389       */
     390      public function sync_unenrol(\stdClass $tool, string $consumerkey, array $currentusers) {
     391          $count = parent::sync_unenrol($tool, $consumerkey, $currentusers);
     392          return $count;
     393      }
     394  }