Commit | Line | Data |
---|---|---|
e7aeaa65 PS |
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 | /** | |
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 | */ | |
26 | ||
27 | defined('MOODLE_INTERNAL') || die(); | |
28 | ||
29 | ||
30 | class auth_db_testcase extends advanced_testcase { | |
bfaf4f00 PŠ |
31 | /** @var string Original error log */ |
32 | protected $oldlog; | |
e7aeaa65 PS |
33 | |
34 | protected function init_auth_database() { | |
35 | global $DB, $CFG; | |
36 | require_once("$CFG->dirroot/auth/db/auth.php"); | |
37 | ||
bfaf4f00 PŠ |
38 | // Discard error logs from AdoDB. |
39 | $this->oldlog = ini_get('error_log'); | |
40 | ini_set('error_log', "$CFG->dataroot/testlog.log"); | |
41 | ||
e7aeaa65 PS |
42 | $dbman = $DB->get_manager(); |
43 | ||
44 | set_config('extencoding', 'utf-8', 'auth/db'); | |
45 | ||
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'); | |
50 | ||
51 | if (!empty($CFG->dboptions['dbport'])) { | |
52 | set_config('host', $CFG->dbhost.':'.$CFG->dboptions['dbport'], 'auth/db'); | |
53 | } | |
54 | ||
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; | |
60 | ||
17601a7e | 61 | case 'mariadb_native_moodle_database': |
e7aeaa65 PS |
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; | |
74 | ||
75 | case 'oci_native_moodle_database': | |
76 | set_config('type', 'oci8po', 'auth/db'); | |
77 | set_config('sybasequoting', '1', 'auth/db'); | |
78 | break; | |
79 | ||
80 | case 'pgsql_native_moodle_database': | |
81 | set_config('type', 'postgres7', 'auth/db'); | |
92b00c32 PS |
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'); | |
e7aeaa65 PS |
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) { | |
6576413e EL |
90 | $socket = $CFG->dboptions['dbsocket']; |
91 | if (!empty($CFG->dboptions['dbport'])) { | |
92 | $socket .= ':' . $CFG->dboptions['dbport']; | |
93 | } | |
94 | set_config('host', $socket, 'auth/db'); | |
e7aeaa65 PS |
95 | } else { |
96 | set_config('host', '', 'auth/db'); | |
97 | } | |
98 | } | |
99 | break; | |
100 | ||
101 | case 'sqlsrv_native_moodle_database': | |
102 | set_config('type', 'mssqlnative', 'auth/db'); | |
103 | set_config('sybasequoting', '1', 'auth/db'); | |
104 | break; | |
105 | ||
106 | default: | |
107 | throw new exception('Unknown database driver '.get_class($DB)); | |
108 | } | |
109 | ||
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); | |
92b00c32 | 122 | set_config('table', $CFG->prefix.'auth_db_users', 'auth/db'); |
e7aeaa65 PS |
123 | set_config('fielduser', 'name', 'auth/db'); |
124 | set_config('fieldpass', 'pass', 'auth/db'); | |
125 | ||
126 | // Setu up field mappings. | |
127 | ||
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'); | |
132 | ||
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 | } | |
139 | ||
140 | protected function cleanup_auth_database() { | |
141 | global $DB; | |
142 | ||
143 | $dbman = $DB->get_manager(); | |
144 | $table = new xmldb_table('auth_db_users'); | |
145 | $dbman->drop_table($table); | |
bfaf4f00 PŠ |
146 | |
147 | ini_set('error_log', $this->oldlog); | |
e7aeaa65 PS |
148 | } |
149 | ||
150 | public function test_plugin() { | |
151 | global $DB, $CFG; | |
152 | ||
153 | $this->resetAfterTest(false); | |
154 | ||
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. | |
158 | ||
159 | $this->preventResetByRollback(); | |
160 | ||
161 | $this->init_auth_database(); | |
162 | ||
163 | /** @var auth_plugin_db $auth */ | |
164 | $auth = get_auth_plugin('db'); | |
165 | ||
166 | $authdb = $auth->db_init(); | |
167 | ||
168 | ||
169 | // Test adodb may access the table. | |
170 | ||
171 | $user1 = (object)array('name'=>'u1', 'pass'=>'heslo', 'email'=>'u1@example.com'); | |
172 | $user1->id = $DB->insert_record('auth_db_users', $user1); | |
173 | ||
174 | ||
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(); | |
183 | ||
184 | $authdb->Close(); | |
185 | ||
186 | ||
187 | // Test bulk user account creation. | |
188 | ||
189 | $user2 = (object)array('name'=>'u2', 'pass'=>'heslo', 'email'=>'u2@example.com'); | |
190 | $user2->id = $DB->insert_record('auth_db_users', $user2); | |
191 | ||
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); | |
194 | ||
195 | $this->assertCount(2, $DB->get_records('user')); | |
196 | ||
197 | $trace = new null_progress_trace(); | |
198 | $auth->sync_users($trace, false); | |
199 | ||
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); | |
207 | ||
208 | ||
209 | // Test sync updates. | |
210 | ||
211 | $user2b = clone($user2); | |
212 | $user2b->email = 'u2b@example.com'; | |
213 | $DB->update_record('auth_db_users', $user2b); | |
214 | ||
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); | |
219 | ||
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); | |
224 | ||
225 | set_config('field_updatelocal_email', 'onlogin', 'auth/db'); | |
226 | $auth->config->field_updatelocal_email = 'onlogin'; | |
227 | ||
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); | |
232 | ||
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); | |
237 | ||
238 | ||
239 | // Test sync deletes and suspends. | |
240 | ||
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); | |
245 | ||
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))); | |
250 | ||
251 | set_config('removeuser', AUTH_REMOVEUSER_SUSPEND, 'auth/db'); | |
252 | $auth->config->removeuser = AUTH_REMOVEUSER_SUSPEND; | |
253 | ||
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))); | |
258 | ||
259 | $user2 = (object)array('name'=>'u2', 'pass'=>'heslo', 'email'=>'u2@example.com'); | |
260 | $user2->id = $DB->insert_record('auth_db_users', $user2); | |
261 | ||
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))); | |
266 | ||
267 | $DB->delete_records('auth_db_users', array('id'=>$user2->id)); | |
268 | ||
269 | set_config('removeuser', AUTH_REMOVEUSER_FULLDELETE, 'auth/db'); | |
270 | $auth->config->removeuser = AUTH_REMOVEUSER_FULLDELETE; | |
271 | ||
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))); | |
276 | ||
277 | $user2 = (object)array('name'=>'u2', 'pass'=>'heslo', 'email'=>'u2@example.com'); | |
278 | $user2->id = $DB->insert_record('auth_db_users', $user2); | |
279 | ||
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))); | |
284 | ||
285 | ||
286 | // Test user_login(). | |
287 | ||
288 | $user3 = (object)array('name'=>'u3', 'pass'=>'heslo', 'email'=>'u3@example.com'); | |
289 | $user3->id = $DB->insert_record('auth_db_users', $user3); | |
290 | ||
291 | $this->assertFalse($auth->user_login('u4', 'heslo')); | |
292 | $this->assertTrue($auth->user_login('u1', 'heslo')); | |
293 | ||
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'))); | |
297 | ||
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')); | |
303 | ||
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')); | |
309 | ||
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')); | |
314 | ||
315 | ||
316 | $DB->delete_records('auth_db_users', array('id'=>$user3->id)); | |
317 | ||
318 | set_config('removeuser', AUTH_REMOVEUSER_KEEP, 'auth/db'); | |
319 | $auth->config->removeuser = AUTH_REMOVEUSER_KEEP; | |
320 | $this->assertTrue($auth->user_login('u3', 'heslo')); | |
321 | ||
322 | set_config('removeuser', AUTH_REMOVEUSER_SUSPEND, 'auth/db'); | |
323 | $auth->config->removeuser = AUTH_REMOVEUSER_SUSPEND; | |
324 | $this->assertFalse($auth->user_login('u3', 'heslo')); | |
325 | ||
326 | set_config('removeuser', AUTH_REMOVEUSER_FULLDELETE, 'auth/db'); | |
327 | $auth->config->removeuser = AUTH_REMOVEUSER_FULLDELETE; | |
328 | $this->assertFalse($auth->user_login('u3', 'heslo')); | |
329 | ||
330 | set_config('passtype', 'sh1', 'auth/db'); | |
331 | $auth->config->passtype = 'sha1'; | |
332 | $this->assertFalse($auth->user_login('u3', 'heslo')); | |
333 | ||
334 | ||
335 | // Test login create and update. | |
336 | ||
337 | $user4 = (object)array('name'=>'u4', 'pass'=>'heslo', 'email'=>'u4@example.com'); | |
338 | $user4->id = $DB->insert_record('auth_db_users', $user4); | |
339 | ||
340 | set_config('passtype', 'plaintext', 'auth/db'); | |
341 | $auth->config->passtype = 'plaintext'; | |
342 | ||
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); | |
349 | ||
350 | $user4b = clone($user4); | |
351 | $user4b->email = 'u4b@example.com'; | |
352 | $DB->update_record('auth_db_users', $user4b); | |
353 | ||
354 | set_config('field_updatelocal_email', 'oncreate', 'auth/db'); | |
355 | $auth->config->field_updatelocal_email = 'oncreate'; | |
356 | ||
357 | update_user_record('u4'); | |
358 | $iuser4 = $DB->get_record('user', array('id'=>$iuser4->id)); | |
359 | $this->assertSame($user4->email, $iuser4->email); | |
360 | ||
361 | set_config('field_updatelocal_email', 'onlogin', 'auth/db'); | |
362 | $auth->config->field_updatelocal_email = 'onlogin'; | |
363 | ||
364 | update_user_record('u4'); | |
365 | $iuser4 = $DB->get_record('user', array('id'=>$iuser4->id)); | |
366 | $this->assertSame($user4b->email, $iuser4->email); | |
367 | ||
368 | ||
369 | // Test user_exists() | |
370 | ||
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')); | |
375 | ||
376 | $this->cleanup_auth_database(); | |
377 | } | |
378 | } |