Skip to content

Commit

Permalink
(NCIOCPL#17) Add aHealthcheck
Browse files Browse the repository at this point in the history
  • Loading branch information
blairl-nih committed May 15, 2023
1 parent a59d4a1 commit 19988ef
Show file tree
Hide file tree
Showing 6 changed files with 176 additions and 3 deletions.
11 changes: 11 additions & 0 deletions integration-tests/features/healthcheck/status.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Feature: The system is able to report whether it is a healthy condition.

Background:
* url apiHost

Scenario: The index has been loaded.

Given path 'HealthCheck', 'status'
When method get
Then status 200
And match response == 'alive!'
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using System;
using System.Threading.Tasks;

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;

using NCI.OCPL.Api.Common;


namespace NCI.OCPL.Api.ResourcesForResearchers.Controllers
{

/// <summary>
/// Controller for reporting on system health.
/// </summary>
[Route("HealthCheck")]
public class HealthCheckController : ControllerBase
{

/// <summary>
/// Message to return for a "healthy" status.
/// </summary>
public const string HEALTHY_STATUS = "alive!";

/// <summary>
/// Message to return for an "unhealthy" status.
/// </summary>
public const string UNHEALTHY_STATUS = "Service not healthy.";

private readonly IHealthCheckService _healthSvc;
private readonly ILogger _logger;

/// <summary>
/// Constructor.
/// </summary>
/// <param name="logger">The logger.</param>
/// <param name="healthCheckSvc">Elasticsearch health check instance.</param>
/// <returns></returns>
public HealthCheckController(ILogger<HealthCheckController> logger, IHealthCheckService healthCheckSvc)
=> (_logger, _healthSvc) = (logger, healthCheckSvc);


/// <summary>
/// Provides an endpoint for checking that the glossary API and underlying Elasticsearch instance
/// are in a good operational state.
/// </summary>
/// <returns>Status 200 and the message "alive!" if the service is healthy.
///
/// Status 500 and the message "Service not healthy." otherwise.</returns>
[HttpGet("status")]
public async Task<string> IsHealthy()
{
try
{
bool isHealthy = await _healthSvc.IndexIsHealthy(); ;
if (isHealthy)
return HEALTHY_STATUS;
else
throw new APIErrorException(500, UNHEALTHY_STATUS);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error checking health.");
throw new APIErrorException(500, UNHEALTHY_STATUS);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

<ItemGroup>
<PackageReference Include="Elasticsearch.Net" Version="7.9.*" />
<PackageReference Include="NCI.OCPL.Api.Common" Version="2.0.*" />
<PackageReference Include="NCI.OCPL.Api.Common" Version="2.1.*" />
<PackageReference Include="NSwag.AspNetCore" Version="13.11.*" />
<PackageReference Include="NEST" Version="7.9.*" />
</ItemGroup>
Expand Down
7 changes: 7 additions & 0 deletions src/NCI.OCPL.Api.ResourcesForResearchers/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,13 @@ protected override void AddAppServices(IServiceCollection services)
services.AddSingleton<IResourceAggregationService, ESResourceAggregationService>();

services.Configure<R4RAPIOptions>(Configuration.GetSection("R4RAPI"));

// Get name for the Healthcheck alias.
services.AddTransient<IESAliasNameProvider>(p =>
{
string alias = Configuration["R4RAPI:AliasName"];
return new ESAliasNameProvider() { Name = alias };
});
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="NCI.OCPL.Api.Common" Version="2.0.*" />
<PackageReference Include="NCI.OCPL.Api.Common.Testing" Version="2.0.*" />
<PackageReference Include="NCI.OCPL.Api.Common" Version="2.1.*" />
<PackageReference Include="NCI.OCPL.Api.Common.Testing" Version="2.1.*" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
using System;

using Microsoft.Extensions.Logging.Testing;

using Moq;
using Xunit;

using NCI.OCPL.Api.Common;
using NCI.OCPL.Api.ResourcesForResearchers.Controllers;


namespace NCI.OCPL.Api.Glossary.Tests
{
public class HealthCheckControllerTests
{
/// <summary>
/// Handle the healthcheck reporting an unhealthy status.
/// </summary>
[Fact]
public async void IsUnhealthy()
{
var logger = NullLogger<HealthCheckController>.Instance;
var healthcheckService = new Mock<IHealthCheckService>();
healthcheckService.Setup(
svc => svc.IndexIsHealthy()
)
.ReturnsAsync(false);

var controller = new HealthCheckController(logger, healthcheckService.Object);

var exception = await Assert.ThrowsAsync<APIErrorException>(() => controller.IsHealthy());

Assert.Equal(500, exception.HttpStatusCode);
Assert.Equal(HealthCheckController.UNHEALTHY_STATUS, exception.Message);
}


/// <summary>
/// Handle the health service failing.
/// </summary>
[Fact]
public async void IsVeryUnhealthy()
{
var logger = NullLogger<HealthCheckController>.Instance;
var healthcheckService = new Mock<IHealthCheckService>();
healthcheckService.Setup(
svc => svc.IndexIsHealthy()
)
.ThrowsAsync(new Exception("kaboom!"));


var controller = new HealthCheckController(logger, healthcheckService.Object);

var exception = await Assert.ThrowsAsync<APIErrorException>(() => controller.IsHealthy());

Assert.Equal(500, exception.HttpStatusCode);
Assert.Equal(HealthCheckController.UNHEALTHY_STATUS, exception.Message);
}


/// <summary>
/// Handle the healthcheck reporting a healthy status.
/// </summary>
[Fact]
public async void IsHealthy()
{
var logger = NullLogger<HealthCheckController>.Instance;
var healthcheckService = new Mock<IHealthCheckService>();
healthcheckService.Setup(
healthSvc => healthSvc.IndexIsHealthy()
)
.ReturnsAsync(true);

var controller = new HealthCheckController(logger, healthcheckService.Object);

string actual = await controller.IsHealthy();

healthcheckService.Verify(
svc => svc.IndexIsHealthy(),
Times.Once
);

Assert.Equal(HealthCheckController.HEALTHY_STATUS, actual);
}

}
}

0 comments on commit 19988ef

Please sign in to comment.