-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
- Loading branch information
1 parent
2f801a8
commit 4f095cc
Showing
11 changed files
with
193 additions
and
93 deletions.
There are no files selected for viewing
60 changes: 60 additions & 0 deletions
60
...eSubscriber/BookingQueueSubscriber.UnitTests/HealthCheckFunctionTests/HealthCheckTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
using System.Net; | ||
using System.Threading; | ||
using Microsoft.AspNetCore.Mvc; | ||
using Microsoft.Extensions.Diagnostics.HealthChecks; | ||
using Microsoft.Extensions.Logging; | ||
|
||
namespace BookingQueueSubscriber.UnitTests.HealthCheckFunctionTests; | ||
|
||
public class HealthCheckTests | ||
{ | ||
private HealthCheckFunction _sut; | ||
private Mock<HealthCheckService> _healthCheckServiceMock; | ||
|
||
[SetUp] | ||
public void Setup() | ||
{ | ||
_healthCheckServiceMock = new Mock<HealthCheckService>(); | ||
_sut = new HealthCheckFunction(_healthCheckServiceMock.Object); | ||
} | ||
|
||
[Test] | ||
public async Task Should_return_200_when_health_check_is_healthy() | ||
{ | ||
// Arrange | ||
var healthReport = new HealthReport(new Dictionary<string, HealthReportEntry> | ||
{ | ||
{"test", new HealthReportEntry(HealthStatus.Healthy, "test", TimeSpan.Zero, null, null)} | ||
}, TimeSpan.Zero); | ||
_healthCheckServiceMock.Setup(x=> x.CheckHealthAsync(It.IsAny<Func<HealthCheckRegistration,bool>?>(), It.IsAny<CancellationToken>())) | ||
.ReturnsAsync(healthReport); | ||
|
||
// Act | ||
var result = await _sut.HealthCheck(null, Mock.Of<ILogger>()); | ||
|
||
// Assert | ||
var okResult = result as ObjectResult; | ||
Assert.NotNull(okResult); | ||
Assert.AreEqual((int) HttpStatusCode.OK, okResult.StatusCode); | ||
} | ||
|
||
[Test] | ||
public async Task Should_return_503_when_health_check_is_unhealthy() | ||
{ | ||
// Arrange | ||
var healthReport = new HealthReport(new Dictionary<string, HealthReportEntry> | ||
{ | ||
{"test", new HealthReportEntry(HealthStatus.Unhealthy, "test", TimeSpan.Zero, new Exception("Not Working Right Now"), null)} | ||
}, TimeSpan.Zero); | ||
_healthCheckServiceMock.Setup(x=> x.CheckHealthAsync(It.IsAny<Func<HealthCheckRegistration,bool>?>(), It.IsAny<CancellationToken>())) | ||
.ReturnsAsync(healthReport); | ||
|
||
// Act | ||
var result = await _sut.HealthCheck(null, Mock.Of<ILogger>()); | ||
|
||
// Assert | ||
var serviceUnavailableResult = result as ObjectResult; | ||
Assert.NotNull(serviceUnavailableResult); | ||
Assert.AreEqual((int) HttpStatusCode.ServiceUnavailable, serviceUnavailableResult.StatusCode); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 0 additions & 30 deletions
30
BookingQueueSubscriber/BookingQueueSubscriber/Contract/Responses/HealthCheckResponse.cs
This file was deleted.
Oops, something went wrong.
36 changes: 36 additions & 0 deletions
36
BookingQueueSubscriber/BookingQueueSubscriber/Health/HealthCheckExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
using Microsoft.Extensions.Diagnostics.HealthChecks; | ||
|
||
namespace BookingQueueSubscriber.Health; | ||
|
||
public static class HealthCheckExtensions | ||
{ | ||
public static IServiceCollection AddVhHealthChecks(this IServiceCollection services) | ||
{ | ||
var container = services.BuildServiceProvider(); | ||
var servicesConfiguration = container.GetService<IOptions<ServicesConfiguration>>().Value; | ||
services.AddHealthChecks() | ||
.AddCheck("self", () => HealthCheckResult.Healthy()) | ||
.AddUrlGroup( | ||
new Uri( | ||
new Uri(servicesConfiguration.VideoApiUrl), | ||
"/health/liveness"), | ||
name: "Video API", | ||
failureStatus: HealthStatus.Unhealthy, | ||
tags: new[] {"services"}) | ||
.AddUrlGroup( | ||
new Uri( | ||
new Uri(servicesConfiguration.BookingsApiUrl), | ||
"/health/liveness"), | ||
name: "Bookings API", | ||
failureStatus: HealthStatus.Unhealthy, | ||
tags: new[] {"services"}) | ||
.AddUrlGroup( | ||
new Uri( | ||
new Uri(servicesConfiguration.UserApiUrl), | ||
"/health/liveness"), | ||
name: "User API", | ||
failureStatus: HealthStatus.Unhealthy, | ||
tags: new[] {"services"}); | ||
return services; | ||
} | ||
} |
66 changes: 21 additions & 45 deletions
66
BookingQueueSubscriber/BookingQueueSubscriber/HealthCheckFunction.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,67 +1,43 @@ | ||
using BookingQueueSubscriber.Contract.Responses; | ||
using VideoApi.Client; | ||
using Microsoft.Extensions.Diagnostics.HealthChecks; | ||
|
||
namespace BookingQueueSubscriber | ||
{ | ||
public class HealthCheckFunction | ||
{ | ||
private readonly IVideoApiClient _videoApiClient; | ||
|
||
private readonly HealthCheckService _healthCheck; | ||
|
||
public HealthCheckFunction(IVideoApiClient videoApiClient) | ||
public HealthCheckFunction(HealthCheckService healthCheck) | ||
{ | ||
_videoApiClient = videoApiClient; | ||
_healthCheck = healthCheck; | ||
} | ||
|
||
[FunctionName("HealthCheck")] | ||
public async Task<IActionResult> HealthCheck( | ||
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "health/liveness")] HttpRequest req, ILogger log) | ||
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "health/liveness")] | ||
HttpRequest req, ILogger log) | ||
{ | ||
var response = new HealthCheckResponse | ||
var report = await _healthCheck.CheckHealthAsync(); | ||
var healthCheckResponse = new | ||
{ | ||
VideoApiHealth = { Successful = true }, | ||
AppVersion = GetApplicationVersion() | ||
status = report.Status.ToString(), | ||
details = report.Entries.Select(e => new | ||
{ | ||
key = e.Key, value = Enum.GetName(typeof(HealthStatus), e.Value.Status), | ||
error = e.Value.Exception?.Message | ||
}) | ||
}; | ||
|
||
try | ||
{ | ||
await _videoApiClient.GetExpiredOpenConferencesAsync(); | ||
} | ||
catch (Exception ex) | ||
{ | ||
log.LogError(ex, "Unable to retrieve expired open conferences"); | ||
response.VideoApiHealth = HandleVideoApiCallException(ex); | ||
} | ||
|
||
return new OkObjectResult(response); | ||
} | ||
var statusCode = report.Status == HealthStatus.Healthy | ||
? (int) HttpStatusCode.OK | ||
: (int) HttpStatusCode.ServiceUnavailable; | ||
|
||
private HealthCheck HandleVideoApiCallException(Exception ex) | ||
{ | ||
var isApiException = ex is VideoApiException; | ||
var healthCheck = new HealthCheck { Successful = true }; | ||
if (isApiException && ((VideoApiException)ex).StatusCode != (int)HttpStatusCode.InternalServerError) | ||
return new ObjectResult(healthCheckResponse) | ||
{ | ||
return healthCheck; | ||
} | ||
|
||
healthCheck.Successful = false; | ||
healthCheck.ErrorMessage = ex.Message; | ||
healthCheck.Data = ex.Data; | ||
StatusCode = statusCode | ||
}; | ||
|
||
return healthCheck; | ||
} | ||
private ApplicationVersion GetApplicationVersion() | ||
{ | ||
var applicationVersion = new ApplicationVersion(); | ||
applicationVersion.FileVersion = GetExecutingAssemblyAttribute<AssemblyFileVersionAttribute>(a => a.Version); | ||
applicationVersion.InformationVersion = GetExecutingAssemblyAttribute<AssemblyInformationalVersionAttribute>(a => a.InformationalVersion); | ||
return applicationVersion; | ||
} | ||
|
||
private string GetExecutingAssemblyAttribute<T>(Func<T, string> value) where T : Attribute | ||
{ | ||
T attribute = (T)Attribute.GetCustomAttribute(Assembly.GetExecutingAssembly(), typeof(T)); | ||
return value.Invoke(attribute); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.