MDL-47666 DB auth & enrol: unit tests fail with custom DB drivers
[moodle.git] / enrol / database / tests / sync_test.php
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/>.
17 /**
18  * External database enrolment sync tests, this also tests adodb drivers
19  * that are matching our four supported Moodle database drivers.
20  *
21  * @package    enrol_database
22  * @category   phpunit
23  * @copyright  2011 Petr Skoda {@link http://skodak.org}
24  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25  */
27 defined('MOODLE_INTERNAL') || die();
29 class enrol_database_testcase extends advanced_testcase {
30     protected static $courses = array();
31     protected static $users = array();
32     protected static $roles = array();
34     /** @var string Original error log */
35     protected $oldlog;
37     protected function init_enrol_database() {
38         global $DB, $CFG;
40         // Discard error logs from AdoDB.
41         $this->oldlog = ini_get('error_log');
42         ini_set('error_log', "$CFG->dataroot/testlog.log");
44         $dbman = $DB->get_manager();
46         set_config('dbencoding', 'utf-8', 'enrol_database');
48         set_config('dbhost', $CFG->dbhost, 'enrol_database');
49         set_config('dbuser', $CFG->dbuser, 'enrol_database');
50         set_config('dbpass', $CFG->dbpass, 'enrol_database');
51         set_config('dbname', $CFG->dbname, 'enrol_database');
53         if (!empty($CFG->dboptions['dbport'])) {
54             set_config('dbhost', $CFG->dbhost.':'.$CFG->dboptions['dbport'], 'enrol_database');
55         }
57         switch ($DB->get_dbfamily()) {
59             case 'mysql':
60                 set_config('dbtype', 'mysqli', 'enrol_database');
61                 set_config('dbsetupsql', "SET NAMES 'UTF-8'", 'enrol_database');
62                 set_config('dbsybasequoting', '0', 'enrol_database');
63                 if (!empty($CFG->dboptions['dbsocket'])) {
64                     $dbsocket = $CFG->dboptions['dbsocket'];
65                     if ((strpos($dbsocket, '/') === false and strpos($dbsocket, '\\') === false)) {
66                         $dbsocket = ini_get('mysqli.default_socket');
67                     }
68                     set_config('dbtype', 'mysqli://'.rawurlencode($CFG->dbuser).':'.rawurlencode($CFG->dbpass).'@'.rawurlencode($CFG->dbhost).'/'.rawurlencode($CFG->dbname).'?socket='.rawurlencode($dbsocket), 'enrol_database');
69                 }
70                 break;
72             case 'oracle':
73                 set_config('dbtype', 'oci8po', 'enrol_database');
74                 set_config('dbsybasequoting', '1', 'enrol_database');
75                 break;
77             case 'postgres':
78                 set_config('dbtype', 'postgres7', 'enrol_database');
79                 $setupsql = "SET NAMES 'UTF-8'";
80                 if (!empty($CFG->dboptions['dbschema'])) {
81                     $setupsql .= "; SET search_path = '".$CFG->dboptions['dbschema']."'";
82                 }
83                 set_config('dbsetupsql', $setupsql, 'enrol_database');
84                 set_config('dbsybasequoting', '0', 'enrol_database');
85                 if (!empty($CFG->dboptions['dbsocket']) and ($CFG->dbhost === 'localhost' or $CFG->dbhost === '127.0.0.1')) {
86                     if (strpos($CFG->dboptions['dbsocket'], '/') !== false) {
87                         $socket = $CFG->dboptions['dbsocket'];
88                         if (!empty($CFG->dboptions['dbport'])) {
89                             $socket .= ':' . $CFG->dboptions['dbport'];
90                         }
91                         set_config('dbhost', $socket, 'enrol_database');
92                     } else {
93                       set_config('dbhost', '', 'enrol_database');
94                     }
95                 }
96                 break;
98             case 'mssql':
99                 if (get_class($DB) == 'mssql_native_moodle_database') {
100                     set_config('dbtype', 'mssql_n', 'enrol_database');
101                 } else {
102                     set_config('dbtype', 'mssqlnative', 'enrol_database');
103                 }
104                 set_config('dbsybasequoting', '1', 'enrol_database');
105                 break;
107             default:
108                 throw new exception('Unknown database driver '.get_class($DB));
109         }
111         // NOTE: It is stongly discouraged to create new tables in advanced_testcase classes,
112         //       but there is no other simple way to test ext database enrol sync, so let's
113         //       disable transactions are try to cleanup after the tests.
115         $table = new xmldb_table('enrol_database_test_enrols');
116         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
117         $table->add_field('courseid', XMLDB_TYPE_CHAR, '255', null, null, null);
118         $table->add_field('userid', XMLDB_TYPE_CHAR, '255', null, null, null);
119         $table->add_field('roleid', XMLDB_TYPE_CHAR, '255', null, null, null);
120         $table->add_field('otheruser', XMLDB_TYPE_CHAR, '1', null, XMLDB_NOTNULL, null, '0');
121         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
122         if ($dbman->table_exists($table)) {
123             $dbman->drop_table($table);
124         }
125         $dbman->create_table($table);
126         set_config('remoteenroltable', $CFG->prefix.'enrol_database_test_enrols', 'enrol_database');
127         set_config('remotecoursefield', 'courseid', 'enrol_database');
128         set_config('remoteuserfield', 'userid', 'enrol_database');
129         set_config('remoterolefield', 'roleid', 'enrol_database');
130         set_config('remoteotheruserfield', 'otheruser', 'enrol_database');
132         $table = new xmldb_table('enrol_database_test_courses');
133         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
134         $table->add_field('fullname', XMLDB_TYPE_CHAR, '255', null, null, null);
135         $table->add_field('shortname', XMLDB_TYPE_CHAR, '255', null, null, null);
136         $table->add_field('idnumber', XMLDB_TYPE_CHAR, '255', null, null, null);
137         $table->add_field('category', XMLDB_TYPE_CHAR, '255', null, null, null);
138         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
139         if ($dbman->table_exists($table)) {
140             $dbman->drop_table($table);
141         }
142         $dbman->create_table($table);
143         set_config('newcoursetable', $CFG->prefix.'enrol_database_test_courses', 'enrol_database');
144         set_config('newcoursefullname', 'fullname', 'enrol_database');
145         set_config('newcourseshortname', 'shortname', 'enrol_database');
146         set_config('newcourseidnumber', 'idnumber', 'enrol_database');
147         set_config('newcoursecategory', 'category', 'enrol_database');
149         // Create some test users and courses.
150         for ($i = 1; $i <= 4; $i++) {
151             self::$courses[$i] = $this->getDataGenerator()->create_course(array('fullname' => 'Test course '.$i, 'shortname' => 'tc'.$i, 'idnumber' => 'courseid'.$i));
152         }
154         for ($i = 1; $i <= 10; $i++) {
155             self::$users[$i] = $this->getDataGenerator()->create_user(array('username' => 'username'.$i, 'idnumber' => 'userid'.$i, 'email' => 'user'.$i.'@example.com'));
156         }
158         foreach (get_all_roles() as $role) {
159             self::$roles[$role->shortname] = $role;
160         }
161     }
163     protected function cleanup_enrol_database() {
164         global $DB;
166         $dbman = $DB->get_manager();
167         $table = new xmldb_table('enrol_database_test_enrols');
168         $dbman->drop_table($table);
169         $table = new xmldb_table('enrol_database_test_courses');
170         $dbman->drop_table($table);
172         self::$courses = null;
173         self::$users = null;
174         self::$roles = null;
176         ini_set('error_log', $this->oldlog);
177     }
179     protected function reset_enrol_database() {
180         global $DB;
182         $DB->delete_records('enrol_database_test_enrols', array());
183         $DB->delete_records('enrol_database_test_courses', array());
185         $plugin = enrol_get_plugin('database');
186         $instances = $DB->get_records('enrol', array('enrol' => 'database'));
187         foreach($instances as $instance) {
188             $plugin->delete_instance($instance);
189         }
190     }
192     protected function assertIsEnrolled($userindex, $courseindex, $status=null, $rolename = null) {
193         global $DB;
194         $dbinstance = $DB->get_record('enrol', array('courseid' => self::$courses[$courseindex]->id, 'enrol' => 'database'), '*', MUST_EXIST);
196         $conditions = array('enrolid' => $dbinstance->id, 'userid' => self::$users[$userindex]->id);
197         if ($status !== null) {
198             $conditions['status'] = $status;
199         }
200         $this->assertTrue($DB->record_exists('user_enrolments', $conditions));
202         $this->assertHasRoleAssignment($userindex, $courseindex, $rolename);
203     }
205     protected function assertHasRoleAssignment($userindex, $courseindex, $rolename = null) {
206         global $DB;
207         $dbinstance = $DB->get_record('enrol', array('courseid' => self::$courses[$courseindex]->id, 'enrol' => 'database'), '*', MUST_EXIST);
209         $coursecontext = context_course::instance(self::$courses[$courseindex]->id);
210         if ($rolename === false) {
211             $this->assertFalse($DB->record_exists('role_assignments', array('component' => 'enrol_database', 'itemid' => $dbinstance->id, 'userid' => self::$users[$userindex]->id, 'contextid' => $coursecontext->id)));
212         } else if ($rolename !== null) {
213             $this->assertTrue($DB->record_exists('role_assignments', array('component' => 'enrol_database', 'itemid' => $dbinstance->id, 'userid' => self::$users[$userindex]->id, 'contextid' => $coursecontext->id, 'roleid' => self::$roles[$rolename]->id)));
214         }
215     }
217     protected function assertIsNotEnrolled($userindex, $courseindex) {
218         global $DB;
219         if (!$dbinstance = $DB->get_record('enrol', array('courseid' => self::$courses[$courseindex]->id, 'enrol' => 'database'))) {
220             return;
221         }
222         $this->assertFalse($DB->record_exists('user_enrolments', array('enrolid' => $dbinstance->id, 'userid' => self::$users[$userindex]->id)));
223     }
225     public function test_sync_user_enrolments() {
226         global $DB;
228         $this->init_enrol_database();
230         $this->resetAfterTest(false);
231         $this->preventResetByRollback();
233         $plugin = enrol_get_plugin('database');
235         // Test basic enrol sync for one user after login.
237         $this->reset_enrol_database();
238         $plugin->set_config('localcoursefield', 'idnumber');
239         $plugin->set_config('localuserfield', 'idnumber');
240         $plugin->set_config('localrolefield', 'shortname');
242         $plugin->set_config('defaultrole', self::$roles['student']->id);
244         $DB->insert_record('enrol_database_test_enrols', array('userid' => 'userid1', 'courseid' => 'courseid1', 'roleid' => 'student'));
245         $DB->insert_record('enrol_database_test_enrols', array('userid' => 'userid1', 'courseid' => 'courseid2', 'roleid' => 'teacher'));
246         $DB->insert_record('enrol_database_test_enrols', array('userid' => 'userid2', 'courseid' => 'courseid1', 'roleid' => null));
247         $DB->insert_record('enrol_database_test_enrols', array('userid' => 'userid4', 'courseid' => 'courseid4', 'roleid' => 'editingteacher', 'otheruser' => '1'));
248         $DB->insert_record('enrol_database_test_enrols', array('userid' => 'xxxxxxx', 'courseid' => 'courseid1', 'roleid' => 'student')); // Bogus record to be ignored.
249         $DB->insert_record('enrol_database_test_enrols', array('userid' => 'userid1', 'courseid' => 'xxxxxxxxx', 'roleid' => 'student')); // Bogus record to be ignored.
251         $this->assertEquals(0, $DB->count_records('user_enrolments', array()));
252         $this->assertEquals(0, $DB->count_records('enrol', array('enrol' => 'database')));
253         $this->assertEquals(0, $DB->count_records('role_assignments', array('component' => 'enrol_database')));
255         $plugin->sync_user_enrolments(self::$users[1]);
256         $this->assertEquals(2, $DB->count_records('user_enrolments', array()));
257         $this->assertEquals(2, $DB->count_records('enrol', array('enrol' => 'database')));
258         $this->assertEquals(2, $DB->count_records('role_assignments', array('component' => 'enrol_database')));
259         $this->assertIsEnrolled(1, 1, ENROL_USER_ACTIVE, 'student');
260         $this->assertIsEnrolled(1, 2, ENROL_USER_ACTIVE, 'teacher');
262         // Make sure there are no errors or changes on the next login.
264         $plugin->sync_user_enrolments(self::$users[1]);
265         $this->assertEquals(2, $DB->count_records('user_enrolments', array()));
266         $this->assertEquals(2, $DB->count_records('enrol', array('enrol' => 'database')));
267         $this->assertEquals(2, $DB->count_records('role_assignments', array('component' => 'enrol_database')));
268         $this->assertIsEnrolled(1, 1, ENROL_USER_ACTIVE, 'student');
269         $this->assertIsEnrolled(1, 2, ENROL_USER_ACTIVE, 'teacher');
271         $plugin->sync_user_enrolments(self::$users[2]);
272         $this->assertEquals(3, $DB->count_records('user_enrolments', array()));
273         $this->assertEquals(2, $DB->count_records('enrol', array('enrol' => 'database')));
274         $this->assertEquals(3, $DB->count_records('role_assignments', array('component' => 'enrol_database')));
275         $this->assertIsEnrolled(1, 1, ENROL_USER_ACTIVE, 'student');
276         $this->assertIsEnrolled(1, 2, ENROL_USER_ACTIVE, 'teacher');
277         $this->assertIsEnrolled(2, 1, ENROL_USER_ACTIVE, 'student');
279         $plugin->sync_user_enrolments(self::$users[4]);
280         $this->assertEquals(3, $DB->count_records('user_enrolments', array()));
281         $this->assertEquals(3, $DB->count_records('enrol', array('enrol' => 'database')));
282         $this->assertEquals(4, $DB->count_records('role_assignments', array('component' => 'enrol_database')));
283         $this->assertIsEnrolled(1, 1, ENROL_USER_ACTIVE, 'student');
284         $this->assertIsEnrolled(1, 2, ENROL_USER_ACTIVE, 'teacher');
285         $this->assertIsEnrolled(2, 1, ENROL_USER_ACTIVE, 'student');
286         $this->assertIsNotEnrolled(4, 4);
287         $this->assertHasRoleAssignment(4, 4, 'editingteacher');
289         // Enrolment removals.
291         $DB->delete_records('enrol_database_test_enrols', array('userid' => 'userid1', 'courseid' => 'courseid1', 'roleid' => 'student'));
292         $plugin->set_config('unenrolaction', ENROL_EXT_REMOVED_KEEP);
293         $plugin->sync_user_enrolments(self::$users[1]);
294         $this->assertEquals(3, $DB->count_records('user_enrolments', array()));
295         $this->assertEquals(3, $DB->count_records('enrol', array('enrol' => 'database')));
296         $this->assertEquals(4, $DB->count_records('role_assignments', array('component' => 'enrol_database')));
297         $this->assertIsEnrolled(1, 1, ENROL_USER_ACTIVE, 'student');
298         $this->assertIsEnrolled(1, 2, ENROL_USER_ACTIVE, 'teacher');
301         $plugin->set_config('unenrolaction', ENROL_EXT_REMOVED_SUSPEND);
302         $plugin->sync_user_enrolments(self::$users[1]);
303         $this->assertEquals(3, $DB->count_records('user_enrolments', array()));
304         $this->assertEquals(3, $DB->count_records('enrol', array('enrol' => 'database')));
305         $this->assertEquals(4, $DB->count_records('role_assignments', array('component' => 'enrol_database')));
306         $this->assertIsEnrolled(1, 1, ENROL_USER_SUSPENDED, 'student');
307         $this->assertIsEnrolled(1, 2, ENROL_USER_ACTIVE, 'teacher');
309         $DB->insert_record('enrol_database_test_enrols', array('userid' => 'userid1', 'courseid' => 'courseid1', 'roleid' => 'student'));
310         $plugin->sync_user_enrolments(self::$users[1]);
311         $this->assertEquals(3, $DB->count_records('user_enrolments', array()));
312         $this->assertEquals(3, $DB->count_records('enrol', array('enrol' => 'database')));
313         $this->assertEquals(4, $DB->count_records('role_assignments', array('component' => 'enrol_database')));
314         $this->assertIsEnrolled(1, 1, ENROL_USER_ACTIVE, 'student');
315         $this->assertIsEnrolled(1, 2, ENROL_USER_ACTIVE, 'teacher');
318         $DB->delete_records('enrol_database_test_enrols', array('userid' => 'userid1', 'courseid' => 'courseid1', 'roleid' => 'student'));
319         $plugin->set_config('unenrolaction', ENROL_EXT_REMOVED_SUSPENDNOROLES);
320         $plugin->sync_user_enrolments(self::$users[1]);
321         $this->assertEquals(3, $DB->count_records('user_enrolments', array()));
322         $this->assertEquals(3, $DB->count_records('enrol', array('enrol' => 'database')));
323         $this->assertEquals(3, $DB->count_records('role_assignments', array('component' => 'enrol_database')));
324         $this->assertIsEnrolled(1, 1, ENROL_USER_SUSPENDED, false);
325         $this->assertIsEnrolled(1, 2, ENROL_USER_ACTIVE, 'teacher');
327         $DB->insert_record('enrol_database_test_enrols', array('userid' => 'userid1', 'courseid' => 'courseid1', 'roleid' => 'student'));
328         $plugin->sync_user_enrolments(self::$users[1]);
329         $this->assertEquals(3, $DB->count_records('user_enrolments', array()));
330         $this->assertEquals(3, $DB->count_records('enrol', array('enrol' => 'database')));
331         $this->assertEquals(4, $DB->count_records('role_assignments', array('component' => 'enrol_database')));
332         $this->assertIsEnrolled(1, 1, ENROL_USER_ACTIVE, 'student');
333         $this->assertIsEnrolled(1, 2, ENROL_USER_ACTIVE, 'teacher');
336         $DB->delete_records('enrol_database_test_enrols', array('userid' => 'userid1', 'courseid' => 'courseid1', 'roleid' => 'student'));
337         $plugin->set_config('unenrolaction', ENROL_EXT_REMOVED_UNENROL);
338         $plugin->sync_user_enrolments(self::$users[1]);
339         $this->assertEquals(2, $DB->count_records('user_enrolments', array()));
340         $this->assertEquals(3, $DB->count_records('enrol', array('enrol' => 'database')));
341         $this->assertEquals(3, $DB->count_records('role_assignments', array('component' => 'enrol_database')));
342         $this->assertIsNotEnrolled(1, 1);
343         $this->assertIsEnrolled(1, 2, ENROL_USER_ACTIVE, 'teacher');
345         $DB->delete_records('enrol_database_test_enrols', array('userid' => 'userid4', 'courseid' => 'courseid4', 'roleid' => 'editingteacher'));
346         $plugin->set_config('unenrolaction', ENROL_EXT_REMOVED_SUSPENDNOROLES);
347         $plugin->sync_user_enrolments(self::$users[4]);
348         $this->assertEquals(2, $DB->count_records('user_enrolments', array()));
349         $this->assertEquals(3, $DB->count_records('enrol', array('enrol' => 'database')));
350         $this->assertEquals(2, $DB->count_records('role_assignments', array('component' => 'enrol_database')));
351         $this->assertIsNotEnrolled(4, 4);
352         $this->assertHasRoleAssignment(4, 4, false);
354         // Test all other mapping options.
356         $this->reset_enrol_database();
358         $this->assertEquals(0, $DB->count_records('user_enrolments', array()));
359         $this->assertEquals(0, $DB->count_records('enrol', array('enrol' => 'database')));
360         $this->assertEquals(0, $DB->count_records('role_assignments', array('component' => 'enrol_database')));
362         $plugin->set_config('localcoursefield', 'id');
363         $plugin->set_config('localuserfield', 'id');
364         $plugin->set_config('localrolefield', 'id');
366         $DB->insert_record('enrol_database_test_enrols', array('userid' => self::$users[1]->id, 'courseid' => self::$courses[1]->id, 'roleid' => self::$roles['student']->id));
367         $DB->insert_record('enrol_database_test_enrols', array('userid' => self::$users[1]->id, 'courseid' => self::$courses[2]->id, 'roleid' => self::$roles['teacher']->id));
368         $DB->insert_record('enrol_database_test_enrols', array('userid' => self::$users[2]->id, 'courseid' => self::$courses[1]->id, 'roleid' => self::$roles['student']->id));
370         $plugin->sync_user_enrolments(self::$users[1]);
371         $this->assertEquals(2, $DB->count_records('user_enrolments', array()));
372         $this->assertEquals(2, $DB->count_records('enrol', array('enrol' => 'database')));
373         $this->assertEquals(2, $DB->count_records('role_assignments', array('component' => 'enrol_database')));
374         $this->assertIsEnrolled(1, 1, ENROL_USER_ACTIVE, 'student');
375         $this->assertIsEnrolled(1, 2, ENROL_USER_ACTIVE, 'teacher');
378         $this->reset_enrol_database();
379         $plugin->set_config('localcoursefield', 'shortname');
380         $plugin->set_config('localuserfield', 'email');
381         $plugin->set_config('localrolefield', 'id');
383         $DB->insert_record('enrol_database_test_enrols', array('userid' => self::$users[1]->email, 'courseid' => self::$courses[1]->shortname, 'roleid' => self::$roles['student']->id));
384         $DB->insert_record('enrol_database_test_enrols', array('userid' => self::$users[1]->email, 'courseid' => self::$courses[2]->shortname, 'roleid' => self::$roles['teacher']->id));
385         $DB->insert_record('enrol_database_test_enrols', array('userid' => self::$users[2]->email, 'courseid' => self::$courses[1]->shortname, 'roleid' => self::$roles['student']->id));
387         $plugin->sync_user_enrolments(self::$users[1]);
388         $this->assertEquals(2, $DB->count_records('user_enrolments', array()));
389         $this->assertEquals(2, $DB->count_records('enrol', array('enrol' => 'database')));
390         $this->assertEquals(2, $DB->count_records('role_assignments', array('component' => 'enrol_database')));
391         $this->assertIsEnrolled(1, 1, ENROL_USER_ACTIVE, 'student');
392         $this->assertIsEnrolled(1, 2, ENROL_USER_ACTIVE, 'teacher');
395         $this->reset_enrol_database();
396         $plugin->set_config('localcoursefield', 'id');
397         $plugin->set_config('localuserfield', 'username');
398         $plugin->set_config('localrolefield', 'id');
400         $DB->insert_record('enrol_database_test_enrols', array('userid' => self::$users[1]->username, 'courseid' => self::$courses[1]->id, 'roleid' => self::$roles['student']->id));
401         $DB->insert_record('enrol_database_test_enrols', array('userid' => self::$users[1]->username, 'courseid' => self::$courses[2]->id, 'roleid' => self::$roles['teacher']->id));
402         $DB->insert_record('enrol_database_test_enrols', array('userid' => self::$users[2]->username, 'courseid' => self::$courses[1]->id, 'roleid' => self::$roles['student']->id));
404         $plugin->sync_user_enrolments(self::$users[1]);
405         $this->assertEquals(2, $DB->count_records('user_enrolments', array()));
406         $this->assertEquals(2, $DB->count_records('enrol', array('enrol' => 'database')));
407         $this->assertEquals(2, $DB->count_records('role_assignments', array('component' => 'enrol_database')));
408         $this->assertIsEnrolled(1, 1, ENROL_USER_ACTIVE, 'student');
409         $this->assertIsEnrolled(1, 2, ENROL_USER_ACTIVE, 'teacher');
410     }
412     /**
413      * @depends test_sync_user_enrolments
414      */
415     public function test_sync_users() {
416         global $DB;
418         $this->resetAfterTest(false);
419         $this->preventResetByRollback();
420         $this->reset_enrol_database();
422         $plugin = enrol_get_plugin('database');
424         $trace = new null_progress_trace();
426         // Test basic enrol sync for one user after login.
428         $this->reset_enrol_database();
429         $plugin->set_config('localcoursefield', 'idnumber');
430         $plugin->set_config('localuserfield', 'idnumber');
431         $plugin->set_config('localrolefield', 'shortname');
433         $DB->insert_record('enrol_database_test_enrols', array('userid' => 'userid1', 'courseid' => 'courseid1', 'roleid' => 'student'));
434         $DB->insert_record('enrol_database_test_enrols', array('userid' => 'userid1', 'courseid' => 'courseid2', 'roleid' => 'editingteacher'));
435         $DB->insert_record('enrol_database_test_enrols', array('userid' => 'userid2', 'courseid' => 'courseid1', 'roleid' => 'student'));
436         $DB->insert_record('enrol_database_test_enrols', array('userid' => 'userid4', 'courseid' => 'courseid4', 'roleid' => 'editingteacher', 'otheruser' => '1'));
437         $DB->insert_record('enrol_database_test_enrols', array('userid' => 'xxxxxxx', 'courseid' => 'courseid1', 'roleid' => 'student')); // Bogus record to be ignored.
438         $DB->insert_record('enrol_database_test_enrols', array('userid' => 'userid1', 'courseid' => 'xxxxxxxxx', 'roleid' => 'student')); // Bogus record to be ignored.
439         $this->assertEquals(0, $DB->count_records('user_enrolments', array()));
440         $this->assertEquals(0, $DB->count_records('enrol', array('enrol' => 'database')));
441         $this->assertEquals(0, $DB->count_records('role_assignments', array('component' => 'enrol_database')));
443         $plugin->sync_enrolments($trace);
444         $this->assertEquals(3, $DB->count_records('user_enrolments', array()));
445         $this->assertEquals(3, $DB->count_records('enrol', array('enrol' => 'database')));
446         $this->assertEquals(4, $DB->count_records('role_assignments', array('component' => 'enrol_database')));
447         $this->assertIsEnrolled(1, 1, ENROL_USER_ACTIVE, 'student');
448         $this->assertIsEnrolled(1, 2, ENROL_USER_ACTIVE, 'editingteacher');
449         $this->assertIsEnrolled(2, 1, ENROL_USER_ACTIVE, 'student');
450         $this->assertIsNotEnrolled(4, 4);
451         $this->assertHasRoleAssignment(4, 4, 'editingteacher');
453         $plugin->set_config('defaultrole', self::$roles['teacher']->id);
454         $DB->insert_record('enrol_database_test_enrols', array('userid' => 'userid3', 'courseid' => 'courseid3'));
455         $plugin->sync_enrolments($trace);
456         $this->assertEquals(4, $DB->count_records('user_enrolments', array()));
457         $this->assertEquals(4, $DB->count_records('enrol', array('enrol' => 'database')));
458         $this->assertEquals(5, $DB->count_records('role_assignments', array('component' => 'enrol_database')));
459         $this->assertIsEnrolled(1, 1, ENROL_USER_ACTIVE, 'student');
460         $this->assertIsEnrolled(1, 2, ENROL_USER_ACTIVE, 'editingteacher');
461         $this->assertIsEnrolled(2, 1, ENROL_USER_ACTIVE, 'student');
462         $this->assertIsNotEnrolled(4, 4);
463         $this->assertHasRoleAssignment(4, 4, 'editingteacher');
464         $this->assertIsEnrolled(3, 3, ENROL_USER_ACTIVE, 'teacher');
467         // Test different unenrolment options.
469         $DB->delete_records('enrol_database_test_enrols', array('userid' => 'userid1', 'courseid' => 'courseid1', 'roleid' => 'student'));
470         $plugin->set_config('unenrolaction', ENROL_EXT_REMOVED_KEEP);
471         $plugin->sync_enrolments($trace);
472         $this->assertEquals(4, $DB->count_records('user_enrolments', array()));
473         $this->assertEquals(4, $DB->count_records('enrol', array('enrol' => 'database')));
474         $this->assertEquals(5, $DB->count_records('role_assignments', array('component' => 'enrol_database')));
475         $this->assertIsEnrolled(1, 1, ENROL_USER_ACTIVE, 'student');
476         $this->assertIsEnrolled(1, 2, ENROL_USER_ACTIVE, 'editingteacher');
477         $this->assertIsEnrolled(2, 1, ENROL_USER_ACTIVE, 'student');
478         $this->assertIsNotEnrolled(4, 4);
479         $this->assertHasRoleAssignment(4, 4, 'editingteacher');
480         $this->assertIsEnrolled(3, 3, ENROL_USER_ACTIVE, 'teacher');
483         $plugin->set_config('unenrolaction', ENROL_EXT_REMOVED_SUSPEND);
484         $plugin->sync_enrolments($trace);
485         $this->assertEquals(4, $DB->count_records('user_enrolments', array()));
486         $this->assertEquals(4, $DB->count_records('enrol', array('enrol' => 'database')));
487         $this->assertEquals(5, $DB->count_records('role_assignments', array('component' => 'enrol_database')));
488         $this->assertIsEnrolled(1, 1, ENROL_USER_SUSPENDED, 'student');
489         $this->assertIsEnrolled(1, 2, ENROL_USER_ACTIVE, 'editingteacher');
490         $this->assertIsEnrolled(2, 1, ENROL_USER_ACTIVE, 'student');
491         $this->assertIsNotEnrolled(4, 4);
492         $this->assertHasRoleAssignment(4, 4, 'editingteacher');
493         $this->assertIsEnrolled(3, 3, ENROL_USER_ACTIVE, 'teacher');
495         $DB->insert_record('enrol_database_test_enrols', array('userid' => 'userid1', 'courseid' => 'courseid1', 'roleid' => 'student'));
496         $plugin->sync_enrolments($trace);
497         $this->assertEquals(4, $DB->count_records('user_enrolments', array()));
498         $this->assertEquals(4, $DB->count_records('enrol', array('enrol' => 'database')));
499         $this->assertEquals(5, $DB->count_records('role_assignments', array('component' => 'enrol_database')));
500         $this->assertIsEnrolled(1, 1, ENROL_USER_ACTIVE, 'student');
501         $this->assertIsEnrolled(1, 2, ENROL_USER_ACTIVE, 'editingteacher');
502         $this->assertIsEnrolled(2, 1, ENROL_USER_ACTIVE, 'student');
503         $this->assertIsNotEnrolled(4, 4);
504         $this->assertHasRoleAssignment(4, 4, 'editingteacher');
505         $this->assertIsEnrolled(3, 3, ENROL_USER_ACTIVE, 'teacher');
508         $DB->delete_records('enrol_database_test_enrols', array('userid' => 'userid1', 'courseid' => 'courseid1', 'roleid' => 'student'));
509         $plugin->set_config('unenrolaction', ENROL_EXT_REMOVED_SUSPENDNOROLES);
510         $plugin->sync_enrolments($trace);
511         $this->assertEquals(4, $DB->count_records('user_enrolments', array()));
512         $this->assertEquals(4, $DB->count_records('enrol', array('enrol' => 'database')));
513         $this->assertEquals(4, $DB->count_records('role_assignments', array('component' => 'enrol_database')));
514         $this->assertIsEnrolled(1, 1, ENROL_USER_SUSPENDED, false);
515         $this->assertIsEnrolled(1, 2, ENROL_USER_ACTIVE, 'editingteacher');
516         $this->assertIsEnrolled(2, 1, ENROL_USER_ACTIVE, 'student');
517         $this->assertIsNotEnrolled(4, 4);
518         $this->assertHasRoleAssignment(4, 4, 'editingteacher');
519         $this->assertIsEnrolled(3, 3, ENROL_USER_ACTIVE, 'teacher');
521         $DB->insert_record('enrol_database_test_enrols', array('userid' => 'userid1', 'courseid' => 'courseid1', 'roleid' => 'student'));
522         $plugin->sync_enrolments($trace);
523         $this->assertEquals(4, $DB->count_records('user_enrolments', array()));
524         $this->assertEquals(4, $DB->count_records('enrol', array('enrol' => 'database')));
525         $this->assertEquals(5, $DB->count_records('role_assignments', array('component' => 'enrol_database')));
526         $this->assertIsEnrolled(1, 1, ENROL_USER_ACTIVE, 'student');
527         $this->assertIsEnrolled(1, 2, ENROL_USER_ACTIVE, 'editingteacher');
528         $this->assertIsEnrolled(2, 1, ENROL_USER_ACTIVE, 'student');
529         $this->assertIsNotEnrolled(4, 4);
530         $this->assertHasRoleAssignment(4, 4, 'editingteacher');
531         $this->assertIsEnrolled(3, 3, ENROL_USER_ACTIVE, 'teacher');
534         $DB->delete_records('enrol_database_test_enrols', array('userid' => 'userid1', 'courseid' => 'courseid1', 'roleid' => 'student'));
535         $plugin->set_config('unenrolaction', ENROL_EXT_REMOVED_UNENROL);
536         $plugin->sync_enrolments($trace);
537         $this->assertEquals(3, $DB->count_records('user_enrolments', array()));
538         $this->assertEquals(4, $DB->count_records('enrol', array('enrol' => 'database')));
539         $this->assertEquals(4, $DB->count_records('role_assignments', array('component' => 'enrol_database')));
540         $this->assertIsNotEnrolled(1, 1);
541         $this->assertIsEnrolled(1, 2, ENROL_USER_ACTIVE, 'editingteacher');
542         $this->assertIsEnrolled(2, 1, ENROL_USER_ACTIVE, 'student');
543         $this->assertIsNotEnrolled(4, 4);
544         $this->assertHasRoleAssignment(4, 4, 'editingteacher');
545         $this->assertIsEnrolled(3, 3, ENROL_USER_ACTIVE, 'teacher');
547         $DB->insert_record('enrol_database_test_enrols', array('userid' => 'userid1', 'courseid' => 'courseid1', 'roleid' => 'student'));
548         $DB->insert_record('enrol_database_test_enrols', array('userid' => 'userid1', 'courseid' => 'courseid1', 'roleid' => 'teacher'));
549         $plugin->sync_enrolments($trace);
550         $this->assertEquals(4, $DB->count_records('user_enrolments', array()));
551         $this->assertEquals(4, $DB->count_records('enrol', array('enrol' => 'database')));
552         $this->assertEquals(6, $DB->count_records('role_assignments', array('component' => 'enrol_database')));
553         $this->assertIsEnrolled(1, 1, ENROL_USER_ACTIVE, 'student');
554         $this->assertIsEnrolled(1, 1, ENROL_USER_ACTIVE, 'teacher');
555         $this->assertIsEnrolled(1, 2, ENROL_USER_ACTIVE, 'editingteacher');
556         $this->assertIsEnrolled(2, 1, ENROL_USER_ACTIVE, 'student');
557         $this->assertIsNotEnrolled(4, 4);
558         $this->assertHasRoleAssignment(4, 4, 'editingteacher');
559         $this->assertIsEnrolled(3, 3, ENROL_USER_ACTIVE, 'teacher');
561         $DB->delete_records('enrol_database_test_enrols', array('userid' => 'userid1', 'courseid' => 'courseid1', 'roleid' => 'teacher'));
562         $plugin->sync_enrolments($trace);
563         $this->assertEquals(4, $DB->count_records('user_enrolments', array()));
564         $this->assertEquals(4, $DB->count_records('enrol', array('enrol' => 'database')));
565         $this->assertEquals(5, $DB->count_records('role_assignments', array('component' => 'enrol_database')));
566         $this->assertIsEnrolled(1, 1, ENROL_USER_ACTIVE, 'student');
567         $this->assertIsEnrolled(1, 2, ENROL_USER_ACTIVE, 'editingteacher');
568         $this->assertIsEnrolled(2, 1, ENROL_USER_ACTIVE, 'student');
569         $this->assertIsNotEnrolled(4, 4);
570         $this->assertHasRoleAssignment(4, 4, 'editingteacher');
571         $this->assertIsEnrolled(3, 3, ENROL_USER_ACTIVE, 'teacher');
574         // Test all other mapping options.
576         $this->reset_enrol_database();
578         $this->assertEquals(0, $DB->count_records('user_enrolments', array()));
579         $this->assertEquals(0, $DB->count_records('enrol', array('enrol' => 'database')));
580         $this->assertEquals(0, $DB->count_records('role_assignments', array('component' => 'enrol_database')));
582         $plugin->set_config('localcoursefield', 'id');
583         $plugin->set_config('localuserfield', 'id');
584         $plugin->set_config('localrolefield', 'id');
586         $DB->insert_record('enrol_database_test_enrols', array('userid' => self::$users[1]->id, 'courseid' => self::$courses[1]->id, 'roleid' => self::$roles['student']->id));
587         $DB->insert_record('enrol_database_test_enrols', array('userid' => self::$users[1]->id, 'courseid' => self::$courses[2]->id, 'roleid' => self::$roles['teacher']->id));
588         $DB->insert_record('enrol_database_test_enrols', array('userid' => self::$users[2]->id, 'courseid' => self::$courses[1]->id, 'roleid' => self::$roles['student']->id));
590         $plugin->sync_enrolments($trace);
591         $this->assertEquals(3, $DB->count_records('user_enrolments', array()));
592         $this->assertEquals(2, $DB->count_records('enrol', array('enrol' => 'database')));
593         $this->assertEquals(3, $DB->count_records('role_assignments', array('component' => 'enrol_database')));
594         $this->assertIsEnrolled(1, 1, ENROL_USER_ACTIVE, 'student');
595         $this->assertIsEnrolled(1, 2, ENROL_USER_ACTIVE, 'teacher');
596         $this->assertIsEnrolled(2, 1, ENROL_USER_ACTIVE, 'student');
599         $this->reset_enrol_database();
600         $plugin->set_config('localcoursefield', 'shortname');
601         $plugin->set_config('localuserfield', 'email');
602         $plugin->set_config('localrolefield', 'id');
604         $DB->insert_record('enrol_database_test_enrols', array('userid' => self::$users[1]->email, 'courseid' => self::$courses[1]->shortname, 'roleid' => self::$roles['student']->id));
605         $DB->insert_record('enrol_database_test_enrols', array('userid' => self::$users[1]->email, 'courseid' => self::$courses[2]->shortname, 'roleid' => self::$roles['teacher']->id));
606         $DB->insert_record('enrol_database_test_enrols', array('userid' => self::$users[2]->email, 'courseid' => self::$courses[1]->shortname, 'roleid' => self::$roles['student']->id));
608         $plugin->sync_enrolments($trace);
609         $this->assertEquals(3, $DB->count_records('user_enrolments', array()));
610         $this->assertEquals(2, $DB->count_records('enrol', array('enrol' => 'database')));
611         $this->assertEquals(3, $DB->count_records('role_assignments', array('component' => 'enrol_database')));
612         $this->assertIsEnrolled(1, 1, ENROL_USER_ACTIVE, 'student');
613         $this->assertIsEnrolled(1, 2, ENROL_USER_ACTIVE, 'teacher');
614         $this->assertIsEnrolled(2, 1, ENROL_USER_ACTIVE, 'student');
617         $this->reset_enrol_database();
618         $plugin->set_config('localcoursefield', 'id');
619         $plugin->set_config('localuserfield', 'username');
620         $plugin->set_config('localrolefield', 'id');
622         $DB->insert_record('enrol_database_test_enrols', array('userid' => self::$users[1]->username, 'courseid' => self::$courses[1]->id, 'roleid' => self::$roles['student']->id));
623         $DB->insert_record('enrol_database_test_enrols', array('userid' => self::$users[1]->username, 'courseid' => self::$courses[2]->id, 'roleid' => self::$roles['teacher']->id));
624         $DB->insert_record('enrol_database_test_enrols', array('userid' => self::$users[2]->username, 'courseid' => self::$courses[1]->id, 'roleid' => self::$roles['student']->id));
626         $plugin->sync_enrolments($trace);
627         $this->assertEquals(3, $DB->count_records('user_enrolments', array()));
628         $this->assertEquals(2, $DB->count_records('enrol', array('enrol' => 'database')));
629         $this->assertEquals(3, $DB->count_records('role_assignments', array('component' => 'enrol_database')));
630         $this->assertIsEnrolled(1, 1, ENROL_USER_ACTIVE, 'student');
631         $this->assertIsEnrolled(1, 2, ENROL_USER_ACTIVE, 'teacher');
632         $this->assertIsEnrolled(2, 1, ENROL_USER_ACTIVE, 'student');
635         // Test sync of one course only.
637         $this->reset_enrol_database();
639         $DB->insert_record('enrol_database_test_enrols', array('userid' => self::$users[1]->username, 'courseid' => self::$courses[1]->id, 'roleid' => self::$roles['student']->id));
640         $DB->insert_record('enrol_database_test_enrols', array('userid' => self::$users[1]->username, 'courseid' => self::$courses[2]->id, 'roleid' => self::$roles['teacher']->id));
641         $DB->insert_record('enrol_database_test_enrols', array('userid' => self::$users[2]->username, 'courseid' => self::$courses[1]->id, 'roleid' => self::$roles['student']->id));
643         $this->assertEquals(0, $DB->count_records('user_enrolments', array()));
644         $this->assertEquals(0, $DB->count_records('enrol', array('enrol' => 'database')));
645         $this->assertEquals(0, $DB->count_records('role_assignments', array('component' => 'enrol_database')));
647         $plugin->sync_enrolments($trace, self::$courses[3]->id);
648         $this->assertEquals(0, $DB->count_records('user_enrolments', array()));
649         $this->assertEquals(1, $DB->count_records('enrol', array('enrol' => 'database')));
650         $this->assertEquals(0, $DB->count_records('role_assignments', array('component' => 'enrol_database')));
652         $plugin->sync_enrolments($trace, self::$courses[1]->id);
653         $this->assertEquals(2, $DB->count_records('user_enrolments', array()));
654         $this->assertEquals(2, $DB->count_records('enrol', array('enrol' => 'database')));
655         $this->assertEquals(2, $DB->count_records('role_assignments', array('component' => 'enrol_database')));
656         $this->assertIsEnrolled(1, 1, ENROL_USER_ACTIVE, 'student');
657         $this->assertIsEnrolled(2, 1, ENROL_USER_ACTIVE, 'student');
659         $plugin->sync_enrolments($trace, self::$courses[2]->id);
660         $this->assertEquals(3, $DB->count_records('user_enrolments', array()));
661         $this->assertEquals(3, $DB->count_records('enrol', array('enrol' => 'database')));
662         $this->assertEquals(3, $DB->count_records('role_assignments', array('component' => 'enrol_database')));
663         $this->assertIsEnrolled(1, 1, ENROL_USER_ACTIVE, 'student');
664         $this->assertIsEnrolled(1, 2, ENROL_USER_ACTIVE, 'teacher');
665         $this->assertIsEnrolled(2, 1, ENROL_USER_ACTIVE, 'student');
668         $plugin->set_config('unenrolaction', ENROL_EXT_REMOVED_UNENROL);
670         $DB->delete_records('enrol_database_test_enrols', array());
672         $plugin->sync_enrolments($trace, self::$courses[1]->id);
673         $this->assertEquals(1, $DB->count_records('user_enrolments', array()));
674         $this->assertEquals(3, $DB->count_records('enrol', array('enrol' => 'database')));
675         $this->assertEquals(1, $DB->count_records('role_assignments', array('component' => 'enrol_database')));
676         $this->assertIsEnrolled(1, 2, ENROL_USER_ACTIVE, 'teacher');
678         $plugin->sync_enrolments($trace, self::$courses[2]->id);
679         $this->assertEquals(0, $DB->count_records('user_enrolments', array()));
680         $this->assertEquals(3, $DB->count_records('enrol', array('enrol' => 'database')));
681         $this->assertEquals(0, $DB->count_records('role_assignments', array('component' => 'enrol_database')));
682     }
684     /**
685      * @depends test_sync_users
686      */
687     public function test_sync_courses() {
688         global $DB;
690         $this->resetAfterTest(true);
691         $this->preventResetByRollback();
692         $this->reset_enrol_database();
694         $plugin = enrol_get_plugin('database');
696         $trace = new null_progress_trace();
698         $plugin->set_config('localcategoryfield', 'id');
699         $coursecat = $this->getDataGenerator()->create_category(array('name' => 'Test category 1', 'idnumber' => 'tcid1'));
700         $defcat = $DB->get_record('course_categories', array('id' => $plugin->get_config('defaultcategory')));
702         $course1 = array('fullname' => 'New course 1', 'shortname' => 'nc1', 'idnumber' => 'ncid1', 'category' => $coursecat->id);
703         $course2 = array('fullname' => 'New course 2', 'shortname' => 'nc2', 'idnumber' => 'ncid2', 'category' => null);
704         // Duplicate records are to be ignored.
705         $course3 = array('fullname' => 'New course 3', 'shortname' => 'xx', 'idnumber' => 'yy2', 'category' => $defcat->id);
706         $course4 = array('fullname' => 'New course 4', 'shortname' => 'xx', 'idnumber' => 'yy3', 'category' => $defcat->id);
707         $course5 = array('fullname' => 'New course 5', 'shortname' => 'xx1', 'idnumber' => 'yy', 'category' => $defcat->id);
708         $course6 = array('fullname' => 'New course 6', 'shortname' => 'xx2', 'idnumber' => 'yy', 'category' => $defcat->id);
710         $DB->insert_record('enrol_database_test_courses', $course1);
711         $DB->insert_record('enrol_database_test_courses', $course2);
712         $DB->insert_record('enrol_database_test_courses', $course3);
713         $DB->insert_record('enrol_database_test_courses', $course4);
714         $DB->insert_record('enrol_database_test_courses', $course5);
715         $DB->insert_record('enrol_database_test_courses', $course6);
717         $this->assertEquals(1+count(self::$courses), $DB->count_records('course'));
719         $plugin->sync_courses($trace);
721         $this->assertEquals(4+1+count(self::$courses), $DB->count_records('course'));
723         $this->assertTrue($DB->record_exists('course', $course1));
724         $course2['category'] = $defcat->id;
725         $this->assertTrue($DB->record_exists('course', $course2));
728         // People should NOT push duplicates there because the results are UNDEFINED! But anyway skip the duplicates.
730         $this->assertEquals(1, $DB->count_records('course', array('idnumber' => 'yy')));
731         $this->assertEquals(1, $DB->count_records('course', array('shortname' => 'xx')));
734         // Test category mapping via idnumber.
736         $plugin->set_config('localcategoryfield', 'idnumber');
737         $course7 = array('fullname' => 'New course 7', 'shortname' => 'nc7', 'idnumber' => 'ncid7', 'category' => 'tcid1');
738         $DB->insert_record('enrol_database_test_courses', $course7);
739         $plugin->sync_courses($trace);
741         $this->assertEquals(1+4+1+count(self::$courses), $DB->count_records('course'));
742         $this->assertTrue($DB->record_exists('course', $course1));
743         $this->assertTrue($DB->record_exists('course', $course2));
744         $course7['category'] = $coursecat->id;
745         $this->assertTrue($DB->record_exists('course', $course7));
748         // Test course template.
750         $template = $this->getDataGenerator()->create_course(array('numsections' => 666, 'shortname' => 'crstempl'));
751         $plugin->set_config('templatecourse', 'crstempl');
753         $course8 = array('fullname' => 'New course 8', 'shortname' => 'nc8', 'idnumber' => 'ncid8', 'category' => null);
754         $DB->insert_record('enrol_database_test_courses', $course8);
755         $plugin->sync_courses($trace);
757         $this->assertEquals(2+1+4+1+count(self::$courses), $DB->count_records('course'));
758         $course8['category'] = $defcat->id;
759         $record = $DB->get_record('course', $course8);
760         $this->assertFalse(empty($record));
761         $courseformatoptions = course_get_format($record)->get_format_options();
762         $this->assertEquals($courseformatoptions['numsections'], 666);
764         // Test invalid category.
766         $course9 = array('fullname' => 'New course 9', 'shortname' => 'nc9', 'idnumber' => 'ncid9', 'category' => 'xxxxxxx');
767         $DB->insert_record('enrol_database_test_courses', $course9);
768         $plugin->sync_courses($trace);
769         $this->assertEquals(2+1+4+1+count(self::$courses), $DB->count_records('course'));
770         $this->assertFalse($DB->record_exists('course', array('idnumber' => 'ncid9')));
773         // Test when categories not specified.
775         $plugin->set_config('newcoursecategory', '');
776         $plugin->sync_courses($trace);
777         $this->assertEquals(1+2+1+4+1+count(self::$courses), $DB->count_records('course'));
778         $this->assertTrue($DB->record_exists('course', array('idnumber' => 'ncid9')));
781         // Final cleanup - remove extra tables, fixtures and caches.
782         $this->cleanup_enrol_database();
783     }