Files
lmxopcua/tests/Server/ZB.MOM.WW.OtOpcUa.Admin.Tests/BootstrapVendoringTests.cs
Joseph Doherty 2b33b64a58 fix(admin): resolve Low code-review findings (Admin-010,011,012)
- Admin-010: vendor Bootstrap 5.3.3 (CSS + JS bundle + maps + provenance
  README) under wwwroot/lib/bootstrap and reference local paths from
  App.razor — Admin no longer pulls Bootstrap from jsDelivr.
- Admin-011: swap FleetStatusPoller's three plain dictionaries for
  ConcurrentDictionary so ResetCache can't race a poll tick.
- Admin-012: drop the EquipmentId column from EquipmentCsvImporter (per
  admin-ui.md — equipment id is system-derived from EquipmentUuid);
  EquipmentImportBatchService and the textarea placeholder updated to
  match.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 07:24:07 -04:00

65 lines
3.1 KiB
C#

using System.IO;
using System.Reflection;
using Shouldly;
using Xunit;
namespace ZB.MOM.WW.OtOpcUa.Admin.Tests;
/// <summary>
/// Regression for Admin-010 — admin-ui.md "Tech Stack" requires Bootstrap 5
/// "vendored under wwwroot/lib/bootstrap/" so the Admin app has no third-party
/// runtime dependency and works in air-gapped fleet deployments. These tests
/// guard against a future re-introduction of the cdn.jsdelivr.net references
/// in App.razor.
/// </summary>
[Trait("Category", "Unit")]
public sealed class BootstrapVendoringTests
{
[Fact]
public void AppRazor_does_not_reference_a_remote_CDN_for_bootstrap()
{
var appRazor = File.ReadAllText(ResolveAdminPath("Components/App.razor"));
appRazor.ShouldNotContain("cdn.jsdelivr.net",
customMessage: "Admin-010: Bootstrap must be served from the vendored copy under wwwroot/lib/bootstrap/, not jsDelivr — air-gapped deployments cannot reach the public CDN.");
appRazor.ShouldNotContain("cdnjs.cloudflare.com",
customMessage: "Admin-010: third-party CDN references regress the vendoring requirement.");
appRazor.ShouldNotContain("unpkg.com",
customMessage: "Admin-010: third-party CDN references regress the vendoring requirement.");
}
[Fact]
public void AppRazor_references_vendored_bootstrap_assets()
{
var appRazor = File.ReadAllText(ResolveAdminPath("Components/App.razor"));
appRazor.ShouldContain("lib/bootstrap/css/bootstrap.min.css",
customMessage: "App.razor must load the vendored Bootstrap stylesheet.");
appRazor.ShouldContain("lib/bootstrap/js/bootstrap.bundle.min.js",
customMessage: "App.razor must load the vendored Bootstrap JS bundle.");
}
[Fact]
public void Vendored_bootstrap_assets_exist_under_wwwroot_lib_bootstrap()
{
var root = ResolveAdminPath("wwwroot/lib/bootstrap");
Directory.Exists(root).ShouldBeTrue($"expected vendored bootstrap directory at '{root}'");
File.Exists(Path.Combine(root, "css", "bootstrap.min.css")).ShouldBeTrue("bootstrap.min.css missing");
File.Exists(Path.Combine(root, "js", "bootstrap.bundle.min.js")).ShouldBeTrue("bootstrap.bundle.min.js missing");
// Sanity-check non-empty (a zero-byte placeholder would still pass File.Exists).
new FileInfo(Path.Combine(root, "css", "bootstrap.min.css")).Length.ShouldBeGreaterThan(100_000);
new FileInfo(Path.Combine(root, "js", "bootstrap.bundle.min.js")).Length.ShouldBeGreaterThan(50_000);
}
/// <summary>Resolve a path under the Admin source project from the test runner's bin folder.</summary>
private static string ResolveAdminPath(string relative)
{
var asmDir = Path.GetDirectoryName(typeof(BootstrapVendoringTests).Assembly.Location)!;
// tests/Server/ZB.MOM.WW.OtOpcUa.Admin.Tests/bin/Debug/net10.0 -> ../../../../../src/Server/...
var repoRoot = Path.GetFullPath(Path.Combine(asmDir, "..", "..", "..", "..", "..", ".."));
return Path.Combine(repoRoot, "src", "Server", "ZB.MOM.WW.OtOpcUa.Admin", relative.Replace('/', Path.DirectorySeparatorChar));
}
}