%PDF- %PDF-
Direktori : /home/vacivi36/ava/enrol/imsenterprise/tests/ |
Current File : /home/vacivi36/ava/enrol/imsenterprise/tests/imsenterprise_unenrol_test.php |
<?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. namespace enrol_imsenterprise; use core_course_category; use enrol_imsenterprise_plugin; use stdClass; defined('MOODLE_INTERNAL') || die(); global $CFG; require_once($CFG->dirroot . '/enrol/imsenterprise/locallib.php'); require_once($CFG->dirroot . '/enrol/imsenterprise/lib.php'); /** * IMS Enterprise test case * * @package enrol_imsenterprise * @category test * @copyright 2019 Segun Babalola * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * * @covers \enrol_imsenterprise_plugin */ class imsenterprise_unenrol_test extends \advanced_testcase { /** * @var $imsplugin enrol_imsenterprise_plugin IMS plugin instance. */ public $imsplugin; /** * Setup required for all tests. */ protected function setUp(): void { $this->resetAfterTest(true); $this->imsplugin = enrol_get_plugin('imsenterprise'); $this->set_test_config(); } /** * Sets the plugin configuration for testing */ public function set_test_config() { $this->imsplugin->set_config('mailadmins', false); $this->imsplugin->set_config('prev_path', ''); $this->imsplugin->set_config('createnewusers', true); $this->imsplugin->set_config('imsupdateusers', true); $this->imsplugin->set_config('createnewcourses', true); $this->imsplugin->set_config('updatecourses', true); $this->imsplugin->set_config('createnewcategories', true); $this->imsplugin->set_config('categoryseparator', ''); $this->imsplugin->set_config('categoryidnumber', false); $this->imsplugin->set_config('nestedcategories', false); } /** * Creates an IMS enterprise XML file and adds it's path to config settings. * * @param bool|array $users false or array of users StdClass * @param bool|array $courses false or of courses StdClass * @param bool|array $usercoursemembership false or of courses StdClass */ public function set_xml_file($users = false, $courses = false, $usercoursemembership = false) { $xmlcontent = '<enterprise>'; // Users. if (!empty($users) && is_array($users)) { foreach ($users as $user) { $xmlcontent .= '<person' . (!empty($user->recstatus) ? ' recstatus="'.$user->recstatus.'"' : '').'>'; $xmlcontent .= '<sourcedid><source>TestSource</source><id>'.$user->idnumber.'</id></sourcedid>'; $xmlcontent .= '<userid' . (!empty($user->auth) ? ' authenticationtype="'.$user->auth.'"' : ''); $xmlcontent .= '>'.$user->username.'</userid>'; $xmlcontent .= '<name>' .'<fn>'.$user->firstname.' '.$user->lastname.'</fn>' .'<n><family>'.$user->lastname.'</family><given>'.$user->firstname.'</given></n>' .'</name>' .'<email>'.$user->email.'</email>'; $xmlcontent .= '</person>'; } } // Courses. // Mapping based on default course attributes - IMS group tags mapping. if (!empty($courses) && is_array($courses)) { foreach ($courses as $course) { $xmlcontent .= '<group' . (!empty($course->recstatus) ? ' recstatus="'.$course->recstatus.'"' : '').'>'; $xmlcontent .= '<sourcedid><source>TestSource</source><id>'.$course->idnumber.'</id></sourcedid>'; $xmlcontent .= '<description>'.(!empty($course->imsshort) ? '<short>'.$course->imsshort.'</short>' : ''); $xmlcontent .= (!empty($course->imslong) ? '<long>'.$course->imslong.'</long>' : ''); $xmlcontent .= (!empty($course->imsfull) ? '<full>'.$course->imsfull.'</full>' : ''); $xmlcontent .= '</description>'; // The orgunit tag value is used by moodle as category name. $xmlcontent .= '<org>'; // Optional category name. if (isset($course->category)) { if (is_array($course->category)) { foreach ($course->category as $category) { $xmlcontent .= '<orgunit>' . $category . '</orgunit>'; } } else if (is_object($course->category)) { $xmlcontent .= '<orgunit>' . $course->category->name . '</orgunit>'; } else if (!empty($course->category)) { $xmlcontent .= '<orgunit>' . $course->category . '</orgunit>'; } } $xmlcontent .= '</org>'; $xmlcontent .= '</group>'; } } // User course membership (i.e. roles and enrolments). if (!empty($usercoursemembership) && is_array($usercoursemembership)) { foreach ($usercoursemembership as $crsemship) { // Only process records that have a source/id (i.e. course code) set in the IMS file. // Note that we could also check that there is a corresponding $course with the course code given here, // however it is possible that we want to test the behaviour of orphan membership elements in future, // so leaving the check out for now. if (isset($crsemship->crseidnumber) && isset($crsemship->member) && is_array($crsemship->member) && count($crsemship->member)) { $xmlcontent .= '<membership><sourcedid><source>TestSource</source><id>' .$crsemship->crseidnumber . '</id></sourcedid>'; foreach ($crsemship->member as $crsemember) { if (!empty($crsemember->useridnumber)) { $xmlcontent .= '<member>'; $xmlcontent .= '<sourcedid><source>TestSource</source><id>'. $crsemember->useridnumber .'</id></sourcedid>'; // Indicates whether the member is a Person (1) or another Group (2). // We're only handling user membership here, so hard-code value of 1. $xmlcontent .= '<idtype>1</idtype>'; if (isset($crsemember->role) && is_array($crsemember->role)) { foreach ($crsemember->role as $role) { $xmlcontent .= '<role roletype="'.$role->roletype.'" recstatus="'.$role->recstatus.'">'; $xmlcontent .= '<userid/>'; $xmlcontent .= '<status>' . $role->rolestatus . '</status>'; $xmlcontent .= '</role>'; } } $xmlcontent .= '</member>'; } } $xmlcontent .= '</membership>'; } } } $xmlcontent .= '</enterprise>'; // Creating the XML file. $filename = 'ims_' . rand(1000, 9999) . '.xml'; $tmpdir = make_temp_directory('enrol_imsenterprise'); $xmlfilepath = $tmpdir . '/' . $filename; file_put_contents($xmlfilepath, $xmlcontent); // Setting the file path in CFG. $this->imsplugin->set_config('imsfilelocation', $xmlfilepath); } /** * Utility function for generating test user records * * @param int $numberofrecordsrequired - number of test users required * @return array of StdClass objects representing test user records */ private function generate_test_user_records($numberofrecordsrequired) { $users = []; for ($i = 0; $i < $numberofrecordsrequired; $i++) { $usernumber = $i + 101; $users[] = (object)[ 'recstatus' => enrol_imsenterprise_plugin::IMSENTERPRISE_ADD, 'idnumber' => $usernumber, 'username' => 'UID' .$usernumber, 'email' => 'user' . $usernumber . '@moodle.org', 'firstname' => 'User' . $usernumber . ' firstname', 'lastname' => 'User' . $usernumber . ' lastname' ]; } return $users; } /** * Utility function for generating test course records * * @param int $numberofrecordsrequired - number of test course records required * @return array of StdClass objects representing test course records */ private function generate_test_course_records($numberofrecordsrequired) { $courses = []; for ($i = 0; $i < $numberofrecordsrequired; $i++) { $coursenumber = $i + 101; $courses[] = (object)[ 'recstatus' => enrol_imsenterprise_plugin::IMSENTERPRISE_ADD, 'idnumber' => 'CID' . $coursenumber, 'imsshort' => 'Course ' . $coursenumber, 'category' => core_course_category::get_default() ]; } return $courses; } /** * Utility function for generating test membership structure for given users and courses. * Linkmatrix is expected to be in [row, col] format, where courses are rows and users are columns. * Each element of the link matrix is expected to contain <roletype>:<role status>:<role recstatus>. * * @param array $users * @param array $courses * @param array $linkmatrix - matrix/two dimensional array of required user course enrolments * @return array */ private function link_users_with_courses($users, $courses, $linkmatrix) { $memberships = []; foreach ($courses as $i => $c) { $membership = new stdClass(); $membership->member = []; $membership->crseidnumber = $c->idnumber; foreach ($users as $j => $u) { if (isset($linkmatrix[$i][$j])) { list($roletype, $rolestatus, $rolerecstatus) = explode(':', $linkmatrix[$i][$j]); if (strlen($rolerecstatus) && strlen($roletype) && strlen($rolestatus)) { $membership->member[] = (object)[ 'useridnumber' => $u->idnumber, 'role' => [(object)[ 'roletype' => $roletype, 'rolestatus' => $rolestatus, 'recstatus' => $rolerecstatus ]] ]; } } } $memberships[] = $membership; } return $memberships; } /** * Add new users, courses and enrolments */ public function test_users_are_enroled_on_courses() { global $DB; $prevnuserenrolments = $DB->count_records('user_enrolments'); $prevnusers = $DB->count_records('user'); $prevncourses = $DB->count_records('course'); $courses = $this->generate_test_course_records(1); $users = $this->generate_test_user_records(1); $coursemembership = $this->link_users_with_courses( $users, $courses, [ ['01:1:1'] // First course. ] ); $this->set_xml_file($users, $courses, $coursemembership); $this->imsplugin->cron(); $this->assertEquals(($prevnuserenrolments + 1), $DB->count_records('user_enrolments')); $this->assertEquals(($prevnusers + 1), $DB->count_records('user')); $this->assertEquals(($prevncourses + 1), $DB->count_records('course')); } /** * Check that the unenrol actions are completely ignored when "unenrol" setting is disabled */ public function test_no_action_when_unenrol_disabled() { global $DB; $prevnuserenrolments = $DB->count_records('user_enrolments'); $prevnusers = $DB->count_records('user'); $prevncourses = $DB->count_records('course'); // Create user and course. $courses = $this->generate_test_course_records(3); $users = $this->generate_test_user_records(2); $coursemembership = $this->link_users_with_courses( $users, $courses, // Role types: 01=Learner, 02=Instructor, 03=Content Dev, 04=Member, 05=Manager, 06=Mentor, 07=Admin, 08=TA. // Role statuses: 0=Inactive, 1=Active. // Role recstatus: 1=Add, 2=Update, 3=Delete. // Format of matrix elements: <roletype>:<role status>:<role recstatus>. [ ['01:1:1', '01:1:1'], // Course 1. ['01:1:1', '01:1:1'], // Course 2. ['::', '01:1:1'], // Course 3. ] ); $this->set_xml_file($users, $courses, $coursemembership); $this->imsplugin->cron(); $this->assertEquals(($prevnuserenrolments + 5), $DB->count_records('user_enrolments')); $this->assertEquals(($prevnusers + 2), $DB->count_records('user')); $this->assertEquals(($prevncourses + 3), $DB->count_records('course')); // Disallow unenrolment, and check that unenroling has no effect. $this->imsplugin->set_config('imsunenrol', 0); $coursemembership = $this->link_users_with_courses( $users, $courses, // Role types: 01=Learner, 02=Instructor, 03=Content Dev, 04=Member, 05=Manager, 06=Mentor, 07=Admin, 08=TA. // Role statuses: 0=Inactive, 1=Active. // Role recstatus: 1=Add, 2=Update, 3=Delete. // Format of matrix elements: <roletype>:<role status>:<role recstatus>. [ ['01:1:3', '01:1:3'], // Course 1. ['::', '01:1:3'], // Course 2. ['::', '01:1:3'], // Course 3. ] ); $this->set_xml_file($users, $courses, $coursemembership); $this->imsplugin->cron(); $this->assertEquals(($prevnuserenrolments + 5), $DB->count_records('user_enrolments')); $this->assertEquals(($prevnusers + 2), $DB->count_records('user')); $this->assertEquals(($prevncourses + 3), $DB->count_records('course')); } /** * When a user has existing roles and enrolments, they are unaffected by IMS instructions for other courses */ public function test_existing_roles_and_enrolments_unaffected() { global $DB; $this->imsplugin->set_config('imsunenrol', 1); $this->imsplugin->set_config('unenrolaction', ENROL_EXT_REMOVED_UNENROL); $prevnuserenrolments = $DB->count_records('user_enrolments'); $prevnusers = $DB->count_records('user'); $prevncourses = $DB->count_records('course'); $courses = $this->generate_test_course_records(2); // Create_course seems to expect the category to be passed as ID, so extract from the object. $course1 = $courses[0]; $course1->category = $course1->category->id; $course1 = $this->getDataGenerator()->create_course($courses[0]); // Enrol user1 on course1. $DB->insert_record('enrol', (object)['enrol' => 'imsenterprise', 'courseid' => $course1->id, 'status' => 1, 'roleid' => 5 ], true); $user1 = $this->getDataGenerator()->create_and_enrol($course1, 'student', ['idnumber' => 'UserIDNumber100'], 'imsenterprise'); $user1->username = $user1->idnumber; // Confirm user was added and that the enrolment happened. $this->assertEquals(($prevnuserenrolments + 1), $DB->count_records('user_enrolments')); $this->assertEquals(($prevnusers + 1), $DB->count_records('user')); $this->assertEquals(($prevncourses + 1), $DB->count_records('course')); // Capture DB id of enrolment record. $initialusernerolment = $DB->get_record('user_enrolments', ['userid' => $user1->id], '*', MUST_EXIST); $initialroleassigned = $DB->get_record('role_assignments', ['userid' => $user1->id], '*', MUST_EXIST); // Add a new enrolment for the same user via IMS file. $coursemembership = $this->link_users_with_courses( [$user1], $courses, // Role types: 01=Learner, 02=Instructor, 03=Content Dev, 04=Member, 05=Manager, 06=Mentor, 07=Admin, 08=TA. // Role statuses: 0=Inactive, 1=Active. // Role recstatus: 1=Add, 2=Update, 3=Delete. // Format of matrix elements: <roletype>:<role status>:<role recstatus>. [ ['::'], // Course 1. ['01:1:1'], // Course 2. ] ); $this->set_xml_file([$user1], $courses, $coursemembership); $this->imsplugin->cron(); $this->assertEquals(2, $DB->count_records('user_enrolments', ['userid' => $user1->id])); $this->assertEquals(($prevncourses + 2), $DB->count_records('course')); // Unenrol the user from course2 via IMS file. $coursemembership = $this->link_users_with_courses( [$user1], $courses, // Role types: 01=Learner, 02=Instructor, 03=Content Dev, 04=Member, 05=Manager, 06=Mentor, 07=Admin, 08=TA. // Role statuses: 0=Inactive, 1=Active. // Role recstatus: 1=Add, 2=Update, 3=Delete. // Format of matrix elements: <roletype>:<role status>:<role recstatus>. [ ['::'], // Course 1. ['01:0:3'], // Course 2. ] ); $this->set_xml_file([$user1], $courses, $coursemembership); $this->imsplugin->cron(); $this->assertEquals(1, $DB->count_records('user_enrolments', ['userid' => $user1->id])); $this->assertTrue($DB->record_exists('user_enrolments', ['id' => $initialusernerolment->id, 'userid' => $initialusernerolment->userid])); $this->assertTrue($DB->record_exists('role_assignments', ['id' => $initialroleassigned->id, 'userid' => $initialusernerolment->userid])); } /** * Enrolments alone are disabled */ public function test_disable_enrolments_only() { global $DB; $this->imsplugin->set_config('imsunenrol', 1); $this->imsplugin->set_config('unenrolaction', ENROL_EXT_REMOVED_SUSPEND); $prevnuserenrolments = $DB->count_records('user_enrolments'); $prevnroles = $DB->count_records('role_assignments'); $prevnusers = $DB->count_records('user'); $prevncourses = $DB->count_records('course'); $courses = $this->generate_test_course_records(1); $users = $this->generate_test_user_records(1); // Add a new enrolment for the same user via IMS file. $coursemembership = $this->link_users_with_courses( $users, $courses, // Role types: 01=Learner, 02=Instructor, 03=Content Dev, 04=Member, 05=Manager, 06=Mentor, 07=Admin, 08=TA. // Role statuses: 0=Inactive, 1=Active. // Role recstatus: 1=Add, 2=Update, 3=Delete. // Format of matrix elements: <roletype>:<role status>:<role recstatus>. [ ['01:1:1'], // Course 1. ] ); $this->set_xml_file($users, $courses, $coursemembership); $this->imsplugin->cron(); $this->assertEquals(($prevncourses + 1), $DB->count_records('course')); $this->assertEquals(($prevnusers + 1), $DB->count_records('user')); $this->assertEquals(($prevnuserenrolments + 1), $DB->count_records('user_enrolments')); $this->assertEquals(($prevnroles + 1), $DB->count_records('role_assignments')); // Capture DB ids. $dbuser = $DB->get_record('user', ['idnumber' => $users[0]->idnumber], '*', MUST_EXIST); $dbenrolment = $DB->get_record('user_enrolments', ['userid' => $dbuser->id, 'status' => ENROL_USER_ACTIVE], '*', MUST_EXIST ); $dbrole = $DB->get_record('role_assignments', ['userid' => $dbuser->id], '*', MUST_EXIST); // Unenrol the user, check that the enrolment and role exist, but the enrolment is suspended. $coursemembership = $this->link_users_with_courses( $users, $courses, // Role types: 01=Learner, 02=Instructor, 03=Content Dev, 04=Member, 05=Manager, 06=Mentor, 07=Admin, 08=TA. // Role statuses: 0=Inactive, 1=Active. // Role recstatus: 1=Add, 2=Update, 3=Delete. // Format of matrix elements: <roletype>:<role status>:<role recstatus>. [ ['01:0:3'], // Course 1. ] ); $this->set_xml_file($users, $courses, $coursemembership); $this->imsplugin->cron(); $this->assertEquals(($prevncourses + 1), $DB->count_records('course')); $this->assertEquals(($prevnusers + 1), $DB->count_records('user')); $this->assertEquals(($prevnuserenrolments + 1), $DB->count_records('user_enrolments')); $this->assertEquals(($prevnroles + 1), $DB->count_records('role_assignments')); $this->assertEquals(1, $DB->count_records('user_enrolments', ['userid' => $dbuser->id, 'id' => $dbenrolment->id, 'status' => ENROL_USER_SUSPENDED])); $this->assertEquals(1, $DB->count_records('role_assignments', ['userid' => $dbuser->id, 'id' => $dbrole->id])); } /** * Enrolments are disabled but retained) and roles removed */ public function test_disable_enrolments_and_remove_roles() { global $DB; $this->imsplugin->set_config('imsunenrol', 1); $this->imsplugin->set_config('unenrolaction', ENROL_EXT_REMOVED_SUSPENDNOROLES); $prevnuserenrolments = $DB->count_records('user_enrolments'); $prevnroles = $DB->count_records('role_assignments'); $prevnusers = $DB->count_records('user'); $prevncourses = $DB->count_records('course'); $courses = $this->generate_test_course_records(1); $users = $this->generate_test_user_records(1); // Add a new enrolment for the same user via IMS file. $coursemembership = $this->link_users_with_courses( $users, $courses, // Role types: 01=Learner, 02=Instructor, 03=Content Dev, 04=Member, 05=Manager, 06=Mentor, 07=Admin, 08=TA. // Role statuses: 0=Inactive, 1=Active. // Role recstatus: 1=Add, 2=Update, 3=Delete. // Format of matrix elements: <roletype>:<role status>:<role recstatus>. [ ['01:1:1'], // Course 1. ] ); $this->set_xml_file($users, $courses, $coursemembership); $this->imsplugin->cron(); $this->assertEquals(($prevncourses + 1), $DB->count_records('course')); $this->assertEquals(($prevnusers + 1), $DB->count_records('user')); $this->assertEquals(($prevnuserenrolments + 1), $DB->count_records('user_enrolments')); $this->assertEquals(($prevnroles + 1), $DB->count_records('role_assignments')); // Capture DB ids. $dbuser = $DB->get_record('user', ['idnumber' => $users[0]->idnumber], '*', MUST_EXIST); $dbenrolment = $DB->get_record('user_enrolments', ['userid' => $dbuser->id, 'status' => ENROL_USER_ACTIVE], '*', MUST_EXIST ); $dbrole = $DB->get_record('role_assignments', ['userid' => $dbuser->id], '*', MUST_EXIST); // Unenrol the user, check that the enrolment and role exist, but the enrolment is suspended. $coursemembership = $this->link_users_with_courses( $users, $courses, // Role types: 01=Learner, 02=Instructor, 03=Content Dev, 04=Member, 05=Manager, 06=Mentor, 07=Admin, 08=TA. // Role statuses: 0=Inactive, 1=Active. // Role recstatus: 1=Add, 2=Update, 3=Delete. // Format of matrix elements: <roletype>:<role status>:<role recstatus>. [ ['01:0:3'], // Course 1. ] ); $this->set_xml_file($users, $courses, $coursemembership); $this->imsplugin->cron(); $this->assertEquals(($prevncourses + 1), $DB->count_records('course')); $this->assertEquals(($prevnusers + 1), $DB->count_records('user')); $this->assertEquals(($prevnuserenrolments + 1), $DB->count_records('user_enrolments')); $this->assertEquals(($prevnroles), $DB->count_records('role_assignments')); $this->assertEquals(1, $DB->count_records('user_enrolments', ['userid' => $dbuser->id, 'id' => $dbenrolment->id, 'status' => ENROL_USER_SUSPENDED])); $this->assertEquals(0, $DB->count_records('role_assignments', ['userid' => $dbuser->id, 'id' => $dbrole->id])); } /** * Enrolments and roles are deleted for specified user */ public function test_delete_roles_and_enrolments() { global $DB; $this->imsplugin->set_config('imsunenrol', 1); $this->imsplugin->set_config('unenrolaction', ENROL_EXT_REMOVED_UNENROL); $prevnuserenrolments = $DB->count_records('user_enrolments'); $prevnroles = $DB->count_records('role_assignments'); $prevnusers = $DB->count_records('user'); $prevncourses = $DB->count_records('course'); $courses = $this->generate_test_course_records(1); $users = $this->generate_test_user_records(1); // Add a new enrolment for the same user via IMS file. $coursemembership = $this->link_users_with_courses( $users, $courses, // Role types: 01=Learner, 02=Instructor, 03=Content Dev, 04=Member, 05=Manager, 06=Mentor, 07=Admin, 08=TA. // Role statuses: 0=Inactive, 1=Active. // Role recstatus: 1=Add, 2=Update, 3=Delete. // Format of matrix elements: <roletype>:<role status>:<role recstatus>. [ ['01:1:1'], // Course 1. ] ); $this->set_xml_file($users, $courses, $coursemembership); $this->imsplugin->cron(); $this->assertEquals(($prevncourses + 1), $DB->count_records('course')); $this->assertEquals(($prevnusers + 1), $DB->count_records('user')); $this->assertEquals(($prevnuserenrolments + 1), $DB->count_records('user_enrolments')); $this->assertEquals(($prevnroles + 1), $DB->count_records('role_assignments')); // Capture DB ids. $dbuser = $DB->get_record('user', ['idnumber' => $users[0]->idnumber], '*', MUST_EXIST); $dbenrolment = $DB->get_record('user_enrolments', ['userid' => $dbuser->id, 'status' => ENROL_USER_ACTIVE], '*', MUST_EXIST ); $dbrole = $DB->get_record('role_assignments', ['userid' => $dbuser->id], '*', MUST_EXIST); // Unenrol the user, check that the enrolment and role exist, but the enrolment is suspended. $coursemembership = $this->link_users_with_courses( $users, $courses, // Role types: 01=Learner, 02=Instructor, 03=Content Dev, 04=Member, 05=Manager, 06=Mentor, 07=Admin, 08=TA. // Role statuses: 0=Inactive, 1=Active. // Role recstatus: 1=Add, 2=Update, 3=Delete. // Format of matrix elements: <roletype>:<role status>:<role recstatus>. [ ['01:1:3'], // Course 1. ] ); $this->set_xml_file($users, $courses, $coursemembership); $this->imsplugin->cron(); $this->assertEquals(($prevncourses + 1), $DB->count_records('course')); $this->assertEquals(($prevnusers + 1), $DB->count_records('user')); $this->assertEquals(($prevnuserenrolments), $DB->count_records('user_enrolments')); $this->assertEquals(($prevnroles), $DB->count_records('role_assignments')); $this->assertEquals(0, $DB->count_records('user_enrolments', ['userid' => $dbuser->id, 'id' => $dbenrolment->id, 'status' => ENROL_USER_SUSPENDED])); $this->assertEquals(0, $DB->count_records('role_assignments', ['userid' => $dbuser->id, 'id' => $dbrole->id])); } }