using System.Security.Claims; using Bunit; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Authorization; using Microsoft.AspNetCore.Components.Rendering; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; using NSubstitute; using ZB.MOM.WW.ScadaBridge.CentralUI.Components.Shared; using ZB.MOM.WW.ScadaBridge.Commons.Entities.Instances; using ZB.MOM.WW.ScadaBridge.Commons.Entities.Sites; using ZB.MOM.WW.ScadaBridge.Commons.Entities.Templates; using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Repositories; using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services; using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Transport; using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums; using ZB.MOM.WW.ScadaBridge.Communication; using ZB.MOM.WW.ScadaBridge.DeploymentManager; using ZB.MOM.WW.ScadaBridge.Security; using ZB.MOM.WW.ScadaBridge.TemplateEngine.Services; using TopologyPage = ZB.MOM.WW.ScadaBridge.CentralUI.Components.Pages.Deployment.Topology; namespace ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Deployment; /// /// Pins the verbs on the Topology instance-action confirmations (deferred-work /// register row 28): Disable must read "Disable", not the red button's /// historical "Delete" default, while a genuine Delete must still read "Delete". /// Like FailoverConfirmLabelTests these run the real /// behind a real DialogHost, so they pin what the user reads rather than /// the argument a substitute received. /// public class TopologyDisableConfirmLabelTests : BunitContext { private readonly ITemplateEngineRepository _repo = Substitute.For(); private readonly ISiteRepository _siteRepo = Substitute.For(); private readonly IDeploymentManagerRepository _deployRepo = Substitute.For(); private readonly IFlatteningPipeline _pipeline = Substitute.For(); private readonly IAuditService _audit = Substitute.For(); private readonly DialogService _dialog = new(); public TopologyDisableConfirmLabelTests() { Services.AddSingleton(_repo); Services.AddSingleton(_siteRepo); Services.AddSingleton(_deployRepo); Services.AddSingleton(_pipeline); Services.AddSingleton(_audit); // DeploymentService has non-mockable concrete deps; instantiate them directly // (the same DI block TopologyPageTests uses to render this page). Services.AddSingleton(new CommunicationService( Options.Create(new CommunicationOptions()), NullLogger.Instance)); Services.AddSingleton(new OperationLockManager()); Services.AddSingleton(Options.Create(new DeploymentManagerOptions { OperationLockTimeout = TimeSpan.FromSeconds(5) })); Services.AddSingleton(Options.Create(new CommunicationOptions())); Services.AddSingleton>(NullLogger.Instance); Services.AddScoped(); Services.AddScoped(); Services.AddSingleton( new DeploymentStatusNotifier(NullLogger.Instance)); Services.AddSingleton(Substitute.For()); Services.AddScoped(); Services.AddScoped(); Services.AddScoped(); Services.AddScoped(); // The concrete service registered as the interface, so the page and the // host share one instance (DialogHost injects IDialogService and casts). Services.AddSingleton(_dialog); var claims = new[] { new Claim(JwtTokenService.UsernameClaimType, "tester"), new Claim(JwtTokenService.RoleClaimType, Roles.Deployer) }; Services.AddSingleton( new TestAuthStateProvider(new ClaimsPrincipal(new ClaimsIdentity(claims, "TestAuth")))); Services.AddAuthorizationCore(); JSInterop.Mode = JSRuntimeMode.Loose; } /// One site with one enabled instance, so both Disable and Delete are offered. private void SeedOneEnabledInstance() { _siteRepo.GetAllSitesAsync(Arg.Any()) .Returns(Task.FromResult>( new List { new("Plant-A", "plant-a") { Id = 1 } })); _repo.GetAllTemplatesAsync(Arg.Any()) .Returns(Task.FromResult>(new List