Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Enable health checks and add health check around the configuration #293

Merged
merged 4 commits into from
Oct 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
killij marked this conversation as resolved.
Show resolved Hide resolved
{
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"});
}
}