feat(comm): stream List attribute values as canonical JSON
Replace ValueFormatter.FormatDisplayValue with AttributeValueCodec.Encode in StreamRelayActor so List<T> attribute values cross the gRPC wire as a JSON array (e.g. ["a","b"]) rather than a comma-joined display string. Scalars and null values are unaffected. Tests cover List→JSON, scalar string pass-through, and null→empty-string.
This commit is contained in:
@@ -45,7 +45,7 @@ public class StreamRelayActor : ReceiveActor
|
||||
InstanceUniqueName = msg.InstanceUniqueName,
|
||||
AttributePath = msg.AttributePath,
|
||||
AttributeName = msg.AttributeName,
|
||||
Value = ValueFormatter.FormatDisplayValue(msg.Value),
|
||||
Value = AttributeValueCodec.Encode(msg.Value) ?? string.Empty,
|
||||
Quality = MapQuality(msg.Quality),
|
||||
Timestamp = Timestamp.FromDateTimeOffset(msg.Timestamp)
|
||||
}
|
||||
|
||||
@@ -204,4 +204,37 @@ public class StreamRelayActorTests : TestKit
|
||||
Assert.True(channel.Reader.TryRead(out var evt));
|
||||
Assert.Equal("", evt.AttributeChanged.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ListValue_EncodesAsJsonArray()
|
||||
{
|
||||
// List attributes must cross the wire as JSON, not as a comma-joined display string.
|
||||
var channel = Channel.CreateUnbounded<SiteStreamEvent>();
|
||||
var actor = Sys.ActorOf(Props.Create(() =>
|
||||
new StreamRelayActor("corr-list", channel.Writer)));
|
||||
|
||||
var ts = DateTimeOffset.UtcNow;
|
||||
actor.Tell(new AttributeValueChanged("Inst", "Path", "Tags",
|
||||
new List<string> { "a", "b" }, "Good", ts));
|
||||
|
||||
Thread.Sleep(500);
|
||||
Assert.True(channel.Reader.TryRead(out var evt));
|
||||
Assert.Equal("[\"a\",\"b\"]", evt.AttributeChanged.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScalarStringValue_PassesThroughUnchanged()
|
||||
{
|
||||
// Scalar strings must not be double-encoded.
|
||||
var channel = Channel.CreateUnbounded<SiteStreamEvent>();
|
||||
var actor = Sys.ActorOf(Props.Create(() =>
|
||||
new StreamRelayActor("corr-scalar", channel.Writer)));
|
||||
|
||||
var ts = DateTimeOffset.UtcNow;
|
||||
actor.Tell(new AttributeValueChanged("Inst", "Path", "Name", "x", "Good", ts));
|
||||
|
||||
Thread.Sleep(500);
|
||||
Assert.True(channel.Reader.TryRead(out var evt));
|
||||
Assert.Equal("x", evt.AttributeChanged.Value);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user