Files
ScadaBridge/tests/ZB.MOM.WW.ScadaBridge.KpiHistory.Tests/KpiHistoryOptionsValidatorTests.cs
T
Joseph Doherty 513fa1aa16 docs(tests): fix CommentChecker findings across tests/ — 13,392 → 0 (repo-wide scan clean)
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.
2026-10-07 15:05:49 -04:00

326 lines
13 KiB
C#

using ZB.MOM.WW.ScadaBridge.KpiHistory;
namespace ZB.MOM.WW.ScadaBridge.KpiHistory.Tests;
/// <summary>
/// Unit tests for <see cref="KpiHistoryOptionsValidator"/>: the default
/// options must validate, and each rule (SampleInterval / RetentionDays /
/// PurgeInterval / DefaultMaxSeriesPoints) must reject its out-of-range values.
/// </summary>
public class KpiHistoryOptionsValidatorTests
{
private static KpiHistoryOptionsValidator NewValidator() => new();
/// <summary>Verifies that a zero source timeout fails validation.</summary>
[Fact]
public void Validate_SourceTimeout_Zero_Fails()
{
var result = NewValidator().Validate(null, new KpiHistoryOptions { SourceTimeout = TimeSpan.Zero });
Assert.True(result.Failed);
Assert.Contains("SourceTimeout", result.FailureMessage);
}
/// <summary>Verifies that the default options pass validation.</summary>
[Fact]
public void Validate_Defaults_Pass()
{
var result = NewValidator().Validate(null, new KpiHistoryOptions());
Assert.True(result.Succeeded);
}
// ---------------------------------------------------------------------
// SampleInterval > TimeSpan.Zero
// ---------------------------------------------------------------------
/// <summary>Verifies that a zero sample interval fails validation.</summary>
[Fact]
public void Validate_SampleInterval_Zero_Fails()
{
var opts = new KpiHistoryOptions { SampleInterval = TimeSpan.Zero };
var result = NewValidator().Validate(null, opts);
Assert.False(result.Succeeded);
Assert.Contains(
result.Failures!,
f => f.Contains(nameof(KpiHistoryOptions.SampleInterval), StringComparison.Ordinal));
}
/// <summary>Verifies that a negative sample interval fails validation.</summary>
[Fact]
public void Validate_SampleInterval_Negative_Fails()
{
var opts = new KpiHistoryOptions { SampleInterval = TimeSpan.FromSeconds(-1) };
var result = NewValidator().Validate(null, opts);
Assert.False(result.Succeeded);
Assert.Contains(
result.Failures!,
f => f.Contains(nameof(KpiHistoryOptions.SampleInterval), StringComparison.Ordinal));
}
// ---------------------------------------------------------------------
// RetentionDays in [1, 3650]
// ---------------------------------------------------------------------
/// <summary>Verifies that an in-range retention period passes validation.</summary>
/// <param name="value">The option value under test.</param>
[Theory]
[InlineData(1)] // min
[InlineData(90)] // default
[InlineData(3650)] // max
public void Validate_RetentionDays_InRange_Passes(int value)
{
// Keep RollupRetentionDays coherent (>= RetentionDays) so this test isolates the
// RetentionDays range rule and doesn't trip the rollup-retention coherence rule when
// RetentionDays is set above the default RollupRetentionDays (365).
var opts = new KpiHistoryOptions { RetentionDays = value, RollupRetentionDays = value };
Assert.True(NewValidator().Validate(null, opts).Succeeded);
}
/// <summary>Verifies that an out-of-range retention period fails validation.</summary>
/// <param name="value">The option value under test.</param>
[Theory]
[InlineData(0)]
[InlineData(3651)]
[InlineData(-1)]
public void Validate_RetentionDays_OutOfRange_Fails(int value)
{
var opts = new KpiHistoryOptions { RetentionDays = value };
var result = NewValidator().Validate(null, opts);
Assert.False(result.Succeeded);
Assert.Contains(
result.Failures!,
f => f.Contains(nameof(KpiHistoryOptions.RetentionDays), StringComparison.Ordinal));
}
// ---------------------------------------------------------------------
// PurgeInterval > TimeSpan.Zero
// ---------------------------------------------------------------------
/// <summary>Verifies that a zero purge interval fails validation.</summary>
[Fact]
public void Validate_PurgeInterval_Zero_Fails()
{
var opts = new KpiHistoryOptions { PurgeInterval = TimeSpan.Zero };
var result = NewValidator().Validate(null, opts);
Assert.False(result.Succeeded);
Assert.Contains(
result.Failures!,
f => f.Contains(nameof(KpiHistoryOptions.PurgeInterval), StringComparison.Ordinal));
}
/// <summary>Verifies that a negative purge interval fails validation.</summary>
[Fact]
public void Validate_PurgeInterval_Negative_Fails()
{
var opts = new KpiHistoryOptions { PurgeInterval = TimeSpan.FromHours(-1) };
var result = NewValidator().Validate(null, opts);
Assert.False(result.Succeeded);
Assert.Contains(
result.Failures!,
f => f.Contains(nameof(KpiHistoryOptions.PurgeInterval), StringComparison.Ordinal));
}
// ---------------------------------------------------------------------
// DefaultMaxSeriesPoints in [2, 5000]
// ---------------------------------------------------------------------
/// <summary>Verifies that an in-range default maximum series point count passes validation.</summary>
/// <param name="value">The option value under test.</param>
[Theory]
[InlineData(2)] // min
[InlineData(200)] // default
[InlineData(5000)] // max
public void Validate_DefaultMaxSeriesPoints_InRange_Passes(int value)
{
var opts = new KpiHistoryOptions { DefaultMaxSeriesPoints = value };
Assert.True(NewValidator().Validate(null, opts).Succeeded);
}
/// <summary>Verifies that an out-of-range default maximum series point count fails validation.</summary>
/// <param name="value">The option value under test.</param>
[Theory]
[InlineData(1)]
[InlineData(5001)]
[InlineData(0)]
public void Validate_DefaultMaxSeriesPoints_OutOfRange_Fails(int value)
{
var opts = new KpiHistoryOptions { DefaultMaxSeriesPoints = value };
var result = NewValidator().Validate(null, opts);
Assert.False(result.Succeeded);
Assert.Contains(
result.Failures!,
f => f.Contains(nameof(KpiHistoryOptions.DefaultMaxSeriesPoints), StringComparison.Ordinal));
}
// ---------------------------------------------------------------------
// RollupInterval > TimeSpan.Zero
// ---------------------------------------------------------------------
/// <summary>Verifies that a non-positive rollup interval fails validation.</summary>
/// <param name="hours">The rollup interval in hours.</param>
[Theory]
[InlineData(0)]
[InlineData(-1)]
public void Validate_RollupInterval_NotPositive_Fails(int hours)
{
var opts = new KpiHistoryOptions { RollupInterval = TimeSpan.FromHours(hours) };
var result = NewValidator().Validate(null, opts);
Assert.False(result.Succeeded);
Assert.Contains(
result.Failures!,
f => f.Contains(nameof(KpiHistoryOptions.RollupInterval), StringComparison.Ordinal));
}
// ---------------------------------------------------------------------
// RollupLookbackHours in [1, 168]
// ---------------------------------------------------------------------
/// <summary>Verifies that an in-range rollup lookback passes validation.</summary>
/// <param name="value">The option value under test.</param>
[Theory]
[InlineData(1)] // min
[InlineData(3)] // default
[InlineData(168)] // max
public void Validate_RollupLookbackHours_InRange_Passes(int value)
{
var opts = new KpiHistoryOptions { RollupLookbackHours = value };
Assert.True(NewValidator().Validate(null, opts).Succeeded);
}
/// <summary>Verifies that an out-of-range rollup lookback fails validation.</summary>
/// <param name="value">The option value under test.</param>
[Theory]
[InlineData(0)]
[InlineData(169)]
[InlineData(-1)]
public void Validate_RollupLookbackHours_OutOfRange_Fails(int value)
{
var opts = new KpiHistoryOptions { RollupLookbackHours = value };
var result = NewValidator().Validate(null, opts);
Assert.False(result.Succeeded);
Assert.Contains(
result.Failures!,
f => f.Contains(nameof(KpiHistoryOptions.RollupLookbackHours), StringComparison.Ordinal));
}
// ---------------------------------------------------------------------
// RollupRetentionDays in [1, 3650] AND >= RetentionDays
// ---------------------------------------------------------------------
/// <summary>Verifies that an in-range rollup retention period passes validation.</summary>
/// <param name="value">The option value under test.</param>
[Theory]
[InlineData(90)] // == RetentionDays default
[InlineData(365)] // default
[InlineData(3650)] // max
public void Validate_RollupRetentionDays_InRange_Passes(int value)
{
var opts = new KpiHistoryOptions { RollupRetentionDays = value };
Assert.True(NewValidator().Validate(null, opts).Succeeded);
}
/// <summary>Verifies that an out-of-range rollup retention period fails validation.</summary>
/// <param name="value">The option value under test.</param>
[Theory]
[InlineData(0)]
[InlineData(3651)]
[InlineData(-1)]
public void Validate_RollupRetentionDays_OutOfRange_Fails(int value)
{
var opts = new KpiHistoryOptions { RollupRetentionDays = value };
var result = NewValidator().Validate(null, opts);
Assert.False(result.Succeeded);
Assert.Contains(
result.Failures!,
f => f.Contains(nameof(KpiHistoryOptions.RollupRetentionDays), StringComparison.Ordinal));
}
/// <summary>Verifies that a rollup retention shorter than the raw retention fails validation.</summary>
[Fact]
public void Validate_RollupRetentionDays_LessThanRetentionDays_Fails()
{
// Coherence rule: rollups must outlive raw samples, else long-range trends hit a hole.
var opts = new KpiHistoryOptions
{
RetentionDays = 90,
RollupRetentionDays = 30, // in [1,3650] but < RetentionDays
};
var result = NewValidator().Validate(null, opts);
Assert.False(result.Succeeded);
Assert.Contains(
result.Failures!,
f => f.Contains(nameof(KpiHistoryOptions.RollupRetentionDays), StringComparison.Ordinal)
&& f.Contains(nameof(KpiHistoryOptions.RetentionDays), StringComparison.Ordinal));
}
/// <summary>Verifies that a rollup retention equal to the raw retention passes validation.</summary>
[Fact]
public void Validate_RollupRetentionDays_EqualToRetentionDays_Passes()
{
// Boundary of the coherence rule (>=): equal retention is allowed.
var opts = new KpiHistoryOptions { RetentionDays = 120, RollupRetentionDays = 120 };
Assert.True(NewValidator().Validate(null, opts).Succeeded);
}
// ---------------------------------------------------------------------
// RollupThresholdHours >= 24
// ---------------------------------------------------------------------
/// <summary>Verifies that a rollup threshold at or above the minimum passes validation.</summary>
/// <param name="value">The option value under test.</param>
[Theory]
[InlineData(24)] // min
[InlineData(168)] // default
[InlineData(2160)] // 90 d
public void Validate_RollupThresholdHours_AtOrAboveMin_Passes(int value)
{
var opts = new KpiHistoryOptions { RollupThresholdHours = value };
Assert.True(NewValidator().Validate(null, opts).Succeeded);
}
/// <summary>Verifies that a rollup threshold below the minimum fails validation.</summary>
/// <param name="value">The option value under test.</param>
[Theory]
[InlineData(23)]
[InlineData(0)]
[InlineData(-1)]
public void Validate_RollupThresholdHours_BelowMin_Fails(int value)
{
var opts = new KpiHistoryOptions { RollupThresholdHours = value };
var result = NewValidator().Validate(null, opts);
Assert.False(result.Succeeded);
Assert.Contains(
result.Failures!,
f => f.Contains(nameof(KpiHistoryOptions.RollupThresholdHours), StringComparison.Ordinal));
}
/// <summary>Verifies that violating every rule accumulates every failure message.</summary>
[Fact]
public void Validate_AllRulesViolated_AccumulatesEveryFailure()
{
// The base class aggregates ALL failures, not just the first — one
// message per violated rule.
var opts = new KpiHistoryOptions
{
SampleInterval = TimeSpan.Zero,
RetentionDays = 0,
PurgeInterval = TimeSpan.Zero,
DefaultMaxSeriesPoints = 1,
};
var result = NewValidator().Validate(null, opts);
Assert.False(result.Succeeded);
Assert.Equal(4, result.Failures!.Count());
}
}