AutorÃa | Ultima modificación | Ver Log |
<?php// This file is part of Moodle - http://moodle.org///// Moodle is free software: you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation, either version 3 of the License, or// (at your option) any later version.//// Moodle is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.//// You should have received a copy of the GNU General Public License// along with Moodle. If not, see <http://www.gnu.org/licenses/>.namespace core\session;use core\tests\session\mock_handler;/*** Unit tests for session manager class.** @package core* @category test* @copyright 2013 Petr Skoda {@link http://skodak.org}* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later* @covers \core\session\manager*/final class manager_test extends \advanced_testcase {/** @var mock_handler $mockhandler Dedicated testing handler. */protected mock_handler $mockhandler;protected function setUp(): void {parent::setUp();$this->mockhandler = new mock_handler();}public function test_start(): void {$this->resetAfterTest();// Session must be started only once...\core\session\manager::start();$this->assertDebuggingCalled('Session was already started!', DEBUG_DEVELOPER);}public function test_init_empty_session(): void {global $SESSION, $USER;$this->resetAfterTest();$user = $this->getDataGenerator()->create_user();$SESSION->test = true;$this->assertTrue($GLOBALS['SESSION']->test);$this->assertTrue($_SESSION['SESSION']->test);\core\session\manager::set_user($user);$this->assertSame($user, $USER);$this->assertSame($user, $GLOBALS['USER']);$this->assertSame($user, $_SESSION['USER']);\core\session\manager::init_empty_session();$this->assertInstanceOf('stdClass', $SESSION);$this->assertEmpty((array)$SESSION);$this->assertSame($GLOBALS['SESSION'], $_SESSION['SESSION']);$this->assertSame($GLOBALS['SESSION'], $SESSION);$this->assertInstanceOf('stdClass', $USER);$this->assertEqualsCanonicalizing(array('id' => 0, 'mnethostid' => 1), (array)$USER);$this->assertSame($GLOBALS['USER'], $_SESSION['USER']);$this->assertSame($GLOBALS['USER'], $USER);// Now test how references work.$GLOBALS['SESSION'] = new \stdClass();$GLOBALS['SESSION']->test = true;$this->assertSame($GLOBALS['SESSION'], $_SESSION['SESSION']);$this->assertSame($GLOBALS['SESSION'], $SESSION);$SESSION = new \stdClass();$SESSION->test2 = true;$this->assertSame($GLOBALS['SESSION'], $_SESSION['SESSION']);$this->assertSame($GLOBALS['SESSION'], $SESSION);$_SESSION['SESSION'] = new \stdClass();$_SESSION['SESSION']->test3 = true;$this->assertSame($GLOBALS['SESSION'], $_SESSION['SESSION']);$this->assertSame($GLOBALS['SESSION'], $SESSION);$GLOBALS['USER'] = new \stdClass();$GLOBALS['USER']->test = true;$this->assertSame($GLOBALS['USER'], $_SESSION['USER']);$this->assertSame($GLOBALS['USER'], $USER);$USER = new \stdClass();$USER->test2 = true;$this->assertSame($GLOBALS['USER'], $_SESSION['USER']);$this->assertSame($GLOBALS['USER'], $USER);$_SESSION['USER'] = new \stdClass();$_SESSION['USER']->test3 = true;$this->assertSame($GLOBALS['USER'], $_SESSION['USER']);$this->assertSame($GLOBALS['USER'], $USER);}public function test_set_user(): void {global $USER;$this->resetAfterTest();$this->assertEquals(0, $USER->id);$user = $this->getDataGenerator()->create_user();$this->assertObjectHasProperty('description', $user);$this->assertObjectHasProperty('password', $user);\core\session\manager::set_user($user);$this->assertEquals($user->id, $USER->id);$this->assertObjectNotHasProperty('description', $user);$this->assertObjectNotHasProperty('password', $user);$this->assertObjectHasProperty('sesskey', $user);$this->assertSame($user, $GLOBALS['USER']);$this->assertSame($GLOBALS['USER'], $_SESSION['USER']);$this->assertSame($GLOBALS['USER'], $USER);}public function test_login_user(): void {global $USER;$this->resetAfterTest();$this->assertEquals(0, $USER->id);$user = $this->getDataGenerator()->create_user();@\core\session\manager::login_user($user); // Ignore header error messages.$this->assertEquals($user->id, $USER->id);$this->assertObjectNotHasProperty('description', $user);$this->assertObjectNotHasProperty('password', $user);$this->assertSame($user, $GLOBALS['USER']);$this->assertSame($GLOBALS['USER'], $_SESSION['USER']);$this->assertSame($GLOBALS['USER'], $USER);}public function test_terminate_current(): void {global $USER, $SESSION;$this->resetAfterTest();$this->setAdminUser();\core\session\manager::terminate_current();$this->assertEquals(0, $USER->id);$this->assertInstanceOf('stdClass', $SESSION);$this->assertEmpty((array)$SESSION);$this->assertSame($GLOBALS['SESSION'], $_SESSION['SESSION']);$this->assertSame($GLOBALS['SESSION'], $SESSION);$this->assertInstanceOf('stdClass', $USER);$this->assertEqualsCanonicalizing(array('id' => 0, 'mnethostid' => 1), (array)$USER);$this->assertSame($GLOBALS['USER'], $_SESSION['USER']);$this->assertSame($GLOBALS['USER'], $USER);}public function test_write_close(): void {global $USER;$this->resetAfterTest();// Just make sure no errors and $USER->id is kept$this->setAdminUser();$userid = $USER->id;\core\session\manager::write_close();$this->assertSame($userid, $USER->id);$this->assertSame($GLOBALS['USER'], $_SESSION['USER']);$this->assertSame($GLOBALS['USER'], $USER);}public function test_session_exists(): void {global $CFG, $DB;$this->resetAfterTest();$this->assertFalse(\core\session\manager::session_exists('abc'));$user = $this->getDataGenerator()->create_user();$guest = guest_user();// The file handler is used by default, so let's fake the data somehow.$sid = md5('hokus');mkdir("$CFG->dataroot/sessions/", $CFG->directorypermissions, true);touch("$CFG->dataroot/sessions/sess_$sid");$this->assertFalse(\core\session\manager::session_exists($sid));$record = new \stdClass();$record->userid = 0;$record->sid = $sid;$record->timecreated = time();$record->timemodified = $record->timecreated;$record->id = $this->mockhandler->add_test_session($record);$this->assertTrue(\core\session\manager::session_exists($sid));$record->timecreated = time() - $CFG->sessiontimeout - 100;$record->timemodified = $record->timecreated + 10;\core\session\manager::update_session($record);$this->assertTrue(\core\session\manager::session_exists($sid));$record->userid = $guest->id;\core\session\manager::update_session($record);$this->assertTrue(\core\session\manager::session_exists($sid));$record->userid = $user->id;\core\session\manager::update_session($record);$this->assertFalse(\core\session\manager::session_exists($sid));$CFG->sessiontimeout = $CFG->sessiontimeout + 3000;$this->assertTrue(\core\session\manager::session_exists($sid));}public function test_touch_session(): void {$this->resetAfterTest();$sid = md5('hokus');$record = new \stdClass();$record->state = 0;$record->sid = $sid;$record->sessdata = null;$record->userid = 2;$record->timecreated = time() - 60*60;$record->timemodified = time() - 30;$record->firstip = $record->lastip = '10.0.0.1';$record->id = $this->mockhandler->add_test_session($record);$now = time();\core\session\manager::touch_session($sid);$session = \core\session\manager::get_session_by_sid($sid);$this->assertGreaterThanOrEqual($now, $session->timemodified);$this->assertLessThanOrEqual(time(), $session->timemodified);}/*** Test destroy method.** @return void* @throws \dml_exception*/public function test_destroy(): void {global $DB, $USER;$this->resetAfterTest();$this->setAdminUser();$userid = $USER->id;$sid = md5('hokus');$record = new \stdClass();$record->state = 0;$record->sid = $sid;$record->sessdata = null;$record->userid = $userid;$record->timecreated = time() - 60*60;$record->timemodified = time() - 30;$record->firstip = $record->lastip = '10.0.0.1';$this->mockhandler->add_test_session($record);$record->userid = 0;$record->sid = md5('pokus');$this->mockhandler->add_test_session($record);$this->assertEquals(2, $this->mockhandler->count_sessions());\core\session\manager::destroy($sid);$sessions = $this->mockhandler->get_all_sessions();$this->assertEquals(1, count($sessions));$this->assertFalse($this->contains_session(['sid' => $sid], $sessions));$this->assertSame($userid, $USER->id);}public function test_destroy_user_sessions(): void {global $DB, $USER;$this->resetAfterTest();$this->setAdminUser();$userid = $USER->id;$sid = md5('hokus');$record = new \stdClass();$record->state = 0;$record->sid = $sid;$record->sessdata = null;$record->userid = $userid;$record->timecreated = time() - 60*60;$record->timemodified = time() - 30;$record->firstip = $record->lastip = '10.0.0.1';$this->mockhandler->add_test_session($record);$record->sid = md5('hokus2');$this->mockhandler->add_test_session($record);$record->userid = 0;$record->sid = md5('pokus');$this->mockhandler->add_test_session($record);$this->assertEquals(3, $DB->count_records('sessions'));\core\session\manager::destroy_user_sessions($userid);$sessions = $this->mockhandler->get_all_sessions();$this->assertEquals(1, count($sessions));$this->assertFalse($this->contains_session(['userid' => $userid], $sessions));$record->userid = $userid;$record->sid = md5('pokus3');$this->mockhandler->add_test_session($record);$record->userid = $userid;$record->sid = md5('pokus4');$this->mockhandler->add_test_session($record);$record->userid = $userid;$record->sid = md5('pokus5');$this->mockhandler->add_test_session($record);$sessions = \core\session\manager::get_sessions_by_userid($userid);$this->assertCount(3, $sessions);\core\session\manager::destroy_user_sessions($userid, md5('pokus5'));$sessions = \core\session\manager::get_sessions_by_userid($userid);$session = reset($sessions);$this->assertCount(1, $sessions);$this->assertEquals(md5('pokus5'), $session->sid);}public function test_apply_concurrent_login_limit(): void {global $DB;$this->resetAfterTest();$user1 = $this->getDataGenerator()->create_user();$user2 = $this->getDataGenerator()->create_user();$guest = guest_user();$record = new \stdClass();$record->state = 0;$record->sessdata = null;$record->userid = $user1->id;$record->timemodified = time();$record->firstip = $record->lastip = '10.0.0.1';$record->sid = md5('hokus1');$record->timecreated = 20;$this->mockhandler->add_test_session($record);$record->sid = md5('hokus2');$record->timecreated = 10;$this->mockhandler->add_test_session($record);$record->sid = md5('hokus3');$record->timecreated = 30;$this->mockhandler->add_test_session($record);$record->userid = $user2->id;$record->sid = md5('pokus1');$record->timecreated = 20;$this->mockhandler->add_test_session($record);$record->sid = md5('pokus2');$record->timecreated = 10;$this->mockhandler->add_test_session($record);$record->sid = md5('pokus3');$record->timecreated = 30;$this->mockhandler->add_test_session($record);$record->timecreated = 10;$record->userid = $guest->id;$record->sid = md5('g1');$this->mockhandler->add_test_session($record);$record->sid = md5('g2');$this->mockhandler->add_test_session($record);$record->sid = md5('g3');$this->mockhandler->add_test_session($record);$record->userid = 0;$record->sid = md5('nl1');$this->mockhandler->add_test_session($record);$record->sid = md5('nl2');$this->mockhandler->add_test_session($record);$record->sid = md5('nl3');$this->mockhandler->add_test_session($record);set_config('limitconcurrentlogins', 0);$this->assertCount(12, $DB->get_records('sessions'));\core\session\manager::apply_concurrent_login_limit($user1->id);\core\session\manager::apply_concurrent_login_limit($user2->id);\core\session\manager::apply_concurrent_login_limit($guest->id);\core\session\manager::apply_concurrent_login_limit(0);$this->assertCount(12, $DB->get_records('sessions'));set_config('limitconcurrentlogins', -1);\core\session\manager::apply_concurrent_login_limit($user1->id);\core\session\manager::apply_concurrent_login_limit($user2->id);\core\session\manager::apply_concurrent_login_limit($guest->id);\core\session\manager::apply_concurrent_login_limit(0);$this->assertCount(12, $DB->get_records('sessions'));set_config('limitconcurrentlogins', 2);\core\session\manager::apply_concurrent_login_limit($user1->id);$sessions = $this->mockhandler->get_all_sessions();$this->assertCount(11, $sessions);$this->assertTrue($this->contains_session(['userid' => $user1->id, 'timecreated' => 20], $sessions));$this->assertTrue($this->contains_session(['userid' => $user1->id, 'timecreated' => 30], $sessions));$this->assertFalse($this->contains_session(['userid' => $user1->id, 'timecreated' => 10], $sessions));$this->assertTrue($this->contains_session(['userid' => $user2->id, 'timecreated' => 20], $sessions));$this->assertTrue($this->contains_session(['userid' => $user2->id, 'timecreated' => 30], $sessions));$this->assertTrue($this->contains_session(['userid' => $user2->id, 'timecreated' => 10], $sessions));set_config('limitconcurrentlogins', 2);\core\session\manager::apply_concurrent_login_limit($user2->id, md5('pokus2'));$sessions = $this->mockhandler->get_all_sessions();$this->assertCount(10, $sessions);$this->assertFalse($this->contains_session(['userid' => $user2->id, 'timecreated' => 20], $sessions));$this->assertTrue($this->contains_session(['userid' => $user2->id, 'timecreated' => 30], $sessions));$this->assertTrue($this->contains_session(['userid' => $user2->id, 'timecreated' => 10], $sessions));\core\session\manager::apply_concurrent_login_limit($guest->id);\core\session\manager::apply_concurrent_login_limit(0);$sessions = $this->mockhandler->get_all_sessions();$this->assertCount(10, $sessions);set_config('limitconcurrentlogins', 1);\core\session\manager::apply_concurrent_login_limit($user1->id, md5('grrr'));$sessions = $this->mockhandler->get_all_sessions();$this->assertCount(9, $sessions);$this->assertFalse($this->contains_session(['userid' => $user1->id, 'timecreated' => 20], $sessions));$this->assertTrue($this->contains_session(['userid' => $user1->id, 'timecreated' => 30], $sessions));$this->assertFalse($this->contains_session(['userid' => $user1->id, 'timecreated' => 10], $sessions));\core\session\manager::apply_concurrent_login_limit($user1->id);$sessions = $this->mockhandler->get_all_sessions();$this->assertCount(9, $sessions);$this->assertFalse($this->contains_session(['userid' => $user1->id, 'timecreated' => 20], $sessions));$this->assertTrue($this->contains_session(['userid' => $user1->id, 'timecreated' => 30], $sessions));$this->assertFalse($this->contains_session(['userid' => $user1->id, 'timecreated' => 10], $sessions));\core\session\manager::apply_concurrent_login_limit($user2->id, md5('pokus2'));$sessions = $this->mockhandler->get_all_sessions();$this->assertCount(8, $sessions);$this->assertFalse($this->contains_session(['userid' => $user2->id, 'timecreated' => 20], $sessions));$this->assertFalse($this->contains_session(['userid' => $user2->id, 'timecreated' => 30], $sessions));$this->assertTrue($this->contains_session(['userid' => $user2->id, 'timecreated' => 10], $sessions));\core\session\manager::apply_concurrent_login_limit($user2->id);$sessions = $this->mockhandler->get_all_sessions();$this->assertCount(8, $sessions);$this->assertFalse($this->contains_session(['userid' => $user2->id, 'timecreated' => 20], $sessions));$this->assertFalse($this->contains_session(['userid' => $user2->id, 'timecreated' => 30], $sessions));$this->assertTrue($this->contains_session(['userid' => $user2->id, 'timecreated' => 10], $sessions));\core\session\manager::apply_concurrent_login_limit($guest->id);\core\session\manager::apply_concurrent_login_limit(0);$sessions = $this->mockhandler->get_all_sessions();$this->assertCount(8, $sessions);}/*** Helper method to check if the sessions array contains a session with the given conditions.** @param array $conditions Conditions to match.* @param null|\Iterator $sessions Sessions to check.* @return bool*/protected function contains_session(array $conditions, ?\Iterator $sessions = null): bool {foreach ($sessions as $session) {if ($this->matches_session($conditions, $session)) {return true;}}return false;}/*** Helper method to check if the session matches the given conditions.** @param array $conditions Conditions to match.* @param \stdClass $session Session to check.* @return bool*/protected function matches_session(array $conditions, \stdClass $session): bool {foreach ($conditions as $key => $value) {if ($session->$key != $value) {return false;}}return true;}/*** Test destroy_all method.** @return void* @throws \dml_exception*/public function test_destroy_all(): void {global $DB, $USER;$this->resetAfterTest();$this->setAdminUser();$userid = $USER->id;$sid = md5('hokus');$record = new \stdClass();$record->state = 0;$record->sid = $sid;$record->sessdata = null;$record->userid = $userid;$record->timecreated = time() - 60*60;$record->timemodified = time() - 30;$record->firstip = $record->lastip = '10.0.0.1';$this->mockhandler->add_test_session($record);$record->sid = md5('hokus2');$this->mockhandler->add_test_session($record);$record->userid = 0;$record->sid = md5('pokus');$this->mockhandler->add_test_session($record);$this->assertEquals(3, $DB->count_records('sessions'));\core\session\manager::destroy_all();$this->assertEquals(0, $DB->count_records('sessions'));$this->assertSame(0, $USER->id);}public function test_gc(): void {global $CFG, $USER;$this->resetAfterTest();$this->setAdminUser();$adminid = $USER->id;$this->setGuestUser();$guestid = $USER->id;$this->setUser(0);// Set sessions timeout to 600 (10 minutes) seconds.// We will test if sessions not modified for 600 seconds are removed.$CFG->sessiontimeout = 60*10;$record = new \stdClass();$record->state = 0;$record->sid = md5('hokus1');$record->sessdata = null;$record->userid = $adminid;$record->timecreated = time() - 60*60;$record->timemodified = time() - 30;$record->firstip = $record->lastip = '10.0.0.1';$r1 = $this->mockhandler->add_test_session($record);$record->sid = md5('hokus2');$record->userid = $adminid;$record->timecreated = time() - 60*60;$record->timemodified = time() - 60*20;$r2 = $this->mockhandler->add_test_session($record);// Guest session still within the session timeout limit.$record->sid = md5('hokus3');$record->userid = $guestid;$record->timecreated = time() - 60*60*60;$record->timemodified = time() - 60*5;$r3 = $this->mockhandler->add_test_session($record);// Guest session outside the session timeout limit.$record->sid = md5('hokus4');$record->userid = $guestid;$record->timecreated = time() - 60*60*60;$record->timemodified = time() - 60*10*5 - 60;$r4 = $this->mockhandler->add_test_session($record);$record->sid = md5('hokus5');$record->userid = 0;$record->timecreated = time() - 60*5;$record->timemodified = time() - 60*5;$r5 = $this->mockhandler->add_test_session($record);$record->sid = md5('hokus6');$record->userid = 0;$record->timecreated = time() - 60*60;$record->timemodified = time() - 60*10 -10;$r6 = $this->mockhandler->add_test_session($record);$record->sid = md5('hokus7');$record->userid = 0;$record->timecreated = time() - 60*60;$record->timemodified = time() - 60*9;$r7 = $this->mockhandler->add_test_session($record);\core\session\manager::gc($CFG->sessiontimeout);$sessions = $this->mockhandler->get_all_sessions();$this->assertTrue($this->contains_session(['id' => $r1], $sessions));$this->assertFalse($this->contains_session(['id' => $r2], $sessions));$this->assertTrue($this->contains_session(['id' => $r3], $sessions));$this->assertFalse($this->contains_session(['id' => $r4], $sessions));$this->assertFalse($this->contains_session(['id' => $r5], $sessions));$this->assertFalse($this->contains_session(['id' => $r6], $sessions));$this->assertTrue($this->contains_session(['id' => $r7], $sessions));}/*** Test loginas.* @copyright 2103 Rajesh Taneja <rajesh@moodle.com>*/public function test_loginas(): void {global $USER, $SESSION;$this->resetAfterTest();// Set current user as Admin user and save it for later use.$this->setAdminUser();$adminuser = $USER;$adminsession = $SESSION;$user = $this->getDataGenerator()->create_user();$_SESSION['extra'] = true;// Try admin loginas this user in system context.$this->assertObjectNotHasProperty('realuser', $USER);\core\session\manager::loginas($user->id, \context_system::instance());$this->assertSame($user->id, $USER->id);$this->assertEquals(\context_system::instance(), $USER->loginascontext);$this->assertSame($adminuser->id, $USER->realuser);$this->assertSame($GLOBALS['USER'], $_SESSION['USER']);$this->assertSame($GLOBALS['USER'], $USER);$this->assertNotSame($adminuser, $_SESSION['REALUSER']);$this->assertEquals($adminuser, $_SESSION['REALUSER']);$this->assertSame($GLOBALS['SESSION'], $_SESSION['SESSION']);$this->assertSame($GLOBALS['SESSION'], $SESSION);$this->assertNotSame($adminsession, $_SESSION['REALSESSION']);$this->assertEquals($adminsession, $_SESSION['REALSESSION']);$this->assertArrayNotHasKey('extra', $_SESSION);// Set user as current user and login as admin user in course context.\core\session\manager::init_empty_session();$this->setUser($user);$this->assertNotEquals($adminuser->id, $USER->id);$course = $this->getDataGenerator()->create_course();$coursecontext = \context_course::instance($course->id);// Catch event triggered.$sink = $this->redirectEvents();\core\session\manager::loginas($adminuser->id, $coursecontext);$events = $sink->get_events();$sink->close();$event = array_pop($events);$this->assertSame($adminuser->id, $USER->id);$this->assertSame($coursecontext, $USER->loginascontext);$this->assertSame($user->id, $USER->realuser);// Test event captured has proper information.$this->assertInstanceOf('\core\event\user_loggedinas', $event);$this->assertSame($user->id, $event->objectid);$this->assertSame($adminuser->id, $event->relateduserid);$this->assertSame($course->id, $event->courseid);$this->assertEquals($coursecontext, $event->get_context());$oldfullname = fullname($user, true);$newfullname = fullname($adminuser, true);}public function test_is_loggedinas(): void {$this->resetAfterTest();$user1 = $this->getDataGenerator()->create_user();$user2 = $this->getDataGenerator()->create_user();$this->assertFalse(\core\session\manager::is_loggedinas());$this->setUser($user1);\core\session\manager::loginas($user2->id, \context_system::instance());$this->assertTrue(\core\session\manager::is_loggedinas());}public function test_get_realuser(): void {$this->resetAfterTest();$user1 = $this->getDataGenerator()->create_user();$user2 = $this->getDataGenerator()->create_user();$this->setUser($user1);$normal = \core\session\manager::get_realuser();$this->assertSame($GLOBALS['USER'], $normal);\core\session\manager::loginas($user2->id, \context_system::instance());$real = \core\session\manager::get_realuser();unset($real->password);unset($real->description);unset($real->sesskey);unset($user1->password);unset($user1->description);unset($user1->sesskey);$this->assertEquals($real, $user1);$this->assertSame($_SESSION['REALUSER'], $real);}/*** Session lock info on pages.** @return array*/public function pages_sessionlocks(): array {return [['url' => '/good.php','start' => 1500000001.000,'gained' => 1500000002.000,'released' => 1500000003.000,'wait' => 1.0,'held' => 1.0],['url' => '/bad.php?wait=5','start' => 1500000003.000,'gained' => 1500000005.000,'released' => 1500000007.000,'held' => 2.0,'wait' => 2.0]];}/*** Test to get recent session locks.*/public function test_get_recent_session_locks(): void {global $CFG;$this->resetAfterTest();$CFG->debugsessionlock = 5;$pages = $this->pages_sessionlocks();// Recent session locks must be empty at first.$recentsessionlocks = \core\session\manager::get_recent_session_locks();$this->assertEmpty($recentsessionlocks);// Add page to the recentsessionlocks array.\core\session\manager::update_recent_session_locks($pages[0]);$recentsessionlocks = \core\session\manager::get_recent_session_locks();// Make sure we are getting the first page we added.$this->assertEquals($pages[0], $recentsessionlocks[0]);// There should be 1 page in the array.$this->assertCount(1, $recentsessionlocks);// Add second page to the recentsessionlocks array.\core\session\manager::update_recent_session_locks($pages[1]);$recentsessionlocks = \core\session\manager::get_recent_session_locks();// Make sure we are getting the second page we added.$this->assertEquals($pages[1], $recentsessionlocks[1]);// There should be 2 pages in the array.$this->assertCount(2, $recentsessionlocks);}/*** Test to update recent session locks.*/public function test_update_recent_session_locks(): void {global $CFG;$this->resetAfterTest();$CFG->debugsessionlock = 5;$pages = $this->pages_sessionlocks();\core\session\manager::update_recent_session_locks($pages[0]);\core\session\manager::update_recent_session_locks($pages[1]);$recentsessionlocks = \core\session\manager::get_recent_session_locks();// There should be 2 pages in the array.$this->assertCount(2, $recentsessionlocks);// Make sure the last page is added at the end of the array.$this->assertEquals($pages[1], end($recentsessionlocks));}/*** Test to get session lock info.*/public function test_get_session_lock_info(): void {global $PERF;$this->resetAfterTest();$pages = $this->pages_sessionlocks();$PERF->sessionlock = $pages[0];$sessionlock = \core\session\manager::get_session_lock_info();$this->assertEquals($pages[0], $sessionlock);}/*** Session lock info on some pages to serve as history.** @return array*/public function sessionlock_history(): array {return [['url' => '/good.php','start' => 1500000001.000,'gained' => 1500000001.100,'released' => 1500000001.500,'wait' => 0.1],[// This bad request doesn't release the session for 10 seconds.'url' => '/bad.php','start' => 1500000012.000,'gained' => 1500000012.200,'released' => 1500000020.200,'wait' => 0.2],[// All subsequent requests are blocked and need to wait.'url' => '/good.php?id=1','start' => 1500000012.900,'gained' => 1500000020.200,'released' => 1500000022.000,'wait' => 7.29],['url' => '/good.php?id=2','start' => 1500000014.000,'gained' => 1500000022.000,'released' => 1500000025.000,'wait' => 8.0],['url' => '/good.php?id=3','start' => 1500000015.000,'gained' => 1500000025.000,'released' => 1500000026.000,'wait' => 10.0],['url' => '/good.php?id=4','start' => 1500000016.000,'gained' => 1500000026.000,'released' => 1500000027.000,'wait' => 10.0]];}/*** Data provider for test_get_locked_page_at function.** @return array*/public static function sessionlocks_info_provider(): array {return [['url' => null,'time' => 1500000001.000],['url' => '/bad.php','time' => 1500000014.000],['url' => '/good.php?id=2','time' => 1500000022.500],];}/*** Test to get locked page at a speficic timestamp.** @dataProvider sessionlocks_info_provider* @param array $url Session lock page url.* @param array $time Session lock time.*/public function test_get_locked_page_at($url, $time): void {global $CFG, $SESSION;$this->resetAfterTest();$CFG->debugsessionlock = 5;$SESSION->recentsessionlocks = $this->sessionlock_history();$page = \core\session\manager::get_locked_page_at($time);$this->assertEquals($url, is_array($page) ? $page['url'] : null);}/*** Test cleanup recent session locks.*/public function test_cleanup_recent_session_locks(): void {global $CFG, $SESSION;$this->resetAfterTest();$CFG->debugsessionlock = 5;$SESSION->recentsessionlocks = $this->sessionlock_history();$this->assertCount(6, $SESSION->recentsessionlocks);\core\session\manager::cleanup_recent_session_locks();// Make sure the session history has been cleaned up and only has the latest page.$this->assertCount(1, $SESSION->recentsessionlocks);$this->assertEquals('/good.php?id=4', $SESSION->recentsessionlocks[0]['url']);}/*** Data provider for the array_session_diff function.** @return array*/public static function array_session_diff_provider(): array {// Create an instance of this object so the comparison object's identities are the same.// Used in one of the tests below.$compareobjectb = (object) ['array' => 'b'];return ['both same objects' => ['a' => ['example' => (object) ['array' => 'a']],'b' => ['example' => (object) ['array' => 'a']],'expected' => [],],'both same arrays' => ['a' => ['example' => ['array' => 'a']],'b' => ['example' => ['array' => 'a']],'expected' => [],],'both the same with nested objects' => ['a' => ['example' => (object) ['array' => 'a', 'deeper' => (object) []]],'b' => ['example' => (object) ['array' => 'a', 'deeper' => (object) []]],'expected' => [],],'first array larger' => ['a' => ['x' => 1, 'y' => 2],'b' => ['x' => 1],'expected' => ['y' => 2]],'second array larger' => ['a' => ['x' => 1],'b' => ['x' => 1, 'y' => 2],'expected' => ['y' => 2]],'objects with different values but same keys' => ['a' => ['example' => (object) ['array' => 'a']],'b' => ['example' => $compareobjectb],'expected' => ['example' => $compareobjectb]],'different arrays with top level indexes' => ['a' => ['x', 'y'],'b' => ['x', 'y', 'z'],'expected' => [2 => 'z']],'different types but same values as first level' => ['a' => ['example' => (object) ['array' => 'a']],'b' => ['example' => ['array' => 'a']],'expected' => ['example' => ['array' => 'a']]],'different types but same values nested' => ['a' => ['example' => (object) ['array' => ['a' => 'test']]],'b' => ['example' => (object) ['array' => (object) ['a' => 'test']]],// Type checking is not done further than the first level, so we expect no difference.'expected' => []]];}/*** Tests array diff method in various situations.** @dataProvider array_session_diff_provider* @covers \core\session\manager::array_session_diff* @param array $a first value.* @param array $b second value to compare to $a.* @param array $expected the expected difference.*/public function test_array_session_diff(array $a, array $b, array $expected): void {$class = new \ReflectionClass('\core\session\manager');$method = $class->getMethod('array_session_diff');$result = $method->invokeArgs(null, [$a, $b]);$this->assertSame($expected, $result);}/*** Test destroy by auth plugin method.*/public function test_destroy_by_auth_plugin(): void {$this->resetAfterTest();global $DB;// Create test users.$user1 = $this->getDataGenerator()->create_user();$user2 = $this->getDataGenerator()->create_user(['auth' => 'db']);// Create sessions for the users.$user1sid = md5('hokus');$record = new \stdClass();$record->state = 0;$record->sid = $user1sid;$record->sessdata = null;$record->userid = $user1->id;$record->timecreated = time() - 60 * 60;$record->timemodified = time() - 30;$record->firstip = $record->lastip = '10.0.0.1';$this->mockhandler->add_test_session($record);$record->sid = md5('pokus');$record->userid = $user2->id;$this->mockhandler->add_test_session($record);// Check sessions.$sessions = $this->mockhandler->get_all_sessions();$this->assertEquals(2, count($sessions));// Destroy the session for the user with manual auth plugin.\core\session\manager::destroy_by_auth_plugin('manual');// Check that the session for the user with manual auth plugin is destroyed.$sessions = $this->mockhandler->get_all_sessions();$this->assertEquals(1, count($sessions));$this->assertFalse($this->contains_session(['sid' => $user1sid], $sessions));}}