226 lines
7.9 KiB
C#
226 lines
7.9 KiB
C#
// <copyright file="ConcelierConfigDiffTests.cs" company="StellaOps">
|
|
// Copyright (c) StellaOps. Licensed under AGPL-3.0-or-later.
|
|
// </copyright>
|
|
// Sprint: SPRINT_20260105_002_005_TEST_cross_cutting
|
|
// Task: CCUT-020
|
|
|
|
using System.Collections.Immutable;
|
|
using FluentAssertions;
|
|
using Microsoft.Extensions.Logging.Abstractions;
|
|
using StellaOps.TestKit;
|
|
using StellaOps.Testing.ConfigDiff;
|
|
using Xunit;
|
|
|
|
namespace StellaOps.Concelier.ConfigDiff.Tests;
|
|
|
|
/// <summary>
|
|
/// Config-diff tests for the Concelier module.
|
|
/// Verifies that configuration changes produce only expected behavioral deltas.
|
|
/// </summary>
|
|
[Trait("Category", TestCategories.ConfigDiff)]
|
|
[Trait("Category", TestCategories.Integration)]
|
|
[Trait("BlastRadius", TestCategories.BlastRadius.Advisories)]
|
|
public class ConcelierConfigDiffTests : ConfigDiffTestBase
|
|
{
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="ConcelierConfigDiffTests"/> class.
|
|
/// </summary>
|
|
public ConcelierConfigDiffTests()
|
|
: base(
|
|
new ConfigDiffTestConfig(StrictMode: true),
|
|
NullLogger.Instance)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verifies that changing cache timeout only affects cache behavior.
|
|
/// </summary>
|
|
[Fact]
|
|
public async Task ChangingCacheTimeout_OnlyAffectsCacheBehavior()
|
|
{
|
|
// Arrange
|
|
var baselineConfig = new ConcelierTestConfig
|
|
{
|
|
CacheTimeoutMinutes = 30,
|
|
MaxConcurrentDownloads = 10,
|
|
RetryCount = 3
|
|
};
|
|
|
|
var changedConfig = baselineConfig with
|
|
{
|
|
CacheTimeoutMinutes = 60
|
|
};
|
|
|
|
// Act
|
|
var result = await TestConfigIsolationAsync(
|
|
baselineConfig,
|
|
changedConfig,
|
|
changedSetting: "CacheTimeoutMinutes",
|
|
unrelatedBehaviors:
|
|
[
|
|
async config => await GetDownloadBehaviorAsync(config),
|
|
async config => await GetRetryBehaviorAsync(config),
|
|
async config => await GetParseBehaviorAsync(config)
|
|
]);
|
|
|
|
// Assert
|
|
result.IsSuccess.Should().BeTrue(
|
|
because: "changing cache timeout should not affect other behaviors");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verifies that changing retry count produces expected behavioral delta.
|
|
/// </summary>
|
|
[Fact]
|
|
public async Task ChangingRetryCount_ProducesExpectedDelta()
|
|
{
|
|
// Arrange
|
|
var baselineConfig = new ConcelierTestConfig { RetryCount = 3 };
|
|
var changedConfig = new ConcelierTestConfig { RetryCount = 5 };
|
|
|
|
var expectedDelta = new ConfigDelta(
|
|
ChangedBehaviors: ["MaxRetryAttempts", "FailureRecoveryWindow"],
|
|
BehaviorDeltas:
|
|
[
|
|
new BehaviorDelta("MaxRetryAttempts", "3", "5", null),
|
|
new BehaviorDelta("FailureRecoveryWindow", "increase", null,
|
|
"More retries extend recovery window")
|
|
]);
|
|
|
|
// Act
|
|
var result = await TestConfigBehavioralDeltaAsync(
|
|
baselineConfig,
|
|
changedConfig,
|
|
getBehavior: async config => await CaptureRetryBehaviorAsync(config),
|
|
computeDelta: ComputeBehaviorSnapshotDelta,
|
|
expectedDelta: expectedDelta);
|
|
|
|
// Assert
|
|
result.IsSuccess.Should().BeTrue(
|
|
because: "retry count change should produce expected behavioral delta");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verifies that changing max concurrent downloads only affects concurrency.
|
|
/// </summary>
|
|
[Fact]
|
|
public async Task ChangingMaxConcurrentDownloads_OnlyAffectsConcurrency()
|
|
{
|
|
// Arrange
|
|
var baselineConfig = new ConcelierTestConfig { MaxConcurrentDownloads = 5 };
|
|
var changedConfig = new ConcelierTestConfig { MaxConcurrentDownloads = 20 };
|
|
|
|
// Act
|
|
var result = await TestConfigIsolationAsync(
|
|
baselineConfig,
|
|
changedConfig,
|
|
changedSetting: "MaxConcurrentDownloads",
|
|
unrelatedBehaviors:
|
|
[
|
|
async config => await GetCacheBehaviorAsync(config),
|
|
async config => await GetRetryBehaviorAsync(config),
|
|
async config => await GetParseBehaviorAsync(config)
|
|
]);
|
|
|
|
// Assert
|
|
result.IsSuccess.Should().BeTrue(
|
|
because: "changing concurrency should not affect cache, retry, or parsing");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verifies that enabling strict validation produces expected changes.
|
|
/// </summary>
|
|
[Fact]
|
|
public async Task EnablingStrictValidation_ProducesExpectedDelta()
|
|
{
|
|
// Arrange
|
|
var baselineConfig = new ConcelierTestConfig { StrictValidation = false };
|
|
var changedConfig = new ConcelierTestConfig { StrictValidation = true };
|
|
|
|
var expectedDelta = new ConfigDelta(
|
|
ChangedBehaviors: ["ValidationStrictness", "RejectionRate"],
|
|
BehaviorDeltas:
|
|
[
|
|
new BehaviorDelta("ValidationStrictness", "relaxed", "strict", null),
|
|
new BehaviorDelta("RejectionRate", "increase", null,
|
|
"Strict validation rejects more malformed advisories")
|
|
]);
|
|
|
|
// Act
|
|
var result = await TestConfigBehavioralDeltaAsync(
|
|
baselineConfig,
|
|
changedConfig,
|
|
getBehavior: async config => await CaptureValidationBehaviorAsync(config),
|
|
computeDelta: ComputeBehaviorSnapshotDelta,
|
|
expectedDelta: expectedDelta);
|
|
|
|
// Assert
|
|
result.IsSuccess.Should().BeTrue();
|
|
}
|
|
|
|
// Helper methods to capture behaviors
|
|
|
|
private static Task<object> GetDownloadBehaviorAsync(ConcelierTestConfig config)
|
|
{
|
|
return Task.FromResult<object>(new { MaxConcurrent = config.MaxConcurrentDownloads });
|
|
}
|
|
|
|
private static Task<object> GetRetryBehaviorAsync(ConcelierTestConfig config)
|
|
{
|
|
return Task.FromResult<object>(new { RetryCount = config.RetryCount });
|
|
}
|
|
|
|
private static Task<object> GetCacheBehaviorAsync(ConcelierTestConfig config)
|
|
{
|
|
return Task.FromResult<object>(new { CacheTimeout = config.CacheTimeoutMinutes });
|
|
}
|
|
|
|
private static Task<object> GetParseBehaviorAsync(ConcelierTestConfig config)
|
|
{
|
|
return Task.FromResult<object>(new { ParseMode = "standard" });
|
|
}
|
|
|
|
private static Task<BehaviorSnapshot> CaptureRetryBehaviorAsync(ConcelierTestConfig config)
|
|
{
|
|
var snapshot = new BehaviorSnapshot(
|
|
ConfigurationId: $"retry-{config.RetryCount}",
|
|
Behaviors:
|
|
[
|
|
new CapturedBehavior("MaxRetryAttempts", config.RetryCount.ToString(), DateTimeOffset.UtcNow),
|
|
new CapturedBehavior("FailureRecoveryWindow",
|
|
config.RetryCount > 3 ? "increase" : "standard", DateTimeOffset.UtcNow)
|
|
],
|
|
CapturedAt: DateTimeOffset.UtcNow);
|
|
|
|
return Task.FromResult(snapshot);
|
|
}
|
|
|
|
private static Task<BehaviorSnapshot> CaptureValidationBehaviorAsync(ConcelierTestConfig config)
|
|
{
|
|
var snapshot = new BehaviorSnapshot(
|
|
ConfigurationId: $"validation-{config.StrictValidation}",
|
|
Behaviors:
|
|
[
|
|
new CapturedBehavior("ValidationStrictness",
|
|
config.StrictValidation ? "strict" : "relaxed", DateTimeOffset.UtcNow),
|
|
new CapturedBehavior("RejectionRate",
|
|
config.StrictValidation ? "increase" : "standard", DateTimeOffset.UtcNow)
|
|
],
|
|
CapturedAt: DateTimeOffset.UtcNow);
|
|
|
|
return Task.FromResult(snapshot);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Test configuration for Concelier module.
|
|
/// </summary>
|
|
public sealed record ConcelierTestConfig
|
|
{
|
|
public int CacheTimeoutMinutes { get; init; } = 30;
|
|
public int MaxConcurrentDownloads { get; init; } = 10;
|
|
public int RetryCount { get; init; } = 3;
|
|
public bool StrictValidation { get; init; } = false;
|
|
public TimeSpan RequestTimeout { get; init; } = TimeSpan.FromSeconds(30);
|
|
}
|