contracts: round-trip degraded provenance/watch-list/mode-changed; proto doc (Contracts-018,019)
This commit is contained in:
@@ -668,8 +668,15 @@ namespace ZB.MOM.WW.MxGateway.Contracts.Proto {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provider selection / current provider for the alarm feed. UNSPECIFIED on a
|
||||
/// SubscribeAlarmsCommand means auto: alarmmgr primary with subtag fallback.
|
||||
/// Provider selection / current provider for the alarm feed. The zero value
|
||||
/// has two distinct meanings depending on the use site:
|
||||
/// - As SubscribeAlarmsCommand.forced_mode, UNSPECIFIED means auto: alarmmgr
|
||||
/// primary with subtag fallback.
|
||||
/// - As a provenance value (OnAlarmTransitionEvent.source_provider,
|
||||
/// ActiveAlarmSnapshot.source_provider, OnAlarmProviderModeChangedEvent.mode,
|
||||
/// AlarmProviderStatus.mode), the worker always emits ALARMMGR or SUBTAG and
|
||||
/// never UNSPECIFIED; clients should treat a UNSPECIFIED provenance value as
|
||||
/// "unknown / not yet determined".
|
||||
/// </summary>
|
||||
public enum AlarmProviderMode {
|
||||
[pbr::OriginalName("ALARM_PROVIDER_MODE_UNSPECIFIED")] Unspecified = 0,
|
||||
@@ -26528,6 +26535,12 @@ namespace ZB.MOM.WW.MxGateway.Contracts.Proto {
|
||||
/// <summary>Field number for the "degraded" field.</summary>
|
||||
public const int DegradedFieldNumber = 14;
|
||||
private bool degraded_;
|
||||
/// <summary>
|
||||
/// True when this snapshot came from the subtag-monitoring fallback rather
|
||||
/// than the native alarmmgr provider — synthesized from data changes, reduced
|
||||
/// fidelity (synthetic GUID, no native raise time). Mirrors
|
||||
/// OnAlarmTransitionEvent.degraded.
|
||||
/// </summary>
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public bool Degraded {
|
||||
@@ -26540,6 +26553,11 @@ namespace ZB.MOM.WW.MxGateway.Contracts.Proto {
|
||||
/// <summary>Field number for the "source_provider" field.</summary>
|
||||
public const int SourceProviderFieldNumber = 15;
|
||||
private global::ZB.MOM.WW.MxGateway.Contracts.Proto.AlarmProviderMode sourceProvider_ = global::ZB.MOM.WW.MxGateway.Contracts.Proto.AlarmProviderMode.Unspecified;
|
||||
/// <summary>
|
||||
/// Which provider produced this snapshot. Mirrors
|
||||
/// OnAlarmTransitionEvent.source_provider; always ALARMMGR or SUBTAG on the
|
||||
/// wire (never UNSPECIFIED).
|
||||
/// </summary>
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public global::ZB.MOM.WW.MxGateway.Contracts.Proto.AlarmProviderMode SourceProvider {
|
||||
|
||||
@@ -315,8 +315,15 @@ message SubscribeBulkCommand {
|
||||
repeated string tag_addresses = 2;
|
||||
}
|
||||
|
||||
// Provider selection / current provider for the alarm feed. UNSPECIFIED on a
|
||||
// SubscribeAlarmsCommand means auto: alarmmgr primary with subtag fallback.
|
||||
// Provider selection / current provider for the alarm feed. The zero value
|
||||
// has two distinct meanings depending on the use site:
|
||||
// - As SubscribeAlarmsCommand.forced_mode, UNSPECIFIED means auto: alarmmgr
|
||||
// primary with subtag fallback.
|
||||
// - As a provenance value (OnAlarmTransitionEvent.source_provider,
|
||||
// ActiveAlarmSnapshot.source_provider, OnAlarmProviderModeChangedEvent.mode,
|
||||
// AlarmProviderStatus.mode), the worker always emits ALARMMGR or SUBTAG and
|
||||
// never UNSPECIFIED; clients should treat a UNSPECIFIED provenance value as
|
||||
// "unknown / not yet determined".
|
||||
enum AlarmProviderMode {
|
||||
ALARM_PROVIDER_MODE_UNSPECIFIED = 0;
|
||||
ALARM_PROVIDER_MODE_ALARMMGR = 1;
|
||||
@@ -847,7 +854,14 @@ message ActiveAlarmSnapshot {
|
||||
string operator_comment = 11;
|
||||
MxValue current_value = 12;
|
||||
MxValue limit_value = 13;
|
||||
// True when this snapshot came from the subtag-monitoring fallback rather
|
||||
// than the native alarmmgr provider — synthesized from data changes, reduced
|
||||
// fidelity (synthetic GUID, no native raise time). Mirrors
|
||||
// OnAlarmTransitionEvent.degraded.
|
||||
bool degraded = 14;
|
||||
// Which provider produced this snapshot. Mirrors
|
||||
// OnAlarmTransitionEvent.source_provider; always ALARMMGR or SUBTAG on the
|
||||
// wire (never UNSPECIFIED).
|
||||
AlarmProviderMode source_provider = 15;
|
||||
}
|
||||
|
||||
|
||||
@@ -1427,4 +1427,120 @@ public sealed class ProtobufContractRoundTripTests
|
||||
Assert.Single(parsed.ReadBulk.Results);
|
||||
Assert.True(parsed.ReadBulk.Results[0].WasCached);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that an <see cref="ActiveAlarmSnapshot"/> carrying the
|
||||
/// alarm-provider provenance fields <c>degraded</c> (14) and
|
||||
/// <c>source_provider</c> (15) round-trips with their values preserved,
|
||||
/// pinning the wire shape of the byte-identical provenance fields that
|
||||
/// also appear on <see cref="OnAlarmTransitionEvent"/>.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ActiveAlarmSnapshot_RoundTripsDegradedProvenance()
|
||||
{
|
||||
var raise = Timestamp.FromDateTime(new DateTime(2026, 6, 13, 12, 0, 0, DateTimeKind.Utc));
|
||||
var original = new ActiveAlarmSnapshot
|
||||
{
|
||||
AlarmFullReference = "Galaxy!Area.Tank01.Level.HiHi",
|
||||
SourceObjectReference = "Tank01",
|
||||
AlarmTypeName = "AnalogLimitAlarm.HiHi",
|
||||
Severity = 750,
|
||||
OriginalRaiseTimestamp = raise,
|
||||
CurrentState = AlarmConditionState.Active,
|
||||
Degraded = true,
|
||||
SourceProvider = AlarmProviderMode.Subtag,
|
||||
};
|
||||
|
||||
var parsed = ActiveAlarmSnapshot.Parser.ParseFrom(original.ToByteArray());
|
||||
|
||||
Assert.Equal(original, parsed);
|
||||
Assert.True(parsed.Degraded);
|
||||
Assert.Equal(AlarmProviderMode.Subtag, parsed.SourceProvider);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that a <see cref="SubscribeAlarmsCommand"/> populating the
|
||||
/// alarm-provider fallback extensions — <c>forced_mode</c> (2), a
|
||||
/// <c>watch_list</c> entry with all six <see cref="AlarmSubtagTarget"/>
|
||||
/// string fields (3), and a <c>failover</c>
|
||||
/// <see cref="AlarmFailoverConfig"/> (4) — round-trips end to end,
|
||||
/// pinning the wire shape that the forced-subtag-mode fix depends on.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void SubscribeAlarmsCommand_RoundTripsForcedModeWatchListAndFailover()
|
||||
{
|
||||
var original = new SubscribeAlarmsCommand
|
||||
{
|
||||
SubscriptionExpression = @"\\node\Galaxy!Area",
|
||||
ForcedMode = AlarmProviderMode.Subtag,
|
||||
WatchList =
|
||||
{
|
||||
new AlarmSubtagTarget
|
||||
{
|
||||
AlarmFullReference = "Galaxy!Area.Tank01.Level.HiHi",
|
||||
SourceObjectReference = "Tank01",
|
||||
ActiveSubtag = "Tank01.Level.HiHi.InAlarm",
|
||||
AckedSubtag = "Tank01.Level.HiHi.Acked",
|
||||
AckCommentSubtag = "Tank01.Level.HiHi.AckMsg",
|
||||
PrioritySubtag = "Tank01.Level.HiHi.Priority",
|
||||
},
|
||||
},
|
||||
Failover = new AlarmFailoverConfig
|
||||
{
|
||||
ConsecutiveFailureThreshold = 3,
|
||||
FailbackProbeIntervalSeconds = 10,
|
||||
FailbackStableProbes = 5,
|
||||
},
|
||||
};
|
||||
|
||||
var parsed = SubscribeAlarmsCommand.Parser.ParseFrom(original.ToByteArray());
|
||||
|
||||
Assert.Equal(original, parsed);
|
||||
Assert.Equal(AlarmProviderMode.Subtag, parsed.ForcedMode);
|
||||
var target = Assert.Single(parsed.WatchList);
|
||||
Assert.Equal("Galaxy!Area.Tank01.Level.HiHi", target.AlarmFullReference);
|
||||
Assert.Equal("Tank01", target.SourceObjectReference);
|
||||
Assert.Equal("Tank01.Level.HiHi.InAlarm", target.ActiveSubtag);
|
||||
Assert.Equal("Tank01.Level.HiHi.Acked", target.AckedSubtag);
|
||||
Assert.Equal("Tank01.Level.HiHi.AckMsg", target.AckCommentSubtag);
|
||||
Assert.Equal("Tank01.Level.HiHi.Priority", target.PrioritySubtag);
|
||||
Assert.Equal(3, parsed.Failover.ConsecutiveFailureThreshold);
|
||||
Assert.Equal(10, parsed.Failover.FailbackProbeIntervalSeconds);
|
||||
Assert.Equal(5, parsed.Failover.FailbackStableProbes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that an <see cref="MxEvent"/> carrying an
|
||||
/// <see cref="OnAlarmProviderModeChangedEvent"/> body (the
|
||||
/// <c>MxEvent.body</c> oneof tag 25 paired with
|
||||
/// <see cref="MxEventFamily.OnAlarmProviderModeChanged"/>, family 6)
|
||||
/// round-trips and resolves to
|
||||
/// <see cref="MxEvent.BodyOneofCase.OnAlarmProviderModeChanged"/>.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void MxEvent_RoundTripsOnAlarmProviderModeChangedBody()
|
||||
{
|
||||
var at = Timestamp.FromDateTime(new DateTime(2026, 6, 13, 9, 30, 0, DateTimeKind.Utc));
|
||||
var original = new MxEvent
|
||||
{
|
||||
Family = MxEventFamily.OnAlarmProviderModeChanged,
|
||||
SessionId = "session-1",
|
||||
WorkerSequence = 42,
|
||||
OnAlarmProviderModeChanged = new OnAlarmProviderModeChangedEvent
|
||||
{
|
||||
Mode = AlarmProviderMode.Subtag,
|
||||
Reason = "wnwrap poll failed 3x",
|
||||
Hresult = unchecked((int)0x80004005),
|
||||
At = at,
|
||||
},
|
||||
};
|
||||
|
||||
var parsed = MxEvent.Parser.ParseFrom(original.ToByteArray());
|
||||
|
||||
Assert.Equal(original, parsed);
|
||||
Assert.Equal(MxEvent.BodyOneofCase.OnAlarmProviderModeChanged, parsed.BodyCase);
|
||||
Assert.Equal(MxEventFamily.OnAlarmProviderModeChanged, parsed.Family);
|
||||
Assert.Equal(AlarmProviderMode.Subtag, parsed.OnAlarmProviderModeChanged.Mode);
|
||||
Assert.Equal(unchecked((int)0x80004005), parsed.OnAlarmProviderModeChanged.Hresult);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user