diff --git a/tests/DocumentationExamplesTest.php b/tests/DocumentationExamplesTest.php index 86240a50ffd04f7c25a35b44af198df992d3ed61..056ad9895cf80948b905673f928e17c1f32e61a2 100644 --- a/tests/DocumentationExamplesTest.php +++ b/tests/DocumentationExamplesTest.php @@ -2,6 +2,7 @@ namespace MongoDB\Tests; +use MongoDB\BSON\UTCDateTime; use MongoDB\Client; use MongoDB\Database; use MongoDB\Driver\Cursor; @@ -13,6 +14,8 @@ use MongoDB\Operation\DropCollection; * Documentation examples to be parsed for inclusion in the MongoDB manual. * * @see https://jira.mongodb.org/browse/DRIVERS-356 + * @see https://jira.mongodb.org/browse/DRIVERS-488 + * @see https://jira.mongodb.org/browse/DRIVERS-547 */ class DocumentationExamplesTest extends FunctionalTestCase { @@ -921,13 +924,7 @@ class DocumentationExamplesTest extends FunctionalTestCase public function testChangeStreamExample_1_4() { - if ($this->getPrimaryServer()->getType() === Server::TYPE_STANDALONE) { - $this->markTestSkipped('$changeStream is not supported on standalone servers'); - } - - if (version_compare($this->getFeatureCompatibilityVersion(), '3.6', '<')) { - $this->markTestSkipped('$changeStream is only supported on FCV 3.6 or higher'); - } + $this->skipIfChangeStreamIsNotSupported(); $db = new Database($this->manager, $this->getDatabaseName()); $db->dropCollection('inventory'); @@ -1408,6 +1405,65 @@ class DocumentationExamplesTest extends FunctionalTestCase } } + function testCausalConsistency() + { + $this->skipIfCausalConsistencyIsNotSupported(); + + // Prep + $client = new Client($this->getUri()); + $test = $client->selectDatabase( + 'test', + [ 'writeConcern' => new WriteConcern(WriteConcern::MAJORITY) ] + ); + $items = $client->test->items; + + $items->drop(); + $items->insertOne( + [ 'sku' => '111', 'name' => 'Peanuts', 'start' => new UTCDateTime() ] + ); + + // Start Causal Consistency Example 1 + $s1 = $client->startSession( + [ 'causalConsistency' => true ] + ); + + $items->updateOne( + [ 'sku' => '111', 'end' => [ '$exists' => false ] ], + [ '$currentDate' => [ 'end' => true ] ], + [ 'session' => $s1 ] + ); + $items->insertOne( + [ 'sku' => '111-nuts', 'name' => 'Pecans', 'start' => new \MongoDB\BSON\UTCDateTime() ], + [ 'session' => $s1 ] + ); + // End Causal Consistency Example 1 + + ob_start(); + + // Start Causal Consistency Example 2 + $s2 = $client->startSession( + [ 'causalConsistency' => true ] + ); + $s2->advanceClusterTime($s1->getClusterTime()); + $s2->advanceOperationTime($s1->getOperationTime()); + + $items = $client->selectDatabase( + 'test', + [ 'readPreference' => new \MongoDB\Driver\ReadPreference(\MongoDB\Driver\ReadPreference::RP_SECONDARY) ] + )->items; + + $result = $items->find( + [ 'end' => [ '$exists' => false ] ], + [ 'session' => $s2 ] + ); + foreach ($result as $item) { + var_dump($item); + } + // End Causal Consistency Example 2 + + ob_end_clean(); + } + /** * Return the test collection name. * diff --git a/tests/FunctionalTestCase.php b/tests/FunctionalTestCase.php index 2c3bc01e786678d3b04206b696fb1850186e8704..6bc6347b7825cc3fba5df49fd4b8810eaa64effe 100644 --- a/tests/FunctionalTestCase.php +++ b/tests/FunctionalTestCase.php @@ -6,6 +6,7 @@ use MongoDB\Driver\Command; use MongoDB\Driver\Cursor; use MongoDB\Driver\Manager; use MongoDB\Driver\ReadPreference; +use MongoDB\Driver\Query; use MongoDB\Driver\Server; use stdClass; use UnexpectedValueException; @@ -114,6 +115,79 @@ abstract class FunctionalTestCase extends TestCase throw new UnexpectedValueException('Could not determine server storage engine'); } + protected function isShardedClusterUsingReplicasets() + { + $cursor = $this->getPrimaryServer()->executeQuery( + 'config.shards', + new Query([], ['limit' => 1]) + ); + + $cursor->setTypeMap(['root' => 'array', 'document' => 'array']); + $document = current($cursor->toArray()); + + if (! $document ) { + return false; + } + + /** + * Use regular expression to distinguish between standalone or replicaset: + * Without a replicaset: "host" : "localhost:4100" + * With a replicaset: "host" : "dec6d8a7-9bc1-4c0e-960c-615f860b956f/localhost:4400,localhost:4401" + */ + return preg_match('@^.*/.*:\d+@', $document['host']); + } + + protected function skipIfChangeStreamIsNotSupported() + { + switch ( $this->getPrimaryServer()->getType() ) + { + case Server::TYPE_MONGOS: + if (version_compare($this->getServerVersion(), '3.6.0', '<')) { + $this->markTestSkipped('$changeStream is only supported on MongoDB 3.6 or higher'); + } + if (!$this->isShardedClusterUsingReplicasets()) { + $this->markTestSkipped('$changeStream is only supported with replicasets'); + } + break; + + case Server::TYPE_RS_PRIMARY: + if (version_compare($this->getFeatureCompatibilityVersion(), '3.6', '<')) { + $this->markTestSkipped('$changeStream is only supported on FCV 3.6 or higher'); + } + break; + + default: + $this->markTestSkipped('$changeStream is not supported'); + } + } + + protected function skipIfCausalConsistencyIsNotSupported() + { + switch ( $this->getPrimaryServer()->getType() ) + { + case Server::TYPE_MONGOS: + if (version_compare($this->getServerVersion(), '3.6.0', '<')) { + $this->markTestSkipped('Causal Consistency is only supported on MongoDB 3.6 or higher'); + } + if (!$this->isShardedClusterUsingReplicasets()) { + $this->markTestSkipped('Causal Consistency is only supported with replicasets'); + } + break; + + case Server::TYPE_RS_PRIMARY: + if (version_compare($this->getFeatureCompatibilityVersion(), '3.6', '<')) { + $this->markTestSkipped('Causal Consistency is only supported on FCV 3.6 or higher'); + } + if ($this->getServerStorageEngine() !== 'wiredTiger') { + $this->markTestSkipped('Causal Consistency requires WiredTiger storage engine'); + } + break; + + default: + $this->markTestSkipped('Causal Consistency is not supported'); + } + } + protected function skipIfTransactionsAreNotSupported() { if ($this->getPrimaryServer()->getType() === Server::TYPE_STANDALONE) {