Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.2.x will end 22 April 2024 (12 months).
  • Bug fixes for security issues in 4.2.x will end 7 October 2024 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.1.x is supported too.

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

   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->assertEventContextNotUsed($event);
 664      }
 665  
 666      /**
 667       * Test user_enrolment_deleted event.
 668       */
 669      public function test_user_enrolment_deleted_event() {
 670          global $DB;
 671  
 672          $this->resetAfterTest(true);
 673  
 674          $metalplugin = enrol_get_plugin('meta');
 675          $user1 = $this->getDataGenerator()->create_user();
 676          $course1 = $this->getDataGenerator()->create_course();
 677          $course2 = $this->getDataGenerator()->create_course();
 678          $student = $DB->get_record('role', array('shortname'=>'student'));
 679  
 680          $e1 = $metalplugin->add_instance($course2, array('customint1' => $course1->id));
 681          $enrol1 = $DB->get_record('enrol', array('id' => $e1));
 682  
 683          // Enrol user.
 684          $metalplugin->enrol_user($enrol1, $user1->id, $student->id);
 685          $this->assertEquals(1, $DB->count_records('user_enrolments'));
 686  
 687          // Unenrol user and capture event.
 688          $sink = $this->redirectEvents();
 689          $metalplugin->unenrol_user($enrol1, $user1->id);
 690          $events = $sink->get_events();
 691          $sink->close();
 692          $event = array_pop($events);
 693  
 694          $this->assertEquals(0, $DB->count_records('user_enrolments'));
 695          $this->assertInstanceOf('\core\event\user_enrolment_deleted', $event);
 696          $this->assertEventContextNotUsed($event);
 697      }
 698  
 699      /**
 700       * Test user_enrolment_updated event.
 701       */
 702      public function test_user_enrolment_updated_event() {
 703          global $DB;
 704  
 705          $this->resetAfterTest(true);
 706  
 707          $metalplugin = enrol_get_plugin('meta');
 708          $user1 = $this->getDataGenerator()->create_user();
 709          $course1 = $this->getDataGenerator()->create_course();
 710          $course2 = $this->getDataGenerator()->create_course();
 711          $student = $DB->get_record('role', array('shortname'=>'student'));
 712  
 713          $e1 = $metalplugin->add_instance($course2, array('customint1' => $course1->id));
 714          $enrol1 = $DB->get_record('enrol', array('id' => $e1));
 715  
 716          // Enrol user.
 717          $metalplugin->enrol_user($enrol1, $user1->id, $student->id);
 718          $this->assertEquals(1, $DB->count_records('user_enrolments'));
 719  
 720          // Updated enrolment for user and capture event.
 721          $sink = $this->redirectEvents();
 722          $metalplugin->update_user_enrol($enrol1, $user1->id, ENROL_USER_SUSPENDED, null, time());
 723          $events = $sink->get_events();
 724          $sink->close();
 725          $event = array_shift($events);
 726  
 727          // Test Event.
 728          $dbuserenrolled = $DB->get_record('user_enrolments', array('userid' => $user1->id));
 729          $this->assertInstanceOf('\core\event\user_enrolment_updated', $event);
 730          $this->assertEquals($dbuserenrolled->id, $event->objectid);
 731          $this->assertEventContextNotUsed($event);
 732      }
 733  
 734      /**
 735       * Test that a new group with the name of the course is created.
 736       */
 737      public function test_enrol_meta_create_new_group() {
 738          global $DB;
 739          $this->resetAfterTest();
 740          // Create two courses.
 741          $course = $this->getDataGenerator()->create_course(array('fullname' => 'Mathematics'));
 742          $course2 = $this->getDataGenerator()->create_course(array('fullname' => 'Physics'));
 743          $metacourse = $this->getDataGenerator()->create_course(array('fullname' => 'All sciences'));
 744          // Run the function.
 745          $groupid = enrol_meta_create_new_group($metacourse->id, $course->id);
 746          // Check the results.
 747          $group = $DB->get_record('groups', array('id' => $groupid));
 748          // The group name should match the course name.
 749          $this->assertEquals('Mathematics course', $group->name);
 750          // Group course id should match the course id.
 751          $this->assertEquals($metacourse->id, $group->courseid);
 752  
 753          // Create a group that will have the same name as the course.
 754          $groupdata = new \stdClass();
 755          $groupdata->courseid = $metacourse->id;
 756          $groupdata->name = 'Physics course';
 757          groups_create_group($groupdata);
 758          // Create a group for the course 2 in metacourse.
 759          $groupid = enrol_meta_create_new_group($metacourse->id, $course2->id);
 760          $groupinfo = $DB->get_record('groups', array('id' => $groupid));
 761          // Check that the group name has been changed.
 762          $this->assertEquals('Physics course (2)', $groupinfo->name);
 763  
 764          // Create a group for the course 2 in metacourse.
 765          $groupid = enrol_meta_create_new_group($metacourse->id, $course2->id);
 766          $groupinfo = $DB->get_record('groups', array('id' => $groupid));
 767          // Check that the group name has been changed.
 768          $this->assertEquals('Physics course (3)', $groupinfo->name);
 769      }
 770  
 771      /**
 772       * Test that enrolment timestart-timeend is respected in meta course.
 773       */
 774      public function test_timeend() {
 775          global $CFG, $DB;
 776  
 777          $this->resetAfterTest(true);
 778  
 779          $timeinfuture = time() + DAYSECS;
 780          $timeinpast = time() - DAYSECS;
 781  
 782          $metalplugin = enrol_get_plugin('meta');
 783          $manplugin = enrol_get_plugin('manual');
 784  
 785          $user1 = $this->getDataGenerator()->create_user();
 786          $user2 = $this->getDataGenerator()->create_user();
 787          $user3 = $this->getDataGenerator()->create_user();
 788          $user4 = $this->getDataGenerator()->create_user();
 789          $user5 = $this->getDataGenerator()->create_user();
 790  
 791          $course1 = $this->getDataGenerator()->create_course();
 792          $course2 = $this->getDataGenerator()->create_course();
 793          $course3 = $this->getDataGenerator()->create_course();
 794          $manual1 = $DB->get_record('enrol', array('courseid' => $course1->id, 'enrol' => 'manual'), '*', MUST_EXIST);
 795  
 796          $student = $DB->get_record('role', array('shortname' => 'student'));
 797  
 798          $this->enable_plugin();
 799  
 800          // Create instance of enrol_meta in course2 when there are no enrolments present.
 801          $meta2id = $metalplugin->add_instance($course2, array('customint1' => $course1->id));
 802  
 803          $expectedenrolments = array(
 804              $user1->id => array(0, 0, ENROL_USER_ACTIVE),
 805              $user2->id => array($timeinpast, 0, ENROL_USER_ACTIVE),
 806              $user3->id => array(0, $timeinfuture, ENROL_USER_ACTIVE),
 807              $user4->id => array($timeinpast, $timeinfuture, ENROL_USER_ACTIVE),
 808              $user5->id => array(0, 0, ENROL_USER_SUSPENDED),
 809          );
 810          foreach ($expectedenrolments as $userid => $data) {
 811              $expectedenrolments[$userid] = (object)(array('userid' => $userid) +
 812                      array_combine(array('timestart', 'timeend', 'status'), $data));
 813          }
 814  
 815          // Enrol users manually in course 1.
 816          foreach ($expectedenrolments as $e) {
 817              $manplugin->enrol_user($manual1, $e->userid, $student->id, $e->timestart, $e->timeend, $e->status);
 818          }
 819  
 820          $enrolments = $DB->get_records('user_enrolments', array('enrolid' => $manual1->id), 'userid', 'userid, timestart, timeend, status');
 821          $this->assertEquals($expectedenrolments, $enrolments);
 822  
 823          // Make sure that the same enrolments are now present in course2 under meta enrolment.
 824          $enrolments = $DB->get_records('user_enrolments', array('enrolid' => $meta2id), '', 'userid, timestart, timeend, status');
 825          $this->assertEquals($expectedenrolments, $enrolments);
 826  
 827          // Create instance of enrol_meta in course3 and run sync.
 828          $meta3id = $metalplugin->add_instance($course3, array('customint1' => $course1->id));
 829          enrol_meta_sync($course3->id);
 830  
 831          // Make sure that the same enrolments are now present in course3 under meta enrolment.
 832          $enrolments = $DB->get_records('user_enrolments', array('enrolid' => $meta3id), '', 'userid, timestart, timeend, status');
 833          $this->assertEquals($expectedenrolments, $enrolments);
 834  
 835          // Update some of the manual enrolments.
 836          $expectedenrolments[$user2->id]->timestart = $timeinpast - 60;
 837          $expectedenrolments[$user3->id]->timeend = $timeinfuture + 60;
 838          $expectedenrolments[$user4->id]->status = ENROL_USER_SUSPENDED;
 839          $expectedenrolments[$user5->id]->status = ENROL_USER_ACTIVE;
 840          foreach ($expectedenrolments as $e) {
 841              $manplugin->update_user_enrol($manual1, $e->userid, $e->status, $e->timestart, $e->timeend);
 842          }
 843  
 844          // Make sure meta courses are also updated.
 845          $enrolments = $DB->get_records('user_enrolments', array('enrolid' => $meta2id), '', 'userid, timestart, timeend, status');
 846          $this->assertEquals($expectedenrolments, $enrolments);
 847          $enrolments = $DB->get_records('user_enrolments', array('enrolid' => $meta3id), '', 'userid, timestart, timeend, status');
 848          $this->assertEquals($expectedenrolments, $enrolments);
 849  
 850          // Test meta sync. Imagine events are not working.
 851          $sink = $this->redirectEvents();
 852          $expectedenrolments[$user2->id]->timestart = $timeinpast;
 853          $expectedenrolments[$user3->id]->timeend = $timeinfuture;
 854          $expectedenrolments[$user4->id]->status = ENROL_USER_ACTIVE;
 855          $expectedenrolments[$user5->id]->status = ENROL_USER_SUSPENDED;
 856          foreach ($expectedenrolments as $e) {
 857              $manplugin->update_user_enrol($manual1, $e->userid, $e->status, $e->timestart, $e->timeend);
 858          }
 859  
 860          // Make sure meta courses are updated only for the course that was synced.
 861          enrol_meta_sync($course3->id);
 862  
 863          $enrolments = $DB->get_records('user_enrolments', array('enrolid' => $meta2id), '', 'userid, timestart, timeend, status');
 864          $this->assertNotEquals($expectedenrolments, $enrolments);
 865  
 866          $enrolments = $DB->get_records('user_enrolments', array('enrolid' => $meta3id), '', 'userid, timestart, timeend, status');
 867          $this->assertEquals($expectedenrolments, $enrolments);
 868  
 869          $sink->close();
 870  
 871          // Disable manual enrolment in course1 and make sure all user enrolments in course2 are suspended.
 872          $manplugin->update_status($manual1, ENROL_INSTANCE_DISABLED);
 873          $allsuspendedenrolemnts = array_combine(array_keys($expectedenrolments), array_fill(0, 5, ENROL_USER_SUSPENDED));
 874          $enrolmentstatuses = $DB->get_records_menu('user_enrolments', array('enrolid' => $meta2id), '', 'userid, status');
 875          $this->assertEquals($allsuspendedenrolemnts, $enrolmentstatuses);
 876  
 877          $manplugin->update_status($manual1, ENROL_INSTANCE_ENABLED);
 878          $enrolments = $DB->get_records('user_enrolments', array('enrolid' => $meta2id), '', 'userid, timestart, timeend, status');
 879          $this->assertEquals($expectedenrolments, $enrolments);
 880  
 881          // Disable events and repeat the same for course3 (testing sync):
 882          $sink = $this->redirectEvents();
 883          $manplugin->update_status($manual1, ENROL_INSTANCE_DISABLED);
 884          enrol_meta_sync($course3->id);
 885          $enrolmentstatuses = $DB->get_records_menu('user_enrolments', array('enrolid' => $meta3id), '', 'userid, status');
 886          $this->assertEquals($allsuspendedenrolemnts, $enrolmentstatuses);
 887  
 888          $manplugin->update_status($manual1, ENROL_INSTANCE_ENABLED);
 889          enrol_meta_sync($course3->id);
 890          $enrolments = $DB->get_records('user_enrolments', array('enrolid' => $meta3id), '', 'userid, timestart, timeend, status');
 891          $this->assertEquals($expectedenrolments, $enrolments);
 892          $sink->close();
 893      }
 894  
 895      /**
 896       * Test for getting user enrolment actions.
 897       */
 898      public function test_get_user_enrolment_actions() {
 899          global $CFG, $PAGE;
 900          $this->resetAfterTest();
 901  
 902          // Set page URL to prevent debugging messages.
 903          $PAGE->set_url('/enrol/editinstance.php');
 904  
 905          $pluginname = 'meta';
 906  
 907          // Only enable the meta enrol plugin.
 908          $CFG->enrol_plugins_enabled = $pluginname;
 909  
 910          $generator = $this->getDataGenerator();
 911  
 912          // Get the enrol plugin.
 913          $plugin = enrol_get_plugin($pluginname);
 914  
 915          // Create a course.
 916          $course = $generator->create_course();
 917          // Enable this enrol plugin for the course.
 918          $plugin->add_instance($course);
 919  
 920          // Create a student.
 921          $student = $generator->create_user();
 922          // Enrol the student to the course.
 923          $generator->enrol_user($student->id, $course->id, 'student', $pluginname);
 924  
 925          // Teachers don't have enrol/meta:unenrol capability by default. Login as admin for simplicity.
 926          $this->setAdminUser();
 927          require_once($CFG->dirroot . '/enrol/locallib.php');
 928          $manager = new \course_enrolment_manager($PAGE, $course);
 929  
 930          $userenrolments = $manager->get_user_enrolments($student->id);
 931          $this->assertCount(1, $userenrolments);
 932  
 933          $ue = reset($userenrolments);
 934          $actions = $plugin->get_user_enrolment_actions($manager, $ue);
 935          // Meta-link enrolment has no enrol actions for active students.
 936          $this->assertCount(0, $actions);
 937  
 938          // Enrol actions for a suspended student.
 939          // Suspend the student.
 940          $ue->status = ENROL_USER_SUSPENDED;
 941  
 942          $actions = $plugin->get_user_enrolment_actions($manager, $ue);
 943          // Meta-link enrolment has enrol actions for suspended students -- unenrol.
 944          $this->assertCount(1, $actions);
 945      }
 946  
 947      /**
 948       * Test how data for instance editing is validated.
 949       */
 950      public function test_edit_instance_validation() {
 951          global $DB;
 952  
 953          $this->resetAfterTest();
 954  
 955          $metaplugin = enrol_get_plugin('meta');
 956  
 957          // A course with meta enrolment.
 958          $course = $this->getDataGenerator()->create_course();
 959          $coursecontext = \context_course::instance($course->id);
 960  
 961          // Create a meta enrolment instance.
 962          $instance = (object)$metaplugin->get_instance_defaults();
 963          $instance->id       = null;
 964          $instance->courseid = $course->id;
 965          $instance->status   = ENROL_INSTANCE_ENABLED;
 966          // Emulate the form data.
 967          $data = [
 968              'customint1' => 0,
 969              'customint2' => 0
 970          ];
 971          // Test when no valid 'customint1' field (meta courses links) is provided.
 972          $errors = $metaplugin->edit_instance_validation($data, [], $instance, $coursecontext);
 973          // We're going to check the string contents of the errors returned as this is the only way
 974          // to differentiate the errors produced by the 'edit_instance_validation()' method somehow.
 975          // The method always returns what the edit instance form expects and this is an array of form fields
 976          // with the corresponding errors messages.
 977          $this->assertEquals('Required', $errors['customint1']);
 978  
 979          // Test when 'customint1' contains an unknown course.
 980          // Fetch the max course id from the courses table and increment it to get
 981          // the course id which surely doesn't exist.
 982          $maxid = $DB->get_field_sql('SELECT MAX(id) FROM {course}');
 983          // Use the same instance as before but set another data.
 984          $data = [
 985              'customint1' => [$maxid + 1],
 986              'customint2' => 0
 987          ];
 988          $errors = $metaplugin->edit_instance_validation($data, [], $instance, $coursecontext);
 989          $this->assertEquals('You are trying to use an invalid course ID', $errors['customint1']);
 990  
 991          // Test when 'customint1' field already contains courses meta linked with the current one.
 992          $metacourse1 = $this->getDataGenerator()->create_course();
 993          $metaplugin->add_instance($course, array('customint1' => $metacourse1->id));
 994          // Use the same instance as before but set another data.
 995          $data = [
 996              'customint1' => [$metacourse1->id],
 997              'customint2' => 0
 998          ];
 999          $errors = $metaplugin->edit_instance_validation($data, [], $instance, $coursecontext);
1000          $this->assertEquals('You are trying to use an invalid course ID', $errors['customint1']);
1001  
1002          // Test when a course is set as a not visible and a user doesn't have the capability to use it here.
1003          $metacourse2record = new \stdClass();
1004          $metacourse2record->visible = 0;
1005          $metacourse2 = $this->getDataGenerator()->create_course($metacourse2record);
1006          $metacourse2context = \context_course::instance($metacourse2->id);
1007  
1008          $user = $this->getDataGenerator()->create_user();
1009          $teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
1010          role_assign($teacherrole->id, $user->id, $metacourse2context->id);
1011          unassign_capability('moodle/course:viewhiddencourses', $teacherrole->id);
1012          $this->setUser($user);
1013  
1014          // Use the same instance as before but set another data.
1015          $data = [
1016              'customint1' => [$metacourse2->id],
1017              'customint2' => 0
1018          ];
1019          $errors = $metaplugin->edit_instance_validation($data, [], $instance, $coursecontext);
1020          $this->assertEquals('Sorry, but you do not currently have permissions to do that (moodle/course:viewhiddencourses).',
1021              $errors['customint1']);
1022  
1023          // Revert some changes from the last assertion to reuse the course.
1024          $metacourse2->visible = 1;
1025          $DB->update_record('course', $metacourse2);
1026          assign_capability('moodle/course:viewhiddencourses', CAP_ALLOW,
1027              $teacherrole->id, \context_course::instance($metacourse2->id));
1028  
1029          // Test with no 'enrol/meta:selectaslinked' capability.
1030          unassign_capability('enrol/meta:selectaslinked', $teacherrole->id);
1031          $errors = $metaplugin->edit_instance_validation($data, [], $instance, $coursecontext);
1032          $this->assertEquals('Sorry, but you do not currently have permissions to do that (enrol/meta:selectaslinked).',
1033              $errors['customint1']);
1034  
1035          // Back to admin user to regain the capabilities quickly.
1036          $this->setAdminUser();
1037  
1038          // Test when meta course id is the site id.
1039          $site = $DB->get_record('course', ['id' => SITEID]);
1040          // Use the same instance as before but set another data.
1041          $data = [
1042              'customint1' => [$site->id],
1043              'customint2' => 0
1044          ];
1045          $errors = $metaplugin->edit_instance_validation($data, [], $instance, $coursecontext);
1046          $this->assertEquals('You are trying to use an invalid course ID', $errors['customint1']);
1047  
1048          // Test when meta course id is id of the current course.
1049          // Use the same instance as before but set another data.
1050          $data = [
1051              'customint1' => [$course->id],
1052              'customint2' => 0
1053          ];
1054          $errors = $metaplugin->edit_instance_validation($data, [], $instance, $coursecontext);
1055          $this->assertEquals('You are trying to use an invalid course ID', $errors['customint1']);
1056  
1057          // Test with the 'customint2' field set (which is groups).
1058          // Prepare some groups data.
1059          $this->getDataGenerator()->create_group(array('courseid' => $course->id));
1060          $this->getDataGenerator()->create_group(array('courseid' => $course->id));
1061          $groups = [];
1062          foreach (groups_get_all_groups($course->id) as $group) {
1063              $groups[$group->id] = format_string($group->name, true, array('context' => $coursecontext));
1064          }
1065  
1066          // Use the same instance as before but set another data.
1067          // Use a non-existing group id.
1068          if (!$maxid = $DB->get_field_sql('SELECT MAX(id) FROM {groups}')) {
1069              $maxid = 0;
1070          }
1071          $data = [
1072              'customint1' => [$metacourse2->id],
1073              'customint2' => [$maxid + 1]
1074          ];
1075          $errors = $metaplugin->edit_instance_validation($data, [], $instance, $coursecontext);
1076          $this->assertArrayHasKey('customint2', $errors);
1077  
1078          // Test with valid data.
1079          reset($groups);
1080          $validgroup = key($groups);
1081          $data = [
1082              'customint1' => [$metacourse2->id],
1083              'customint2' => $validgroup
1084          ];
1085          $errors = $metaplugin->edit_instance_validation($data, [], $instance, $coursecontext);
1086          $this->assertArrayNotHasKey('customint1', $errors);
1087          $this->assertArrayNotHasKey('customint2', $errors);
1088      }
1089  }