513fa1aa16
Comment/XML-doc changes only: - add summaries to ~10k test methods, fixtures, fakes and helpers (+ <param> on theories, <returns> on async Task methods, <inheritdoc/> on interface implementations the checker can resolve) - strip ~2.6k project-tracking references (WP*, P*-*, row-NN, Task N, #NN, Component-0NN) from comments, keeping the explanatory text; reword false positives in comments only - real docs on fakes implementing BCL/library interfaces (IDisposable, ILogger, IOptionsMonitor, IAsyncLifetime) - reword the last 5 src/ false positives (CWE-1236, failures-1, year-0001, M365) Only non-comment edits: four one-line nested classes split across lines so members can carry docs. Build 0 errors / 0 warnings.
109 lines
4.4 KiB
C#
109 lines
4.4 KiB
C#
using Microsoft.Extensions.Options;
|
|
|
|
namespace ZB.MOM.WW.ScadaBridge.StoreAndForward.Tests;
|
|
|
|
/// <summary>
|
|
/// <see cref="StoreAndForwardOptions"/> retry intervals feed the background sweep
|
|
/// timer (zero/negative trips the timer constructor) and the SQLite path backs the
|
|
/// buffer. These tests assert the <see cref="StoreAndForwardOptionsValidator"/>
|
|
/// rejects a bad <c>ScadaBridge:StoreAndForward</c> section with a clear,
|
|
/// key-naming message rather than crashing later with an opaque exception.
|
|
/// </summary>
|
|
public class StoreAndForwardOptionsValidatorTests
|
|
{
|
|
private static ValidateOptionsResult Validate(StoreAndForwardOptions options) =>
|
|
new StoreAndForwardOptionsValidator().Validate(Options.DefaultName, options);
|
|
|
|
/// <summary>Verifies that the default options are valid.</summary>
|
|
[Fact]
|
|
public void DefaultOptions_AreValid()
|
|
{
|
|
var result = Validate(new StoreAndForwardOptions());
|
|
Assert.True(result.Succeeded, result.FailureMessage);
|
|
}
|
|
|
|
/// <summary>Verifies that a zero default retry interval is rejected.</summary>
|
|
[Fact]
|
|
public void ZeroDefaultRetryInterval_IsRejected()
|
|
{
|
|
var result = Validate(new StoreAndForwardOptions { DefaultRetryInterval = TimeSpan.Zero });
|
|
|
|
Assert.True(result.Failed);
|
|
Assert.Contains("DefaultRetryInterval", result.FailureMessage);
|
|
}
|
|
|
|
/// <summary>Verifies that a zero retry timer interval is rejected.</summary>
|
|
[Fact]
|
|
public void ZeroRetryTimerInterval_IsRejected()
|
|
{
|
|
var result = Validate(new StoreAndForwardOptions { RetryTimerInterval = TimeSpan.Zero });
|
|
|
|
Assert.True(result.Failed);
|
|
Assert.Contains("RetryTimerInterval", result.FailureMessage);
|
|
}
|
|
|
|
/// <summary>
|
|
/// The inverse of the rule this replaces. Before LocalDb Phase 2 an empty
|
|
/// SqliteDbPath was rejected, because it was the live buffer file and an empty
|
|
/// value failed opaquely at first enqueue. The buffer now lives in the
|
|
/// consolidated LocalDb database, so the key is only the legacy migration
|
|
/// source and an empty value legitimately means "nothing to migrate" — a node
|
|
/// that has already migrated must be able to drop it.
|
|
/// </summary>
|
|
[Fact]
|
|
public void EmptySqliteDbPath_IsAccepted_BecauseThePathIsMigrationOnly()
|
|
{
|
|
var result = Validate(new StoreAndForwardOptions { SqliteDbPath = "" });
|
|
|
|
Assert.False(result.Failed);
|
|
}
|
|
|
|
// ── R2 T9: sweep-tuning eager validation (N4) ──
|
|
|
|
/// <summary>Verifies that a negative sweep batch limit fails validation.</summary>
|
|
/// <param name="limit">The negative sweep batch limit under test.</param>
|
|
[Theory]
|
|
[InlineData(-1)]
|
|
[InlineData(-500)]
|
|
public void Validate_NegativeSweepBatchLimit_Fails(int limit)
|
|
{
|
|
var result = Validate(new StoreAndForwardOptions { SweepBatchLimit = limit });
|
|
Assert.True(result.Failed);
|
|
Assert.Contains("SweepBatchLimit", result.FailureMessage);
|
|
}
|
|
|
|
/// <summary>Verifies that a zero sweep batch limit is valid and means unlimited, as in the legacy behavior.</summary>
|
|
[Fact]
|
|
public void Validate_ZeroSweepBatchLimit_IsValidUnlimitedLegacy()
|
|
{
|
|
var result = Validate(new StoreAndForwardOptions { SweepBatchLimit = 0 });
|
|
Assert.True(result.Succeeded, result.FailureMessage);
|
|
}
|
|
|
|
/// <summary>Verifies that a non-positive sweep target parallelism fails validation.</summary>
|
|
/// <param name="parallelism">The non-positive parallelism value under test.</param>
|
|
[Theory]
|
|
[InlineData(0)]
|
|
[InlineData(-4)]
|
|
public void Validate_NonPositiveSweepTargetParallelism_Fails(int parallelism)
|
|
{
|
|
var result = Validate(new StoreAndForwardOptions { SweepTargetParallelism = parallelism });
|
|
Assert.True(result.Failed);
|
|
Assert.Contains("SweepTargetParallelism", result.FailureMessage);
|
|
}
|
|
|
|
// ── Bounded observer queue capacity ──
|
|
|
|
/// <summary>Verifies that a non-positive observer queue capacity fails validation.</summary>
|
|
/// <param name="capacity">The non-positive capacity value under test.</param>
|
|
[Theory]
|
|
[InlineData(0)]
|
|
[InlineData(-1)]
|
|
public void Validate_NonPositiveObserverQueueCapacity_Fails(int capacity)
|
|
{
|
|
var result = Validate(new StoreAndForwardOptions { ObserverQueueCapacity = capacity });
|
|
Assert.True(result.Failed);
|
|
Assert.Contains("ObserverQueueCapacity", result.FailureMessage);
|
|
}
|
|
}
|