diff --git a/.github/workflows/build-ci.yml b/.github/workflows/build-ci.yml index 6f57f015d..f081e3273 100644 --- a/.github/workflows/build-ci.yml +++ b/.github/workflows/build-ci.yml @@ -44,10 +44,6 @@ jobs: - '8.0' - '8.1' services: - mongo: - image: mongo:${{ matrix.mongodb }} - ports: - - 27017:27017 mysql: image: mysql:5.7 ports: @@ -59,6 +55,16 @@ jobs: steps: - uses: actions/checkout@v2 + - name: Create MongoDB Replica Set + run: | + docker run --name mongodb -p 27017:27017 -e MONGO_INITDB_DATABASE=unittest --detach mongo:${{ matrix.mongodb }} mongod --replSet rs --setParameter transactionLifetimeLimitSeconds=5 + until docker exec --tty mongodb mongo 127.0.0.1:27017 --eval "db.runCommand({ ping: 1 })"; do + sleep 1 + done + sudo docker exec --tty mongodb mongo 127.0.0.1:27017 --eval "rs.initiate({\"_id\":\"rs\",\"members\":[{\"_id\":0,\"host\":\"127.0.0.1:27017\" }]})" + - name: Show MongoDB server status + run: | + docker exec --tty mongodb mongo 127.0.0.1:27017 --eval "db.runCommand({ serverStatus: 1 })" - name: "Installing php" uses: shivammathur/setup-php@v2 with: @@ -88,7 +94,7 @@ jobs: run: | ./vendor/bin/phpunit --coverage-clover coverage.xml env: - MONGODB_URI: 'mongodb://127.0.0.1/' + MONGODB_URI: 'mongodb://127.0.0.1/?replicaSet=rs' MYSQL_HOST: 0.0.0.0 MYSQL_PORT: 3307 - uses: codecov/codecov-action@v1 diff --git a/README.md b/README.md index 06531dcb1..0c07e7288 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ This package adds functionalities to the Eloquent model and Query builder for Mo - [Query Builder](#query-builder) - [Basic Usage](#basic-usage-2) - [Available operations](#available-operations) + - [Transactions](#transactions) - [Schema](#schema) - [Basic Usage](#basic-usage-3) - [Geospatial indexes](#geospatial-indexes) @@ -968,6 +969,52 @@ If you are familiar with [Eloquent Queries](http://laravel.com/docs/queries), th ### Available operations To see the available operations, check the [Eloquent](#eloquent) section. +Transactions +------------ +Transactions require MongoDB version ^4.0 as well as deployment of replica set or sharded clusters. You can find more information [in the MongoDB docs](https://docs.mongodb.com/manual/core/transactions/) + +### Basic Usage + +```php +DB::transaction(function () { + User::create(['name' => 'john', 'age' => 19, 'title' => 'admin', 'email' => 'john@example.com']); + DB::collection('users')->where('name', 'john')->update(['age' => 20]); + DB::collection('users')->where('name', 'john')->delete(); +}); +``` + +```php +// begin a transaction +DB::beginTransaction(); +User::create(['name' => 'john', 'age' => 19, 'title' => 'admin', 'email' => 'john@example.com']); +DB::collection('users')->where('name', 'john')->update(['age' => 20]); +DB::collection('users')->where('name', 'john')->delete(); + +// commit changes +DB::commit(); +``` + +To abort a transaction, call the `rollBack` method at any point during the transaction: +```php +DB::beginTransaction(); +User::create(['name' => 'john', 'age' => 19, 'title' => 'admin', 'email' => 'john@example.com']); + +// Abort the transaction, discarding any data created as part of it +DB::rollBack(); +``` + +**NOTE:** Transactions in MongoDB cannot be nested. DB::beginTransaction() function will start new transactions in a new created or existing session and will raise the RuntimeException when transactions already exist. See more in MongoDB official docs [Transactions and Sessions](https://www.mongodb.com/docs/manual/core/transactions/#transactions-and-sessions) +```php +DB::beginTransaction(); +User::create(['name' => 'john', 'age' => 20, 'title' => 'admin']); + +// This call to start a nested transaction will raise a RuntimeException +DB::beginTransaction(); +DB::collection('users')->where('name', 'john')->update(['age' => 20]); +DB::commit(); +DB::rollBack(); +``` + Schema ------ The database driver also has (limited) schema builder support. You can easily manipulate collections and set indexes. diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 15601b8dc..9aebe0c0a 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -19,6 +19,9 @@ tests/QueryBuilderTest.php tests/QueryTest.php + + tests/TransactionTest.php + tests/ModelTest.php tests/RelationsTest.php @@ -36,7 +39,7 @@ - + diff --git a/src/Concerns/ManagesTransactions.php b/src/Concerns/ManagesTransactions.php new file mode 100644 index 000000000..d3344f919 --- /dev/null +++ b/src/Concerns/ManagesTransactions.php @@ -0,0 +1,116 @@ +session; + } + + private function getSessionOrCreate(): Session + { + if ($this->session === null) { + $this->session = $this->getMongoClient()->startSession(); + } + + return $this->session; + } + + private function getSessionOrThrow(): Session + { + $session = $this->getSession(); + + if ($session === null) { + throw new RuntimeException('There is no active session.'); + } + + return $session; + } + + /** + * Starts a transaction on the active session. An active session will be created if none exists. + */ + public function beginTransaction(array $options = []): void + { + $this->getSessionOrCreate()->startTransaction($options); + $this->transactions = 1; + } + + /** + * Commit transaction in this session. + */ + public function commit(): void + { + $this->getSessionOrThrow()->commitTransaction(); + $this->transactions = 0; + } + + /** + * Abort transaction in this session. + */ + public function rollBack($toLevel = null): void + { + $this->getSessionOrThrow()->abortTransaction(); + $this->transactions = 0; + } + + /** + * Static transaction function realize the with_transaction functionality provided by MongoDB. + * + * @param int $attempts + */ + public function transaction(Closure $callback, $attempts = 1, array $options = []): mixed + { + $attemptsLeft = $attempts; + $callbackResult = null; + $throwable = null; + + $callbackFunction = function (Session $session) use ($callback, &$attemptsLeft, &$callbackResult, &$throwable) { + $attemptsLeft--; + + if ($attemptsLeft < 0) { + $session->abortTransaction(); + + return; + } + + // Catch, store, and re-throw any exception thrown during execution + // of the callable. The last exception is re-thrown if the transaction + // was aborted because the number of callback attempts has been exceeded. + try { + $callbackResult = $callback($this); + } catch (Throwable $throwable) { + throw $throwable; + } + }; + + with_transaction($this->getSessionOrCreate(), $callbackFunction, $options); + + if ($attemptsLeft < 0 && $throwable) { + throw $throwable; + } + + return $callbackResult; + } +} diff --git a/src/Connection.php b/src/Connection.php index b65b40ca3..c78ac95c1 100644 --- a/src/Connection.php +++ b/src/Connection.php @@ -5,11 +5,14 @@ use Illuminate\Database\Connection as BaseConnection; use Illuminate\Support\Arr; use InvalidArgumentException; +use Jenssegers\Mongodb\Concerns\ManagesTransactions; use MongoDB\Client; use MongoDB\Database; class Connection extends BaseConnection { + use ManagesTransactions; + /** * The MongoDB database handler. * diff --git a/src/Query/Builder.php b/src/Query/Builder.php index 631e64950..066412734 100644 --- a/src/Query/Builder.php +++ b/src/Query/Builder.php @@ -346,6 +346,8 @@ public function getFresh($columns = [], $returnLazy = false) $options = array_merge($options, $this->options); } + $options = $this->inheritConnectionOptions($options); + // Execute aggregation $results = iterator_to_array($this->collection->aggregate($pipeline, $options)); @@ -356,12 +358,10 @@ public function getFresh($columns = [], $returnLazy = false) // Return distinct results directly $column = isset($this->columns[0]) ? $this->columns[0] : '_id'; + $options = $this->inheritConnectionOptions(); + // Execute distinct - if ($wheres) { - $result = $this->collection->distinct($column, $wheres); - } else { - $result = $this->collection->distinct($column); - } + $result = $this->collection->distinct($column, $wheres ?: [], $options); return new Collection($result); } // Normal query @@ -407,6 +407,8 @@ public function getFresh($columns = [], $returnLazy = false) $options = array_merge($options, $this->options); } + $options = $this->inheritConnectionOptions($options); + // Execute query and get MongoCursor $cursor = $this->collection->find($wheres, $options); @@ -581,8 +583,9 @@ public function insert(array $values) $values = [$values]; } - // Batch insert - $result = $this->collection->insertMany($values); + $options = $this->inheritConnectionOptions(); + + $result = $this->collection->insertMany($values, $options); return 1 == (int) $result->isAcknowledged(); } @@ -592,7 +595,9 @@ public function insert(array $values) */ public function insertGetId(array $values, $sequence = null) { - $result = $this->collection->insertOne($values); + $options = $this->inheritConnectionOptions(); + + $result = $this->collection->insertOne($values, $options); if (1 == (int) $result->isAcknowledged()) { if ($sequence === null) { @@ -614,6 +619,8 @@ public function update(array $values, array $options = []) $values = ['$set' => $values]; } + $options = $this->inheritConnectionOptions($options); + return $this->performUpdate($values, $options); } @@ -635,6 +642,8 @@ public function increment($column, $amount = 1, array $extra = [], array $option $query->orWhereNotNull($column); }); + $options = $this->inheritConnectionOptions($options); + return $this->performUpdate($query, $options); } @@ -696,7 +705,10 @@ public function delete($id = null) } $wheres = $this->compileWheres(); - $result = $this->collection->DeleteMany($wheres); + $options = $this->inheritConnectionOptions(); + + $result = $this->collection->deleteMany($wheres, $options); + if (1 == (int) $result->isAcknowledged()) { return $result->getDeletedCount(); } @@ -721,7 +733,8 @@ public function from($collection, $as = null) */ public function truncate(): bool { - $result = $this->collection->deleteMany([]); + $options = $this->inheritConnectionOptions(); + $result = $this->collection->deleteMany([], $options); return 1 === (int) $result->isAcknowledged(); } @@ -855,6 +868,8 @@ protected function performUpdate($query, array $options = []) $options['multiple'] = true; } + $options = $this->inheritConnectionOptions($options); + $wheres = $this->compileWheres(); $result = $this->collection->UpdateMany($wheres, $query, $options); if (1 == (int) $result->isAcknowledged()) { @@ -1249,6 +1264,18 @@ public function options(array $options) return $this; } + /** + * Apply the connection's session to options if it's not already specified. + */ + private function inheritConnectionOptions(array $options = []): array + { + if (! isset($options['session']) && ($session = $this->connection->getSession())) { + $options['session'] = $session; + } + + return $options; + } + /** * @inheritdoc */ diff --git a/tests/TransactionTest.php b/tests/TransactionTest.php new file mode 100644 index 000000000..52ce422a7 --- /dev/null +++ b/tests/TransactionTest.php @@ -0,0 +1,448 @@ +getPrimaryServerType() === Server::TYPE_STANDALONE) { + $this->markTestSkipped('Transactions are not supported on standalone servers'); + } + + User::truncate(); + } + + public function tearDown(): void + { + User::truncate(); + + parent::tearDown(); + } + + public function testCreateWithCommit(): void + { + DB::beginTransaction(); + /** @var User $klinson */ + $klinson = User::create(['name' => 'klinson', 'age' => 20, 'title' => 'admin']); + DB::commit(); + + $this->assertInstanceOf(Model::class, $klinson); + $this->assertTrue($klinson->exists); + $this->assertEquals('klinson', $klinson->name); + + $check = User::find($klinson->_id); + $this->assertInstanceOf(User::class, $check); + $this->assertEquals($klinson->name, $check->name); + } + + public function testCreateRollBack(): void + { + DB::beginTransaction(); + /** @var User $klinson */ + $klinson = User::create(['name' => 'klinson', 'age' => 20, 'title' => 'admin']); + DB::rollBack(); + + $this->assertInstanceOf(Model::class, $klinson); + $this->assertTrue($klinson->exists); + $this->assertEquals('klinson', $klinson->name); + + $this->assertFalse(User::where('_id', $klinson->_id)->exists()); + } + + public function testInsertWithCommit(): void + { + DB::beginTransaction(); + DB::collection('users')->insert(['name' => 'klinson', 'age' => 20, 'title' => 'admin']); + DB::commit(); + + $this->assertTrue(DB::collection('users')->where('name', 'klinson')->exists()); + } + + public function testInsertWithRollBack(): void + { + DB::beginTransaction(); + DB::collection('users')->insert(['name' => 'klinson', 'age' => 20, 'title' => 'admin']); + DB::rollBack(); + + $this->assertFalse(DB::collection('users')->where('name', 'klinson')->exists()); + } + + public function testEloquentCreateWithCommit(): void + { + DB::beginTransaction(); + /** @var User $klinson */ + $klinson = User::getModel(); + $klinson->name = 'klinson'; + $klinson->save(); + DB::commit(); + + $this->assertTrue($klinson->exists); + $this->assertNotNull($klinson->getIdAttribute()); + + $check = User::find($klinson->_id); + $this->assertInstanceOf(User::class, $check); + $this->assertEquals($check->name, $klinson->name); + } + + public function testEloquentCreateWithRollBack(): void + { + DB::beginTransaction(); + /** @var User $klinson */ + $klinson = User::getModel(); + $klinson->name = 'klinson'; + $klinson->save(); + DB::rollBack(); + + $this->assertTrue($klinson->exists); + $this->assertNotNull($klinson->getIdAttribute()); + + $this->assertFalse(User::where('_id', $klinson->_id)->exists()); + } + + public function testInsertGetIdWithCommit(): void + { + DB::beginTransaction(); + $userId = DB::collection('users')->insertGetId(['name' => 'klinson', 'age' => 20, 'title' => 'admin']); + DB::commit(); + + $this->assertInstanceOf(ObjectId::class, $userId); + + $user = DB::collection('users')->find((string) $userId); + $this->assertEquals('klinson', $user['name']); + } + + public function testInsertGetIdWithRollBack(): void + { + DB::beginTransaction(); + $userId = DB::collection('users')->insertGetId(['name' => 'klinson', 'age' => 20, 'title' => 'admin']); + DB::rollBack(); + + $this->assertInstanceOf(ObjectId::class, $userId); + $this->assertFalse(DB::collection('users')->where('_id', (string) $userId)->exists()); + } + + public function testUpdateWithCommit(): void + { + User::create(['name' => 'klinson', 'age' => 20, 'title' => 'admin']); + + DB::beginTransaction(); + $updated = DB::collection('users')->where('name', 'klinson')->update(['age' => 21]); + DB::commit(); + + $this->assertEquals(1, $updated); + $this->assertTrue(DB::collection('users')->where('name', 'klinson')->where('age', 21)->exists()); + } + + public function testUpdateWithRollback(): void + { + User::create(['name' => 'klinson', 'age' => 20, 'title' => 'admin']); + + DB::beginTransaction(); + $updated = DB::collection('users')->where('name', 'klinson')->update(['age' => 21]); + DB::rollBack(); + + $this->assertEquals(1, $updated); + $this->assertFalse(DB::collection('users')->where('name', 'klinson')->where('age', 21)->exists()); + } + + public function testEloquentUpdateWithCommit(): void + { + /** @var User $klinson */ + $klinson = User::create(['name' => 'klinson', 'age' => 20, 'title' => 'admin']); + /** @var User $alcaeus */ + $alcaeus = User::create(['name' => 'alcaeus', 'age' => 38, 'title' => 'admin']); + + DB::beginTransaction(); + $klinson->age = 21; + $klinson->update(); + + $alcaeus->update(['age' => 39]); + DB::commit(); + + $this->assertEquals(21, $klinson->age); + $this->assertEquals(39, $alcaeus->age); + + $this->assertTrue(User::where('_id', $klinson->_id)->where('age', 21)->exists()); + $this->assertTrue(User::where('_id', $alcaeus->_id)->where('age', 39)->exists()); + } + + public function testEloquentUpdateWithRollBack(): void + { + /** @var User $klinson */ + $klinson = User::create(['name' => 'klinson', 'age' => 20, 'title' => 'admin']); + /** @var User $alcaeus */ + $alcaeus = User::create(['name' => 'klinson', 'age' => 38, 'title' => 'admin']); + + DB::beginTransaction(); + $klinson->age = 21; + $klinson->update(); + + $alcaeus->update(['age' => 39]); + DB::rollBack(); + + $this->assertEquals(21, $klinson->age); + $this->assertEquals(39, $alcaeus->age); + + $this->assertFalse(User::where('_id', $klinson->_id)->where('age', 21)->exists()); + $this->assertFalse(User::where('_id', $alcaeus->_id)->where('age', 39)->exists()); + } + + public function testDeleteWithCommit(): void + { + User::create(['name' => 'klinson', 'age' => 20, 'title' => 'admin']); + + DB::beginTransaction(); + $deleted = User::where(['name' => 'klinson'])->delete(); + DB::commit(); + + $this->assertEquals(1, $deleted); + $this->assertFalse(User::where(['name' => 'klinson'])->exists()); + } + + public function testDeleteWithRollBack(): void + { + User::create(['name' => 'klinson', 'age' => 20, 'title' => 'admin']); + + DB::beginTransaction(); + $deleted = User::where(['name' => 'klinson'])->delete(); + DB::rollBack(); + + $this->assertEquals(1, $deleted); + $this->assertTrue(User::where(['name' => 'klinson'])->exists()); + } + + public function testEloquentDeleteWithCommit(): void + { + /** @var User $klinson */ + $klinson = User::create(['name' => 'klinson', 'age' => 20, 'title' => 'admin']); + + DB::beginTransaction(); + $klinson->delete(); + DB::commit(); + + $this->assertFalse(User::where('_id', $klinson->_id)->exists()); + } + + public function testEloquentDeleteWithRollBack(): void + { + /** @var User $klinson */ + $klinson = User::create(['name' => 'klinson', 'age' => 20, 'title' => 'admin']); + + DB::beginTransaction(); + $klinson->delete(); + DB::rollBack(); + + $this->assertTrue(User::where('_id', $klinson->_id)->exists()); + } + + public function testIncrementWithCommit(): void + { + User::create(['name' => 'klinson', 'age' => 20, 'title' => 'admin']); + + DB::beginTransaction(); + DB::collection('users')->where('name', 'klinson')->increment('age'); + DB::commit(); + + $this->assertTrue(DB::collection('users')->where('name', 'klinson')->where('age', 21)->exists()); + } + + public function testIncrementWithRollBack(): void + { + User::create(['name' => 'klinson', 'age' => 20, 'title' => 'admin']); + + DB::beginTransaction(); + DB::collection('users')->where('name', 'klinson')->increment('age'); + DB::rollBack(); + + $this->assertTrue(DB::collection('users')->where('name', 'klinson')->where('age', 20)->exists()); + } + + public function testDecrementWithCommit(): void + { + User::create(['name' => 'klinson', 'age' => 20, 'title' => 'admin']); + + DB::beginTransaction(); + DB::collection('users')->where('name', 'klinson')->decrement('age'); + DB::commit(); + + $this->assertTrue(DB::collection('users')->where('name', 'klinson')->where('age', 19)->exists()); + } + + public function testDecrementWithRollBack(): void + { + User::create(['name' => 'klinson', 'age' => 20, 'title' => 'admin']); + + DB::beginTransaction(); + DB::collection('users')->where('name', 'klinson')->decrement('age'); + DB::rollBack(); + + $this->assertTrue(DB::collection('users')->where('name', 'klinson')->where('age', 20)->exists()); + } + + public function testQuery() + { + /** rollback test */ + DB::beginTransaction(); + $count = DB::collection('users')->count(); + $this->assertEquals(0, $count); + DB::collection('users')->insert(['name' => 'klinson', 'age' => 20, 'title' => 'admin']); + $count = DB::collection('users')->count(); + $this->assertEquals(1, $count); + DB::rollBack(); + + $count = DB::collection('users')->count(); + $this->assertEquals(0, $count); + + /** commit test */ + DB::beginTransaction(); + $count = DB::collection('users')->count(); + $this->assertEquals(0, $count); + DB::collection('users')->insert(['name' => 'klinson', 'age' => 20, 'title' => 'admin']); + $count = DB::collection('users')->count(); + $this->assertEquals(1, $count); + DB::commit(); + + $count = DB::collection('users')->count(); + $this->assertEquals(1, $count); + } + + public function testTransaction(): void + { + User::create(['name' => 'klinson', 'age' => 20, 'title' => 'admin']); + + // The $connection parameter may be unused, but is implicitly used to + // test that the closure is executed with the connection as an argument. + DB::transaction(function (Connection $connection): void { + User::create(['name' => 'alcaeus', 'age' => 38, 'title' => 'admin']); + User::where(['name' => 'klinson'])->update(['age' => 21]); + }); + + $count = User::count(); + $this->assertEquals(2, $count); + + $this->assertTrue(User::where('alcaeus')->exists()); + $this->assertTrue(User::where(['name' => 'klinson'])->where('age', 21)->exists()); + } + + public function testTransactionRepeatsOnTransientFailure(): void + { + User::create(['name' => 'klinson', 'age' => 20, 'title' => 'admin']); + + $timesRun = 0; + + DB::transaction(function () use (&$timesRun): void { + $timesRun++; + + // Run a query to start the transaction on the server + User::create(['name' => 'alcaeus', 'age' => 38, 'title' => 'admin']); + + // Update user outside of the session + if ($timesRun == 1) { + DB::getCollection('users')->updateOne(['name' => 'klinson'], ['$set' => ['age' => 22]]); + } + + // This update will create a write conflict, aborting the transaction + User::where(['name' => 'klinson'])->update(['age' => 21]); + }, 2); + + $this->assertSame(2, $timesRun); + $this->assertTrue(User::where(['name' => 'klinson'])->where('age', 21)->exists()); + } + + public function testTransactionRespectsRepetitionLimit(): void + { + $klinson = User::create(['name' => 'klinson', 'age' => 20, 'title' => 'admin']); + + $timesRun = 0; + + try { + DB::transaction(function () use (&$timesRun): void { + $timesRun++; + + // Run a query to start the transaction on the server + User::create(['name' => 'alcaeus', 'age' => 38, 'title' => 'admin']); + + // Update user outside of the session + DB::getCollection('users')->updateOne(['name' => 'klinson'], ['$inc' => ['age' => 2]]); + + // This update will create a write conflict, aborting the transaction + User::where(['name' => 'klinson'])->update(['age' => 21]); + }, 2); + + $this->fail('Expected exception during transaction'); + } catch (BulkWriteException $e) { + $this->assertInstanceOf(BulkWriteException::class, $e); + $this->assertStringContainsString('WriteConflict', $e->getMessage()); + } + + $this->assertSame(2, $timesRun); + + $check = User::find($klinson->_id); + $this->assertInstanceOf(User::class, $check); + + // Age is expected to be 24: the callback is executed twice, incrementing age by 2 every time + $this->assertSame(24, $check->age); + } + + public function testTransactionReturnsCallbackResult(): void + { + $result = DB::transaction(function (): User { + return User::create(['name' => 'klinson', 'age' => 20, 'title' => 'admin']); + }); + + $this->assertInstanceOf(User::class, $result); + $this->assertEquals($result->title, 'admin'); + $this->assertSame(1, User::count()); + } + + public function testNestedTransactionsCauseException(): void + { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('Transaction already in progress'); + + DB::beginTransaction(); + DB::beginTransaction(); + DB::commit(); + DB::rollBack(); + } + + public function testNestingTransactionInManualTransaction() + { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('Transaction already in progress'); + + DB::beginTransaction(); + DB::transaction(function (): void { + }); + DB::rollBack(); + } + + public function testCommitWithoutSession(): void + { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('There is no active session.'); + + DB::commit(); + } + + public function testRollBackWithoutSession(): void + { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('There is no active session.'); + + DB::rollback(); + } + + private function getPrimaryServerType(): int + { + return DB::getMongoClient()->getManager()->selectServer()->getType(); + } +} diff --git a/tests/config/database.php b/tests/config/database.php index 73f3d8697..498e4e7e0 100644 --- a/tests/config/database.php +++ b/tests/config/database.php @@ -6,7 +6,11 @@ 'name' => 'mongodb', 'driver' => 'mongodb', 'dsn' => env('MONGODB_URI', 'mongodb://127.0.0.1/'), - 'database' => env('MONGO_DATABASE', 'unittest'), + 'database' => env('MONGODB_DATABASE', 'unittest'), + 'options' => [ + 'connectTimeoutMS' => 100, + 'serverSelectionTimeoutMS' => 250, + ], ], 'mysql' => [ diff --git a/tests/config/queue.php b/tests/config/queue.php index 7d52487fa..d287780e9 100644 --- a/tests/config/queue.php +++ b/tests/config/queue.php @@ -16,7 +16,7 @@ ], 'failed' => [ - 'database' => env('MONGO_DATABASE'), + 'database' => env('MONGODB_DATABASE'), 'driver' => 'mongodb', 'table' => 'failed_jobs', ],