Phase 3 PR 36 — AVEVA prerequisites test-support library #35
Reference in New Issue
Block a user
Delete Branch "phase-3-pr36-aveva-prerequisites"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes the gap where live-Galaxy smoke tests silently returned 'unreachable' without telling operators which specific piece failed. Adds a new multi-targeted test-support library (
net10.0+net48so both modern and MXAccess-COM x86 consumers can reference it) exposingAvevaPrerequisites.CheckAllAsync/CheckRepositoryOnlyAsync/CheckGalaxyHostPipeOnlyAsync.Eight probe categories
EnvironmentAvevaInstallHKLM\SOFTWARE\WOW6432Node\ArchestrA\Frameworkregistry keys, deployed-Platform marker, pending-reboot flag.AvevaCoreServiceaaBootstrap+aaGR+NmxSvc+MSSQLSERVER— hard fail if missing.AvevaSoftServiceaaLogger+aaUserValidator+aaGlobalDataCacheMonitorSvr— warn only.MxAccessComLMXProxy.LMXProxyServerProgID → CLSID → 32-bitInprocServer32file-on-disk.GalaxyRepositoryAvevaHistorianaahClientAccessPoint+aahGateway— opt-in, only matters for HistoryRead.OtOpcUaServiceOtOpcUaGalaxyHost+OtOpcUa+GLAuth+ optional named-pipe probe.Each check returns a
PrerequisiteCheckrecord:Name(service:aaBootstrap,com:LMXProxy, …),Category,Status(Pass/Warn/Fail/Skip), and operator-facingDetail.Report surface
IsLivetestReady— no Fail anywhere.IsAvevaSideReady— AVEVA categories clean, lets v2 services be absent while still considering the environment AVEVA-ready (important while the v2 stack is mid-development).SkipReason— multi-line message forAssert.Skipwhen any hard dependency failed; lists every Fail with its operator-actionable detail.Warnings— separate text for Warn rows (degraded but not blocking).RequireCategories(...)— throws when specific categories fail; lets a test be strict about what it needs.Probe details worth flagging
DemandStart+Stoppedas Warn (NmxSvc is DemandStart by design). AutoStart+Stopped = Fail. Not-installed = Fail for hard-required, Warn for soft.PfeConfigOptionswithPlatformId=0means never deployed → surfaces the 'MXAccess will connect but every subscription is Bad quality' case that would otherwise debug-fail opaquely.RebootRequiredpost-patch surfaces as a loud warn.InprocServer32file, catches orphan-registry installs where the DLL was removed but the registry entry remains. Also warns when the test process is 64-bit (explains REGDB_E_CLASSNOTREG in advance).SQL unreachable(can't connect) fromZB missing(SELECT DB_ID('ZB')returns null) because remediation differs. Countsgobject WHERE deployed_version > 0as a secondary warn-on-zero signal.NamedPipeClientStream.ConnectAsyncagainstOtOpcUaGalaxy; disconnects immediately so we don't consume a session slot.Multi-targeting
net48 gets
System.ServiceProcess+Microsoft.Win32in-box via BCL references; net10 gets the NuGet packages. Microsoft.Data.SqlClient v6 supports both.Net48Polyfills.csprovidesIsExternalInit(records) +SupportedOSPlatformAttributestub so the same sources compile on both frameworks with no per-callsite preprocessor guards.Tests
AvevaPrerequisitesLiveTests(8 newCategory=LiveGalaxycases inGalaxy.Host.Tests) exercises the helper against this live dev box:IsAvevaSideReady == trueeven when our v2 services aren't installed (dev-box in-progress state).OtOpcUaGalaxyHost+OtOpcUa+GLAutheven when not installed — regression guard so nobody can silently drop our own services from the check.GalaxyRepositoryLiveSmokeTestsupdated to delegate its skip decision toAvevaPrerequisites.CheckRepositoryOnlyAsync(legacyZbReachableAsynckept as a compat adapter while surrounding fixtures migrate toAssert.Skip-with-reason).Test posture
What's next
The end-to-end live-Galaxy stack smoke (Proxy → Host pipe → MXAccess → real Galaxy tag) is the next PR. It'll call
AvevaPrerequisites.CheckAllAsyncat fixture construction andAssert.Skip(report.SkipReason)when the environment isn't ready — replacing 'silent return' with actionable diagnostics.AvevaPrerequisites.CheckAllAsync walks eight probe categories producing PrerequisiteCheck rows each with Name (e.g. 'service:aaBootstrap', 'sql:ZB', 'com:LMXProxy', 'registry:ArchestrA.Framework'), Category (AvevaCoreService / AvevaSoftService / AvevaInstall / MxAccessCom / GalaxyRepository / AvevaHistorian / OtOpcUaService / Environment), Status (Pass / Warn / Fail / Skip), and operator-facing Detail message. Report aggregates them: IsLivetestReady (no Fails anywhere) and IsAvevaSideReady (AVEVA-side categories pass, our v2 services can be absent while still considering the environment AVEVA-ready) so different test tiers can use the right threshold. Individual probes: ServiceProbe.Check queries the Windows Service Control Manager via System.ServiceProcess.ServiceController — treats DemandStart+Stopped as Warn (NmxSvc is DemandStart by design; master pulls it up) but AutoStart+Stopped as Fail; not-installed is Fail for hard-required services, Warn for soft ones; non-Windows hosts get Skip; transitional states like StartPending get Warn with a 'try again' hint. RegistryProbe reads HKLM\SOFTWARE\WOW6432Node\ArchestrA\{Framework,Framework\Platform,MSIInstall} — Framework key presence + populated InstallPath/RootPath values mean System Platform installed; PfeConfigOptions in the Platform subkey (format 'PlatformId=N,EngineId=N,...') indicates a Platform has been deployed from the IDE (PlatformId=0 means never deployed — MXAccess will connect but every subscription will be Bad quality); RebootRequired='True' under MSIInstall surfaces as a loud warn since post-patch behavior is undefined. MxAccessComProbe resolves the LMXProxy.LMXProxyServer ProgID → CLSID → HKLM\SOFTWARE\Classes\WOW6432Node\CLSID\{guid}\InprocServer32, verifying the registered file exists on disk (catches the orphan-registry case where a previous uninstall left the ProgID registered but the DLL is gone — distinguishes it from the 'totally not installed' case by message); also emits a Warn when the test process is 64-bit (MXAccess COM activation fails with REGDB_E_CLASSNOTREG 0x80040154 regardless of registration, so seeing this warning tells operators why the activation would fail even on a fully-installed machine). SqlProbe tests Galaxy Repository via Microsoft.Data.SqlClient using the Windows-auth localhost connection string the repo code defaults to — distinguishes 'SQL Server unreachable' (connection fails) from 'ZB database does not exist' (SELECT DB_ID('ZB') returns null) because they have different remediation paths (sc.exe start MSSQLSERVER vs. restore from .cab backup); a secondary CheckDeployedObjectCountAsync query on 'gobject WHERE deployed_version > 0' warns when the count is zero because discovery smoke tests will return empty hierarchies. NamedPipeProbe opens a 2s NamedPipeClientStream against OtOpcUaGalaxyHost's pipe ('OtOpcUaGalaxy' per the installer default) — pipe accepting a connection proves the Host service is listening; disconnects immediately so we don't consume a session slot. Service lists kept as internal static data so tests can inspect + override: CoreServices (aaBootstrap + aaGR + NmxSvc + MSSQLSERVER — hard fail if missing), SoftServices (aaLogger + aaUserValidator + aaGlobalDataCacheMonitorSvr — warn only; stack runs without them but diagnostics/auth are degraded), HistorianServices (aahClientAccessPoint + aahGateway — opt-in via Options.CheckHistorian, only matters for HistoryRead IPC paths), OtOpcUaServices (our OtOpcUaGalaxyHost hard-required for end-to-end live tests + OtOpcUa warn + GLAuth warn). Narrower entry points CheckRepositoryOnlyAsync and CheckGalaxyHostPipeOnlyAsync for tests that only care about specific subsystems — avoid paying the full probe cost on every GalaxyRepositoryLiveSmokeTests fact. Multi-targeting mechanics: System.ServiceProcess.ServiceController + Microsoft.Win32.Registry are NuGet packages on net10 but in-box BCL references on net48; csproj conditions Package vs Reference by TargetFramework. Microsoft.Data.SqlClient v6 supports both frameworks so single PackageReference. Net48Polyfills.cs provides IsExternalInit shim (records/init-only setters) and SupportedOSPlatformAttribute stub so the same Probe sources compile on both frameworks without per-callsite preprocessor guards — lets Roslyn's platform-compatibility analyzer stay useful on net10 without breaking net48 builds. Existing GalaxyRepositoryLiveSmokeTests updated to delegate its skip decision to AvevaPrerequisites.CheckRepositoryOnlyAsync (legacy ZbReachableAsync kept as a compatibility adapter so the in-test 'if (!await ZbReachableAsync()) return;' pattern keeps working while the surrounding fixtures gradually migrate to Assert.Skip-with-reason). Slnx file registers the new project. Tests — AvevaPrerequisitesLiveTests (8 new Integration cases, Category=LiveGalaxy): the helper correctly reports Framework install (registry pass), aaBootstrap Running (service pass), aaGR Running (service pass), MxAccess COM registered (com pass), ZB database reachable (sql pass), deployed-object count > 0 (warn-upgraded-to-pass because this box has 49 objects deployed), the AVEVA side is ready even when our own services (OtOpcUaGalaxyHost) aren't installed yet (IsAvevaSideReady=true), and the helper emits rows for OtOpcUaGalaxyHost + OtOpcUa + GLAuth even when not installed (regression guard — nobody can accidentally ship a check that omits our own services). Full Galaxy.Host.Tests Category=LiveGalaxy suite: 13 pass (5 prior smoke + 8 new prerequisites). Full solution build clean, 0 errors. What's NOT in this PR: end-to-end Galaxy stack smoke (Proxy → Host pipe → MXAccess → real Galaxy tag). That's the next PR — this one is the gate the end-to-end smoke will call first to produce actionable skip messages instead of silent returns. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>