MDL-81616 upgrade: add the 4.4.0 separation line to all upgrade scripts
[moodle.git] / lib / tests / session_manager_test.php
blob9f025c7774d13cb553b9d5ab905d134e4f2f1d55
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.
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 namespace core;
19 /**
20 * Unit tests for session manager class.
22 * @package core
23 * @category test
24 * @copyright 2013 Petr Skoda {@link http://skodak.org}
25 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
27 class session_manager_test extends \advanced_testcase {
28 public function test_start() {
29 $this->resetAfterTest();
30 // Session must be started only once...
31 \core\session\manager::start();
32 $this->assertDebuggingCalled('Session was already started!', DEBUG_DEVELOPER);
35 public function test_init_empty_session() {
36 global $SESSION, $USER;
37 $this->resetAfterTest();
39 $user = $this->getDataGenerator()->create_user();
41 $SESSION->test = true;
42 $this->assertTrue($GLOBALS['SESSION']->test);
43 $this->assertTrue($_SESSION['SESSION']->test);
45 \core\session\manager::set_user($user);
46 $this->assertSame($user, $USER);
47 $this->assertSame($user, $GLOBALS['USER']);
48 $this->assertSame($user, $_SESSION['USER']);
50 \core\session\manager::init_empty_session();
52 $this->assertInstanceOf('stdClass', $SESSION);
53 $this->assertEmpty((array)$SESSION);
54 $this->assertSame($GLOBALS['SESSION'], $_SESSION['SESSION']);
55 $this->assertSame($GLOBALS['SESSION'], $SESSION);
57 $this->assertInstanceOf('stdClass', $USER);
58 $this->assertEqualsCanonicalizing(array('id' => 0, 'mnethostid' => 1), (array)$USER);
59 $this->assertSame($GLOBALS['USER'], $_SESSION['USER']);
60 $this->assertSame($GLOBALS['USER'], $USER);
62 // Now test how references work.
64 $GLOBALS['SESSION'] = new \stdClass();
65 $GLOBALS['SESSION']->test = true;
66 $this->assertSame($GLOBALS['SESSION'], $_SESSION['SESSION']);
67 $this->assertSame($GLOBALS['SESSION'], $SESSION);
69 $SESSION = new \stdClass();
70 $SESSION->test2 = true;
71 $this->assertSame($GLOBALS['SESSION'], $_SESSION['SESSION']);
72 $this->assertSame($GLOBALS['SESSION'], $SESSION);
74 $_SESSION['SESSION'] = new \stdClass();
75 $_SESSION['SESSION']->test3 = true;
76 $this->assertSame($GLOBALS['SESSION'], $_SESSION['SESSION']);
77 $this->assertSame($GLOBALS['SESSION'], $SESSION);
79 $GLOBALS['USER'] = new \stdClass();
80 $GLOBALS['USER']->test = true;
81 $this->assertSame($GLOBALS['USER'], $_SESSION['USER']);
82 $this->assertSame($GLOBALS['USER'], $USER);
84 $USER = new \stdClass();
85 $USER->test2 = true;
86 $this->assertSame($GLOBALS['USER'], $_SESSION['USER']);
87 $this->assertSame($GLOBALS['USER'], $USER);
89 $_SESSION['USER'] = new \stdClass();
90 $_SESSION['USER']->test3 = true;
91 $this->assertSame($GLOBALS['USER'], $_SESSION['USER']);
92 $this->assertSame($GLOBALS['USER'], $USER);
95 public function test_set_user() {
96 global $USER;
97 $this->resetAfterTest();
99 $this->assertEquals(0, $USER->id);
101 $user = $this->getDataGenerator()->create_user();
102 $this->assertObjectHasProperty('description', $user);
103 $this->assertObjectHasProperty('password', $user);
105 \core\session\manager::set_user($user);
107 $this->assertEquals($user->id, $USER->id);
108 $this->assertObjectNotHasProperty('description', $user);
109 $this->assertObjectNotHasProperty('password', $user);
110 $this->assertObjectHasProperty('sesskey', $user);
111 $this->assertSame($user, $GLOBALS['USER']);
112 $this->assertSame($GLOBALS['USER'], $_SESSION['USER']);
113 $this->assertSame($GLOBALS['USER'], $USER);
116 public function test_login_user() {
117 global $USER;
118 $this->resetAfterTest();
120 $this->assertEquals(0, $USER->id);
122 $user = $this->getDataGenerator()->create_user();
124 @\core\session\manager::login_user($user); // Ignore header error messages.
125 $this->assertEquals($user->id, $USER->id);
127 $this->assertObjectNotHasProperty('description', $user);
128 $this->assertObjectNotHasProperty('password', $user);
129 $this->assertSame($user, $GLOBALS['USER']);
130 $this->assertSame($GLOBALS['USER'], $_SESSION['USER']);
131 $this->assertSame($GLOBALS['USER'], $USER);
134 public function test_terminate_current() {
135 global $USER, $SESSION;
136 $this->resetAfterTest();
138 $this->setAdminUser();
139 \core\session\manager::terminate_current();
140 $this->assertEquals(0, $USER->id);
142 $this->assertInstanceOf('stdClass', $SESSION);
143 $this->assertEmpty((array)$SESSION);
144 $this->assertSame($GLOBALS['SESSION'], $_SESSION['SESSION']);
145 $this->assertSame($GLOBALS['SESSION'], $SESSION);
147 $this->assertInstanceOf('stdClass', $USER);
148 $this->assertEqualsCanonicalizing(array('id' => 0, 'mnethostid' => 1), (array)$USER);
149 $this->assertSame($GLOBALS['USER'], $_SESSION['USER']);
150 $this->assertSame($GLOBALS['USER'], $USER);
153 public function test_write_close() {
154 global $USER;
155 $this->resetAfterTest();
157 // Just make sure no errors and $USER->id is kept
158 $this->setAdminUser();
159 $userid = $USER->id;
160 \core\session\manager::write_close();
161 $this->assertSame($userid, $USER->id);
163 $this->assertSame($GLOBALS['USER'], $_SESSION['USER']);
164 $this->assertSame($GLOBALS['USER'], $USER);
167 public function test_session_exists() {
168 global $CFG, $DB;
169 $this->resetAfterTest();
171 $this->assertFalse(\core\session\manager::session_exists('abc'));
173 $user = $this->getDataGenerator()->create_user();
174 $guest = guest_user();
176 // The file handler is used by default, so let's fake the data somehow.
177 $sid = md5('hokus');
178 mkdir("$CFG->dataroot/sessions/", $CFG->directorypermissions, true);
179 touch("$CFG->dataroot/sessions/sess_$sid");
181 $this->assertFalse(\core\session\manager::session_exists($sid));
183 $record = new \stdClass();
184 $record->userid = 0;
185 $record->sid = $sid;
186 $record->timecreated = time();
187 $record->timemodified = $record->timecreated;
188 $record->id = $DB->insert_record('sessions', $record);
190 $this->assertTrue(\core\session\manager::session_exists($sid));
192 $record->timecreated = time() - $CFG->sessiontimeout - 100;
193 $record->timemodified = $record->timecreated + 10;
194 $DB->update_record('sessions', $record);
196 $this->assertTrue(\core\session\manager::session_exists($sid));
198 $record->userid = $guest->id;
199 $DB->update_record('sessions', $record);
201 $this->assertTrue(\core\session\manager::session_exists($sid));
203 $record->userid = $user->id;
204 $DB->update_record('sessions', $record);
206 $this->assertFalse(\core\session\manager::session_exists($sid));
208 $CFG->sessiontimeout = $CFG->sessiontimeout + 3000;
210 $this->assertTrue(\core\session\manager::session_exists($sid));
213 public function test_touch_session() {
214 global $DB;
215 $this->resetAfterTest();
217 $sid = md5('hokus');
218 $record = new \stdClass();
219 $record->state = 0;
220 $record->sid = $sid;
221 $record->sessdata = null;
222 $record->userid = 2;
223 $record->timecreated = time() - 60*60;
224 $record->timemodified = time() - 30;
225 $record->firstip = $record->lastip = '10.0.0.1';
226 $record->id = $DB->insert_record('sessions', $record);
228 $now = time();
229 \core\session\manager::touch_session($sid);
230 $updated = $DB->get_field('sessions', 'timemodified', array('id'=>$record->id));
232 $this->assertGreaterThanOrEqual($now, $updated);
233 $this->assertLessThanOrEqual(time(), $updated);
236 public function test_kill_session() {
237 global $DB, $USER;
238 $this->resetAfterTest();
240 $this->setAdminUser();
241 $userid = $USER->id;
243 $sid = md5('hokus');
244 $record = new \stdClass();
245 $record->state = 0;
246 $record->sid = $sid;
247 $record->sessdata = null;
248 $record->userid = $userid;
249 $record->timecreated = time() - 60*60;
250 $record->timemodified = time() - 30;
251 $record->firstip = $record->lastip = '10.0.0.1';
252 $DB->insert_record('sessions', $record);
254 $record->userid = 0;
255 $record->sid = md5('pokus');
256 $DB->insert_record('sessions', $record);
258 $this->assertEquals(2, $DB->count_records('sessions'));
260 \core\session\manager::kill_session($sid);
262 $this->assertEquals(1, $DB->count_records('sessions'));
263 $this->assertFalse($DB->record_exists('sessions', array('sid'=>$sid)));
265 $this->assertSame($userid, $USER->id);
268 public function test_kill_user_sessions() {
269 global $DB, $USER;
270 $this->resetAfterTest();
272 $this->setAdminUser();
273 $userid = $USER->id;
275 $sid = md5('hokus');
276 $record = new \stdClass();
277 $record->state = 0;
278 $record->sid = $sid;
279 $record->sessdata = null;
280 $record->userid = $userid;
281 $record->timecreated = time() - 60*60;
282 $record->timemodified = time() - 30;
283 $record->firstip = $record->lastip = '10.0.0.1';
284 $DB->insert_record('sessions', $record);
286 $record->sid = md5('hokus2');
287 $DB->insert_record('sessions', $record);
289 $record->userid = 0;
290 $record->sid = md5('pokus');
291 $DB->insert_record('sessions', $record);
293 $this->assertEquals(3, $DB->count_records('sessions'));
295 \core\session\manager::kill_user_sessions($userid);
297 $this->assertEquals(1, $DB->count_records('sessions'));
298 $this->assertFalse($DB->record_exists('sessions', array('userid' => $userid)));
300 $record->userid = $userid;
301 $record->sid = md5('pokus3');
302 $DB->insert_record('sessions', $record);
304 $record->userid = $userid;
305 $record->sid = md5('pokus4');
306 $DB->insert_record('sessions', $record);
308 $record->userid = $userid;
309 $record->sid = md5('pokus5');
310 $DB->insert_record('sessions', $record);
312 $this->assertEquals(3, $DB->count_records('sessions', array('userid' => $userid)));
314 \core\session\manager::kill_user_sessions($userid, md5('pokus5'));
316 $this->assertEquals(1, $DB->count_records('sessions', array('userid' => $userid)));
317 $this->assertEquals(1, $DB->count_records('sessions', array('userid' => $userid, 'sid' => md5('pokus5'))));
320 public function test_apply_concurrent_login_limit() {
321 global $DB;
322 $this->resetAfterTest();
324 $user1 = $this->getDataGenerator()->create_user();
325 $user2 = $this->getDataGenerator()->create_user();
326 $guest = guest_user();
328 $record = new \stdClass();
329 $record->state = 0;
330 $record->sessdata = null;
331 $record->userid = $user1->id;
332 $record->timemodified = time();
333 $record->firstip = $record->lastip = '10.0.0.1';
335 $record->sid = md5('hokus1');
336 $record->timecreated = 20;
337 $DB->insert_record('sessions', $record);
338 $record->sid = md5('hokus2');
339 $record->timecreated = 10;
340 $DB->insert_record('sessions', $record);
341 $record->sid = md5('hokus3');
342 $record->timecreated = 30;
343 $DB->insert_record('sessions', $record);
345 $record->userid = $user2->id;
346 $record->sid = md5('pokus1');
347 $record->timecreated = 20;
348 $DB->insert_record('sessions', $record);
349 $record->sid = md5('pokus2');
350 $record->timecreated = 10;
351 $DB->insert_record('sessions', $record);
352 $record->sid = md5('pokus3');
353 $record->timecreated = 30;
354 $DB->insert_record('sessions', $record);
356 $record->timecreated = 10;
357 $record->userid = $guest->id;
358 $record->sid = md5('g1');
359 $DB->insert_record('sessions', $record);
360 $record->sid = md5('g2');
361 $DB->insert_record('sessions', $record);
362 $record->sid = md5('g3');
363 $DB->insert_record('sessions', $record);
365 $record->userid = 0;
366 $record->sid = md5('nl1');
367 $DB->insert_record('sessions', $record);
368 $record->sid = md5('nl2');
369 $DB->insert_record('sessions', $record);
370 $record->sid = md5('nl3');
371 $DB->insert_record('sessions', $record);
373 set_config('limitconcurrentlogins', 0);
374 $this->assertCount(12, $DB->get_records('sessions'));
376 \core\session\manager::apply_concurrent_login_limit($user1->id);
377 \core\session\manager::apply_concurrent_login_limit($user2->id);
378 \core\session\manager::apply_concurrent_login_limit($guest->id);
379 \core\session\manager::apply_concurrent_login_limit(0);
380 $this->assertCount(12, $DB->get_records('sessions'));
382 set_config('limitconcurrentlogins', -1);
384 \core\session\manager::apply_concurrent_login_limit($user1->id);
385 \core\session\manager::apply_concurrent_login_limit($user2->id);
386 \core\session\manager::apply_concurrent_login_limit($guest->id);
387 \core\session\manager::apply_concurrent_login_limit(0);
388 $this->assertCount(12, $DB->get_records('sessions'));
390 set_config('limitconcurrentlogins', 2);
392 \core\session\manager::apply_concurrent_login_limit($user1->id);
393 $this->assertCount(11, $DB->get_records('sessions'));
394 $this->assertTrue($DB->record_exists('sessions', array('userid' => $user1->id, 'timecreated' => 20)));
395 $this->assertTrue($DB->record_exists('sessions', array('userid' => $user1->id, 'timecreated' => 30)));
396 $this->assertFalse($DB->record_exists('sessions', array('userid' => $user1->id, 'timecreated' => 10)));
398 $this->assertTrue($DB->record_exists('sessions', array('userid' => $user2->id, 'timecreated' => 20)));
399 $this->assertTrue($DB->record_exists('sessions', array('userid' => $user2->id, 'timecreated' => 30)));
400 $this->assertTrue($DB->record_exists('sessions', array('userid' => $user2->id, 'timecreated' => 10)));
401 set_config('limitconcurrentlogins', 2);
402 \core\session\manager::apply_concurrent_login_limit($user2->id, md5('pokus2'));
403 $this->assertCount(10, $DB->get_records('sessions'));
404 $this->assertFalse($DB->record_exists('sessions', array('userid' => $user2->id, 'timecreated' => 20)));
405 $this->assertTrue($DB->record_exists('sessions', array('userid' => $user2->id, 'timecreated' => 30)));
406 $this->assertTrue($DB->record_exists('sessions', array('userid' => $user2->id, 'timecreated' => 10)));
408 \core\session\manager::apply_concurrent_login_limit($guest->id);
409 \core\session\manager::apply_concurrent_login_limit(0);
410 $this->assertCount(10, $DB->get_records('sessions'));
412 set_config('limitconcurrentlogins', 1);
414 \core\session\manager::apply_concurrent_login_limit($user1->id, md5('grrr'));
415 $this->assertCount(9, $DB->get_records('sessions'));
416 $this->assertFalse($DB->record_exists('sessions', array('userid' => $user1->id, 'timecreated' => 20)));
417 $this->assertTrue($DB->record_exists('sessions', array('userid' => $user1->id, 'timecreated' => 30)));
418 $this->assertFalse($DB->record_exists('sessions', array('userid' => $user1->id, 'timecreated' => 10)));
420 \core\session\manager::apply_concurrent_login_limit($user1->id);
421 $this->assertCount(9, $DB->get_records('sessions'));
422 $this->assertFalse($DB->record_exists('sessions', array('userid' => $user1->id, 'timecreated' => 20)));
423 $this->assertTrue($DB->record_exists('sessions', array('userid' => $user1->id, 'timecreated' => 30)));
424 $this->assertFalse($DB->record_exists('sessions', array('userid' => $user1->id, 'timecreated' => 10)));
426 \core\session\manager::apply_concurrent_login_limit($user2->id, md5('pokus2'));
427 $this->assertCount(8, $DB->get_records('sessions'));
428 $this->assertFalse($DB->record_exists('sessions', array('userid' => $user2->id, 'timecreated' => 20)));
429 $this->assertFalse($DB->record_exists('sessions', array('userid' => $user2->id, 'timecreated' => 30)));
430 $this->assertTrue($DB->record_exists('sessions', array('userid' => $user2->id, 'timecreated' => 10)));
432 \core\session\manager::apply_concurrent_login_limit($user2->id);
433 $this->assertCount(8, $DB->get_records('sessions'));
434 $this->assertFalse($DB->record_exists('sessions', array('userid' => $user2->id, 'timecreated' => 20)));
435 $this->assertFalse($DB->record_exists('sessions', array('userid' => $user2->id, 'timecreated' => 30)));
436 $this->assertTrue($DB->record_exists('sessions', array('userid' => $user2->id, 'timecreated' => 10)));
438 \core\session\manager::apply_concurrent_login_limit($guest->id);
439 \core\session\manager::apply_concurrent_login_limit(0);
440 $this->assertCount(8, $DB->get_records('sessions'));
443 public function test_kill_all_sessions() {
444 global $DB, $USER;
445 $this->resetAfterTest();
447 $this->setAdminUser();
448 $userid = $USER->id;
450 $sid = md5('hokus');
451 $record = new \stdClass();
452 $record->state = 0;
453 $record->sid = $sid;
454 $record->sessdata = null;
455 $record->userid = $userid;
456 $record->timecreated = time() - 60*60;
457 $record->timemodified = time() - 30;
458 $record->firstip = $record->lastip = '10.0.0.1';
459 $DB->insert_record('sessions', $record);
461 $record->sid = md5('hokus2');
462 $DB->insert_record('sessions', $record);
464 $record->userid = 0;
465 $record->sid = md5('pokus');
466 $DB->insert_record('sessions', $record);
468 $this->assertEquals(3, $DB->count_records('sessions'));
470 \core\session\manager::kill_all_sessions();
472 $this->assertEquals(0, $DB->count_records('sessions'));
473 $this->assertSame(0, $USER->id);
476 public function test_gc() {
477 global $CFG, $DB, $USER;
478 $this->resetAfterTest();
480 $this->setAdminUser();
481 $adminid = $USER->id;
482 $this->setGuestUser();
483 $guestid = $USER->id;
484 $this->setUser(0);
486 $CFG->sessiontimeout = 60*10;
488 $record = new \stdClass();
489 $record->state = 0;
490 $record->sid = md5('hokus1');
491 $record->sessdata = null;
492 $record->userid = $adminid;
493 $record->timecreated = time() - 60*60;
494 $record->timemodified = time() - 30;
495 $record->firstip = $record->lastip = '10.0.0.1';
496 $r1 = $DB->insert_record('sessions', $record);
498 $record->sid = md5('hokus2');
499 $record->userid = $adminid;
500 $record->timecreated = time() - 60*60;
501 $record->timemodified = time() - 60*20;
502 $r2 = $DB->insert_record('sessions', $record);
504 $record->sid = md5('hokus3');
505 $record->userid = $guestid;
506 $record->timecreated = time() - 60*60*60;
507 $record->timemodified = time() - 60*20;
508 $r3 = $DB->insert_record('sessions', $record);
510 $record->sid = md5('hokus4');
511 $record->userid = $guestid;
512 $record->timecreated = time() - 60*60*60;
513 $record->timemodified = time() - 60*10*5 - 60;
514 $r4 = $DB->insert_record('sessions', $record);
516 $record->sid = md5('hokus5');
517 $record->userid = 0;
518 $record->timecreated = time() - 60*5;
519 $record->timemodified = time() - 60*5;
520 $r5 = $DB->insert_record('sessions', $record);
522 $record->sid = md5('hokus6');
523 $record->userid = 0;
524 $record->timecreated = time() - 60*60;
525 $record->timemodified = time() - 60*10 -10;
526 $r6 = $DB->insert_record('sessions', $record);
528 $record->sid = md5('hokus7');
529 $record->userid = 0;
530 $record->timecreated = time() - 60*60;
531 $record->timemodified = time() - 60*9;
532 $r7 = $DB->insert_record('sessions', $record);
534 \core\session\manager::gc();
536 $this->assertTrue($DB->record_exists('sessions', array('id'=>$r1)));
537 $this->assertFalse($DB->record_exists('sessions', array('id'=>$r2)));
538 $this->assertTrue($DB->record_exists('sessions', array('id'=>$r3)));
539 $this->assertFalse($DB->record_exists('sessions', array('id'=>$r4)));
540 $this->assertFalse($DB->record_exists('sessions', array('id'=>$r5)));
541 $this->assertFalse($DB->record_exists('sessions', array('id'=>$r6)));
542 $this->assertTrue($DB->record_exists('sessions', array('id'=>$r7)));
546 * Test loginas.
547 * @copyright 2103 Rajesh Taneja <rajesh@moodle.com>
549 public function test_loginas() {
550 global $USER, $SESSION;
551 $this->resetAfterTest();
553 // Set current user as Admin user and save it for later use.
554 $this->setAdminUser();
555 $adminuser = $USER;
556 $adminsession = $SESSION;
557 $user = $this->getDataGenerator()->create_user();
558 $_SESSION['extra'] = true;
560 // Try admin loginas this user in system context.
561 $this->assertObjectNotHasProperty('realuser', $USER);
562 \core\session\manager::loginas($user->id, \context_system::instance());
564 $this->assertSame($user->id, $USER->id);
565 $this->assertEquals(\context_system::instance(), $USER->loginascontext);
566 $this->assertSame($adminuser->id, $USER->realuser);
567 $this->assertSame($GLOBALS['USER'], $_SESSION['USER']);
568 $this->assertSame($GLOBALS['USER'], $USER);
569 $this->assertNotSame($adminuser, $_SESSION['REALUSER']);
570 $this->assertEquals($adminuser, $_SESSION['REALUSER']);
572 $this->assertSame($GLOBALS['SESSION'], $_SESSION['SESSION']);
573 $this->assertSame($GLOBALS['SESSION'], $SESSION);
574 $this->assertNotSame($adminsession, $_SESSION['REALSESSION']);
575 $this->assertEquals($adminsession, $_SESSION['REALSESSION']);
577 $this->assertArrayNotHasKey('extra', $_SESSION);
579 // Set user as current user and login as admin user in course context.
580 \core\session\manager::init_empty_session();
581 $this->setUser($user);
582 $this->assertNotEquals($adminuser->id, $USER->id);
583 $course = $this->getDataGenerator()->create_course();
584 $coursecontext = \context_course::instance($course->id);
586 // Catch event triggered.
587 $sink = $this->redirectEvents();
588 \core\session\manager::loginas($adminuser->id, $coursecontext);
589 $events = $sink->get_events();
590 $sink->close();
591 $event = array_pop($events);
593 $this->assertSame($adminuser->id, $USER->id);
594 $this->assertSame($coursecontext, $USER->loginascontext);
595 $this->assertSame($user->id, $USER->realuser);
597 // Test event captured has proper information.
598 $this->assertInstanceOf('\core\event\user_loggedinas', $event);
599 $this->assertSame($user->id, $event->objectid);
600 $this->assertSame($adminuser->id, $event->relateduserid);
601 $this->assertSame($course->id, $event->courseid);
602 $this->assertEquals($coursecontext, $event->get_context());
603 $oldfullname = fullname($user, true);
604 $newfullname = fullname($adminuser, true);
607 public function test_is_loggedinas() {
608 $this->resetAfterTest();
610 $user1 = $this->getDataGenerator()->create_user();
611 $user2 = $this->getDataGenerator()->create_user();
613 $this->assertFalse(\core\session\manager::is_loggedinas());
615 $this->setUser($user1);
616 \core\session\manager::loginas($user2->id, \context_system::instance());
618 $this->assertTrue(\core\session\manager::is_loggedinas());
621 public function test_get_realuser() {
622 $this->resetAfterTest();
624 $user1 = $this->getDataGenerator()->create_user();
625 $user2 = $this->getDataGenerator()->create_user();
627 $this->setUser($user1);
628 $normal = \core\session\manager::get_realuser();
629 $this->assertSame($GLOBALS['USER'], $normal);
631 \core\session\manager::loginas($user2->id, \context_system::instance());
633 $real = \core\session\manager::get_realuser();
635 unset($real->password);
636 unset($real->description);
637 unset($real->sesskey);
638 unset($user1->password);
639 unset($user1->description);
640 unset($user1->sesskey);
642 $this->assertEquals($real, $user1);
643 $this->assertSame($_SESSION['REALUSER'], $real);
647 * Session lock info on pages.
649 * @return array
651 public function pages_sessionlocks() {
652 return [
654 'url' => '/good.php',
655 'start' => 1500000001.000,
656 'gained' => 1500000002.000,
657 'released' => 1500000003.000,
658 'wait' => 1.0,
659 'held' => 1.0
662 'url' => '/bad.php?wait=5',
663 'start' => 1500000003.000,
664 'gained' => 1500000005.000,
665 'released' => 1500000007.000,
666 'held' => 2.0,
667 'wait' => 2.0
673 * Test to get recent session locks.
675 public function test_get_recent_session_locks() {
676 global $CFG;
678 $this->resetAfterTest();
679 $CFG->debugsessionlock = 5;
680 $pages = $this->pages_sessionlocks();
681 // Recent session locks must be empty at first.
682 $recentsessionlocks = \core\session\manager::get_recent_session_locks();
683 $this->assertEmpty($recentsessionlocks);
685 // Add page to the recentsessionlocks array.
686 \core\session\manager::update_recent_session_locks($pages[0]);
687 $recentsessionlocks = \core\session\manager::get_recent_session_locks();
688 // Make sure we are getting the first page we added.
689 $this->assertEquals($pages[0], $recentsessionlocks[0]);
690 // There should be 1 page in the array.
691 $this->assertCount(1, $recentsessionlocks);
693 // Add second page to the recentsessionlocks array.
694 \core\session\manager::update_recent_session_locks($pages[1]);
695 $recentsessionlocks = \core\session\manager::get_recent_session_locks();
696 // Make sure we are getting the second page we added.
697 $this->assertEquals($pages[1], $recentsessionlocks[1]);
698 // There should be 2 pages in the array.
699 $this->assertCount(2, $recentsessionlocks);
703 * Test to update recent session locks.
705 public function test_update_recent_session_locks() {
706 global $CFG;
708 $this->resetAfterTest();
709 $CFG->debugsessionlock = 5;
710 $pages = $this->pages_sessionlocks();
712 \core\session\manager::update_recent_session_locks($pages[0]);
713 \core\session\manager::update_recent_session_locks($pages[1]);
714 $recentsessionlocks = \core\session\manager::get_recent_session_locks();
715 // There should be 2 pages in the array.
716 $this->assertCount(2, $recentsessionlocks);
717 // Make sure the last page is added at the end of the array.
718 $this->assertEquals($pages[1], end($recentsessionlocks));
723 * Test to get session lock info.
725 public function test_get_session_lock_info() {
726 global $PERF;
728 $this->resetAfterTest();
730 $pages = $this->pages_sessionlocks();
731 $PERF->sessionlock = $pages[0];
732 $sessionlock = \core\session\manager::get_session_lock_info();
733 $this->assertEquals($pages[0], $sessionlock);
737 * Session lock info on some pages to serve as history.
739 * @return array
741 public function sessionlock_history() {
742 return [
744 'url' => '/good.php',
745 'start' => 1500000001.000,
746 'gained' => 1500000001.100,
747 'released' => 1500000001.500,
748 'wait' => 0.1
751 // This bad request doesn't release the session for 10 seconds.
752 'url' => '/bad.php',
753 'start' => 1500000012.000,
754 'gained' => 1500000012.200,
755 'released' => 1500000020.200,
756 'wait' => 0.2
759 // All subsequent requests are blocked and need to wait.
760 'url' => '/good.php?id=1',
761 'start' => 1500000012.900,
762 'gained' => 1500000020.200,
763 'released' => 1500000022.000,
764 'wait' => 7.29
767 'url' => '/good.php?id=2',
768 'start' => 1500000014.000,
769 'gained' => 1500000022.000,
770 'released' => 1500000025.000,
771 'wait' => 8.0
774 'url' => '/good.php?id=3',
775 'start' => 1500000015.000,
776 'gained' => 1500000025.000,
777 'released' => 1500000026.000,
778 'wait' => 10.0
781 'url' => '/good.php?id=4',
782 'start' => 1500000016.000,
783 'gained' => 1500000026.000,
784 'released' => 1500000027.000,
785 'wait' => 10.0
791 * Data provider for test_get_locked_page_at function.
793 * @return array
795 public function sessionlocks_info_provider(): array {
796 return [
798 'url' => null,
799 'time' => 1500000001.000
802 'url' => '/bad.php',
803 'time' => 1500000014.000
806 'url' => '/good.php?id=2',
807 'time' => 1500000022.500
813 * Test to get locked page at a speficic timestamp.
815 * @dataProvider sessionlocks_info_provider
816 * @param array $url Session lock page url.
817 * @param array $time Session lock time.
819 public function test_get_locked_page_at($url, $time) {
820 global $CFG, $SESSION;
822 $this->resetAfterTest();
823 $CFG->debugsessionlock = 5;
824 $SESSION->recentsessionlocks = $this->sessionlock_history();
826 $page = \core\session\manager::get_locked_page_at($time);
827 $this->assertEquals($url, is_array($page) ? $page['url'] : null);
831 * Test cleanup recent session locks.
833 public function test_cleanup_recent_session_locks() {
834 global $CFG, $SESSION;
836 $this->resetAfterTest();
837 $CFG->debugsessionlock = 5;
839 $SESSION->recentsessionlocks = $this->sessionlock_history();
840 $this->assertCount(6, $SESSION->recentsessionlocks);
841 \core\session\manager::cleanup_recent_session_locks();
842 // Make sure the session history has been cleaned up and only has the latest page.
843 $this->assertCount(1, $SESSION->recentsessionlocks);
844 $this->assertEquals('/good.php?id=4', $SESSION->recentsessionlocks[0]['url']);
848 * Data provider for the array_session_diff function.
850 * @return array
852 public function array_session_diff_provider() {
853 // Create an instance of this object so the comparison object's identities are the same.
854 // Used in one of the tests below.
855 $compareobjectb = (object) ['array' => 'b'];
857 return [
858 'both same objects' => [
859 'a' => ['example' => (object) ['array' => 'a']],
860 'b' => ['example' => (object) ['array' => 'a']],
861 'expected' => [],
863 'both same arrays' => [
864 'a' => ['example' => ['array' => 'a']],
865 'b' => ['example' => ['array' => 'a']],
866 'expected' => [],
868 'both the same with nested objects' => [
869 'a' => ['example' => (object) ['array' => 'a', 'deeper' => (object) []]],
870 'b' => ['example' => (object) ['array' => 'a', 'deeper' => (object) []]],
871 'expected' => [],
873 'first array larger' => [
874 'a' => ['x' => 1, 'y' => 2],
875 'b' => ['x' => 1],
876 'expected' => ['y' => 2]
878 'second array larger' => [
879 'a' => ['x' => 1],
880 'b' => ['x' => 1, 'y' => 2],
881 'expected' => ['y' => 2]
883 'objects with different values but same keys' => [
884 'a' => ['example' => (object) ['array' => 'a']],
885 'b' => ['example' => $compareobjectb],
886 'expected' => ['example' => $compareobjectb]
888 'different arrays with top level indexes' => [
889 'a' => ['x', 'y'],
890 'b' => ['x', 'y', 'z'],
891 'expected' => [2 => 'z']
893 'different types but same values as first level' => [
894 'a' => ['example' => (object) ['array' => 'a']],
895 'b' => ['example' => ['array' => 'a']],
896 'expected' => ['example' => ['array' => 'a']]
898 'different types but same values nested' => [
899 'a' => ['example' => (object) ['array' => ['a' => 'test']]],
900 'b' => ['example' => (object) ['array' => (object) ['a' => 'test']]],
901 // Type checking is not done further than the first level, so we expect no difference.
902 'expected' => []
908 * Tests array diff method in various situations.
910 * @dataProvider array_session_diff_provider
911 * @covers \core\session\manager::array_session_diff
912 * @param array $a first value.
913 * @param array $b second value to compare to $a.
914 * @param array $expected the expected difference.
916 public function test_array_session_diff(array $a, array $b, array $expected) {
917 $class = new \ReflectionClass('\core\session\manager');
918 $method = $class->getMethod('array_session_diff');
920 $result = $method->invokeArgs(null, [$a, $b]);
921 $this->assertSame($expected, $result);