Files
MBN_STOCK_WEBVIEW/tests/MBN_STOCK_WEBVIEW.Infrastructure.Tests/DatabaseHealthServiceTests.cs

106 lines
3.7 KiB
C#

using System.Data;
using MBN_STOCK_WEBVIEW.Infrastructure;
using MMoneyCoderSharp.Data;
namespace MBN_STOCK_WEBVIEW.Infrastructure.Tests;
public sealed class DatabaseHealthServiceTests
{
[Fact]
public async Task CheckAsync_Unconfigured_ReturnsNotConfiguredWithoutQuery()
{
var executor = new StubDataQueryExecutor();
var service = new DatabaseHealthService(executor, new DatabaseOptions());
var status = await service.CheckAsync(DataSourceKind.Oracle);
Assert.Equal(DatabaseHealthState.NotConfigured, status.State);
Assert.Equal(DataSourceKind.Oracle, status.Source);
Assert.Equal(TimeSpan.Zero, status.Elapsed);
Assert.Equal(0, executor.CallCount);
}
[Theory]
[InlineData(DataSourceKind.Oracle, "SELECT 1 FROM DUAL")]
[InlineData(DataSourceKind.MariaDb, "SELECT 1")]
public async Task CheckAsync_ConfiguredAndQuerySucceeds_ReturnsHealthy(
DataSourceKind source,
string expectedQuery)
{
var executor = new StubDataQueryExecutor
{
ExecuteAsyncHandler = (_, _, _, _) => Task.FromResult(new DataTable())
};
var service = new DatabaseHealthService(executor, TestOptions.CreateConfigured());
var status = await service.CheckAsync(source);
Assert.Equal(DatabaseHealthState.Healthy, status.State);
Assert.Equal(source, status.Source);
Assert.Equal(1, executor.CallCount);
Assert.Equal(expectedQuery, executor.LastQuery);
}
[Fact]
public async Task CheckAsync_ConfiguredAndQueryFails_ReturnsUnhealthyWithoutThrowing()
{
const string host = "health-host-sensitive-sentinel";
var executor = new StubDataQueryExecutor
{
ExecuteAsyncHandler = (_, _, _, _) => Task.FromException<DataTable>(
new DatabaseQueryException(DataSourceKind.MariaDb, isTransient: true))
};
var service = new DatabaseHealthService(executor, TestOptions.CreateConfigured());
var status = await service.CheckAsync(DataSourceKind.MariaDb);
Assert.Equal(DatabaseHealthState.Unhealthy, status.State);
Assert.Equal(DataSourceKind.MariaDb, status.Source);
Assert.DoesNotContain(host, status.UserMessage, StringComparison.Ordinal);
}
[Fact]
public async Task CheckAsync_ConfiguredAndQueryTimesOut_ReturnsTimedOut()
{
var executor = new StubDataQueryExecutor
{
ExecuteAsyncHandler = (_, _, _, _) => Task.FromException<DataTable>(
new DatabaseQueryTimeoutException(DataSourceKind.Oracle))
};
var service = new DatabaseHealthService(executor, TestOptions.CreateConfigured());
var status = await service.CheckAsync(DataSourceKind.Oracle);
Assert.Equal(DatabaseHealthState.TimedOut, status.State);
Assert.Equal(DataSourceKind.Oracle, status.Source);
}
}
internal sealed class StubDataQueryExecutor : IDataQueryExecutor
{
public Func<DataSourceKind, string, string, CancellationToken, Task<DataTable>>? ExecuteAsyncHandler
{
get;
init;
}
public int CallCount { get; private set; }
public string? LastQuery { get; private set; }
public DataTable Execute(DataSourceKind source, string tableName, string query) =>
ExecuteAsync(source, tableName, query).GetAwaiter().GetResult();
public Task<DataTable> ExecuteAsync(
DataSourceKind source,
string tableName,
string query,
CancellationToken cancellationToken = default)
{
CallCount++;
LastQuery = query;
return ExecuteAsyncHandler?.Invoke(source, tableName, query, cancellationToken)
?? Task.FromResult(new DataTable());
}
}