mbproxy: close out the dashboard code-review minor findings
Resolves the remaining Minor items from the 2026-05-15 review so the web-UI dashboard work has no open follow-ups: a real-HubConnection end-to-end test for the SignalR feed, stable mbproxy.admin.broadcast.* log-event names, keyboard/aria accessibility on the fleet table, frontend JS hardening (URL-decode guard, NaN guards, shared util.js), reconciler<->capture-registry coverage, throwing-sink and embedded-asset tests, broadcaster polish, and a soft upper bound on AdminPushIntervalMs. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
using System.Reflection;
|
||||
using Mbproxy.Admin;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Mbproxy.Tests.Admin;
|
||||
|
||||
/// <summary>
|
||||
/// Guards the <c>Admin\wwwroot\*.*</c> embedded-resource glob in <c>Mbproxy.csproj</c>.
|
||||
/// A broken or narrowed glob would silently drop a UI asset from the single-file binary;
|
||||
/// the admin endpoint would then 404 it at runtime with no compile-time failure. This
|
||||
/// test fails the build instead by comparing the on-disk source folder against the
|
||||
/// assembly's manifest resources.
|
||||
/// </summary>
|
||||
[Trait("Category", "Unit")]
|
||||
public sealed class EmbeddedAssetsTests
|
||||
{
|
||||
private const string ResourcePrefix = "Mbproxy.Admin.wwwroot.";
|
||||
|
||||
[Fact]
|
||||
public void EveryWwwrootFile_IsEmbeddedAsAManifestResource()
|
||||
{
|
||||
var sourceDir = LocateWwwrootSource();
|
||||
var sourceFiles = Directory.GetFiles(sourceDir)
|
||||
.Select(Path.GetFileName)
|
||||
.Where(n => n is not null)
|
||||
.Select(n => n!)
|
||||
.ToArray();
|
||||
|
||||
sourceFiles.ShouldNotBeEmpty("the source wwwroot folder should contain UI assets");
|
||||
|
||||
var embedded = typeof(StatusHub).Assembly
|
||||
.GetManifestResourceNames()
|
||||
.Where(n => n.StartsWith(ResourcePrefix, StringComparison.Ordinal))
|
||||
.ToHashSet(StringComparer.Ordinal);
|
||||
|
||||
foreach (var file in sourceFiles)
|
||||
{
|
||||
embedded.ShouldContain(ResourcePrefix + file,
|
||||
$"wwwroot asset '{file}' is not embedded — check the EmbeddedResource glob in Mbproxy.csproj");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Walks up from the test assembly directory to the repo and returns
|
||||
/// <c>src/Mbproxy/Admin/wwwroot</c> — same upward-search pattern the simulator
|
||||
/// fixture uses to find <c>tests/sim</c>.
|
||||
/// </summary>
|
||||
private static string LocateWwwrootSource()
|
||||
{
|
||||
var dir = new DirectoryInfo(
|
||||
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? ".");
|
||||
while (dir is not null)
|
||||
{
|
||||
var candidate = Path.Combine(dir.FullName, "src", "Mbproxy", "Admin", "wwwroot");
|
||||
if (Directory.Exists(candidate))
|
||||
return candidate;
|
||||
dir = dir.Parent;
|
||||
}
|
||||
throw new DirectoryNotFoundException(
|
||||
"Could not locate src/Mbproxy/Admin/wwwroot above the test assembly.");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user