Files
natsdotnet/tests/NATS.Server.Tests/JetStreamApiGapInventoryTests.cs

89 lines
2.9 KiB
C#

using System.Diagnostics;
using System.Text.RegularExpressions;
namespace NATS.Server.Tests;
public class JetStreamApiGapInventoryTests
{
[Fact]
public void Parity_map_has_no_unclassified_go_js_api_subjects()
{
var gap = JetStreamApiGapInventory.Load();
gap.UnclassifiedSubjects.ShouldBeEmpty();
}
}
internal sealed class JetStreamApiGapInventory
{
public IReadOnlyList<string> UnclassifiedSubjects { get; }
private JetStreamApiGapInventory(IReadOnlyList<string> unclassifiedSubjects)
{
UnclassifiedSubjects = unclassifiedSubjects;
}
public static JetStreamApiGapInventory Load()
{
var goSubjects = LoadGoSubjects();
var mappedSubjects = LoadMappedSubjects();
var unclassified = goSubjects
.Where(s => !mappedSubjects.Contains(s))
.OrderBy(s => s, StringComparer.Ordinal)
.ToArray();
return new JetStreamApiGapInventory(unclassified);
}
private static HashSet<string> LoadGoSubjects()
{
var script = Path.Combine(AppContext.BaseDirectory, "../../../../../scripts/jetstream/extract-go-js-api.sh");
script = Path.GetFullPath(script);
if (!File.Exists(script))
throw new FileNotFoundException($"missing script: {script}");
var psi = new ProcessStartInfo
{
FileName = "bash",
RedirectStandardOutput = true,
RedirectStandardError = true,
};
psi.ArgumentList.Add(script);
using var process = Process.Start(psi) ?? throw new InvalidOperationException("failed to start inventory script");
var output = process.StandardOutput.ReadToEnd();
var errors = process.StandardError.ReadToEnd();
process.WaitForExit();
if (process.ExitCode != 0)
throw new InvalidOperationException($"inventory script failed: {errors}");
return output
.Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
.Where(x => x.StartsWith("$JS.API.", StringComparison.Ordinal))
.ToHashSet(StringComparer.Ordinal);
}
private static HashSet<string> LoadMappedSubjects()
{
var mapPath = Path.Combine(AppContext.BaseDirectory, "../../../../../docs/plans/2026-02-23-jetstream-remaining-parity-map.md");
mapPath = Path.GetFullPath(mapPath);
if (!File.Exists(mapPath))
throw new FileNotFoundException($"missing parity map: {mapPath}");
var subjectRegex = new Regex(@"^\|\s*(\$JS\.API[^\|]+?)\s*\|", RegexOptions.Compiled);
var subjects = new HashSet<string>(StringComparer.Ordinal);
foreach (var line in File.ReadLines(mapPath))
{
var match = subjectRegex.Match(line);
if (!match.Success)
continue;
subjects.Add(match.Groups[1].Value.Trim());
}
return subjects;
}
}