From 484b96440e432dcdefd6ced42221ef8cc667162c Mon Sep 17 00:00:00 2001 From: Sarah Persov Date: Sat, 26 Jun 2021 16:25:16 +0100 Subject: [PATCH 1/8] task 2 completed: implemented http client, gets and returns all the names as a string --- .../PaymentsenseCodingChallengeController.cs | 14 ++++++++++---- .../Models/CountryModel.cs | 13 +++++++++++++ .../Models/CurrencyModel.cs | 9 +++++++++ .../Paymentsense.Coding.Challenge.Api.csproj | 1 - 4 files changed, 32 insertions(+), 5 deletions(-) create mode 100644 paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Models/CountryModel.cs create mode 100644 paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Models/CurrencyModel.cs diff --git a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Controllers/PaymentsenseCodingChallengeController.cs b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Controllers/PaymentsenseCodingChallengeController.cs index d7ced3c..4bf244b 100644 --- a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Controllers/PaymentsenseCodingChallengeController.cs +++ b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Controllers/PaymentsenseCodingChallengeController.cs @@ -1,4 +1,6 @@ -using Microsoft.AspNetCore.Mvc; +using System.Net.Http; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; namespace Paymentsense.Coding.Challenge.Api.Controllers { @@ -7,9 +9,13 @@ namespace Paymentsense.Coding.Challenge.Api.Controllers public class PaymentsenseCodingChallengeController : ControllerBase { [HttpGet] - public ActionResult Get() + public async Task> Get() { - return Ok("Paymentsense Coding Challenge!"); + var client = new HttpClient(); + var res = await client.GetAsync("https://restcountries.eu/rest/v2/all?fields=name"); + var resRaw = await res.Content.ReadAsStringAsync(); + + return Ok(resRaw); } } -} +} \ No newline at end of file diff --git a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Models/CountryModel.cs b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Models/CountryModel.cs new file mode 100644 index 0000000..115aa13 --- /dev/null +++ b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Models/CountryModel.cs @@ -0,0 +1,13 @@ +namespace Paymentsense.Coding.Challenge.Api.Models +{ + public class CountryModel + { + public CurrencyModel[] currencies { get; set; } + public string flag { get; set; } + public string name { get; set; } + public string capital { get; set; } + public int population { get; set; } + public string[] timezones { get; set; } + public string[] borders { get; set; } + } +} \ No newline at end of file diff --git a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Models/CurrencyModel.cs b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Models/CurrencyModel.cs new file mode 100644 index 0000000..86db493 --- /dev/null +++ b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Models/CurrencyModel.cs @@ -0,0 +1,9 @@ +namespace Paymentsense.Coding.Challenge.Api.Models +{ + public class CurrencyModel + { + public string code { get; set; } + public string name { get; set; } + public string symbol { get; set; } + } +} \ No newline at end of file diff --git a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Paymentsense.Coding.Challenge.Api.csproj b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Paymentsense.Coding.Challenge.Api.csproj index 1d82fb7..7bde099 100644 --- a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Paymentsense.Coding.Challenge.Api.csproj +++ b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Paymentsense.Coding.Challenge.Api.csproj @@ -6,7 +6,6 @@ - From e28582f7c8514c359f9484ffb96584112a9e55ba Mon Sep 17 00:00:00 2001 From: Sarah Persov Date: Sat, 26 Jun 2021 22:30:54 +0100 Subject: [PATCH 2/8] refactored for the get countries to be in its own controller --- .../Controllers/CountriesController.cs | 37 +++++++++++++++++++ .../PaymentsenseCodingChallengeController.cs | 12 ++---- .../Models/CountryModel.cs | 20 ++++++---- .../Models/CurrencyModel.cs | 10 +++-- 4 files changed, 58 insertions(+), 21 deletions(-) create mode 100644 paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Controllers/CountriesController.cs diff --git a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Controllers/CountriesController.cs b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Controllers/CountriesController.cs new file mode 100644 index 0000000..c3a90a1 --- /dev/null +++ b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Controllers/CountriesController.cs @@ -0,0 +1,37 @@ +using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; +using System.Net.Http; +using System.Text.Json; +using System.Threading.Tasks; +using Paymentsense.Coding.Challenge.Api.Models; + +namespace Paymentsense.Coding.Challenge.Api.Controllers +{ + [ApiController] + [Route("[controller]")] + public class CountriesController : ControllerBase + { + private static List Countries { get; set; } = new List(); + + [HttpGet] + public async Task> Get() + { + if (Countries.Count == 0) + { + await PopulateCountries(); + } + + return Ok(Countries); + } + + + private static async Task PopulateCountries() + { + using var client = new HttpClient(); + var responseStream = client.GetStreamAsync( + "https://restcountries.eu/rest/v2/all?fields=name;flag;population;timezones;currencies;language;capital;borders"); + + Countries = await JsonSerializer.DeserializeAsync>(await responseStream); + } + } +} \ No newline at end of file diff --git a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Controllers/PaymentsenseCodingChallengeController.cs b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Controllers/PaymentsenseCodingChallengeController.cs index 4bf244b..35feee9 100644 --- a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Controllers/PaymentsenseCodingChallengeController.cs +++ b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Controllers/PaymentsenseCodingChallengeController.cs @@ -1,6 +1,4 @@ -using System.Net.Http; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc; namespace Paymentsense.Coding.Challenge.Api.Controllers { @@ -9,13 +7,9 @@ namespace Paymentsense.Coding.Challenge.Api.Controllers public class PaymentsenseCodingChallengeController : ControllerBase { [HttpGet] - public async Task> Get() + public ActionResult Get() { - var client = new HttpClient(); - var res = await client.GetAsync("https://restcountries.eu/rest/v2/all?fields=name"); - var resRaw = await res.Content.ReadAsStringAsync(); - - return Ok(resRaw); + return Ok("Paymentsense Coding Challenge!"); } } } \ No newline at end of file diff --git a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Models/CountryModel.cs b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Models/CountryModel.cs index 115aa13..0ce0409 100644 --- a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Models/CountryModel.cs +++ b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Models/CountryModel.cs @@ -1,13 +1,17 @@ -namespace Paymentsense.Coding.Challenge.Api.Models +using System.Text.Json.Serialization; +using Microsoft.AspNetCore.Mvc; + +namespace Paymentsense.Coding.Challenge.Api.Models { + [BindProperties(SupportsGet = true)] public class CountryModel { - public CurrencyModel[] currencies { get; set; } - public string flag { get; set; } - public string name { get; set; } - public string capital { get; set; } - public int population { get; set; } - public string[] timezones { get; set; } - public string[] borders { get; set; } + [JsonPropertyName("currencies")] public CurrencyModel[] Currencies { get; set; } + [JsonPropertyName("flag")] public string Flag { get; set; } + [JsonPropertyName("name")] public string Name { get; set; } + [JsonPropertyName("capital")] public string Capital { get; set; } + [JsonPropertyName("population")] public int Population { get; set; } + [JsonPropertyName("timezones")] public string[] Timezones { get; set; } + [JsonPropertyName("borders")] public string[] Borders { get; set; } } } \ No newline at end of file diff --git a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Models/CurrencyModel.cs b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Models/CurrencyModel.cs index 86db493..fb11d2f 100644 --- a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Models/CurrencyModel.cs +++ b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Models/CurrencyModel.cs @@ -1,9 +1,11 @@ -namespace Paymentsense.Coding.Challenge.Api.Models +using System.Text.Json.Serialization; + +namespace Paymentsense.Coding.Challenge.Api.Models { public class CurrencyModel { - public string code { get; set; } - public string name { get; set; } - public string symbol { get; set; } + [JsonPropertyName("code")] public string Code { get; set; } + [JsonPropertyName("name")] public string Name { get; set; } + [JsonPropertyName("symbol")] public string Symbol { get; set; } } } \ No newline at end of file From 6e1040ef2ae21956d7397c14ef0685a0b8cf9e23 Mon Sep 17 00:00:00 2001 From: Sarah Persov Date: Sat, 26 Jun 2021 23:30:50 +0100 Subject: [PATCH 3/8] Implemented Clients & Services, added tests --- .../Controllers/CountriesControllerTests.cs | 45 +++++++++++++++++++ ...entsense.Coding.Challenge.Api.Tests.csproj | 1 + .../Clients/CountriesApiClient.cs | 20 +++++++++ .../Clients/CountryCache.cs | 20 +++++++++ .../Clients/ICountriesApiClient.cs | 11 +++++ .../Clients/ICountryCache.cs | 11 +++++ .../Controllers/CountriesController.cs | 24 ++++------ .../Models/CountryModel.cs | 1 + .../Models/Language.cs | 9 ++++ .../Paymentsense.Coding.Challenge.Api.csproj | 4 -- .../Services/CountriesService.cs | 35 +++++++++++++++ .../Services/ICountriesService.cs | 11 +++++ 12 files changed, 172 insertions(+), 20 deletions(-) create mode 100644 paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api.Tests/Controllers/CountriesControllerTests.cs create mode 100644 paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Clients/CountriesApiClient.cs create mode 100644 paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Clients/CountryCache.cs create mode 100644 paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Clients/ICountriesApiClient.cs create mode 100644 paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Clients/ICountryCache.cs create mode 100644 paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Models/Language.cs create mode 100644 paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Services/CountriesService.cs create mode 100644 paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Services/ICountriesService.cs diff --git a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api.Tests/Controllers/CountriesControllerTests.cs b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api.Tests/Controllers/CountriesControllerTests.cs new file mode 100644 index 0000000..d88708a --- /dev/null +++ b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api.Tests/Controllers/CountriesControllerTests.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; +using FluentAssertions; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Moq; +using Paymentsense.Coding.Challenge.Api.Controllers; +using Paymentsense.Coding.Challenge.Api.Models; +using Paymentsense.Coding.Challenge.Api.Services; +using Xunit; + +namespace Paymentsense.Coding.Challenge.Api.Tests.Controllers +{ + public class CountriesControllerTests + { + [Fact] + public async void Get_OnInvoke_ReturnsCountries() + { + var country = new CountryModel + { + Name = "Test Country", + Flag = "flag", + Population = 123456, + Timezones = new[] {"UTC", "UTC+01:00"}, + Languages = new[] {new Language() {Name = "English"}}, + Currencies = new[] {new CurrencyModel() {Name = "GBP"}}, + Capital = "London", + Borders = new[] {"IRL"} + }; + + var countriesMock = new List() {country}; + + var mockCountriesService = new Mock(); + mockCountriesService.Setup(c => c.GetCountries()).ReturnsAsync(countriesMock); + + var controller = new CountriesController(mockCountriesService.Object); + + var result = (await controller.Get()).Result as OkObjectResult; + + result.StatusCode.Should().Be(StatusCodes.Status200OK); + result.Value.Should().BeOfType>(); + result.Value.Should().Be(countriesMock); + mockCountriesService.Verify(c => c.GetCountries(), Times.Once); + } + } +} \ No newline at end of file diff --git a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api.Tests/Paymentsense.Coding.Challenge.Api.Tests.csproj b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api.Tests/Paymentsense.Coding.Challenge.Api.Tests.csproj index ba38576..773da86 100644 --- a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api.Tests/Paymentsense.Coding.Challenge.Api.Tests.csproj +++ b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api.Tests/Paymentsense.Coding.Challenge.Api.Tests.csproj @@ -10,6 +10,7 @@ + all diff --git a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Clients/CountriesApiClient.cs b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Clients/CountriesApiClient.cs new file mode 100644 index 0000000..341035e --- /dev/null +++ b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Clients/CountriesApiClient.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using System.Net.Http; +using System.Text.Json; +using System.Threading.Tasks; +using Paymentsense.Coding.Challenge.Api.Models; + +namespace Paymentsense.Coding.Challenge.Api.Clients +{ + internal class CountriesApiClient : ICountriesApiClient + { + public async Task> GetCountries() + { + using var client = new HttpClient(); + var responseStream = client.GetStreamAsync( + "https://restcountries.eu/rest/v2/all?fields=name;flag;population;timezones;currencies;languages;capital;borders"); + + return await JsonSerializer.DeserializeAsync>(await responseStream); + } + } +} \ No newline at end of file diff --git a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Clients/CountryCache.cs b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Clients/CountryCache.cs new file mode 100644 index 0000000..a555b7f --- /dev/null +++ b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Clients/CountryCache.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using Paymentsense.Coding.Challenge.Api.Models; + +namespace Paymentsense.Coding.Challenge.Api.Clients +{ + public class CountryCache : ICountryCache + { + public static List Countries { get; private set; } = new List(); + + public List GetCountries() + { + return Countries; + } + + public void PopulateCountries(List countries) + { + Countries = countries; + } + } +} \ No newline at end of file diff --git a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Clients/ICountriesApiClient.cs b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Clients/ICountriesApiClient.cs new file mode 100644 index 0000000..c9c793a --- /dev/null +++ b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Clients/ICountriesApiClient.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Paymentsense.Coding.Challenge.Api.Models; + +namespace Paymentsense.Coding.Challenge.Api.Clients +{ + public interface ICountriesApiClient + { + public Task> GetCountries(); + } +} \ No newline at end of file diff --git a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Clients/ICountryCache.cs b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Clients/ICountryCache.cs new file mode 100644 index 0000000..42ea196 --- /dev/null +++ b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Clients/ICountryCache.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using Paymentsense.Coding.Challenge.Api.Models; + +namespace Paymentsense.Coding.Challenge.Api.Clients +{ + public interface ICountryCache + { + public List GetCountries(); + public void PopulateCountries(List countries); + } +} \ No newline at end of file diff --git a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Controllers/CountriesController.cs b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Controllers/CountriesController.cs index c3a90a1..2823316 100644 --- a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Controllers/CountriesController.cs +++ b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Controllers/CountriesController.cs @@ -1,9 +1,8 @@ using Microsoft.AspNetCore.Mvc; using System.Collections.Generic; -using System.Net.Http; -using System.Text.Json; using System.Threading.Tasks; using Paymentsense.Coding.Challenge.Api.Models; +using Paymentsense.Coding.Challenge.Api.Services; namespace Paymentsense.Coding.Challenge.Api.Controllers { @@ -11,27 +10,20 @@ namespace Paymentsense.Coding.Challenge.Api.Controllers [Route("[controller]")] public class CountriesController : ControllerBase { - private static List Countries { get; set; } = new List(); + private readonly ICountriesService _countriesService; - [HttpGet] - public async Task> Get() + public CountriesController(ICountriesService countriesService) { - if (Countries.Count == 0) - { - await PopulateCountries(); - } - - return Ok(Countries); + _countriesService = countriesService; } - private static async Task PopulateCountries() + [HttpGet] + public async Task>> Get() { - using var client = new HttpClient(); - var responseStream = client.GetStreamAsync( - "https://restcountries.eu/rest/v2/all?fields=name;flag;population;timezones;currencies;language;capital;borders"); + var countries = await _countriesService.GetCountries(); - Countries = await JsonSerializer.DeserializeAsync>(await responseStream); + return Ok(countries); } } } \ No newline at end of file diff --git a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Models/CountryModel.cs b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Models/CountryModel.cs index 0ce0409..c2ae6bb 100644 --- a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Models/CountryModel.cs +++ b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Models/CountryModel.cs @@ -13,5 +13,6 @@ public class CountryModel [JsonPropertyName("population")] public int Population { get; set; } [JsonPropertyName("timezones")] public string[] Timezones { get; set; } [JsonPropertyName("borders")] public string[] Borders { get; set; } + [JsonPropertyName("languages")] public Language[] Languages { get; set; } } } \ No newline at end of file diff --git a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Models/Language.cs b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Models/Language.cs new file mode 100644 index 0000000..1c95547 --- /dev/null +++ b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Models/Language.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +public class Language +{ + [JsonPropertyName("iso639_1")] public string Iso6391 { get; set; } + [JsonPropertyName("iso639_2")] public string Iso6392 { get; set; } + [JsonPropertyName("name")] public string Name { get; set; } + [JsonPropertyName("nativeName")] public string NativeName { get; set; } +} \ No newline at end of file diff --git a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Paymentsense.Coding.Challenge.Api.csproj b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Paymentsense.Coding.Challenge.Api.csproj index 7bde099..e699224 100644 --- a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Paymentsense.Coding.Challenge.Api.csproj +++ b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Paymentsense.Coding.Challenge.Api.csproj @@ -5,8 +5,4 @@ Paymentsense.Coding.Challenge.Api.Program - - - - diff --git a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Services/CountriesService.cs b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Services/CountriesService.cs new file mode 100644 index 0000000..dfa349d --- /dev/null +++ b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Services/CountriesService.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using System.Net.Http; +using System.Text.Json; +using System.Threading.Tasks; +using Paymentsense.Coding.Challenge.Api.Clients; +using Paymentsense.Coding.Challenge.Api.Models; + +namespace Paymentsense.Coding.Challenge.Api.Services +{ + public class CountriesService : ICountriesService + { + private readonly ICountriesApiClient _countriesApiClient; + private readonly ICountryCache _countryCache; + + public CountriesService(ICountryCache cache, ICountriesApiClient countriesApiClient) + { + _countriesApiClient = countriesApiClient; + _countryCache = cache; + } + + public async Task> GetCountries() + { + var countries = _countryCache.GetCountries(); + if (countries.Count != 0) + { + return countries; + } + + countries = await _countriesApiClient.GetCountries(); + _countryCache.PopulateCountries(countries); + + return countries; + } + } +} \ No newline at end of file diff --git a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Services/ICountriesService.cs b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Services/ICountriesService.cs new file mode 100644 index 0000000..2bb752b --- /dev/null +++ b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Services/ICountriesService.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Paymentsense.Coding.Challenge.Api.Models; + +namespace Paymentsense.Coding.Challenge.Api.Services +{ + public interface ICountriesService + { + Task> GetCountries(); + } +} \ No newline at end of file From a74972c4fdb18491c7b5ab73c4f40263755b0c58 Mon Sep 17 00:00:00 2001 From: Sarah Persov Date: Sat, 26 Jun 2021 23:54:23 +0100 Subject: [PATCH 4/8] Service Tests --- ...entsense.Coding.Challenge.Api.Tests.csproj | 4 - .../Services/CountriesServiceTests.cs | 86 +++++++++++++++++++ 2 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api.Tests/Services/CountriesServiceTests.cs diff --git a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api.Tests/Paymentsense.Coding.Challenge.Api.Tests.csproj b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api.Tests/Paymentsense.Coding.Challenge.Api.Tests.csproj index 773da86..8f766be 100644 --- a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api.Tests/Paymentsense.Coding.Challenge.Api.Tests.csproj +++ b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api.Tests/Paymentsense.Coding.Challenge.Api.Tests.csproj @@ -22,10 +22,6 @@ - - - - diff --git a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api.Tests/Services/CountriesServiceTests.cs b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api.Tests/Services/CountriesServiceTests.cs new file mode 100644 index 0000000..bdc6eed --- /dev/null +++ b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api.Tests/Services/CountriesServiceTests.cs @@ -0,0 +1,86 @@ +using System.Collections.Generic; +using FluentAssertions; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Moq; +using Paymentsense.Coding.Challenge.Api.Clients; +using Paymentsense.Coding.Challenge.Api.Controllers; +using Paymentsense.Coding.Challenge.Api.Models; +using Paymentsense.Coding.Challenge.Api.Services; +using Xunit; + +namespace Paymentsense.Coding.Challenge.Api.Tests.Services +{ + public class CountriesServiceTests + { + private readonly List _countriesMock; + + public CountriesServiceTests() + { + var country = new CountryModel + { + Name = "Test Country", + Flag = "flag", + Population = 123456, + Timezones = new[] {"UTC", "UTC+01:00"}, + Languages = new[] {new Language() {Name = "English"}}, + Currencies = new[] {new CurrencyModel() {Name = "GBP"}}, + Capital = "London", + Borders = new[] {"IRL"} + }; + + _countriesMock = new List() {country}; + } + + [Fact] + public async void GetCountries_OnInvoke_ReturnsCountriesFromApiClientFirstCall() + { + var mockCountriesApiClient = new Mock(); + mockCountriesApiClient.Setup(c => c.GetCountries()).ReturnsAsync(_countriesMock); + + var mockCache = new Mock(); + mockCache.Setup(c => c.GetCountries()).Returns(new List()); + var countriesService = new CountriesService(mockCache.Object, mockCountriesApiClient.Object); + + var result = await countriesService.GetCountries(); + + result.Should().BeOfType>(); + result.Should().BeSameAs(_countriesMock); + mockCountriesApiClient.Verify(c => c.GetCountries(), Times.Once); + mockCache.Verify(c => c.GetCountries(), Times.Once); + } + + [Fact] + public async void GetCountries_OnInvoke_PopulatesCacheOnFirstCall() + { + var mockCountriesApiClient = new Mock(); + mockCountriesApiClient.Setup(c => c.GetCountries()).ReturnsAsync(_countriesMock); + + var mockCache = new Mock(); + mockCache.Setup(c => c.GetCountries()).Returns(new List()); + var countriesService = new CountriesService(mockCache.Object, mockCountriesApiClient.Object); + + var result = await countriesService.GetCountries(); + mockCache.Verify(c => c.PopulateCountries(result), Times.Once); + + mockCache.Verify(c => c.GetCountries(), Times.Once); + } + + [Fact] + public async void GetCountries_OnInvoke_ReturnsCountriesFromCacheSecondCall() + { + var mockCountriesApiClient = new Mock(); + + var mockCache = new Mock(); + mockCache.Setup(c => c.GetCountries()).Returns(_countriesMock); + var countriesService = new CountriesService(mockCache.Object, mockCountriesApiClient.Object); + + var result = await countriesService.GetCountries(); + + result.Should().BeOfType>(); + result.Should().BeSameAs(_countriesMock); + mockCountriesApiClient.Verify(c => c.GetCountries(), Times.Never); + mockCache.Verify(c => c.GetCountries(), Times.Once); + } + } +} \ No newline at end of file From 4a46a9adb2525fbf8505d4d1d793c47d661b9c4b Mon Sep 17 00:00:00 2001 From: Sarah Persov Date: Sat, 26 Jun 2021 23:57:14 +0100 Subject: [PATCH 5/8] Added dependency injection --- .../Paymentsense.Coding.Challenge.Api/Startup.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Startup.cs b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Startup.cs index 623b8b2..17df845 100644 --- a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Startup.cs +++ b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Startup.cs @@ -3,6 +3,8 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Paymentsense.Coding.Challenge.Api.Clients; +using Paymentsense.Coding.Challenge.Api.Services; namespace Paymentsense.Coding.Challenge.Api { @@ -29,6 +31,9 @@ public void ConfigureServices(IServiceCollection services) .AllowAnyHeader(); }); }); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. @@ -54,4 +59,4 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) }); } } -} +} \ No newline at end of file From 7a50be8fc1f20b31d0fa07a847cc0027e1ea5cae Mon Sep 17 00:00:00 2001 From: Sarah Persov Date: Sun, 27 Jun 2021 00:01:26 +0100 Subject: [PATCH 6/8] Switched http client to dependency injected client --- .../Clients/CountriesApiClient.cs | 9 ++++++++- .../Paymentsense.Coding.Challenge.Api/Startup.cs | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Clients/CountriesApiClient.cs b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Clients/CountriesApiClient.cs index 341035e..3a8427a 100644 --- a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Clients/CountriesApiClient.cs +++ b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Clients/CountriesApiClient.cs @@ -8,9 +8,16 @@ namespace Paymentsense.Coding.Challenge.Api.Clients { internal class CountriesApiClient : ICountriesApiClient { + private readonly IHttpClientFactory _clientFactory; + + public CountriesApiClient(IHttpClientFactory clientFactory) + { + _clientFactory = clientFactory; + } + public async Task> GetCountries() { - using var client = new HttpClient(); + using var client = _clientFactory.CreateClient(); var responseStream = client.GetStreamAsync( "https://restcountries.eu/rest/v2/all?fields=name;flag;population;timezones;currencies;languages;capital;borders"); diff --git a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Startup.cs b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Startup.cs index 17df845..dd78b1a 100644 --- a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Startup.cs +++ b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Startup.cs @@ -34,6 +34,7 @@ public void ConfigureServices(IServiceCollection services) services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddHttpClient(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. From 804c3703ffa8b8a3b550be424057b037e7ecf4e0 Mon Sep 17 00:00:00 2001 From: Sarah Persov Date: Sun, 27 Jun 2021 00:49:31 +0100 Subject: [PATCH 7/8] Added Pagination, Cache tests --- .../Clients/CountryCacheTests.cs | 58 +++++++++++++++++++ .../Controllers/CountriesControllerTests.cs | 6 +- .../Services/CountriesServiceTests.cs | 47 ++++++++++++--- .../Clients/CountriesApiClient.cs | 6 +- .../Clients/CountryCache.cs | 2 +- .../Controllers/CountriesController.cs | 4 +- .../Models/Language.cs | 13 +++-- .../Services/CountriesService.cs | 17 ++++-- .../Services/ICountriesService.cs | 2 +- 9 files changed, 127 insertions(+), 28 deletions(-) create mode 100644 paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api.Tests/Clients/CountryCacheTests.cs diff --git a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api.Tests/Clients/CountryCacheTests.cs b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api.Tests/Clients/CountryCacheTests.cs new file mode 100644 index 0000000..a1ce762 --- /dev/null +++ b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api.Tests/Clients/CountryCacheTests.cs @@ -0,0 +1,58 @@ +using System.Collections.Generic; +using System.Linq; +using FluentAssertions; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Moq; +using Paymentsense.Coding.Challenge.Api.Clients; +using Paymentsense.Coding.Challenge.Api.Controllers; +using Paymentsense.Coding.Challenge.Api.Models; +using Paymentsense.Coding.Challenge.Api.Services; +using Xunit; + +namespace Paymentsense.Coding.Challenge.Api.Tests.Clients +{ + public class CountryCacheTests + { + private readonly List _countriesMock; + + public CountryCacheTests() + { + var country = new CountryModel + { + Name = "Test Country", + Flag = "flag", + Population = 123456, + Timezones = new[] {"UTC", "UTC+01:00"}, + Languages = new[] {new Language() {Name = "English"}}, + Currencies = new[] {new CurrencyModel() {Name = "GBP"}}, + Capital = "London", + Borders = new[] {"IRL"} + }; + + _countriesMock = Enumerable.Range(1, 100).Select(x => country).ToList(); + } + + [Fact] + public void GetCountries_ReturnsEmptyList() + { + var cache = new CountryCache(); + var result = cache.GetCountries(); + + result.Should().BeOfType>(); + result.Should().HaveCount(0); + } + + [Fact] + public void PopulateCountries_PopulatesCountries() + { + var cache = new CountryCache(); + cache.PopulateCountries(_countriesMock); + var result = cache.GetCountries(); + + result.Should().BeOfType>(); + result.Should().HaveCount(_countriesMock.Count); + result.Should().BeSameAs(_countriesMock); + } + } +} \ No newline at end of file diff --git a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api.Tests/Controllers/CountriesControllerTests.cs b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api.Tests/Controllers/CountriesControllerTests.cs index d88708a..9513d96 100644 --- a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api.Tests/Controllers/CountriesControllerTests.cs +++ b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api.Tests/Controllers/CountriesControllerTests.cs @@ -30,16 +30,16 @@ public async void Get_OnInvoke_ReturnsCountries() var countriesMock = new List() {country}; var mockCountriesService = new Mock(); - mockCountriesService.Setup(c => c.GetCountries()).ReturnsAsync(countriesMock); + mockCountriesService.Setup(c => c.GetCountries(null, null)).ReturnsAsync(countriesMock); var controller = new CountriesController(mockCountriesService.Object); - var result = (await controller.Get()).Result as OkObjectResult; + var result = (await controller.Get(null, null)).Result as OkObjectResult; result.StatusCode.Should().Be(StatusCodes.Status200OK); result.Value.Should().BeOfType>(); result.Value.Should().Be(countriesMock); - mockCountriesService.Verify(c => c.GetCountries(), Times.Once); + mockCountriesService.Verify(c => c.GetCountries(null, null), Times.Once); } } } \ No newline at end of file diff --git a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api.Tests/Services/CountriesServiceTests.cs b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api.Tests/Services/CountriesServiceTests.cs index bdc6eed..2fcfffc 100644 --- a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api.Tests/Services/CountriesServiceTests.cs +++ b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api.Tests/Services/CountriesServiceTests.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; using FluentAssertions; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -29,11 +30,11 @@ public CountriesServiceTests() Borders = new[] {"IRL"} }; - _countriesMock = new List() {country}; + _countriesMock = Enumerable.Range(1, 100).Select(x => country).ToList(); } [Fact] - public async void GetCountries_OnInvoke_ReturnsCountriesFromApiClientFirstCall() + public async void GetCountries_OnInvoke_ReturnsCountriesFromApiClientFirstCall_NoPagination() { var mockCountriesApiClient = new Mock(); mockCountriesApiClient.Setup(c => c.GetCountries()).ReturnsAsync(_countriesMock); @@ -42,7 +43,7 @@ public async void GetCountries_OnInvoke_ReturnsCountriesFromApiClientFirstCall() mockCache.Setup(c => c.GetCountries()).Returns(new List()); var countriesService = new CountriesService(mockCache.Object, mockCountriesApiClient.Object); - var result = await countriesService.GetCountries(); + var result = await countriesService.GetCountries(null, null); result.Should().BeOfType>(); result.Should().BeSameAs(_countriesMock); @@ -51,7 +52,7 @@ public async void GetCountries_OnInvoke_ReturnsCountriesFromApiClientFirstCall() } [Fact] - public async void GetCountries_OnInvoke_PopulatesCacheOnFirstCall() + public async void GetCountries_OnInvoke_PopulatesCacheOnFirstCall_NoPagination() { var mockCountriesApiClient = new Mock(); mockCountriesApiClient.Setup(c => c.GetCountries()).ReturnsAsync(_countriesMock); @@ -60,14 +61,14 @@ public async void GetCountries_OnInvoke_PopulatesCacheOnFirstCall() mockCache.Setup(c => c.GetCountries()).Returns(new List()); var countriesService = new CountriesService(mockCache.Object, mockCountriesApiClient.Object); - var result = await countriesService.GetCountries(); + var result = await countriesService.GetCountries(null, null); mockCache.Verify(c => c.PopulateCountries(result), Times.Once); mockCache.Verify(c => c.GetCountries(), Times.Once); } [Fact] - public async void GetCountries_OnInvoke_ReturnsCountriesFromCacheSecondCall() + public async void GetCountries_OnInvoke_ReturnsCountriesFromCacheSecondCall_NoPagination() { var mockCountriesApiClient = new Mock(); @@ -75,12 +76,44 @@ public async void GetCountries_OnInvoke_ReturnsCountriesFromCacheSecondCall() mockCache.Setup(c => c.GetCountries()).Returns(_countriesMock); var countriesService = new CountriesService(mockCache.Object, mockCountriesApiClient.Object); - var result = await countriesService.GetCountries(); + var result = await countriesService.GetCountries(null, null); result.Should().BeOfType>(); result.Should().BeSameAs(_countriesMock); mockCountriesApiClient.Verify(c => c.GetCountries(), Times.Never); mockCache.Verify(c => c.GetCountries(), Times.Once); } + + [Fact] + public async void GetCountries_OnInvoke_Returns10Countries_Pagination() + { + var mockCountriesApiClient = new Mock(); + mockCountriesApiClient.Setup(c => c.GetCountries()).ReturnsAsync(_countriesMock); + + var mockCache = new Mock(); + mockCache.Setup(c => c.GetCountries()).Returns(new List()); + var countriesService = new CountriesService(mockCache.Object, mockCountriesApiClient.Object); + + var result = await countriesService.GetCountries(10, 0); + + result.Should().HaveCount(10); + } + + [Fact] + public async void GetCountries_OnInvoke_ReturnsDifferent10Countries_Pagination() + { + var mockCountriesApiClient = new Mock(); + mockCountriesApiClient.Setup(c => c.GetCountries()).ReturnsAsync(_countriesMock); + + var mockCache = new Mock(); + mockCache.Setup(c => c.GetCountries()).Returns(new List()); + var countriesService = new CountriesService(mockCache.Object, mockCountriesApiClient.Object); + + var result = await countriesService.GetCountries(10, 0); + var resultNextPage = await countriesService.GetCountries(10, 1); + result.Should().HaveCount(10); + resultNextPage.Should().HaveCount(10); + resultNextPage.Should().NotBeSameAs(result); + } } } \ No newline at end of file diff --git a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Clients/CountriesApiClient.cs b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Clients/CountriesApiClient.cs index 3a8427a..b4b1ebc 100644 --- a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Clients/CountriesApiClient.cs +++ b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Clients/CountriesApiClient.cs @@ -8,16 +8,16 @@ namespace Paymentsense.Coding.Challenge.Api.Clients { internal class CountriesApiClient : ICountriesApiClient { - private readonly IHttpClientFactory _clientFactory; + private readonly HttpClient _clientFactory; public CountriesApiClient(IHttpClientFactory clientFactory) { - _clientFactory = clientFactory; + _clientFactory = clientFactory.CreateClient(); } public async Task> GetCountries() { - using var client = _clientFactory.CreateClient(); + using var client = _clientFactory; var responseStream = client.GetStreamAsync( "https://restcountries.eu/rest/v2/all?fields=name;flag;population;timezones;currencies;languages;capital;borders"); diff --git a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Clients/CountryCache.cs b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Clients/CountryCache.cs index a555b7f..fe5f9fd 100644 --- a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Clients/CountryCache.cs +++ b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Clients/CountryCache.cs @@ -5,7 +5,7 @@ namespace Paymentsense.Coding.Challenge.Api.Clients { public class CountryCache : ICountryCache { - public static List Countries { get; private set; } = new List(); + private static List Countries { get; set; } = new List(); public List GetCountries() { diff --git a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Controllers/CountriesController.cs b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Controllers/CountriesController.cs index 2823316..776bb64 100644 --- a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Controllers/CountriesController.cs +++ b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Controllers/CountriesController.cs @@ -19,9 +19,9 @@ public CountriesController(ICountriesService countriesService) [HttpGet] - public async Task>> Get() + public async Task>> Get(int? pageNumber, int? page) { - var countries = await _countriesService.GetCountries(); + var countries = await _countriesService.GetCountries(null, null); return Ok(countries); } diff --git a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Models/Language.cs b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Models/Language.cs index 1c95547..ca753f2 100644 --- a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Models/Language.cs +++ b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Models/Language.cs @@ -1,9 +1,12 @@ using System.Text.Json.Serialization; -public class Language +namespace Paymentsense.Coding.Challenge.Api.Models { - [JsonPropertyName("iso639_1")] public string Iso6391 { get; set; } - [JsonPropertyName("iso639_2")] public string Iso6392 { get; set; } - [JsonPropertyName("name")] public string Name { get; set; } - [JsonPropertyName("nativeName")] public string NativeName { get; set; } + public class Language + { + [JsonPropertyName("iso639_1")] public string Iso6391 { get; set; } + [JsonPropertyName("iso639_2")] public string Iso6392 { get; set; } + [JsonPropertyName("name")] public string Name { get; set; } + [JsonPropertyName("nativeName")] public string NativeName { get; set; } + } } \ No newline at end of file diff --git a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Services/CountriesService.cs b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Services/CountriesService.cs index dfa349d..b569acd 100644 --- a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Services/CountriesService.cs +++ b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Services/CountriesService.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; using System.Net.Http; using System.Text.Json; using System.Threading.Tasks; @@ -18,18 +19,22 @@ public CountriesService(ICountryCache cache, ICountriesApiClient countriesApiCli _countryCache = cache; } - public async Task> GetCountries() + public async Task> GetCountries(int? pageNumber, int? page) { var countries = _countryCache.GetCountries(); - if (countries.Count != 0) + if (countries.Count == 0) { - return countries; + countries = await _countriesApiClient.GetCountries(); + _countryCache.PopulateCountries(countries); } - countries = await _countriesApiClient.GetCountries(); - _countryCache.PopulateCountries(countries); + if (page == null || pageNumber == null) + { + return countries; + } - return countries; + var numToSkip = page.Value * pageNumber.Value; + return countries.Skip(numToSkip).Take(pageNumber.Value).ToList(); } } } \ No newline at end of file diff --git a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Services/ICountriesService.cs b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Services/ICountriesService.cs index 2bb752b..7394c11 100644 --- a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Services/ICountriesService.cs +++ b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Services/ICountriesService.cs @@ -6,6 +6,6 @@ namespace Paymentsense.Coding.Challenge.Api.Services { public interface ICountriesService { - Task> GetCountries(); + Task> GetCountries(int? pageNumber, int? page); } } \ No newline at end of file From 239f61f9e5ee6b153410087b58a19dfa519fa7ed Mon Sep 17 00:00:00 2001 From: Sarah Persov Date: Sun, 27 Jun 2021 01:01:42 +0100 Subject: [PATCH 8/8] Added lock --- .../Clients/CountryCacheTests.cs | 5 ----- .../Services/CountriesServiceTests.cs | 13 +++++-------- .../Clients/CountryCache.cs | 11 +++++++++-- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api.Tests/Clients/CountryCacheTests.cs b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api.Tests/Clients/CountryCacheTests.cs index a1ce762..f4184df 100644 --- a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api.Tests/Clients/CountryCacheTests.cs +++ b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api.Tests/Clients/CountryCacheTests.cs @@ -1,13 +1,8 @@ using System.Collections.Generic; using System.Linq; using FluentAssertions; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Moq; using Paymentsense.Coding.Challenge.Api.Clients; -using Paymentsense.Coding.Challenge.Api.Controllers; using Paymentsense.Coding.Challenge.Api.Models; -using Paymentsense.Coding.Challenge.Api.Services; using Xunit; namespace Paymentsense.Coding.Challenge.Api.Tests.Clients diff --git a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api.Tests/Services/CountriesServiceTests.cs b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api.Tests/Services/CountriesServiceTests.cs index 2fcfffc..0004eba 100644 --- a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api.Tests/Services/CountriesServiceTests.cs +++ b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api.Tests/Services/CountriesServiceTests.cs @@ -1,11 +1,8 @@ using System.Collections.Generic; using System.Linq; using FluentAssertions; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; using Moq; using Paymentsense.Coding.Challenge.Api.Clients; -using Paymentsense.Coding.Challenge.Api.Controllers; using Paymentsense.Coding.Challenge.Api.Models; using Paymentsense.Coding.Challenge.Api.Services; using Xunit; @@ -34,7 +31,7 @@ public CountriesServiceTests() } [Fact] - public async void GetCountries_OnInvoke_ReturnsCountriesFromApiClientFirstCall_NoPagination() + public async void GetCountries_ReturnsCountriesFromApiClientFirstCall_NoPagination() { var mockCountriesApiClient = new Mock(); mockCountriesApiClient.Setup(c => c.GetCountries()).ReturnsAsync(_countriesMock); @@ -52,7 +49,7 @@ public async void GetCountries_OnInvoke_ReturnsCountriesFromApiClientFirstCall_N } [Fact] - public async void GetCountries_OnInvoke_PopulatesCacheOnFirstCall_NoPagination() + public async void GetCountries_PopulatesCacheOnFirstCall_NoPagination() { var mockCountriesApiClient = new Mock(); mockCountriesApiClient.Setup(c => c.GetCountries()).ReturnsAsync(_countriesMock); @@ -68,7 +65,7 @@ public async void GetCountries_OnInvoke_PopulatesCacheOnFirstCall_NoPagination() } [Fact] - public async void GetCountries_OnInvoke_ReturnsCountriesFromCacheSecondCall_NoPagination() + public async void GetCountries_ReturnsCountriesFromCacheSecondCall_NoPagination() { var mockCountriesApiClient = new Mock(); @@ -85,7 +82,7 @@ public async void GetCountries_OnInvoke_ReturnsCountriesFromCacheSecondCall_NoPa } [Fact] - public async void GetCountries_OnInvoke_Returns10Countries_Pagination() + public async void GetCountries_Returns10Countries_Pagination() { var mockCountriesApiClient = new Mock(); mockCountriesApiClient.Setup(c => c.GetCountries()).ReturnsAsync(_countriesMock); @@ -100,7 +97,7 @@ public async void GetCountries_OnInvoke_Returns10Countries_Pagination() } [Fact] - public async void GetCountries_OnInvoke_ReturnsDifferent10Countries_Pagination() + public async void GetCountries_ReturnsDifferent10Countries_Pagination() { var mockCountriesApiClient = new Mock(); mockCountriesApiClient.Setup(c => c.GetCountries()).ReturnsAsync(_countriesMock); diff --git a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Clients/CountryCache.cs b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Clients/CountryCache.cs index fe5f9fd..242ca59 100644 --- a/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Clients/CountryCache.cs +++ b/paymentsense-coding-challenge-api/Paymentsense.Coding.Challenge.Api/Clients/CountryCache.cs @@ -6,15 +6,22 @@ namespace Paymentsense.Coding.Challenge.Api.Clients public class CountryCache : ICountryCache { private static List Countries { get; set; } = new List(); + private static readonly object CountriesLock = new object(); public List GetCountries() { - return Countries; + lock (CountriesLock) + { + return Countries; + } } public void PopulateCountries(List countries) { - Countries = countries; + lock (CountriesLock) + { + Countries = countries; + } } } } \ No newline at end of file