public void Config_validation_exception_contains_missing_values_when_server_and_cache_config_is_invalid()
        {
            ConfigRoot configFromMockCache = MockHabitatServer.GetConfigRoot(TestComponentName);

            configFromMockCache.Data.Children[0].Value = "fromcache";
            configFromMockCache.Data.Children.Add(new ConfigNode {
                Name = "N4", Value = "V4"
            });
            CreateMockDurableCacheEntry(configFromMockCache);

            var testFactory = new ConfigProviderFactory(TestAssemblyName, _mockConfigServiceHttpClient, _mockFileSystem.Object);
            var validators  = new Dictionary <string, Func <string, bool> > {
                { "foo.N1", x => true }, { "foo.N2", x => true }, { "foo.N3", x => true }, { "foo.N4", x => true }
            };

            IConfigProvider configProvider = testFactory.Create(TestComponentName, validators);

            try
            {
                configProvider.GetAndValidateConfiguration();
                Assert.Fail("Invalid configuration passed validation");
            }
            catch (UnableToAccessConfigurationException e)
            {
                Assert.IsInstanceOfType(e.InnerException, typeof(ConfigValidationException), "Expected a ConfigValidationException to be thrown");
                ConfigValidationException configValidationEx = (ConfigValidationException)e.InnerException;
                Assert.IsTrue(Regex.IsMatch(configValidationEx.Message, "foo.N3, foo.N4"), "Missing invalid parameters from validation error message");
            }
        }
        public void Missing_config_settings_should_cause_config_validation_exception_to_be_thrown()
        {
            var testFactory = new ConfigProviderFactory(TestAssemblyName, _mockConfigServiceHttpClient, _mockFileSystem.Object);
            var validators  = new Dictionary <string, Func <string, bool> > {
                { "Taco", x => true }
            };
            IConfigProvider configProvider = testFactory.Create(TestComponentName, validators);

            configProvider.GetAndValidateConfiguration();
        }
        public void If_server_is_down_and_cache_is_empty_a_config_access_exception_should_be_thrown()
        {
            _mockConfigServiceHttpClient = HttpClientTestHelper.CreateClientSimulatingABadAddress();
            var testFactory = new ConfigProviderFactory(TestAssemblyName, _mockConfigServiceHttpClient, _mockFileSystem.Object);

            // This validator would cause an error, but the simulated connection issue above should prevent it from hitting that.
            var validators = new Dictionary <string, Func <string, bool> > {
                { "Taco", x => true }
            };
            IConfigProvider configProvider = testFactory.Create(TestComponentName, validators);

            configProvider.GetAndValidateConfiguration();
        }
        public void Retrieve_valid_configuration()
        {
            var testFactory = new ConfigProviderFactory(TestAssemblyName, _mockConfigServiceHttpClient, _mockFileSystem.Object);

            var validators = new Dictionary <string, Func <string, bool> > {
                { string.Format("{0}.N1", TestComponentName), x => true }, { string.Format("{0}.N2", TestComponentName), x => true }
            };
            IConfigProvider             configProvider = testFactory.Create(TestComponentName, validators);
            ConfigRoot                  configuration  = configProvider.GetAndValidateConfiguration();
            Dictionary <string, string> dictionary     = configuration.Data.ToDictionary();

            Assert.AreEqual("V1", dictionary[string.Format("{0}.N1", TestComponentName)]);
            Assert.AreEqual("V2", dictionary[string.Format("{0}.N2", TestComponentName)]);
        }
        public void Config_should_always_come_from_server_if_it_returns_valid_data()
        {
            ConfigRoot configFromMockCache = MockHabitatServer.GetConfigRoot(TestComponentName);

            configFromMockCache.Data.Children[0].Value = "fromcache";
            CreateMockDurableCacheEntry(configFromMockCache);

            var testFactory = new ConfigProviderFactory(TestAssemblyName, _mockConfigServiceHttpClient, _mockFileSystem.Object);

            IConfigProvider             configProvider = testFactory.Create(TestComponentName, new Dictionary <string, Func <string, bool> >());
            ConfigRoot                  config         = configProvider.GetAndValidateConfiguration();
            Dictionary <string, string> dictionary     = config.Data.ToDictionary();

            Assert.AreEqual("V1", dictionary[string.Format("{0}.N1", TestComponentName)]);
        }
        public void Cache_should_always_be_updated_when_valid_data_is_retrieved_from_server()
        {
            ConfigRoot originalConfigFromMockCache = MockHabitatServer.GetConfigRoot(TestComponentName);

            originalConfigFromMockCache.Data.Children[0].Value = "fromcache";
            CreateMockDurableCacheEntry(originalConfigFromMockCache);

            var testFactory = new ConfigProviderFactory(TestAssemblyName, _mockConfigServiceHttpClient, _mockFileSystem.Object);

            IConfigProvider configProvider     = testFactory.Create(TestComponentName, new Dictionary <string, Func <string, bool> >());
            ConfigRoot      configFromProvider = configProvider.GetAndValidateConfiguration();

            ConfigRoot updatedConfigFromMockCache = ReadMockDurableCacheEntry();

            Assert.IsFalse(_objectComparer.Compare(originalConfigFromMockCache, updatedConfigFromMockCache).AreEqual);
            Assert.IsTrue(_objectComparer.Compare(configFromProvider, updatedConfigFromMockCache).AreEqual);
        }
        public void Config_data_in_cache_should_always_be_validated()
        {
            ConfigRoot configFromMockCache = MockHabitatServer.GetConfigRoot(TestComponentName);

            configFromMockCache.Data.Children[0].Value = "fromcache";
            CreateMockDurableCacheEntry(configFromMockCache);

            // In this case, we have to bypass validation of the service data because the service is offline
            _mockConfigServiceHttpClient = HttpClientTestHelper.CreateClientSimulatingABadAddress();
            var testFactory = new ConfigProviderFactory(TestAssemblyName, _mockConfigServiceHttpClient, _mockFileSystem.Object);

            var validators = new Dictionary <string, Func <string, bool> > {
                { "N1.N1", x => false }, { "N1.N2", x => false }
            };
            IConfigProvider configProvider = testFactory.Create(TestComponentName, validators);

            configProvider.GetAndValidateConfiguration();
        }
        /// <summary>
        /// Uses CreateTypedConfig method to return strongly typed configuration object.
        /// </summary>
        /// <returns>A strongly typed configuration package</returns>
        /// <remarks>
        /// This method will always return the most recent configuration settings without the need to
        /// restart the consuming application.  For best results, call this method often rather than calling once at startup.
        /// </remarks>
        public virtual T GetConfiguration()
        {
            string callingAssemblyName = Assembly.GetCallingAssembly().GetName().Name;
            IConfigProviderFactory configProviderFactory = _configProviderFactory ?? new ConfigProviderFactory(callingAssemblyName);

            IConfigProvider applicationConfigProvider = configProviderFactory.Create(ApplicationComponentName, _applicationValidationMappings);
            ConfigRoot      applicationConfig         = applicationConfigProvider.GetAndValidateConfiguration();

            IConfigProvider environmentConfigProvider = configProviderFactory.Create(EnvironmentComponentName, _environmentValidationMappings);
            ConfigRoot      environmentConfig         = environmentConfigProvider.GetAndValidateConfiguration();

            // In order to keep the config names short and simple, we'll remove application/environment names as prefixes. The consuming application does not need this information.
            var originalApplicationConfigDictionary = applicationConfig.Data.ToDictionary();
            var originalEnvironmentConfigDictionary = environmentConfig.Data.ToDictionary();
            var modifiedApplicationConfigDictionary = originalApplicationConfigDictionary.ToDictionary(originalKey => RemoveComponentPrefix(originalKey.Key, string.Format("{0}.", ApplicationComponentName)), y => y.Value);
            var modifiedEnvironmentConfigDictionary = originalEnvironmentConfigDictionary.ToDictionary(originalKey => RemoveComponentPrefix(originalKey.Key, string.Format("{0}.", EnvironmentComponentName)), y => y.Value);

            return(CreateTypedConfig(modifiedApplicationConfigDictionary, modifiedEnvironmentConfigDictionary));
        }
        public void Config_validation_exception_contains_missing_values_when_server_config_is_invalid_and_cache_is_empty()
        {
            var testFactory = new ConfigProviderFactory(TestAssemblyName, _mockConfigServiceHttpClient, _mockFileSystem.Object);
            var validators  = new Dictionary <string, Func <string, bool> > {
                { "foo.N1", x => true }, { "foo.N2", x => true }, { "foo.N3", x => true }
            };

            IConfigProvider configProvider = testFactory.Create(TestComponentName, validators);

            try
            {
                configProvider.GetAndValidateConfiguration();
                Assert.Fail("Invalid configuration passed validation");
            }
            catch (UnableToAccessConfigurationException e)
            {
                Assert.IsInstanceOfType(e.InnerException, typeof(ConfigValidationException), "Expected a ConfigValidationException to be thrown");
                ConfigValidationException configValidationEx = (ConfigValidationException)e.InnerException;
                Assert.IsTrue(Regex.IsMatch(configValidationEx.Message, "foo.N3"), "Missing invalid parameters from validation error message");
            }
        }