public async Task EncryptionUTCreateItem()
        {
            Container container = this.GetContainerWithMockSetup();
            MyItem    item      = await EncryptionUnitTests.CreateItemAsync(container, EncryptionUnitTests.DekId, MyItem.PathsToEncrypt);

            // Validate server state
            Assert.IsTrue(this.testHandler.Items.TryGetValue(item.Id, out JObject serverItem));
            Assert.IsNotNull(serverItem);
            Assert.AreEqual(item.Id, serverItem.Property(Constants.Properties.Id).Value.Value <string>());
            Assert.AreEqual(item.PK, serverItem.Property(nameof(MyItem.PK)).Value.Value <string>());
            Assert.IsNull(serverItem.Property(nameof(MyItem.EncStr1)));
            Assert.IsNull(serverItem.Property(nameof(MyItem.EncInt)));

            JProperty eiJProp = serverItem.Property(Constants.Properties.EncryptedInfo);

            Assert.IsNotNull(eiJProp);
            Assert.IsNotNull(eiJProp.Value);
            Assert.AreEqual(JTokenType.Object, eiJProp.Value.Type);
            EncryptionProperties encryptionPropertiesAtServer = ((JObject)eiJProp.Value).ToObject <EncryptionProperties>();

            Assert.IsNotNull(encryptionPropertiesAtServer);
            Assert.AreEqual(EncryptionUnitTests.DekId, encryptionPropertiesAtServer.DataEncryptionKeyId);
            Assert.AreEqual(2, encryptionPropertiesAtServer.EncryptionFormatVersion);
            Assert.IsNotNull(encryptionPropertiesAtServer.EncryptedData);

            JObject decryptedJObj = EncryptionUnitTests.ParseStream(new MemoryStream(EncryptionUnitTests.DecryptData(encryptionPropertiesAtServer.EncryptedData)));

            Assert.AreEqual(2, decryptedJObj.Properties().Count());
            Assert.AreEqual(item.EncStr1, decryptedJObj.Property(nameof(MyItem.EncStr1)).Value.Value <string>());
            Assert.AreEqual(item.EncInt, decryptedJObj.Property(nameof(MyItem.EncInt)).Value.Value <int>());
        }
        public async Task EncryptionUTCreateItemWithUnknownDek()
        {
            Container container = this.GetContainerWithMockSetup();
            MyItem    item      = EncryptionUnitTests.GetNewItem();

            try
            {
                await container.CreateItemAsync(
                    item,
                    new Cosmos.PartitionKey(item.PK),
                    new ItemRequestOptions
                {
                    EncryptionOptions = new EncryptionOptions
                    {
                        DataEncryptionKeyId = "random",
                        EncryptionAlgorithm = EncryptionUnitTests.Algo,
                        PathsToEncrypt      = MyItem.PathsToEncrypt
                    }
                });

                Assert.Fail("Expected CreateItemAsync with unknown data encryption key to fail");
            }
            catch (Exception)
            {
                // todo: Should we expose a exception class in the contract too
            }
        }
        public async Task EncryptionUTReadItem()
        {
            Container container = this.GetContainerWithMockSetup();
            MyItem    item      = await EncryptionUnitTests.CreateItemAsync(container, EncryptionUnitTests.DekId, MyItem.PathsToEncrypt);

            ItemResponse <MyItem> readResponse = await container.ReadItemAsync <MyItem>(item.Id, new Cosmos.PartitionKey(item.PK));

            Assert.AreEqual(item, readResponse.Resource);
        }
        private static async Task <MyItem> CreateItemAsync(Container container, string dekId, List <string> pathsToEncrypt)
        {
            MyItem item = EncryptionUnitTests.GetNewItem();
            ItemResponse <MyItem> response = await container.CreateItemAsync <MyItem>(
                item,
                requestOptions : new ItemRequestOptions
            {
                EncryptionOptions = new EncryptionOptions
                {
                    DataEncryptionKeyId = dekId,
                    EncryptionAlgorithm = EncryptionUnitTests.Algo,
                    PathsToEncrypt      = pathsToEncrypt
                }
            });

            Assert.AreEqual(HttpStatusCode.Created, response.StatusCode);
            Assert.AreEqual(item, response.Resource);
            return(item);
        }
            public override async Task <ResponseMessage> SendAsync(
                RequestMessage request,
                CancellationToken cancellationToken)
            {
                // We clone the request message as the Content is disposed before we can use it in the test assertions later.
                this.Received.Add(EncryptionTestHandler.CloneRequestMessage(request));

                if (this.func != null)
                {
                    return(await this.func(request));
                }

                HttpStatusCode httpStatusCode = HttpStatusCode.InternalServerError;

                if (request.ResourceType == ResourceType.Document)
                {
                    JObject item = null;
                    if (request.OperationType == OperationType.Create)
                    {
                        item = EncryptionUnitTests.ParseStream(request.Content);
                        string itemId = item.Property("id").Value.Value <string>();

                        httpStatusCode = HttpStatusCode.Created;
                        if (!this.Items.TryAdd(itemId, item))
                        {
                            httpStatusCode = HttpStatusCode.Conflict;
                        }
                    }
                    else if (request.OperationType == OperationType.Read)
                    {
                        string itemId = EncryptionTestHandler.ParseItemUri(request.RequestUri);
                        httpStatusCode = HttpStatusCode.OK;
                        if (!this.Items.TryGetValue(itemId, out item))
                        {
                            httpStatusCode = HttpStatusCode.NotFound;
                        }
                    }
                    else if (request.OperationType == OperationType.Replace)
                    {
                        string itemId = EncryptionTestHandler.ParseItemUri(request.RequestUri);
                        item = EncryptionUnitTests.ParseStream(request.Content);

                        httpStatusCode = HttpStatusCode.OK;
                        if (!this.Items.TryGetValue(itemId, out JObject existingItem))
                        {
                            httpStatusCode = HttpStatusCode.NotFound;
                        }

                        if (!this.Items.TryUpdate(itemId, item, existingItem))
                        {
                            throw new InvalidOperationException("Concurrency not handled in tests.");
                        }
                    }
                    else if (request.OperationType == OperationType.Delete)
                    {
                        string itemId = EncryptionTestHandler.ParseItemUri(request.RequestUri);
                        httpStatusCode = HttpStatusCode.NoContent;
                        if (!this.Items.TryRemove(itemId, out _))
                        {
                            httpStatusCode = HttpStatusCode.NotFound;
                        }
                    }

                    ResponseMessage responseMessage = new ResponseMessage(httpStatusCode, request)
                    {
                        Content = item != null?this.serializer.ToStream(item) : null,
                    };

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

                return(new ResponseMessage(httpStatusCode, request));
            }
        private Container GetContainerWithMockSetup(EncryptionTestHandler encryptionTestHandler = null)
        {
            this.testHandler = encryptionTestHandler ?? new EncryptionTestHandler();

            this.mockEncryptor = new Mock <Encryptor>();

            this.mockEncryptor.Setup(m => m.EncryptAsync(It.IsAny <byte[]>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync((byte[] plainText, string dekId, string algo, CancellationToken t) => EncryptionUnitTests.EncryptData(plainText));
            this.mockEncryptor.Setup(m => m.DecryptAsync(It.IsAny <byte[]>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync((byte[] cipherText, string dekId, string algo, CancellationToken t) => EncryptionUnitTests.DecryptData(cipherText));
            CosmosClient client = MockCosmosUtil.CreateMockCosmosClient((builder) => builder
                                                                        .AddCustomHandlers(this.testHandler)
                                                                        .WithEncryptor(this.mockEncryptor.Object));

            DatabaseCore database = new DatabaseCore(client.ClientContext, EncryptionUnitTests.DatabaseId);

            return(new ContainerInlineCore(new ContainerCore(client.ClientContext, database, EncryptionUnitTests.ContainerId)));
        }