/// <summary>
        /// Gets the document client.
        /// </summary>
        /// <returns>The document client.</returns>
        /// <remarks>
        /// <para>This operation ensures that the database configuration is current before returning the client. This is
        /// an expensive operation if the configuration has changed by another process because the database must be
        /// updated to reflect the changes. In practice, configuration should not be changing if this class is reused
        /// for the life time of an application.
        /// </para>
        /// <para>The config update process is run synchronously.</para>
        /// </remarks>
        internal IDocumentClient GetClient()
        {
            if (!_started)
            {
                throw new NebulaServiceException("Document DB services have not been started");
            }

            _configManager.EnsureConfigCurrent(_client, _dbConfig);

            return(_client);
        }
        public async void EnsureConfigCurrentWithUnchangedSignature()
        {
            var dbConfig = CreateDbConfig();

            string signature = "sig";
            var    configDoc = CreateConfigDoc("Test", signature);

            _signatureGenerator.CreateSignature(Arg.Any <IList <DocumentStoreConfig> >()).Returns(signature);
            _documentClient.ReadDocumentAsync(Arg.Any <Uri>(), Arg.Is <RequestOptions>(x => x.PartitionKey != null)).Returns(WrapResource(configDoc));

            // Existing index that should remain.
            var includeIdx1 = new IncludedPath();

            includeIdx1.Path = "/content_Test_StoreA_DocA/*";
            includeIdx1.Indexes.Add(new HashIndex(DataType.String, -1));

            // Existing index that should be removed. It is no longer present.
            var includeIdx2 = new IncludedPath();

            includeIdx2.Path = "/content_Test_StoreB_DocA/PropA/*";
            includeIdx2.Indexes.Add(new RangeIndex(DataType.String));

            var manager = new ServiceDbConfigManager("Test", _signatureGenerator);

            _documentClient.UpsertDocumentAsync(Arg.Any <Uri>(), Arg.Is <Document>(x => x.GetPropertyValue <string>("Signature") == signature))
            .Returns(WrapResource(CreateConfigDoc(configDoc.Id, signature)));

            manager.RegisterStoreConfigSource(CreateConfigSource("A"));
            manager.RegisterStoreConfigSource(CreateConfigSource("B"));

            manager.EnsureConfigCurrent(_documentClient, dbConfig);

            await AssertNoUpdateTriggered();
        }
        private async Task EnsureStoreConfigCurrentAsync(IEnumerable <IDocumentStoreConfigSource> storeConfigSources)
        {
            foreach (var source in storeConfigSources)
            {
                _configManager.RegisterStoreConfigSource(source);
            }

            await _configManager.EnsureConfigCurrent(_client, _dbConfig);
        }
        public void EnsureConfigCurrentThrowsForSignatureFailure()
        {
            var dbConfig  = CreateDbConfig();
            var configDoc = CreateConfigDoc("Test", "sig");

            _signatureGenerator.CreateSignature(Arg.Any <IList <DocumentStoreConfig> >()).Throws(new Exception());
            _documentClient.ReadDocumentAsync(Arg.Any <Uri>()).Returns(WrapResource(configDoc));

            var manager = new ServiceDbConfigManager("Test", _signatureGenerator);

            manager.RegisterStoreConfigSource(_configSourceA);

            var ex = Assert.Throws <NebulaConfigException>(() => manager.EnsureConfigCurrent(_documentClient, dbConfig));

            Assert.Contains("signature generation failed", ex.Message);
        }
        public async void EnsureConfigCurrentWithDuplicateStoreConfigRegistrationsAndNoSignatureChange()
        {
            var dbConfig  = CreateDbConfig();
            var configDoc = CreateConfigDoc("Test", "sig");

            _signatureGenerator.CreateSignature(Arg.Any <IList <DocumentStoreConfig> >()).Returns("sig");
            _documentClient.ReadDocumentAsync(Arg.Any <Uri>(), Arg.Is <RequestOptions>(x => x.PartitionKey != null)).Returns(WrapResource(configDoc));

            var manager = new ServiceDbConfigManager("Test", _signatureGenerator);

            manager.RegisterStoreConfigSource(CreateConfigSource("A"));
            manager.RegisterStoreConfigSource(CreateConfigSource("A"));

            manager.EnsureConfigCurrent(_documentClient, dbConfig);

            await AssertNoUpdateTriggered();
        }
        public async void EnsureConfigCurrentWithChangedSignature()
        {
            var dbConfig = CreateDbConfig();

            string oldSig    = "old_sig";
            string newSig    = "new_sig";
            var    configDoc = CreateConfigDoc("Test", oldSig);

            DocumentStoreConfigBuilder storeABuilder = new DocumentStoreConfigBuilder("StoreA");

            storeABuilder.AddDocument("DocA");

            DocumentStoreConfigBuilder storeBBuilder = new DocumentStoreConfigBuilder("StoreB");

            storeBBuilder.AddDocument("DocA");
            storeBBuilder.AddDocument("DocB");

            var configSourceA = CreateConfigSource(storeABuilder);
            var configSourceB = CreateConfigSource(storeBBuilder);

            _signatureGenerator.CreateSignature(Arg.Any <IList <DocumentStoreConfig> >()).Returns(newSig);
            _documentClient.ReadDocumentAsync(Arg.Any <Uri>(), Arg.Is <RequestOptions>(x => x.PartitionKey != null)).Returns(WrapResource(configDoc));

            // Existing index that should remain.
            var includeIdx1 = new IncludedPath();

            includeIdx1.Path = "/content_Test_StoreA_DocA/*";
            includeIdx1.Indexes.Add(new HashIndex(DataType.String, -1));

            // Existing index that should be removed. It is no longer present.
            var includeIdx2 = new IncludedPath();

            includeIdx2.Path = "/content_Test_StoreB_DocA/PropA/*";
            includeIdx2.Indexes.Add(new RangeIndex(DataType.String));

            var col1 = new DocumentCollection();

            col1.IndexingPolicy.IncludedPaths.Add(includeIdx1);
            col1.IndexingPolicy.IncludedPaths.Add(includeIdx2);

            _documentClient.ReadDocumentCollectionAsync(Arg.Any <Uri>()).Returns(WrapResource(col1));

            var manager = new ServiceDbConfigManager("Test", _signatureGenerator);

            var foo = WrapResource(col1);

            _documentClient.ReplaceDocumentCollectionAsync(Arg.Any <DocumentCollection>(), Arg.Any <RequestOptions>()).Returns(foo);

            _documentClient.UpsertDocumentAsync(
                Arg.Any <Uri>(),
                Arg.Is <object>(r => ((ServiceDbConfigManager.ServiceConfigRecord)r).Signature == newSig),
                Arg.Any <RequestOptions>())
            .Returns(WrapResource(CreateConfigDoc(configDoc.Id, newSig)));

            manager.RegisterStoreConfigSource(configSourceA);
            manager.RegisterStoreConfigSource(configSourceB);

            manager.EnsureConfigCurrent(_documentClient, dbConfig);

            await _documentClient.Received(1).UpsertDocumentAsync(Arg.Any <Uri>(), Arg.Any <object>(), Arg.Any <RequestOptions>());

            await _documentClient.Received().ReplaceDocumentCollectionAsync(
                Arg.Is <DocumentCollection>(c =>
                                            IncludedPathCheck(
                                                c.IndexingPolicy.IncludedPaths, "/content_Test_StoreA_DocA/*", "/content_Test_StoreB_DocA/*", "/content_Test_StoreB_DocB/*")),
                Arg.Any <RequestOptions>());
        }