PHPLIB-468: Integrate spec tests for Convenient Transactions API

parent 0d09f2a7
...@@ -5,6 +5,7 @@ namespace MongoDB\Tests\SpecTests; ...@@ -5,6 +5,7 @@ namespace MongoDB\Tests\SpecTests;
use Exception; use Exception;
use MongoDB\Driver\Exception\BulkWriteException; use MongoDB\Driver\Exception\BulkWriteException;
use MongoDB\Driver\Exception\CommandException; use MongoDB\Driver\Exception\CommandException;
use MongoDB\Driver\Exception\ExecutionTimeoutException;
use MongoDB\Driver\Exception\RuntimeException; use MongoDB\Driver\Exception\RuntimeException;
use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\InvalidArgumentException;
use MongoDB\Tests\TestCase; use MongoDB\Tests\TestCase;
...@@ -26,9 +27,10 @@ final class ErrorExpectation ...@@ -26,9 +27,10 @@ final class ErrorExpectation
*/ */
private static $codeNameMap = [ private static $codeNameMap = [
'Interrupted' => 11601, 'Interrupted' => 11601,
'WriteConflict' => 112, 'MaxTimeMSExpired' => 50,
'NoSuchTransaction' => 251, 'NoSuchTransaction' => 251,
'OperationNotSupportedInTransaction' => 263, 'OperationNotSupportedInTransaction' => 263,
'WriteConflict' => 112,
]; ];
/** @var integer */ /** @var integer */
...@@ -198,7 +200,7 @@ final class ErrorExpectation ...@@ -198,7 +200,7 @@ final class ErrorExpectation
* around this be comparing the error code against a map. * around this be comparing the error code against a map.
* *
* TODO: Remove this once PHPC-1386 is resolved. */ * TODO: Remove this once PHPC-1386 is resolved. */
if ($actual instanceof BulkWriteException) { if ($actual instanceof BulkWriteException || $actual instanceof ExecutionTimeoutException) {
$test->assertArrayHasKey($this->codeName, self::$codeNameMap); $test->assertArrayHasKey($this->codeName, self::$codeNameMap);
$test->assertSame(self::$codeNameMap[$this->codeName], $actual->getCode()); $test->assertSame(self::$codeNameMap[$this->codeName], $actual->getCode());
...@@ -207,6 +209,14 @@ final class ErrorExpectation ...@@ -207,6 +209,14 @@ final class ErrorExpectation
$test->assertInstanceOf(CommandException::class, $actual); $test->assertInstanceOf(CommandException::class, $actual);
$result = $actual->getResultDocument(); $result = $actual->getResultDocument();
if (isset($result->writeConcernError)) {
$test->assertObjectHasAttribute('codeName', $result->writeConcernError);
$test->assertSame($this->codeName, $result->writeConcernError->codeName);
return;
}
$test->assertObjectHasAttribute('codeName', $result); $test->assertObjectHasAttribute('codeName', $result);
$test->assertSame($this->codeName, $result->codeName); $test->assertSame($this->codeName, $result->codeName);
} }
......
...@@ -20,6 +20,7 @@ use function array_map; ...@@ -20,6 +20,7 @@ use function array_map;
use function fclose; use function fclose;
use function fopen; use function fopen;
use function MongoDB\is_last_pipeline_operator_write; use function MongoDB\is_last_pipeline_operator_write;
use function MongoDB\with_transaction;
use function stream_get_contents; use function stream_get_contents;
use function strtolower; use function strtolower;
...@@ -127,6 +128,29 @@ final class Operation ...@@ -127,6 +128,29 @@ final class Operation
return $o; return $o;
} }
/**
* This method is exclusively used to prepare nested operations for the
* withTransaction session operation
*
* @return Operation
*/
private static function fromConvenientTransactions(stdClass $operation)
{
$o = new self($operation);
if (isset($operation->error)) {
$o->errorExpectation = ErrorExpectation::fromTransactions($operation);
}
$o->resultExpectation = ResultExpectation::fromTransactions($operation, $o->getResultAssertionType());
if (isset($operation->collectionOptions)) {
$o->collectionOptions = (array) $operation->collectionOptions;
}
return $o;
}
public static function fromCrud(stdClass $operation) public static function fromCrud(stdClass $operation)
{ {
$o = new self($operation); $o = new self($operation);
...@@ -177,16 +201,17 @@ final class Operation ...@@ -177,16 +201,17 @@ final class Operation
/** /**
* Execute the operation and assert its outcome. * Execute the operation and assert its outcome.
* *
* @param FunctionalTestCase $test Test instance * @param FunctionalTestCase $test Test instance
* @param Context $context Execution context * @param Context $context Execution context
* @param bool $bubbleExceptions If true, any exception that was caught is rethrown
*/ */
public function assert(FunctionalTestCase $test, Context $context) public function assert(FunctionalTestCase $test, Context $context, $bubbleExceptions = false)
{ {
$result = null; $result = null;
$exception = null; $exception = null;
try { try {
$result = $this->execute($context); $result = $this->execute($test, $context);
/* Eagerly iterate the results of a cursor. This both allows an /* Eagerly iterate the results of a cursor. This both allows an
* exception to be thrown sooner and ensures that any expected * exception to be thrown sooner and ensures that any expected
...@@ -211,6 +236,10 @@ final class Operation ...@@ -211,6 +236,10 @@ final class Operation
if (isset($this->resultExpectation)) { if (isset($this->resultExpectation)) {
$this->resultExpectation->assert($test, $result); $this->resultExpectation->assert($test, $result);
} }
if ($exception && $bubbleExceptions) {
throw $exception;
}
} }
/** /**
...@@ -220,7 +249,7 @@ final class Operation ...@@ -220,7 +249,7 @@ final class Operation
* @return mixed * @return mixed
* @throws LogicException if the operation is unsupported * @throws LogicException if the operation is unsupported
*/ */
private function execute(Context $context) private function execute(FunctionalTestCase $test, Context $context)
{ {
switch ($this->object) { switch ($this->object) {
case self::OBJECT_CLIENT: case self::OBJECT_CLIENT:
...@@ -248,9 +277,9 @@ final class Operation ...@@ -248,9 +277,9 @@ final class Operation
return $this->executeForDatabase($database, $context); return $this->executeForDatabase($database, $context);
case self::OBJECT_SESSION0: case self::OBJECT_SESSION0:
return $this->executeForSession($context->session0, $context); return $this->executeForSession($context->session0, $test, $context);
case self::OBJECT_SESSION1: case self::OBJECT_SESSION1:
return $this->executeForSession($context->session1, $context); return $this->executeForSession($context->session1, $test, $context);
default: default:
throw new LogicException('Unsupported object: ' . $this->object); throw new LogicException('Unsupported object: ' . $this->object);
} }
...@@ -479,12 +508,13 @@ final class Operation ...@@ -479,12 +508,13 @@ final class Operation
/** /**
* Executes the session operation and return its result. * Executes the session operation and return its result.
* *
* @param Session $session * @param Session $session
* @param Context $context Execution context * @param FunctionalTestCase $test
* @param Context $context Execution context
* @return mixed * @return mixed
* @throws LogicException if the session operation is unsupported * @throws LogicException if the session operation is unsupported
*/ */
private function executeForSession(Session $session, Context $context) private function executeForSession(Session $session, FunctionalTestCase $test, Context $context)
{ {
switch ($this->name) { switch ($this->name) {
case 'abortTransaction': case 'abortTransaction':
...@@ -495,6 +525,21 @@ final class Operation ...@@ -495,6 +525,21 @@ final class Operation
$options = isset($this->arguments['options']) ? (array) $this->arguments['options'] : []; $options = isset($this->arguments['options']) ? (array) $this->arguments['options'] : [];
return $session->startTransaction($context->prepareOptions($options)); return $session->startTransaction($context->prepareOptions($options));
case 'withTransaction':
/** @var self[] $callbackOperations */
$callbackOperations = array_map(function ($operation) {
return self::fromConvenientTransactions($operation);
}, $this->arguments['callback']->operations);
$callback = function () use ($callbackOperations, $test, $context) {
foreach ($callbackOperations as $operation) {
$operation->assert($test, $context, true);
}
};
$options = isset($this->arguments['options']) ? (array) $this->arguments['options'] : [];
return with_transaction($session, $callback, $context->prepareOptions($options));
default: default:
throw new LogicException('Unsupported session operation: ' . $this->name); throw new LogicException('Unsupported session operation: ' . $this->name);
} }
......
...@@ -12,6 +12,7 @@ use MongoDB\Driver\Server; ...@@ -12,6 +12,7 @@ use MongoDB\Driver\Server;
use stdClass; use stdClass;
use Symfony\Bridge\PhpUnit\SetUpTearDownTrait; use Symfony\Bridge\PhpUnit\SetUpTearDownTrait;
use function basename; use function basename;
use function dirname;
use function file_get_contents; use function file_get_contents;
use function get_object_vars; use function get_object_vars;
use function glob; use function glob;
...@@ -34,17 +35,17 @@ class TransactionsSpecTest extends FunctionalTestCase ...@@ -34,17 +35,17 @@ class TransactionsSpecTest extends FunctionalTestCase
* @var array * @var array
*/ */
private static $incompleteTests = [ private static $incompleteTests = [
'read-pref: default readPreference' => 'PHPLIB does not properly inherit readPreference for transactions', 'transactions/read-pref: default readPreference' => 'PHPLIB does not properly inherit readPreference for transactions',
'read-pref: primary readPreference' => 'PHPLIB does not properly inherit readPreference for transactions', 'transactions/read-pref: primary readPreference' => 'PHPLIB does not properly inherit readPreference for transactions',
'run-command: run command with secondary read preference in client option and primary read preference in transaction options' => 'PHPLIB does not properly inherit readPreference for transactions', 'transactions/run-command: run command with secondary read preference in client option and primary read preference in transaction options' => 'PHPLIB does not properly inherit readPreference for transactions',
'transaction-options: transaction options inherited from client' => 'PHPLIB does not properly inherit readConcern for transactions', 'transactions/transaction-options: transaction options inherited from client' => 'PHPLIB does not properly inherit readConcern for transactions',
'transaction-options: readConcern local in defaultTransactionOptions' => 'PHPLIB does not properly inherit readConcern for transactions', 'transactions/transaction-options: readConcern local in defaultTransactionOptions' => 'PHPLIB does not properly inherit readConcern for transactions',
'transaction-options: readConcern snapshot in startTransaction options' => 'PHPLIB does not properly inherit readConcern for transactions', 'transactions/transaction-options: readConcern snapshot in startTransaction options' => 'PHPLIB does not properly inherit readConcern for transactions',
]; ];
private static function doSetUpBeforeClass() private function doSetUp()
{ {
parent::setUpBeforeClass(); parent::setUp();
static::killAllSessions(); static::killAllSessions();
} }
...@@ -184,9 +185,9 @@ class TransactionsSpecTest extends FunctionalTestCase ...@@ -184,9 +185,9 @@ class TransactionsSpecTest extends FunctionalTestCase
{ {
$testArgs = []; $testArgs = [];
foreach (glob(__DIR__ . '/transactions/*.json') as $filename) { foreach (glob(__DIR__ . '/transactions*/*.json') as $filename) {
$json = $this->decodeJson(file_get_contents($filename)); $json = $this->decodeJson(file_get_contents($filename));
$group = basename($filename, '.json'); $group = basename(dirname($filename)) . '/' . basename($filename, '.json');
$runOn = isset($json->runOn) ? $json->runOn : null; $runOn = isset($json->runOn) ? $json->runOn : null;
$data = isset($json->data) ? $json->data : []; $data = isset($json->data) ? $json->data : [];
$databaseName = isset($json->database_name) ? $json->database_name : null; $databaseName = isset($json->database_name) ? $json->database_name : null;
......
{
"runOn": [
{
"minServerVersion": "4.0",
"topology": [
"replicaset"
]
},
{
"minServerVersion": "4.1.8",
"topology": [
"sharded"
]
}
],
"database_name": "withTransaction-tests",
"collection_name": "test",
"data": [],
"tests": [
{
"description": "withTransaction succeeds if callback aborts",
"useMultipleMongoses": true,
"operations": [
{
"name": "withTransaction",
"object": "session0",
"arguments": {
"callback": {
"operations": [
{
"name": "insertOne",
"object": "collection",
"arguments": {
"session": "session0",
"document": {
"_id": 1
}
},
"result": {
"insertedId": 1
}
},
{
"name": "abortTransaction",
"object": "session0"
}
]
}
}
}
],
"expectations": [
{
"command_started_event": {
"command": {
"insert": "test",
"documents": [
{
"_id": 1
}
],
"ordered": true,
"lsid": "session0",
"txnNumber": {
"$numberLong": "1"
},
"startTransaction": true,
"autocommit": false,
"readConcern": null,
"writeConcern": null
},
"command_name": "insert",
"database_name": "withTransaction-tests"
}
},
{
"command_started_event": {
"command": {
"abortTransaction": 1,
"lsid": "session0",
"txnNumber": {
"$numberLong": "1"
},
"autocommit": false,
"readConcern": null,
"startTransaction": null,
"writeConcern": null
},
"command_name": "abortTransaction",
"database_name": "admin"
}
}
],
"outcome": {
"collection": {
"data": []
}
}
},
{
"description": "withTransaction succeeds if callback aborts with no ops",
"useMultipleMongoses": true,
"operations": [
{
"name": "withTransaction",
"object": "session0",
"arguments": {
"callback": {
"operations": [
{
"name": "abortTransaction",
"object": "session0"
}
]
}
}
}
],
"expectations": [],
"outcome": {
"collection": {
"data": []
}
}
},
{
"description": "withTransaction still succeeds if callback aborts and runs extra op",
"useMultipleMongoses": true,
"operations": [
{
"name": "withTransaction",
"object": "session0",
"arguments": {
"callback": {
"operations": [
{
"name": "insertOne",
"object": "collection",
"arguments": {
"session": "session0",
"document": {
"_id": 1
}
},
"result": {
"insertedId": 1
}
},
{
"name": "abortTransaction",
"object": "session0"
},
{
"name": "insertOne",
"object": "collection",
"arguments": {
"session": "session0",
"document": {
"_id": 2
}
},
"result": {
"insertedId": 2
}
}
]
}
}
}
],
"expectations": [
{
"command_started_event": {
"command": {
"insert": "test",
"documents": [
{
"_id": 1
}
],
"ordered": true,
"lsid": "session0",
"txnNumber": {
"$numberLong": "1"
},
"startTransaction": true,
"autocommit": false,
"readConcern": null,
"writeConcern": null
},
"command_name": "insert",
"database_name": "withTransaction-tests"
}
},
{
"command_started_event": {
"command": {
"abortTransaction": 1,
"lsid": "session0",
"txnNumber": {
"$numberLong": "1"
},
"autocommit": false,
"readConcern": null,
"startTransaction": null,
"writeConcern": null
},
"command_name": "abortTransaction",
"database_name": "admin"
}
},
{
"command_started_event": {
"command": {
"insert": "test",
"documents": [
{
"_id": 2
}
],
"ordered": true,
"lsid": "session0",
"autocommit": null,
"readConcern": null,
"startTransaction": null,
"writeConcern": null
},
"command_name": "insert",
"database_name": "withTransaction-tests"
}
}
],
"outcome": {
"collection": {
"data": [
{
"_id": 2
}
]
}
}
}
]
}
{
"runOn": [
{
"minServerVersion": "4.0",
"topology": [
"replicaset"
]
},
{
"minServerVersion": "4.1.8",
"topology": [
"sharded"
]
}
],
"database_name": "withTransaction-tests",
"collection_name": "test",
"data": [],
"tests": [
{
"description": "withTransaction succeeds if callback commits",
"useMultipleMongoses": true,
"operations": [
{
"name": "withTransaction",
"object": "session0",
"arguments": {
"callback": {
"operations": [
{
"name": "insertOne",
"object": "collection",
"arguments": {
"session": "session0",
"document": {
"_id": 1
}
},
"result": {
"insertedId": 1
}
},
{
"name": "insertOne",
"object": "collection",
"arguments": {
"session": "session0",
"document": {
"_id": 2
}
},
"result": {
"insertedId": 2
}
},
{
"name": "commitTransaction",
"object": "session0"
}
]
}
}
}
],
"expectations": [
{
"command_started_event": {
"command": {
"insert": "test",
"documents": [
{
"_id": 1
}
],
"ordered": true,
"lsid": "session0",
"txnNumber": {
"$numberLong": "1"
},
"startTransaction": true,
"autocommit": false,
"readConcern": null,
"writeConcern": null
},
"command_name": "insert",
"database_name": "withTransaction-tests"
}
},
{
"command_started_event": {
"command": {
"insert": "test",
"documents": [
{
"_id": 2
}
],
"ordered": true,
"lsid": "session0",
"txnNumber": {
"$numberLong": "1"
},
"autocommit": false,
"readConcern": null,
"startTransaction": null,
"writeConcern": null
},
"command_name": "insert",
"database_name": "withTransaction-tests"
}
},
{
"command_started_event": {
"command": {
"commitTransaction": 1,
"lsid": "session0",
"txnNumber": {
"$numberLong": "1"
},
"autocommit": false,
"readConcern": null,
"startTransaction": null,
"writeConcern": null
},
"command_name": "commitTransaction",
"database_name": "admin"
}
}
],
"outcome": {
"collection": {
"data": [
{
"_id": 1
},
{
"_id": 2
}
]
}
}
},
{
"description": "withTransaction still succeeds if callback commits and runs extra op",
"useMultipleMongoses": true,
"operations": [
{
"name": "withTransaction",
"object": "session0",
"arguments": {
"callback": {
"operations": [
{
"name": "insertOne",
"object": "collection",
"arguments": {
"session": "session0",
"document": {
"_id": 1
}
},
"result": {
"insertedId": 1
}
},
{
"name": "insertOne",
"object": "collection",
"arguments": {
"session": "session0",
"document": {
"_id": 2
}
},
"result": {
"insertedId": 2
}
},
{
"name": "commitTransaction",
"object": "session0"
},
{
"name": "insertOne",
"object": "collection",
"arguments": {
"session": "session0",
"document": {
"_id": 3
}
},
"result": {
"insertedId": 3
}
}
]
}
}
}
],
"expectations": [
{
"command_started_event": {
"command": {
"insert": "test",
"documents": [
{
"_id": 1
}
],
"ordered": true,
"lsid": "session0",
"txnNumber": {
"$numberLong": "1"
},
"startTransaction": true,
"autocommit": false,
"readConcern": null,
"writeConcern": null
},
"command_name": "insert",
"database_name": "withTransaction-tests"
}
},
{
"command_started_event": {
"command": {
"insert": "test",
"documents": [
{
"_id": 2
}
],
"ordered": true,
"lsid": "session0",
"txnNumber": {
"$numberLong": "1"
},
"autocommit": false,
"readConcern": null,
"startTransaction": null,
"writeConcern": null
},
"command_name": "insert",
"database_name": "withTransaction-tests"
}
},
{
"command_started_event": {
"command": {
"commitTransaction": 1,
"lsid": "session0",
"txnNumber": {
"$numberLong": "1"
},
"autocommit": false,
"readConcern": null,
"startTransaction": null,
"writeConcern": null
},
"command_name": "commitTransaction",
"database_name": "admin"
}
},
{
"command_started_event": {
"command": {
"insert": "test",
"documents": [
{
"_id": 3
}
],
"ordered": true,
"lsid": "session0",
"autocommit": null,
"readConcern": null,
"startTransaction": null,
"writeConcern": null
},
"command_name": "insert",
"database_name": "withTransaction-tests"
}
}
],
"outcome": {
"collection": {
"data": [
{
"_id": 1
},
{
"_id": 2
},
{
"_id": 3
}
]
}
}
}
]
}
{
"runOn": [
{
"minServerVersion": "4.0",
"topology": [
"replicaset"
]
},
{
"minServerVersion": "4.1.8",
"topology": [
"sharded"
]
}
],
"database_name": "withTransaction-tests",
"collection_name": "test",
"data": [],
"tests": [
{
"description": "callback succeeds after multiple connection errors",
"failPoint": {
"configureFailPoint": "failCommand",
"mode": {
"times": 2
},
"data": {
"failCommands": [
"insert"
],
"closeConnection": true
}
},
"operations": [
{
"name": "withTransaction",
"object": "session0",
"arguments": {
"callback": {
"operations": [
{
"name": "insertOne",
"object": "collection",
"arguments": {
"session": "session0",
"document": {
"_id": 1
}
}
}
]
}
}
}
],
"expectations": [
{
"command_started_event": {
"command": {
"insert": "test",
"documents": [
{
"_id": 1
}
],
"ordered": true,
"lsid": "session0",
"txnNumber": {
"$numberLong": "1"
},
"startTransaction": true,
"autocommit": false,
"readConcern": null,
"writeConcern": null
},
"command_name": "insert",
"database_name": "withTransaction-tests"
}
},
{
"command_started_event": {
"command": {
"abortTransaction": 1,
"lsid": "session0",
"txnNumber": {
"$numberLong": "1"
},
"autocommit": false,
"readConcern": null,
"startTransaction": null,
"writeConcern": null
},
"command_name": "abortTransaction",
"database_name": "admin"
}
},
{
"command_started_event": {
"command": {
"insert": "test",
"documents": [
{
"_id": 1
}
],
"ordered": true,
"lsid": "session0",
"readConcern": {
"afterClusterTime": 42
},
"txnNumber": {
"$numberLong": "2"
},
"startTransaction": true,
"autocommit": false,
"writeConcern": null
},
"command_name": "insert",
"database_name": "withTransaction-tests"
}
},
{
"command_started_event": {
"command": {
"abortTransaction": 1,
"lsid": "session0",
"txnNumber": {
"$numberLong": "2"
},
"autocommit": false,
"readConcern": null,
"startTransaction": null,
"writeConcern": null
},
"command_name": "abortTransaction",
"database_name": "admin"
}
},
{
"command_started_event": {
"command": {
"insert": "test",
"documents": [
{
"_id": 1
}
],
"ordered": true,
"lsid": "session0",
"readConcern": {
"afterClusterTime": 42
},
"txnNumber": {
"$numberLong": "3"
},
"startTransaction": true,
"autocommit": false,
"writeConcern": null
},
"command_name": "insert",
"database_name": "withTransaction-tests"
}
},
{
"command_started_event": {
"command": {
"commitTransaction": 1,
"lsid": "session0",
"txnNumber": {
"$numberLong": "3"
},
"autocommit": false,
"readConcern": null,
"startTransaction": null,
"writeConcern": null
},
"command_name": "commitTransaction",
"database_name": "admin"
}
}
],
"outcome": {
"collection": {
"data": [
{
"_id": 1
}
]
}
}
},
{
"description": "callback is not retried after non-transient error (DuplicateKeyError)",
"useMultipleMongoses": true,
"operations": [
{
"name": "withTransaction",
"object": "session0",
"arguments": {
"callback": {
"operations": [
{
"name": "insertOne",
"object": "collection",
"arguments": {
"session": "session0",
"document": {
"_id": 1
}
},
"result": {
"insertedId": 1
}
},
{
"name": "insertOne",
"object": "collection",
"arguments": {
"session": "session0",
"document": {
"_id": 1
}
},
"result": {
"errorLabelsOmit": [
"TransientTransactionError",
"UnknownTransactionCommitResult"
]
}
}
]
}
},
"result": {
"errorLabelsOmit": [
"TransientTransactionError",
"UnknownTransactionCommitResult"
]
}
}
],
"expectations": [
{
"command_started_event": {
"command": {
"insert": "test",
"documents": [
{
"_id": 1
}
],
"ordered": true,
"lsid": "session0",
"txnNumber": {
"$numberLong": "1"
},
"startTransaction": true,
"autocommit": false,
"readConcern": null,
"writeConcern": null
},
"command_name": "insert",
"database_name": "withTransaction-tests"
}
},
{
"command_started_event": {
"command": {
"insert": "test",
"documents": [
{
"_id": 1
}
],
"ordered": true,
"lsid": "session0",
"txnNumber": {
"$numberLong": "1"
},
"autocommit": false,
"readConcern": null,
"startTransaction": null,
"writeConcern": null
},
"command_name": "insert",
"database_name": "withTransaction-tests"
}
},
{
"command_started_event": {
"command": {
"abortTransaction": 1,
"lsid": "session0",
"txnNumber": {
"$numberLong": "1"
},
"autocommit": false,
"readConcern": null,
"startTransaction": null,
"writeConcern": null
},
"command_name": "abortTransaction",
"database_name": "admin"
}
}
],
"outcome": {
"collection": {
"data": []
}
}
}
]
}
This diff is collapsed.
{
"runOn": [
{
"minServerVersion": "4.1.6",
"topology": [
"replicaset"
]
},
{
"minServerVersion": "4.1.8",
"topology": [
"sharded"
]
}
],
"database_name": "withTransaction-tests",
"collection_name": "test",
"data": [],
"tests": [
{
"description": "transaction is retried after commitTransaction TransientTransactionError (PreparedTransactionInProgress)",
"failPoint": {
"configureFailPoint": "failCommand",
"mode": {
"times": 2
},
"data": {
"failCommands": [
"commitTransaction"
],
"errorCode": 267,
"closeConnection": false
}
},
"operations": [
{
"name": "withTransaction",
"object": "session0",
"arguments": {
"callback": {
"operations": [
{
"name": "insertOne",
"object": "collection",
"arguments": {
"session": "session0",
"document": {
"_id": 1
}
},
"result": {
"insertedId": 1
}
}
]
}
}
}
],
"expectations": [
{
"command_started_event": {
"command": {
"insert": "test",
"documents": [
{
"_id": 1
}
],
"ordered": true,
"lsid": "session0",
"txnNumber": {
"$numberLong": "1"
},
"startTransaction": true,
"autocommit": false,
"readConcern": null,
"writeConcern": null
},
"command_name": "insert",
"database_name": "withTransaction-tests"
}
},
{
"command_started_event": {
"command": {
"commitTransaction": 1,
"lsid": "session0",
"txnNumber": {
"$numberLong": "1"
},
"autocommit": false,
"readConcern": null,
"startTransaction": null,
"writeConcern": null
},
"command_name": "commitTransaction",
"database_name": "admin"
}
},
{
"command_started_event": {
"command": {
"insert": "test",
"documents": [
{
"_id": 1
}
],
"ordered": true,
"lsid": "session0",
"readConcern": {
"afterClusterTime": 42
},
"txnNumber": {
"$numberLong": "2"
},
"startTransaction": true,
"autocommit": false,
"writeConcern": null
},
"command_name": "insert",
"database_name": "withTransaction-tests"
}
},
{
"command_started_event": {
"command": {
"commitTransaction": 1,
"lsid": "session0",
"txnNumber": {
"$numberLong": "2"
},
"autocommit": false,
"readConcern": null,
"startTransaction": null,
"writeConcern": null
},
"command_name": "commitTransaction",
"database_name": "admin"
}
},
{
"command_started_event": {
"command": {
"insert": "test",
"documents": [
{
"_id": 1
}
],
"ordered": true,
"lsid": "session0",
"readConcern": {
"afterClusterTime": 42
},
"txnNumber": {
"$numberLong": "3"
},
"startTransaction": true,
"autocommit": false,
"writeConcern": null
},
"command_name": "insert",
"database_name": "withTransaction-tests"
}
},
{
"command_started_event": {
"command": {
"commitTransaction": 1,
"lsid": "session0",
"txnNumber": {
"$numberLong": "3"
},
"autocommit": false,
"readConcern": null,
"startTransaction": null,
"writeConcern": null
},
"command_name": "commitTransaction",
"database_name": "admin"
}
}
],
"outcome": {
"collection": {
"data": [
{
"_id": 1
}
]
}
}
}
]
}
{
"runOn": [
{
"minServerVersion": "4.0",
"topology": [
"replicaset"
]
},
{
"minServerVersion": "4.1.8",
"topology": [
"sharded"
]
}
],
"database_name": "withTransaction-tests",
"collection_name": "test",
"data": [],
"tests": [
{
"description": "withTransaction commits after callback returns",
"useMultipleMongoses": true,
"operations": [
{
"name": "withTransaction",
"object": "session0",
"arguments": {
"callback": {
"operations": [
{
"name": "insertOne",
"object": "collection",
"arguments": {
"session": "session0",
"document": {
"_id": 1
}
},
"result": {
"insertedId": 1
}
},
{
"name": "insertOne",
"object": "collection",
"arguments": {
"session": "session0",
"document": {
"_id": 2
}
},
"result": {
"insertedId": 2
}
}
]
}
}
}
],
"expectations": [
{
"command_started_event": {
"command": {
"insert": "test",
"documents": [
{
"_id": 1
}
],
"ordered": true,
"lsid": "session0",
"txnNumber": {
"$numberLong": "1"
},
"startTransaction": true,
"autocommit": false,
"readConcern": null,
"writeConcern": null
},
"command_name": "insert",
"database_name": "withTransaction-tests"
}
},
{
"command_started_event": {
"command": {
"insert": "test",
"documents": [
{
"_id": 2
}
],
"ordered": true,
"lsid": "session0",
"txnNumber": {
"$numberLong": "1"
},
"autocommit": false,
"readConcern": null,
"startTransaction": null,
"writeConcern": null
},
"command_name": "insert",
"database_name": "withTransaction-tests"
}
},
{
"command_started_event": {
"command": {
"commitTransaction": 1,
"lsid": "session0",
"txnNumber": {
"$numberLong": "1"
},
"autocommit": false,
"readConcern": null,
"startTransaction": null,
"writeConcern": null
},
"command_name": "commitTransaction",
"database_name": "admin"
}
}
],
"outcome": {
"collection": {
"data": [
{
"_id": 1
},
{
"_id": 2
}
]
}
}
},
{
"description": "withTransaction commits after callback returns (second transaction)",
"useMultipleMongoses": true,
"operations": [
{
"name": "withTransaction",
"object": "session0",
"arguments": {
"callback": {
"operations": [
{
"name": "insertOne",
"object": "collection",
"arguments": {
"session": "session0",
"document": {
"_id": 1
}
},
"result": {
"insertedId": 1
}
},
{
"name": "commitTransaction",
"object": "session0"
},
{
"name": "startTransaction",
"object": "session0"
},
{
"name": "insertOne",
"object": "collection",
"arguments": {
"session": "session0",
"document": {
"_id": 2
}
},
"result": {
"insertedId": 2
}
}
]
}
}
}
],
"expectations": [
{
"command_started_event": {
"command": {
"insert": "test",
"documents": [
{
"_id": 1
}
],
"ordered": true,
"lsid": "session0",
"txnNumber": {
"$numberLong": "1"
},
"startTransaction": true,
"autocommit": false,
"readConcern": null,
"writeConcern": null
},
"command_name": "insert",
"database_name": "withTransaction-tests"
}
},
{
"command_started_event": {
"command": {
"commitTransaction": 1,
"lsid": "session0",
"txnNumber": {
"$numberLong": "1"
},
"autocommit": false,
"readConcern": null,
"startTransaction": null,
"writeConcern": null
},
"command_name": "commitTransaction",
"database_name": "admin"
}
},
{
"command_started_event": {
"command": {
"insert": "test",
"documents": [
{
"_id": 2
}
],
"ordered": true,
"lsid": "session0",
"readConcern": {
"afterClusterTime": 42
},
"txnNumber": {
"$numberLong": "2"
},
"startTransaction": true,
"autocommit": false,
"writeConcern": null
},
"command_name": "insert",
"database_name": "withTransaction-tests"
}
},
{
"command_started_event": {
"command": {
"commitTransaction": 1,
"lsid": "session0",
"txnNumber": {
"$numberLong": "2"
},
"autocommit": false,
"readConcern": null,
"startTransaction": null,
"writeConcern": null
},
"command_name": "commitTransaction",
"database_name": "admin"
}
}
],
"outcome": {
"collection": {
"data": [
{
"_id": 1
},
{
"_id": 2
}
]
}
}
}
]
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment