diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 73da1815ea08528e216196746a390d7132a9e129..19f1490b655ad41acc2e7c184b480166fa456f76 100755 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,2 +1,5 @@ include: - - remote: https://git-cdn.e15r.co/gitlab/ci/wordpress/-/raw/main/plugins/default.yml + - remote: https://git-cdn.e15r.co/gitlab/ci/wordpress/-/raw/main/plugins/templates/variables.yml + - remote: https://git-cdn.e15r.co/gitlab/ci/wordpress/-/raw/main/plugins/templates/cache.yml + - remote: https://git-cdn.e15r.co/gitlab/ci/wordpress/-/raw/main/plugins/templates/before-script-redis.yml + - remote: https://git-cdn.e15r.co/gitlab/ci/wordpress/-/raw/main/plugins/templates/matrix-redis.yml diff --git a/README.md b/README.md index 1980ae69c3476175f90dc248c85de6de149f016e..f4f8f1822982e7fee2fa17305ff9e93899ef3da7 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ Install and activate this plugin, then deactivate the old plugin. Both plugins c ## Changelog ## ### 0.2 ### -* Rename plugin to `Redis User Session Storage` to submit to WordPress.org plugins repository. +* Rename plugin to `Redis User Session Storage` to comply with WordPress.org plugin-naming requirements. * Allow two versions of this plugin to co-exist safely to support seamless migration. * Changes plugin class name to `Redis_User_Session_Storage` from `WP_Redis_User_Session_Storage`. diff --git a/inc/class-plugin.php b/inc/class-plugin.php index e6b2e07f009c3e62f3ea83ebe154317e702623a8..942b9c377fab510f4c74bfab59820acd662e3a72 100644 --- a/inc/class-plugin.php +++ b/inc/class-plugin.php @@ -104,9 +104,6 @@ class Plugin extends WP_Session_Tokens { /** * Get all sessions of a user. * - * @since 0.1 - * @access protected - * * @return array Sessions of a user. */ protected function get_sessions() { @@ -146,9 +143,6 @@ class Plugin extends WP_Session_Tokens { /** * Retrieve a session by its verifier (token hash). * - * @since 0.1 - * @access protected - * * @param string $verifier Verifier of the session to retrieve. * @return array|null The session, or null if it does not exist */ @@ -165,9 +159,6 @@ class Plugin extends WP_Session_Tokens { /** * Update a session by its verifier. * - * @since 0.1 - * @access protected - * * @param string $verifier Verifier of the session to update. * @param array $session Optional. Session. Omitting this argument destroys the session. */ @@ -186,9 +177,6 @@ class Plugin extends WP_Session_Tokens { /** * Update a user's sessions in Redis. * - * @since 0.1 - * @access protected - * * @param array $sessions Sessions. */ protected function update_sessions( $sessions ) { @@ -196,10 +184,6 @@ class Plugin extends WP_Session_Tokens { return; } - if ( ! has_filter( 'attach_session_information' ) ) { - $sessions = wp_list_pluck( $sessions, 'expiration' ); - } - $key = $this->get_key(); if ( $sessions ) { @@ -212,9 +196,6 @@ class Plugin extends WP_Session_Tokens { /** * Destroy all session tokens for a user, except a single session passed. * - * @since 0.1 - * @access protected - * * @param string $verifier Verifier of the session to keep. */ protected function destroy_other_sessions( $verifier ) { @@ -224,9 +205,6 @@ class Plugin extends WP_Session_Tokens { /** * Destroy all session tokens for a user. - * - * @since 0.1 - * @access protected */ protected function destroy_all_sessions() { $this->update_sessions( array() ); @@ -235,10 +213,6 @@ class Plugin extends WP_Session_Tokens { /** * Destroy all session tokens for all users. * - * @since 0.1 - * @access public - * @static - * * @return bool */ public static function drop_sessions() { @@ -248,9 +222,6 @@ class Plugin extends WP_Session_Tokens { /** * Empty database, clearing all tokens. * - * @since 0.2 - * @access protected - * * @return bool */ protected function flush_redis_db() { @@ -258,10 +229,7 @@ class Plugin extends WP_Session_Tokens { } /** - * Build key for current user - * - * @since 0.1 - * @access protected + * Build key for current user. * * @return string */ diff --git a/languages/redis-user-session-storage.pot b/languages/redis-user-session-storage.pot index 0eb5f2db532cb812d135870b68889897a138b321..75009fa459e37dd8cd9cdc53aab94cd1bd41ccce 100644 --- a/languages/redis-user-session-storage.pot +++ b/languages/redis-user-session-storage.pot @@ -5,7 +5,7 @@ msgstr "" "Project-Id-Version: Redis User Session Storage 0.2\n" "Report-Msgid-Bugs-To: " "https://wordpress.org/support/plugin/redis-user-session-storage\n" -"POT-Creation-Date: 2022-07-09 03:45:24+00:00\n" +"POT-Creation-Date: 2022-07-09 20:23:47+00:00\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" diff --git a/phpcs.xml b/phpcs.xml index e41bee18e8bcd39874a217fd866ec735c07980f2..04859b2ff96c6f715514f82f798e6015db5166e6 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -32,7 +32,7 @@ <rule ref="WordPress.NamingConventions.PrefixAllGlobals"> <properties> <!-- Value: replace the function, class, and variable prefixes used. Separate multiple prefixes with a comma. --> - <property name="prefixes" type="array" value="redis_user_session_storage,wp_redis_user_session_storage"/> + <property name="prefixes" type="array" value="redis_user_session_storage,wp_redis_user_session"/> </properties> </rule> <rule ref="WordPress.WP.I18n"> diff --git a/phpunit.xml b/phpunit.xml index 16a39027e72be2cf0a2656056074b6e6ed818be1..a76c2f2178cf14a55b734a9de28be696aa17a5b9 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -8,9 +8,9 @@ convertWarningsToExceptions="true" > <testsuites> - <testsuite> - <directory prefix="test-" suffix=".php">./tests/</directory> - <exclude>./tests/test-sample.php</exclude> + <testsuite name="wpruss"> + <directory suffix=".php">./tests/</directory> + <exclude>./tests/bootstrap.php</exclude> </testsuite> </testsuites> </phpunit> diff --git a/readme.txt b/readme.txt index 3ec3b397dcfc1475ae433f23544b0b8f1389b8a1..59aafad0e400d5c5326702d247ef4b802da826a4 100644 --- a/readme.txt +++ b/readme.txt @@ -45,7 +45,7 @@ Install and activate this plugin, then deactivate the old plugin. Both plugins c == Changelog == = 0.2 = -* Rename plugin to `Redis User Session Storage` to submit to WordPress.org plugins repository. +* Rename plugin to `Redis User Session Storage` to comply with WordPress.org plugin-naming requirements. * Allow two versions of this plugin to co-exist safely to support seamless migration. * Changes plugin class name to `Redis_User_Session_Storage` from `WP_Redis_User_Session_Storage`. diff --git a/tests/bootstrap.php b/tests/bootstrap.php index f838a17324fb9d11ace8eb00e2902b3cd4b8acfd..b8985bb10f91380244117b3be4a452a5cdd2fc93 100755 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -29,3 +29,8 @@ tests_add_filter( 'muplugins_loaded', 'redis_user_session_storage_tests_manually // Start up the WP testing environment. require $redis_user_session_storage . '/includes/bootstrap.php'; + +// Set Redis host for CI. +if ( ! defined( 'WP_REDIS_USER_SESSION_HOST' ) ) { + define( 'WP_REDIS_USER_SESSION_HOST', 'redis' ); +} diff --git a/tests/inc/class-test-plugin.php b/tests/inc/class-test-plugin.php new file mode 100755 index 0000000000000000000000000000000000000000..c92a1cccbbac4d894191ab844bc61eba16745497 --- /dev/null +++ b/tests/inc/class-test-plugin.php @@ -0,0 +1,430 @@ +<?php +/** + * Test plugin features. + * + * @package Redis_User_Session_Storage + */ + +namespace Redis_User_Session_Storage\Tests\Inc; + +use Redis; +use Redis_User_Session_Storage\Plugin; +use ReflectionClass; +use WP_Session_Tokens; +use WP_UnitTestCase; + +/** + * Tests for main plugin class. + * + * @coversDefaultClass \Redis_User_Session_Storage\Plugin + */ +class Test_Plugin extends WP_UnitTestCase { + /** + * Clear stored sessions after each test, as factory can create user with + * same ID as previous test. + */ + public function tear_down() { + parent::tear_down(); + + $this->_invoke_method( 0, 'flush_redis_db' ); + } + + /** + * Test construction. + * + * @covers ::__construct() + * @return void + */ + public function test__construct() { + $user_id = $this->factory->user->create(); + $object = new Plugin( $user_id ); + + $this->assertInstanceOf( + WP_Session_Tokens::class, + $object, + 'Failed to assert that plugin class is an instance of `WP_Session_Tokens`.' + ); + + $this->assertEquals( 'wpruss', $object->prefix ); + + $this->assertTrue( + $this->_get_property( $user_id, 'redis_connected' ), + 'Failed to assert that Redis is connected.' + ); + + $this->assertInstanceOf( + Redis::class, + $this->_get_property( $user_id, 'redis' ), + 'Failed to assert that Redis client is an instance of `Redis`.' + ); + } + + /** + * Test `get_sessions()` method. + * + * @covers ::get_sessions() + * @return void + */ + public function test_get_sessions() { + $user_id = $this->factory->user->create(); + $plugin = new Plugin( $user_id ); + + $this->assertEmpty( + $this->_invoke_method( $user_id, 'get_sessions' ), + 'Failed to assert that no sessions are returned before user logs in.' + ); + + $plugin->create( time() + 60 ); + + $this->assertNotEmpty( + $this->_invoke_method( $user_id, 'get_sessions' ), + 'Failed to assert that session token is stored in Redis.' + ); + } + + /** + * Test `prepare_session()` method. + * + * @covers ::prepare_session() + * @return void + */ + public function test_prepare_session() { + $this->assertEquals( + array( + 'expiration' => 1, + ), + $this->_invoke_method( + 0, + 'prepare_session', + array( + 1, + ) + ), + 'Failed to assert that session data is transformed as expected.' + ); + + $test_data = array( + 'expiration' => 2, + 'foo' => 'bar', + ); + + $this->assertEquals( + $test_data, + $this->_invoke_method( + 0, + 'prepare_session', + array( + $test_data, + ) + ), + 'Failed to assert that session data is not transformed if it is already prepared.' + ); + } + + /** + * Test `get_session()` method. + * + * @covers ::get_session() + * @return void + */ + public function test_get_session() { + $user_id = $this->factory->user->create(); + $plugin = new Plugin( $user_id ); + + $this->assertEmpty( + $this->_invoke_method( + $user_id, + 'get_session', + array( + 'abcdef0123456789', + ) + ), + 'Failed to assert that arbitrary verifier does not return a session.' + ); + + $expiration = time() + 60; + + $plugin->create( $expiration ); + $tokens = $this->_invoke_method( $user_id, 'get_sessions' ); + $verifier = array_keys( $tokens )[0]; + + $session_data = $this->_invoke_method( + $user_id, + 'get_session', + array( + $verifier, + ) + ); + + $this->assertEquals( + $session_data['expiration'], + $expiration, + 'Failed to assert that session expiration is stored in Redis.' + ); + } + + /** + * Test `update_session()` method. + * + * @covers ::update_session() + * @covers ::update_sessions() + * @return void + */ + public function test_update_session() { + $user_id = $this->factory->user->create(); + $plugin = new Plugin( $user_id ); + + $plugin->create( time() + 60 ); + + $sessions = $this->_invoke_method( $user_id, 'get_sessions' ); + $verifier = array_keys( $sessions )[0]; + + $this->assertNotEmpty( + $sessions, + 'Failed to assert that session was created.' + ); + + $this->_invoke_method( + $user_id, + 'update_session', + array( + $verifier, + ) + ); + + $this->assertEmpty( + $this->_invoke_method( + $user_id, + 'get_session', + array( + $verifier, + ) + ), + 'Failed to assert that session is not destroyed when no session data is provided.' + ); + + $plugin->create( time() + 60 ); + + $sessions = $this->_invoke_method( $user_id, 'get_sessions' ); + $verifier = array_keys( $sessions )[0]; + $session_data = array( + 'expiration' => time() + 60, + 'foo' => 'bar', + ); + + $this->_invoke_method( + $user_id, + 'update_session', + array( + $verifier, + $session_data, + ) + ); + + $this->assertEquals( + $session_data, + $this->_invoke_method( + $user_id, + 'get_session', + array( + $verifier, + ) + ), + 'Failed to assert that session is updated when session data is provided.' + ); + } + + /** + * Test `destroy_other_sessions()` method. + * + * @covers ::destroy_other_sessions() + * @return void + */ + public function test_destroy_other_sessions() { + $user_id = $this->factory->user->create(); + $plugin = new Plugin( $user_id ); + + $plugin->create( time() + 60 ); + $plugin->create( time() + 120 ); + $plugin->create( time() + 180 ); + + $sessions = $this->_invoke_method( $user_id, 'get_sessions' ); + + $this->assertCount( + 3, + $sessions, + 'Failed to assert that multiple sessions were created.' + ); + + $verifier = array_keys( $sessions )[0]; + + $this->_invoke_method( + $user_id, + 'destroy_other_sessions', + array( + $verifier, + ) + ); + + $this->assertCount( + 1, + $this->_invoke_method( + $user_id, + 'get_sessions' + ), + 'Failed to assert that other sessions are destroyed.' + ); + } + + /** + * Test `destroy_all_sessions()` method. + * + * @covers ::destroy_all_sessions() + * @return void + */ + public function test_destroy_all_sessions() { + $user_id = $this->factory->user->create(); + $plugin = new Plugin( $user_id ); + + $plugin->create( time() + 60 ); + $plugin->create( time() + 120 ); + $plugin->create( time() + 180 ); + + $sessions = $this->_invoke_method( $user_id, 'get_sessions' ); + + $this->assertCount( + 3, + $this->_invoke_method( + $user_id, + 'get_sessions' + ), + 'Failed to assert that multiple sessions were created.' + ); + + $this->_invoke_method( + $user_id, + 'destroy_all_sessions' + ); + + $this->assertEmpty( + $this->_invoke_method( + $user_id, + 'get_sessions' + ), + 'Failed to assert that all sessions were destroyed.' + ); + } + + /** + * Test `drop_sessions()` method. + * + * @covers ::drop_sessions() + * @covers ::flush_redis_db() + * @return void + */ + public function test_drop_sessions() { + $user_1 = $this->factory->user->create(); + $plugin_user_1 = new Plugin( $user_1 ); + $user_2 = $this->factory->user->create(); + $plugin_user_2 = new Plugin( $user_2 ); + + $plugin_user_1->create( time() + 60 ); + $plugin_user_1->create( time() + 120 ); + $plugin_user_1->create( time() + 180 ); + $plugin_user_2->create( time() + 60 ); + $plugin_user_2->create( time() + 120 ); + $plugin_user_2->create( time() + 180 ); + + $this->assertCount( + 3, + $this->_invoke_method( + $user_1, + 'get_sessions' + ), + 'Failed to assert that multiple sessions were created for user 1.' + ); + + $this->assertCount( + 3, + $this->_invoke_method( + $user_2, + 'get_sessions' + ), + 'Failed to assert that multiple sessions were created for user 2.' + ); + + $this->_invoke_method( + $user_1, + 'flush_redis_db' + ); + + $this->assertEmpty( + $this->_invoke_method( + $user_1, + 'get_sessions' + ), + 'Failed to assert that sessions were destroyed for user 1.' + ); + + $this->assertEmpty( + $this->_invoke_method( + $user_2, + 'get_sessions' + ), + 'Failed to assert that sessions were destroyed for user 2.' + ); + } + + /** + * Test `get_key()` method. + * + * @covers ::get_key() + * @return void + */ + public function test_get_key() { + $user_id = $this->factory->user->create(); + $plugin = new Plugin( $user_id ); + + $this->assertEquals( + $plugin->prefix . ':' . $user_id, + $this->_invoke_method( $user_id, 'get_key' ) + ); + } + + /** + * Invoke a non-public class method. + * + * @param int $user_id WP User ID. + * @param string $method_name Method name. + * @param array $args Method arguments. + * @return mixed + */ + protected function _invoke_method( + $user_id, + $method_name, + $args = array() + ) { + $object = new Plugin( $user_id ); + $reflection = new ReflectionClass( $object ); + $method = $reflection->getMethod( $method_name ); + $method->setAccessible( true ); + + return $method->invokeArgs( $object, $args ); + } + + /** + * Get value of non-public property. + * + * @param int $user_id WP User ID. + * @param string $property_name Property name. + * @return mixed + */ + protected function _get_property( $user_id, $property_name ) { + $object = new Plugin( $user_id ); + $reflection = new ReflectionClass( $object ); + $property = $reflection->getProperty( $property_name ); + $property->setAccessible( true ); + + return $property->getValue( $object ); + } +} diff --git a/tests/test-sample.php b/tests/test-sample.php deleted file mode 100755 index c8f05ed5bd8bfe159a2d1b5efe3a96e2dbf30198..0000000000000000000000000000000000000000 --- a/tests/test-sample.php +++ /dev/null @@ -1,20 +0,0 @@ -<?php -/** - * Class SampleTest - * - * @package Redis_User_Session_Storage - */ - -/** - * Sample test case. - */ -class SampleTest extends WP_UnitTestCase { - - /** - * A single example test. - */ - public function test_sample() { - // Replace this with some actual testing code. - $this->assertTrue( true ); - } -}