description: "poc-retryable-writes"

schemaVersion: "1.0"

runOnRequirements:
  - minServerVersion: "3.6"
    topologies: [ replicaset ]

createEntities:
  - client:
      id: &client0 client0
      useMultipleMongoses: false
      observeEvents: [ commandStartedEvent ]
  - client:
      id: &client1 client1
      uriOptions: { retryWrites: false }
      useMultipleMongoses: false
      observeEvents: [ commandStartedEvent ]
  - database:
      id: &database0 database0
      client: *client0
      databaseName: &databaseName retryable-writes-tests
  - database:
      id: &database1 database1
      client: *client1
      databaseName: *databaseName
  - collection:
      id: &collection0 collection0
      database: *database0
      collectionName: &collectionName coll
  - collection:
      id: &collection1 collection1
      database: *database1
      collectionName: *collectionName

initialData:
  - collectionName: *collectionName
    databaseName: *databaseName
    documents:
      - { _id: 1, x: 11 }
      - { _id: 2, x: 22 }

tests:
  - description: "FindOneAndUpdate is committed on first attempt"
    operations:
      - name: failPoint
        object: testRunner
        arguments:
          client: *client0
          failPoint:
            configureFailPoint: onPrimaryTransactionalWrite
            mode: { times: 1 }
      - name: findOneAndUpdate
        object: *collection0
        arguments:
          filter: { _id: 1 }
          update: { $inc: { x : 1 } }
          returnDocument: Before
        expectResult: { _id: 1, x: 11 }
    outcome:
      - collectionName: *collectionName
        databaseName: *databaseName
        documents:
          - { _id: 1, x: 12 }
          - { _id: 2, x: 22 }

  - description: "FindOneAndUpdate is not committed on first attempt"
    operations:
      - name: failPoint
        object: testRunner
        arguments:
          client: *client0
          failPoint:
            configureFailPoint: onPrimaryTransactionalWrite
            mode: { times: 1 }
            data: { failBeforeCommitExceptionCode: 1 }
      - name: findOneAndUpdate
        object: *collection0
        arguments:
          filter: { _id: 1 }
          update: { $inc: { x : 1 } }
          returnDocument: Before
        expectResult: { _id: 1, x: 11 }
    outcome:
      - collectionName: *collectionName
        databaseName: *databaseName
        documents:
          - { _id: 1, x: 12 }
          - { _id: 2, x: 22 }

  - description: "FindOneAndUpdate is never committed"
    operations:
      - name: failPoint
        object: testRunner
        arguments:
          client: *client0
          failPoint:
            configureFailPoint: onPrimaryTransactionalWrite
            mode: { times: 2 }
            data: { failBeforeCommitExceptionCode: 1 }
      - name: findOneAndUpdate
        object: *collection0
        arguments:
          filter: { _id: 1 }
          update: { $inc: { x : 1 } }
          returnDocument: Before
        expectError: { isError: true }
    outcome:
      - collectionName: *collectionName
        databaseName: *databaseName
        documents:
          - { _id: 1, x: 11 }
          - { _id: 2, x: 22 }

  - description: "InsertMany succeeds after PrimarySteppedDown"
    runOnRequirements: &failCommand_requirements
      - minServerVersion: "4.0"
        topologies: [ replicaset ]
      - minServerVersion: "4.1.7"
        # Original test uses "sharded", but retryable writes requires a sharded
        # cluster backed by replica sets
        topologies: [ sharded-replicaset ]
    operations:
      - name: failPoint
        object: testRunner
        arguments:
          client: *client0
          failPoint:
            configureFailPoint: failCommand
            mode: { times: 1 }
            data:
              failCommands: [ insert ]
              errorCode: 189 # PrimarySteppedDown
              errorLabels: [  RetryableWriteError ]
      - name: insertMany
        object: *collection0
        arguments:
          documents:
            # Documents are modified from original test for "initialData"
            - { _id: 3, x: 33 }
            - { _id: 4, x: 44 }
          ordered: true
        expectResult:
          # InsertManyResult is optional because all of its fields are optional
          $$unsetOrMatches: { insertedIds: { $$unsetOrMatches: { 0: 3, 1: 4 } } }
    outcome:
      - collectionName: *collectionName
        databaseName: *databaseName
        documents:
          - { _id: 1, x: 11 }
          - { _id: 2, x: 22 }
          - { _id: 3, x: 33 }
          - { _id: 4, x: 44 }

  - description: "InsertOne fails after connection failure when retryWrites option is false"
    runOnRequirements: *failCommand_requirements
    operations:
      - name: failPoint
        object: testRunner
        arguments:
          client: *client1
          failPoint:
            configureFailPoint: failCommand
            mode: { times: 1 }
            data:
                failCommands: [ insert ]
                closeConnection: true
      - name: insertOne
        object: *collection1
        arguments:
          document: { _id: 3, x: 33 }
        expectError:
          # If retryWrites is false, the driver should not add the
          # RetryableWriteError label to the error.
          errorLabelsOmit: [ RetryableWriteError ]
    outcome:
      - collectionName: *collectionName
        databaseName: *databaseName
        documents:
          - { _id: 1, x: 11 }
          - { _id: 2, x: 22 }

  - description: "InsertOne fails after multiple retryable writeConcernErrors"
    runOnRequirements: *failCommand_requirements
    operations:
      - name: failPoint
        object: testRunner
        arguments:
          client: *client0
          failPoint:
            configureFailPoint: failCommand
            mode: { times: 2 }
            data:
              failCommands: [ insert ]
              writeConcernError:
                code: 91 # ShutdownInProgress
                errmsg: "Replication is being shut down"
      - name: insertOne
        object: *collection0
        arguments:
          document: { _id: 3, x: 33 }
        expectError:
          errorLabelsContain: [ RetryableWriteError ]
    outcome:
      - collectionName: *collectionName
        databaseName: *databaseName
        documents:
          - { _id: 1, x: 11 }
          - { _id: 2, x: 22 }
          - { _id: 3, x: 33 }  # The write was still applied
