public async Task BatchInvalidOptionsAsync()
        {
            Container             container           = BatchUnitTests.GetContainer();
            List <RequestOptions> badBatchOptionsList = new List <RequestOptions>()
            {
                new RequestOptions()
                {
                    IfMatchEtag = "cond",
                },
                new RequestOptions()
                {
                    IfNoneMatchEtag = "cond2",
                }
            };

            foreach (RequestOptions batchOptions in badBatchOptionsList)
            {
                BatchCore batch = (BatchCore)
                                  new BatchCore((ContainerInternal)container, new Cosmos.PartitionKey(BatchUnitTests.PartitionKey1))
                                  .ReadItem("someId");

                await BatchUnitTests.VerifyExceptionThrownOnExecuteAsync(
                    batch,
                    typeof(ArgumentException),
                    ClientResources.BatchRequestOptionNotSupported,
                    batchOptions);
            }
        }
        public async Task BatchSingleServerResponseAsync()
        {
            List <TransactionalBatchOperationResult> expectedResults = new List <TransactionalBatchOperationResult>();
            CosmosJsonDotNetSerializer jsonSerializer = new CosmosJsonDotNetSerializer();
            TestItem testItem = new TestItem("tst");

            Stream       itemStream     = jsonSerializer.ToStream <TestItem>(testItem);
            MemoryStream resourceStream = itemStream as MemoryStream;

            if (resourceStream == null)
            {
                await itemStream.CopyToAsync(resourceStream);

                resourceStream.Position = 0;
            }

            expectedResults.Add(
                new TransactionalBatchOperationResult(HttpStatusCode.OK)
            {
                ETag           = "theETag",
                SubStatusCode  = (SubStatusCodes)1100,
                ResourceStream = resourceStream
            });
            expectedResults.Add(new TransactionalBatchOperationResult(HttpStatusCode.Conflict));

            double requestCharge = 3.6;

            TestHandler testHandler = new TestHandler(async(request, cancellationToken) =>
            {
                ResponseMessage responseMessage = new ResponseMessage(HttpStatusCode.OK, requestMessage: null, errorMessage: null)
                {
                    Content = await new BatchResponsePayloadWriter(expectedResults).GeneratePayloadAsync()
                };

                responseMessage.Headers.RequestCharge = requestCharge;
                return(responseMessage);
            });

            Container container = BatchUnitTests.GetContainer(testHandler);

            TransactionalBatchResponse batchResponse = await new BatchCore((ContainerInternal)container, new Cosmos.PartitionKey(BatchUnitTests.PartitionKey1))
                                                       .ReadItem("id1")
                                                       .ReadItem("id2")
                                                       .ExecuteAsync();

            Assert.AreEqual(HttpStatusCode.OK, batchResponse.StatusCode);
            Assert.AreEqual(requestCharge, batchResponse.RequestCharge);

            TransactionalBatchOperationResult <TestItem> result0 = batchResponse.GetOperationResultAtIndex <TestItem>(0);

            Assert.AreEqual(expectedResults[0].StatusCode, result0.StatusCode);
            Assert.AreEqual(expectedResults[0].SubStatusCode, result0.SubStatusCode);
            Assert.AreEqual(expectedResults[0].ETag, result0.ETag);
            Assert.AreEqual(testItem, result0.Resource);

            Assert.AreEqual(expectedResults[1].StatusCode, batchResponse[1].StatusCode);
            Assert.AreEqual(SubStatusCodes.Unknown, batchResponse[1].SubStatusCode);
            Assert.IsNull(batchResponse[1].ETag);
            Assert.IsNull(batchResponse[1].ResourceStream);
        }
 public async Task BatchNoOperationsAsync()
 {
     Container          container = BatchUnitTests.GetContainer();
     TransactionalBatch batch     = new BatchCore((ContainerInternal)container, new Cosmos.PartitionKey(BatchUnitTests.PartitionKey1));
     await BatchUnitTests.VerifyExceptionThrownOnExecuteAsync(
         batch,
         typeof(ArgumentException),
         ClientResources.BatchNoOperations);
 }
        public async Task BatchWithTooManyOperationsAsync()
        {
            Container container      = BatchUnitTests.GetContainer();
            const int operationCount = Constants.MaxOperationsInDirectModeBatchRequest + 1;

            Batch batch = new BatchCore((ContainerCore)container, new Cosmos.PartitionKey(BatchUnitTests.PartitionKey1));

            for (int i = 0; i < operationCount; i++)
            {
                batch.ReadItem("someId");
            }

            await BatchUnitTests.VerifyExceptionThrownOnExecuteAsync(
                batch,
                typeof(ArgumentException),
                ClientResources.BatchTooLarge);
        }
        public async Task BatchInvalidItemOptionsAsync()
        {
            Container container = BatchUnitTests.GetContainer();

            List <TransactionalBatchItemRequestOptions> badItemOptionsList = new List <TransactionalBatchItemRequestOptions>()
            {
                new TransactionalBatchItemRequestOptions()
                {
                    Properties = new Dictionary <string, object>
                    {
                        // EPK without string representation
                        { WFConstants.BackendHeaders.EffectivePartitionKey, new byte[1] {
                              0x41
                          } }
                    }
                },
                new TransactionalBatchItemRequestOptions()
                {
                    Properties = new Dictionary <string, object>
                    {
                        // EPK string without corresponding byte representation
                        { WFConstants.BackendHeaders.EffectivePartitionKeyString, "epk" }
                    }
                },
                new TransactionalBatchItemRequestOptions()
                {
                    Properties = new Dictionary <string, object>
                    {
                        // Partition key without EPK string
                        { HttpConstants.HttpHeaders.PartitionKey, "epk" }
                    }
                }
            };

            foreach (TransactionalBatchItemRequestOptions itemOptions in badItemOptionsList)
            {
                TransactionalBatch batch = new BatchCore((ContainerInternal)container, new Cosmos.PartitionKey(BatchUnitTests.PartitionKey1))
                                           .ReplaceItem("someId", new TestItem("repl"), itemOptions);

                await BatchUnitTests.VerifyExceptionThrownOnExecuteAsync(
                    batch,
                    typeof(ArgumentException));
            }
        }
        public async Task BatchLargerThanServerRequestAsync()
        {
            Container container      = BatchUnitTests.GetContainer();
            const int operationCount = 20;
            int       appxDocSize    = Constants.MaxDirectModeBatchRequestBodySizeInBytes / operationCount;

            // Increase the doc size by a bit so all docs won't fit in one server request.
            appxDocSize = (int)(appxDocSize * 1.05);
            Batch batch = new BatchCore((ContainerCore)container, new Cosmos.PartitionKey(BatchUnitTests.PartitionKey1));

            for (int i = 0; i < operationCount; i++)
            {
                TestItem testItem = new TestItem(new string('x', appxDocSize));
                batch.CreateItem(testItem);
            }

            await BatchUnitTests.VerifyExceptionThrownOnExecuteAsync(
                batch,
                typeof(RequestEntityTooLargeException));
        }
        public async Task BatchJsonServerResponseAsync()
        {
            TestHandler testHandler = new TestHandler((request, cancellationToken) =>
            {
                HttpStatusCode serverStatusCode = HttpStatusCode.Gone;
                Stream serverContent            = new MemoryStream(Encoding.UTF8.GetBytes("{ \"random\": 1 }"));

                ResponseMessage responseMessage = new ResponseMessage(serverStatusCode, requestMessage: null, errorMessage: null)
                {
                    Content = serverContent
                };

                return(Task.FromResult(responseMessage));
            });

            Container container = BatchUnitTests.GetContainer(testHandler);

            TransactionalBatchResponse batchResponse = await new BatchCore((ContainerInternal)container, new Cosmos.PartitionKey(BatchUnitTests.PartitionKey1))
                                                       .ReadItem("id1")
                                                       .ReadItem("id2")
                                                       .ExecuteAsync();

            Assert.AreEqual(HttpStatusCode.Gone, batchResponse.StatusCode);
        }
        public async Task BatchCrudRequestAsync()
        {
            Random random = new Random();

            TestItem createItem = new TestItem("create");

            byte[] createStreamContent = new byte[20];
            random.NextBytes(createStreamContent);
            byte[] createStreamBinaryId = new byte[20];
            random.NextBytes(createStreamBinaryId);
            int createTtl = 45;
            TransactionalBatchItemRequestOptions createRequestOptions = new TransactionalBatchItemRequestOptions()
            {
                Properties = new Dictionary <string, object>()
                {
                    { WFConstants.BackendHeaders.BinaryId, createStreamBinaryId },
                    { WFConstants.BackendHeaders.TimeToLiveInSeconds, createTtl.ToString() },
                },
                IndexingDirective = Microsoft.Azure.Cosmos.IndexingDirective.Exclude
            };

            string readId = Guid.NewGuid().ToString();

            byte[] readStreamBinaryId = new byte[20];
            random.NextBytes(readStreamBinaryId);
            TransactionalBatchItemRequestOptions readRequestOptions = new TransactionalBatchItemRequestOptions()
            {
                Properties = new Dictionary <string, object>()
                {
                    { WFConstants.BackendHeaders.BinaryId, readStreamBinaryId }
                },
                IfNoneMatchEtag = "readCondition"
            };

            TestItem replaceItem = new TestItem("repl");

            byte[] replaceStreamContent = new byte[20];
            random.NextBytes(replaceStreamContent);
            const string replaceStreamId = "replStream";

            byte[] replaceStreamBinaryId = new byte[20];
            random.NextBytes(replaceStreamBinaryId);
            TransactionalBatchItemRequestOptions replaceRequestOptions = new TransactionalBatchItemRequestOptions()
            {
                Properties = new Dictionary <string, object>()
                {
                    { WFConstants.BackendHeaders.BinaryId, replaceStreamBinaryId }
                },
                IfMatchEtag       = "replCondition",
                IndexingDirective = Microsoft.Azure.Cosmos.IndexingDirective.Exclude
            };

            TestItem upsertItem = new TestItem("upsert");

            byte[] upsertStreamContent = new byte[20];
            random.NextBytes(upsertStreamContent);
            byte[] upsertStreamBinaryId = new byte[20];
            random.NextBytes(upsertStreamBinaryId);
            TransactionalBatchItemRequestOptions upsertRequestOptions = new TransactionalBatchItemRequestOptions()
            {
                Properties = new Dictionary <string, object>()
                {
                    { WFConstants.BackendHeaders.BinaryId, upsertStreamBinaryId }
                },
                IfMatchEtag       = "upsertCondition",
                IndexingDirective = Microsoft.Azure.Cosmos.IndexingDirective.Exclude
            };

            string deleteId = Guid.NewGuid().ToString();

            byte[] deleteStreamBinaryId = new byte[20];
            random.NextBytes(deleteStreamBinaryId);
            TransactionalBatchItemRequestOptions deleteRequestOptions = new TransactionalBatchItemRequestOptions()
            {
                Properties = new Dictionary <string, object>()
                {
                    { WFConstants.BackendHeaders.BinaryId, deleteStreamBinaryId }
                },
                IfNoneMatchEtag = "delCondition"
            };

            CosmosJsonDotNetSerializer jsonSerializer = new CosmosJsonDotNetSerializer();
            BatchTestHandler           testHandler    = new BatchTestHandler((request, operations) =>
            {
                Assert.AreEqual(new Cosmos.PartitionKey(BatchUnitTests.PartitionKey1).ToString(), request.Headers.PartitionKey);
                Assert.AreEqual(bool.TrueString, request.Headers[HttpConstants.HttpHeaders.IsBatchAtomic]);
                Assert.AreEqual(bool.TrueString, request.Headers[HttpConstants.HttpHeaders.IsBatchOrdered]);
                Assert.IsFalse(request.Headers.TryGetValue(HttpConstants.HttpHeaders.ShouldBatchContinueOnError, out string unused));

                Assert.AreEqual(16, operations.Count);

                int operationIndex = 0;

                // run the loop twice, once for operations without item request options, and one for with item request options
                for (int loopCount = 0; loopCount < 2; loopCount++)
                {
                    bool hasItemRequestOptions = loopCount == 1;

                    ItemBatchOperation operation = operations[operationIndex++];
                    Assert.AreEqual(OperationType.Create, operation.OperationType);
                    Assert.IsNull(operation.Id);
                    Assert.AreEqual(createItem, BatchUnitTests.Deserialize(operation.ResourceBody, jsonSerializer));
                    BatchUnitTests.VerifyBatchItemRequestOptionsAreEqual(hasItemRequestOptions ? createRequestOptions : null, operation.RequestOptions);

                    operation = operations[operationIndex++];
                    Assert.AreEqual(OperationType.Read, operation.OperationType);
                    Assert.AreEqual(readId, operation.Id);
                    BatchUnitTests.VerifyBatchItemRequestOptionsAreEqual(hasItemRequestOptions ? readRequestOptions : null, operation.RequestOptions);

                    operation = operations[operationIndex++];
                    Assert.AreEqual(OperationType.Replace, operation.OperationType);
                    Assert.AreEqual(replaceItem.Id, operation.Id);
                    Assert.AreEqual(replaceItem, BatchUnitTests.Deserialize(operation.ResourceBody, jsonSerializer));
                    BatchUnitTests.VerifyBatchItemRequestOptionsAreEqual(hasItemRequestOptions ? replaceRequestOptions : null, operation.RequestOptions);

                    operation = operations[operationIndex++];
                    Assert.AreEqual(OperationType.Upsert, operation.OperationType);
                    Assert.IsNull(operation.Id);
                    Assert.AreEqual(upsertItem, BatchUnitTests.Deserialize(operation.ResourceBody, jsonSerializer));
                    BatchUnitTests.VerifyBatchItemRequestOptionsAreEqual(hasItemRequestOptions ? upsertRequestOptions : null, operation.RequestOptions);

                    operation = operations[operationIndex++];
                    Assert.AreEqual(OperationType.Delete, operation.OperationType);
                    Assert.AreEqual(deleteId, operation.Id);
                    BatchUnitTests.VerifyBatchItemRequestOptionsAreEqual(hasItemRequestOptions ? deleteRequestOptions : null, operation.RequestOptions);

                    operation = operations[operationIndex++];
                    Assert.AreEqual(OperationType.Create, operation.OperationType);
                    Assert.IsNull(operation.Id);
                    Assert.IsTrue(operation.ResourceBody.Span.SequenceEqual(createStreamContent));
                    BatchUnitTests.VerifyBatchItemRequestOptionsAreEqual(hasItemRequestOptions ? createRequestOptions : null, operation.RequestOptions);

                    operation = operations[operationIndex++];
                    Assert.AreEqual(OperationType.Replace, operation.OperationType);
                    Assert.AreEqual(replaceStreamId, operation.Id);
                    Assert.IsTrue(operation.ResourceBody.Span.SequenceEqual(replaceStreamContent));
                    BatchUnitTests.VerifyBatchItemRequestOptionsAreEqual(hasItemRequestOptions ? replaceRequestOptions : null, operation.RequestOptions);

                    operation = operations[operationIndex++];
                    Assert.AreEqual(OperationType.Upsert, operation.OperationType);
                    Assert.IsNull(operation.Id);
                    Assert.IsTrue(operation.ResourceBody.Span.SequenceEqual(upsertStreamContent));
                    BatchUnitTests.VerifyBatchItemRequestOptionsAreEqual(hasItemRequestOptions ? upsertRequestOptions : null, operation.RequestOptions);
                }

                return(Task.FromResult(new ResponseMessage(HttpStatusCode.OK)));
            });

            Container container = BatchUnitTests.GetContainer(testHandler);

            TransactionalBatchResponse batchResponse = await new BatchCore((ContainerInternal)container, new Cosmos.PartitionKey(BatchUnitTests.PartitionKey1))
                                                       .CreateItem(createItem)
                                                       .ReadItem(readId)
                                                       .ReplaceItem(replaceItem.Id, replaceItem)
                                                       .UpsertItem(upsertItem)
                                                       .DeleteItem(deleteId)

                                                       // stream
                                                       .CreateItemStream(new MemoryStream(createStreamContent))
                                                       .ReplaceItemStream(replaceStreamId, new MemoryStream(replaceStreamContent))
                                                       .UpsertItemStream(new MemoryStream(upsertStreamContent))

                                                       // regular with options
                                                       .CreateItem(createItem, createRequestOptions)
                                                       .ReadItem(readId, readRequestOptions)
                                                       .ReplaceItem(replaceItem.Id, replaceItem, replaceRequestOptions)
                                                       .UpsertItem(upsertItem, upsertRequestOptions)
                                                       .DeleteItem(deleteId, deleteRequestOptions)

                                                       // stream with options
                                                       .CreateItemStream(new MemoryStream(createStreamContent), createRequestOptions)
                                                       .ReplaceItemStream(replaceStreamId, new MemoryStream(replaceStreamContent), replaceRequestOptions)
                                                       .UpsertItemStream(new MemoryStream(upsertStreamContent), upsertRequestOptions)
                                                       .ExecuteAsync();
        }