using System; using System.Threading; using System.Threading.Tasks; using Shouldly; using Xunit; using ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Host.Backend; using ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Host.Backend.Galaxy; using ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Shared.Contracts; namespace ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Host.Tests { /// /// Live smoke against the Galaxy ZB repository. Skipped when ZB is unreachable so /// CI / dev boxes without an AVEVA install still pass. Exercises the ported /// + against the same /// SQL the v1 Host uses, proving the lift is byte-for-byte equivalent at the /// DiscoverHierarchyResponse shape. /// [Trait("Category", "LiveGalaxy")] public sealed class GalaxyRepositoryLiveSmokeTests { private static GalaxyRepositoryOptions DevZbOptions() => new() { ConnectionString = "Server=localhost;Database=ZB;Integrated Security=True;TrustServerCertificate=True;Encrypt=False;Connect Timeout=2;", CommandTimeoutSeconds = 10, }; private static async Task ZbReachableAsync() { try { var repo = new GalaxyRepository(DevZbOptions()); using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(3)); return await repo.TestConnectionAsync(cts.Token); } catch { return false; } } [Fact] public async Task TestConnection_returns_true_against_live_ZB() { if (!await ZbReachableAsync()) return; var repo = new GalaxyRepository(DevZbOptions()); (await repo.TestConnectionAsync()).ShouldBeTrue(); } [Fact] public async Task GetHierarchy_returns_at_least_one_deployed_gobject() { if (!await ZbReachableAsync()) return; var repo = new GalaxyRepository(DevZbOptions()); var rows = await repo.GetHierarchyAsync(); rows.Count.ShouldBeGreaterThan(0, "the dev Galaxy has at least the WinPlatform + AppEngine deployed"); rows.ShouldAllBe(r => !string.IsNullOrEmpty(r.TagName)); } [Fact] public async Task GetAttributes_returns_attributes_for_deployed_objects() { if (!await ZbReachableAsync()) return; var repo = new GalaxyRepository(DevZbOptions()); var attrs = await repo.GetAttributesAsync(); attrs.Count.ShouldBeGreaterThan(0); attrs.ShouldAllBe(a => !string.IsNullOrEmpty(a.FullTagReference) && a.FullTagReference.Contains(".")); } [Fact] public async Task GetLastDeployTime_returns_a_value() { if (!await ZbReachableAsync()) return; var repo = new GalaxyRepository(DevZbOptions()); var ts = await repo.GetLastDeployTimeAsync(); ts.ShouldNotBeNull(); } [Fact] public async Task DbBackedBackend_DiscoverAsync_returns_objects_with_attributes_and_categories() { if (!await ZbReachableAsync()) return; var backend = new DbBackedGalaxyBackend(new GalaxyRepository(DevZbOptions())); var resp = await backend.DiscoverAsync(new DiscoverHierarchyRequest { SessionId = 1 }, CancellationToken.None); resp.Success.ShouldBeTrue(resp.Error); resp.Objects.Length.ShouldBeGreaterThan(0); var firstWithAttrs = System.Linq.Enumerable.FirstOrDefault(resp.Objects, o => o.Attributes.Length > 0); firstWithAttrs.ShouldNotBeNull("at least one gobject in the dev Galaxy carries dynamic attributes"); firstWithAttrs!.TemplateCategory.ShouldNotBeNullOrEmpty(); } } }