Skip to content

Fix expected matcher never populating expected_ in GenericAnalyzer#655

Open
matthew-t-watson wants to merge 2 commits into
ros:ros2from
matthew-t-watson:fix/generic-analyzer-expected-matcher
Open

Fix expected matcher never populating expected_ in GenericAnalyzer#655
matthew-t-watson wants to merge 2 commits into
ros:ros2from
matthew-t-watson:fix/generic-analyzer-expected-matcher

Conversation

@matthew-t-watson

@matthew-t-watson matthew-t-watson commented Jul 1, 2026

Copy link
Copy Markdown

Fixes #656

Summary

GenericAnalyzer's expected matcher is currently non-functional: the branch that parses the expected parameter only pre-seeds the base-class items_ map (via addItem()) and never populates the expected_ vector.

expected_ is what the code actually relies on:

  • init guardstartswith_.size() == 0 && name_.size() == 0 && contains_.size() == 0 && expected_.size() == 0 && regex_.size() == 0 decides "was not initialized with any way of checking diagnostics";
  • match() — iterates expected_ (name == expected_[i]);
  • report() — iterates expected_ to detect missing expected items.

Because expected_ is never written, an analyzer whose only matcher is expected:

  1. fails to initialise (GenericAnalyzer '<x>' was not initialized with any way of checking diagnostics), which leaves its AnalyzerGroup empty and produces Group '<x>' doesn't contain any analyzers, can't match; and
  2. would not match anything even when combined with another matcher, since match() reads the empty expected_.

This is a regression from the ROS 1 implementation, where the expected branch populated the vector via getParamVals(expected, expected_) before creating the pre-seeded items (noetic-devel generic_analyzer.cpp).

Fix

Populate expected_ from the parameter's string array alongside the existing addItem() loop:

} else if (pname.compare("expected") == 0) {
  ...
  expected_ = pvalue.as_string_array();
  for (const auto & exp : expected_) {
    auto item = std::make_shared<StatusItem>(exp);
    this->addItem(exp, item);
  }
}

Reproduction

Minimal analyzer config (aggregator_node --ros-args --params-file expected.yaml):

/**:
  ros__parameters:
    path: Test
    loctest:
      type: diagnostic_aggregator/GenericAnalyzer
      path: LocTest
      expected: ['some/expected/status_name']
      timeout: 5.0

Before this change the node logs GenericAnalyzer 'LocTest' was not initialized with any way of checking diagnostics and Group 'Test' doesn't contain any analyzers. Swapping expected for startswith/contains/regex works, confirming the issue is specific to expected.

Verified against the installed Jazzy build (diagnostic_aggregator 4.2.7); the same code is present on ros2 (rolling).

Testing

Adds a create-analyzers launch test (test/expected_only_analyzer.yaml + test/expected_output/create_expected_only_analyzer.txt, wired into create_analyzers_tests) with an analyzer whose only matcher is expected. It asserts the success-only Initialized analyzer ... with path '/ExpectedOnly' log line, so it times out ("was not initialized with any way of checking diagnostics") without the fix and passes with it.

Verified locally on Jazzy:

  • Without the fix (released 4.2.7 plugin): the new test fails (assertWaitFor timeout).
  • With the fix: the new test passes.

Notes

Draft: opening early for maintainer feedback. If preferred, the fixture could also be extended to an output_/behavioural test that publishes a matching status and checks aggregation.

The `expected` parameter branch in GenericAnalyzer::init only pre-seeds the
base-class items_ map via addItem(); it never populates the expected_ vector.
But expected_ is what the initialisation guard, match() and report() all read,
so an analyzer whose only matcher is `expected`:

  * fails to initialise ("was not initialized with any way of checking
    diagnostics"), which leaves its AnalyzerGroup with no analyzers
    ("Group '<x>' doesn't contain any analyzers, can't match"), and
  * never matches incoming statuses even when paired with another matcher,
    since match() iterates the empty expected_.

This is a regression from the ROS 1 implementation, which populated expected_
via getParamVals(expected, expected_) before creating the pre-seeded items.

Restore the expected_ population alongside the existing addItem() loop.

Signed-off-by: Matthew Watson <matt@opteran.com>
@mergify mergify Bot added the ros2 PR tackling a ROS2 branch label Jul 1, 2026
Adds a create-analyzers launch test with an analyzer whose only matcher is
`expected`. The success-only "Initialized ... with path '/ExpectedOnly'"
log line is asserted, so the test fails (assertWaitFor times out on
"not initialized with any way of checking diagnostics") without the fix and
passes with it.

Verified: fails against the released plugin, passes with the fix applied.

Signed-off-by: Matthew Watson <matt@opteran.com>
@mergify

mergify Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ros2 PR tackling a ROS2 branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

GenericAnalyzer: expected matcher never populates expected_ (analyzer fails to initialise)

1 participant