//
// Copyright (c) StellaOps. Licensed under AGPL-3.0-or-later.
//
// Sprint: SPRINT_20260105_002_005_TEST_cross_cutting
// Task: CCUT-022
using System.Collections.Immutable;
using FluentAssertions;
using Microsoft.Extensions.Logging.Abstractions;
using StellaOps.TestKit;
using StellaOps.Testing.ConfigDiff;
using Xunit;
namespace StellaOps.Scanner.ConfigDiff.Tests;
///
/// Config-diff tests for the Scanner module.
/// Verifies that configuration changes produce only expected behavioral deltas.
///
[Trait("Category", TestCategories.ConfigDiff)]
[Trait("Category", TestCategories.Integration)]
[Trait("BlastRadius", TestCategories.BlastRadius.Scanning)]
public class ScannerConfigDiffTests : ConfigDiffTestBase
{
///
/// Initializes a new instance of the class.
///
public ScannerConfigDiffTests()
: base(
new ConfigDiffTestConfig(StrictMode: true),
NullLogger.Instance)
{
}
///
/// Verifies that changing scan depth only affects traversal behavior.
///
[Fact]
public async Task ChangingScanDepth_OnlyAffectsTraversal()
{
// Arrange
var baselineConfig = new ScannerTestConfig
{
MaxScanDepth = 10,
EnableReachabilityAnalysis = true,
MaxConcurrentAnalyzers = 4
};
var changedConfig = baselineConfig with
{
MaxScanDepth = 20
};
// Act
var result = await TestConfigIsolationAsync(
baselineConfig,
changedConfig,
changedSetting: "MaxScanDepth",
unrelatedBehaviors:
[
async config => await GetReachabilityBehaviorAsync(config),
async config => await GetConcurrencyBehaviorAsync(config),
async config => await GetOutputFormatBehaviorAsync(config)
]);
// Assert
result.IsSuccess.Should().BeTrue(
because: "changing scan depth should not affect reachability or concurrency");
}
///
/// Verifies that enabling reachability analysis produces expected delta.
///
[Fact]
public async Task EnablingReachability_ProducesExpectedDelta()
{
// Arrange
var baselineConfig = new ScannerTestConfig { EnableReachabilityAnalysis = false };
var changedConfig = new ScannerTestConfig { EnableReachabilityAnalysis = true };
var expectedDelta = new ConfigDelta(
ChangedBehaviors: ["ReachabilityMode", "ScanDuration", "OutputDetail"],
BehaviorDeltas:
[
new BehaviorDelta("ReachabilityMode", "disabled", "enabled", null),
new BehaviorDelta("ScanDuration", "increase", null,
"Reachability analysis adds processing time"),
new BehaviorDelta("OutputDetail", "basic", "enhanced",
"Reachability data added to findings")
]);
// Act
var result = await TestConfigBehavioralDeltaAsync(
baselineConfig,
changedConfig,
getBehavior: async config => await CaptureReachabilityBehaviorAsync(config),
computeDelta: ComputeBehaviorSnapshotDelta,
expectedDelta: expectedDelta);
// Assert
result.IsSuccess.Should().BeTrue(
because: "enabling reachability should produce expected behavioral delta");
}
///
/// Verifies that changing SBOM format only affects output.
///
[Fact]
public async Task ChangingSbomFormat_OnlyAffectsOutput()
{
// Arrange
var baselineConfig = new ScannerTestConfig { SbomFormat = "spdx-3.0" };
var changedConfig = new ScannerTestConfig { SbomFormat = "cyclonedx-1.7" };
// Act
var result = await TestConfigIsolationAsync(
baselineConfig,
changedConfig,
changedSetting: "SbomFormat",
unrelatedBehaviors:
[
async config => await GetScanningBehaviorAsync(config),
async config => await GetVulnMatchingBehaviorAsync(config),
async config => await GetReachabilityBehaviorAsync(config)
]);
// Assert
result.IsSuccess.Should().BeTrue(
because: "SBOM format should only affect output serialization");
}
///
/// Verifies that changing concurrency produces expected delta.
///
[Fact]
public async Task ChangingConcurrency_ProducesExpectedDelta()
{
// Arrange
var baselineConfig = new ScannerTestConfig { MaxConcurrentAnalyzers = 2 };
var changedConfig = new ScannerTestConfig { MaxConcurrentAnalyzers = 8 };
var expectedDelta = new ConfigDelta(
ChangedBehaviors: ["ParallelismLevel", "ResourceUsage"],
BehaviorDeltas:
[
new BehaviorDelta("ParallelismLevel", "2", "8", null),
new BehaviorDelta("ResourceUsage", "increase", null,
"More concurrent analyzers use more resources")
]);
// Act
var result = await TestConfigBehavioralDeltaAsync(
baselineConfig,
changedConfig,
getBehavior: async config => await CaptureConcurrencyBehaviorAsync(config),
computeDelta: ComputeBehaviorSnapshotDelta,
expectedDelta: expectedDelta);
// Assert
result.IsSuccess.Should().BeTrue();
}
///
/// Verifies that changing vulnerability threshold only affects filtering.
///
[Fact]
public async Task ChangingVulnThreshold_OnlyAffectsFiltering()
{
// Arrange
var baselineConfig = new ScannerTestConfig { MinimumSeverity = "medium" };
var changedConfig = new ScannerTestConfig { MinimumSeverity = "critical" };
// Act
var result = await TestConfigIsolationAsync(
baselineConfig,
changedConfig,
changedSetting: "MinimumSeverity",
unrelatedBehaviors:
[
async config => await GetScanningBehaviorAsync(config),
async config => await GetSbomBehaviorAsync(config)
]);
// Assert
result.IsSuccess.Should().BeTrue(
because: "severity threshold should only affect output filtering");
}
// Helper methods
private static Task