feat(auditlog): scaffold ScadaLink.AuditLog project + tests project (#23)

This commit is contained in:
Joseph Doherty
2026-05-20 11:14:03 -04:00
parent de839627ed
commit a15ceb3ec9
6 changed files with 153 additions and 0 deletions

View File

@@ -1,5 +1,6 @@
<Solution>
<Folder Name="/src/">
<Project Path="src/ScadaLink.AuditLog/ScadaLink.AuditLog.csproj" />
<Project Path="src/ScadaLink.Commons/ScadaLink.Commons.csproj" />
<Project Path="src/ScadaLink.Host/ScadaLink.Host.csproj" />
<Project Path="src/ScadaLink.TemplateEngine/ScadaLink.TemplateEngine.csproj" />
@@ -22,6 +23,7 @@
<Project Path="src/ScadaLink.CLI/ScadaLink.CLI.csproj" />
</Folder>
<Folder Name="/tests/">
<Project Path="tests/ScadaLink.AuditLog.Tests/ScadaLink.AuditLog.Tests.csproj" />
<Project Path="tests/ScadaLink.Commons.Tests/ScadaLink.Commons.Tests.csproj" />
<Project Path="tests/ScadaLink.Host.Tests/ScadaLink.Host.Tests.csproj" />
<Project Path="tests/ScadaLink.TemplateEngine.Tests/ScadaLink.TemplateEngine.Tests.csproj" />

View File

@@ -0,0 +1,10 @@
namespace ScadaLink.AuditLog.Configuration;
/// <summary>
/// Configuration for Audit Log (#23). Bound from the "AuditLog" section of
/// <c>appsettings.json</c>. Bundle E (M1) ships the type so the DI scaffold can
/// register it; the full property set + validator are added by Task 9.
/// </summary>
public sealed class AuditLogOptions
{
}

View File

@@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
<PackageReference Include="Microsoft.Extensions.Options" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../ScadaLink.Commons/ScadaLink.Commons.csproj" />
<!-- Audit Log (#23) sits alongside Notification Outbox (#21) and Site Call Audit (#22).
IAuditLogRepository is registered by ScadaLink.ConfigurationDatabase; the project
reference is documented here so M2 writers + telemetry actors can depend on it. -->
<ProjectReference Include="../ScadaLink.ConfigurationDatabase/ScadaLink.ConfigurationDatabase.csproj" />
</ItemGroup>
<ItemGroup>
<InternalsVisibleTo Include="ScadaLink.AuditLog.Tests" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,36 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using ScadaLink.AuditLog.Configuration;
namespace ScadaLink.AuditLog;
/// <summary>
/// Composition root for the Audit Log (#23) component. M1 registers
/// <see cref="AuditLogOptions"/>; later milestones extend this method to wire
/// up writers, telemetry actors, and the central ingest pipeline. Audit Log
/// (#23) sits alongside Notification Outbox (#21) and Site Call Audit (#22).
/// </summary>
public static class ServiceCollectionExtensions
{
/// <summary>Configuration section bound to <see cref="AuditLogOptions"/>.</summary>
public const string ConfigSectionName = "AuditLog";
/// <summary>
/// Binds <see cref="AuditLogOptions"/> from the
/// <see cref="ConfigSectionName"/> section of <paramref name="config"/>.
/// M2+ will register writers, telemetry actors, and the central ingest
/// pipeline here. <c>IAuditLogRepository</c> is registered by
/// <c>ScadaLink.ConfigurationDatabase.ServiceCollectionExtensions.AddConfigurationDatabase</c>,
/// so the caller (the Host on the central node) must also call that.
/// </summary>
public static IServiceCollection AddAuditLog(this IServiceCollection services, IConfiguration config)
{
ArgumentNullException.ThrowIfNull(services);
ArgumentNullException.ThrowIfNull(config);
services.AddOptions<AuditLogOptions>()
.Bind(config.GetSection(ConfigSectionName));
return services;
}
}

View File

@@ -0,0 +1,50 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using ScadaLink.AuditLog.Configuration;
namespace ScadaLink.AuditLog.Tests;
/// <summary>
/// Bundle E (M1) smoke tests for the Audit Log (#23) DI scaffold. Verifies
/// <c>AddAuditLog</c> registers <see cref="AuditLogOptions"/> against the
/// <c>AuditLog</c> configuration section. Bundle E ships only the scaffold;
/// the validator + full options surface land in Task 9.
/// </summary>
public class AddAuditLogTests
{
[Fact]
public void AddAuditLog_RegistersAuditLogOptions()
{
var config = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string?>())
.Build();
var services = new ServiceCollection();
services.AddAuditLog(config);
var provider = services.BuildServiceProvider();
var opts = provider.GetService<IOptions<AuditLogOptions>>();
Assert.NotNull(opts);
Assert.NotNull(opts!.Value);
}
[Fact]
public void AddAuditLog_NullServices_Throws()
{
var config = new ConfigurationBuilder().Build();
Assert.Throws<ArgumentNullException>(
() => ServiceCollectionExtensions.AddAuditLog(null!, config));
}
[Fact]
public void AddAuditLog_NullConfig_Throws()
{
var services = new ServiceCollection();
Assert.Throws<ArgumentNullException>(
() => services.AddAuditLog(null!));
}
}

View File

@@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="coverlet.collector" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="xunit" />
<PackageReference Include="xunit.runner.visualstudio" />
</ItemGroup>
<ItemGroup>
<Using Include="Xunit" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../../src/ScadaLink.AuditLog/ScadaLink.AuditLog.csproj" />
</ItemGroup>
</Project>