Skip to content

feat: Introduce metric validation for otter tests #19260

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

timo0
Copy link
Member

@timo0 timo0 commented May 18, 2025

Fix #18638

This change introduces:

  • NetworkMetrics a singleton that collects all NodeMetric instances
  • NodeMetric lightweight in-memory Metrics implementation that instruments all added Metric with TestMetricInvocationHandler to record the history of the metrics
  • assertThat validations for metric validation

Currently only assertThat().neverExceeds() is implemented to show how the system works. More to follow.

Fix #18638

This change introduces:
* `NetworkMetrics` a singleton that collects all `NodeMetric` instances
* `NodeMetric` lightweight in-memory `Metrics` implementation that instruments all added `Metric` with `TestMetricInvocationHandler` to record the history of the metrics
* `assertThat` validations for metric validation

Currently only `assertThat().neverExceeds()` is implemented to show how the system works. More to follow.

Signed-off-by: Timo Brandstätter <[email protected]>
@timo0 timo0 added this to the v0.63 milestone May 18, 2025
@timo0 timo0 self-assigned this May 18, 2025
@timo0 timo0 requested review from a team as code owners May 18, 2025 13:25
Copy link

codecov bot commented May 18, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Impacted file tree graph

@@            Coverage Diff            @@
##               main   #19260   +/-   ##
=========================================
  Coverage     69.35%   69.35%           
  Complexity    23268    23268           
=========================================
  Files          2645     2645           
  Lines        100710   100710           
  Branches      10409    10409           
=========================================
  Hits          69846    69846           
  Misses        26902    26902           
  Partials       3962     3962           

Impacted file tree graph

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link

Coverage summary from Codacy

See diff coverage on Codacy

Coverage variation Diff coverage
+0.00% (target: -1.00%)
Coverage variation details
Coverable lines Covered lines Coverage
Common ancestor commit (a24192e) 100660 73812 73.33%
Head commit (78198fc) 100660 (+0) 73812 (+0) 73.33% (+0.00%)

Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch: <coverage of head commit> - <coverage of common ancestor commit>

Diff coverage details
Coverable lines Covered lines Diff coverage
Pull request (#19260) 0 0 ∅ (not applicable)

Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified: <covered lines added or modified>/<coverable lines added or modified> * 100%

See your quality gate settings    Change summary preferences

@timo0 timo0 requested a review from netopyr May 18, 2025 14:39
* @param threshold the threshold for the metric
* @return the {@link MultipleNodeMetricsResults} instance
*/
public MultipleNodeMetricsAssert neverExceeds(final double threshold) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am unsure if we should introduce new names or stick with typical AssertJ names (e.g., isLessThan()). I see the advantages of both.

.map(SingleNodeMetricsAssert::toDouble)
.filter(v -> v > threshold)
.toList();
failWithMessage(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wrongValues can potentially be very long. I wonder if there is a better way to report this. Maybe the maximum would be sufficient?

We should also report the timestamp when the limit was exceeded.

*/
public final class NetworkMetrics {

private static final NetworkMetrics INSTANCE = new NetworkMetrics();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we avoid introducing a Singleton?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes removed

if (started) {
return;
}
started = true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not thread-safe. Not sure if it is intended.

final Thread updaterThread = new Thread(
() -> {
while (started) {
final Instant start = Instant.now();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not use Instant.now() but use the FakeTime instead.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On second thought. If this implementation is only used in Turtle tests, we should make NodeMetrics a TimeTickReceiver and call the updaters every time a tick is received. What do you think?

* integration tests. It records the full history of every metric value so that assertions can be
* executed after a test run.
*/
public class NodeMetrics implements Metrics {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this implementation will only be used in tests running on Turtle. I suggest moving this package under the turtle package.

Copy link
Contributor

@netopyr netopyr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am afraid I have to refresh my memory about the Metrics implementation before I can finish the review.

timo0 added 2 commits May 19, 2025 14:06
# Conflicts:
#	platform-sdk/consensus-otter-tests/src/test/java/org/hiero/otter/test/HappyPathTest.java
assertThat(logResults).noMessageWithLevelHigherThan(Level.INFO);

assertThat(network.getStatusProgression())
.hasSteps(target(ACTIVE).requiringInterim(REPLAYING_EVENTS, OBSERVING, CHECKING));

assertThat(network.getMetricsResultsFor("platform", "bytes_per_trans").ignoring(firstNode))
.neverExceeds(444);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we make 444 a constant?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the strings should also be constants I think

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like we should introduce a class like MetricId that has category and name. and use that for creating metrics as well as when we are asserting them

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Implement metric validator
3 participants