runOn:
    -
        minServerVersion: "4.0"
        topology: ["replicaset"]
    -
        minServerVersion: "4.1.8"
        topology: ["sharded"]

database_name: &database_name "withTransaction-tests"
collection_name: &collection_name "test"

data: []

# These tests use error codes where the TransientTransactionError label will be
# applied to the error response for commitTransaction. This will cause the
# entire transaction to be retried instead of commitTransaction.
#
# See: https://github.com/mongodb/mongo/blob/r4.1.6/src/mongo/db/handle_request_response.cpp
tests:
  -
    description: transaction is retried after commitTransaction TransientTransactionError (LockTimeout)
    failPoint:
      configureFailPoint: failCommand
      mode: { times: 2 }
      data:
          failCommands: ["commitTransaction"]
          errorCode: 24 # LockTimeout
          closeConnection: false
    operations: &operations
      -
        name: withTransaction
        object: session0
        arguments:
          callback:
            operations:
              -
                name: insertOne
                object: collection
                arguments:
                  session: session0
                  document: { _id: 1 }
                result:
                  insertedId: 1
    expectations: &expectations
      -
        command_started_event:
          command:
            insert: *collection_name
            documents:
              - { _id: 1 }
            ordered: true
            lsid: session0
            txnNumber: { $numberLong: "1" }
            startTransaction: true
            autocommit: false
            # omitted fields
            readConcern: ~
            writeConcern: ~
          command_name: insert
          database_name: *database_name
      -
        command_started_event:
          command:
            commitTransaction: 1
            lsid: session0
            txnNumber: { $numberLong: "1" }
            autocommit: false
            # omitted fields
            readConcern: ~
            startTransaction: ~
            writeConcern: ~
          command_name: commitTransaction
          database_name: admin
      -
        command_started_event:
          command:
            insert: *collection_name
            documents:
              - { _id: 1 }
            ordered: true
            lsid: session0
            # second transaction will be causally consistent with the first
            readConcern: { afterClusterTime: 42 }
            # txnNumber is incremented when retrying the transaction
            txnNumber: { $numberLong: "2" }
            startTransaction: true
            autocommit: false
            # omitted fields
            writeConcern: ~
          command_name: insert
          database_name: *database_name
      -
        command_started_event:
          command:
            commitTransaction: 1
            lsid: session0
            txnNumber: { $numberLong: "2" }
            autocommit: false
            # omitted fields
            readConcern: ~
            startTransaction: ~
            writeConcern: ~
          command_name: commitTransaction
          database_name: admin
      -
        command_started_event:
          command:
            insert: *collection_name
            documents:
              - { _id: 1 }
            ordered: true
            lsid: session0
            # third transaction will be causally consistent with the second
            readConcern: { afterClusterTime: 42 }
            # txnNumber is incremented when retrying the transaction
            txnNumber: { $numberLong: "3" }
            startTransaction: true
            autocommit: false
            # omitted fields
            writeConcern: ~
          command_name: insert
          database_name: *database_name
      -
        command_started_event:
          command:
            commitTransaction: 1
            lsid: session0
            txnNumber: { $numberLong: "3" }
            autocommit: false
            # omitted fields
            readConcern: ~
            startTransaction: ~
            writeConcern: ~
          command_name: commitTransaction
          database_name: admin
    outcome: &outcome
      collection:
        data:
          - { _id: 1 }
  -
    description: transaction is retried after commitTransaction TransientTransactionError (WriteConflict)
    failPoint:
      configureFailPoint: failCommand
      mode: { times: 2 }
      data:
          failCommands: ["commitTransaction"]
          errorCode: 112 # WriteConflict
          closeConnection: false
    operations: *operations
    expectations: *expectations
    outcome: *outcome
  -
    description: transaction is retried after commitTransaction TransientTransactionError (SnapshotUnavailable)
    failPoint:
      configureFailPoint: failCommand
      mode: { times: 2 }
      data:
          failCommands: ["commitTransaction"]
          errorCode: 246 # SnapshotUnavailable
          closeConnection: false
    operations: *operations
    expectations: *expectations
    outcome: *outcome
  -
    description: transaction is retried after commitTransaction TransientTransactionError (NoSuchTransaction)
    failPoint:
      configureFailPoint: failCommand
      mode: { times: 2 }
      data:
          failCommands: ["commitTransaction"]
          errorCode: 251 # NoSuchTransaction
          closeConnection: false
    operations: *operations
    expectations: *expectations
    outcome: *outcome