Files
scadaproj/ZB.MOM.WW.Health/tests/ZB.MOM.WW.Health.Tests/GrpcDependencyHealthCheckTests.cs
T

108 lines
3.3 KiB
C#

using Grpc.Core;
using Grpc.Net.Client;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using ZB.MOM.WW.Health;
namespace ZB.MOM.WW.Health.Tests;
/// <summary>
/// Verifies <see cref="GrpcDependencyHealthCheck"/> via an injected probe (no live gRPC server):
/// probe-true → Healthy, probe-false → Unhealthy, and an <see cref="RpcException"/> from the probe
/// → Unhealthy. The channel is constructed but never dialled because the probe is stubbed.
/// </summary>
public sealed class GrpcDependencyHealthCheckTests
{
private static readonly GrpcChannel Channel = GrpcChannel.ForAddress("http://localhost");
private static async Task<HealthCheckResult> RunAsync(
GrpcDependencyOptions options, CancellationToken cancellationToken = default)
{
var check = new GrpcDependencyHealthCheck(Channel, options);
var context = new HealthCheckContext
{
Registration = new HealthCheckRegistration("grpc-dep", check, HealthStatus.Unhealthy, tags: null),
};
return await check.CheckHealthAsync(context, cancellationToken);
}
[Fact]
public async Task ProbeReturnsTrue_Healthy()
{
var result = await RunAsync(new GrpcDependencyOptions
{
Probe = static (_, _) => Task.FromResult(true),
});
Assert.Equal(HealthStatus.Healthy, result.Status);
}
[Fact]
public async Task ProbeReturnsFalse_Unhealthy()
{
var result = await RunAsync(new GrpcDependencyOptions
{
Probe = static (_, _) => Task.FromResult(false),
});
Assert.Equal(HealthStatus.Unhealthy, result.Status);
}
[Fact]
public async Task ProbeThrowsRpcException_Unhealthy()
{
var result = await RunAsync(new GrpcDependencyOptions
{
Probe = static (_, _) => throw new RpcException(new Status(StatusCode.Unavailable, "down")),
});
Assert.Equal(HealthStatus.Unhealthy, result.Status);
}
[Fact]
public async Task DependencyName_AppearsInDescription()
{
var result = await RunAsync(new GrpcDependencyOptions
{
DependencyName = "mxaccessgw worker",
Probe = static (_, _) => Task.FromResult(false),
});
Assert.Equal(HealthStatus.Unhealthy, result.Status);
Assert.Contains("mxaccessgw worker", result.Description);
}
[Fact]
public async Task ProbeExceedsTimeout_Unhealthy()
{
var result = await RunAsync(new GrpcDependencyOptions
{
Timeout = TimeSpan.FromMilliseconds(50),
Probe = static async (_, ct) =>
{
await Task.Delay(Timeout.Infinite, ct);
return true;
},
});
Assert.Equal(HealthStatus.Unhealthy, result.Status);
}
[Fact]
public async Task ExternalCancellation_Throws()
{
using var cts = new CancellationTokenSource();
await cts.CancelAsync();
await Assert.ThrowsAnyAsync<OperationCanceledException>(() => RunAsync(
new GrpcDependencyOptions
{
Probe = static async (_, ct) =>
{
await Task.Delay(Timeout.Infinite, ct);
return true;
},
},
cts.Token));
}
}