Skip to content

Commit

Permalink
Issue#369 add health probe for sub services (#503)
Browse files Browse the repository at this point in the history
* add healthcheck endpoint

* fix #369

* add new test
  • Loading branch information
Sben65 authored Mar 28, 2022
1 parent ddfcfc7 commit f4e306a
Show file tree
Hide file tree
Showing 20 changed files with 900 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public async Task UpdateShouldCreateNewEntity()
It.IsAny<int?>(),
It.IsAny<IEnumerable<string>>(),
It.IsAny<CancellationToken>()))
.Returns(Pageable<TableEntity>.FromPages(new[] {
.Returns(Pageable<TableEntity>.FromPages(new[] {
Page<TableEntity>.FromValues(new[]
{
new TableEntity(DeviceTagService.DefaultPartitionKey,tag.Name)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
// Copyright (c) CGI France. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace AzureIoTHub.Portal.Server.Tests.Unit.ServicesHealthCheck
{
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using AzureIoTHub.Portal.Server.ServicesHealthCheck;
using Microsoft.Azure.Devices;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Moq;
using NUnit.Framework;

[TestFixture]
public class IoTHubHealthCheckTest
{
private MockRepository mockRepository;

private Mock<RegistryManager> mockRegistryManager;
private Mock<ServiceClient> mockServiceClient;

[SetUp]
public void SetUp()
{
this.mockRepository = new MockRepository(MockBehavior.Strict);

this.mockRegistryManager = this.mockRepository.Create<RegistryManager>();
this.mockServiceClient = this.mockRepository.Create<ServiceClient>();
}

private IoTHubHealthCheck CreateHealthCheck()
{
return new IoTHubHealthCheck(this.mockRegistryManager.Object, this.mockServiceClient.Object);
}

[Test]
public async Task CheckHealthAsyncStateUnderTestExpectedBehavior()
{
// Arrange
var healthService = CreateHealthCheck();

var mockServiceStat = this.mockRepository.Create<ServiceStatistics>();
var mockQuery = this.mockRepository.Create<IQuery>();

var healthCheckContext = new HealthCheckContext();
var token = new CancellationToken(canceled:false);

_ = mockQuery.Setup(c => c.GetNextAsJsonAsync())
.ReturnsAsync(new string[]
{
/*lang=json*/
"{ $0: 2}"
});

_ = this.mockServiceClient
.Setup(c => c.GetServiceStatisticsAsync(It.IsAny<CancellationToken>()))
.ReturnsAsync(mockServiceStat.Object);

_ = this.mockRegistryManager
.Setup(c => c.CreateQuery(It.Is<string>(x => x == "SELECT count() FROM devices")))
.Returns(mockQuery.Object);

// Act
var result = await healthService.CheckHealthAsync(healthCheckContext, token);

// Assert
Assert.IsNotNull(result);
Assert.AreEqual(HealthStatus.Healthy, result.Status);
}

[Test]
public async Task CheckHealthAsyncThrowExceptionReturnUnHealthy()
{
// Arrange
var healthService = CreateHealthCheck();

var mockServiceStat = this.mockRepository.Create<ServiceStatistics>();
var mockQuery = this.mockRepository.Create<IQuery>();

var healthRegistration = new HealthCheckRegistration(Guid.NewGuid().ToString(), healthService, HealthStatus.Unhealthy, new List<string>());

var healthCheckContext = new HealthCheckContext()
{
Registration = healthRegistration
};
var token = new CancellationToken(canceled:false);

_ = mockQuery.Setup(c => c.GetNextAsJsonAsync())
.ReturnsAsync(new string[]
{
/*lang=json*/
"{ $0: 2}"
});

_ = this.mockServiceClient
.Setup(c => c.GetServiceStatisticsAsync(It.IsAny<CancellationToken>()))
.Throws(exception: new SystemException("test"));

_ = this.mockRegistryManager
.Setup(c => c.CreateQuery(It.Is<string>(x => x == "SELECT count() FROM devices")))
.Returns(mockQuery.Object);

// Act
var result = await healthService.CheckHealthAsync(healthCheckContext, token);

// Assert
Assert.IsNotNull(result);
Assert.AreEqual(HealthStatus.Unhealthy, result.Status);
}

[Test]
public async Task CheckHealthAsyncWithNullQueryReturnUnHealthy()
{
// Arrange
var healthService = CreateHealthCheck();

var mockServiceStat = this.mockRepository.Create<ServiceStatistics>();
var mockQuery = this.mockRepository.Create<IQuery>();

var healthRegistration = new HealthCheckRegistration(Guid.NewGuid().ToString(), healthService, HealthStatus.Unhealthy, new List<string>());

var healthCheckContext = new HealthCheckContext()
{
Registration = healthRegistration
};
var token = new CancellationToken(canceled:false);

_ = mockQuery.Setup(c => c.GetNextAsJsonAsync())
.ReturnsAsync(new string[]
{
/*lang=json*/
"{ $0: 2}"
});

_ = this.mockServiceClient
.Setup(c => c.GetServiceStatisticsAsync(It.IsAny<CancellationToken>()))
.ReturnsAsync(mockServiceStat.Object);

_ = this.mockRegistryManager
.Setup(c => c.CreateQuery(It.Is<string>(x => x == "SELECT count() FROM devices")))
.Returns(value: null);

// Act
var result = await healthService.CheckHealthAsync(healthCheckContext, token);

// Assert
Assert.IsNotNull(result);
Assert.AreEqual(HealthStatus.Unhealthy, result.Status);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright (c) CGI France. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace AzureIoTHub.Portal.Server.Tests.Unit.ServicesHealthCheck
{
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using AzureIoTHub.Portal.Server.Managers;
using AzureIoTHub.Portal.Server.ServicesHealthCheck;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Moq;
using NUnit.Framework;

[TestFixture]
public class LoRaManagementKeyFacadeHealthCheckTest
{
private MockRepository mockRepository;
private Mock<ILoraDeviceMethodManager> mockoraDeviceMethodManager;

[SetUp]
public void SetUp()
{
this.mockRepository = new MockRepository(MockBehavior.Strict);

this.mockoraDeviceMethodManager = this.mockRepository.Create<ILoraDeviceMethodManager>();
}

private LoRaManagementKeyFacadeHealthCheck CreateService()
{
return new LoRaManagementKeyFacadeHealthCheck(this.mockoraDeviceMethodManager.Object);
}

[Test]
public async Task CheckHealthAsyncStateUnderTestReturnHealthy()
{
// Arrange
var healthService = CreateService();

var healthCheckContext = new HealthCheckContext();
var token = new CancellationToken(canceled:false);

var mockHttpMessage = this.mockRepository.Create<HttpResponseMessage>(System.Net.HttpStatusCode.OK);

_ = this.mockoraDeviceMethodManager
.Setup(c => c.CheckAzureFunctionReturn(It.IsAny<CancellationToken>()))
.ReturnsAsync(mockHttpMessage.Object);

// Act
var result = await healthService.CheckHealthAsync(healthCheckContext, token);

// Assert
Assert.IsNotNull(result);
Assert.AreEqual(HealthStatus.Healthy, result.Status);
}

[Test]
public async Task CheckHealthAsyncStateUnderTestReturnUnhealthy()
{
// Arrange
var healthService = CreateService();

var healthRegistration = new HealthCheckRegistration(Guid.NewGuid().ToString(), healthService, HealthStatus.Unhealthy, new List<string>());
var healthCheckContext = new HealthCheckContext()
{
Registration = healthRegistration
};
var token = new CancellationToken(canceled:false);

var mockHttpMessage = this.mockRepository.Create<HttpResponseMessage>(System.Net.HttpStatusCode.BadRequest);

_ = this.mockoraDeviceMethodManager
.Setup(c => c.CheckAzureFunctionReturn(It.IsAny<CancellationToken>()))
.ReturnsAsync(mockHttpMessage.Object);

// Act
var result = await healthService.CheckHealthAsync(healthCheckContext, token);

// Assert
Assert.IsNotNull(result);
Assert.AreEqual(HealthStatus.Unhealthy, result.Status);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// Copyright (c) CGI France. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace AzureIoTHub.Portal.Server.Tests.Unit.ServicesHealthCheck
{
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;
using AzureIoTHub.Portal.Server.ServicesHealthCheck;
using AzureIoTHub.Portal.Server.Wrappers;
using Microsoft.Azure.Devices.Provisioning.Service;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Moq;
using NUnit.Framework;

[TestFixture]
public class ProvisioningServiceClientHealthCheckTest
{
private MockRepository mockRepository;
private Mock<IProvisioningServiceClient> mockDps;

[SetUp]
public void SetUp()
{
this.mockRepository = new MockRepository(MockBehavior.Strict);

this.mockDps = this.mockRepository.Create<IProvisioningServiceClient>();
}

private ProvisioningServiceClientHealthCheck CreateHealthService()
{
return new ProvisioningServiceClientHealthCheck(this.mockDps.Object);
}

//[Test]
//public async Task CheckHealthAsyncStateUnderTestReturnHealthy()
//{
// // Arrange
// var healthService = CreateHealthService();

// var healthCheckContext = new HealthCheckContext();
// var token = new CancellationToken(canceled:false);

// var attestation = new SymmetricKeyAttestation(GenerateKey(), GenerateKey());
// var enrollmentGroup = new EnrollmentGroup("enrollmentId", attestation);

// _ = this.mockDps
// .Setup(c => c.CreateOrUpdateEnrollmentGroupAsync(It.IsAny<EnrollmentGroup>()))
// .ReturnsAsync(enrollmentGroup);

// _ = this.mockDps
// .Setup(c => c.GetEnrollmentGroupAsync(It.IsAny<string>()))
// .ReturnsAsync(enrollmentGroup);

// _ = this.mockDps
// .Setup(c => c.DeleteEnrollmentGroupAsync(It.IsAny<EnrollmentGroup>(), It.IsAny<CancellationToken>()));

// // Act
// var result = await healthService.CheckHealthAsync(healthCheckContext, token);

// // Assert
// Assert.IsNotNull(result);
// Assert.AreEqual(HealthStatus.Healthy, result.Status);
//}

[Test]
public async Task CheckHealthAsyncStateUnderTestReturnUnhealthy()
{
// Arrange
var healthService = CreateHealthService();

var healthRegistration = new HealthCheckRegistration(Guid.NewGuid().ToString(), healthService, HealthStatus.Unhealthy, new List<string>());
var healthCheckContext = new HealthCheckContext()
{
Registration = healthRegistration
};
var token = new CancellationToken(canceled:false);

var attestation = new SymmetricKeyAttestation(GenerateKey(), GenerateKey());
var enrollmentGroup = new EnrollmentGroup("enrollmentId", attestation);

_ = this.mockDps
.Setup(c => c.CreateOrUpdateEnrollmentGroupAsync(It.IsAny<EnrollmentGroup>()))
.Throws(new Exception());

_ = this.mockDps
.Setup(c => c.GetEnrollmentGroupAsync(It.IsAny<string>()))
.ReturnsAsync(enrollmentGroup);

_ = this.mockDps
.Setup(c => c.DeleteEnrollmentGroupAsync(It.IsAny<EnrollmentGroup>(), It.IsAny<CancellationToken>()));

// Act
var result = await healthService.CheckHealthAsync(healthCheckContext, token);

// Assert
Assert.IsNotNull(result);
Assert.AreEqual(HealthStatus.Unhealthy, result.Status);
}

private static string GenerateKey()
{
const int length = 48;
var rnd = RandomNumberGenerator.GetBytes(length);

return Convert.ToBase64String(rnd);
}

}
}
Loading

0 comments on commit f4e306a

Please sign in to comment.