Skip to content

Commit

Permalink
feat: Enable health checks and add health check around the configuration
Browse files Browse the repository at this point in the history
Merge pull request #293 from DFE-Digital/feat/add-healthcheck
  • Loading branch information
killij authored Oct 4, 2023
2 parents c326465 + bcd13cc commit 337c23c
Show file tree
Hide file tree
Showing 4 changed files with 221 additions and 0 deletions.
165 changes: 165 additions & 0 deletions Childrens-Social-Care-CPD-Tests/ConfigurationHealthCheckTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
using Castle.Core.Logging;
using Childrens_Social_Care_CPD;
using Childrens_Social_Care_CPD.Configuration;
using FluentAssertions;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Logging;
using NSubstitute;
using NSubstitute.Extensions;
using NUnit.Framework;
using System.Threading.Tasks;

namespace Childrens_Social_Care_CPD_Tests;

public class ConfigurationHealthCheckTests
{
private ILogger<ConfigurationHealthCheck> _logger;
private IApplicationConfiguration _applicationConfiguration;

[SetUp]
public void Setup()
{
_logger = Substitute.For<ILogger<ConfigurationHealthCheck>>();
_applicationConfiguration = Substitute.For<IApplicationConfiguration>();
_applicationConfiguration.ReturnsForAll("foo");
}

[Test]
public async Task Passes_When_All_Values_Set_And_Cookies_Are_Secured()
{
// arrange
var sut = new ConfigurationHealthCheck(_logger, _applicationConfiguration);

// act
var result = await sut.CheckHealthAsync(null, default);

// assert
result.Status.Should().Be(HealthStatus.Healthy);
}

[Test]
public async Task Fails_When_Disable_Cookies_Is_True()
{
// arrange
_applicationConfiguration.DisableSecureCookies.Returns(true);
var sut = new ConfigurationHealthCheck(_logger, _applicationConfiguration);

// act
var result = await sut.CheckHealthAsync(null, default);

// assert
result.Status.Should().Be(HealthStatus.Unhealthy);
}

[Test]
public async Task Fails_When_AppInsightsConnectionString_Is_Not_Set()
{
// arrange
_applicationConfiguration.AppInsightsConnectionString.Returns(string.Empty);
var sut = new ConfigurationHealthCheck(_logger, _applicationConfiguration);

// act
var result = await sut.CheckHealthAsync(null, default);

// assert
result.Status.Should().Be(HealthStatus.Unhealthy);
}

[Test]
public async Task Fails_When_AppVersion_Is_Not_Set()
{
// arrange
_applicationConfiguration.AppVersion.Returns(string.Empty);
var sut = new ConfigurationHealthCheck(_logger, _applicationConfiguration);

// act
var result = await sut.CheckHealthAsync(null, default);

// assert
result.Status.Should().Be(HealthStatus.Unhealthy);
}

[Test]
public async Task Fails_When_AzureEnvironment_Is_Not_Set()
{
// arrange
_applicationConfiguration.AzureEnvironment.Returns(string.Empty);
var sut = new ConfigurationHealthCheck(_logger, _applicationConfiguration);

// act
var result = await sut.CheckHealthAsync(null, default);

// assert
result.Status.Should().Be(HealthStatus.Unhealthy);
}

[Test]
public async Task Fails_When_ClarityProjectId_Is_Not_Set()
{
// arrange
_applicationConfiguration.ClarityProjectId.Returns(string.Empty);
var sut = new ConfigurationHealthCheck(_logger, _applicationConfiguration);

// act
var result = await sut.CheckHealthAsync(null, default);

// assert
result.Status.Should().Be(HealthStatus.Unhealthy);
}

[Test]
public async Task Fails_When_ContentfulDeliveryApiKey_Is_Not_Set()
{
// arrange
_applicationConfiguration.ContentfulDeliveryApiKey.Returns(string.Empty);
var sut = new ConfigurationHealthCheck(_logger, _applicationConfiguration);

// act
var result = await sut.CheckHealthAsync(null, default);

// assert
result.Status.Should().Be(HealthStatus.Unhealthy);
}

[Test]
public async Task Fails_When_ContentfulEnvironment_Is_Not_Set()
{
// arrange
_applicationConfiguration.ContentfulEnvironment.Returns(string.Empty);
var sut = new ConfigurationHealthCheck(_logger, _applicationConfiguration);

// act
var result = await sut.CheckHealthAsync(null, default);

// assert
result.Status.Should().Be(HealthStatus.Unhealthy);
}

[Test]
public async Task Fails_When_ContentfulSpaceId_Is_Not_Set()
{
// arrange
_applicationConfiguration.ContentfulSpaceId.Returns(string.Empty);
var sut = new ConfigurationHealthCheck(_logger, _applicationConfiguration);

// act
var result = await sut.CheckHealthAsync(null, default);

// assert
result.Status.Should().Be(HealthStatus.Unhealthy);
}

[Test]
public async Task Fails_When_GoogleTagManagerKey_Is_Not_Set()
{
// arrange
_applicationConfiguration.GoogleTagManagerKey.Returns(string.Empty);
var sut = new ConfigurationHealthCheck(_logger, _applicationConfiguration);

// act
var result = await sut.CheckHealthAsync(null, default);

// assert
result.Status.Should().Be(HealthStatus.Unhealthy);
}
}
52 changes: 52 additions & 0 deletions Childrens-Social-Care-CPD/ConfigurationHealthCheck.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using Childrens_Social_Care_CPD.Configuration;
using Microsoft.Extensions.Diagnostics.HealthChecks;

namespace Childrens_Social_Care_CPD;

public class ConfigurationHealthCheck : IHealthCheck
{
private readonly ILogger _logger;
private readonly IApplicationConfiguration _applicationConfiguration;

public ConfigurationHealthCheck(ILogger<ConfigurationHealthCheck> logger, IApplicationConfiguration applicationConfiguration)
{
_logger = logger;
_applicationConfiguration = applicationConfiguration;
}

private bool CheckSetting(string name, string value)
{
if (string.IsNullOrWhiteSpace(value))
{
_logger.LogError("Configuration setting {propertyName} does not have a value", name);
return false;
}

return true;
}

public Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
{
var healthy = CheckSetting("AppInsightsConnectionString", _applicationConfiguration.AppInsightsConnectionString)
&& CheckSetting("AppVersion", _applicationConfiguration.AppVersion)
&& CheckSetting("AzureEnvironment", _applicationConfiguration.AzureEnvironment)
&& CheckSetting("ClarityProjectId", _applicationConfiguration.ClarityProjectId)
&& CheckSetting("ContentfulDeliveryApiKey", _applicationConfiguration.ContentfulDeliveryApiKey)
&& CheckSetting("ContentfulEnvironment", _applicationConfiguration.ContentfulEnvironment)
&& CheckSetting("ContentfulSpaceId", _applicationConfiguration.ContentfulSpaceId)
&& CheckSetting("GoogleTagManagerKey", _applicationConfiguration.GoogleTagManagerKey);

if (_applicationConfiguration.DisableSecureCookies)
{
_logger.LogError("DisableSecureCookies should not be enabled for standard environments");
healthy = false;
}

if (!healthy)
{
return Task.FromResult(HealthCheckResult.Unhealthy("One or more application configuration settings is missing or incorrect"));
}

return Task.FromResult(HealthCheckResult.Healthy("Application configuration is OK"));
}
}
2 changes: 2 additions & 0 deletions Childrens-Social-Care-CPD/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
app.MapControllerRoute(
name: "default",
pattern: "{controller=Content}/{action=Index}");
app.MapHealthChecks("application/status");


app.Run();

Expand Down
2 changes: 2 additions & 0 deletions Childrens-Social-Care-CPD/WebApplicationBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,5 +74,7 @@ public static void AddFeatures(this WebApplicationBuilder builder)
options.Rules.Insert(0, new LoggerFilterRule(typeof(ApplicationInsightsLoggerProvider).FullName, null, LogLevel.Information, null));
}
});

builder.Services.AddHealthChecks().AddCheck<ConfigurationHealthCheck>("Configuration Health Check", tags: new[] {"configuration"});
}
}

0 comments on commit 337c23c

Please sign in to comment.