From c4a9a1a24f172eb1de9ea6258eda7a4f919e3bdb Mon Sep 17 00:00:00 2001 From: Ivaylo Mutafov Date: Fri, 1 Sep 2023 10:25:38 +0300 Subject: [PATCH 1/7] Added support for Laravel 10.x (#15) --- composer.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index f2947ef..33a2981 100644 --- a/composer.json +++ b/composer.json @@ -2,12 +2,11 @@ "name": "1ff/laravel-mongodb-session", "description": "A mongodb session driver for laravel", "type": "library", - "version": "5.0.4", + "version": "5.0.0", "require": { "php": "^8.1", "illuminate/session": "^10.0", - "mongodb/laravel-mongodb": "^4.0", - "ext-mongodb": "*" + "mongodb/laravel-mongodb": "dev-master" }, "license": "MIT", From acbcc6810833697df8605d9c1d0f8cac343c3e3d Mon Sep 17 00:00:00 2001 From: Ivaylo Mutafov Date: Tue, 5 Sep 2023 14:19:22 +0300 Subject: [PATCH 2/7] Updated mongodb/laravel-mongodb package (#16) --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 33a2981..f466c5e 100644 --- a/composer.json +++ b/composer.json @@ -2,11 +2,11 @@ "name": "1ff/laravel-mongodb-session", "description": "A mongodb session driver for laravel", "type": "library", - "version": "5.0.0", + "version": "5.0.1", "require": { "php": "^8.1", "illuminate/session": "^10.0", - "mongodb/laravel-mongodb": "dev-master" + "mongodb/laravel-mongodb": "4.0.0-ALPHA2" }, "license": "MIT", From 9a51554ad57f8aabc2623323dc323dff7b7939b9 Mon Sep 17 00:00:00 2001 From: Ivelin Ivanov <9060426+ivosgem@users.noreply.github.com> Date: Wed, 5 Feb 2025 15:56:15 +0200 Subject: [PATCH 3/7] Refactor method signatures in MongoDbSessionHandler for clarity and type safety. Add .editorconfig for consistent coding style across files. Update composer.json to include ext-mongodb requirement. (#23) --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index f466c5e..d833c6c 100644 --- a/composer.json +++ b/composer.json @@ -6,7 +6,8 @@ "require": { "php": "^8.1", "illuminate/session": "^10.0", - "mongodb/laravel-mongodb": "4.0.0-ALPHA2" + "mongodb/laravel-mongodb": "4.0.0-ALPHA2", + "ext-mongodb": "*" }, "license": "MIT", From 73395e6abbe85794256951c5812c082b4ac2eb67 Mon Sep 17 00:00:00 2001 From: Ivaylo Mutafov Date: Wed, 5 Feb 2025 16:32:49 +0200 Subject: [PATCH 4/7] V5.x rebase (#25) * v5.x to master (#17) * Added support for Laravel 10.x (#15) * Updated mongodb/laravel-mongodb package (#16) # Conflicts: # composer.json * Update laravel mongodb to rc1 (#18) * Added support for Laravel 10.x (#15) * Updated mongodb/laravel-mongodb package (#16) * Updated mongodb/laravel-mongodb to rc1. * Updated mongodb/laravel-mongodb to stable version 4. (#19) * Changed package version --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index d833c6c..f2947ef 100644 --- a/composer.json +++ b/composer.json @@ -2,11 +2,11 @@ "name": "1ff/laravel-mongodb-session", "description": "A mongodb session driver for laravel", "type": "library", - "version": "5.0.1", + "version": "5.0.4", "require": { "php": "^8.1", "illuminate/session": "^10.0", - "mongodb/laravel-mongodb": "4.0.0-ALPHA2", + "mongodb/laravel-mongodb": "^4.0", "ext-mongodb": "*" }, From 175002706e03e0fb3abf36a534eb33593f0473a0 Mon Sep 17 00:00:00 2001 From: Ivelin Ivanov <9060426+ivosgem@users.noreply.github.com> Date: Fri, 25 Apr 2025 13:54:40 +0300 Subject: [PATCH 5/7] Update deprecated MongoDB read preference constants to use current values (#28) * Update deprecated MongoDB read preference constants to use current values * Bump version to 5.0.5 in composer.json for updated dependencies * Update session testing suite, add MongoDB test cases, and configure PHPUnit - Enhance `.gitignore` to exclude `.phpunit.cache`. - Update GitHub workflow to include Testbench version for Laravel 10.x. - Create new feature tests: `TestHelperIntegrationTest`, `HttpSessionTest`, and `MongoDbSessionHandlerTest` to validate session handling with MongoDB. - Refactor MongoDB session command files to remove unnecessary docblocks. - Document testing process in `README.md`, including setup and expected results. - Add basic PHPUnit configuration file. - Define session environment in the base `TestCase`. - Ensure session operations like reading, writing, and destruction are tested against MongoDB. * Update GitHub Actions workflow to use MongoDB 7 and improve caching - Add MongoDB 7 service to CI workflow - Upgrade checkout action to v3 - Include MongoDB extension in PHP setup - Implement Composer dependency caching for faster builds - Modify composer install command for better performance - Set environment variables for MongoDB connection during test execution - Update README.md to reflect changes in the CI process * Remove deprecated MongoDB version constraint from composer.json --- .github/workflows/run-tests-l10.yml | 38 +++++- .gitignore | 3 +- README.md | 68 +++++++++++ composer.json | 14 ++- phpunit.xml | 27 ++++ .../Commands/MongodbSessionDropIndex.php | 24 +--- src/Console/Commands/MongodbSessionIndex.php | 24 +--- ...0000_index_mongodb_sessions_collection.php | 4 +- tests/Feature/HttpSessionTest.php | 89 ++++++++++++++ tests/Feature/MongoDbSessionHandlerTest.php | 101 +++++++++++++++ tests/Feature/TestHelperIntegrationTest.php | 76 ++++++++++++ tests/TestCase.php | 62 ++++++++++ tests/Unit/MongoDbSessionHandlerTest.php | 115 ++++++++++++++++++ 13 files changed, 601 insertions(+), 44 deletions(-) create mode 100644 phpunit.xml create mode 100644 tests/Feature/HttpSessionTest.php create mode 100644 tests/Feature/MongoDbSessionHandlerTest.php create mode 100644 tests/Feature/TestHelperIntegrationTest.php create mode 100644 tests/TestCase.php create mode 100644 tests/Unit/MongoDbSessionHandlerTest.php diff --git a/.github/workflows/run-tests-l10.yml b/.github/workflows/run-tests-l10.yml index 741ad2d..1f93cbe 100644 --- a/.github/workflows/run-tests-l10.yml +++ b/.github/workflows/run-tests-l10.yml @@ -11,6 +11,18 @@ jobs: tests: runs-on: ubuntu-latest + + services: + mongodb: + image: mongo:7 + ports: + - 27017:27017 + options: >- + --health-cmd="mongosh --quiet --eval 'db.runCommand({ping:1})'" + --health-interval=10s + --health-timeout=5s + --health-retries=3 + strategy: fail-fast: false matrix: @@ -18,18 +30,38 @@ jobs: laravel: [ 10.* ] include: - laravel: 10.* + testbench: 10.* name: P${{ matrix.php }} - L${{ matrix.laravel }} steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Setup PHP uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} - extensions: pdo, sqlite, pdo_sqlite + extensions: pdo, sqlite, pdo_sqlite, mongodb + coverage: none + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache dependencies + uses: actions/cache@v3 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- - name: Install Dependencies - run: composer install + run: composer install --prefer-dist --no-interaction --no-progress + + - name: Execute tests + run: vendor/bin/phpunit + env: + MONGODB_HOST: 127.0.0.1 + MONGODB_PORT: 27017 + MONGODB_DATABASE: laravel_session_test diff --git a/.gitignore b/.gitignore index dfd6caa..b868185 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /vendor -composer.lock \ No newline at end of file +composer.lock +.phpunit.cache diff --git a/README.md b/README.md index 5db9bf9..3fb89ec 100644 --- a/README.md +++ b/README.md @@ -34,3 +34,71 @@ Advantages Enjoy! ------ + +## Testing + +This package includes a comprehensive test suite to ensure the MongoDB session handler works correctly. The tests cover: + +1. Basic session operations (read, write, destroy) +2. Integration with Laravel's session system +3. HTTP session functionality +4. Laravel's testing helpers integration + +### Running the Tests + +To run the tests, follow these steps: + +1. Make sure MongoDB is installed and running on your system +2. Install the package dependencies with Composer: + +```bash +composer install +``` + +3. Run the tests with PHPUnit: + +```bash +vendor/bin/phpunit +``` + +### Continuous Integration + +The package includes a GitHub Actions workflow that automatically runs tests on PHP 8.1 with Laravel 10.x against MongoDB 7. The workflow: + +1. Sets up a MongoDB service container +2. Installs PHP with MongoDB extension +3. Caches Composer dependencies for faster builds +4. Runs the test suite + +This ensures all tests pass before merging new changes. + +### Expected Test Results + +When all tests are passing, you should see output similar to: + +``` +PHPUnit 10.x.x by Sebastian Bergmann and contributors. + +............... 15 / 15 (100%) + +Time: 00:00.444, Memory: 32.00 MB + +OK (15 tests, 41 assertions) +``` + +### Testing Environments + +The tests are compatible with: + +- PHP 8.1+ +- Laravel 10.x +- MongoDB 4.0+ + +### Test Coverage + +- **Unit Tests**: These test the `MongoDbSessionHandler` methods directly (open, close, read, write, destroy, gc) +- **Feature Tests**: These test the integration with Laravel's session functionality +- **HTTP Tests**: These test session handling in HTTP requests and session persistence +- **Laravel Helper Tests**: These test integration with Laravel's testing helpers like `withSession` and `flushSession` + +If you encounter any issues with the tests, please submit an issue on the GitHub repository. diff --git a/composer.json b/composer.json index f2947ef..459bdda 100644 --- a/composer.json +++ b/composer.json @@ -2,14 +2,16 @@ "name": "1ff/laravel-mongodb-session", "description": "A mongodb session driver for laravel", "type": "library", - "version": "5.0.4", "require": { "php": "^8.1", "illuminate/session": "^10.0", "mongodb/laravel-mongodb": "^4.0", "ext-mongodb": "*" }, - + "require-dev": { + "phpunit/phpunit": "^10.0", + "orchestra/testbench": "^8.0" + }, "license": "MIT", "authors": [ { @@ -27,11 +29,19 @@ "ForFit\\Session\\": "src" } }, + "autoload-dev": { + "psr-4": { + "ForFit\\Session\\Tests\\": "tests" + } + }, "extra": { "laravel": { "providers": [ "ForFit\\Session\\SessionServiceProvider" ] } + }, + "scripts": { + "test": "vendor/bin/phpunit" } } diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..41f3b6a --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,27 @@ + + + + + ./tests/Unit + + + ./tests/Feature + + + + + + + + + \ No newline at end of file diff --git a/src/Console/Commands/MongodbSessionDropIndex.php b/src/Console/Commands/MongodbSessionDropIndex.php index 72ce1d7..d506777 100644 --- a/src/Console/Commands/MongodbSessionDropIndex.php +++ b/src/Console/Commands/MongodbSessionDropIndex.php @@ -4,7 +4,7 @@ use Illuminate\Console\Command; use Illuminate\Support\Facades\DB; -use \MongoDB\Driver\ReadPreference; +use MongoDB\Driver\ReadPreference; /** * Drop the indexes created by MongodbSessionIndex @@ -12,26 +12,14 @@ class MongodbSessionDropIndex extends Command { - /** - * The name and signature of the console command. - * - * @var string - */ + /** The name and signature of the console command. */ protected $signature = 'mongodb:session:dropindex {index}'; - /** - * The console command description. - * - * @var string - */ + /** The console command description. */ protected $description = 'Drops the passed index from the mongodb `sessions` collection'; - /** - * Execute the console command. - * - * @return mixed - */ - public function handle() + /** Execute the console command. */ + public function handle(): void { $collection = config('session.table'); @@ -39,7 +27,7 @@ public function handle() 'dropIndexes' => $collection, 'index' => $this->argument('index'), ], [ - 'readPreference' => new ReadPreference(ReadPreference::RP_PRIMARY) + 'readPreference' => new ReadPreference(ReadPreference::PRIMARY) ]); } } diff --git a/src/Console/Commands/MongodbSessionIndex.php b/src/Console/Commands/MongodbSessionIndex.php index 9b909d5..4ee93be 100644 --- a/src/Console/Commands/MongodbSessionIndex.php +++ b/src/Console/Commands/MongodbSessionIndex.php @@ -4,7 +4,7 @@ use Illuminate\Console\Command; use Illuminate\Support\Facades\DB; -use \MongoDB\Driver\ReadPreference; +use MongoDB\Driver\ReadPreference; /** * Create indexes for the Session collection @@ -12,26 +12,14 @@ class MongodbSessionIndex extends Command { - /** - * The name and signature of the console command. - * - * @var string - */ + /** The name and signature of the console command. */ protected $signature = 'mongodb:session:index'; - /** - * The console command description. - * - * @var string - */ + /** The console command description. */ protected $description = 'Create indexes on the mongodb `sessions` collection'; - /** - * Execute the console command. - * - * @return mixed - */ - public function handle() + /** Execute the console command. */ + public function handle(): void { $collection = config('session.table'); @@ -46,7 +34,7 @@ public function handle() ] ] ], [ - 'readPreference' => new ReadPreference(ReadPreference::RP_PRIMARY) + 'readPreference' => new ReadPreference(ReadPreference::PRIMARY) ]); } } diff --git a/src/Database/Migrations/2019_08_01_000000_index_mongodb_sessions_collection.php b/src/Database/Migrations/2019_08_01_000000_index_mongodb_sessions_collection.php index 917bec4..7b4c696 100644 --- a/src/Database/Migrations/2019_08_01_000000_index_mongodb_sessions_collection.php +++ b/src/Database/Migrations/2019_08_01_000000_index_mongodb_sessions_collection.php @@ -11,7 +11,7 @@ class IndexMongodbSessionsCollection extends Migration * * @return void */ - public function up() + public function up(): void { Artisan::call('mongodb:session:index'); } @@ -21,7 +21,7 @@ public function up() * * @return void */ - public function down() + public function down(): void { Artisan::call('mongodb:session:dropindex', ['index' => 'expires_at_ttl']); } diff --git a/tests/Feature/HttpSessionTest.php b/tests/Feature/HttpSessionTest.php new file mode 100644 index 0000000..f103e62 --- /dev/null +++ b/tests/Feature/HttpSessionTest.php @@ -0,0 +1,89 @@ +app['router']->get('/test-session', function () { + // Returns the session data for verification + return response()->json([ + 'session_data' => session()->all(), + ]); + }); + + // Make request with session data + $response = $this->withSession(['test_key' => 'test_value']) + ->get('/test-session'); + + $response->assertOk(); + $responseData = $response->json(); + + // Verify that the session data was properly stored and retrieved + $this->assertArrayHasKey('test_key', $responseData['session_data']); + $this->assertEquals('test_value', $responseData['session_data']['test_key']); + } + + /** + * Test session persistence between requests + */ + public function test_session_persists_between_requests(): void + { + // Create routes for testing + $this->app['router']->get('/set-session', function () { + session(['persisted_key' => 'persisted_value']); + return response()->json(['status' => 'session_set']); + }); + + $this->app['router']->get('/get-session', function () { + return response()->json([ + 'session_data' => session()->all(), + ]); + }); + + // First request to set the session + $this->get('/set-session')->assertOk(); + + // Second request to verify the session persists + $response = $this->get('/get-session'); + $response->assertOk(); + + $responseData = $response->json(); + $this->assertArrayHasKey('persisted_key', $responseData['session_data']); + $this->assertEquals('persisted_value', $responseData['session_data']['persisted_key']); + } + + /** + * Test session exists during requests + */ + public function test_session_data_in_request(): void + { + // Since we can't verify session in the request with `request()->hasSession()`, + // we'll test with the session facade instead + $this->app['router']->get('/session-test', function () { + return response()->json([ + 'has_session_facade' => session()->isStarted(), + 'session_data' => session()->all(), + ]); + }); + + // Make request with session data + $response = $this->withSession(['auth_test' => 'auth_value']) + ->get('/session-test'); + + $response->assertOk(); + $responseData = $response->json(); + + // Verify session data is present + $this->assertArrayHasKey('session_data', $responseData); + $this->assertArrayHasKey('auth_test', $responseData['session_data']); + $this->assertEquals('auth_value', $responseData['session_data']['auth_test']); + } +} diff --git a/tests/Feature/MongoDbSessionHandlerTest.php b/tests/Feature/MongoDbSessionHandlerTest.php new file mode 100644 index 0000000..fd67ec3 --- /dev/null +++ b/tests/Feature/MongoDbSessionHandlerTest.php @@ -0,0 +1,101 @@ +assertEquals('mongodb', config('session.driver')); + $this->assertInstanceOf(MongoDbSessionHandler::class, $this->app['session.store']->getHandler()); + } + + /** + * Test storing and retrieving session data + */ + public function test_session_store_and_retrieve(): void + { + // Set session data + Session::put('key1', 'value1'); + Session::put('key2', ['nested' => 'value2']); + + // Force session to be stored + Session::save(); + + // Clear the session from memory to force a reload from storage + Session::flush(); + + // Start a new session to read from storage + Session::start(); + + // Check that the values were correctly retrieved + $this->assertEquals('value1', Session::get('key1')); + $this->assertEquals(['nested' => 'value2'], Session::get('key2')); + } + + /** + * Test session data is correctly saved in MongoDB + */ + public function test_session_is_saved_in_mongodb(): void + { + // Generate a unique session ID + $sessionId = md5(uniqid()); + + // Create a session directly in the database + $this->app['db']->table(config('session.table'))->insert([ + '_id' => $sessionId, + 'payload' => new Binary('a:1:{s:4:"test";s:5:"value";}', Binary::TYPE_OLD_BINARY), + 'last_activity' => new \MongoDB\BSON\UTCDateTime(now()->timestamp * 1000), + 'expires_at' => new \MongoDB\BSON\UTCDateTime((now()->addMinutes(config('session.lifetime'))->timestamp) * 1000), + ]); + + // Manually retrieve session through the handler + $handler = $this->app['session.store']->getHandler(); + $data = $handler->read($sessionId); + + // Decode the session data + $sessionData = @unserialize($data); + + $this->assertEquals(['test' => 'value'], $sessionData); + } + + /** + * Test session destroy functionality + */ + public function test_session_can_be_destroyed(): void + { + // Set a value in the session + Session::put('key', 'value'); + $sessionId = Session::getId(); + + // Force save to database + Session::save(); + + // Verify it exists in the database + $count = $this->app['db']->table(config('session.table')) + ->where('_id', $sessionId) + ->count(); + $this->assertEquals(1, $count); + + // Get the handler and explicitly destroy the session + $handler = $this->app['session.store']->getHandler(); + $handler->destroy($sessionId); + + // Allow a moment for the delete operation to complete + usleep(100000); // 100ms pause + + // Verify it was removed from the database + $count = $this->app['db']->table(config('session.table')) + ->where('_id', $sessionId) + ->count(); + $this->assertEquals(0, $count); + } +} \ No newline at end of file diff --git a/tests/Feature/TestHelperIntegrationTest.php b/tests/Feature/TestHelperIntegrationTest.php new file mode 100644 index 0000000..785608a --- /dev/null +++ b/tests/Feature/TestHelperIntegrationTest.php @@ -0,0 +1,76 @@ + 'value2']); + + // Get the session ID before it's saved + $sessionId = Session::getId(); + + // Explicitly save the session + Session::save(); + + // Create a test route + $this->app['router']->get('/session-helper-test', function () { + return response()->json([ + 'session_data' => session()->all(), + ]); + }); + + // Make a request to access the session + $response = $this->get('/session-helper-test'); + $response->assertOk(); + + // Verify session data was stored in MongoDB + $sessionRecord = $this->app['db']->table(config('session.table')) + ->where('_id', $sessionId) + ->first(); + + $this->assertNotNull($sessionRecord, 'Session record was not found in MongoDB'); + + // Verify session data + $responseData = $response->json(); + $this->assertArrayHasKey('test_key1', $responseData['session_data']); + $this->assertEquals('test_value1', $responseData['session_data']['test_key1']); + $this->assertArrayHasKey('test_key2', $responseData['session_data']); + $this->assertEquals(['nested' => 'value2'], $responseData['session_data']['test_key2']); + } + + /** + * Test that Laravel's flushSession helper works with MongoDB sessions + */ + public function test_flush_session_helper(): void + { + // Create a test route + $this->app['router']->get('/flush-session-test', function () { + return response()->json([ + 'session_data' => session()->all(), + ]); + }); + + // Set some session data + $response = $this->withSession(['to_be_flushed' => 'value']) + ->get('/flush-session-test'); + + $response->assertOk(); + $this->assertArrayHasKey('to_be_flushed', $response->json()['session_data']); + + // Flush the session and verify it's empty + $response = $this->flushSession()->get('/flush-session-test'); + + $response->assertOk(); + $this->assertEmpty($response->json()['session_data']); + } +} \ No newline at end of file diff --git a/tests/TestCase.php b/tests/TestCase.php new file mode 100644 index 0000000..76094e8 --- /dev/null +++ b/tests/TestCase.php @@ -0,0 +1,62 @@ +artisan('mongodb:session:index'); + } + + /** + * Define environment setup. + * + * @param \Illuminate\Foundation\Application $app + * @return void + */ + protected function defineEnvironment($app): void + { + // Setup default database to use MongoDB + $app['config']->set('database.default', 'mongodb'); + $app['config']->set('database.connections.mongodb', [ + 'driver' => 'mongodb', + 'host' => env('MONGODB_HOST', '127.0.0.1'), + 'port' => env('MONGODB_PORT', 27017), + 'database' => env('MONGODB_DATABASE', 'laravel_session_test'), + 'username' => env('MONGODB_USERNAME', ''), + 'password' => env('MONGODB_PASSWORD', ''), + 'options' => [ + 'database' => env('MONGODB_AUTHENTICATION_DATABASE', 'admin'), + ], + ]); + + // Configure session to use MongoDB driver + $app['config']->set('session.driver', 'mongodb'); + $app['config']->set('session.lifetime', 120); + $app['config']->set('session.table', 'sessions'); + } + + /** + * Get package providers. + * + * @param \Illuminate\Foundation\Application $app + * @return array + */ + protected function getPackageProviders($app): array + { + return [ + MongoDBServiceProvider::class, + SessionServiceProvider::class, + ]; + } +} \ No newline at end of file diff --git a/tests/Unit/MongoDbSessionHandlerTest.php b/tests/Unit/MongoDbSessionHandlerTest.php new file mode 100644 index 0000000..2c2c784 --- /dev/null +++ b/tests/Unit/MongoDbSessionHandlerTest.php @@ -0,0 +1,115 @@ +handler = $this->app['session.store']->getHandler(); + $this->sessionId = md5(uniqid('test_session')); + } + + /** + * Test the open method + */ + public function test_open_method(): void + { + $this->assertTrue($this->handler->open('path', 'name')); + } + + /** + * Test the close method + */ + public function test_close_method(): void + { + $this->assertTrue($this->handler->close()); + } + + /** + * Test reading non-existent session + */ + public function test_read_non_existent_session(): void + { + $this->assertEquals('', $this->handler->read('non_existent_id')); + } + + /** + * Test write and read session + */ + public function test_write_and_read_session(): void + { + $data = 'test_data_' . time(); + + // Write session data + $this->assertTrue($this->handler->write($this->sessionId, $data)); + + // Read it back + $readData = $this->handler->read($this->sessionId); + + $this->assertEquals($data, $readData); + + // Check database directly + $session = $this->app['db']->table(config('session.table')) + ->where('_id', $this->sessionId) + ->first(); + + $this->assertNotNull($session); + $this->assertInstanceOf(Binary::class, $session['payload']); + $this->assertInstanceOf(UTCDateTime::class, $session['expires_at']); + $this->assertInstanceOf(UTCDateTime::class, $session['last_activity']); + } + + /** + * Test destroy session + */ + public function test_destroy_session(): void + { + // First write a session + $this->handler->write($this->sessionId, 'test_data'); + + // Verify it exists + $exists = $this->app['db']->table(config('session.table')) + ->where('_id', $this->sessionId) + ->exists(); + $this->assertTrue($exists); + + // Now destroy it + $this->assertTrue($this->handler->destroy($this->sessionId)); + + // Verify it's gone + $exists = $this->app['db']->table(config('session.table')) + ->where('_id', $this->sessionId) + ->exists(); + $this->assertFalse($exists); + } + + /** + * Test garbage collection + */ + public function test_garbage_collection(): void + { + // gc should return a truthy value as it's handled by MongoDB TTL index + $this->assertNotFalse($this->handler->gc(100)); + } +} \ No newline at end of file From 5b283b5aa922015ba6bd508565987f164802cf26 Mon Sep 17 00:00:00 2001 From: Ivelin Ivanov <9060426+ivosgem@users.noreply.github.com> Date: Mon, 28 Apr 2025 16:10:27 +0300 Subject: [PATCH 6/7] Update mongodb/laravel-mongodb package to version 5.0 in composer.json (#27) * Update mongodb/laravel-mongodb package to version 5.0 in composer.json * Update MongoDB commands and improve session handling Refactor the command to use `getDatabase()` instead of `getMongoDB()`. Update payload access in `MongoDbSessionHandler` from array syntax to object syntax for better readability. Adjust test assertions to match the new access methodology and ensure compatibility with Carbon instances for expiration and last activity timestamps. Clean up formatting inconsistencies throughout the code. * Update MongoDB connection method to use getDatabase() instead of getMongoDB() in MongodbSessionIndex command --- composer.json | 2 +- .../Commands/MongodbSessionDropIndex.php | 2 +- src/Console/Commands/MongodbSessionIndex.php | 2 +- src/MongoDbSessionHandler.php | 10 ++--- tests/Unit/MongoDbSessionHandlerTest.php | 44 +++++++++---------- 5 files changed, 30 insertions(+), 30 deletions(-) diff --git a/composer.json b/composer.json index 459bdda..6ef049a 100644 --- a/composer.json +++ b/composer.json @@ -5,7 +5,7 @@ "require": { "php": "^8.1", "illuminate/session": "^10.0", - "mongodb/laravel-mongodb": "^4.0", + "mongodb/laravel-mongodb": "^5.0", "ext-mongodb": "*" }, "require-dev": { diff --git a/src/Console/Commands/MongodbSessionDropIndex.php b/src/Console/Commands/MongodbSessionDropIndex.php index d506777..17eaf94 100644 --- a/src/Console/Commands/MongodbSessionDropIndex.php +++ b/src/Console/Commands/MongodbSessionDropIndex.php @@ -23,7 +23,7 @@ public function handle(): void { $collection = config('session.table'); - DB::connection('mongodb')->getMongoDB()->command([ + DB::connection('mongodb')->getDatabase()->command([ 'dropIndexes' => $collection, 'index' => $this->argument('index'), ], [ diff --git a/src/Console/Commands/MongodbSessionIndex.php b/src/Console/Commands/MongodbSessionIndex.php index 4ee93be..8c29904 100644 --- a/src/Console/Commands/MongodbSessionIndex.php +++ b/src/Console/Commands/MongodbSessionIndex.php @@ -23,7 +23,7 @@ public function handle(): void { $collection = config('session.table'); - DB::connection('mongodb')->getMongoDB()->command([ + DB::connection('mongodb')->getDatabase()->command([ 'createIndexes' => $collection, 'indexes' => [ [ diff --git a/src/MongoDbSessionHandler.php b/src/MongoDbSessionHandler.php index ae34554..507fc46 100644 --- a/src/MongoDbSessionHandler.php +++ b/src/MongoDbSessionHandler.php @@ -2,8 +2,8 @@ namespace ForFit\Session; -use MongoDB\BSON\UTCDateTime; use MongoDB\BSON\Binary; +use MongoDB\BSON\UTCDateTime; use MongoDB\Driver\Exception\BulkWriteException; use SessionHandlerInterface; @@ -14,14 +14,14 @@ class MongoDbSessionHandler implements SessionHandlerInterface protected $table; /** - * @param \Illuminate\Database\ConnectionInterface $connection + * @param \Illuminate\Database\ConnectionInterface $connection * @param string $table * @param integer $minutes */ public function __construct($connection, $table = 'sessions', $minutes = 60) { $this->connection = $connection; - $this->minutes = (int) $minutes; + $this->minutes = (int)$minutes; $this->table = $table; } @@ -48,7 +48,7 @@ public function read($id): false|string { $session = $this->query()->find($id); - return $session ? $session['payload'] : ''; + return $session ? $session->payload : ''; } /** @@ -57,7 +57,7 @@ public function read($id): false|string public function write($id, $data): bool { try { - return (bool) $this->query() + return (bool)$this->query() ->where('_id', $id) ->update($this->buildPayload($data), ['upsert' => true]); } catch (BulkWriteException $exception) { diff --git a/tests/Unit/MongoDbSessionHandlerTest.php b/tests/Unit/MongoDbSessionHandlerTest.php index 2c2c784..a008442 100644 --- a/tests/Unit/MongoDbSessionHandlerTest.php +++ b/tests/Unit/MongoDbSessionHandlerTest.php @@ -4,8 +4,8 @@ use ForFit\Session\MongoDbSessionHandler; use ForFit\Session\Tests\TestCase; +use Illuminate\Support\Carbon; use MongoDB\BSON\Binary; -use MongoDB\BSON\UTCDateTime; class MongoDbSessionHandlerTest extends TestCase { @@ -13,23 +13,23 @@ class MongoDbSessionHandlerTest extends TestCase * @var MongoDbSessionHandler */ protected $handler; - + /** * @var string */ protected $sessionId; - + /** * Set up the test environment. */ protected function setUp(): void { parent::setUp(); - + $this->handler = $this->app['session.store']->getHandler(); $this->sessionId = md5(uniqid('test_session')); } - + /** * Test the open method */ @@ -37,7 +37,7 @@ public function test_open_method(): void { $this->assertTrue($this->handler->open('path', 'name')); } - + /** * Test the close method */ @@ -45,7 +45,7 @@ public function test_close_method(): void { $this->assertTrue($this->handler->close()); } - + /** * Test reading non-existent session */ @@ -53,33 +53,33 @@ public function test_read_non_existent_session(): void { $this->assertEquals('', $this->handler->read('non_existent_id')); } - + /** * Test write and read session */ public function test_write_and_read_session(): void { $data = 'test_data_' . time(); - + // Write session data $this->assertTrue($this->handler->write($this->sessionId, $data)); - + // Read it back $readData = $this->handler->read($this->sessionId); - + $this->assertEquals($data, $readData); - + // Check database directly $session = $this->app['db']->table(config('session.table')) ->where('_id', $this->sessionId) ->first(); - + $this->assertNotNull($session); - $this->assertInstanceOf(Binary::class, $session['payload']); - $this->assertInstanceOf(UTCDateTime::class, $session['expires_at']); - $this->assertInstanceOf(UTCDateTime::class, $session['last_activity']); + $this->assertInstanceOf(Binary::class, $session->payload); + $this->assertInstanceOf(Carbon::class, $session->expires_at); + $this->assertInstanceOf(Carbon::class, $session->last_activity); } - + /** * Test destroy session */ @@ -87,23 +87,23 @@ public function test_destroy_session(): void { // First write a session $this->handler->write($this->sessionId, 'test_data'); - + // Verify it exists $exists = $this->app['db']->table(config('session.table')) ->where('_id', $this->sessionId) ->exists(); $this->assertTrue($exists); - + // Now destroy it $this->assertTrue($this->handler->destroy($this->sessionId)); - + // Verify it's gone $exists = $this->app['db']->table(config('session.table')) ->where('_id', $this->sessionId) ->exists(); $this->assertFalse($exists); } - + /** * Test garbage collection */ @@ -112,4 +112,4 @@ public function test_garbage_collection(): void // gc should return a truthy value as it's handled by MongoDB TTL index $this->assertNotFalse($this->handler->gc(100)); } -} \ No newline at end of file +} From 3cfbab4f704d6c0e403bf9ef8171f4eb86b040d6 Mon Sep 17 00:00:00 2001 From: Ivelin Ivanov <9060426+ivosgem@users.noreply.github.com> Date: Mon, 28 Apr 2025 16:29:19 +0300 Subject: [PATCH 7/7] Update GitHub Actions workflow to trigger on the master branch --- .github/workflows/run-tests-l10.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/run-tests-l10.yml b/.github/workflows/run-tests-l10.yml index 1f93cbe..dacb918 100644 --- a/.github/workflows/run-tests-l10.yml +++ b/.github/workflows/run-tests-l10.yml @@ -2,16 +2,16 @@ name: "Run Tests - Laravel 10" on: push: - branches: [ v5.x ] + branches: [ v5.x, master ] pull_request: - branches: [ v5.x ] + branches: [ v5.x, master ] jobs: tests: runs-on: ubuntu-latest - + services: mongodb: image: mongo:7 @@ -22,7 +22,7 @@ jobs: --health-interval=10s --health-timeout=5s --health-retries=3 - + strategy: fail-fast: false matrix: