Skip to content

Commit 7e7f564

Browse files
authored
chore: PlatformStatus assertions (#19184)
Signed-off-by: Michael Heinrichs <[email protected]>
1 parent 35282ab commit 7e7f564

15 files changed

+499
-4
lines changed

platform-sdk/consensus-otter-tests/src/test/java/org/hiero/otter/test/BirthRoundMigrationTest.java

+13
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,14 @@
33

44
import static org.apache.logging.log4j.Level.WARN;
55
import static org.assertj.core.data.Percentage.withPercentage;
6+
import static org.hiero.consensus.model.status.PlatformStatus.ACTIVE;
7+
import static org.hiero.consensus.model.status.PlatformStatus.CHECKING;
8+
import static org.hiero.consensus.model.status.PlatformStatus.FREEZE_COMPLETE;
9+
import static org.hiero.consensus.model.status.PlatformStatus.FREEZING;
10+
import static org.hiero.consensus.model.status.PlatformStatus.OBSERVING;
11+
import static org.hiero.consensus.model.status.PlatformStatus.REPLAYING_EVENTS;
612
import static org.hiero.otter.fixtures.OtterAssertions.assertThat;
13+
import static org.hiero.otter.fixtures.assertions.StatusProgressionStep.target;
714
import static org.hiero.otter.fixtures.turtle.TurtleNodeConfiguration.SOFTWARE_VERSION;
815

916
import java.time.Duration;
@@ -70,5 +77,11 @@ void testBirthRoundMigration(TestEnvironment env) throws InterruptedException {
7077
assertThat(network.getConsensusResult())
7178
.hasAdvancedSince(freezeRound)
7279
.hasEqualRoundsIgnoringLast(withPercentage(5));
80+
81+
assertThat(network.getStatusProgression())
82+
.hasSteps(
83+
target(ACTIVE).requiringInterim(REPLAYING_EVENTS, OBSERVING, CHECKING),
84+
target(FREEZE_COMPLETE).requiringInterim(FREEZING),
85+
target(ACTIVE).requiringInterim(REPLAYING_EVENTS, OBSERVING, CHECKING));
7386
}
7487
}

platform-sdk/consensus-otter-tests/src/test/java/org/hiero/otter/test/HappyPathTest.java

+8
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@
22
package org.hiero.otter.test;
33

44
import static com.swirlds.logging.legacy.LogMarker.STARTUP;
5+
import static org.hiero.consensus.model.status.PlatformStatus.ACTIVE;
6+
import static org.hiero.consensus.model.status.PlatformStatus.CHECKING;
7+
import static org.hiero.consensus.model.status.PlatformStatus.OBSERVING;
8+
import static org.hiero.consensus.model.status.PlatformStatus.REPLAYING_EVENTS;
59
import static org.hiero.otter.fixtures.OtterAssertions.assertThat;
10+
import static org.hiero.otter.fixtures.assertions.StatusProgressionStep.target;
611

712
import java.time.Duration;
813
import org.apache.logging.log4j.Level;
@@ -36,5 +41,8 @@ void testHappyPath(TestEnvironment env) throws InterruptedException {
3641
final MultipleNodeLogResults logResults =
3742
network.getLogResults().ignoring(network.getNodes().getFirst()).ignoring(STARTUP);
3843
assertThat(logResults).noMessageWithLevelHigherThan(Level.INFO);
44+
45+
assertThat(network.getStatusProgression())
46+
.hasSteps(target(ACTIVE).requiringInterim(REPLAYING_EVENTS, OBSERVING, CHECKING));
3947
}
4048
}

platform-sdk/consensus-otter-tests/src/testFixtures/java/org/hiero/otter/fixtures/Network.java

+9
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import java.util.List;
77
import org.hiero.otter.fixtures.result.MultipleNodeConsensusResults;
88
import org.hiero.otter.fixtures.result.MultipleNodeLogResults;
9+
import org.hiero.otter.fixtures.result.MultipleNodeStatusProgression;
910

1011
/**
1112
* Interface representing a network of nodes.
@@ -88,4 +89,12 @@ public interface Network {
8889
*/
8990
@NonNull
9091
MultipleNodeLogResults getLogResults();
92+
93+
/**
94+
* Gets the status progression of all nodes in the network.
95+
*
96+
* @return the status progression of the nodes
97+
*/
98+
@NonNull
99+
MultipleNodeStatusProgression getStatusProgression();
91100
}

platform-sdk/consensus-otter-tests/src/testFixtures/java/org/hiero/otter/fixtures/Node.java

+9
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import org.hiero.consensus.model.node.NodeId;
77
import org.hiero.otter.fixtures.result.SingleNodeConsensusResult;
88
import org.hiero.otter.fixtures.result.SingleNodeLogResult;
9+
import org.hiero.otter.fixtures.result.SingleNodeStatusProgression;
910

1011
/**
1112
* Interface representing a node in the network.
@@ -82,4 +83,12 @@ public interface Node {
8283
*/
8384
@NonNull
8485
SingleNodeLogResult getLogResult();
86+
87+
/**
88+
* Gets the status progression of the node.
89+
*
90+
* @return the status progression of the node
91+
*/
92+
@NonNull
93+
SingleNodeStatusProgression getStatusProgression();
8594
}

platform-sdk/consensus-otter-tests/src/testFixtures/java/org/hiero/otter/fixtures/OtterAssertions.java

+28
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,16 @@
66
import org.assertj.core.api.Assertions;
77
import org.hiero.otter.fixtures.assertions.MultipleNodeConsensusResultsAssert;
88
import org.hiero.otter.fixtures.assertions.MultipleNodeLogResultsAssert;
9+
import org.hiero.otter.fixtures.assertions.MultipleNodeStatusProgressionAssert;
910
import org.hiero.otter.fixtures.assertions.SingleNodeConsensusResultAssert;
1011
import org.hiero.otter.fixtures.assertions.SingleNodeLogResultAssert;
12+
import org.hiero.otter.fixtures.assertions.SingleNodeStatusProgressionAssert;
1113
import org.hiero.otter.fixtures.result.MultipleNodeConsensusResults;
1214
import org.hiero.otter.fixtures.result.MultipleNodeLogResults;
15+
import org.hiero.otter.fixtures.result.MultipleNodeStatusProgression;
1316
import org.hiero.otter.fixtures.result.SingleNodeConsensusResult;
1417
import org.hiero.otter.fixtures.result.SingleNodeLogResult;
18+
import org.hiero.otter.fixtures.result.SingleNodeStatusProgression;
1519

1620
/**
1721
* This class contains all {@code assertThat()} methods for test results of the Otter framework.
@@ -63,4 +67,28 @@ public static SingleNodeLogResultAssert assertThat(@Nullable final SingleNodeLog
6367
public static MultipleNodeLogResultsAssert assertThat(@Nullable final MultipleNodeLogResults result) {
6468
return MultipleNodeLogResultsAssert.assertThat(result);
6569
}
70+
71+
/**
72+
* Creates an assertion for the given {@link SingleNodeStatusProgression}.
73+
*
74+
* @param statusProgression the {@link SingleNodeStatusProgression} to assert
75+
* @return an assertion for the given {@link SingleNodeStatusProgression}
76+
*/
77+
@NonNull
78+
public static SingleNodeStatusProgressionAssert assertThat(
79+
@Nullable final SingleNodeStatusProgression statusProgression) {
80+
return SingleNodeStatusProgressionAssert.assertThat(statusProgression);
81+
}
82+
83+
/**
84+
* Creates an assertion for the given {@link MultipleNodeStatusProgression}.
85+
*
86+
* @param statusProgression the {@link MultipleNodeStatusProgression} to assert
87+
* @return an assertion for the given {@link MultipleNodeStatusProgression}
88+
*/
89+
@NonNull
90+
public static MultipleNodeStatusProgressionAssert assertThat(
91+
@Nullable final MultipleNodeStatusProgression statusProgression) {
92+
return MultipleNodeStatusProgressionAssert.assertThat(statusProgression);
93+
}
6694
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
package org.hiero.otter.fixtures.assertions;
3+
4+
import edu.umd.cs.findbugs.annotations.NonNull;
5+
import edu.umd.cs.findbugs.annotations.Nullable;
6+
import org.assertj.core.api.AbstractAssert;
7+
import org.hiero.otter.fixtures.OtterAssertions;
8+
import org.hiero.otter.fixtures.result.MultipleNodeStatusProgression;
9+
import org.hiero.otter.fixtures.result.SingleNodeStatusProgression;
10+
11+
/**
12+
* Assertions for {@link MultipleNodeStatusProgression}.
13+
*/
14+
@SuppressWarnings("UnusedReturnValue")
15+
public class MultipleNodeStatusProgressionAssert
16+
extends AbstractAssert<MultipleNodeStatusProgressionAssert, MultipleNodeStatusProgression> {
17+
18+
/**
19+
* Creates a new instance of {@link MultipleNodeStatusProgressionAssert}
20+
*
21+
* @param actual the actual {@link MultipleNodeStatusProgression} to assert
22+
*/
23+
public MultipleNodeStatusProgressionAssert(@Nullable final MultipleNodeStatusProgression actual) {
24+
super(actual, MultipleNodeStatusProgressionAssert.class);
25+
}
26+
27+
/**
28+
* Creates an assertion for the given {@link MultipleNodeStatusProgression}.
29+
*
30+
* @param actual the {@link MultipleNodeStatusProgression} to assert
31+
* @return an assertion for the given {@link MultipleNodeStatusProgression}
32+
*/
33+
@NonNull
34+
public static MultipleNodeStatusProgressionAssert assertThat(@Nullable final MultipleNodeStatusProgression actual) {
35+
return new MultipleNodeStatusProgressionAssert(actual);
36+
}
37+
38+
/**
39+
* Verifies that all nodes' statuses went exactly through specified steps.
40+
*
41+
* @param first the first expected step
42+
* @param rest additional expected steps
43+
* @return this assertion object for method chaining
44+
*/
45+
@NonNull
46+
public MultipleNodeStatusProgressionAssert hasSteps(
47+
@NonNull final StatusProgressionStep first, @Nullable final StatusProgressionStep... rest) {
48+
isNotNull();
49+
for (final SingleNodeStatusProgression statusProgression : actual.statusProgressions()) {
50+
OtterAssertions.assertThat(statusProgression).hasSteps(first, rest);
51+
}
52+
return this;
53+
}
54+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
package org.hiero.otter.fixtures.assertions;
3+
4+
import edu.umd.cs.findbugs.annotations.NonNull;
5+
import edu.umd.cs.findbugs.annotations.Nullable;
6+
import java.util.ArrayList;
7+
import java.util.Arrays;
8+
import java.util.EnumSet;
9+
import java.util.Iterator;
10+
import java.util.List;
11+
import java.util.Set;
12+
import org.assertj.core.api.AbstractAssert;
13+
import org.hiero.consensus.model.status.PlatformStatus;
14+
import org.hiero.otter.fixtures.result.SingleNodeConsensusResult;
15+
import org.hiero.otter.fixtures.result.SingleNodeStatusProgression;
16+
17+
/**
18+
* Assertions for {@link SingleNodeConsensusResult}.
19+
*/
20+
@SuppressWarnings("UnusedReturnValue")
21+
public class SingleNodeStatusProgressionAssert
22+
extends AbstractAssert<SingleNodeStatusProgressionAssert, SingleNodeStatusProgression> {
23+
24+
/**
25+
* Creates a new instance of {@link SingleNodeStatusProgressionAssert}.
26+
*
27+
* @param actual the actual {@link SingleNodeStatusProgression} to assert
28+
*/
29+
public SingleNodeStatusProgressionAssert(@Nullable final SingleNodeStatusProgression actual) {
30+
super(actual, SingleNodeStatusProgressionAssert.class);
31+
}
32+
33+
/**
34+
* Creates an assertion for the given {@link SingleNodeStatusProgression}.
35+
*
36+
* @param actual the {@link SingleNodeStatusProgression} to assert
37+
* @return an assertion for the given {@link SingleNodeStatusProgression}
38+
*/
39+
@NonNull
40+
public static SingleNodeStatusProgressionAssert assertThat(@Nullable final SingleNodeStatusProgression actual) {
41+
return new SingleNodeStatusProgressionAssert(actual);
42+
}
43+
44+
/**
45+
* Verifies that the node's statuses went exactly through the specified steps.
46+
*
47+
* @param first the first expected step
48+
* @param rest additional expected steps
49+
* @return this assertion object for method chaining
50+
*/
51+
@NonNull
52+
public SingleNodeStatusProgressionAssert hasSteps(
53+
@NonNull final StatusProgressionStep first, @Nullable final StatusProgressionStep... rest) {
54+
isNotNull();
55+
56+
final List<StatusProgressionStep> expectedSteps = new ArrayList<>();
57+
expectedSteps.add(first);
58+
if (rest != null) {
59+
expectedSteps.addAll(Arrays.asList(rest));
60+
}
61+
62+
int currentStepIndex = 0;
63+
final Set<PlatformStatus> observedStatuses = EnumSet.noneOf(PlatformStatus.class);
64+
for (final Iterator<PlatformStatus> actualStatusesIterator =
65+
actual.statusProgression().iterator();
66+
actualStatusesIterator.hasNext(); ) {
67+
final PlatformStatus actualStatus = actualStatusesIterator.next();
68+
final StatusProgressionStep currentStep = expectedSteps.get(currentStepIndex);
69+
if (actualStatus == currentStep.target()) {
70+
if (!observedStatuses.containsAll(currentStep.requiredInterim())) {
71+
failWithMessage(
72+
"Expected required interim statuses %s, but only got %s",
73+
currentStep.requiredInterim(), observedStatuses);
74+
}
75+
currentStepIndex++;
76+
if (currentStepIndex >= expectedSteps.size() && actualStatusesIterator.hasNext()) {
77+
failWithMessage(
78+
"Expected only %s steps, but encountered more statuses %s",
79+
expectedSteps.size(), actual.statusProgression());
80+
}
81+
observedStatuses.clear();
82+
} else {
83+
if (!currentStep.optionalInterim().contains(actualStatus)
84+
&& !currentStep.requiredInterim().contains(actualStatus)) {
85+
failWithMessage("Unexpected status %s in step %s", actualStatus, currentStep);
86+
}
87+
observedStatuses.add(actualStatus);
88+
}
89+
}
90+
91+
if (currentStepIndex < expectedSteps.size()) {
92+
failWithMessage("Expected %s steps, but only got %s", expectedSteps.size(), currentStepIndex);
93+
}
94+
95+
return this;
96+
}
97+
}

0 commit comments

Comments
 (0)