public async void SecondRequestWithSameCurrencyShouldBeFromCache() { // Arrange // var handler = new Mock <HttpMessageHandler>(); var currencyConverterClientMock = new Mock <CurrencyConverterClient>( MockBehavior.Loose, null, handler.CreateClient(), null, null); currencyConverterClientMock .Setup(_ => _.RequestCurrencyConverter("USD", "CHF")) .Returns(() => Task.FromResult(new ExchangeRateInfo { ExchangeRate = (decimal)1.1, RequestStatus = new RequestStatus(RequestStatusCode.Ok) })) .Verifiable(); var webRequestProvider = new ExchangeRateCacheStrategy( TestHelper.GetLoggerMock <ExchangeRateCacheStrategy>().Object, currencyConverterClientMock.Object, null, TestHelper.GetFaceSettings(), TestHelper.GetMetricsMock().Object); // Act // var result1 = await webRequestProvider.GetExchangeRate("USD", "CHF"); var result2 = await webRequestProvider.GetExchangeRate("USD", "CHF"); // Assert // currencyConverterClientMock.Verify(_ => _.RequestCurrencyConverter("USD", "CHF"), Times.Once); Assert.Equal((decimal)1.1, result1.ExchangeRate); Assert.Equal((decimal)1.1, result2.ExchangeRate); }
public async void ExchangeRateWithErrorShouldFallbackAndProvideLogRecord() { // Arrange // var handler = new Mock <HttpMessageHandler>(); var currencyConverterClientMock = new Mock <CurrencyConverterClient>( MockBehavior.Loose, null, handler.CreateClient(), null, null); currencyConverterClientMock .Setup(_ => _.RequestCurrencyConverter("CHF", "BTC")) .Returns(() => Task.FromResult(new ExchangeRateInfo { ExchangeRate = 0, RequestStatus = new RequestStatus(RequestStatusCode.Error) })) .Verifiable(); var exchangeApiClientMock = new Mock <ExchangeRateApiClient>( MockBehavior.Loose, null, handler.CreateClient(), null, null); exchangeApiClientMock .Setup(_ => _.RequestExchangeRateApi("CHF", "BTC")) .Returns(() => Task.FromResult(new ExchangeRateInfo { ExchangeRate = (decimal)1.1, RequestStatus = new RequestStatus(RequestStatusCode.Ok) })) .Verifiable(); var loggerMock = TestHelper.GetLoggerMock <ExchangeRateCacheStrategy>(); var webRequestProvider = new ExchangeRateCacheStrategy( loggerMock.Object, currencyConverterClientMock.Object, exchangeApiClientMock.Object, TestHelper.GetFaceSettings(), TestHelper.GetMetricsMock().Object); // Act // var result = await webRequestProvider.GetExchangeRate("CHF", "BTC"); // Assert // loggerMock.Verify( x => x.Log( It.IsAny <LogLevel>(), It.IsAny <EventId>(), It.Is <It.IsAnyType>((o, t) => o.ToString().StartsWith("Fallback, object state ")), It.IsAny <Exception>(), (Func <It.IsAnyType, Exception, string>)It.IsAny <object>()), Times.Once); }
public YAFaceController( ILogger <YAFaceController> logger, PostgresDataProvider postgresDataProvider, KafkaProvider kafkaProvider, ExchangeRateCacheStrategy exchangeRateCacheStrategy, VirtualearthClient virtualearthClient, DarkSkyClient darkSkyClient, OpenWeatherClient openWeatherClient, FaceSettings faceSettings) { _logger = logger; _postgresDataProvider = postgresDataProvider; _kafkaProvider = kafkaProvider; _exchangeRateCacheStrategy = exchangeRateCacheStrategy; _virtualearthClient = virtualearthClient; _darkSkyClient = darkSkyClient; _openWeatherClient = openWeatherClient; _faceSettings = faceSettings; }
public async void ExchangeRateWithErrorShouldFallbackAndReturnZeroForUnsupportedPair() { // Arrange // var handler = new Mock <HttpMessageHandler>(); var currencyConverterClientMock = new Mock <CurrencyConverterClient>( MockBehavior.Loose, null, handler.CreateClient(), null, null); currencyConverterClientMock .Setup(_ => _.RequestCurrencyConverter("CHF", "BTC")) .Returns(() => Task.FromResult(new ExchangeRateInfo { ExchangeRate = 0, RequestStatus = new RequestStatus(RequestStatusCode.Error) })) .Verifiable(); var exchangeApiClientMock = new Mock <ExchangeRateApiClient>( MockBehavior.Loose, null, handler.CreateClient(), null, null); exchangeApiClientMock .Setup(_ => _.RequestExchangeRateApi("CHF", "BTC")) .Returns(() => Task.FromResult(new ExchangeRateInfo { ExchangeRate = (decimal)1.1, RequestStatus = new RequestStatus(RequestStatusCode.Ok) })) .Verifiable(); var webRequestProvider = new ExchangeRateCacheStrategy( TestHelper.GetLoggerMock <ExchangeRateCacheStrategy>().Object, currencyConverterClientMock.Object, exchangeApiClientMock.Object, TestHelper.GetFaceSettings(), TestHelper.GetMetricsMock().Object); // Act // var result = await webRequestProvider.GetExchangeRate("CHF", "BTC"); // Assert // currencyConverterClientMock.Verify(_ => _.RequestCurrencyConverter(It.IsAny <string>(), It.IsAny <string>()), Times.Once); exchangeApiClientMock.Verify(_ => _.RequestExchangeRateApi(It.IsAny <string>(), It.IsAny <string>()), Times.Never); Assert.Equal(0, result.ExchangeRate); Assert.Equal(RequestStatusCode.HasNotBeenRequested, result.RequestStatus.StatusCode); }
public async void After2FaultsCircuitBreakerShouldSendRequestsToFallback() { // Arrange // var config = new ConfigurationBuilder() //.SetBasePath(AppContext.BaseDirectory) .AddJsonFile("appsettings.json", false, true) .AddJsonFile("appsettings.Development.json", false, true) .Build(); var settings = config.LoadVerifiedConfiguration <FaceSettings>(); var mainUrl1 = settings.BuildCurrencyConverterUrl("USD", "RUB"); var mainUrl2 = settings.BuildCurrencyConverterUrl("EUR", "PHP"); var fallbackUrl1 = settings.BuildExchangeRateApiUrl("USD", "RUB"); var fallbackUrl2 = settings.BuildExchangeRateApiUrl("EUR", "PHP"); var handler = new Mock <HttpMessageHandler>(); handler.SetupRequest(HttpMethod.Get, mainUrl1) .ReturnsResponse(HttpStatusCode.ServiceUnavailable) .Verifiable(); handler.SetupRequest(HttpMethod.Get, mainUrl2) .ReturnsResponse(HttpStatusCode.ServiceUnavailable) .Verifiable(); handler.SetupRequest(HttpMethod.Get, fallbackUrl1) .ReturnsResponse(HttpStatusCode.OK, "{\"rates\":{\"RUB\":50.9298531811},\"base\":\"USD\",\"date\":\"2020-03-30\"}") .Verifiable(); handler.SetupRequest(HttpMethod.Get, fallbackUrl2) .ReturnsResponse(HttpStatusCode.OK, "{\"rates\":{\"PHP\":50.9298531811},\"base\":\"EUR\",\"date\":\"2020-03-30\"}") .Verifiable(); var measureCounterMetrics = new Mock <IMeasureCounterMetrics>(); var measureMetricMock = new Mock <IMeasureMetrics>(); measureMetricMock.Setup(_ => _.Counter).Returns(measureCounterMetrics.Object); var metricsMock = new Mock <IMetrics>(); metricsMock.Setup(_ => _.Measure).Returns(measureMetricMock.Object); var client = handler.CreateClient(); IServiceCollection services = new ServiceCollection(); var loggerCccMock = new Mock <ILogger <CurrencyConverterClient> >(); var loggerErcMock = new Mock <ILogger <ExchangeRateApiClient> >(); // var ccc = new CurrencyConverterClient(loggerCccMock.Object, handler.CreateClient(), settings, metricsMock.Object); // var erc = new ExchangeRateApiClient(loggerErcMock.Object, handler.CreateClient(), settings, metricsMock.Object); services.AddSingleton(settings); services.AddSingleton(loggerCccMock.Object); services.AddSingleton(loggerErcMock.Object); services.AddSingleton(metricsMock.Object); services.AddHttpClient <CurrencyConverterClient>() .AddRetryPolicyWithCb(2, TimeSpan.FromMinutes(10)) .AddHttpMessageHandler(() => new StubDelegatingHandler(client)); services.AddHttpClient <ExchangeRateApiClient>() .AddRetryPolicyWithCb(2, TimeSpan.FromMinutes(10)) .AddHttpMessageHandler(() => new StubDelegatingHandler(client)); var isp = services.BuildServiceProvider(); var webRequestProvider = new ExchangeRateCacheStrategy( TestHelper.GetLoggerMock <ExchangeRateCacheStrategy>().Object, isp.GetRequiredService <CurrencyConverterClient>(), isp.GetRequiredService <ExchangeRateApiClient>(), settings, metricsMock.Object); // Act // var result1 = await webRequestProvider.GetExchangeRate("USD", "RUB"); var result2 = await webRequestProvider.GetExchangeRate("EUR", "PHP"); // Assert // handler.VerifyRequest(HttpMethod.Get, mainUrl1, Times.Exactly(2)); handler.VerifyRequest(HttpMethod.Get, mainUrl2, Times.Exactly(0)); handler.VerifyRequest(HttpMethod.Get, fallbackUrl1, Times.Exactly(1)); handler.VerifyRequest(HttpMethod.Get, fallbackUrl2, Times.Exactly(1)); }