using ZB.MOM.WW.ScadaBridge.AuditLog.Site; namespace ZB.MOM.WW.ScadaBridge.AuditLog.Tests.Site; /// /// Eager startup validation for /// (arch-review 08 round 2 NF4). The site hot-path writer's channel/batch/flush /// knobs must be positive or the background writer task cannot make progress. /// BacklogPollIntervalSeconds is deliberately NOT validated — a /// non-positive value has a documented fall-back-to-30s contract. /// /// /// DatabasePath is intentionally NOT covered here (arch-review remediation /// WP1.2): it defaults to "" (no CWD-relative default — mirrors /// LocalDb:Path), but this validator runs on both Central and Site /// composition roots via ValidateOnStart, and only Site nodes ever resolve /// the writer. The Site-only requirement is enforced pre-host by /// StartupValidator in ZB.MOM.WW.ScadaBridge.Host — see /// StartupValidatorTests.SiteWithoutAuditLogDatabasePath_FailsValidation. /// public class SqliteAuditWriterOptionsValidatorTests { [Fact] public void DefaultOptions_AreValid() { // Includes the empty DatabasePath default — this validator does not check // it (see class remarks); only StartupValidator does, and only for Site nodes. var validator = new SqliteAuditWriterOptionsValidator(); Assert.True(validator.Validate(null, new SqliteAuditWriterOptions()).Succeeded); } [Fact] public void ZeroChannelCapacity_Fails() { var validator = new SqliteAuditWriterOptionsValidator(); var result = validator.Validate(null, new SqliteAuditWriterOptions { ChannelCapacity = 0 }); Assert.False(result.Succeeded); Assert.Contains(result.Failures!, f => f.Contains(nameof(SqliteAuditWriterOptions.ChannelCapacity), StringComparison.Ordinal)); } [Fact] public void ZeroBatchSize_Fails() { var validator = new SqliteAuditWriterOptionsValidator(); var result = validator.Validate(null, new SqliteAuditWriterOptions { BatchSize = 0 }); Assert.False(result.Succeeded); Assert.Contains(result.Failures!, f => f.Contains(nameof(SqliteAuditWriterOptions.BatchSize), StringComparison.Ordinal)); } [Fact] public void ZeroFlushInterval_Fails() { var validator = new SqliteAuditWriterOptionsValidator(); var result = validator.Validate(null, new SqliteAuditWriterOptions { FlushIntervalMs = 0 }); Assert.False(result.Succeeded); Assert.Contains(result.Failures!, f => f.Contains(nameof(SqliteAuditWriterOptions.FlushIntervalMs), StringComparison.Ordinal)); } [Theory] [InlineData(0)] [InlineData(-1)] public void NonPositiveBacklogPollInterval_StillValid(int value) { // Documented fall-back-to-30s contract — must NOT be rejected. var validator = new SqliteAuditWriterOptionsValidator(); Assert.True(validator.Validate(null, new SqliteAuditWriterOptions { BacklogPollIntervalSeconds = value }).Succeeded); } }