diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api.IntegrationTests/Pipeline/HealthCheckTests.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api.IntegrationTests/Pipeline/HealthCheckTests.cs index 1937cced16..c8e6094d49 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api.IntegrationTests/Pipeline/HealthCheckTests.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api.IntegrationTests/Pipeline/HealthCheckTests.cs @@ -17,12 +17,6 @@ public Task CallPingEndpoint_ThenShouldReturnOkResponse() { return TestAsync(f => f.Client.GetAsync("/api/ping"), (f, r) => r.StatusCode.Should().Be(HttpStatusCode.OK)); } - - [Test] - public Task CallHealthEndpoint_ThenShouldReturnOkResponse() - { - return TestAsync(f => f.Client.GetAsync("/health"), (f, r) => r.StatusCode.Should().Be(HttpStatusCode.OK)); - } } public class HealthCheckFixture diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api.UnitTests/HealthChecks/ApprenticeshipInfoServiceHealthCheckTests.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api.UnitTests/HealthChecks/ApprenticeshipInfoServiceHealthCheckTests.cs new file mode 100644 index 0000000000..774d1f3bf5 --- /dev/null +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api.UnitTests/HealthChecks/ApprenticeshipInfoServiceHealthCheckTests.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Diagnostics.HealthChecks; +using Moq; +using NUnit.Framework; +using SFA.DAS.Apprenticeships.Api.Types.Providers; +using SFA.DAS.CommitmentsV2.Api.HealthChecks; +using SFA.DAS.Providers.Api.Client; + +namespace SFA.DAS.CommitmentsV2.Api.UnitTests.HealthChecks +{ + [TestFixture] + [Parallelizable] + public class ApprenticeshipInfoServiceHealthCheckTests + { + private ApprenticeshipInfoServiceHealthCheckTestsFixture _fixture; + + [SetUp] + public void SetUp() + { + _fixture = new ApprenticeshipInfoServiceHealthCheckTestsFixture(); + } + + [Test] + public async Task CheckHealthAsync_WhenFindAllAsyncSucceeds_ThenShouldReturnHealthyStatus() + { + var healthCheckResult = await _fixture.SetFindAllAsyncSuccess().CheckHealthAsync(); + + Assert.AreEqual(HealthStatus.Healthy, healthCheckResult.Status); + } + + [Test] + public async Task CheckHealthAsync_WhenFindAllAsyncFails_ThenShouldReturnDegradedStatus() + { + var healthCheckResult = await _fixture.SetFindAllAsyncFailure().CheckHealthAsync(); + + Assert.AreEqual(HealthStatus.Degraded, healthCheckResult.Status); + Assert.AreEqual(_fixture.Exception.Message, healthCheckResult.Description); + } + + private class ApprenticeshipInfoServiceHealthCheckTestsFixture + { + public HealthCheckContext HealthCheckContext { get; set; } + public CancellationToken CancellationToken { get; set; } + public Mock ProviderApiClient { get; set; } + public ApprenticeshipInfoServiceApiHealthCheck HealthCheck { get; set; } + public Exception Exception { get; set; } + + public ApprenticeshipInfoServiceHealthCheckTestsFixture() + { + HealthCheckContext = new HealthCheckContext + { + Registration = new HealthCheckRegistration("Foo", Mock.Of(), null, null) + }; + + ProviderApiClient = new Mock(); + HealthCheck = new ApprenticeshipInfoServiceApiHealthCheck(ProviderApiClient.Object); + Exception = new Exception("Foobar"); + } + + public Task CheckHealthAsync() + { + return HealthCheck.CheckHealthAsync(HealthCheckContext, CancellationToken); + } + + public ApprenticeshipInfoServiceHealthCheckTestsFixture SetFindAllAsyncSuccess() + { + ProviderApiClient.Setup(c => c.FindAllAsync()).ReturnsAsync(new List()); + + return this; + } + + public ApprenticeshipInfoServiceHealthCheckTestsFixture SetFindAllAsyncFailure() + { + ProviderApiClient.Setup(c => c.FindAllAsync()).ThrowsAsync(Exception); + + return this; + } + } + } +} \ No newline at end of file diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api.UnitTests/HealthChecks/ReservationsApiHealthCheckTests.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api.UnitTests/HealthChecks/ReservationsApiHealthCheckTests.cs new file mode 100644 index 0000000000..b3beb73833 --- /dev/null +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api.UnitTests/HealthChecks/ReservationsApiHealthCheckTests.cs @@ -0,0 +1,81 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Diagnostics.HealthChecks; +using Moq; +using NUnit.Framework; +using SFA.DAS.CommitmentsV2.Api.HealthChecks; +using SFA.DAS.Reservations.Api.Types; + +namespace SFA.DAS.CommitmentsV2.Api.UnitTests.HealthChecks +{ + [TestFixture] + [Parallelizable] + public class ReservationsApiHealthCheckTests + { + private ReservationsApiHealthCheckTestsFixture _fixture; + + [SetUp] + public void SetUp() + { + _fixture = new ReservationsApiHealthCheckTestsFixture(); + } + + [Test] + public async Task CheckHealthAsync_WhenPingSucceeds_ThenShouldReturnHealthyStatus() + { + var healthCheckResult = await _fixture.SetPingSuccess().CheckHealthAsync(); + + Assert.AreEqual(HealthStatus.Healthy, healthCheckResult.Status); + } + + [Test] + public async Task CheckHealthAsync_WhenPingFails_ThenShouldReturnDegradedStatus() + { + var healthCheckResult = await _fixture.SetPingFailure().CheckHealthAsync(); + + Assert.AreEqual(HealthStatus.Degraded, healthCheckResult.Status); + Assert.AreEqual(_fixture.Exception.Message, healthCheckResult.Description); + } + + private class ReservationsApiHealthCheckTestsFixture + { + public HealthCheckContext HealthCheckContext { get; set; } + public CancellationToken CancellationToken { get; set; } + public Mock ReservationsApiClient { get; set; } + public ReservationsApiHealthCheck HealthCheck { get; set; } + public Exception Exception { get; set; } + + public ReservationsApiHealthCheckTestsFixture() + { + HealthCheckContext = new HealthCheckContext + { + Registration = new HealthCheckRegistration("Foo", Mock.Of(), null, null) + }; + + ReservationsApiClient = new Mock(); + HealthCheck = new ReservationsApiHealthCheck(ReservationsApiClient.Object); + Exception = new Exception("Foobar"); + } + + public Task CheckHealthAsync() + { + return HealthCheck.CheckHealthAsync(HealthCheckContext, CancellationToken); + } + + public ReservationsApiHealthCheckTestsFixture SetPingSuccess() + { + ReservationsApiClient.Setup(c => c.Ping(CancellationToken)).Returns(Task.CompletedTask); + + return this; + } + + public ReservationsApiHealthCheckTestsFixture SetPingFailure() + { + ReservationsApiClient.Setup(c => c.Ping(CancellationToken)).ThrowsAsync(Exception); + + return this; + } + } + } +} \ No newline at end of file diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api.UnitTests/SFA.DAS.CommitmentsV2.Api.UnitTests.csproj b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api.UnitTests/SFA.DAS.CommitmentsV2.Api.UnitTests.csproj index 6c74d9d2a4..7676abe26f 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api.UnitTests/SFA.DAS.CommitmentsV2.Api.UnitTests.csproj +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api.UnitTests/SFA.DAS.CommitmentsV2.Api.UnitTests.csproj @@ -23,6 +23,7 @@ + diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api/DependencyResolution/IoC.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api/DependencyResolution/IoC.cs index 0be60bbd72..c899891199 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api/DependencyResolution/IoC.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api/DependencyResolution/IoC.cs @@ -15,6 +15,7 @@ public static class IoC public static void Initialize(Registry registry) { registry.IncludeRegistry(); + registry.IncludeRegistry(); registry.IncludeRegistry(); registry.IncludeRegistry(); registry.IncludeRegistry(); @@ -28,7 +29,6 @@ public static void Initialize(Registry registry) registry.IncludeRegistry(); registry.IncludeRegistry(); registry.IncludeRegistry(); - registry.IncludeRegistry(); registry.IncludeRegistry(); } } diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api/HealthChecks/ApprenticeshipInfoServiceApiHealthCheck.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api/HealthChecks/ApprenticeshipInfoServiceApiHealthCheck.cs new file mode 100644 index 0000000000..c6fb65260c --- /dev/null +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api/HealthChecks/ApprenticeshipInfoServiceApiHealthCheck.cs @@ -0,0 +1,32 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Diagnostics.HealthChecks; +using SFA.DAS.Providers.Api.Client; + +namespace SFA.DAS.CommitmentsV2.Api.HealthChecks +{ + public class ApprenticeshipInfoServiceApiHealthCheck : IHealthCheck + { + private readonly IProviderApiClient _providerApiClient; + + public ApprenticeshipInfoServiceApiHealthCheck(IProviderApiClient providerApiClient) + { + _providerApiClient = providerApiClient; + } + + public async Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default) + { + try + { + await _providerApiClient.FindAllAsync(); + + return HealthCheckResult.Healthy(); + } + catch (Exception exception) + { + return HealthCheckResult.Degraded(exception.Message); + } + } + } +} \ No newline at end of file diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api/HealthChecks/NServiceBusHealthCheck.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api/HealthChecks/NServiceBusHealthCheck.cs index 50d45cf134..0888c262a5 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api/HealthChecks/NServiceBusHealthCheck.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api/HealthChecks/NServiceBusHealthCheck.cs @@ -24,7 +24,7 @@ public NServiceBusHealthCheck(IMessageSession messageSession, IDistributedCache _distributedCache = distributedCache; } - public async Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = new CancellationToken()) + public async Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default) { var messageId = Guid.NewGuid(); var data = new Dictionary { ["MessageId"] = messageId }; diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api/HealthChecks/ReservationsApiHealthCheck.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api/HealthChecks/ReservationsApiHealthCheck.cs new file mode 100644 index 0000000000..cfe3aba5ea --- /dev/null +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api/HealthChecks/ReservationsApiHealthCheck.cs @@ -0,0 +1,32 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Diagnostics.HealthChecks; +using SFA.DAS.Reservations.Api.Types; + +namespace SFA.DAS.CommitmentsV2.Api.HealthChecks +{ + public class ReservationsApiHealthCheck : IHealthCheck + { + private readonly IReservationsApiClient _reservationsApiClient; + + public ReservationsApiHealthCheck(IReservationsApiClient reservationsApiClient) + { + _reservationsApiClient = reservationsApiClient; + } + + public async Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default) + { + try + { + await _reservationsApiClient.Ping(cancellationToken); + + return HealthCheckResult.Healthy(); + } + catch (Exception exception) + { + return HealthCheckResult.Degraded(exception.Message); + } + } + } +} \ No newline at end of file diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api/HealthChecks/ServiceCollectionExtensions.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api/HealthChecks/ServiceCollectionExtensions.cs index d6c2ef8317..20b93681b0 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api/HealthChecks/ServiceCollectionExtensions.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api/HealthChecks/ServiceCollectionExtensions.cs @@ -15,7 +15,9 @@ public static IServiceCollection AddDasHealthChecks(this IServiceCollection serv var databaseConnectionString = configuration.GetValue(CommitmentsConfigurationKeys.DatabaseConnectionString); services.AddHealthChecks() + .AddCheck("Apprenticeship Info Service API Health Check") .AddCheck("Service Bus Health Check") + .AddCheck("Reservations API Health Check") .AddSqlServer(databaseConnectionString, name: "Commitments DB Health Check"); return services; diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Jobs/DependencyResolution/DefaultRegistry.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Jobs/DependencyResolution/DefaultRegistry.cs index d23f72fdc3..930560bd6b 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Jobs/DependencyResolution/DefaultRegistry.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Jobs/DependencyResolution/DefaultRegistry.cs @@ -1,7 +1,5 @@ -using SFA.DAS.CommitmentsV2.Configuration; -using SFA.DAS.CommitmentsV2.Data; +using SFA.DAS.CommitmentsV2.Data; using SFA.DAS.CommitmentsV2.Jobs.ScheduledJobs; -using SFA.DAS.Providers.Api.Client; using StructureMap; namespace SFA.DAS.CommitmentsV2.Jobs.DependencyResolution @@ -12,7 +10,6 @@ public DefaultRegistry() { For(); For().Use(); - For().Use(c => new ProviderApiClient(c.GetInstance().BaseUrl)); } } } \ No newline at end of file diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Jobs/DependencyResolution/IoC.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Jobs/DependencyResolution/IoC.cs index 756111d719..edc90d1643 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Jobs/DependencyResolution/IoC.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Jobs/DependencyResolution/IoC.cs @@ -7,6 +7,7 @@ public static class IoC { public static void Initialize(Registry registry) { + registry.IncludeRegistry(); registry.IncludeRegistry(); registry.IncludeRegistry(); registry.IncludeRegistry(); diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Jobs/SFA.DAS.CommitmentsV2.Jobs.csproj b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Jobs/SFA.DAS.CommitmentsV2.Jobs.csproj index a70db6cd5b..7740149f94 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Jobs/SFA.DAS.CommitmentsV2.Jobs.csproj +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Jobs/SFA.DAS.CommitmentsV2.Jobs.csproj @@ -25,7 +25,6 @@ - diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/DependencyResolution/TrainingProgrammeRegistry.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/DependencyResolution/ApprenticeshipInfoServiceRegistry.cs similarity index 65% rename from src/CommitmentsV2/SFA.DAS.CommitmentsV2/DependencyResolution/TrainingProgrammeRegistry.cs rename to src/CommitmentsV2/SFA.DAS.CommitmentsV2/DependencyResolution/ApprenticeshipInfoServiceRegistry.cs index 0069f0ed0d..cdf5afd53a 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/DependencyResolution/TrainingProgrammeRegistry.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/DependencyResolution/ApprenticeshipInfoServiceRegistry.cs @@ -1,24 +1,19 @@ -using MediatR; -using SFA.DAS.Apprenticeships.Api.Client; +using SFA.DAS.Apprenticeships.Api.Client; using SFA.DAS.CommitmentsV2.Configuration; using SFA.DAS.CommitmentsV2.Domain.Interfaces; -using SFA.DAS.CommitmentsV2.Mapping; using SFA.DAS.CommitmentsV2.Services; +using SFA.DAS.Providers.Api.Client; using StructureMap; -using StructureMap.Pipeline; namespace SFA.DAS.CommitmentsV2.DependencyResolution { - public class TrainingProgrammeRegistry : Registry + public class ApprenticeshipInfoServiceRegistry : Registry { - private const string ServiceName = "SFA.DAS.CommitmentsV2"; - - public TrainingProgrammeRegistry() + public ApprenticeshipInfoServiceRegistry() { - // You'll also need to use the call AddMemoryCache in MVC startup to make IMemoryCache available - For().Use().Ctor("baseUrl").Is(ctx => ctx.GetInstance().BaseUrl); For().Use().Ctor("baseUrl").Is(ctx => ctx.GetInstance().BaseUrl); - + For().Use().Ctor("baseUrl").Is(ctx => ctx.GetInstance().BaseUrl); + For().Use().Ctor("baseUrl").Is(ctx => ctx.GetInstance().BaseUrl); For().Use().Singleton(); For().Use().Singleton(); } diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/SFA.DAS.CommitmentsV2.csproj b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/SFA.DAS.CommitmentsV2.csproj index 2e9e107400..9cca563fe8 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/SFA.DAS.CommitmentsV2.csproj +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/SFA.DAS.CommitmentsV2.csproj @@ -25,6 +25,7 @@ + diff --git a/src/CommitmentsV2/SFA.DAS.ReservationsV2.Api.Client.UnitTests/SFA.DAS.ReservationsV2.Api.Client.UnitTests.csproj b/src/CommitmentsV2/SFA.DAS.ReservationsV2.Api.Client.UnitTests/SFA.DAS.ReservationsV2.Api.Client.UnitTests.csproj index f45b7895ae..5ccb11387d 100644 --- a/src/CommitmentsV2/SFA.DAS.ReservationsV2.Api.Client.UnitTests/SFA.DAS.ReservationsV2.Api.Client.UnitTests.csproj +++ b/src/CommitmentsV2/SFA.DAS.ReservationsV2.Api.Client.UnitTests/SFA.DAS.ReservationsV2.Api.Client.UnitTests.csproj @@ -1,4 +1,4 @@ - + netcoreapp2.2 diff --git a/src/SFA.DAS.Reservations.API.Types/IReservationsApiClient.cs b/src/SFA.DAS.Reservations.API.Types/IReservationsApiClient.cs index bcf86e9b64..b077a07a6d 100644 --- a/src/SFA.DAS.Reservations.API.Types/IReservationsApiClient.cs +++ b/src/SFA.DAS.Reservations.API.Types/IReservationsApiClient.cs @@ -5,6 +5,7 @@ namespace SFA.DAS.Reservations.Api.Types { public interface IReservationsApiClient { + Task Ping(CancellationToken cancellationToken); Task ValidateReservation(ReservationValidationMessage request, CancellationToken cancellationToken); Task GetReservationAllocationStatus(ReservationAllocationStatusMessage request, CancellationToken cancellationToken); Task BulkCreateReservations(long accountLegalEntity, BulkCreateReservationsRequest request, CancellationToken cancellationToken); diff --git a/src/SFA.DAS.Reservations.Api.Types.UnitTests/ReservationsApiClient/WhenCallingThePingEndpoint.cs b/src/SFA.DAS.Reservations.Api.Types.UnitTests/ReservationsApiClient/WhenCallingThePingEndpoint.cs new file mode 100644 index 0000000000..118a721f6e --- /dev/null +++ b/src/SFA.DAS.Reservations.Api.Types.UnitTests/ReservationsApiClient/WhenCallingThePingEndpoint.cs @@ -0,0 +1,36 @@ +using System.Threading; +using System.Threading.Tasks; +using Moq; +using NUnit.Framework; + +namespace SFA.DAS.ReservationsV2.Api.Client.UnitTests +{ + [TestFixture] + [Parallelizable(ParallelScope.All)] + public class WhenCallingThePingEndpoint + { + [Test] + public async Task ThenTheRequestUriIsCorrectlyFormed() + { + var fixture = new WhenCallingThePingEndpointFixtures(); + await fixture.Ping(); + fixture.AssertUriCorrectlyFormed(); + } + } + + public class WhenCallingThePingEndpointFixtures : ReservationsClientTestFixtures + { + public Task Ping() + { + return ReservationsApiClient.Ping(new CancellationToken()); + } + + public void AssertUriCorrectlyFormed() + { + var expectedUrl = $"{Config.ApiBaseUrl}/ping"; + + HttpHelper.Verify(x => x.GetAsync(It.Is(actualUrl => IsSameUri(expectedUrl, actualUrl)), + It.IsAny(), It.IsAny())); + } + } +} diff --git a/src/SFA.DAS.Reservations.Api.Types/ReservationsApiClient.cs b/src/SFA.DAS.Reservations.Api.Types/ReservationsApiClient.cs index 96c97c61a0..f250a7700f 100644 --- a/src/SFA.DAS.Reservations.Api.Types/ReservationsApiClient.cs +++ b/src/SFA.DAS.Reservations.Api.Types/ReservationsApiClient.cs @@ -16,6 +16,12 @@ public ReservationsApiClient(ReservationsClientApiConfiguration config, IHttpHel _httpHelper = httpHelper ?? throw new ArgumentNullException(nameof(httpHelper)); } + public Task Ping(CancellationToken cancellationToken) + { + var url = BuildUrl("ping"); + return _httpHelper.GetAsync(url, null, cancellationToken); + } + public Task ValidateReservation(ReservationValidationMessage request, CancellationToken cancellationToken) { var url = BuildUrl($"api/reservations/validate/{request.ReservationId}");