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,
|
InstanceUniqueName = msg.InstanceUniqueName,
|
||||||
AttributePath = msg.AttributePath,
|
AttributePath = msg.AttributePath,
|
||||||
AttributeName = msg.AttributeName,
|
AttributeName = msg.AttributeName,
|
||||||
Value = ValueFormatter.FormatDisplayValue(msg.Value),
|
Value = AttributeValueCodec.Encode(msg.Value) ?? string.Empty,
|
||||||
Quality = MapQuality(msg.Quality),
|
Quality = MapQuality(msg.Quality),
|
||||||
Timestamp = Timestamp.FromDateTimeOffset(msg.Timestamp)
|
Timestamp = Timestamp.FromDateTimeOffset(msg.Timestamp)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -204,4 +204,37 @@ public class StreamRelayActorTests : TestKit
|
|||||||
Assert.True(channel.Reader.TryRead(out var evt));
|
Assert.True(channel.Reader.TryRead(out var evt));
|
||||||
Assert.Equal("", evt.AttributeChanged.Value);
|
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