probe: InitializeConsumer required — provider visible after, alarms still absent

InitializeConsumer was the missing call. Adding it before
RegisterConsumer makes the \Galaxy! provider appear in
GetProviders (status 0 -> 100 within 500ms). Without Initialize,
GetProviders returns an empty list even though everything else
returns rc=0 (success).

Probe trace 2026-05-01:

  InitializeConsumer -> 0
  RegisterConsumer -> 0
  GetProviders [after Register] -> count=0 list=[]
  Subscribe('\Galaxy!') -> 0
  GetProviders [after Subscribe] -> count=1 list=[  0 \Galaxy!]
  GetProviders [poll #1] -> count=1 list=[100 \Galaxy!]

Despite the provider being at "100% query complete" for the
entire 60s window, GetStatistics continued to report
total=0 active=0 codes=[7] -- no alarm transitions reached the
consumer even with a System Platform script flipping
TestMachine_001.TestAlarm001 every 10s during the run.

So the consumer chain works end-to-end. What's missing is alarm
traffic from the producer side. The next discriminator is
whether ObjectViewer (or another live consumer) sees the alarm
fire while the script runs.

API-ordering bug fix to apply to PR A.5's AlarmClientConsumer
regardless of how A.2 lands: AlarmClientConsumer.Subscribe
should call InitializeConsumer before RegisterConsumer (currently
omits Initialize entirely, which means the provider chain is
never visible from the worker either). That fix lifts a
fundamental bug independent of the polling-vs-callback question.

Probe changes:

- Added InitializeConsumer call before RegisterConsumer.
- Added LogProviders helper that logs only on change; called
  after Register, after Subscribe, and on every poll. Easier
  to spot when the provider chain transitions from empty to
  populated.
- Restored Skip-gating after run.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Joseph Doherty
2026-05-01 07:43:06 -04:00
parent f4423dfb6d
commit 4e8928cf71
2 changed files with 80 additions and 12 deletions
@@ -231,6 +231,22 @@ public sealed class AlarmClientWmProbeTests : IDisposable
try
{
client = new AlarmClient();
// Try InitializeConsumer first — separate from RegisterConsumer
// per the discovered API surface; previous probe runs skipped
// it. Some AVEVA managed-client patterns require Initialize
// before Register; others reverse the order. Try Initialize
// first; on failure proceed to Register.
try
{
int init = client.InitializeConsumer("AlarmProbe.Tests");
Log($"InitializeConsumer -> {init}");
}
catch (Exception ex)
{
Log($"InitializeConsumer threw: {ex.GetType().Name}: {ex.Message}");
}
int register = client.RegisterConsumer(
hWnd: probeWindow.ToInt32(),
szProductName: "AlarmProbe",
@@ -239,18 +255,7 @@ public sealed class AlarmClientWmProbeTests : IDisposable
bRetainHiddenAlarms: false);
Log($"RegisterConsumer -> {register}");
// Discover what providers AVEVA sees before subscribing, so we
// can spot a wrong subscription expression up front.
try
{
var providers = new System.Collections.Generic.List<string>();
int gp = client.GetProviders(providers);
Log($"GetProviders -> rc={gp} count={providers.Count} list=[{string.Join(", ", providers)}]");
}
catch (Exception ex)
{
Log($"GetProviders threw: {ex.GetType().Name}: {ex.Message}");
}
LogProviders(client, "after Register");
int subscribe = client.Subscribe(
szSubscription: SubscriptionExpression,
@@ -261,6 +266,8 @@ public sealed class AlarmClientWmProbeTests : IDisposable
FilterSpecification: eAlarmFilterState.asNone);
Log($"Subscribe('{SubscriptionExpression}') -> {subscribe}");
LogProviders(client, "after Subscribe");
// 3c. Pump for the configured duration. Log every message we see
// (filtered light to avoid noise from WM_PAINT / WM_TIMER /
// WM_GETICON spam from typical pumps). Poll GetStatistics on
@@ -290,6 +297,7 @@ public sealed class AlarmClientWmProbeTests : IDisposable
if (DateTime.UtcNow >= nextPoll)
{
PollGetStatistics(client, ++pollCount);
LogProviders(client, $"poll #{pollCount}");
nextPoll = DateTime.UtcNow + PollInterval;
}
Thread.Sleep(10);
@@ -316,6 +324,26 @@ public sealed class AlarmClientWmProbeTests : IDisposable
}
private string lastStatsSummary = string.Empty;
private string lastProvidersSummary = string.Empty;
private void LogProviders(AlarmClient client, string when)
{
try
{
var providers = new System.Collections.Generic.List<string>();
int rc = client.GetProviders(providers);
string summary = $"count={providers.Count} list=[{string.Join(", ", providers)}]";
if (summary != lastProvidersSummary)
{
Log($"GetProviders [{when}] -> rc={rc} {summary} (changed)");
lastProvidersSummary = summary;
}
}
catch (Exception ex)
{
Log($"GetProviders [{when}] threw: {ex.GetType().Name}: {ex.Message}");
}
}
/// <summary>
/// Drive an MxAccess write to <see cref="TriggerTagReference"/> with the