Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

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