diff --git a/src/AdminAan/SFA.DAS.AdminAan.Api.UnitTests/HealthCheck/EducationalOrganisationApiHealthChecksTests.cs b/src/AdminAan/SFA.DAS.AdminAan.Api.UnitTests/HealthCheck/EducationalOrganisationApiHealthChecksTests.cs new file mode 100644 index 0000000000..d1d69f1229 --- /dev/null +++ b/src/AdminAan/SFA.DAS.AdminAan.Api.UnitTests/HealthCheck/EducationalOrganisationApiHealthChecksTests.cs @@ -0,0 +1,48 @@ +using System.Net; +using AutoFixture.NUnit3; +using FluentAssertions; +using Microsoft.Extensions.Diagnostics.HealthChecks; +using Moq; +using SFA.DAS.AdminAan.Api.HealthCheck; +using SFA.DAS.SharedOuterApi.Configuration; +using SFA.DAS.SharedOuterApi.InnerApi.Requests; +using SFA.DAS.SharedOuterApi.Interfaces; +using SFA.DAS.Testing.AutoFixture; + +namespace SFA.DAS.AdminAan.Api.UnitTests.HealthCheck; + +public class EducationalOrganisationApiHealthChecksTests : HealthChecksTestsBase +{ + [Test, MoqAutoData] + public async Task CheckHealthAsync_ValidQueryResult_ReturnsHealthyStatus( + [Frozen] Mock> apiClient, + HealthCheckContext healthCheckContext, + EducationalOrganisationApiHealthCheck healthCheck, + CancellationToken cancellationToken) + { + // Arrange + apiClient + .Setup(x => x.GetResponseCode(It.IsAny())) + .ReturnsAsync(HttpStatusCode.OK); + + // Act + var actual = await healthCheck.CheckHealthAsync(healthCheckContext, cancellationToken); + + // Assert + actual.Status.Should().Be(HealthStatus.Healthy); + } + + [Test, MoqAutoData] + public async Task CheckHealthAsync_NotValidQueryResult_ReturnsUnHealthyStatus( + [Frozen] Mock> apiClient, + HealthCheckContext healthCheckContext, + EducationalOrganisationApiHealthCheck healthCheck) + { + apiClient.Setup(x => x.GetResponseCode(It.IsAny())) + .ReturnsAsync(HttpStatusCode.BadRequest); + + var actual = await healthCheck.CheckHealthAsync(healthCheckContext, CancellationToken.None); + + Assert.That(actual.Status, Is.EqualTo(HealthStatus.Unhealthy)); + } +} \ No newline at end of file diff --git a/src/AdminAan/SFA.DAS.AdminAan.Api.UnitTests/HealthCheck/ReferenceDataApiHealthChecksTests.cs b/src/AdminAan/SFA.DAS.AdminAan.Api.UnitTests/HealthCheck/ReferenceDataApiHealthChecksTests.cs deleted file mode 100644 index f870221096..0000000000 --- a/src/AdminAan/SFA.DAS.AdminAan.Api.UnitTests/HealthCheck/ReferenceDataApiHealthChecksTests.cs +++ /dev/null @@ -1,38 +0,0 @@ -using AutoFixture.NUnit3; -using Microsoft.Extensions.Diagnostics.HealthChecks; -using Moq; -using SFA.DAS.AdminAan.Api.HealthCheck; -using SFA.DAS.AdminAan.Infrastructure; -using SFA.DAS.Testing.AutoFixture; - -namespace SFA.DAS.AdminAan.Api.UnitTests.HealthCheck; - -public class ReferenceDataApiHealthChecksTests : HealthChecksTestsBase -{ - [Test, MoqAutoData] - public async Task CheckHealthAsync_ValidQueryResult_ReturnsHealthyStatus( - [Frozen] Mock apiClient, - HealthCheckContext healthCheckContext, - ReferenceDataApiHealthCheck healthCheck, - CancellationToken cancellationToken) - { - apiClient.Setup(x => x.GetHealth(cancellationToken)).ReturnsAsync(ResponseMessageOk); - - var actual = await healthCheck.CheckHealthAsync(healthCheckContext, cancellationToken); - - Assert.That(actual.Status, Is.EqualTo(HealthStatus.Healthy)); - } - - [Test, MoqAutoData] - public async Task CheckHealthAsync_NotValidQueryResult_ReturnsUnHealthyStatus( - [Frozen] Mock apiClient, - HealthCheckContext healthCheckContext, - ReferenceDataApiHealthCheck healthCheck) - { - apiClient.Setup(x => x.GetHealth(It.IsAny())).ReturnsAsync(ResponseMessageBadRequest); - - var actual = await healthCheck.CheckHealthAsync(healthCheckContext, CancellationToken.None); - - Assert.That(actual.Status, Is.EqualTo(HealthStatus.Unhealthy)); - } -} \ No newline at end of file diff --git a/src/AdminAan/SFA.DAS.AdminAan.Api/AppStart/ServiceCollectionExtensions.cs b/src/AdminAan/SFA.DAS.AdminAan.Api/AppStart/ServiceCollectionExtensions.cs index 3fc3a6b0e1..2204def357 100644 --- a/src/AdminAan/SFA.DAS.AdminAan.Api/AppStart/ServiceCollectionExtensions.cs +++ b/src/AdminAan/SFA.DAS.AdminAan.Api/AppStart/ServiceCollectionExtensions.cs @@ -45,7 +45,7 @@ public static IServiceCollection AddServiceRegistration(this IServiceCollection services.AddHttpClient(); AddAanHubApiClient(services, configuration); - AddReferenceDataApiClient(services, configuration); + AddEducationalOrganisationApiClient(services, configuration); AddLocationApiClient(services, configuration); AddCommitmentsV2ApiClient(services, configuration); AddCoursesApiClient(services, configuration); @@ -81,22 +81,22 @@ public static IServiceCollection AddServiceHealthChecks(this IServiceCollection services.AddHealthChecks() .AddCheck(AanHubApiHealthCheck.HealthCheckResultDescription, failureStatus: HealthStatus.Unhealthy, - tags: new[] { Ready }) + tags: [Ready]) .AddCheck(CommitmentsV2InnerApiHealthCheck.HealthCheckResultDescription, failureStatus: HealthStatus.Unhealthy, - tags: new[] { Ready }) + tags: [Ready]) .AddCheck(ApprenticeAccountsApiHealthCheck.HealthCheckResultDescription, failureStatus: HealthStatus.Unhealthy, - tags: new[] { Ready }) + tags: [Ready]) .AddCheck(CoursesApiHealthCheck.HealthCheckResultDescription, failureStatus: HealthStatus.Unhealthy, - tags: new[] { Ready }) - .AddCheck(ReferenceDataApiHealthCheck.HealthCheckResultDescription, + tags: [Ready]) + .AddCheck(EducationalOrganisationApiHealthCheck.HealthCheckResultDescription, failureStatus: HealthStatus.Unhealthy, - tags: new[] { Ready }) + tags: [Ready]) .AddCheck(LocationsApiHealthCheck.HealthCheckResultDescription, failureStatus: HealthStatus.Unhealthy, - tags: new[] { Ready }); + tags: [Ready]); return services; } @@ -109,13 +109,11 @@ private static void AddAanHubApiClient(IServiceCollection services, IConfigurati services.AddRestEaseClient(apiConfig.Url) .AddHttpMessageHandler(() => new InnerApiAuthenticationHeaderHandler(new AzureClientCredentialHelper(), apiConfig.Identifier)); } - private static void AddReferenceDataApiClient(IServiceCollection services, IConfigurationRoot configuration) + private static void AddEducationalOrganisationApiClient(IServiceCollection services, IConfigurationRoot configuration) { - var apiConfig = GetApiConfiguration(configuration, "ReferenceDataApiConfiguration"); - - services - .AddRestEaseClient(apiConfig.Url) - .AddHttpMessageHandler(() => new InnerApiAuthenticationHeaderHandler(new AzureClientCredentialHelper(), apiConfig.Identifier)); + services.Configure(configuration.GetSection(nameof(EducationalOrganisationApiConfiguration))); + services.AddSingleton(cfg => cfg.GetService>().Value); + services.AddTransient, EducationalOrganisationApiClient>(); } private static void AddLocationApiClient(IServiceCollection services, IConfiguration configuration) diff --git a/src/AdminAan/SFA.DAS.AdminAan.Api/HealthCheck/CoursesApiHealthCheck.cs b/src/AdminAan/SFA.DAS.AdminAan.Api/HealthCheck/CoursesApiHealthCheck.cs index d0f50412eb..be00eb6141 100644 --- a/src/AdminAan/SFA.DAS.AdminAan.Api/HealthCheck/CoursesApiHealthCheck.cs +++ b/src/AdminAan/SFA.DAS.AdminAan.Api/HealthCheck/CoursesApiHealthCheck.cs @@ -3,20 +3,13 @@ namespace SFA.DAS.AdminAan.Api.HealthCheck; -public class CoursesApiHealthCheck : IHealthCheck +public class CoursesApiHealthCheck(ICoursesApiClient coursesApiClient) : IHealthCheck { public const string HealthCheckResultDescription = "Courses API Health Check"; - private readonly ICoursesApiClient _coursesApiClient; - - public CoursesApiHealthCheck(ICoursesApiClient coursesApiClient) - { - _coursesApiClient = coursesApiClient; - } - public async Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = new()) { - var response = await _coursesApiClient.GetHealth(cancellationToken); + var response = await coursesApiClient.GetHealth(cancellationToken); return response.IsSuccessStatusCode ? HealthCheckResult.Healthy(HealthCheckResultDescription) : HealthCheckResult.Unhealthy(HealthCheckResultDescription); diff --git a/src/AdminAan/SFA.DAS.AdminAan.Api/HealthCheck/EducationalOrganisationApiHealthCheck.cs b/src/AdminAan/SFA.DAS.AdminAan.Api/HealthCheck/EducationalOrganisationApiHealthCheck.cs new file mode 100644 index 0000000000..73527ef509 --- /dev/null +++ b/src/AdminAan/SFA.DAS.AdminAan.Api/HealthCheck/EducationalOrganisationApiHealthCheck.cs @@ -0,0 +1,16 @@ +using Microsoft.Extensions.Diagnostics.HealthChecks; +using SFA.DAS.SharedOuterApi.Configuration; +using SFA.DAS.SharedOuterApi.Infrastructure.HealthCheck; +using SFA.DAS.SharedOuterApi.Interfaces; + +namespace SFA.DAS.AdminAan.Api.HealthCheck; + +public class EducationalOrganisationApiHealthCheck( + IEducationalOrganisationApiClient apiClient, + ILogger logger) + : ApiHealthCheck(HealthCheckDescription, HealthCheckResultDescription, + apiClient, logger), IHealthCheck +{ + private static readonly string HealthCheckDescription = "Educational Organisations API"; + public static string HealthCheckResultDescription => $"{HealthCheckDescription} check"; +} \ No newline at end of file diff --git a/src/AdminAan/SFA.DAS.AdminAan.Api/HealthCheck/ReferenceDataApiHealthCheck.cs b/src/AdminAan/SFA.DAS.AdminAan.Api/HealthCheck/ReferenceDataApiHealthCheck.cs deleted file mode 100644 index fb133305f0..0000000000 --- a/src/AdminAan/SFA.DAS.AdminAan.Api/HealthCheck/ReferenceDataApiHealthCheck.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Microsoft.Extensions.Diagnostics.HealthChecks; -using SFA.DAS.AdminAan.Infrastructure; - -namespace SFA.DAS.AdminAan.Api.HealthCheck; - -public class ReferenceDataApiHealthCheck : IHealthCheck -{ - public const string HealthCheckResultDescription = "Reference Data API Health Check"; - - private readonly IReferenceDataApiClient _referenceDataApiClient; - - public ReferenceDataApiHealthCheck(IReferenceDataApiClient referenceDataApiClient) - { - _referenceDataApiClient = referenceDataApiClient; - } - - public async Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = new()) - { - var response = await _referenceDataApiClient.GetHealth(cancellationToken); - return response.IsSuccessStatusCode - ? HealthCheckResult.Healthy(HealthCheckResultDescription) - : HealthCheckResult.Unhealthy(HealthCheckResultDescription); - } -} \ No newline at end of file diff --git a/src/AdminAan/SFA.DAS.AdminAan.UnitTests/Application/CalendarEvents/Queries/GetCalendarEvent/GetCalendarEventQueryHandlerTests.cs b/src/AdminAan/SFA.DAS.AdminAan.UnitTests/Application/CalendarEvents/Queries/GetCalendarEvent/GetCalendarEventQueryHandlerTests.cs index fcca1ac27c..242f551f6b 100644 --- a/src/AdminAan/SFA.DAS.AdminAan.UnitTests/Application/CalendarEvents/Queries/GetCalendarEvent/GetCalendarEventQueryHandlerTests.cs +++ b/src/AdminAan/SFA.DAS.AdminAan.UnitTests/Application/CalendarEvents/Queries/GetCalendarEvent/GetCalendarEventQueryHandlerTests.cs @@ -1,12 +1,17 @@ -using AutoFixture; +using System.Net; +using AutoFixture; using FluentAssertions; using Moq; -using RestEase; using SFA.DAS.AdminAan.Application.CalendarEvents.Queries.GetCalendarEvent; using SFA.DAS.AdminAan.Application.Regions.Queries.GetRegions; using SFA.DAS.AdminAan.Application.Schools.Queries; using SFA.DAS.AdminAan.Domain.InnerApi.AanHubApi.Responses; using SFA.DAS.AdminAan.Infrastructure; +using SFA.DAS.SharedOuterApi.Configuration; +using SFA.DAS.SharedOuterApi.InnerApi.Requests.EducationalOrganisations; +using SFA.DAS.SharedOuterApi.InnerApi.Responses.EducationalOrganisation; +using SFA.DAS.SharedOuterApi.Interfaces; +using SFA.DAS.SharedOuterApi.Models; namespace SFA.DAS.AdminAan.UnitTests.Application.CalendarEvents.Queries.GetCalendarEvent; @@ -23,9 +28,9 @@ public async Task Handle_ReturnCalendarEvents_WithRegionName(int? regionId, stri { var fixture = new Fixture(); - var cancellationToken = new CancellationToken(); + var cancellationToken = CancellationToken.None; var aanHubRestApiClientMock = new Mock(); - var referenceDataApiClient = new Mock(); + var educationalOrgsApiClientMock = new Mock>(); var apiResponse = fixture.Create(); var requestedByMemberId = Guid.NewGuid(); var calendarEventId = Guid.NewGuid(); @@ -44,7 +49,7 @@ public async Task Handle_ReturnCalendarEvents_WithRegionName(int? regionId, stri aanHubRestApiClientMock.Setup(x => x.GetCalendarEvent(requestedByMemberId, calendarEventId, cancellationToken)) .ReturnsAsync(apiResponse); - var handler = new GetCalendarEventQueryHandler(aanHubRestApiClientMock.Object, referenceDataApiClient.Object); + var handler = new GetCalendarEventQueryHandler(aanHubRestApiClientMock.Object, educationalOrgsApiClientMock.Object); var query = new GetCalendarEventQuery(requestedByMemberId, calendarEventId); var actual = await handler.Handle(query, cancellationToken); @@ -53,7 +58,8 @@ public async Task Handle_ReturnCalendarEvents_WithRegionName(int? regionId, stri var callCount = regionId == null ? 0 : 1; aanHubRestApiClientMock.Verify(x => x.GetRegions(cancellationToken), Times.Exactly(callCount)); aanHubRestApiClientMock.Verify(x => x.GetCalendarEvent(requestedByMemberId, calendarEventId, cancellationToken), Times.Once); - referenceDataApiClient.Verify(x => x.GetSchoolFromUrn(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); + educationalOrgsApiClientMock + .Verify(x => x.GetWithResponseCode(It.IsAny()), Times.Never); } [TestCase(null, null, false)] @@ -64,10 +70,10 @@ public async Task Handle_ReturnCalendarEvents_WithSchoolName(long? urn, string? var fixture = new Fixture(); const int OrganisationEducationType = 4; - var cancellationToken = new CancellationToken(); + var cancellationToken = CancellationToken.None; var aanHubRestApiClientMock = new Mock(); var apiResponse = fixture.Create(); - var referenceDataApiClient = new Mock(); + var educationalOrgsApiClientMock = new Mock>(); var requestedByMemberId = Guid.NewGuid(); var calendarEventId = Guid.NewGuid(); @@ -82,30 +88,39 @@ public async Task Handle_ReturnCalendarEvents_WithSchoolName(long? urn, string? { var schoolResult = new GetSchoolApiResult(schoolName!); - var status = System.Net.HttpStatusCode.OK; + var status = HttpStatusCode.OK; if (schoolApiReturnsBadRequest) { - status = System.Net.HttpStatusCode.BadRequest; + status = HttpStatusCode.BadRequest; } - var response = new Response( - "not used", - new HttpResponseMessage(status), - () => schoolResult); - - referenceDataApiClient.Setup(x => x.GetSchoolFromUrn(urn.Value.ToString(), OrganisationEducationType, cancellationToken)) - .ReturnsAsync(response); + var response = new ApiResponse( + new GetLatestDetailsForEducationalOrgResponse + { + EducationalOrganisation = new() + { + Name = schoolName! + } + }, + status, + string.Empty); + + educationalOrgsApiClientMock + .Setup(x => x.GetWithResponseCode( + It.Is(x => x.Identifier == urn.Value.ToString()))) + .ReturnsAsync(response) + .Verifiable(); } - var handler = new GetCalendarEventQueryHandler(aanHubRestApiClientMock.Object, referenceDataApiClient.Object); + var handler = new GetCalendarEventQueryHandler(aanHubRestApiClientMock.Object, educationalOrgsApiClientMock.Object); var query = new GetCalendarEventQuery(requestedByMemberId, calendarEventId); var actual = await handler.Handle(query, cancellationToken); actual.Should().BeEquivalentTo(apiResponse, options => options.ExcludingMissingMembers()); - actual?.SchoolName.Should().Be(schoolName); + actual.SchoolName.Should().Be(schoolName); aanHubRestApiClientMock.Verify(x => x.GetRegions(cancellationToken), Times.Never); aanHubRestApiClientMock.Verify(x => x.GetCalendarEvent(requestedByMemberId, calendarEventId, cancellationToken), Times.Once); - var callCount = urn == null ? 0 : 1; - referenceDataApiClient.Verify(x => x.GetSchoolFromUrn(It.IsAny(), OrganisationEducationType, cancellationToken), Times.Exactly(callCount)); + educationalOrgsApiClientMock.Verify(); + educationalOrgsApiClientMock.VerifyNoOtherCalls(); } } diff --git a/src/AdminAan/SFA.DAS.AdminAan/Application/CalendarEvents/Queries/GetCalendarEvent/GetCalendarEventQueryHandler.cs b/src/AdminAan/SFA.DAS.AdminAan/Application/CalendarEvents/Queries/GetCalendarEvent/GetCalendarEventQueryHandler.cs index 2e5205fa1e..4cb8de6af7 100644 --- a/src/AdminAan/SFA.DAS.AdminAan/Application/CalendarEvents/Queries/GetCalendarEvent/GetCalendarEventQueryHandler.cs +++ b/src/AdminAan/SFA.DAS.AdminAan/Application/CalendarEvents/Queries/GetCalendarEvent/GetCalendarEventQueryHandler.cs @@ -1,13 +1,15 @@ using MediatR; using SFA.DAS.AdminAan.Infrastructure; +using SFA.DAS.SharedOuterApi.Configuration; +using SFA.DAS.SharedOuterApi.InnerApi.Requests.EducationalOrganisations; +using SFA.DAS.SharedOuterApi.InnerApi.Responses.EducationalOrganisation; +using SFA.DAS.SharedOuterApi.Interfaces; using static SFA.DAS.AdminAan.Application.CalendarEvents.Queries.GetCalendarEvent.GetCalendarEventQueryResult; namespace SFA.DAS.AdminAan.Application.CalendarEvents.Queries.GetCalendarEvent; -public class GetCalendarEventQueryHandler(IAanHubRestApiClient apiClient, IReferenceDataApiClient apiReferenceDataApiClient) +public class GetCalendarEventQueryHandler(IAanHubRestApiClient apiClient, IEducationalOrganisationApiClient educationalOrganisationApiClient) : IRequestHandler { - private const int OrganisationTypeEducational = 4; - public async Task Handle(GetCalendarEventQuery request, CancellationToken cancellationToken) { var apiResponse = await apiClient.GetCalendarEvent(request.RequestedByMemberId, request.CalendarEventId, cancellationToken); @@ -49,12 +51,13 @@ public async Task Handle(GetCalendarEventQuery requ if (string.IsNullOrEmpty(result.Urn.ToString())) return result; - var response = await apiReferenceDataApiClient.GetSchoolFromUrn(result.Urn.ToString()!, - OrganisationTypeEducational, cancellationToken); + var response = + await educationalOrganisationApiClient.GetWithResponseCode( + new GetLatestDetailsForEducationalOrgRequest(identifier: result.Urn.ToString())); - if (response.ResponseMessage.StatusCode == System.Net.HttpStatusCode.OK) + if (response.StatusCode == System.Net.HttpStatusCode.OK) { - result.SchoolName = response.GetContent().Name; + result.SchoolName = response.Body.EducationalOrganisation.Name; } return result; diff --git a/src/AdminAan/SFA.DAS.AdminAan/Infrastructure/IReferenceDataApiClient.cs b/src/AdminAan/SFA.DAS.AdminAan/Infrastructure/IReferenceDataApiClient.cs deleted file mode 100644 index 7f859e3693..0000000000 --- a/src/AdminAan/SFA.DAS.AdminAan/Infrastructure/IReferenceDataApiClient.cs +++ /dev/null @@ -1,15 +0,0 @@ -using RestEase; -using SFA.DAS.AdminAan.Application.Schools.Queries; - -namespace SFA.DAS.AdminAan.Infrastructure; - -public interface IReferenceDataApiClient : IHealthChecker -{ - [Get("api/organisations/educational")] - [AllowAnyStatusCode] - Task> GetSchools(string searchTerm, int pageSize, int pageNumber, CancellationToken cancellationToken); - - [Get("api/organisations/get")] - [AllowAnyStatusCode] - Task> GetSchoolFromUrn(string identifier, int organisationType, CancellationToken cancellationToken); -} \ No newline at end of file