Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backend-Task: Jairo Blanco #671

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 0 additions & 20 deletions jobs/Backend/Task/Currency.cs

This file was deleted.

23 changes: 0 additions & 23 deletions jobs/Backend/Task/ExchangeRate.cs

This file was deleted.

19 changes: 0 additions & 19 deletions jobs/Backend/Task/ExchangeRateProvider.cs

This file was deleted.

52 changes: 52 additions & 0 deletions jobs/Backend/Task/ExchangeRateUpdater.ConsoleUI/ConsoleExecutor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using ExchangeRateUpdater.Core.Models;
using ExchangeRateUpdater.Core.Providers;
using Microsoft.Extensions.DependencyInjection;

namespace ExchangeRateUpdater.ConsoleUI;

internal class ConsoleExecutor
{
private readonly IEnumerable<Currency> currencies = new[]
{
new Currency("USD"),
new Currency("EUR"),
new Currency("CZK"),
new Currency("JPY"),
new Currency("KES"),
new Currency("RUB"),
new Currency("THB"),
new Currency("TRY"),
new Currency("XYZ")
};

public static ConsoleExecutor Default => new();

public async Task ExecuteAsync(IServiceProvider services)
{
try
{
var exchangeRateProvider = services.GetRequiredService<IExchangeRateProvider>();
using var cts = new CancellationTokenSource(Debugger.IsAttached ? TimeSpan.FromMinutes(10) : TimeSpan.FromSeconds(20));
var rates = await exchangeRateProvider.GetExchangeRatesAsync(currencies, cts.Token);

var exchangeRates = rates as ExchangeRate[] ?? rates.ToArray();
Console.WriteLine($"Successfully retrieved {exchangeRates.Count()} exchange rates:");
foreach (var rate in exchangeRates)
{
Console.WriteLine(rate.ToString());
}
}
catch (Exception e)
{
Console.WriteLine($"Could not retrieve exchange rates: '{e.Message}'.");
}

Console.ReadLine();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<None Remove="appsettings.json" />
</ItemGroup>

<ItemGroup>
<Content Include="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\ExchangeRateUpdater.Core\ExchangeRateUpdater.Core.csproj" />
</ItemGroup>

</Project>
13 changes: 13 additions & 0 deletions jobs/Backend/Task/ExchangeRateUpdater.ConsoleUI/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System.IO;
using ExchangeRateUpdater.ConsoleUI;
using ExchangeRateUpdater.Core.IoC;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;

var builder = Host.CreateApplicationBuilder(args);
var config = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json").Build();

builder.RegisterCore(config);
var app = builder.Build();
await ConsoleExecutor.Default.ExecuteAsync(app.Services);
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"CzechNationalBankApiConfig": {
"BaseUrl": "https://api.cnb.cz/"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using ExchangeRateUpdate.Testing;
using ExchangeRateUpdater.Core.Adapters.CzechNationalBankApi;
using ExchangeRateUpdater.Core.Models;
using ExchangeRateUpdater.Core.TestingSupport;
using Moq.AutoMock;
using NUnit.Framework;

namespace ExchangeRateUpdater.Core.IntegrationTests.Adapters.CzechNationalBankApi;

internal partial class CzechNationalBankApiAdapterTests
{
public class TestContext : TestContext<CzechNationalBankApiAdapter>
{
protected override CzechNationalBankApiAdapter BuildSut(AutoMocker autoMocker) =>
(CzechNationalBankApiAdapter)CoreInstanceBuilder.GetCzechNationalBankApiAdapter();

public void AssertApiResponse(IEnumerable<ExchangeRate> exchangeRates)
{
var exchangeRatesArray = exchangeRates as ExchangeRate[] ?? exchangeRates.ToArray();
Assert.That(exchangeRatesArray, Is.Not.Empty);
Assert.That(exchangeRatesArray.All(y => y.TargetCurrency.Code == "CZK"), Is.True);
Assert.That(exchangeRatesArray.Select(y => y.SourceCurrency.Code).Count(),
Is.EqualTo(exchangeRatesArray.Select(x => x.SourceCurrency.Code).Distinct().Count()));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using ExchangeRateUpdater.Core.Adapters.CzechNationalBankApi;
using ExchangeRateUpdater.Testing;
using NUnit.Framework;

namespace ExchangeRateUpdater.Core.IntegrationTests.Adapters.CzechNationalBankApi;

internal partial class
CzechNationalBankApiAdapterTests : TestFixture<CzechNationalBankApiAdapterTests.TestContext,
CzechNationalBankApiAdapter>
{
[Test]
public async Task CanGetExchangeRatesFromApi()
{
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(20));
var result = await Context.Sut.GetExchangesRateAsync(cts.Token);
Context.AssertApiResponse(result);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="NUnit" Version="4.3.1" />
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0" />
<PackageReference Include="NUnit.Analyzers" Version="4.5.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="6.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\ExchangeRateUpdater.Core.TestingSupport\ExchangeRateUpdater.Core.TestingSupport.csproj" />
<ProjectReference Include="..\ExchangeRateUpdater.Core\ExchangeRateUpdater.Core.csproj" />
<ProjectReference Include="..\ExchangeRateUpdater.Testing\ExchangeRateUpdater.Testing.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using ExchangeRateUpdate.Testing;
using ExchangeRateUpdater.Core.Models;
using ExchangeRateUpdater.Core.Providers;
using ExchangeRateUpdater.Core.TestingSupport;
using Moq.AutoMock;
using NUnit.Framework;

namespace ExchangeRateUpdater.Core.IntegrationTests.Providers;

internal partial class ExchangeRateProviderTests
{
public class TestContext : TestContext<ExchangeRateProvider>
{
public readonly IEnumerable<Currency> Currencies = new[]
{
new Currency("AUD"),
new Currency("BRL"),
new Currency("CZK")
};

protected override ExchangeRateProvider BuildSut(AutoMocker autoMocker) =>
(ExchangeRateProvider)CoreInstanceBuilder.GetExchangeRateProvider(CoreInstanceBuilder
.GetCzechNationalBankApiAdapter);

public void AssertExchangeRate(IEnumerable<ExchangeRate> result)
{
var exchangeRatesArray = result as ExchangeRate[] ?? result.ToArray();
Assert.That(exchangeRatesArray, Is.Not.Empty);

foreach (var exchangeRate in exchangeRatesArray)
{
Assert.That(Currencies.Contains(exchangeRate.SourceCurrency, new CurrencyComparer()));
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using ExchangeRateUpdater.Core.Models;
using ExchangeRateUpdater.Core.Providers;
using ExchangeRateUpdater.Testing;
using NUnit.Framework;

namespace ExchangeRateUpdater.Core.IntegrationTests.Providers;

internal partial class
ExchangeRateProviderTests : TestFixture<ExchangeRateProviderTests.TestContext, ExchangeRateProvider>
{
[Test]
public async Task CanGetFilteredExchangeRates()
{
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(20));
var result = await Context.Sut.GetExchangeRatesAsync(Context.Currencies, cts.Token);
Context.AssertExchangeRate(result);
}

[Test]
public void WhenCurrenciesIsEmptyThrows()
{
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(20));
Assert.ThrowsAsync<ArgumentException>(() => Context.Sut.GetExchangeRatesAsync(Enumerable.Empty<Currency>(), cts.Token));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using ExchangeRateUpdater.Core.Adapters;
using ExchangeRateUpdater.Core.Adapters.CzechNationalBankApi;
using ExchangeRateUpdater.Core.Providers;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging.Abstractions;

namespace ExchangeRateUpdater.Core.TestingSupport;

//This should be more elaborated, but the idea is to provide an easy way to get the instances for integration tests
public static class CoreInstanceBuilder
{
public static IExchangeRateApiAdapter GetCzechNationalBankApiAdapter() => new CzechNationalBankApiAdapter(
new HttpClient
{
BaseAddress = new Uri("https://api.cnb.cz/")
}, new MemoryCache(new MemoryCacheOptions()));

public static IExchangeRateProvider GetExchangeRateProvider(Func<IExchangeRateApiAdapter> exchangeRateApi) =>
new ExchangeRateProvider(exchangeRateApi(), NullLogger<ExchangeRateProvider>.Instance);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\ExchangeRateUpdater.Core\ExchangeRateUpdater.Core.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.4.2" />
<PackageReference Include="NUnit.Analyzers" Version="3.6.1" />
<PackageReference Include="coverlet.collector" Version="3.2.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\ExchangeRateUpdate.Testing\ExchangeRateUpdate.Testing.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System.Collections.Generic;
using ExchangeRateUpdater.Core.Models;

namespace ExchangeRateUpdater.Core.Adapters.CzechNationalBankApi.ApiModels;

internal class CzechNationalBankBaseExchangeRate
{
public IEnumerable<CzechNationalBankExchangeRate> Rates { get; set; }
}

internal class CzechNationalBankExchangeRate
{
public string CurrencyCode { get; set; } = null!;
public decimal Rate { get; set; }
public int Amount { get; set; }
}
Loading