Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.0.x will end 8 May 2023 (12 months).
  • Bug fixes for security issues in 4.0.x will end 13 November 2023 (18 months).
  • PHP version: minimum PHP 7.3.0 Note: the minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is also supported.

Differences Between: [Versions 310 and 400] [Versions 39 and 400] [Versions 400 and 401] [Versions 400 and 402] [Versions 400 and 403]

   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_meta;
  18  
  19  /**
  20   * Meta enrolment sync functional test.
  21   *
  22   * @package    enrol_meta
  23   * @category   phpunit
  24   * @copyright  2013 Petr Skoda {@link http://skodak.org}
  25   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  26   */
  27  class plugin_test extends \advanced_testcase {
  28  
  29      protected function enable_plugin() {
  30          $enabled = enrol_get_plugins(true);
  31          $enabled['meta'] = true;
  32          $enabled = array_keys($enabled);
  33          set_config('enrol_plugins_enabled', implode(',', $enabled));
  34      }
  35  
  36      protected function disable_plugin() {
  37          $enabled = enrol_get_plugins(true);
  38          unset($enabled['meta']);
  39          $enabled = array_keys($enabled);
  40          set_config('enrol_plugins_enabled', implode(',', $enabled));
  41      }
  42  
  43      protected function is_meta_enrolled($user, $enrol, $role = null) {
  44          global $DB;
  45  
  46          if (!$DB->record_exists('user_enrolments', array('enrolid'=>$enrol->id, 'userid'=>$user->id))) {
  47              return false;
  48          }
  49  
  50          if ($role === null) {
  51              return true;
  52          }
  53  
  54          return $this->has_role($user, $enrol, $role);
  55      }
  56  
  57      protected function has_role($user, $enrol, $role) {
  58          global $DB;
  59  
  60          $context = \context_course::instance($enrol->courseid);
  61  
  62          if ($role === false) {
  63              if ($DB->record_exists('role_assignments', array('contextid'=>$context->id, 'userid'=>$user->id, 'component'=>'enrol_meta', 'itemid'=>$enrol->id))) {
  64                  return false;
  65              }
  66          } else if (!$DB->record_exists('role_assignments', array('contextid'=>$context->id, 'userid'=>$user->id, 'roleid'=>$role->id, 'component'=>'enrol_meta', 'itemid'=>$enrol->id))) {
  67              return false;
  68          }
  69  
  70          return true;
  71      }
  72  
  73      public function test_sync() {
  74          global $CFG, $DB;
  75  
  76          $this->resetAfterTest(true);
  77  
  78          $metalplugin = enrol_get_plugin('meta');
  79          $manplugin = enrol_get_plugin('manual');
  80  
  81          $user1 = $this->getDataGenerator()->create_user();
  82          $user2 = $this->getDataGenerator()->create_user();
  83          $user3 = $this->getDataGenerator()->create_user();
  84          $user4 = $this->getDataGenerator()->create_user();
  85          $user5 = $this->getDataGenerator()->create_user();
  86  
  87          $course1 = $this->getDataGenerator()->create_course();
  88          $course2 = $this->getDataGenerator()->create_course();
  89          $course3 = $this->getDataGenerator()->create_course();
  90          $course4 = $this->getDataGenerator()->create_course();
  91          $manual1 = $DB->get_record('enrol', array('courseid'=>$course1->id, 'enrol'=>'manual'), '*', MUST_EXIST);
  92          $manual2 = $DB->get_record('enrol', array('courseid'=>$course2->id, 'enrol'=>'manual'), '*', MUST_EXIST);
  93          $manual3 = $DB->get_record('enrol', array('courseid'=>$course3->id, 'enrol'=>'manual'), '*', MUST_EXIST);
  94          $manual4 = $DB->get_record('enrol', array('courseid'=>$course4->id, 'enrol'=>'manual'), '*', MUST_EXIST);
  95  
  96          $student = $DB->get_record('role', array('shortname'=>'student'));
  97          $teacher = $DB->get_record('role', array('shortname'=>'teacher'));
  98          $manager = $DB->get_record('role', array('shortname'=>'manager'));
  99  
 100          $this->disable_plugin();
 101  
 102          $this->getDataGenerator()->enrol_user($user1->id, $course1->id, $student->id);
 103          $this->getDataGenerator()->enrol_user($user2->id, $course1->id, $student->id);
 104          $this->getDataGenerator()->enrol_user($user3->id, $course1->id, 0);
 105          $this->getDataGenerator()->enrol_user($user4->id, $course1->id, $teacher->id);
 106          $this->getDataGenerator()->enrol_user($user5->id, $course1->id, $manager->id);
 107  
 108          $this->getDataGenerator()->enrol_user($user1->id, $course2->id, $student->id);
 109          $this->getDataGenerator()->enrol_user($user2->id, $course2->id, $teacher->id);
 110  
 111          $this->assertEquals(7, $DB->count_records('user_enrolments'));
 112          $this->assertEquals(6, $DB->count_records('role_assignments'));
 113  
 114          set_config('syncall', 0, 'enrol_meta');
 115          set_config('nosyncroleids', $manager->id, 'enrol_meta');
 116  
 117          require_once($CFG->dirroot.'/enrol/meta/locallib.php');
 118  
 119          enrol_meta_sync(null, false);
 120          $this->assertEquals(7, $DB->count_records('user_enrolments'));
 121          $this->assertEquals(6, $DB->count_records('role_assignments'));
 122  
 123          $this->enable_plugin();
 124          enrol_meta_sync(null, false);
 125          $this->assertEquals(7, $DB->count_records('user_enrolments'));
 126          $this->assertEquals(6, $DB->count_records('role_assignments'));
 127  
 128          // Disable the plugin to prevent add_instance from calling enrol_meta_sync.
 129          $this->disable_plugin();
 130          $e1 = $metalplugin->add_instance($course3, array('customint1'=>$course1->id));
 131          $e2 = $metalplugin->add_instance($course3, array('customint1'=>$course2->id));
 132          $e3 = $metalplugin->add_instance($course4, array('customint1'=>$course2->id));
 133          $enrol1 = $DB->get_record('enrol', array('id'=>$e1));
 134          $enrol2 = $DB->get_record('enrol', array('id'=>$e2));
 135          $enrol3 = $DB->get_record('enrol', array('id'=>$e3));
 136          $this->enable_plugin();
 137  
 138          enrol_meta_sync($course4->id, false);
 139          $this->assertEquals(9, $DB->count_records('user_enrolments'));
 140          $this->assertEquals(8, $DB->count_records('role_assignments'));
 141          $this->assertTrue($this->is_meta_enrolled($user1, $enrol3, $student));
 142          $this->assertTrue($this->is_meta_enrolled($user2, $enrol3, $teacher));
 143  
 144          enrol_meta_sync(null, false);
 145          $this->assertEquals(14, $DB->count_records('user_enrolments'));
 146          $this->assertEquals(13, $DB->count_records('role_assignments'));
 147  
 148          $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student));
 149          $this->assertTrue($this->is_meta_enrolled($user2, $enrol1, $student));
 150          $this->assertFalse($this->is_meta_enrolled($user3, $enrol1));
 151          $this->assertTrue($this->is_meta_enrolled($user4, $enrol1, $teacher));
 152          $this->assertFalse($this->is_meta_enrolled($user5, $enrol1));
 153  
 154          $this->assertTrue($this->is_meta_enrolled($user1, $enrol2, $student));
 155          $this->assertTrue($this->is_meta_enrolled($user2, $enrol2, $teacher));
 156  
 157          $this->assertTrue($this->is_meta_enrolled($user1, $enrol3, $student));
 158          $this->assertTrue($this->is_meta_enrolled($user2, $enrol3, $teacher));
 159  
 160          set_config('syncall', 1, 'enrol_meta');
 161          enrol_meta_sync(null, false);
 162          $this->assertEquals(16, $DB->count_records('user_enrolments'));
 163          $this->assertEquals(13, $DB->count_records('role_assignments'));
 164  
 165          $this->assertTrue($this->is_meta_enrolled($user3, $enrol1, false));
 166          $this->assertTrue($this->is_meta_enrolled($user5, $enrol1, false));
 167  
 168          $this->assertEquals(16, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 169          $this->disable_plugin();
 170          $manplugin->unenrol_user($manual1, $user1->id);
 171          $manplugin->unenrol_user($manual2, $user1->id);
 172  
 173          $this->assertEquals(14, $DB->count_records('user_enrolments'));
 174          $this->assertEquals(11, $DB->count_records('role_assignments'));
 175          $this->assertEquals(14, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 176  
 177          $this->enable_plugin();
 178  
 179          set_config('unenrolaction', ENROL_EXT_REMOVED_SUSPEND, 'enrol_meta');
 180          enrol_meta_sync($course4->id, false);
 181          $this->assertEquals(14, $DB->count_records('user_enrolments'));
 182          $this->assertEquals(11, $DB->count_records('role_assignments'));
 183          $this->assertEquals(13, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 184          $this->assertTrue($this->is_meta_enrolled($user1, $enrol3, $student));
 185          $this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$enrol3->id, 'status'=>ENROL_USER_SUSPENDED, 'userid'=>$user1->id)));
 186  
 187          enrol_meta_sync(null, false);
 188          $this->assertEquals(14, $DB->count_records('user_enrolments'));
 189          $this->assertEquals(11, $DB->count_records('role_assignments'));
 190          $this->assertEquals(11, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 191          $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student));
 192          $this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$enrol1->id, 'status'=>ENROL_USER_SUSPENDED, 'userid'=>$user1->id)));
 193          $this->assertTrue($this->is_meta_enrolled($user1, $enrol2, $student));
 194          $this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$enrol2->id, 'status'=>ENROL_USER_SUSPENDED, 'userid'=>$user1->id)));
 195  
 196          set_config('unenrolaction', ENROL_EXT_REMOVED_SUSPENDNOROLES, 'enrol_meta');
 197          enrol_meta_sync($course4->id, false);
 198          $this->assertEquals(14, $DB->count_records('user_enrolments'));
 199          $this->assertEquals(10, $DB->count_records('role_assignments'));
 200          $this->assertEquals(11, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 201          $this->assertTrue($this->is_meta_enrolled($user1, $enrol3, false));
 202          $this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$enrol3->id, 'status'=>ENROL_USER_SUSPENDED, 'userid'=>$user1->id)));
 203  
 204          enrol_meta_sync(null, false);
 205          $this->assertEquals(14, $DB->count_records('user_enrolments'));
 206          $this->assertEquals(8, $DB->count_records('role_assignments'));
 207          $this->assertEquals(11, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 208          $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, false));
 209          $this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$enrol1->id, 'status'=>ENROL_USER_SUSPENDED, 'userid'=>$user1->id)));
 210          $this->assertTrue($this->is_meta_enrolled($user1, $enrol2, false));
 211          $this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$enrol2->id, 'status'=>ENROL_USER_SUSPENDED, 'userid'=>$user1->id)));
 212  
 213          set_config('unenrolaction', ENROL_EXT_REMOVED_UNENROL, 'enrol_meta');
 214          enrol_meta_sync($course4->id, false);
 215          $this->assertEquals(13, $DB->count_records('user_enrolments'));
 216          $this->assertEquals(8, $DB->count_records('role_assignments'));
 217          $this->assertEquals(11, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 218          $this->assertFalse($this->is_meta_enrolled($user1, $enrol3));
 219  
 220          enrol_meta_sync(null, false);
 221          $this->assertEquals(11, $DB->count_records('user_enrolments'));
 222          $this->assertEquals(8, $DB->count_records('role_assignments'));
 223          $this->assertEquals(11, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 224          $this->assertFalse($this->is_meta_enrolled($user1, $enrol1));
 225          $this->assertFalse($this->is_meta_enrolled($user1, $enrol2));
 226  
 227  
 228          // Now try sync triggered by events.
 229  
 230          set_config('syncall', 1, 'enrol_meta');
 231  
 232          $this->getDataGenerator()->enrol_user($user1->id, $course1->id, $student->id);
 233          $this->assertEquals(13, $DB->count_records('user_enrolments'));
 234          $this->assertEquals(10, $DB->count_records('role_assignments'));
 235          $this->assertEquals(13, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 236          $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student));
 237          enrol_meta_sync(null, false);
 238          $this->assertEquals(13, $DB->count_records('user_enrolments'));
 239          $this->assertEquals(10, $DB->count_records('role_assignments'));
 240          $this->assertEquals(13, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 241          $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student));
 242  
 243          $manplugin->unenrol_user($manual1, $user1->id);
 244          $this->assertEquals(11, $DB->count_records('user_enrolments'));
 245          $this->assertEquals(8, $DB->count_records('role_assignments'));
 246          $this->assertEquals(11, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 247          $this->assertFalse($this->is_meta_enrolled($user1, $enrol1));
 248          enrol_meta_sync(null, false);
 249          $this->assertEquals(11, $DB->count_records('user_enrolments'));
 250          $this->assertEquals(8, $DB->count_records('role_assignments'));
 251          $this->assertEquals(11, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 252          $this->assertFalse($this->is_meta_enrolled($user1, $enrol1));
 253  
 254          $this->getDataGenerator()->enrol_user($user1->id, $course1->id, 0);
 255          $this->assertEquals(13, $DB->count_records('user_enrolments'));
 256          $this->assertEquals(8, $DB->count_records('role_assignments'));
 257          $this->assertEquals(13, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 258          $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, false));
 259          enrol_meta_sync(null, false);
 260          $this->assertEquals(13, $DB->count_records('user_enrolments'));
 261          $this->assertEquals(8, $DB->count_records('role_assignments'));
 262          $this->assertEquals(13, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 263          $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, false));
 264  
 265          $manplugin->unenrol_user($manual1, $user1->id);
 266          $this->assertEquals(11, $DB->count_records('user_enrolments'));
 267          $this->assertEquals(8, $DB->count_records('role_assignments'));
 268          $this->assertEquals(11, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 269          $this->assertFalse($this->is_meta_enrolled($user1, $enrol1));
 270          enrol_meta_sync(null, false);
 271          $this->assertEquals(11, $DB->count_records('user_enrolments'));
 272          $this->assertEquals(8, $DB->count_records('role_assignments'));
 273          $this->assertEquals(11, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 274          $this->assertFalse($this->is_meta_enrolled($user1, $enrol1));
 275  
 276          set_config('syncall', 0, 'enrol_meta');
 277          enrol_meta_sync(null, false);
 278          $this->assertEquals(9, $DB->count_records('user_enrolments'));
 279          $this->assertEquals(8, $DB->count_records('role_assignments'));
 280          $this->assertEquals(9, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 281          $this->assertFalse($this->is_meta_enrolled($user1, $enrol1));
 282  
 283          $this->getDataGenerator()->enrol_user($user1->id, $course1->id, 0);
 284          $this->assertEquals(10, $DB->count_records('user_enrolments'));
 285          $this->assertEquals(8, $DB->count_records('role_assignments'));
 286          $this->assertEquals(10, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 287          $this->assertFalse($this->is_meta_enrolled($user1, $enrol1, $student));
 288          enrol_meta_sync(null, false);
 289          $this->assertEquals(10, $DB->count_records('user_enrolments'));
 290          $this->assertEquals(8, $DB->count_records('role_assignments'));
 291          $this->assertEquals(10, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 292          $this->assertFalse($this->is_meta_enrolled($user1, $enrol1, $student));
 293  
 294          role_assign($teacher->id, $user1->id, \context_course::instance($course1->id)->id);
 295          $this->assertEquals(11, $DB->count_records('user_enrolments'));
 296          $this->assertEquals(10, $DB->count_records('role_assignments'));
 297          $this->assertEquals(11, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 298          $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $teacher));
 299          enrol_meta_sync(null, false);
 300          $this->assertEquals(11, $DB->count_records('user_enrolments'));
 301          $this->assertEquals(10, $DB->count_records('role_assignments'));
 302          $this->assertEquals(11, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 303          $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $teacher));
 304  
 305          role_unassign($teacher->id, $user1->id, \context_course::instance($course1->id)->id);
 306          $this->assertEquals(10, $DB->count_records('user_enrolments'));
 307          $this->assertEquals(8, $DB->count_records('role_assignments'));
 308          $this->assertEquals(10, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 309          $this->assertFalse($this->is_meta_enrolled($user1, $enrol1, $student));
 310          enrol_meta_sync(null, false);
 311          $this->assertEquals(10, $DB->count_records('user_enrolments'));
 312          $this->assertEquals(8, $DB->count_records('role_assignments'));
 313          $this->assertEquals(10, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 314          $this->assertFalse($this->is_meta_enrolled($user1, $enrol1, $student));
 315  
 316          $manplugin->unenrol_user($manual1, $user1->id);
 317          $this->assertEquals(9, $DB->count_records('user_enrolments'));
 318          $this->assertEquals(8, $DB->count_records('role_assignments'));
 319          $this->assertEquals(9, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 320          $this->assertFalse($this->is_meta_enrolled($user1, $enrol1));
 321  
 322          set_config('syncall', 1, 'enrol_meta');
 323          set_config('unenrolaction', ENROL_EXT_REMOVED_SUSPEND, 'enrol_meta');
 324          enrol_meta_sync(null, false);
 325          $this->assertEquals(11, $DB->count_records('user_enrolments'));
 326          $this->assertEquals(8, $DB->count_records('role_assignments'));
 327          $this->assertEquals(11, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 328  
 329          $this->getDataGenerator()->enrol_user($user1->id, $course1->id, $student->id);
 330          $this->assertEquals(13, $DB->count_records('user_enrolments'));
 331          $this->assertEquals(10, $DB->count_records('role_assignments'));
 332          $this->assertEquals(13, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 333          $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student));
 334          enrol_meta_sync(null, false);
 335          $this->assertEquals(13, $DB->count_records('user_enrolments'));
 336          $this->assertEquals(10, $DB->count_records('role_assignments'));
 337          $this->assertEquals(13, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 338          $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student));
 339  
 340          $manplugin->update_user_enrol($manual1, $user1->id, ENROL_USER_SUSPENDED);
 341          $this->assertEquals(13, $DB->count_records('user_enrolments'));
 342          $this->assertEquals(10, $DB->count_records('role_assignments'));
 343          $this->assertEquals(11, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 344          $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student));
 345          enrol_meta_sync(null, false);
 346          $this->assertEquals(13, $DB->count_records('user_enrolments'));
 347          $this->assertEquals(10, $DB->count_records('role_assignments'));
 348          $this->assertEquals(11, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 349          $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student));
 350  
 351          $manplugin->unenrol_user($manual1, $user1->id);
 352          $this->assertEquals(12, $DB->count_records('user_enrolments'));
 353          $this->assertEquals(9, $DB->count_records('role_assignments'));
 354          $this->assertEquals(11, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 355          $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student));
 356          enrol_meta_sync(null, false);
 357          $this->assertEquals(12, $DB->count_records('user_enrolments'));
 358          $this->assertEquals(9, $DB->count_records('role_assignments'));
 359          $this->assertEquals(11, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 360          $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student));
 361  
 362          $this->getDataGenerator()->enrol_user($user1->id, $course1->id, $student->id);
 363          $this->assertEquals(13, $DB->count_records('user_enrolments'));
 364          $this->assertEquals(10, $DB->count_records('role_assignments'));
 365          $this->assertEquals(13, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 366          $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student));
 367          enrol_meta_sync(null, false);
 368          $this->assertEquals(13, $DB->count_records('user_enrolments'));
 369          $this->assertEquals(10, $DB->count_records('role_assignments'));
 370          $this->assertEquals(13, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 371          $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student));
 372  
 373          set_config('syncall', 1, 'enrol_meta');
 374          set_config('unenrolaction', ENROL_EXT_REMOVED_SUSPENDNOROLES, 'enrol_meta');
 375          enrol_meta_sync(null, false);
 376          $this->assertEquals(13, $DB->count_records('user_enrolments'));
 377          $this->assertEquals(10, $DB->count_records('role_assignments'));
 378          $this->assertEquals(13, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 379  
 380          $this->getDataGenerator()->enrol_user($user1->id, $course1->id, $student->id);
 381          $this->assertEquals(13, $DB->count_records('user_enrolments'));
 382          $this->assertEquals(10, $DB->count_records('role_assignments'));
 383          $this->assertEquals(13, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 384          $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student));
 385          enrol_meta_sync(null, false);
 386          $this->assertEquals(13, $DB->count_records('user_enrolments'));
 387          $this->assertEquals(10, $DB->count_records('role_assignments'));
 388          $this->assertEquals(13, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 389          $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student));
 390  
 391          $manplugin->unenrol_user($manual1, $user1->id);
 392          $this->assertEquals(12, $DB->count_records('user_enrolments'));
 393          $this->assertEquals(8, $DB->count_records('role_assignments'));
 394          $this->assertEquals(11, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 395          $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, false));
 396          enrol_meta_sync(null, false);
 397          $this->assertEquals(12, $DB->count_records('user_enrolments'));
 398          $this->assertEquals(8, $DB->count_records('role_assignments'));
 399          $this->assertEquals(11, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 400          $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, false));
 401  
 402          $this->getDataGenerator()->enrol_user($user1->id, $course1->id, $student->id);
 403          $this->assertEquals(13, $DB->count_records('user_enrolments'));
 404          $this->assertEquals(10, $DB->count_records('role_assignments'));
 405          $this->assertEquals(13, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 406          $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student));
 407          enrol_meta_sync(null, false);
 408          $this->assertEquals(13, $DB->count_records('user_enrolments'));
 409          $this->assertEquals(10, $DB->count_records('role_assignments'));
 410          $this->assertEquals(13, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 411          $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student));
 412  
 413  
 414          set_config('unenrolaction', ENROL_EXT_REMOVED_UNENROL, 'enrol_meta');
 415          enrol_meta_sync(null, false);
 416          $this->assertEquals(13, $DB->count_records('user_enrolments'));
 417          $this->assertEquals(10, $DB->count_records('role_assignments'));
 418          $this->assertEquals(13, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 419  
 420          delete_course($course1, false);
 421          $this->assertEquals(3, $DB->count_records('user_enrolments'));
 422          $this->assertEquals(3, $DB->count_records('role_assignments'));
 423          $this->assertEquals(3, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 424          enrol_meta_sync(null, false);
 425          $this->assertEquals(3, $DB->count_records('user_enrolments'));
 426          $this->assertEquals(3, $DB->count_records('role_assignments'));
 427          $this->assertEquals(3, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 428  
 429          delete_course($course2, false);
 430          $this->assertEquals(0, $DB->count_records('user_enrolments'));
 431          $this->assertEquals(0, $DB->count_records('role_assignments'));
 432          $this->assertEquals(0, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 433          enrol_meta_sync(null, false);
 434          $this->assertEquals(0, $DB->count_records('user_enrolments'));
 435          $this->assertEquals(0, $DB->count_records('role_assignments'));
 436          $this->assertEquals(0, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
 437  
 438          delete_course($course3, false);
 439          delete_course($course4, false);
 440  
 441      }
 442  
 443      public function test_add_to_group() {
 444          global $CFG, $DB;
 445  
 446          require_once($CFG->dirroot.'/group/lib.php');
 447  
 448          $this->resetAfterTest(true);
 449  
 450          $metalplugin = enrol_get_plugin('meta');
 451  
 452          $user1 = $this->getDataGenerator()->create_user();
 453          $user4 = $this->getDataGenerator()->create_user();
 454  
 455          $course1 = $this->getDataGenerator()->create_course();
 456          $course2 = $this->getDataGenerator()->create_course();
 457          $course3 = $this->getDataGenerator()->create_course();
 458          $manualenrol1 = $DB->get_record('enrol', array('courseid' => $course1->id, 'enrol' => 'manual'), '*', MUST_EXIST);
 459          $manualenrol2 = $DB->get_record('enrol', array('courseid' => $course2->id, 'enrol' => 'manual'), '*', MUST_EXIST);
 460  
 461          $student = $DB->get_record('role', array('shortname' => 'student'));
 462          $teacher = $DB->get_record('role', array('shortname' => 'teacher'));
 463  
 464          $id = groups_create_group((object)array('name' => 'Group 1 in course 3', 'courseid' => $course3->id));
 465          $group31 = $DB->get_record('groups', array('id' => $id), '*', MUST_EXIST);
 466          $id = groups_create_group((object)array('name' => 'Group 2 in course 4', 'courseid' => $course3->id));
 467          $group32 = $DB->get_record('groups', array('id' => $id), '*', MUST_EXIST);
 468  
 469          $this->enable_plugin();
 470  
 471          $e1 = $metalplugin->add_instance($course3, array('customint1' => $course1->id, 'customint2' => $group31->id));
 472          $e2 = $metalplugin->add_instance($course3, array('customint1' => $course2->id, 'customint2' => $group32->id));
 473  
 474          $this->getDataGenerator()->enrol_user($user1->id, $course1->id, $student->id);
 475          $this->getDataGenerator()->enrol_user($user4->id, $course1->id, $teacher->id);
 476  
 477          $this->getDataGenerator()->enrol_user($user1->id, $course2->id, $student->id);
 478  
 479          // Now make sure users are in the correct groups.
 480          $this->assertTrue(groups_is_member($group31->id, $user1->id));
 481          $this->assertTrue($DB->record_exists('groups_members', array('groupid' => $group31->id, 'userid' => $user1->id,
 482              'component' => 'enrol_meta', 'itemid' => $e1)));
 483          $this->assertTrue(groups_is_member($group32->id, $user1->id));
 484          $this->assertTrue($DB->record_exists('groups_members', array('groupid' => $group32->id, 'userid' => $user1->id,
 485              'component' => 'enrol_meta', 'itemid' => $e2)));
 486  
 487          $this->assertTrue(groups_is_member($group31->id, $user4->id));
 488          $this->assertTrue($DB->record_exists('groups_members', array('groupid' => $group31->id, 'userid' => $user4->id,
 489              'component' => 'enrol_meta', 'itemid' => $e1)));
 490  
 491          // Make sure everything is the same after sync.
 492          enrol_meta_sync(null, false);
 493          $this->assertTrue(groups_is_member($group31->id, $user1->id));
 494          $this->assertTrue($DB->record_exists('groups_members', array('groupid' => $group31->id, 'userid' => $user1->id,
 495              'component' => 'enrol_meta', 'itemid' => $e1)));
 496          $this->assertTrue(groups_is_member($group32->id, $user1->id));
 497          $this->assertTrue($DB->record_exists('groups_members', array('groupid' => $group32->id, 'userid' => $user1->id,
 498              'component' => 'enrol_meta', 'itemid' => $e2)));
 499  
 500          $this->assertTrue(groups_is_member($group31->id, $user4->id));
 501          $this->assertTrue($DB->record_exists('groups_members', array('groupid' => $group31->id, 'userid' => $user4->id,
 502              'component' => 'enrol_meta', 'itemid' => $e1)));
 503  
 504          set_config('unenrolaction', ENROL_EXT_REMOVED_UNENROL, 'enrol_meta');
 505  
 506          // When user 1 is unenrolled from course1, he is removed from group31 but still present in group32.
 507          enrol_get_plugin('manual')->unenrol_user($manualenrol1, $user1->id);
 508          $this->assertFalse(groups_is_member($group31->id, $user1->id));
 509          $this->assertTrue(groups_is_member($group32->id, $user1->id));
 510          $this->assertTrue(is_enrolled(\context_course::instance($course3->id), $user1, '', true)); // He still has active enrolment.
 511          // And the same after sync.
 512          enrol_meta_sync(null, false);
 513          $this->assertFalse(groups_is_member($group31->id, $user1->id));
 514          $this->assertTrue(groups_is_member($group32->id, $user1->id));
 515          $this->assertTrue(is_enrolled(\context_course::instance($course3->id), $user1, '', true));
 516  
 517          // Unenroll user1 from course2 and make sure he is completely unenrolled from course3.
 518          enrol_get_plugin('manual')->unenrol_user($manualenrol2, $user1->id);
 519          $this->assertFalse(groups_is_member($group32->id, $user1->id));
 520          $this->assertFalse(is_enrolled(\context_course::instance($course3->id), $user1));
 521  
 522          set_config('unenrolaction', ENROL_EXT_REMOVED_SUSPENDNOROLES, 'enrol_meta');
 523  
 524          // When user is unenrolled in this case, he is still a member of a group (but enrolment is suspended).
 525          enrol_get_plugin('manual')->unenrol_user($manualenrol1, $user4->id);
 526          $this->assertTrue(groups_is_member($group31->id, $user4->id));
 527          $this->assertTrue(is_enrolled(\context_course::instance($course3->id), $user4));
 528          $this->assertFalse(is_enrolled(\context_course::instance($course3->id), $user4, '', true));
 529          enrol_meta_sync(null, false);
 530          $this->assertTrue(groups_is_member($group31->id, $user4->id));
 531          $this->assertTrue(is_enrolled(\context_course::instance($course3->id), $user4));
 532          $this->assertFalse(is_enrolled(\context_course::instance($course3->id), $user4, '', true));
 533      }
 534  
 535      /**
 536       * Enrol users from another course into a course where one of the members is already enrolled
 537       * and is a member of the same group.
 538       */
 539      public function test_add_to_group_with_member() {
 540          global $CFG, $DB;
 541  
 542          require_once($CFG->dirroot.'/group/lib.php');
 543  
 544          $this->resetAfterTest(true);
 545  
 546          $metalplugin = enrol_get_plugin('meta');
 547  
 548          $user1 = $this->getDataGenerator()->create_user();
 549          $user2 = $this->getDataGenerator()->create_user();
 550  
 551          $course1 = $this->getDataGenerator()->create_course();
 552          $course2 = $this->getDataGenerator()->create_course();
 553          $manualenrol1 = $DB->get_record('enrol', array('courseid' => $course1->id, 'enrol' => 'manual'), '*', MUST_EXIST);
 554          $manualenrol2 = $DB->get_record('enrol', array('courseid' => $course2->id, 'enrol' => 'manual'), '*', MUST_EXIST);
 555  
 556          $student = $DB->get_record('role', array('shortname' => 'student'));
 557  
 558          $groupid = groups_create_group((object)array('name' => 'Grp', 'courseid' => $course2->id));
 559  
 560          $this->enable_plugin();
 561          set_config('unenrolaction', ENROL_EXT_REMOVED_UNENROL, 'enrol_meta');
 562  
 563          // Manually enrol user1 to course2 and add him to group.
 564          // Manually enrol user2 to course2 but do not add him to the group.
 565          enrol_get_plugin('manual')->enrol_user($manualenrol2, $user1->id, $student->id);
 566          groups_add_member($groupid, $user1->id);
 567          enrol_get_plugin('manual')->enrol_user($manualenrol2, $user2->id, $student->id);
 568          $this->assertTrue(groups_is_member($groupid, $user1->id));
 569          $this->assertFalse(groups_is_member($groupid, $user2->id));
 570  
 571          // Add instance of meta enrolment in course2 linking to course1 and enrol both users in course1.
 572          $metalplugin->add_instance($course2, array('customint1' => $course1->id, 'customint2' => $groupid));
 573  
 574          enrol_get_plugin('manual')->enrol_user($manualenrol1, $user1->id, $student->id);
 575          enrol_get_plugin('manual')->enrol_user($manualenrol1, $user2->id, $student->id);
 576  
 577          // Both users now should be members of the group.
 578          $this->assertTrue(groups_is_member($groupid, $user1->id));
 579          $this->assertTrue(groups_is_member($groupid, $user2->id));
 580  
 581          // Ununerol both users from course1.
 582          enrol_get_plugin('manual')->unenrol_user($manualenrol1, $user1->id);
 583          enrol_get_plugin('manual')->unenrol_user($manualenrol1, $user2->id);
 584  
 585          // User1 should still be member of the group because he was added there manually. User2 should no longer be there.
 586          $this->assertTrue(groups_is_member($groupid, $user1->id));
 587          $this->assertFalse(groups_is_member($groupid, $user2->id));
 588  
 589          // Assert that everything is the same after sync.
 590          enrol_meta_sync();
 591  
 592          $this->assertTrue(groups_is_member($groupid, $user1->id));
 593          $this->assertFalse(groups_is_member($groupid, $user2->id));
 594  
 595      }
 596  
 597      /**
 598       * Test user_enrolment_created event.
 599       */
 600      public function test_user_enrolment_created_event() {
 601          global $DB;
 602  
 603          $this->resetAfterTest();
 604  
 605          $metaplugin = enrol_get_plugin('meta');
 606          $user1 = $this->getDataGenerator()->create_user();
 607          $course1 = $this->getDataGenerator()->create_course();
 608          $course2 = $this->getDataGenerator()->create_course();
 609          $student = $DB->get_record('role', array('shortname' => 'student'));
 610  
 611          $e1 = $metaplugin->add_instance($course2, array('customint1' => $course1->id));
 612          $enrol1 = $DB->get_record('enrol', array('id' => $e1));
 613  
 614          // Enrol user and capture event.
 615          $sink = $this->redirectEvents();
 616  
 617          $metaplugin->enrol_user($enrol1, $user1->id, $student->id);
 618          $events = $sink->get_events();
 619          $sink->close();
 620          $event = array_shift($events);
 621  
 622          // Test Event.
 623          $dbuserenrolled = $DB->get_record('user_enrolments', array('userid' => $user1->id));
 624          $this->assertInstanceOf('\core\event\user_enrolment_created', $event);
 625          $this->assertEquals($dbuserenrolled->id, $event->objectid);
 626          $this->assertEquals('user_enrolled', $event->get_legacy_eventname());
 627          $expectedlegacyeventdata = $dbuserenrolled;
 628          $expectedlegacyeventdata->enrol = 'meta';
 629          $expectedlegacyeventdata->courseid = $course2->id;
 630          $this->assertEventLegacyData($expectedlegacyeventdata, $event);
 631          $this->assertEventContextNotUsed($event);
 632      }
 633  
 634      /**
 635       * Test user_enrolment_deleted event.
 636       */
 637      public function test_user_enrolment_deleted_event() {
 638          global $DB;
 639  
 640          $this->resetAfterTest(true);
 641  
 642          $metalplugin = enrol_get_plugin('meta');
 643          $user1 = $this->getDataGenerator()->create_user();
 644          $course1 = $this->getDataGenerator()->create_course();
 645          $course2 = $this->getDataGenerator()->create_course();
 646          $student = $DB->get_record('role', array('shortname'=>'student'));
 647  
 648          $e1 = $metalplugin->add_instance($course2, array('customint1' => $course1->id));
 649          $enrol1 = $DB->get_record('enrol', array('id' => $e1));
 650  
 651          // Enrol user.
 652          $metalplugin->enrol_user($enrol1, $user1->id, $student->id);
 653          $this->assertEquals(1, $DB->count_records('user_enrolments'));
 654  
 655          // Unenrol user and capture event.
 656          $sink = $this->redirectEvents();
 657          $metalplugin->unenrol_user($enrol1, $user1->id);
 658          $events = $sink->get_events();
 659          $sink->close();
 660          $event = array_pop($events);
 661  
 662          $this->assertEquals(0, $DB->count_records('user_enrolments'));
 663          $this->assertInstanceOf('\core\event\user_enrolment_deleted', $event);
 664          $this->assertEquals('user_unenrolled', $event->get_legacy_eventname());
 665          $this->assertEventContextNotUsed($event);
 666      }
 667  
 668      /**
 669       * Test user_enrolment_updated event.
 670       */
 671      public function test_user_enrolment_updated_event() {
 672          global $DB;
 673  
 674          $this->resetAfterTest(true);
 675  
 676          $metalplugin = enrol_get_plugin('meta');
 677          $user1 = $this->getDataGenerator()->create_user();
 678          $course1 = $this->getDataGenerator()->create_course();
 679          $course2 = $this->getDataGenerator()->create_course();
 680          $student = $DB->get_record('role', array('shortname'=>'student'));
 681  
 682          $e1 = $metalplugin->add_instance($course2, array('customint1' => $course1->id));
 683          $enrol1 = $DB->get_record('enrol', array('id' => $e1));
 684  
 685          // Enrol user.
 686          $metalplugin->enrol_user($enrol1, $user1->id, $student->id);
 687          $this->assertEquals(1, $DB->count_records('user_enrolments'));
 688  
 689          // Updated enrolment for user and capture event.
 690          $sink = $this->redirectEvents();
 691          $metalplugin->update_user_enrol($enrol1, $user1->id, ENROL_USER_SUSPENDED, null, time());
 692          $events = $sink->get_events();
 693          $sink->close();
 694          $event = array_shift($events);
 695  
 696          // Test Event.
 697          $dbuserenrolled = $DB->get_record('user_enrolments', array('userid' => $user1->id));
 698          $this->assertInstanceOf('\core\event\user_enrolment_updated', $event);
 699          $this->assertEquals($dbuserenrolled->id, $event->objectid);
 700          $this->assertEquals('user_enrol_modified', $event->get_legacy_eventname());
 701          $expectedlegacyeventdata = $dbuserenrolled;
 702          $expectedlegacyeventdata->enrol = 'meta';
 703          $expectedlegacyeventdata->courseid = $course2->id;
 704          $url = new \moodle_url('/enrol/editenrolment.php', array('ue' => $event->objectid));
 705          $this->assertEquals($url, $event->get_url());
 706          $this->assertEventLegacyData($expectedlegacyeventdata, $event);
 707          $this->assertEventContextNotUsed($event);
 708      }
 709  
 710      /**
 711       * Test that a new group with the name of the course is created.
 712       */
 713      public function test_enrol_meta_create_new_group() {
 714          global $DB;
 715          $this->resetAfterTest();
 716          // Create two courses.
 717          $course = $this->getDataGenerator()->create_course(array('fullname' => 'Mathematics'));
 718          $course2 = $this->getDataGenerator()->create_course(array('fullname' => 'Physics'));
 719          $metacourse = $this->getDataGenerator()->create_course(array('fullname' => 'All sciences'));
 720          // Run the function.
 721          $groupid = enrol_meta_create_new_group($metacourse->id, $course->id);
 722          // Check the results.
 723          $group = $DB->get_record('groups', array('id' => $groupid));
 724          // The group name should match the course name.
 725          $this->assertEquals('Mathematics course', $group->name);
 726          // Group course id should match the course id.
 727          $this->assertEquals($metacourse->id, $group->courseid);
 728  
 729          // Create a group that will have the same name as the course.
 730          $groupdata = new \stdClass();
 731          $groupdata->courseid = $metacourse->id;
 732          $groupdata->name = 'Physics course';
 733          groups_create_group($groupdata);
 734          // Create a group for the course 2 in metacourse.
 735          $groupid = enrol_meta_create_new_group($metacourse->id, $course2->id);
 736          $groupinfo = $DB->get_record('groups', array('id' => $groupid));
 737          // Check that the group name has been changed.
 738          $this->assertEquals('Physics course (2)', $groupinfo->name);
 739  
 740          // Create a group for the course 2 in metacourse.
 741          $groupid = enrol_meta_create_new_group($metacourse->id, $course2->id);
 742          $groupinfo = $DB->get_record('groups', array('id' => $groupid));
 743          // Check that the group name has been changed.
 744          $this->assertEquals('Physics course (3)', $groupinfo->name);
 745      }
 746  
 747      /**
 748       * Test that enrolment timestart-timeend is respected in meta course.
 749       */
 750      public function test_timeend() {
 751          global $CFG, $DB;
 752  
 753          $this->resetAfterTest(true);
 754  
 755          $timeinfuture = time() + DAYSECS;
 756          $timeinpast = time() - DAYSECS;
 757  
 758          $metalplugin = enrol_get_plugin('meta');
 759          $manplugin = enrol_get_plugin('manual');
 760  
 761          $user1 = $this->getDataGenerator()->create_user();
 762          $user2 = $this->getDataGenerator()->create_user();
 763          $user3 = $this->getDataGenerator()->create_user();
 764          $user4 = $this->getDataGenerator()->create_user();
 765          $user5 = $this->getDataGenerator()->create_user();
 766  
 767          $course1 = $this->getDataGenerator()->create_course();
 768          $course2 = $this->getDataGenerator()->create_course();
 769          $course3 = $this->getDataGenerator()->create_course();
 770          $manual1 = $DB->get_record('enrol', array('courseid' => $course1->id, 'enrol' => 'manual'), '*', MUST_EXIST);
 771  
 772          $student = $DB->get_record('role', array('shortname' => 'student'));
 773  
 774          $this->enable_plugin();
 775  
 776          // Create instance of enrol_meta in course2 when there are no enrolments present.
 777          $meta2id = $metalplugin->add_instance($course2, array('customint1' => $course1->id));
 778  
 779          $expectedenrolments = array(
 780              $user1->id => array(0, 0, ENROL_USER_ACTIVE),
 781              $user2->id => array($timeinpast, 0, ENROL_USER_ACTIVE),
 782              $user3->id => array(0, $timeinfuture, ENROL_USER_ACTIVE),
 783              $user4->id => array($timeinpast, $timeinfuture, ENROL_USER_ACTIVE),
 784              $user5->id => array(0, 0, ENROL_USER_SUSPENDED),
 785          );
 786          foreach ($expectedenrolments as $userid => $data) {
 787              $expectedenrolments[$userid] = (object)(array('userid' => $userid) +
 788                      array_combine(array('timestart', 'timeend', 'status'), $data));
 789          }
 790  
 791          // Enrol users manually in course 1.
 792          foreach ($expectedenrolments as $e) {
 793              $manplugin->enrol_user($manual1, $e->userid, $student->id, $e->timestart, $e->timeend, $e->status);
 794          }
 795  
 796          $enrolments = $DB->get_records('user_enrolments', array('enrolid' => $manual1->id), 'userid', 'userid, timestart, timeend, status');
 797          $this->assertEquals($expectedenrolments, $enrolments);
 798  
 799          // Make sure that the same enrolments are now present in course2 under meta enrolment.
 800          $enrolments = $DB->get_records('user_enrolments', array('enrolid' => $meta2id), '', 'userid, timestart, timeend, status');
 801          $this->assertEquals($expectedenrolments, $enrolments);
 802  
 803          // Create instance of enrol_meta in course3 and run sync.
 804          $meta3id = $metalplugin->add_instance($course3, array('customint1' => $course1->id));
 805          enrol_meta_sync($course3->id);
 806  
 807          // Make sure that the same enrolments are now present in course3 under meta enrolment.
 808          $enrolments = $DB->get_records('user_enrolments', array('enrolid' => $meta3id), '', 'userid, timestart, timeend, status');
 809          $this->assertEquals($expectedenrolments, $enrolments);
 810  
 811          // Update some of the manual enrolments.
 812          $expectedenrolments[$user2->id]->timestart = $timeinpast - 60;
 813          $expectedenrolments[$user3->id]->timeend = $timeinfuture + 60;
 814          $expectedenrolments[$user4->id]->status = ENROL_USER_SUSPENDED;
 815          $expectedenrolments[$user5->id]->status = ENROL_USER_ACTIVE;
 816          foreach ($expectedenrolments as $e) {
 817              $manplugin->update_user_enrol($manual1, $e->userid, $e->status, $e->timestart, $e->timeend);
 818          }
 819  
 820          // Make sure meta courses are also updated.
 821          $enrolments = $DB->get_records('user_enrolments', array('enrolid' => $meta2id), '', 'userid, timestart, timeend, status');
 822          $this->assertEquals($expectedenrolments, $enrolments);
 823          $enrolments = $DB->get_records('user_enrolments', array('enrolid' => $meta3id), '', 'userid, timestart, timeend, status');
 824          $this->assertEquals($expectedenrolments, $enrolments);
 825  
 826          // Test meta sync. Imagine events are not working.
 827          $sink = $this->redirectEvents();
 828          $expectedenrolments[$user2->id]->timestart = $timeinpast;
 829          $expectedenrolments[$user3->id]->timeend = $timeinfuture;
 830          $expectedenrolments[$user4->id]->status = ENROL_USER_ACTIVE;
 831          $expectedenrolments[$user5->id]->status = ENROL_USER_SUSPENDED;
 832          foreach ($expectedenrolments as $e) {
 833              $manplugin->update_user_enrol($manual1, $e->userid, $e->status, $e->timestart, $e->timeend);
 834          }
 835  
 836          // Make sure meta courses are updated only for the course that was synced.
 837          enrol_meta_sync($course3->id);
 838  
 839          $enrolments = $DB->get_records('user_enrolments', array('enrolid' => $meta2id), '', 'userid, timestart, timeend, status');
 840          $this->assertNotEquals($expectedenrolments, $enrolments);
 841  
 842          $enrolments = $DB->get_records('user_enrolments', array('enrolid' => $meta3id), '', 'userid, timestart, timeend, status');
 843          $this->assertEquals($expectedenrolments, $enrolments);
 844  
 845          $sink->close();
 846  
 847          // Disable manual enrolment in course1 and make sure all user enrolments in course2 are suspended.
 848          $manplugin->update_status($manual1, ENROL_INSTANCE_DISABLED);
 849          $allsuspendedenrolemnts = array_combine(array_keys($expectedenrolments), array_fill(0, 5, ENROL_USER_SUSPENDED));
 850          $enrolmentstatuses = $DB->get_records_menu('user_enrolments', array('enrolid' => $meta2id), '', 'userid, status');
 851          $this->assertEquals($allsuspendedenrolemnts, $enrolmentstatuses);
 852  
 853          $manplugin->update_status($manual1, ENROL_INSTANCE_ENABLED);
 854          $enrolments = $DB->get_records('user_enrolments', array('enrolid' => $meta2id), '', 'userid, timestart, timeend, status');
 855          $this->assertEquals($expectedenrolments, $enrolments);
 856  
 857          // Disable events and repeat the same for course3 (testing sync):
 858          $sink = $this->redirectEvents();
 859          $manplugin->update_status($manual1, ENROL_INSTANCE_DISABLED);
 860          enrol_meta_sync($course3->id);
 861          $enrolmentstatuses = $DB->get_records_menu('user_enrolments', array('enrolid' => $meta3id), '', 'userid, status');
 862          $this->assertEquals($allsuspendedenrolemnts, $enrolmentstatuses);
 863  
 864          $manplugin->update_status($manual1, ENROL_INSTANCE_ENABLED);
 865          enrol_meta_sync($course3->id);
 866          $enrolments = $DB->get_records('user_enrolments', array('enrolid' => $meta3id), '', 'userid, timestart, timeend, status');
 867          $this->assertEquals($expectedenrolments, $enrolments);
 868          $sink->close();
 869      }
 870  
 871      /**
 872       * Test for getting user enrolment actions.
 873       */
 874      public function test_get_user_enrolment_actions() {
 875          global $CFG, $PAGE;
 876          $this->resetAfterTest();
 877  
 878          // Set page URL to prevent debugging messages.
 879          $PAGE->set_url('/enrol/editinstance.php');
 880  
 881          $pluginname = 'meta';
 882  
 883          // Only enable the meta enrol plugin.
 884          $CFG->enrol_plugins_enabled = $pluginname;
 885  
 886          $generator = $this->getDataGenerator();
 887  
 888          // Get the enrol plugin.
 889          $plugin = enrol_get_plugin($pluginname);
 890  
 891          // Create a course.
 892          $course = $generator->create_course();
 893          // Enable this enrol plugin for the course.
 894          $plugin->add_instance($course);
 895  
 896          // Create a student.
 897          $student = $generator->create_user();
 898          // Enrol the student to the course.
 899          $generator->enrol_user($student->id, $course->id, 'student', $pluginname);
 900  
 901          // Teachers don't have enrol/meta:unenrol capability by default. Login as admin for simplicity.
 902          $this->setAdminUser();
 903          require_once($CFG->dirroot . '/enrol/locallib.php');
 904          $manager = new \course_enrolment_manager($PAGE, $course);
 905  
 906          $userenrolments = $manager->get_user_enrolments($student->id);
 907          $this->assertCount(1, $userenrolments);
 908  
 909          $ue = reset($userenrolments);
 910          $actions = $plugin->get_user_enrolment_actions($manager, $ue);
 911          // Meta-link enrolment has no enrol actions for active students.
 912          $this->assertCount(0, $actions);
 913  
 914          // Enrol actions for a suspended student.
 915          // Suspend the student.
 916          $ue->status = ENROL_USER_SUSPENDED;
 917  
 918          $actions = $plugin->get_user_enrolment_actions($manager, $ue);
 919          // Meta-link enrolment has enrol actions for suspended students -- unenrol.
 920          $this->assertCount(1, $actions);
 921      }
 922  
 923      /**
 924       * Test how data for instance editing is validated.
 925       */
 926      public function test_edit_instance_validation() {
 927          global $DB;
 928  
 929          $this->resetAfterTest();
 930  
 931          $metaplugin = enrol_get_plugin('meta');
 932  
 933          // A course with meta enrolment.
 934          $course = $this->getDataGenerator()->create_course();
 935          $coursecontext = \context_course::instance($course->id);
 936  
 937          // Create a meta enrolment instance.
 938          $instance = (object)$metaplugin->get_instance_defaults();
 939          $instance->id       = null;
 940          $instance->courseid = $course->id;
 941          $instance->status   = ENROL_INSTANCE_ENABLED;
 942          // Emulate the form data.
 943          $data = [
 944              'customint1' => 0,
 945              'customint2' => 0
 946          ];
 947          // Test when no valid 'customint1' field (meta courses links) is provided.
 948          $errors = $metaplugin->edit_instance_validation($data, [], $instance, $coursecontext);
 949          // We're going to check the string contents of the errors returned as this is the only way
 950          // to differentiate the errors produced by the 'edit_instance_validation()' method somehow.
 951          // The method always returns what the edit instance form expects and this is an array of form fields
 952          // with the corresponding errors messages.
 953          $this->assertEquals('Required', $errors['customint1']);
 954  
 955          // Test when 'customint1' contains an unknown course.
 956          // Fetch the max course id from the courses table and increment it to get
 957          // the course id which surely doesn't exist.
 958          $maxid = $DB->get_field_sql('SELECT MAX(id) FROM {course}');
 959          // Use the same instance as before but set another data.
 960          $data = [
 961              'customint1' => [$maxid + 1],
 962              'customint2' => 0
 963          ];
 964          $errors = $metaplugin->edit_instance_validation($data, [], $instance, $coursecontext);
 965          $this->assertEquals('You are trying to use an invalid course ID', $errors['customint1']);
 966  
 967          // Test when 'customint1' field already contains courses meta linked with the current one.
 968          $metacourse1 = $this->getDataGenerator()->create_course();
 969          $metaplugin->add_instance($course, array('customint1' => $metacourse1->id));
 970          // Use the same instance as before but set another data.
 971          $data = [
 972              'customint1' => [$metacourse1->id],
 973              'customint2' => 0
 974          ];
 975          $errors = $metaplugin->edit_instance_validation($data, [], $instance, $coursecontext);
 976          $this->assertEquals('You are trying to use an invalid course ID', $errors['customint1']);
 977  
 978          // Test when a course is set as a not visible and a user doesn't have the capability to use it here.
 979          $metacourse2record = new \stdClass();
 980          $metacourse2record->visible = 0;
 981          $metacourse2 = $this->getDataGenerator()->create_course($metacourse2record);
 982          $metacourse2context = \context_course::instance($metacourse2->id);
 983  
 984          $user = $this->getDataGenerator()->create_user();
 985          $teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
 986          role_assign($teacherrole->id, $user->id, $metacourse2context->id);
 987          unassign_capability('moodle/course:viewhiddencourses', $teacherrole->id);
 988          $this->setUser($user);
 989  
 990          // Use the same instance as before but set another data.
 991          $data = [
 992              'customint1' => [$metacourse2->id],
 993              'customint2' => 0
 994          ];
 995          $errors = $metaplugin->edit_instance_validation($data, [], $instance, $coursecontext);
 996          $this->assertEquals('Sorry, but you do not currently have permissions to do that (moodle/course:viewhiddencourses).',
 997              $errors['customint1']);
 998  
 999          // Revert some changes from the last assertion to reuse the course.
1000          $metacourse2->visible = 1;
1001          $DB->update_record('course', $metacourse2);
1002          assign_capability('moodle/course:viewhiddencourses', CAP_ALLOW,
1003              $teacherrole->id, \context_course::instance($metacourse2->id));
1004  
1005          // Test with no 'enrol/meta:selectaslinked' capability.
1006          unassign_capability('enrol/meta:selectaslinked', $teacherrole->id);
1007          $errors = $metaplugin->edit_instance_validation($data, [], $instance, $coursecontext);
1008          $this->assertEquals('Sorry, but you do not currently have permissions to do that (enrol/meta:selectaslinked).',
1009              $errors['customint1']);
1010  
1011          // Back to admin user to regain the capabilities quickly.
1012          $this->setAdminUser();
1013  
1014          // Test when meta course id is the site id.
1015          $site = $DB->get_record('course', ['id' => SITEID]);
1016          // Use the same instance as before but set another data.
1017          $data = [
1018              'customint1' => [$site->id],
1019              'customint2' => 0
1020          ];
1021          $errors = $metaplugin->edit_instance_validation($data, [], $instance, $coursecontext);
1022          $this->assertEquals('You are trying to use an invalid course ID', $errors['customint1']);
1023  
1024          // Test when meta course id is id of the current course.
1025          // Use the same instance as before but set another data.
1026          $data = [
1027              'customint1' => [$course->id],
1028              'customint2' => 0
1029          ];
1030          $errors = $metaplugin->edit_instance_validation($data, [], $instance, $coursecontext);
1031          $this->assertEquals('You are trying to use an invalid course ID', $errors['customint1']);
1032  
1033          // Test with the 'customint2' field set (which is groups).
1034          // Prepare some groups data.
1035          $this->getDataGenerator()->create_group(array('courseid' => $course->id));
1036          $this->getDataGenerator()->create_group(array('courseid' => $course->id));
1037          $groups = [];
1038          foreach (groups_get_all_groups($course->id) as $group) {
1039              $groups[$group->id] = format_string($group->name, true, array('context' => $coursecontext));
1040          }
1041  
1042          // Use the same instance as before but set another data.
1043          // Use a non-existing group id.
1044          if (!$maxid = $DB->get_field_sql('SELECT MAX(id) FROM {groups}')) {
1045              $maxid = 0;
1046          }
1047          $data = [
1048              'customint1' => [$metacourse2->id],
1049              'customint2' => [$maxid + 1]
1050          ];
1051          $errors = $metaplugin->edit_instance_validation($data, [], $instance, $coursecontext);
1052          $this->assertArrayHasKey('customint2', $errors);
1053  
1054          // Test with valid data.
1055          reset($groups);
1056          $validgroup = key($groups);
1057          $data = [
1058              'customint1' => [$metacourse2->id],
1059              'customint2' => $validgroup
1060          ];
1061          $errors = $metaplugin->edit_instance_validation($data, [], $instance, $coursecontext);
1062          $this->assertArrayNotHasKey('customint1', $errors);
1063          $this->assertArrayNotHasKey('customint2', $errors);
1064      }
1065  }