description: "timeoutMS behaves correctly for GridFS upload operations"

schemaVersion: "1.9"

runOnRequirements:
  - minServerVersion: "4.4"
    serverless: forbid  # GridFS ops can be slow on serverless.

createEntities:
  - client:
      id: &failPointClient failPointClient
      useMultipleMongoses: false
  - client:
      id: &client client
      uriOptions:
        timeoutMS: 75
      useMultipleMongoses: false
  - database:
      id: &database database
      client: *client
      databaseName: &databaseName test
  - bucket:
      id: &bucket bucket
      database: *database
  - collection:
      id: &filesCollection filesCollection
      database: *database
      collectionName: &filesCollectionName fs.files
  - collection:
      id: &chunksCollection chunksCollection
      database: *database
      collectionName: &chunksCollectionName fs.chunks

initialData:
  - collectionName: *filesCollectionName
    databaseName: *databaseName
    documents: []
  - collectionName: *chunksCollectionName
    databaseName: *databaseName
    documents: []

tests:
  # Many tests in this file do not specify command monitoring expectations because GridFS uploads internally do a
  # number of operations, so expecting an exact set of commands can cause flaky failures.

  - description: "timeoutMS can be overridden for upload"
    operations:
      - name: failPoint
        object: testRunner
        arguments:
          client: *failPointClient
          failPoint:
            configureFailPoint: failCommand
            mode: { times: 1 }
            data:
              failCommands: ["find"]
              blockConnection: true
              blockTimeMS: 100
      - name: upload
        object: *bucket
        arguments:
          filename: filename
          source: { $$hexBytes: "1122334455" }
          timeoutMS: 1000

  # On the first write to the bucket, drivers check if the files collection is empty to see if indexes need to be
  # created.
  - description: "timeoutMS applied to initial find on files collection"
    operations:
      - name: failPoint
        object: testRunner
        arguments:  
          client: *failPointClient
          failPoint:
            configureFailPoint: failCommand
            mode: { times: 1 }
            data:
              failCommands: ["find"]
              blockConnection: true
              blockTimeMS: 100
      - name: upload
        object: *bucket
        arguments:
          filename: filename
          source: { $$hexBytes: "1122334455" }
        expectError:
          isTimeoutError: true

  # On the first write to the bucket, drivers check if the files collection has the correct indexes.
  - description: "timeoutMS applied to listIndexes on files collection"
    operations:
      - name: failPoint
        object: testRunner
        arguments:  
          client: *failPointClient
          failPoint:
            configureFailPoint: failCommand
            mode: { times: 1 }
            data:
              failCommands: ["listIndexes"]
              blockConnection: true
              blockTimeMS: 100
      - name: upload
        object: *bucket
        arguments:
          filename: filename
          source: { $$hexBytes: "1122334455" }
        expectError:
          isTimeoutError: true

  # If the files collection is empty when the first write to the bucket occurs, drivers attempt to create an index
  # on the bucket's files collection.
  - description: "timeoutMS applied to index creation for files collection"
    operations:
      - name: failPoint
        object: testRunner
        arguments:  
          client: *failPointClient
          failPoint:
            configureFailPoint: failCommand
            mode: { times: 1 }
            data:
              failCommands: ["createIndexes"]
              blockConnection: true
              blockTimeMS: 100
      - name: upload
        object: *bucket
        arguments:
          filename: filename
          source: { $$hexBytes: "1122334455" }
        expectError:
          isTimeoutError: true

  # On the first write to the bucket, drivers check if the chunks collection has the correct indexes.
  - description: "timeoutMS applied to listIndexes on chunks collection"
    operations:
      - name: failPoint
        object: testRunner
        arguments:  
          client: *failPointClient
          failPoint:
            configureFailPoint: failCommand
            # The first listIndexes will be on the files collection, so we skip it.
            mode: { skip: 1 }
            data:
              failCommands: ["listIndexes"]
              blockConnection: true
              blockTimeMS: 100
      - name: upload
        object: *bucket
        arguments:
          filename: filename
          source: { $$hexBytes: "1122334455" }
        expectError:
          isTimeoutError: true

  # If the files collection is empty when the first write to the bucket occurs, drivers attempt to create an index
  # on the bucket's chunks collection.
  - description: "timeoutMS applied to index creation for chunks collection"
    operations:
      - name: failPoint
        object: testRunner
        arguments:  
          client: *failPointClient
          failPoint:
            configureFailPoint: failCommand
            # This index is created after the one on the files collection, so we skip the first createIndexes command
            # and target the second.
            mode: { skip: 1 }
            data:
              failCommands: ["createIndexes"]
              blockConnection: true
              blockTimeMS: 100
      - name: upload
        object: *bucket
        arguments:
          filename: filename
          source: { $$hexBytes: "1122334455" }
        expectError:
          isTimeoutError: true

  - description: "timeoutMS applied to chunk insertion"
    operations:
      - name: failPoint
        object: testRunner
        arguments:  
          client: *failPointClient
          failPoint:
            configureFailPoint: failCommand
            mode: { times: 1 }
            data:
              failCommands: ["insert"]
              blockConnection: true
              blockTimeMS: 100
      - name: upload
        object: *bucket
        arguments:
          filename: filename
          source: { $$hexBytes: "1122334455" }
        expectError:
          isTimeoutError: true

  - description: "timeoutMS applied to creation of files document"
    operations:
      - name: failPoint
        object: testRunner
        arguments:  
          client: *failPointClient
          failPoint:
            configureFailPoint: failCommand
            # Skip the insert to upload the chunk. Because the whole file fits into one chunk, the second insert will
            # be the files document upload.
            mode: { skip: 1 }
            data:
              failCommands: ["insert"]
              blockConnection: true
              blockTimeMS: 100
      - name: upload
        object: *bucket
        arguments:
          filename: filename
          source: { $$hexBytes: "1122334455" }
        expectError:
          isTimeoutError: true

  # Test that drivers apply timeoutMS to the entire upload rather than refreshing it between individual commands. We
  # test this by blocking the "find" and "listIndexes" commands for 50ms each and performing an upload. The upload
  # should inherit timeoutMS=75 from the client/database and the server takes over 75ms total, so the operation should
  # fail.
  - description: "timeoutMS applied to upload as a whole, not individual parts"
    operations:
      - name: failPoint
        object: testRunner
        arguments:
          client: *failPointClient
          failPoint:
            configureFailPoint: failCommand
            mode: { times: 2 }
            data:
              failCommands: ["find", "listIndexes"]
              blockConnection: true
              blockTimeMS: 50
      - name: upload
        object: *bucket
        arguments:
          filename: filename
          source: { $$hexBytes: "1122334455" }
        expectError:
          isTimeoutError: true
