@@ -0,0 +1,61 @@
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
|
||||
|
||||
namespace ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests.Series;
|
||||
|
||||
/// <summary>
|
||||
/// Issue #271, plan PR F4-d — series-level (would-be integration) coverage of
|
||||
/// <c>cnc_wrunlockparam</c>. Hardware-gated: the FOCAS driver has no public
|
||||
/// simulator (task #222) so the live-controller cases require a real CNC with
|
||||
/// parameter-protect on. The CI lane for this assembly runs the unit-test fakes
|
||||
/// under <see cref="FocasUnlockTests"/>; this file is a scaffold that runs
|
||||
/// against a simulator + matching <c>mock_set_password</c> admin endpoint when
|
||||
/// <c>FOCAS_TRUST_WIRE=1</c>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Build-only today: the simulator gate (FOCAS_TRUST_WIRE) skips at runtime so
|
||||
/// CI doesn't need the simulator binary. When the simulator's
|
||||
/// <c>cnc_wrunlockparam</c> + <c>mock_set_password</c> endpoints land
|
||||
/// (<c>docs/v2/implementation/focas-simulator-plan.md</c>) the gated test
|
||||
/// becomes a real round-trip.
|
||||
/// </remarks>
|
||||
[Trait("Category", "Series")]
|
||||
public sealed class PasswordUnlockTests
|
||||
{
|
||||
[Fact]
|
||||
public void Single_unlock_retry_path_is_documented()
|
||||
{
|
||||
// Build-only scaffold — see FocasUnlockTests for the actual fake-backed
|
||||
// assertion. The integration version of this test (gated on a FOCAS
|
||||
// simulator with mock_set_password) will:
|
||||
// 1. Configure the simulator with password "1234".
|
||||
// 2. Spin up FocasDriver with FocasDeviceOptions.Password = "1234".
|
||||
// 3. Issue a cnc_wrparam against PARAM:1815 — expect Good (unlock applied
|
||||
// on connect).
|
||||
// 4. Use the simulator's admin endpoint to flip the password to "5678"
|
||||
// mid-session (forces EW_PASSWD on the next write).
|
||||
// 5. Issue another write — expect EW_PASSWD on attempt 1, then BadUserAccessDenied
|
||||
// surfaced because the new password doesn't match the cached one.
|
||||
// 6. Reconfigure FocasDeviceOptions.Password = "5678" on a new instance,
|
||||
// issue write — expect Good (unlock applied on first connect).
|
||||
// For now this test merely asserts the type contract; the simulator is
|
||||
// tracked under task #222 + the focas-simulator-plan.md document.
|
||||
typeof(IFocasClient).GetMethod(nameof(IFocasClient.UnlockAsync))
|
||||
.ShouldNotBeNull();
|
||||
// Driver-side records the password redaction invariant.
|
||||
var dev = new FocasDeviceOptions("focas://1.2.3.4:8193", Password: "1234");
|
||||
dev.ToString().ShouldNotContain("1234");
|
||||
}
|
||||
|
||||
[Fact(Skip = "Hardware-gated — requires the FOCAS simulator with cnc_wrunlockparam + mock_set_password endpoints (task #222 / focas-simulator-plan.md).")]
|
||||
public Task Live_simulator_unlock_retry_round_trip()
|
||||
{
|
||||
// Body deliberately empty — the [Skip] attribute keeps this off the CI lane.
|
||||
// When the simulator lands, this test materialises a FocasDriver pointed at
|
||||
// the simulator + drives the EW_PASSWD -> unlock -> retry path through real
|
||||
// wire calls. See <c>docs/v2/implementation/focas-simulator-plan.md</c>
|
||||
// § "FOCAS password unlock" for the simulator-side endpoints.
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user