From efbebe7ee531d49d01c810d3893eada81287674c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Tue, 7 Apr 2026 17:00:15 +0200 Subject: [PATCH 1/4] Add tests to improve coverage of untested or under-tested APIs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Session::getServer() — no test existed; documents that the method returns null when the session is not pinned to a server (pinning was removed for sharded clusters in MongoDB 6.0+) - Session::startTransaction() with all options combined — each option (maxCommitTimeMS, readConcern, readPreference, writeConcern) was only tested in isolation; this test verifies they coexist correctly and are all reflected by getTransactionOptions() - ExecutionTimeoutException::hasErrorLabel() — hasErrorLabel() was tested on RuntimeException and BulkWriteException but not on this subclass - ConnectionTimeoutException::hasErrorLabel() — same gap as above - BulkWriteCommandException::getWriteConcernErrors() — the method appeared in debug output but was never explicitly asserted; this test verifies it returns an empty array when only write errors occur - Query construction with maxAwaitTimeMS — only error/range validation tests existed; this test verifies valid values are accepted - BulkWriteCommand constructor with multiple options combined — each option (ordered, comment, verboseResults) was tested in isolation; this test verifies they work together - Command construction with invalid maxAwaitTimeMS — the >= 0 validation existed in Command.c but had no corresponding test --- ...ritecommand-ctor-options-combined-001.phpt | 60 +++++++++++++++++++ tests/command/command-ctor_error-002.phpt | 18 ++++++ ...ndexception-getwriteconcernerrors-001.phpt | 32 ++++++++++ ...iontimeoutexception-haserrorlabel-001.phpt | 22 +++++++ ...iontimeoutexception-haserrorlabel-001.phpt | 22 +++++++ .../query/query-ctor-maxAwaitTimeMS-001.phpt | 22 +++++++ tests/session/session-getServer-001.phpt | 23 +++++++ .../session/session-startTransaction-002.phpt | 40 +++++++++++++ 8 files changed, 239 insertions(+) create mode 100644 tests/bulkwritecommand/bulkwritecommand-ctor-options-combined-001.phpt create mode 100644 tests/command/command-ctor_error-002.phpt create mode 100644 tests/exception/bulkwritecommandexception-getwriteconcernerrors-001.phpt create mode 100644 tests/exception/connectiontimeoutexception-haserrorlabel-001.phpt create mode 100644 tests/exception/executiontimeoutexception-haserrorlabel-001.phpt create mode 100644 tests/query/query-ctor-maxAwaitTimeMS-001.phpt create mode 100644 tests/session/session-getServer-001.phpt create mode 100644 tests/session/session-startTransaction-002.phpt diff --git a/tests/bulkwritecommand/bulkwritecommand-ctor-options-combined-001.phpt b/tests/bulkwritecommand/bulkwritecommand-ctor-options-combined-001.phpt new file mode 100644 index 000000000..b10b491b6 --- /dev/null +++ b/tests/bulkwritecommand/bulkwritecommand-ctor-options-combined-001.phpt @@ -0,0 +1,60 @@ +--TEST-- +MongoDB\Driver\BulkWriteCommand::__construct() multiple options combined +--SKIPIF-- + + + + +--FILE-- +getCommandName() !== 'bulkWrite') { + return; + } + + $command = $event->getCommand(); + + printf("ordered: %s\n", var_export((bool) $command->ordered, true)); + printf("comment: %s\n", json_encode($command->comment)); + } + + public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void + { + } + + public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void + { + } +} + +$manager = create_test_manager(); + +$bulk = new MongoDB\Driver\BulkWriteCommand([ + 'ordered' => false, + 'comment' => 'test comment', + 'verboseResults' => true, +]); +$bulk->insertOne(NS, ['_id' => 1]); +$bulk->insertOne(NS, ['_id' => 2]); + +$manager->addSubscriber(new CommandLogger); +$result = $manager->executeBulkWriteCommand($bulk); + +var_dump($result->getInsertedCount()); +var_dump($result->getInsertResults() !== null); + +?> +===DONE=== + +--EXPECT-- +ordered: false +comment: "test comment" +int(2) +bool(true) +===DONE=== diff --git a/tests/command/command-ctor_error-002.phpt b/tests/command/command-ctor_error-002.phpt new file mode 100644 index 000000000..f133145c5 --- /dev/null +++ b/tests/command/command-ctor_error-002.phpt @@ -0,0 +1,18 @@ +--TEST-- +MongoDB\Driver\Command construction (invalid maxAwaitTimeMS range) +--FILE-- + 1], ['maxAwaitTimeMS' => -1]); +}, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; + +?> +===DONE=== + +--EXPECT-- +OK: Got MongoDB\Driver\Exception\InvalidArgumentException +Expected "maxAwaitTimeMS" option to be >= 0, -1 given +===DONE=== diff --git a/tests/exception/bulkwritecommandexception-getwriteconcernerrors-001.phpt b/tests/exception/bulkwritecommandexception-getwriteconcernerrors-001.phpt new file mode 100644 index 000000000..604044645 --- /dev/null +++ b/tests/exception/bulkwritecommandexception-getwriteconcernerrors-001.phpt @@ -0,0 +1,32 @@ +--TEST-- +MongoDB\Driver\Exception\BulkWriteCommandException::getWriteConcernErrors() +--SKIPIF-- + + + + +--FILE-- + false]); +$bulk->insertOne(NS, ['_id' => 1]); +$bulk->insertOne(NS, ['_id' => 1]); + +try { + $manager->executeBulkWriteCommand($bulk); +} catch (MongoDB\Driver\Exception\BulkWriteCommandException $e) { + var_dump($e->getWriteConcernErrors()); +} + +?> +===DONE=== + +--EXPECT-- +array(0) { +} +===DONE=== diff --git a/tests/exception/connectiontimeoutexception-haserrorlabel-001.phpt b/tests/exception/connectiontimeoutexception-haserrorlabel-001.phpt new file mode 100644 index 000000000..0da38c822 --- /dev/null +++ b/tests/exception/connectiontimeoutexception-haserrorlabel-001.phpt @@ -0,0 +1,22 @@ +--TEST-- +MongoDB\Driver\Exception\ConnectionTimeoutException::hasErrorLabel() +--FILE-- +getProperty('errorLabels'); +$errorLabelsProperty->setValue($exception, $labels); + +var_dump($exception->hasErrorLabel('foo')); +var_dump($exception->hasErrorLabel('bar')); + +?> +===DONE=== + +--EXPECT-- +bool(true) +bool(false) +===DONE=== diff --git a/tests/exception/executiontimeoutexception-haserrorlabel-001.phpt b/tests/exception/executiontimeoutexception-haserrorlabel-001.phpt new file mode 100644 index 000000000..fd7d93c79 --- /dev/null +++ b/tests/exception/executiontimeoutexception-haserrorlabel-001.phpt @@ -0,0 +1,22 @@ +--TEST-- +MongoDB\Driver\Exception\ExecutionTimeoutException::hasErrorLabel() +--FILE-- +getProperty('errorLabels'); +$errorLabelsProperty->setValue($exception, $labels); + +var_dump($exception->hasErrorLabel('foo')); +var_dump($exception->hasErrorLabel('bar')); + +?> +===DONE=== + +--EXPECT-- +bool(true) +bool(false) +===DONE=== diff --git a/tests/query/query-ctor-maxAwaitTimeMS-001.phpt b/tests/query/query-ctor-maxAwaitTimeMS-001.phpt new file mode 100644 index 000000000..0c2084191 --- /dev/null +++ b/tests/query/query-ctor-maxAwaitTimeMS-001.phpt @@ -0,0 +1,22 @@ +--TEST-- +MongoDB\Driver\Query construction with maxAwaitTimeMS option +--FILE-- + 0]); +echo "maxAwaitTimeMS=0: OK\n"; + +$q = new MongoDB\Driver\Query([], ['maxAwaitTimeMS' => 1000]); +echo "maxAwaitTimeMS=1000: OK\n"; + +$q = new MongoDB\Driver\Query([], ['maxAwaitTimeMS' => 4294967295]); +echo "maxAwaitTimeMS=4294967295: OK\n"; + +?> +===DONE=== + +--EXPECT-- +maxAwaitTimeMS=0: OK +maxAwaitTimeMS=1000: OK +maxAwaitTimeMS=4294967295: OK +===DONE=== diff --git a/tests/session/session-getServer-001.phpt b/tests/session/session-getServer-001.phpt new file mode 100644 index 000000000..49547bb0e --- /dev/null +++ b/tests/session/session-getServer-001.phpt @@ -0,0 +1,23 @@ +--TEST-- +MongoDB\Driver\Session::getServer() +--SKIPIF-- + + + +--FILE-- +startSession(); + +/* Session is not pinned to a server until a transaction operation is executed + * on a sharded cluster. Returns null when the session is not pinned. */ +var_dump($session->getServer()); + +?> +===DONE=== + +--EXPECT-- +NULL +===DONE=== diff --git a/tests/session/session-startTransaction-002.phpt b/tests/session/session-startTransaction-002.phpt new file mode 100644 index 000000000..9df2ef5ad --- /dev/null +++ b/tests/session/session-startTransaction-002.phpt @@ -0,0 +1,40 @@ +--TEST-- +MongoDB\Driver\Session::startTransaction() with all valid options combined +--SKIPIF-- + + + +--FILE-- +startSession(); + +$session->startTransaction([ + 'maxCommitTimeMS' => 5000, + 'readConcern' => new MongoDB\Driver\ReadConcern(MongoDB\Driver\ReadConcern::MAJORITY), + 'readPreference' => new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY), + 'writeConcern' => new MongoDB\Driver\WriteConcern(MongoDB\Driver\WriteConcern::MAJORITY), +]); + +$options = $session->getTransactionOptions(); + +var_dump(isset($options['maxCommitTimeMS'])); +var_dump($options['maxCommitTimeMS']); +var_dump($options['readConcern']->getLevel()); +var_dump($options['readPreference']->getModeString()); +var_dump($options['writeConcern']->getW()); + +$session->abortTransaction(); + +?> +===DONE=== + +--EXPECT-- +bool(true) +int(5000) +string(8) "majority" +string(7) "primary" +string(8) "majority" +===DONE=== From f80e673167c58864a81d120fd9a13dc77aeabec8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Tue, 7 Apr 2026 17:19:03 +0200 Subject: [PATCH 2/4] Address Copilot review comments - query-ctor-maxAwaitTimeMS-001: remove UINT32_MAX case (4294967295 overflows PHP_INT_MAX on 32-bit platforms, causing float coercion) - session-getServer-001: update comment to accurately reflect that mongos pinning was removed in MongoDB 6.0+ --- tests/query/query-ctor-maxAwaitTimeMS-001.phpt | 4 ---- tests/session/session-getServer-001.phpt | 4 ++-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/tests/query/query-ctor-maxAwaitTimeMS-001.phpt b/tests/query/query-ctor-maxAwaitTimeMS-001.phpt index 0c2084191..6a4039fb0 100644 --- a/tests/query/query-ctor-maxAwaitTimeMS-001.phpt +++ b/tests/query/query-ctor-maxAwaitTimeMS-001.phpt @@ -9,14 +9,10 @@ echo "maxAwaitTimeMS=0: OK\n"; $q = new MongoDB\Driver\Query([], ['maxAwaitTimeMS' => 1000]); echo "maxAwaitTimeMS=1000: OK\n"; -$q = new MongoDB\Driver\Query([], ['maxAwaitTimeMS' => 4294967295]); -echo "maxAwaitTimeMS=4294967295: OK\n"; - ?> ===DONE=== --EXPECT-- maxAwaitTimeMS=0: OK maxAwaitTimeMS=1000: OK -maxAwaitTimeMS=4294967295: OK ===DONE=== diff --git a/tests/session/session-getServer-001.phpt b/tests/session/session-getServer-001.phpt index 49547bb0e..90942f3fb 100644 --- a/tests/session/session-getServer-001.phpt +++ b/tests/session/session-getServer-001.phpt @@ -11,8 +11,8 @@ require_once __DIR__ . "/../utils/basic.inc"; $manager = create_test_manager(); $session = $manager->startSession(); -/* Session is not pinned to a server until a transaction operation is executed - * on a sharded cluster. Returns null when the session is not pinned. */ +/* Session::getServer() returns null, as sessions are not pinned to a server. + * Note: mongos pinning for sharded transactions was removed in MongoDB 6.0. */ var_dump($session->getServer()); ?> From 2662df544780444fc2fff081edda6c5a7bac25fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Tue, 7 Apr 2026 17:44:55 +0200 Subject: [PATCH 3/4] Merge new tests into existing files where appropriate - bulkwritecommand-ctor-ordered-002: add getWriteConcernErrors() assertion (verifies empty array when only write errors occur); removes the need for a separate bulkwritecommandexception-getwriteconcernerrors-001.phpt - session-getTransactionOptions-001: add combined-options case (all four transaction options together); removes the need for a separate session-startTransaction-002.phpt --- .../bulkwritecommand-ctor-ordered-002.phpt | 3 ++ ...ndexception-getwriteconcernerrors-001.phpt | 32 --------------- .../session-getTransactionOptions-001.phpt | 25 ++++++++++++ .../session/session-startTransaction-002.phpt | 40 ------------------- 4 files changed, 28 insertions(+), 72 deletions(-) delete mode 100644 tests/exception/bulkwritecommandexception-getwriteconcernerrors-001.phpt delete mode 100644 tests/session/session-startTransaction-002.phpt diff --git a/tests/bulkwritecommand/bulkwritecommand-ctor-ordered-002.phpt b/tests/bulkwritecommand/bulkwritecommand-ctor-ordered-002.phpt index 24ad876d4..bacb0a4d4 100644 --- a/tests/bulkwritecommand/bulkwritecommand-ctor-ordered-002.phpt +++ b/tests/bulkwritecommand/bulkwritecommand-ctor-ordered-002.phpt @@ -23,6 +23,7 @@ try { printf("%s(%d): %s\n", get_class($e), $e->getCode(), $e->getMessage()); var_dump($e->getPartialResult()); var_dump($e->getWriteErrors()); + var_dump($e->getWriteConcernErrors()); } ?> @@ -64,4 +65,6 @@ array(1) { } } } +array(0) { +} ===DONE=== diff --git a/tests/exception/bulkwritecommandexception-getwriteconcernerrors-001.phpt b/tests/exception/bulkwritecommandexception-getwriteconcernerrors-001.phpt deleted file mode 100644 index 604044645..000000000 --- a/tests/exception/bulkwritecommandexception-getwriteconcernerrors-001.phpt +++ /dev/null @@ -1,32 +0,0 @@ ---TEST-- -MongoDB\Driver\Exception\BulkWriteCommandException::getWriteConcernErrors() ---SKIPIF-- - - - - ---FILE-- - false]); -$bulk->insertOne(NS, ['_id' => 1]); -$bulk->insertOne(NS, ['_id' => 1]); - -try { - $manager->executeBulkWriteCommand($bulk); -} catch (MongoDB\Driver\Exception\BulkWriteCommandException $e) { - var_dump($e->getWriteConcernErrors()); -} - -?> -===DONE=== - ---EXPECT-- -array(0) { -} -===DONE=== diff --git a/tests/session/session-getTransactionOptions-001.phpt b/tests/session/session-getTransactionOptions-001.phpt index b1ad1d1c8..2a09079d5 100644 --- a/tests/session/session-getTransactionOptions-001.phpt +++ b/tests/session/session-getTransactionOptions-001.phpt @@ -19,6 +19,12 @@ $options = [ ['readConcern' => new \MongoDB\Driver\ReadConcern('majority')], ['readPreference' => new \MongoDB\Driver\ReadPreference('primaryPreferred')], ['writeConcern' => new \MongoDB\Driver\WriteConcern('majority')], + [ + 'maxCommitTimeMS' => 5000, + 'readConcern' => new \MongoDB\Driver\ReadConcern(\MongoDB\Driver\ReadConcern::MAJORITY), + 'readPreference' => new \MongoDB\Driver\ReadPreference(\MongoDB\Driver\ReadPreference::PRIMARY), + 'writeConcern' => new \MongoDB\Driver\WriteConcern(\MongoDB\Driver\WriteConcern::MAJORITY), + ], ]; foreach ($options as $test) { @@ -82,4 +88,23 @@ array(2) { string(8) "majority" } } +array(4) { + ["maxCommitTimeMS"]=> + int(5000) + ["readConcern"]=> + object(MongoDB\Driver\ReadConcern)#%d (1) { + ["level"]=> + string(8) "majority" + } + ["readPreference"]=> + object(MongoDB\Driver\ReadPreference)#%d (1) { + ["mode"]=> + string(7) "primary" + } + ["writeConcern"]=> + object(MongoDB\Driver\WriteConcern)#%d (1) { + ["w"]=> + string(8) "majority" + } +} ===DONE=== diff --git a/tests/session/session-startTransaction-002.phpt b/tests/session/session-startTransaction-002.phpt deleted file mode 100644 index 9df2ef5ad..000000000 --- a/tests/session/session-startTransaction-002.phpt +++ /dev/null @@ -1,40 +0,0 @@ ---TEST-- -MongoDB\Driver\Session::startTransaction() with all valid options combined ---SKIPIF-- - - - ---FILE-- -startSession(); - -$session->startTransaction([ - 'maxCommitTimeMS' => 5000, - 'readConcern' => new MongoDB\Driver\ReadConcern(MongoDB\Driver\ReadConcern::MAJORITY), - 'readPreference' => new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY), - 'writeConcern' => new MongoDB\Driver\WriteConcern(MongoDB\Driver\WriteConcern::MAJORITY), -]); - -$options = $session->getTransactionOptions(); - -var_dump(isset($options['maxCommitTimeMS'])); -var_dump($options['maxCommitTimeMS']); -var_dump($options['readConcern']->getLevel()); -var_dump($options['readPreference']->getModeString()); -var_dump($options['writeConcern']->getW()); - -$session->abortTransaction(); - -?> -===DONE=== - ---EXPECT-- -bool(true) -int(5000) -string(8) "majority" -string(7) "primary" -string(8) "majority" -===DONE=== From 71f80815268f19e8afa8a0adf945fd2106b9c406 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Tue, 7 Apr 2026 18:32:20 +0200 Subject: [PATCH 4/4] Address Copilot review comments --- ...lkwritecommand-ctor-options-combined-001.phpt | 2 +- tests/query/query-ctor-maxAwaitTimeMS-002.phpt | 16 ++++++++++++++++ tests/session/session-getServer-001.phpt | 4 ++-- 3 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 tests/query/query-ctor-maxAwaitTimeMS-002.phpt diff --git a/tests/bulkwritecommand/bulkwritecommand-ctor-options-combined-001.phpt b/tests/bulkwritecommand/bulkwritecommand-ctor-options-combined-001.phpt index b10b491b6..9912848b2 100644 --- a/tests/bulkwritecommand/bulkwritecommand-ctor-options-combined-001.phpt +++ b/tests/bulkwritecommand/bulkwritecommand-ctor-options-combined-001.phpt @@ -20,7 +20,7 @@ class CommandLogger implements MongoDB\Driver\Monitoring\CommandSubscriber $command = $event->getCommand(); - printf("ordered: %s\n", var_export((bool) $command->ordered, true)); + printf("ordered: %s\n", var_export($command->ordered, true)); printf("comment: %s\n", json_encode($command->comment)); } diff --git a/tests/query/query-ctor-maxAwaitTimeMS-002.phpt b/tests/query/query-ctor-maxAwaitTimeMS-002.phpt new file mode 100644 index 000000000..427c46eb6 --- /dev/null +++ b/tests/query/query-ctor-maxAwaitTimeMS-002.phpt @@ -0,0 +1,16 @@ +--TEST-- +MongoDB\Driver\Query construction with maxAwaitTimeMS option (64-bit) +--SKIPIF-- + +--FILE-- + 4294967295]); +echo "maxAwaitTimeMS=4294967295: OK\n"; + +?> +===DONE=== + +--EXPECT-- +maxAwaitTimeMS=4294967295: OK +===DONE=== diff --git a/tests/session/session-getServer-001.phpt b/tests/session/session-getServer-001.phpt index 90942f3fb..77c39c6ff 100644 --- a/tests/session/session-getServer-001.phpt +++ b/tests/session/session-getServer-001.phpt @@ -11,8 +11,8 @@ require_once __DIR__ . "/../utils/basic.inc"; $manager = create_test_manager(); $session = $manager->startSession(); -/* Session::getServer() returns null, as sessions are not pinned to a server. - * Note: mongos pinning for sharded transactions was removed in MongoDB 6.0. */ +/* Session::getServer() currently returns null, as sessions are not pinned + * to a server. */ var_dump($session->getServer()); ?>