Skip to content

Commit 35e6181

Browse files
committed
Merge ChangeStreamsProseTest into WatchFunctionalTest
1 parent 6afb08f commit 35e6181

File tree

4 files changed

+109
-125
lines changed

4 files changed

+109
-125
lines changed

tests/FunctionalTestCase.php

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,31 @@
1111
use MongoDB\Driver\WriteConcern;
1212
use MongoDB\Driver\Exception\CommandException;
1313
use MongoDB\Operation\CreateCollection;
14+
use MongoDB\Operation\DatabaseCommand;
1415
use MongoDB\Operation\DropCollection;
16+
use InvalidArgumentException;
1517
use stdClass;
1618
use UnexpectedValueException;
1719

1820
abstract class FunctionalTestCase extends TestCase
1921
{
22+
protected $manager;
23+
24+
private $configuredFailPoints = [];
25+
2026
public function setUp()
2127
{
28+
parent::setUp();
29+
2230
$this->manager = new Manager(static::getUri());
31+
$this->configuredFailPoints = [];
32+
}
33+
34+
public function tearDown()
35+
{
36+
$this->disableFailPoints();
37+
38+
parent::tearDown();
2339
}
2440

2541
protected function assertCollectionCount($namespace, $count)
@@ -49,6 +65,39 @@ protected function assertSameObjectId($expectedObjectId, $actualObjectId)
4965
$this->assertEquals((string) $expectedObjectId, (string) $actualObjectId);
5066
}
5167

68+
/**
69+
* Configure a fail point for the test.
70+
*
71+
* The fail point will automatically be disabled during tearDown() to avoid
72+
* affecting a subsequent test.
73+
*
74+
* @param array|stdClass $command configureFailPoint command document
75+
* @throws InvalidArgumentException if $command is not a configureFailPoint command
76+
*/
77+
protected function configureFailPoint($command)
78+
{
79+
if (is_array($command)) {
80+
$command = (object) $command;
81+
}
82+
83+
if ( ! $command instanceof stdClass) {
84+
throw new InvalidArgumentException('$command is not an array or stdClass instance');
85+
}
86+
87+
if (key($command) !== 'configureFailPoint') {
88+
throw new InvalidArgumentException('$command is not a configureFailPoint command');
89+
}
90+
91+
$operation = new DatabaseCommand('admin', $command);
92+
$cursor = $operation->execute($this->getPrimaryServer());
93+
$result = $cursor->toArray()[0];
94+
95+
$this->assertCommandSucceeded($result);
96+
97+
// Record the fail point so it can be disabled during tearDown()
98+
$this->configuredFailPoints[] = $command->configureFailPoint;
99+
}
100+
52101
/**
53102
* Creates the test collection with the specified options.
54103
*
@@ -260,4 +309,24 @@ protected function skipIfTransactionsAreNotSupported()
260309
$this->markTestSkipped('Transactions require WiredTiger storage engine');
261310
}
262311
}
312+
313+
/**
314+
* Disables any fail points that were configured earlier in the test.
315+
*
316+
* This tracks fail points set via configureFailPoint() and should be called
317+
* during tearDown().
318+
*/
319+
private function disableFailPoints()
320+
{
321+
if (empty($this->configuredFailPoints)) {
322+
return;
323+
}
324+
325+
$server = $this->getPrimaryServer();
326+
327+
foreach ($this->configuredFailPoints as $failPoint) {
328+
$operation = new DatabaseCommand('admin', ['configureFailPoint' => $failPoint, 'mode' => 'off']);
329+
$operation->execute($server);
330+
}
331+
}
263332
}

tests/Operation/WatchFunctionalTest.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use MongoDB\Driver\Server;
1010
use MongoDB\Driver\WriteConcern;
1111
use MongoDB\Driver\Exception\LogicException;
12+
use MongoDB\Driver\Exception\ServerException;
1213
use MongoDB\Exception\ResumeTokenException;
1314
use MongoDB\Operation\CreateCollection;
1415
use MongoDB\Operation\DatabaseCommand;
@@ -580,6 +581,45 @@ public function testInitialCursorIsNotClosed()
580581
$this->assertFalse($cursor->isDead());
581582
}
582583

584+
/**
585+
* Prose test: "ChangeStream will not attempt to resume after encountering
586+
* error code 11601 (Interrupted), 136 (CappedPositionLost), or 237
587+
* (CursorKilled) while executing a getMore command."
588+
*
589+
* @dataProvider provideNonResumableErrorCodes
590+
*/
591+
public function testNonResumableErrorCodes($errorCode)
592+
{
593+
if (version_compare($this->getServerVersion(), '4.0.0', '<')) {
594+
$this->markTestSkipped('failCommand is not supported');
595+
}
596+
597+
$this->configureFailPoint([
598+
'configureFailPoint' => 'failCommand',
599+
'mode' => ['times' => 1],
600+
'data' => ['failCommands' => ['getMore'], 'errorCode' => $errorCode],
601+
]);
602+
603+
$this->insertDocument(['x' => 1]);
604+
605+
$operation = new Watch($this->manager, $this->getDatabaseName(), $this->getCollectionName(), []);
606+
$changeStream = $operation->execute($this->getPrimaryServer());
607+
$changeStream->rewind();
608+
609+
$this->expectException(ServerException::class);
610+
$this->expectExceptionCode($errorCode);
611+
$changeStream->next();
612+
}
613+
614+
public function provideNonResumableErrorCodes()
615+
{
616+
return [
617+
[136], // CappedPositionLost
618+
[237], // CursorKilled
619+
[11601], // Interrupted
620+
];
621+
}
622+
583623
public function testNextResumeTokenNotFound()
584624
{
585625
if (version_compare($this->getServerVersion(), '4.1.8', '>=')) {

tests/SpecTests/ChangeStreamsProseTest.php

Lines changed: 0 additions & 72 deletions
This file was deleted.

tests/SpecTests/FunctionalTestCase.php

Lines changed: 0 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
use MongoDB\Client;
66
use MongoDB\Collection;
7-
use MongoDB\Database;
87
use MongoDB\Driver\Server;
98
use MongoDB\Driver\WriteConcern;
109
use MongoDB\Driver\Exception\BulkWriteException;
@@ -14,7 +13,6 @@
1413
use MongoDB\Tests\TestCase;
1514
use PHPUnit\Framework\SkippedTest;
1615
use ArrayIterator;
17-
use InvalidArgumentException;
1816
use IteratorIterator;
1917
use LogicException;
2018
use MultipleIterator;
@@ -32,21 +30,18 @@ class FunctionalTestCase extends BaseFunctionalTestCase
3230
const TOPOLOGY_REPLICASET = 'replicaset';
3331
const TOPOLOGY_SHARDED = 'sharded';
3432

35-
private $configuredFailPoints = [];
3633
private $context;
3734

3835
public function setUp()
3936
{
4037
parent::setUp();
4138

42-
$this->configuredFailPoints = [];
4339
$this->context = null;
4440
}
4541

4642
public function tearDown()
4743
{
4844
$this->context = null;
49-
$this->disableFailPoints();
5045

5146
parent::tearDown();
5247
}
@@ -141,39 +136,6 @@ protected function checkServerRequirements(array $runOn)
141136
$this->markTestSkipped(sprintf('Server version "%s" and topology "%s" do not meet test requirements: %s', $serverVersion, $topology, json_encode($runOn)));
142137
}
143138

144-
/**
145-
* Configure a fail point for the test.
146-
*
147-
* The fail point will automatically be disabled during tearDown() to avoid
148-
* affecting a subsequent test.
149-
*
150-
* @param array|stdClass $command configureFailPoint command document
151-
* @throws InvalidArgumentException if $command is not a configureFailPoint command
152-
*/
153-
protected function configureFailPoint($command)
154-
{
155-
if (is_array($command)) {
156-
$command = (object) $command;
157-
}
158-
159-
if ( ! $command instanceof stdClass) {
160-
throw new InvalidArgumentException('$command is not an array or stdClass instance');
161-
}
162-
163-
if (key($command) !== 'configureFailPoint') {
164-
throw new InvalidArgumentException('$command is not a configureFailPoint command');
165-
}
166-
167-
$database = new Database($this->manager, 'admin');
168-
$cursor = $database->command($command);
169-
$result = $cursor->toArray()[0];
170-
171-
$this->assertCommandSucceeded($result);
172-
173-
// Record the fail point so it can be disabled during tearDown()
174-
$this->configuredFailPoints[] = $command->configureFailPoint;
175-
}
176-
177139
/**
178140
* Decode a JSON spec test.
179141
*
@@ -255,21 +217,6 @@ private function getOutcomeCollection()
255217
return new Collection($this->manager, $context->databaseName, $context->outcomeCollectionName);
256218
}
257219

258-
/**
259-
* Disables any fail points that were configured earlier in the test.
260-
*
261-
* This tracks fail points set via configureFailPoint() and should be called
262-
* during tearDown().
263-
*/
264-
private function disableFailPoints()
265-
{
266-
$database = new Database($this->manager, 'admin');
267-
268-
foreach ($this->configuredFailPoints as $failPoint) {
269-
$database->command(['configureFailPoint' => $failPoint, 'mode' => 'off']);
270-
}
271-
}
272-
273220
/**
274221
* Return the corresponding topology constants for the current topology.
275222
*

0 commit comments

Comments
 (0)