Files
lmxopcua/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Browser.Tests/GalaxyDriverBrowserTests.cs
Joseph Doherty bd6c0b4d3d docs: complete XML doc comments via fixdocs (2757 to 131 findings)
Add missing <returns>/<param>/<summary>/<typeparam> tags and clean up
misused inheritdoc across 481 files so the documented API surface is
complete. Documentation-only (zero code lines changed). The 131 remaining
findings are inheritdoc-style warnings deliberately left to preserve
hand-written implementation rationale (plan-decision notes, race-condition
explanations).
2026-06-03 12:34:34 -04:00

59 lines
2.9 KiB
C#

using Shouldly;
using Xunit;
namespace ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Browser.Tests;
/// <summary>
/// Unit-only coverage of <see cref="GalaxyDriverBrowser"/>'s pre-connect validation.
/// These tests do not require a live mxaccessgw endpoint and are safe to run without
/// the gateway fixture — they exercise the JSON deserialization + validation paths
/// that run before <c>GalaxyRepositoryClient.Create</c> + <c>TestConnectionAsync</c>.
/// The factory's transport-construction path is covered by the integration suite
/// (Task 17) and manual smoke (Task 18) since both require a real gateway.
/// </summary>
[Trait("Category", "Unit")]
public sealed class GalaxyDriverBrowserTests
{
private readonly GalaxyDriverBrowser _sut = new();
/// <summary>The DriverType key must match the AdminUI's persisted "GalaxyMxGateway" value
/// so the factory wire-up picks the right browser implementation.</summary>
[Fact]
public void DriverType_is_GalaxyMxGateway() => _sut.DriverType.ShouldBe("GalaxyMxGateway");
/// <summary>An empty Gateway.Endpoint must fail fast with a clear, endpoint-mentioning
/// message rather than surfacing a downstream gRPC URI parse error.</summary>
/// <returns>A task that represents the asynchronous test operation.</returns>
[Fact]
public async Task OpenAsync_with_empty_endpoint_throws_InvalidOperationException()
{
var json = """{"Gateway":{"Endpoint":"","ApiKeySecretRef":"dev:k"},"MxAccess":{"ClientName":"X"},"Repository":{},"Reconnect":{}}""";
var ex = await Should.ThrowAsync<InvalidOperationException>(
() => _sut.OpenAsync(json, TestContext.Current.CancellationToken));
ex.Message.ShouldContain("Endpoint");
}
/// <summary>An empty MxAccess.ClientName must fail fast — refused so the gateway
/// side doesn't see anonymous browse sessions during triage.</summary>
/// <returns>A task that represents the asynchronous test operation.</returns>
[Fact]
public async Task OpenAsync_with_empty_clientName_throws_InvalidOperationException()
{
var json = """{"Gateway":{"Endpoint":"http://127.0.0.1:1","ApiKeySecretRef":"dev:k"},"MxAccess":{"ClientName":""},"Repository":{},"Reconnect":{}}""";
var ex = await Should.ThrowAsync<InvalidOperationException>(
() => _sut.OpenAsync(json, TestContext.Current.CancellationToken));
ex.Message.ShouldContain("ClientName");
}
/// <summary>A JSON literal that deserializes to null must fail fast with a
/// "deserialized to null" message — never a downstream NRE.</summary>
/// <returns>A task that represents the asynchronous test operation.</returns>
[Fact]
public async Task OpenAsync_with_null_json_throws_InvalidOperationException()
{
var ex = await Should.ThrowAsync<InvalidOperationException>(
() => _sut.OpenAsync("null", TestContext.Current.CancellationToken));
ex.Message.ShouldContain("null");
}
}