Skip to content

Commit e6d5397

Browse files
committed
CRUD prose tests 5-9
1 parent e61a8cd commit e6d5397

5 files changed

+456
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?php
2+
3+
namespace MongoDB\Tests\SpecTests\Crud;
4+
5+
use MongoDB\BulkWriteCommandBuilder;
6+
use MongoDB\Driver\Exception\BulkWriteCommandException;
7+
use MongoDB\Driver\Monitoring\CommandFailedEvent;
8+
use MongoDB\Driver\Monitoring\CommandStartedEvent;
9+
use MongoDB\Driver\Monitoring\CommandSubscriber;
10+
use MongoDB\Driver\Monitoring\CommandSucceededEvent;
11+
use MongoDB\Tests\SpecTests\FunctionalTestCase;
12+
13+
/**
14+
* Prose test 5: MongoClient.bulkWrite collects WriteConcernErrors across batches
15+
*
16+
* @see https://github.com/mongodb/specifications/tree/master/source/crud/tests#5-mongoclientbulkwrite-collects-writeconcernerrors-across-batches
17+
*/
18+
class Prose5_BulkWriteCollectsWriteConcernErrorsAcrossBatchesTest extends FunctionalTestCase
19+
{
20+
public function testCollectWriteConcernErrors(): void
21+
{
22+
if ($this->isServerless()) {
23+
$this->markTestSkipped('bulkWrite command is not supported');
24+
}
25+
26+
$this->skipIfServerVersion('<', '8.0', 'bulkWrite command is not supported');
27+
28+
$client = self::createTestClient(null, ['retryWrites' => false]);
29+
30+
$maxWriteBatchSize = $this->getPrimaryServer()->getInfo()['maxWriteBatchSize'] ?? null;
31+
self::assertIsInt($maxWriteBatchSize);
32+
33+
$this->configureFailPoint([
34+
'configureFailPoint' => 'failCommand',
35+
'mode' => ['times' => 2],
36+
'data' => [
37+
'failCommands' => ['bulkWrite'],
38+
'writeConcernError' => [
39+
'code' => 91, // ShutdownInProgress
40+
'errmsg' => 'Replication is being shut down',
41+
],
42+
],
43+
]);
44+
45+
$collection = $client->selectCollection($this->getDatabaseName(), $this->getCollectionName());
46+
$bulkWrite = BulkWriteCommandBuilder::createWithCollection($collection);
47+
48+
for ($i = 0; $i < $maxWriteBatchSize + 1; ++$i) {
49+
$bulkWrite->insertOne(['a' => 'b']);
50+
}
51+
52+
$subscriber = new class implements CommandSubscriber {
53+
public int $numBulkWriteObserved = 0;
54+
55+
public function commandStarted(CommandStartedEvent $event): void
56+
{
57+
if ($event->getCommandName() === 'bulkWrite') {
58+
++$this->numBulkWriteObserved;
59+
}
60+
}
61+
62+
public function commandSucceeded(CommandSucceededEvent $event): void
63+
{
64+
}
65+
66+
public function commandFailed(CommandFailedEvent $event): void
67+
{
68+
}
69+
};
70+
71+
$client->addSubscriber($subscriber);
72+
73+
try {
74+
$client->bulkWrite($bulkWrite);
75+
self::fail('BulkWriteCommandException was not thrown');
76+
} catch (BulkWriteCommandException $e) {
77+
self::assertCount(2, $e->getWriteConcernErrors());
78+
$partialResult = $e->getPartialResult();
79+
self::assertNotNull($partialResult);
80+
self::assertSame($maxWriteBatchSize + 1, $partialResult->getInsertedCount());
81+
self::assertSame(2, $subscriber->numBulkWriteObserved);
82+
}
83+
}
84+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
<?php
2+
3+
namespace MongoDB\Tests\SpecTests\Crud;
4+
5+
use MongoDB\BulkWriteCommandBuilder;
6+
use MongoDB\Driver\Exception\BulkWriteCommandException;
7+
use MongoDB\Driver\Monitoring\CommandFailedEvent;
8+
use MongoDB\Driver\Monitoring\CommandStartedEvent;
9+
use MongoDB\Driver\Monitoring\CommandSubscriber;
10+
use MongoDB\Driver\Monitoring\CommandSucceededEvent;
11+
use MongoDB\Tests\SpecTests\FunctionalTestCase;
12+
13+
/**
14+
* Prose test 6: MongoClient.bulkWrite handles individual WriteErrors across batches
15+
*
16+
* @see https://github.com/mongodb/specifications/tree/master/source/crud/tests#6-mongoclientbulkwrite-handles-individual-writeerrors-across-batches
17+
*/
18+
class Prose6_BulkWriteHandlesWriteErrorsAcrossBatchesTest extends FunctionalTestCase
19+
{
20+
public function setUp(): void
21+
{
22+
parent::setUp();
23+
24+
if ($this->isServerless()) {
25+
$this->markTestSkipped('bulkWrite command is not supported');
26+
}
27+
28+
$this->skipIfServerVersion('<', '8.0', 'bulkWrite command is not supported');
29+
}
30+
31+
public function testOrdered(): void
32+
{
33+
$client = self::createTestClient();
34+
35+
$maxWriteBatchSize = $this->getPrimaryServer()->getInfo()['maxWriteBatchSize'] ?? null;
36+
self::assertIsInt($maxWriteBatchSize);
37+
38+
$collection = $client->selectCollection($this->getDatabaseName(), $this->getCollectionName());
39+
$collection->drop();
40+
$collection->insertOne(['_id' => 1]);
41+
42+
$bulkWrite = BulkWriteCommandBuilder::createWithCollection($collection, ['ordered' => true]);
43+
44+
for ($i = 0; $i < $maxWriteBatchSize + 1; ++$i) {
45+
$bulkWrite->insertOne(['_id' => 1]);
46+
}
47+
48+
$subscriber = $this->createSubscriber();
49+
$client->addSubscriber($subscriber);
50+
51+
try {
52+
$client->bulkWrite($bulkWrite);
53+
self::fail('BulkWriteCommandException was not thrown');
54+
} catch (BulkWriteCommandException $e) {
55+
self::assertCount(1, $e->getWriteErrors());
56+
self::assertSame(1, $subscriber->numBulkWriteObserved);
57+
}
58+
}
59+
60+
public function testUnordered(): void
61+
{
62+
$client = self::createTestClient();
63+
64+
$maxWriteBatchSize = $this->getPrimaryServer()->getInfo()['maxWriteBatchSize'] ?? null;
65+
self::assertIsInt($maxWriteBatchSize);
66+
67+
$collection = $client->selectCollection($this->getDatabaseName(), $this->getCollectionName());
68+
$collection->drop();
69+
$collection->insertOne(['_id' => 1]);
70+
71+
$bulkWrite = BulkWriteCommandBuilder::createWithCollection($collection, ['ordered' => false]);
72+
73+
for ($i = 0; $i < $maxWriteBatchSize + 1; ++$i) {
74+
$bulkWrite->insertOne(['_id' => 1]);
75+
}
76+
77+
$subscriber = $this->createSubscriber();
78+
$client->addSubscriber($subscriber);
79+
80+
try {
81+
$client->bulkWrite($bulkWrite);
82+
self::fail('BulkWriteCommandException was not thrown');
83+
} catch (BulkWriteCommandException $e) {
84+
self::assertCount($maxWriteBatchSize + 1, $e->getWriteErrors());
85+
self::assertSame(2, $subscriber->numBulkWriteObserved);
86+
}
87+
}
88+
89+
private function createSubscriber(): CommandSubscriber
90+
{
91+
return new class implements CommandSubscriber {
92+
public int $numBulkWriteObserved = 0;
93+
94+
public function commandStarted(CommandStartedEvent $event): void
95+
{
96+
if ($event->getCommandName() === 'bulkWrite') {
97+
++$this->numBulkWriteObserved;
98+
}
99+
}
100+
101+
public function commandSucceeded(CommandSucceededEvent $event): void
102+
{
103+
}
104+
105+
public function commandFailed(CommandFailedEvent $event): void
106+
{
107+
}
108+
};
109+
}
110+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<?php
2+
3+
namespace MongoDB\Tests\SpecTests\Crud;
4+
5+
use MongoDB\BulkWriteCommandBuilder;
6+
use MongoDB\Driver\Monitoring\CommandFailedEvent;
7+
use MongoDB\Driver\Monitoring\CommandStartedEvent;
8+
use MongoDB\Driver\Monitoring\CommandSubscriber;
9+
use MongoDB\Driver\Monitoring\CommandSucceededEvent;
10+
use MongoDB\Tests\SpecTests\FunctionalTestCase;
11+
12+
use function str_repeat;
13+
14+
/**
15+
* Prose test 7: MongoClient.bulkWrite handles a cursor requiring a getMore
16+
*
17+
* @see https://github.com/mongodb/specifications/tree/master/source/crud/tests#7-mongoclientbulkwrite-handles-a-cursor-requiring-a-getmore
18+
*/
19+
class Prose7_BulkWriteHandlesCursorRequiringGetMoreTest extends FunctionalTestCase
20+
{
21+
public function testHandlesCursor(): void
22+
{
23+
if ($this->isServerless()) {
24+
$this->markTestSkipped('bulkWrite command is not supported');
25+
}
26+
27+
$this->skipIfServerVersion('<', '8.0', 'bulkWrite command is not supported');
28+
29+
$client = self::createTestClient();
30+
31+
$maxBsonObjectSize = $this->getPrimaryServer()->getInfo()['maxBsonObjectSize'] ?? null;
32+
self::assertIsInt($maxBsonObjectSize);
33+
34+
$collection = $client->selectCollection($this->getDatabaseName(), $this->getCollectionName());
35+
$collection->drop();
36+
37+
$bulkWrite = BulkWriteCommandBuilder::createWithCollection($collection, ['verboseResults' => true]);
38+
$bulkWrite->updateOne(
39+
['_id' => str_repeat('a', (int) ($maxBsonObjectSize / 2))],
40+
['$set' => ['x' => 1]],
41+
['upsert' => true],
42+
);
43+
$bulkWrite->updateOne(
44+
['_id' => str_repeat('b', (int) ($maxBsonObjectSize / 2))],
45+
['$set' => ['x' => 1]],
46+
['upsert' => true],
47+
);
48+
49+
$subscriber = new class implements CommandSubscriber {
50+
public int $numGetMoreObserved = 0;
51+
52+
public function commandStarted(CommandStartedEvent $event): void
53+
{
54+
if ($event->getCommandName() === 'getMore') {
55+
++$this->numGetMoreObserved;
56+
}
57+
}
58+
59+
public function commandSucceeded(CommandSucceededEvent $event): void
60+
{
61+
}
62+
63+
public function commandFailed(CommandFailedEvent $event): void
64+
{
65+
}
66+
};
67+
68+
$client->addSubscriber($subscriber);
69+
70+
$result = $client->bulkWrite($bulkWrite);
71+
72+
self::assertSame(2, $result->getUpsertedCount());
73+
self::assertCount(2, $result->getUpdateResults());
74+
self::assertSame(1, $subscriber->numGetMoreObserved);
75+
}
76+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<?php
2+
3+
namespace MongoDB\Tests\SpecTests\Crud;
4+
5+
use MongoDB\BulkWriteCommandBuilder;
6+
use MongoDB\Driver\Monitoring\CommandFailedEvent;
7+
use MongoDB\Driver\Monitoring\CommandStartedEvent;
8+
use MongoDB\Driver\Monitoring\CommandSubscriber;
9+
use MongoDB\Driver\Monitoring\CommandSucceededEvent;
10+
use MongoDB\Tests\SpecTests\FunctionalTestCase;
11+
12+
use function str_repeat;
13+
14+
/**
15+
* Prose test 8: MongoClient.bulkWrite handles a cursor requiring a getMore within a transaction
16+
*
17+
* @see https://github.com/mongodb/specifications/tree/master/source/crud/tests#8-mongoclientbulkwrite-handles-a-cursor-requiring-getmore-within-a-transaction
18+
*/
19+
class Prose8_BulkWriteHandlesCursorRequiringGetMoreWithinTransactionTest extends FunctionalTestCase
20+
{
21+
public function testHandlesCursorWithinTransaction(): void
22+
{
23+
if ($this->isServerless()) {
24+
$this->markTestSkipped('bulkWrite command is not supported');
25+
}
26+
27+
$this->skipIfServerVersion('<', '8.0', 'bulkWrite command is not supported');
28+
$this->skipIfTransactionsAreNotSupported();
29+
30+
$client = self::createTestClient();
31+
32+
$maxBsonObjectSize = $this->getPrimaryServer()->getInfo()['maxBsonObjectSize'] ?? null;
33+
self::assertIsInt($maxBsonObjectSize);
34+
35+
$collection = $client->selectCollection($this->getDatabaseName(), $this->getCollectionName());
36+
$collection->drop();
37+
38+
$bulkWrite = BulkWriteCommandBuilder::createWithCollection($collection, ['verboseResults' => true]);
39+
$bulkWrite->updateOne(
40+
['_id' => str_repeat('a', (int) ($maxBsonObjectSize / 2))],
41+
['$set' => ['x' => 1]],
42+
['upsert' => true],
43+
);
44+
$bulkWrite->updateOne(
45+
['_id' => str_repeat('b', (int) ($maxBsonObjectSize / 2))],
46+
['$set' => ['x' => 1]],
47+
['upsert' => true],
48+
);
49+
50+
$subscriber = new class implements CommandSubscriber {
51+
public int $numGetMoreObserved = 0;
52+
53+
public function commandStarted(CommandStartedEvent $event): void
54+
{
55+
if ($event->getCommandName() === 'getMore') {
56+
++$this->numGetMoreObserved;
57+
}
58+
}
59+
60+
public function commandSucceeded(CommandSucceededEvent $event): void
61+
{
62+
}
63+
64+
public function commandFailed(CommandFailedEvent $event): void
65+
{
66+
}
67+
};
68+
69+
$client->addSubscriber($subscriber);
70+
71+
$session = $client->startSession();
72+
$session->startTransaction();
73+
74+
/* Note: the prose test does not call for committing the transaction.
75+
* The transaction will be aborted when the Session object is freed. */
76+
$result = $client->bulkWrite($bulkWrite, ['session' => $session]);
77+
78+
self::assertSame(2, $result->getUpsertedCount());
79+
self::assertCount(2, $result->getUpdateResults());
80+
self::assertSame(1, $subscriber->numGetMoreObserved);
81+
}
82+
}

0 commit comments

Comments
 (0)