From b6d04b488271eac6345efa049ba358fc3e2f7ed8 Mon Sep 17 00:00:00 2001 From: meirzamoodle Date: Fri, 31 Jan 2025 09:11:10 +0700 Subject: [PATCH] MDL-84051 core: Call parent function to clear session data in the table --- lib/classes/session/file.php | 4 +- lib/classes/session/memcached.php | 4 +- lib/tests/session/file_test.php | 103 +++++++++++++++++++ lib/tests/session/memcached_test.php | 145 +++++++++++++++++++++++++++ 4 files changed, 252 insertions(+), 4 deletions(-) create mode 100644 lib/tests/session/file_test.php create mode 100644 lib/tests/session/memcached_test.php diff --git a/lib/classes/session/file.php b/lib/classes/session/file.php index 23def9ea2fd..4527bee0920 100644 --- a/lib/classes/session/file.php +++ b/lib/classes/session/file.php @@ -82,7 +82,7 @@ class file extends handler { } } - return true; + return parent::destroy_all(); } #[\Override] @@ -96,6 +96,6 @@ class file extends handler { @unlink($sessionfile); } - return true; + return parent::destroy($id); } } diff --git a/lib/classes/session/memcached.php b/lib/classes/session/memcached.php index 91fb2d5dd2f..203b212de63 100644 --- a/lib/classes/session/memcached.php +++ b/lib/classes/session/memcached.php @@ -221,7 +221,7 @@ class memcached extends handler { $memcached->quit(); } - return true; + return parent::destroy_all(); } #[\Override] @@ -242,7 +242,7 @@ class memcached extends handler { $memcached->quit(); } - return true; + return parent::destroy($id); } /** diff --git a/lib/tests/session/file_test.php b/lib/tests/session/file_test.php new file mode 100644 index 00000000000..ab01775ff8c --- /dev/null +++ b/lib/tests/session/file_test.php @@ -0,0 +1,103 @@ +. + +namespace core\session; + +use core\tests\session\mock_handler; + +/** + * Unit tests for classes/session/file.php. + * + * @package core + * @copyright Meirza + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * + * @runTestsInSeparateProcesses + * @covers \core\session\file + */ +final class file_test extends \advanced_testcase { + /** @var file|null $filesession */ + private ?file $filesession = null; + + /** @var mock_handler $mockhandler Dedicated testing handler. */ + private mock_handler $mockhandler; + + #[\Override] + public function setUp(): void { + global $CFG; + + parent::setUp(); + $this->resetAfterTest(); + + $this->mockhandler = new mock_handler(); + + $this->filesession = new file(); + $this->filesession->init(); + } + + /** + * Test destroy a specific session and delete this session record for this session id. + */ + public function test_destroy(): void { + $sid = md5('sesstest'); + $this->add_session($sid); + + $this->assertTrue($this->filesession->session_exists($sid)); + $this->assertTrue(manager::session_exists($sid)); + + $this->filesession->destroy($sid); + + $this->assertFalse($this->filesession->session_exists($sid)); + $this->assertFalse(manager::session_exists($sid)); + } + + /** + * Test destroy all sessions, and delete all the session data. + */ + public function test_destroy_all(): void { + global $DB; + + $sid1 = md5('sesstest1'); + $this->add_session($sid1); + $sid2 = md5('sesstest2'); + $this->add_session($sid2); + + $this->assertTrue($this->filesession->session_exists($sid1)); + $this->assertTrue($this->filesession->session_exists($sid2)); + $this->assertEquals(2, $DB->count_records('sessions')); + + $this->filesession->destroy_all(); + + $this->assertFalse($this->filesession->session_exists($sid1)); + $this->assertFalse($this->filesession->session_exists($sid2)); + $this->assertEquals(0, $DB->count_records('sessions')); + } + + /** + * Adds a session with the given session ID. + * + * @param string $sid The session ID to add. + */ + private function add_session(string $sid): void { + global $CFG; + + touch("{$CFG->dataroot}/sessions/sess_{$sid}"); + + $record = new \stdClass(); + $record->sid = $sid; + $this->mockhandler->add_test_session($record); + } +} diff --git a/lib/tests/session/memcached_test.php b/lib/tests/session/memcached_test.php new file mode 100644 index 00000000000..18f41411fae --- /dev/null +++ b/lib/tests/session/memcached_test.php @@ -0,0 +1,145 @@ +. + +namespace core\session; + +use core\tests\session\mock_handler; + +/** + * Unit tests for classes/session/memcached.php. + * + * NOTE: in order to execute this test you need to set up + * Memcached server and add configuration a constant + * to config.php or phpunit.xml configuration file: + * + * define('TEST_SESSION_MEMCACHED_SERVER', 'localhost:11211'); + * define('TEST_SESSION_MEMCACHED_PREFIX', 'memc.sess.key.'); + * + * The 'TEST_SESSION_MEMCACHED_PREFIX' is optional and if not set the default value will be used. + * + * @package core + * @copyright Meirza + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * + * @runTestsInSeparateProcesses + * @covers core\session\memcached + */ +final class memcached_test extends \advanced_testcase { + /** @var memcached|null $memcachedession An instance of the memcached session or null if not initialized. */ + private ?memcached $memcachedession = null; + + /** @var \Memcached $memcached An instance of the Memcached class used for handling session storage. */ + private \Memcached $memcached; + + /** @var mock_handler $mockhandler Dedicated testing handler. */ + private mock_handler $mockhandler; + + /** @var string $keyprefix The prefix used for keys in the Memcached session storage. */ + private string $keyprefix = 'memc.sess.key.'; + + #[\Override] + public function setUp(): void { + global $CFG; + parent::setUp(); + $this->resetAfterTest(); + + if (!extension_loaded('memcached')) { + $this->markTestSkipped('memcached extension is not loaded'); + } + + $version = phpversion('memcached'); + if (!$version || version_compare($version, '2.0') < 0) { + $this->markTestSkipped('memcached extension version must be at least 2.0'); + } + + if (!defined('TEST_SESSION_MEMCACHED_SERVER')) { + $this->markTestSkipped('Session test server not set. define: TEST_SESSION_MEMCACHED_SERVER'); + } + + if (defined('TEST_SESSION_MEMCACHED_PREFIX')) { + $this->keyprefix = TEST_SESSION_MEMCACHED_PREFIX; + $CFG->session_memcached_prefix = TEST_SESSION_MEMCACHED_PREFIX; + } + + $this->mockhandler = new mock_handler(); + + $CFG->session_memcached_save_path = TEST_SESSION_MEMCACHED_SERVER; + $this->memcachedession = new memcached(); + $this->memcachedession->init(); + + [$host, $port] = explode(':', TEST_SESSION_MEMCACHED_SERVER); + $this->memcached = new \Memcached(); + $this->memcached->addServer($host, $port); + } + + #[\Override] + public function tearDown(): void { + $this->memcached->quit(); + parent::tearDown(); + } + + /** + * Test the destruction of a session. + */ + public function test_destroy(): void { + $sid = $this->add_session('sesstest'); + + $this->assertTrue($this->memcachedession->session_exists($sid)); + $this->assertTrue(manager::session_exists($sid)); + + $this->memcachedession->destroy($sid); + + $this->assertFalse($this->memcachedession->session_exists($sid)); + $this->assertFalse(manager::session_exists($sid)); + } + + /** + * Test the destruction of all sessions. + */ + public function test_destroy_all(): void { + global $DB; + + $sid1 = $this->add_session('sesstest1'); + $sid2 = $this->add_session('sesstest2'); + + $this->assertTrue($this->memcachedession->session_exists($sid1)); + $this->assertTrue($this->memcachedession->session_exists($sid2)); + $this->assertEquals(2, $DB->count_records('sessions')); + + $this->memcachedession->destroy_all(); + + $this->assertFalse($this->memcachedession->session_exists($sid1)); + $this->assertFalse($this->memcachedession->session_exists($sid2)); + $this->assertEquals(0, $DB->count_records('sessions')); + } + + /** + * Adds a session with the given session ID. + * + * @param string $sid The session ID to add. + * @return string The result of adding the session. + */ + private function add_session(string $sid): string { + $sid = md5($sid); + $this->memcached->set($this->keyprefix . $sid, 'abc'); + + $record = new \stdClass(); + $record->sid = $sid; + $this->mockhandler->add_test_session($record); + + return $sid; + } +}