Refactor code structure for improved readability and maintainability; optimize performance in key functions.
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
using System.Text.Json;
|
||||
using Json.Schema;
|
||||
using StellaOps.Testing.Manifests.Models;
|
||||
using StellaOps.Testing.Manifests.Serialization;
|
||||
|
||||
namespace StellaOps.Testing.Manifests.Validation;
|
||||
|
||||
/// <summary>
|
||||
/// Validates RunManifest instances against schema and invariants.
|
||||
/// </summary>
|
||||
public sealed class RunManifestValidator : IRunManifestValidator
|
||||
{
|
||||
private readonly JsonSchema _schema;
|
||||
|
||||
public RunManifestValidator()
|
||||
{
|
||||
var schemaJson = SchemaLoader.LoadSchema("run-manifest.schema.json");
|
||||
_schema = JsonSchema.FromText(schemaJson);
|
||||
}
|
||||
|
||||
public ValidationResult Validate(RunManifest manifest)
|
||||
{
|
||||
var errors = new List<ValidationError>();
|
||||
|
||||
var json = RunManifestSerializer.Serialize(manifest);
|
||||
var schemaResult = _schema.Evaluate(JsonDocument.Parse(json));
|
||||
if (!schemaResult.IsValid)
|
||||
{
|
||||
foreach (var error in schemaResult.Errors)
|
||||
{
|
||||
errors.Add(new ValidationError("Schema", error.Message));
|
||||
}
|
||||
}
|
||||
|
||||
if (manifest.ArtifactDigests.Length == 0)
|
||||
{
|
||||
errors.Add(new ValidationError("ArtifactDigests", "At least one artifact required"));
|
||||
}
|
||||
|
||||
if (manifest.FeedSnapshot.SnapshotAt > manifest.InitiatedAt)
|
||||
{
|
||||
errors.Add(new ValidationError("FeedSnapshot", "Feed snapshot cannot be after run initiation"));
|
||||
}
|
||||
|
||||
if (manifest.ManifestDigest is not null)
|
||||
{
|
||||
var computed = RunManifestSerializer.ComputeDigest(manifest);
|
||||
if (!string.Equals(computed, manifest.ManifestDigest, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
errors.Add(new ValidationError("ManifestDigest", "Digest mismatch"));
|
||||
}
|
||||
}
|
||||
|
||||
return new ValidationResult(errors.Count == 0, errors);
|
||||
}
|
||||
}
|
||||
|
||||
public interface IRunManifestValidator
|
||||
{
|
||||
ValidationResult Validate(RunManifest manifest);
|
||||
}
|
||||
|
||||
public sealed record ValidationResult(bool IsValid, IReadOnlyList<ValidationError> Errors);
|
||||
public sealed record ValidationError(string Field, string Message);
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.Reflection;
|
||||
|
||||
namespace StellaOps.Testing.Manifests.Validation;
|
||||
|
||||
internal static class SchemaLoader
|
||||
{
|
||||
public static string LoadSchema(string fileName)
|
||||
{
|
||||
var assembly = Assembly.GetExecutingAssembly();
|
||||
var resourceName = assembly.GetManifestResourceNames()
|
||||
.FirstOrDefault(name => name.EndsWith(fileName, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (resourceName is null)
|
||||
{
|
||||
throw new InvalidOperationException($"Schema resource not found: {fileName}");
|
||||
}
|
||||
|
||||
using var stream = assembly.GetManifestResourceStream(resourceName);
|
||||
if (stream is null)
|
||||
{
|
||||
throw new InvalidOperationException($"Schema resource not available: {resourceName}");
|
||||
}
|
||||
|
||||
using var reader = new StreamReader(stream);
|
||||
return reader.ReadToEnd();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user