using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.Core.AlarmHistorian;
namespace ZB.MOM.WW.OtOpcUa.Runtime.Tests.Historian;
///
/// Verifies the config-gated AddAlarmHistorian registration: when the
/// AlarmHistorian section is absent or disabled the
/// default survives; when it is enabled a real wins
/// (last-registration-wins over the TryAddSingleton Null default).
///
public sealed class AlarmHistorianRegistrationTests
{
/// A no-op writer the factory hands the Sqlite sink; never actually invoked in these tests.
private sealed class FakeWriter : IAlarmHistorianWriter
{
public Task> WriteBatchAsync(
IReadOnlyList batch, CancellationToken cancellationToken)
=> Task.FromResult>(
batch.Select(_ => HistorianWriteOutcome.Ack).ToList());
}
/// Seed the Null default exactly the way AddOtOpcUaRuntime does, then add logging.
private static ServiceCollection BaseServices()
{
var services = new ServiceCollection();
services.AddLogging();
services.TryAddSingleton(NullAlarmHistorianSink.Instance);
return services;
}
private static IConfiguration ConfigFrom(Dictionary values)
=> new ConfigurationBuilder().AddInMemoryCollection(values).Build();
[Fact]
public void Section_absent_keeps_null_sink()
{
var services = BaseServices();
var config = ConfigFrom(new Dictionary());
services.AddAlarmHistorian(config, (_, _) => new FakeWriter());
using var provider = services.BuildServiceProvider();
provider.GetRequiredService().ShouldBeOfType();
}
[Fact]
public void Section_disabled_keeps_null_sink()
{
var services = BaseServices();
var config = ConfigFrom(new Dictionary
{
["AlarmHistorian:Enabled"] = "false",
});
services.AddAlarmHistorian(config, (_, _) => new FakeWriter());
using var provider = services.BuildServiceProvider();
provider.GetRequiredService().ShouldBeOfType();
}
[Fact]
public void Section_enabled_registers_sqlite_sink()
{
var tempDir = Path.Combine(Path.GetTempPath(), "otopcua-alarmhist-test-" + Guid.NewGuid().ToString("N"));
Directory.CreateDirectory(tempDir);
var dbPath = Path.Combine(tempDir, "alarm-historian-test.db");
try
{
var services = BaseServices();
var config = ConfigFrom(new Dictionary
{
["AlarmHistorian:Enabled"] = "true",
["AlarmHistorian:DatabasePath"] = dbPath,
});
services.AddAlarmHistorian(config, (_, _) => new FakeWriter());
using (var provider = services.BuildServiceProvider())
{
provider.GetRequiredService().ShouldBeOfType();
} // dispose stops the drain loop + releases the SQLite file handle
}
finally
{
try { Directory.Delete(tempDir, recursive: true); } catch (IOException) { /* best effort */ }
}
}
}