fix(sql): Test Connect must construct Postgres and Oracle dialects too
SqlDriverProbe.DefaultDialectFor was left SqlServer-only when the provider gates were widened, so AdminUI Test Connect failed for both new providers with InvalidOperationException while Deploy and browse worked. Found by the live chrome/AdminUI gate the plan deferred, not by any test: every case in SqlDriverProbeTests builds its probe through ForTest(), which injects the dialect and never reaches the production switch. Widen the switch arm-for-arm with SqlDriverFactoryExtensions.CreateDialect, and cover the gate directly via an internal seam — plus a reserved-provider falsification control and an end-to-end production-constructor case.
This commit is contained in:
@@ -3,6 +3,7 @@ using System.Data.Common;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
|
||||
using ZB.MOM.WW.OtOpcUa.Driver.Sql.Contracts;
|
||||
|
||||
namespace ZB.MOM.WW.OtOpcUa.Driver.Sql.Tests;
|
||||
|
||||
@@ -125,6 +126,54 @@ public sealed class SqlDriverProbeTests
|
||||
result.Ok.ShouldBeFalse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <b>production</b> dialect gate — the one seam every other test in this file bypasses.
|
||||
/// <para>Each case above builds its probe with <see cref="SqlDriverProbe.ForTest"/>, which injects
|
||||
/// <c>_ => dialect</c> and therefore never reaches <c>DefaultDialectFor</c>. That is exactly how the
|
||||
/// probe kept a SqlServer-only gate while the factory and the browser were widened to Postgres +
|
||||
/// Oracle: the whole suite stayed green, and AdminUI "Test Connect" failed for two of the three
|
||||
/// shipped providers with <c>InvalidOperationException</c>. Caught by the live chrome/AdminUI gate,
|
||||
/// not by any test — so this asserts the gate directly.</para>
|
||||
/// </summary>
|
||||
[Theory]
|
||||
[InlineData(SqlProvider.SqlServer)]
|
||||
[InlineData(SqlProvider.Postgres)]
|
||||
[InlineData(SqlProvider.Oracle)]
|
||||
public void ProductionDialectGate_constructsEveryShippedProvider(SqlProvider provider)
|
||||
=> SqlDriverProbe.DefaultDialectForTest(provider).Provider.ShouldBe(provider);
|
||||
|
||||
/// <summary>
|
||||
/// The falsification control for the Theory above: the two <b>reserved</b> members must still be
|
||||
/// rejected. Without this, widening the gate to "return a dialect for anything" would pass.
|
||||
/// </summary>
|
||||
[Theory]
|
||||
[InlineData(SqlProvider.MySql)]
|
||||
[InlineData(SqlProvider.Odbc)]
|
||||
public void ProductionDialectGate_stillRejectsReservedProviders(SqlProvider provider)
|
||||
=> Should.Throw<InvalidOperationException>(() => SqlDriverProbe.DefaultDialectForTest(provider))
|
||||
.Message.ShouldContain(provider.ToString());
|
||||
|
||||
/// <summary>
|
||||
/// End-to-end through the <b>production constructor</b>: a Postgres config must get PAST dialect
|
||||
/// selection and fail at the connection attempt instead. Both outcomes are a red result whose message
|
||||
/// names only an exception type, so the type is the discriminator — with the SqlServer-only gate this
|
||||
/// is <c>InvalidOperationException</c> thrown before any socket is opened.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task ProductionProbe_postgresConfig_reachesTheConnectionAttempt_notTheProviderGate()
|
||||
{
|
||||
// Port 1 on the loopback: nothing listens, so the connect fails fast and locally — no fixture, no
|
||||
// network egress, and a failure that is the PROVIDER's, which is the point of the assertion.
|
||||
var name = SetRef("Host=127.0.0.1;Port=1;Database=x;Username=u;Password=p;Timeout=2");
|
||||
var result = await new SqlDriverProbe().ProbeAsync(
|
||||
$$"""{"provider":"Postgres","connectionStringRef":"{{name}}"}""",
|
||||
TimeSpan.FromSeconds(10), CancellationToken.None);
|
||||
|
||||
result.Ok.ShouldBeFalse();
|
||||
result.Message.ShouldNotBeNull();
|
||||
result.Message!.ShouldNotContain(nameof(InvalidOperationException));
|
||||
}
|
||||
|
||||
// ---- helpers ----
|
||||
|
||||
/// <summary>A config blob whose connectionStringRef resolves (for the life of the returned scope) to the
|
||||
|
||||
Reference in New Issue
Block a user