feat(adminui): author MTConnect write-back on the driver form (Driver.MTConnect-004)

IWritable shipped behind write.enabled and docs/drivers/MTConnect.md told the operator to
set it, but MTConnectDriverForm — the only editor DriverFormMaps maps for this type, with
no raw-JSON escape hatch and no driver-instance API — exposed no write section, so the
documented enablement path was a hand edit of DriverInstance.DriverConfig in the config DB.

- Write-back section: switch + form text stating it is observation injection, that the
  Agent's AllowPut is an independent second gate, and that it does not by itself make a
  node writable over OPC UA (Tag.AccessLevel still composes CurrentWrite).
- Write added to the mirrored MTConnectConfigDto and to the form model, written in BOTH
  states — an omitted block would leave a previously-authored true standing, so the switch
  could never turn writing off again.
- The false 'MTConnect is read-only' header comment is gone; the doc names the new section.

No bUnit here, so the model/serialization seam is unit-tested both sides: the AdminUI test
pins the emitted bytes, and MTConnectFactoryTests parses that same document and asserts
MTConnectDriverOptions.Write.Enabled. Live page verification remains a rig step.
This commit is contained in:
Joseph Doherty
2026-08-10 08:07:36 -04:00
parent 2d7dffcc42
commit 298ad04fba
4 changed files with 182 additions and 4 deletions
@@ -382,6 +382,33 @@ public sealed class MTConnectFactoryTests
.DriverInstanceId.ShouldBe("mt1");
}
/// <summary>
/// Driver.MTConnect-004: the document the AdminUI's <c>MTConnectDriverForm</c> emits arms
/// write-back through this parse. The literal below is the form's own output for a
/// write-enabled instance — key spelling, casing and block nesting included — since the
/// AdminUI cannot be referenced from a driver test project; the form side of the same
/// contract is pinned by <c>MTConnectDriverFormModelTests</c>, which asserts these exact
/// keys come out of <c>BuildConfigJson</c>.
/// </summary>
[Fact]
public void The_document_the_AdminUI_form_emits_arms_write_back()
{
const string formEmitted =
"""{"agentUri":"http://agent:5000","requestTimeoutMs":5000,"sampleIntervalMs":1000,"sampleCount":1000,"heartbeatMs":10000,"probe":{"enabled":true,"intervalMs":5000,"timeoutMs":2000},"reconnect":{"minBackoffMs":0,"maxBackoffMs":30000,"backoffMultiplier":2},"write":{"enabled":true}}""";
var options = MTConnectDriver.ParseOptions("mt1", formEmitted);
options.Write.Enabled.ShouldBeTrue();
options.AgentUri.ShouldBe("http://agent:5000");
// The same document with the switch off is read-only again — the form writes the block in
// both states, so this is the round trip an operator turning the feature back off performs.
MTConnectDriver.ParseOptions(
"mt1",
formEmitted.Replace("""enabled":true}""", """enabled":false}""", StringComparison.Ordinal))
.Write.Enabled.ShouldBeFalse();
}
/// <summary>
/// A malformed <c>write</c> block fails <b>exactly as its siblings do</b> — the whole
/// document is one <c>JsonSerializer.Deserialize</c>, so a non-boolean <c>enabled</c> faults