audit remarks work
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
<LangVersion>preview</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\FixtureUpdater\FixtureUpdater.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,142 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using StellaOps.Tools.FixtureUpdater;
|
||||
using Xunit;
|
||||
|
||||
public sealed class FixtureUpdaterRunnerTests
|
||||
{
|
||||
[Fact]
|
||||
public void Run_IsDeterministic_And_WritesGhsaFixtures()
|
||||
{
|
||||
var repoRoot = FindRepoRoot();
|
||||
using var temp = new TempDirectory();
|
||||
|
||||
var osvDir = Path.Combine(temp.Path, "osv");
|
||||
var ghsaDir = Path.Combine(temp.Path, "ghsa");
|
||||
var nvdDir = Path.Combine(temp.Path, "nvd");
|
||||
Directory.CreateDirectory(osvDir);
|
||||
Directory.CreateDirectory(ghsaDir);
|
||||
Directory.CreateDirectory(nvdDir);
|
||||
|
||||
File.Copy(
|
||||
Path.Combine(repoRoot, "src", "Concelier", "__Tests", "StellaOps.Concelier.Connector.Osv.Tests", "Fixtures", "osv-ghsa.raw-osv.json"),
|
||||
Path.Combine(osvDir, "osv-ghsa.raw-osv.json"));
|
||||
|
||||
File.Copy(
|
||||
Path.Combine(repoRoot, "src", "Concelier", "__Tests", "StellaOps.Concelier.Connector.Ghsa.Tests", "Fixtures", "osv-ghsa.raw-ghsa.json"),
|
||||
Path.Combine(ghsaDir, "osv-ghsa.raw-ghsa.json"));
|
||||
|
||||
var options = new FixtureUpdaterOptions(
|
||||
RepoRoot: null,
|
||||
OsvFixturesPath: osvDir,
|
||||
GhsaFixturesPath: ghsaDir,
|
||||
NvdFixturesPath: nvdDir,
|
||||
FixedTime: new DateTimeOffset(2025, 1, 1, 0, 0, 0, TimeSpan.Zero));
|
||||
|
||||
var firstResult = new FixtureUpdaterRunner(options).Run();
|
||||
Assert.Equal(0, firstResult.ErrorCount);
|
||||
|
||||
var firstOutputs = ReadOutputs(temp.Path);
|
||||
|
||||
var secondResult = new FixtureUpdaterRunner(options).Run();
|
||||
Assert.Equal(0, secondResult.ErrorCount);
|
||||
|
||||
var secondOutputs = ReadOutputs(temp.Path);
|
||||
Assert.Equal(firstOutputs.Count, secondOutputs.Count);
|
||||
foreach (var (path, content) in firstOutputs)
|
||||
{
|
||||
Assert.True(secondOutputs.TryGetValue(path, out var secondContent));
|
||||
Assert.Equal(content, secondContent);
|
||||
}
|
||||
|
||||
Assert.True(File.Exists(Path.Combine(ghsaDir, "osv-ghsa.ghsa.json")));
|
||||
Assert.False(File.Exists(Path.Combine(osvDir, "osv-ghsa.ghsa.json")));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Run_Reports_ParseErrors_With_Context()
|
||||
{
|
||||
var repoRoot = FindRepoRoot();
|
||||
using var temp = new TempDirectory();
|
||||
|
||||
var osvDir = Path.Combine(temp.Path, "osv");
|
||||
var ghsaDir = Path.Combine(temp.Path, "ghsa");
|
||||
var nvdDir = Path.Combine(temp.Path, "nvd");
|
||||
Directory.CreateDirectory(osvDir);
|
||||
Directory.CreateDirectory(ghsaDir);
|
||||
Directory.CreateDirectory(nvdDir);
|
||||
|
||||
File.Copy(
|
||||
Path.Combine(repoRoot, "src", "Concelier", "__Tests", "StellaOps.Concelier.Connector.Osv.Tests", "Fixtures", "osv-ghsa.raw-osv.json"),
|
||||
Path.Combine(osvDir, "osv-ghsa.raw-osv.json"));
|
||||
|
||||
File.WriteAllText(Path.Combine(ghsaDir, "osv-ghsa.raw-ghsa.json"), "{ broken json }");
|
||||
|
||||
var errors = new List<string>();
|
||||
var options = new FixtureUpdaterOptions(
|
||||
RepoRoot: null,
|
||||
OsvFixturesPath: osvDir,
|
||||
GhsaFixturesPath: ghsaDir,
|
||||
NvdFixturesPath: nvdDir,
|
||||
FixedTime: new DateTimeOffset(2025, 1, 1, 0, 0, 0, TimeSpan.Zero));
|
||||
|
||||
var result = new FixtureUpdaterRunner(options, _ => { }, message => errors.Add(message)).Run();
|
||||
Assert.True(result.ErrorCount > 0);
|
||||
Assert.Contains(errors, message => message.Contains("osv-ghsa.raw-ghsa.json", StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
private static Dictionary<string, string> ReadOutputs(string root)
|
||||
{
|
||||
var files = Directory.GetFiles(root, "*.json", SearchOption.AllDirectories)
|
||||
.OrderBy(path => path, StringComparer.Ordinal)
|
||||
.ToArray();
|
||||
|
||||
var outputs = new Dictionary<string, string>(StringComparer.Ordinal);
|
||||
foreach (var file in files)
|
||||
{
|
||||
var relative = Path.GetRelativePath(root, file);
|
||||
var content = File.ReadAllText(file).ReplaceLineEndings("\n");
|
||||
outputs[relative] = content;
|
||||
}
|
||||
|
||||
return outputs;
|
||||
}
|
||||
|
||||
private static string FindRepoRoot()
|
||||
{
|
||||
var current = new DirectoryInfo(AppContext.BaseDirectory);
|
||||
while (current is not null)
|
||||
{
|
||||
var solution = Path.Combine(current.FullName, "src", "StellaOps.sln");
|
||||
if (File.Exists(solution))
|
||||
{
|
||||
return current.FullName;
|
||||
}
|
||||
|
||||
current = current.Parent;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Repository root not found.");
|
||||
}
|
||||
|
||||
private sealed class TempDirectory : IDisposable
|
||||
{
|
||||
public TempDirectory()
|
||||
{
|
||||
Path = System.IO.Path.Combine(System.IO.Path.GetTempPath(), $"fixture-updater-{Guid.NewGuid():N}");
|
||||
Directory.CreateDirectory(Path);
|
||||
}
|
||||
|
||||
public string Path { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (Directory.Exists(Path))
|
||||
{
|
||||
Directory.Delete(Path, recursive: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
<LangVersion>preview</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\LanguageAnalyzerSmoke\LanguageAnalyzerSmoke.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,76 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using StellaOps.Tools.LanguageAnalyzerSmoke;
|
||||
using Xunit;
|
||||
|
||||
public sealed class LanguageAnalyzerSmokeRunnerTests
|
||||
{
|
||||
[Fact]
|
||||
public void Resolve_UsesProfileDefaults_WhenOverridesMissing()
|
||||
{
|
||||
var profile = AnalyzerProfileCatalog.GetProfile("python");
|
||||
var options = SmokeOptions.Resolve(
|
||||
repoRoot: "C:\\repo",
|
||||
analyzerId: "python",
|
||||
pluginDirectoryName: null,
|
||||
fixtureRelativePath: null,
|
||||
allowGoldenDrift: false,
|
||||
fixedTime: new DateTimeOffset(2025, 1, 1, 0, 0, 0, TimeSpan.Zero),
|
||||
useSystemTime: false,
|
||||
timeoutSeconds: 120);
|
||||
|
||||
Assert.Equal(profile.PluginDirectory, options.PluginDirectoryName);
|
||||
Assert.Equal(profile.FixtureRelativePath, options.FixtureRelativePath);
|
||||
Assert.Equal(profile.AnalyzerId, options.AnalyzerId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidateManifest_RejectsMissingCapabilities()
|
||||
{
|
||||
var profile = AnalyzerProfileCatalog.GetProfile("python");
|
||||
var manifest = new PluginManifest
|
||||
{
|
||||
SchemaVersion = "1.0",
|
||||
Id = profile.ExpectedPluginId,
|
||||
RequiresRestart = true,
|
||||
EntryPoint = new PluginEntryPoint
|
||||
{
|
||||
Type = "dotnet",
|
||||
TypeName = profile.ExpectedEntryPointType,
|
||||
Assembly = "Plugin.dll"
|
||||
},
|
||||
Capabilities = Array.Empty<string>()
|
||||
};
|
||||
|
||||
var exception = Assert.Throws<InvalidOperationException>(() =>
|
||||
LanguageAnalyzerSmokeRunner.ValidateManifest(manifest, profile, profile.PluginDirectory));
|
||||
Assert.Contains("capability", exception.Message, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CompareGoldenSnapshot_Throws_WhenDriftNotAllowed()
|
||||
{
|
||||
Assert.Throws<InvalidOperationException>(() =>
|
||||
LanguageAnalyzerSmokeRunner.CompareGoldenSnapshot(
|
||||
scenarioName: "sample",
|
||||
actualJson: "{\"a\":1}",
|
||||
goldenNormalized: "{\"a\":2}",
|
||||
allowGoldenDrift: false,
|
||||
info: _ => { }));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CompareGoldenSnapshot_AllowsWhenDriftAllowed()
|
||||
{
|
||||
var warnings = new List<string>();
|
||||
LanguageAnalyzerSmokeRunner.CompareGoldenSnapshot(
|
||||
scenarioName: "sample",
|
||||
actualJson: "{\"a\":1}",
|
||||
goldenNormalized: "{\"a\":2}",
|
||||
allowGoldenDrift: true,
|
||||
info: message => warnings.Add(message));
|
||||
|
||||
Assert.Single(warnings);
|
||||
Assert.Contains("golden", warnings[0], StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
<LangVersion>preview</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\NotifySmokeCheck\NotifySmokeCheck.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using StackExchange.Redis;
|
||||
using StellaOps.Tools.NotifySmokeCheck;
|
||||
using Xunit;
|
||||
|
||||
public sealed class NotifySmokeCheckRunnerTests
|
||||
{
|
||||
[Fact]
|
||||
public void FromEnvironment_ParsesExpectedKinds()
|
||||
{
|
||||
var env = new Dictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
["NOTIFY_SMOKE_REDIS_DSN"] = "localhost:6379",
|
||||
["NOTIFY_SMOKE_EXPECT_KINDS"] = "scan, scan, Alert",
|
||||
["NOTIFY_SMOKE_LOOKBACK_MINUTES"] = "15",
|
||||
["NOTIFY_SMOKE_NOTIFY_BASEURL"] = "https://notify.local",
|
||||
["NOTIFY_SMOKE_NOTIFY_TOKEN"] = "token",
|
||||
["NOTIFY_SMOKE_NOTIFY_TENANT"] = "tenant"
|
||||
};
|
||||
|
||||
var options = NotifySmokeOptions.FromEnvironment(name => env.TryGetValue(name, out var value) ? value : null);
|
||||
|
||||
Assert.Equal(new[] { "scan", "alert" }, options.ExpectedKinds);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FromEnvironment_UsesFixedTimeWhenProvided()
|
||||
{
|
||||
var env = new Dictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
["NOTIFY_SMOKE_REDIS_DSN"] = "localhost:6379",
|
||||
["NOTIFY_SMOKE_EXPECT_KINDS"] = "scan",
|
||||
["NOTIFY_SMOKE_LOOKBACK_MINUTES"] = "5",
|
||||
["NOTIFY_SMOKE_NOTIFY_BASEURL"] = "https://notify.local",
|
||||
["NOTIFY_SMOKE_NOTIFY_TOKEN"] = "token",
|
||||
["NOTIFY_SMOKE_NOTIFY_TENANT"] = "tenant",
|
||||
["NOTIFY_SMOKE_FIXED_TIME"] = "2025-01-02T03:04:05Z"
|
||||
};
|
||||
|
||||
var options = NotifySmokeOptions.FromEnvironment(name => env.TryGetValue(name, out var value) ? value : null);
|
||||
Assert.Equal(new DateTimeOffset(2025, 1, 2, 3, 4, 5, TimeSpan.Zero), options.TimeProvider.GetUtcNow());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ParseDeliveries_HandlesItemsArray()
|
||||
{
|
||||
var json = "{\"items\":[{\"kind\":\"scan\",\"status\":\"delivered\"},{\"kind\":\"vex\",\"status\":\"failed\"}]}";
|
||||
var deliveries = NotifySmokeCheckRunner.ParseDeliveries(json);
|
||||
|
||||
Assert.Equal(2, deliveries.Count);
|
||||
Assert.Equal("scan", deliveries[0].Kind, StringComparer.OrdinalIgnoreCase);
|
||||
Assert.Equal("delivered", deliveries[0].Status, StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryGetStreamTimestamp_ParsesEntryId()
|
||||
{
|
||||
var entry = new StreamEntry("1700000000000-0", Array.Empty<NameValueEntry>());
|
||||
|
||||
var success = NotifySmokeCheckRunner.TryGetStreamTimestamp(entry, out var timestamp);
|
||||
|
||||
Assert.True(success);
|
||||
Assert.Equal(DateTimeOffset.FromUnixTimeMilliseconds(1700000000000), timestamp);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
<LangVersion>preview</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\PolicyDslValidator\PolicyDslValidator.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,44 @@
|
||||
using StellaOps.Policy;
|
||||
using StellaOps.Policy.Tools;
|
||||
|
||||
public sealed class PolicyDslValidatorAppTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task RunAsync_ReturnsUsageExitCode_OnMissingInputs()
|
||||
{
|
||||
var runner = new CapturingRunner();
|
||||
|
||||
var exitCode = await PolicyDslValidatorApp.RunAsync(Array.Empty<string>(), runner);
|
||||
|
||||
Assert.Equal(64, exitCode);
|
||||
Assert.False(runner.WasCalled);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Command_CapturesStrictAndJson()
|
||||
{
|
||||
var runner = new CapturingRunner();
|
||||
var exitCode = await PolicyDslValidatorApp.RunAsync(new[] { "--strict", "--json", "policy.json" }, runner);
|
||||
|
||||
Assert.Equal(0, exitCode);
|
||||
Assert.True(runner.WasCalled);
|
||||
Assert.NotNull(runner.CapturedOptions);
|
||||
Assert.True(runner.CapturedOptions!.Strict);
|
||||
Assert.True(runner.CapturedOptions!.OutputJson);
|
||||
Assert.Single(runner.CapturedOptions!.Inputs);
|
||||
Assert.Equal("policy.json", runner.CapturedOptions!.Inputs[0]);
|
||||
}
|
||||
|
||||
private sealed class CapturingRunner : IPolicyValidationRunner
|
||||
{
|
||||
public PolicyValidationCliOptions? CapturedOptions { get; private set; }
|
||||
public bool WasCalled { get; private set; }
|
||||
|
||||
public Task<int> RunAsync(PolicyValidationCliOptions options, CancellationToken cancellationToken)
|
||||
{
|
||||
CapturedOptions = options;
|
||||
WasCalled = true;
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
<LangVersion>preview</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\PolicySchemaExporter\PolicySchemaExporter.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,46 @@
|
||||
using System.IO;
|
||||
using StellaOps.Policy.Tools;
|
||||
|
||||
public sealed class PolicySchemaExporterTests
|
||||
{
|
||||
[Fact]
|
||||
public void GenerateSchemas_IsStableAndHasExpectedNames()
|
||||
{
|
||||
var exports = PolicySchemaExporterSchema.BuildExports();
|
||||
|
||||
var first = PolicySchemaExporterSchema.GenerateSchemas(
|
||||
PolicySchemaExporterSchema.CreateGenerator(),
|
||||
exports);
|
||||
var second = PolicySchemaExporterSchema.GenerateSchemas(
|
||||
PolicySchemaExporterSchema.CreateGenerator(),
|
||||
exports);
|
||||
|
||||
Assert.Equal(exports.Length, first.Count);
|
||||
foreach (var export in exports)
|
||||
{
|
||||
Assert.True(first.ContainsKey(export.FileName));
|
||||
Assert.True(second.ContainsKey(export.FileName));
|
||||
Assert.Equal(first[export.FileName], second[export.FileName]);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ResolveOutputDirectory_UsesRepoRootForRelativeOutput()
|
||||
{
|
||||
var repoRoot = Path.Combine(Path.GetTempPath(), "schema-exporter");
|
||||
var resolved = PolicySchemaExporterPaths.ResolveOutputDirectory("out", repoRoot);
|
||||
var expected = Path.GetFullPath(Path.Combine(repoRoot, "out"));
|
||||
|
||||
Assert.Equal(expected, resolved);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ResolveDefaultOutputDirectory_UsesRepoRootDocsSchemas()
|
||||
{
|
||||
var repoRoot = Path.Combine(Path.GetTempPath(), "schema-exporter-root");
|
||||
var resolved = PolicySchemaExporterPaths.ResolveDefaultOutputDirectory(repoRoot);
|
||||
var expected = Path.GetFullPath(Path.Combine(repoRoot, "docs", "schemas"));
|
||||
|
||||
Assert.Equal(expected, resolved);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
<LangVersion>preview</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\PolicySimulationSmoke\PolicySimulationSmoke.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,67 @@
|
||||
using System.Collections.Immutable;
|
||||
using StellaOps.Policy;
|
||||
using StellaOps.Policy.Tools;
|
||||
|
||||
public sealed class PolicySimulationSmokeEvaluatorTests
|
||||
{
|
||||
[Fact]
|
||||
public void EvaluateScenario_FailsWhenPreviewFails()
|
||||
{
|
||||
var scenario = new PolicySimulationScenario { Name = "demo" };
|
||||
var response = new PolicyPreviewResponse(
|
||||
Success: false,
|
||||
PolicyDigest: "digest",
|
||||
RevisionId: null,
|
||||
Issues: ImmutableArray<PolicyIssue>.Empty,
|
||||
Diffs: ImmutableArray<PolicyVerdictDiff>.Empty,
|
||||
ChangedCount: 0);
|
||||
|
||||
var result = PolicySimulationSmokeEvaluator.EvaluateScenario(scenario, response);
|
||||
|
||||
Assert.False(result.Success);
|
||||
Assert.Contains("Preview failed.", result.Failures);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EvaluateScenario_FailsWhenExpectedDiffMissing()
|
||||
{
|
||||
var scenario = new PolicySimulationScenario
|
||||
{
|
||||
Name = "demo",
|
||||
ExpectedDiffs = new List<ScenarioExpectedDiff>
|
||||
{
|
||||
new ScenarioExpectedDiff { FindingId = "F-1", Status = "Blocked" }
|
||||
}
|
||||
};
|
||||
|
||||
var baseline = new PolicyVerdict("F-2", PolicyVerdictStatus.Pass);
|
||||
var projected = new PolicyVerdict("F-2", PolicyVerdictStatus.Pass);
|
||||
var diff = new PolicyVerdictDiff(baseline, projected);
|
||||
|
||||
var response = new PolicyPreviewResponse(
|
||||
Success: true,
|
||||
PolicyDigest: "digest",
|
||||
RevisionId: null,
|
||||
Issues: ImmutableArray<PolicyIssue>.Empty,
|
||||
Diffs: ImmutableArray.Create(diff),
|
||||
ChangedCount: 1);
|
||||
|
||||
var result = PolicySimulationSmokeEvaluator.EvaluateScenario(scenario, response);
|
||||
|
||||
Assert.False(result.Success);
|
||||
Assert.Contains("Expected finding 'F-1' missing from diff.", result.Failures);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RunAsync_ReturnsNoInputWhenScenarioRootMissing()
|
||||
{
|
||||
var runner = new PolicySimulationSmokeRunner();
|
||||
var missingRoot = Path.Combine(Path.GetTempPath(), "stellaops-missing-" + Guid.NewGuid().ToString("N"));
|
||||
|
||||
var exitCode = await runner.RunAsync(
|
||||
new PolicySimulationSmokeOptions { ScenarioRoot = missingRoot },
|
||||
CancellationToken.None);
|
||||
|
||||
Assert.Equal(66, exitCode);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
<LangVersion>preview</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\RustFsMigrator\RustFsMigrator.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using Xunit;
|
||||
|
||||
public sealed class RustFsMigratorTests
|
||||
{
|
||||
[Fact]
|
||||
public void Parse_ExtractsRetryAndTimeoutOptions()
|
||||
{
|
||||
var options = MigrationOptions.Parse(new[]
|
||||
{
|
||||
"--s3-bucket", "bucket",
|
||||
"--rustfs-endpoint", "http://rustfs:8080",
|
||||
"--rustfs-bucket", "target",
|
||||
"--retry-attempts", "5",
|
||||
"--retry-delay-ms", "500",
|
||||
"--timeout-seconds", "60",
|
||||
"--retain-days", "1.5"
|
||||
});
|
||||
|
||||
Assert.NotNull(options);
|
||||
Assert.Equal(5, options!.RetryAttempts);
|
||||
Assert.Equal(500, options.RetryDelayMs);
|
||||
Assert.Equal(60, options.TimeoutSeconds);
|
||||
Assert.NotNull(options.RetentionSeconds);
|
||||
Assert.True(options.RetentionSeconds > 0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildRustFsUri_EncodesObjectKey()
|
||||
{
|
||||
var options = new MigrationOptions
|
||||
{
|
||||
RustFsEndpoint = "https://rustfs.local",
|
||||
RustFsBucket = "scanner artifacts"
|
||||
};
|
||||
|
||||
var uri = RustFsMigratorPaths.BuildRustFsUri(options, "path/with space/file.txt");
|
||||
Assert.Equal("https", uri.Scheme);
|
||||
Assert.Contains("scanner%20artifacts", uri.AbsoluteUri, StringComparison.Ordinal);
|
||||
Assert.Contains("path/with%20space/file.txt", uri.AbsoluteUri, StringComparison.Ordinal);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user