64f34f30de17fdb0be86dea8a8f9a086f3a7df43
[moodle.git] / auth / db / tests / db_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 auth sync tests, this also tests adodb drivers
19  * that are matching our four supported Moodle database drivers.
20  *
21  * @package    auth_db
22  * @category   phpunit
23  * @copyright  2012 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();
30 class auth_db_testcase extends advanced_testcase {
31     /** @var string Original error log */
32     protected $oldlog;
34     protected function init_auth_database() {
35         global $DB, $CFG;
36         require_once("$CFG->dirroot/auth/db/auth.php");
38         // Discard error logs from AdoDB.
39         $this->oldlog = ini_get('error_log');
40         ini_set('error_log', "$CFG->dataroot/testlog.log");
42         $dbman = $DB->get_manager();
44         set_config('extencoding', 'utf-8', 'auth/db');
46         set_config('host', $CFG->dbhost, 'auth/db');
47         set_config('user', $CFG->dbuser, 'auth/db');
48         set_config('pass', $CFG->dbpass, 'auth/db');
49         set_config('name', $CFG->dbname, 'auth/db');
51         if (!empty($CFG->dboptions['dbport'])) {
52             set_config('host', $CFG->dbhost.':'.$CFG->dboptions['dbport'], 'auth/db');
53         }
55         switch (get_class($DB)) {
56             case 'mssql_native_moodle_database':
57                 set_config('type', 'mssql_n', 'auth/db');
58                 set_config('sybasequoting', '1', 'auth/db');
59                 break;
61             case 'mariadb_native_moodle_database':
62             case 'mysqli_native_moodle_database':
63                 set_config('type', 'mysqli', 'auth/db');
64                 set_config('setupsql', "SET NAMES 'UTF-8'", 'auth/db');
65                 set_config('sybasequoting', '0', 'auth/db');
66                 if (!empty($CFG->dboptions['dbsocket'])) {
67                     $dbsocket = $CFG->dboptions['dbsocket'];
68                     if ((strpos($dbsocket, '/') === false and strpos($dbsocket, '\\') === false)) {
69                         $dbsocket = ini_get('mysqli.default_socket');
70                     }
71                     set_config('type', 'mysqli://'.rawurlencode($CFG->dbuser).':'.rawurlencode($CFG->dbpass).'@'.rawurlencode($CFG->dbhost).'/'.rawurlencode($CFG->dbname).'?socket='.rawurlencode($dbsocket), 'auth/db');
72                 }
73                 break;
75             case 'oci_native_moodle_database':
76                 set_config('type', 'oci8po', 'auth/db');
77                 set_config('sybasequoting', '1', 'auth/db');
78                 break;
80             case 'pgsql_native_moodle_database':
81                 set_config('type', 'postgres7', 'auth/db');
82                 $setupsql = "SET NAMES 'UTF-8'";
83                 if (!empty($CFG->dboptions['dbschema'])) {
84                     $setupsql .= "; SET search_path = '".$CFG->dboptions['dbschema']."'";
85                 }
86                 set_config('setupsql', $setupsql, 'auth/db');
87                 set_config('sybasequoting', '0', 'auth/db');
88                 if (!empty($CFG->dboptions['dbsocket']) and ($CFG->dbhost === 'localhost' or $CFG->dbhost === '127.0.0.1')) {
89                     if (strpos($CFG->dboptions['dbsocket'], '/') !== false) {
90                         $socket = $CFG->dboptions['dbsocket'];
91                         if (!empty($CFG->dboptions['dbport'])) {
92                             $socket .= ':' . $CFG->dboptions['dbport'];
93                         }
94                         set_config('host', $socket, 'auth/db');
95                     } else {
96                         set_config('host', '', 'auth/db');
97                     }
98                 }
99                 break;
101             case 'sqlsrv_native_moodle_database':
102                 set_config('type', 'mssqlnative', 'auth/db');
103                 set_config('sybasequoting', '1', 'auth/db');
104                 break;
106             default:
107                 throw new exception('Unknown database driver '.get_class($DB));
108         }
110         $table = new xmldb_table('auth_db_users');
111         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
112         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null);
113         $table->add_field('pass', XMLDB_TYPE_CHAR, '255', null, null, null);
114         $table->add_field('email', XMLDB_TYPE_CHAR, '255', null, null, null);
115         $table->add_field('firstname', XMLDB_TYPE_CHAR, '255', null, null, null);
116         $table->add_field('lastname', XMLDB_TYPE_CHAR, '255', null, null, null);
117         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
118         if ($dbman->table_exists($table)) {
119             $dbman->drop_table($table);
120         }
121         $dbman->create_table($table);
122         set_config('table', $CFG->prefix.'auth_db_users', 'auth/db');
123         set_config('fielduser', 'name', 'auth/db');
124         set_config('fieldpass', 'pass', 'auth/db');
126         // Setu up field mappings.
128         set_config('field_map_email', 'email', 'auth/db');
129         set_config('field_updatelocal_email', 'oncreate', 'auth/db');
130         set_config('field_updateremote_email', '0', 'auth/db');
131         set_config('field_lock_email', 'unlocked', 'auth/db');
133         // Init the rest of settings.
134         set_config('passtype', 'plaintext', 'auth/db');
135         set_config('changepasswordurl', '', 'auth/db');
136         set_config('debugauthdb', 0, 'auth/db');
137         set_config('removeuser', AUTH_REMOVEUSER_KEEP, 'auth/db');
138     }
140     protected function cleanup_auth_database() {
141         global $DB;
143         $dbman = $DB->get_manager();
144         $table = new xmldb_table('auth_db_users');
145         $dbman->drop_table($table);
147         ini_set('error_log', $this->oldlog);
148     }
150     public function test_plugin() {
151         global $DB, $CFG;
153         $this->resetAfterTest(false);
155         // NOTE: It is strongly discouraged to create new tables in advanced_testcase classes,
156         //       but there is no other simple way to test ext database enrol sync, so let's
157         //       disable transactions are try to cleanup after the tests.
159         $this->preventResetByRollback();
161         $this->init_auth_database();
163         /** @var auth_plugin_db $auth */
164         $auth = get_auth_plugin('db');
166         $authdb = $auth->db_init();
169         // Test adodb may access the table.
171         $user1 = (object)array('name'=>'u1', 'pass'=>'heslo', 'email'=>'u1@example.com');
172         $user1->id = $DB->insert_record('auth_db_users', $user1);
175         $sql = "SELECT * FROM {$auth->config->table}";
176         $rs = $authdb->Execute($sql);
177         $this->assertInstanceOf('ADORecordSet', $rs);
178         $this->assertFalse($rs->EOF);
179         $fields = $rs->FetchRow();
180         $this->assertTrue(is_array($fields));
181         $this->assertTrue($rs->EOF);
182         $rs->Close();
184         $authdb->Close();
187         // Test bulk user account creation.
189         $user2 = (object)array('name'=>'u2', 'pass'=>'heslo', 'email'=>'u2@example.com');
190         $user2->id = $DB->insert_record('auth_db_users', $user2);
192         $user3 = (object)array('name'=>'admin', 'pass'=>'heslo', 'email'=>'admin@example.com'); // Should be skipped.
193         $user3->id = $DB->insert_record('auth_db_users', $user3);
195         $this->assertCount(2, $DB->get_records('user'));
197         $trace = new null_progress_trace();
198         $auth->sync_users($trace, false);
200         $this->assertEquals(4, $DB->count_records('user'));
201         $u1 = $DB->get_record('user', array('username'=>$user1->name, 'auth'=>'db'));
202         $this->assertSame($user1->email, $u1->email);
203         $u2 = $DB->get_record('user', array('username'=>$user2->name, 'auth'=>'db'));
204         $this->assertSame($user2->email, $u2->email);
205         $admin = $DB->get_record('user', array('username'=>'admin', 'auth'=>'manual'));
206         $this->assertNotEmpty($admin);
209         // Test sync updates.
211         $user2b = clone($user2);
212         $user2b->email = 'u2b@example.com';
213         $DB->update_record('auth_db_users', $user2b);
215         $auth->sync_users($trace, false);
216         $this->assertEquals(4, $DB->count_records('user'));
217         $u2 = $DB->get_record('user', array('username'=>$user2->name));
218         $this->assertSame($user2->email, $u2->email);
220         $auth->sync_users($trace, true);
221         $this->assertEquals(4, $DB->count_records('user'));
222         $u2 = $DB->get_record('user', array('username'=>$user2->name));
223         $this->assertSame($user2->email, $u2->email);
225         set_config('field_updatelocal_email', 'onlogin', 'auth/db');
226         $auth->config->field_updatelocal_email = 'onlogin';
228         $auth->sync_users($trace, false);
229         $this->assertEquals(4, $DB->count_records('user'));
230         $u2 = $DB->get_record('user', array('username'=>$user2->name));
231         $this->assertSame($user2->email, $u2->email);
233         $auth->sync_users($trace, true);
234         $this->assertEquals(4, $DB->count_records('user'));
235         $u2 = $DB->get_record('user', array('username'=>$user2->name));
236         $this->assertSame($user2b->email, $u2->email);
239         // Test sync deletes and suspends.
241         $DB->delete_records('auth_db_users', array('id'=>$user2->id));
242         $this->assertCount(2, $DB->get_records('auth_db_users'));
243         unset($user2);
244         unset($user2b);
246         $auth->sync_users($trace, false);
247         $this->assertEquals(4, $DB->count_records('user'));
248         $this->assertEquals(0, $DB->count_records('user', array('deleted'=>1)));
249         $this->assertEquals(0, $DB->count_records('user', array('suspended'=>1)));
251         set_config('removeuser', AUTH_REMOVEUSER_SUSPEND, 'auth/db');
252         $auth->config->removeuser = AUTH_REMOVEUSER_SUSPEND;
254         $auth->sync_users($trace, false);
255         $this->assertEquals(4, $DB->count_records('user'));
256         $this->assertEquals(0, $DB->count_records('user', array('deleted'=>1)));
257         $this->assertEquals(1, $DB->count_records('user', array('suspended'=>1)));
259         $user2 = (object)array('name'=>'u2', 'pass'=>'heslo', 'email'=>'u2@example.com');
260         $user2->id = $DB->insert_record('auth_db_users', $user2);
262         $auth->sync_users($trace, false);
263         $this->assertEquals(4, $DB->count_records('user'));
264         $this->assertEquals(0, $DB->count_records('user', array('deleted'=>1)));
265         $this->assertEquals(0, $DB->count_records('user', array('suspended'=>1)));
267         $DB->delete_records('auth_db_users', array('id'=>$user2->id));
269         set_config('removeuser', AUTH_REMOVEUSER_FULLDELETE, 'auth/db');
270         $auth->config->removeuser = AUTH_REMOVEUSER_FULLDELETE;
272         $auth->sync_users($trace, false);
273         $this->assertEquals(4, $DB->count_records('user'));
274         $this->assertEquals(1, $DB->count_records('user', array('deleted'=>1)));
275         $this->assertEquals(0, $DB->count_records('user', array('suspended'=>1)));
277         $user2 = (object)array('name'=>'u2', 'pass'=>'heslo', 'email'=>'u2@example.com');
278         $user2->id = $DB->insert_record('auth_db_users', $user2);
280         $auth->sync_users($trace, false);
281         $this->assertEquals(5, $DB->count_records('user'));
282         $this->assertEquals(1, $DB->count_records('user', array('deleted'=>1)));
283         $this->assertEquals(0, $DB->count_records('user', array('suspended'=>1)));
286         // Test user_login().
288         $user3 = (object)array('name'=>'u3', 'pass'=>'heslo', 'email'=>'u3@example.com');
289         $user3->id = $DB->insert_record('auth_db_users', $user3);
291         $this->assertFalse($auth->user_login('u4', 'heslo'));
292         $this->assertTrue($auth->user_login('u1', 'heslo'));
294         $this->assertFalse($DB->record_exists('user', array('username'=>'u3', 'auth'=>'db')));
295         $this->assertTrue($auth->user_login('u3', 'heslo'));
296         $this->assertFalse($DB->record_exists('user', array('username'=>'u3', 'auth'=>'db')));
298         set_config('passtype', 'md5', 'auth/db');
299         $auth->config->passtype = 'md5';
300         $user3->pass = md5('heslo');
301         $DB->update_record('auth_db_users', $user3);
302         $this->assertTrue($auth->user_login('u3', 'heslo'));
304         set_config('passtype', 'sh1', 'auth/db');
305         $auth->config->passtype = 'sha1';
306         $user3->pass = sha1('heslo');
307         $DB->update_record('auth_db_users', $user3);
308         $this->assertTrue($auth->user_login('u3', 'heslo'));
310         set_config('passtype', 'internal', 'auth/db');
311         $auth->config->passtype = 'internal';
312         create_user_record('u3', 'heslo', 'db');
313         $this->assertTrue($auth->user_login('u3', 'heslo'));
316         $DB->delete_records('auth_db_users', array('id'=>$user3->id));
318         set_config('removeuser', AUTH_REMOVEUSER_KEEP, 'auth/db');
319         $auth->config->removeuser = AUTH_REMOVEUSER_KEEP;
320         $this->assertTrue($auth->user_login('u3', 'heslo'));
322         set_config('removeuser', AUTH_REMOVEUSER_SUSPEND, 'auth/db');
323         $auth->config->removeuser = AUTH_REMOVEUSER_SUSPEND;
324         $this->assertFalse($auth->user_login('u3', 'heslo'));
326         set_config('removeuser', AUTH_REMOVEUSER_FULLDELETE, 'auth/db');
327         $auth->config->removeuser = AUTH_REMOVEUSER_FULLDELETE;
328         $this->assertFalse($auth->user_login('u3', 'heslo'));
330         set_config('passtype', 'sh1', 'auth/db');
331         $auth->config->passtype = 'sha1';
332         $this->assertFalse($auth->user_login('u3', 'heslo'));
335         // Test login create and update.
337         $user4 = (object)array('name'=>'u4', 'pass'=>'heslo', 'email'=>'u4@example.com');
338         $user4->id = $DB->insert_record('auth_db_users', $user4);
340         set_config('passtype', 'plaintext', 'auth/db');
341         $auth->config->passtype = 'plaintext';
343         $iuser4 = create_user_record('u4', 'heslo', 'db');
344         $this->assertNotEmpty($iuser4);
345         $this->assertSame($user4->name, $iuser4->username);
346         $this->assertSame($user4->email, $iuser4->email);
347         $this->assertSame('db', $iuser4->auth);
348         $this->assertSame($CFG->mnet_localhost_id, $iuser4->mnethostid);
350         $user4b = clone($user4);
351         $user4b->email = 'u4b@example.com';
352         $DB->update_record('auth_db_users', $user4b);
354         set_config('field_updatelocal_email', 'oncreate', 'auth/db');
355         $auth->config->field_updatelocal_email = 'oncreate';
357         update_user_record('u4');
358         $iuser4 = $DB->get_record('user', array('id'=>$iuser4->id));
359         $this->assertSame($user4->email, $iuser4->email);
361         set_config('field_updatelocal_email', 'onlogin', 'auth/db');
362         $auth->config->field_updatelocal_email = 'onlogin';
364         update_user_record('u4');
365         $iuser4 = $DB->get_record('user', array('id'=>$iuser4->id));
366         $this->assertSame($user4b->email, $iuser4->email);
369         // Test user_exists()
371         $this->assertTrue($auth->user_exists('u1'));
372         $this->assertTrue($auth->user_exists('admin'));
373         $this->assertFalse($auth->user_exists('u3'));
374         $this->assertTrue($auth->user_exists('u4'));
376         $this->cleanup_auth_database();
377     }