7f29a75edb
v2-ci / unit-tests (push) Has been cancelled
R06:M-5 made Sparkplug *Array leaves unbindable because the ingestor refused them. The ingestor now decodes the packed bytes_value of all 13 array types (new SparkplugArrayCodec: LE fixed widths, int64-ms DateTime, uint32-count + MSB-first BooleanArray, NUL-terminated UTF-8 StringArray; golden vectors are the spec's examples, reproduced byte-for-byte by SparkplugNet 1.3.10) and publishes a typed 1-D array through the scalar coercion, all-or-nothing. Shape uses the fleet's one array model: the tag's platform isArray/arrayLength keys (ValueRank=1, ArrayDimensions=[arrayLength] or [0] = variable length). The driver reads them with TagConfigIntent's exact semantics and never rejects on them, so composer, driver, authoring model and deploy inspector agree (MqttArrayShapeParityTests). Shape mismatch (array metric on a scalar tag, or the reverse) is BadTypeMismatch - a String tag no longer gets the packed buffer as base64; a malformed body or a length differing from a declared arrayLength is BadDecodingError (MTConnect #627 verdict). Template/DataSet members of an array type take the same path. Arrays stay read-only (encoder refuses them; MQTT is not in DriverArrayWriteSupport). Browser: array leaves are bindable again and state isArray in AddressFields; the commit mapper writes "isArray": true (no arrayLength). Discovery reports IsArray/ArrayDim. Docs: Mqtt.md "Array metrics", design table, drivers rule. Tests: codec (golden + malformed), ingest through the real codec + Dispatch (the project's MiniBroker never forwards a PUBLISH, so there is no in-process broker harness), browse, discovery, commit mapper, parity corpus. Mutating the fix back out fails 18 MQTT + 9 AdminUI tests. Claude-Session: https://claude.ai/code/session_01GT67AEHd2Acv1YPwGfXEoV
60 lines
2.8 KiB
C#
60 lines
2.8 KiB
C#
using Shouldly;
|
|
using Xunit;
|
|
using ZB.MOM.WW.OtOpcUa.AdminUI.Uns;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests.Uns;
|
|
|
|
/// <summary>
|
|
/// G2-F2: a Sparkplug array / unsupported-type metric is refused at commit with a "not bindable in this
|
|
/// version" message that echoes the browser's descriptor — not the "attribute lookup returned nothing"
|
|
/// text, which is reserved for a lookup that really did return nothing.
|
|
/// </summary>
|
|
[Trait("Category", "Unit")]
|
|
public sealed class MqttUnbindableLeafMessageTests
|
|
{
|
|
[Fact]
|
|
public void An_unsupported_metric_says_it_is_not_bindable_and_echoes_the_descriptor()
|
|
{
|
|
// (Array metrics were the original example; they are bindable since #754 — an unsupported type is not.)
|
|
const string descriptor = "Metric · DataSet · alias 7 · unsupported in v1 — not bindable";
|
|
|
|
var error = RawBrowseCommitMapper.DescribeUncommittableLeaf("Mqtt", "Pressures", addressFields: null, descriptor);
|
|
|
|
error.ShouldNotBeNull();
|
|
error!.ShouldContain("'Pressures' cannot be bound in this version");
|
|
error.ShouldContain(descriptor);
|
|
error.ShouldNotContain("attribute lookup returned nothing");
|
|
}
|
|
|
|
[Fact]
|
|
public void A_lookup_that_returned_nothing_keeps_the_original_message()
|
|
{
|
|
// Positive control: the new branch is selected by the descriptor, not by MQTT in general.
|
|
RawBrowseCommitMapper.DescribeUncommittableLeaf("Mqtt", "Temperature", addressFields: null, descriptor: null)!
|
|
.ShouldContain("attribute lookup returned nothing");
|
|
RawBrowseCommitMapper.DescribeUncommittableLeaf("Mqtt", "Temperature", null, "Metric · Double")!
|
|
.ShouldContain("attribute lookup returned nothing");
|
|
}
|
|
|
|
[Fact]
|
|
public void A_bindable_leaf_is_never_refused_whatever_its_descriptor_says()
|
|
=> RawBrowseCommitMapper.DescribeUncommittableLeaf(
|
|
"Mqtt", "Temperature",
|
|
new Dictionary<string, string> { [ZB.MOM.WW.OtOpcUa.Driver.Mqtt.MqttTagConfigKeys.MetricName] = "Temperature" },
|
|
"anything · not bindable")
|
|
.ShouldBeNull();
|
|
|
|
[Fact]
|
|
public void The_marker_matches_what_the_sparkplug_browser_writes()
|
|
{
|
|
var dir = new DirectoryInfo(AppContext.BaseDirectory);
|
|
while (dir is not null && !File.Exists(Path.Combine(dir.FullName, "ZB.MOM.WW.OtOpcUa.slnx"))) dir = dir.Parent;
|
|
var browser = File.ReadAllText(Path.Combine(dir!.FullName, "src", "Drivers",
|
|
"ZB.MOM.WW.OtOpcUa.Driver.Mqtt.Browser", "MqttBrowseSession.cs"));
|
|
|
|
browser.ShouldContain("— " + RawBrowseCommitMapper.NotBindableMarker + "\")");
|
|
AdminUiSource.Read("Components", "Shared", "Raw", "RawBrowseModal.razor")
|
|
.ShouldContain("DescribeUncommittableLeaf(_driverType, s.Name, s.AddressFields, s.Descriptor)");
|
|
}
|
|
}
|