gnodet-bot commented on code in PR #28243:
URL: https://github.com/apache/camel/pull/28243#discussion_r4358161411


##########
components/camel-jgroups-raft/src/test/java/org/apache/camel/component/jgroups/raft/cluster/JGroupsRaftClusterAbstractTest.java:
##########
@@ -16,39 +16,88 @@
  */
 package org.apache.camel.component.jgroups.raft.cluster;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.TimeUnit;
 
+import org.apache.camel.CamelContext;
+import org.apache.camel.component.jgroups.raft.RaftNodesState;
+import org.awaitility.core.ConditionTimeoutException;
 import org.jgroups.JChannel;
 import org.jgroups.raft.RaftHandle;
+import org.jgroups.raft.StateMachine;
+import org.junit.jupiter.api.AfterEach;
 
 import static org.awaitility.Awaitility.await;
 
 public abstract class JGroupsRaftClusterAbstractTest {
 
+    protected final List<CamelContext> contexts = new ArrayList<>();
+    protected final List<String> routeNames = new ArrayList<>();
+    private final List<RaftHandle> openHandles = new ArrayList<>();
+
+    /**
+     * The channels are registered in the static routing table of 
SHARED_LOOPBACK, so a channel left open by a failed
+     * test would make a rerun of the test fail on joining with the same 
member names ("duplicate members"), and would
+     * hide the reason of the first failure.
+     */
+    @AfterEach
+    void closeAll() {
+        for (CamelContext context : contexts) {
+            try {
+                context.stop();
+            } catch (Exception e) {
+                // best effort cleanup
+            }
+        }
+        for (RaftHandle handle : openHandles) {
+            JChannel channel = handle.channel();
+            if (channel != null) {
+                channel.close();
+            }
+        }
+        contexts.clear();
+        routeNames.clear();
+        openHandles.clear();
+    }
+
+    /**
+     * Create the Raft handle of a node and keep track of it, so that its 
channel is closed at the end of the test.
+     */
+    protected RaftHandle createHandle(String id, StateMachine stateMachine) 
throws Exception {
+        RaftHandle handle = new RaftHandle(new 
JChannel("raftABC.xml").name(id), stateMachine).raftId(id);
+        openHandles.add(handle);
+        return handle;
+    }
+
     /**
      * Wait until a leader has been elected AND all given handles know who the 
leader is. Only connected handles are
      * checked; disconnected or closed handles are skipped. Without checking 
leader() on every active handle, a follower
      * node may not yet have discovered the leader, causing set() to throw 
when the REDIRECT protocol has no leader
      * address to forward to.
      */
     protected void waitForLeader(int attempts, RaftHandle... handles) {
-        await().atMost(attempts, TimeUnit.SECONDS)
-                .pollInterval(500, TimeUnit.MILLISECONDS)
-                .until(() -> {
-                    boolean hasLeader = false;
-                    for (RaftHandle rh : handles) {
-                        if (!rh.channel().isConnected()) {
-                            continue;
-                        }
-                        if (rh.isLeader()) {
-                            hasLeader = true;
-                        }
-                        if (rh.leader() == null) {
-                            return false;
+        try {
+            await().atMost(attempts, TimeUnit.SECONDS)
+                    .pollInterval(500, TimeUnit.MILLISECONDS)
+                    .until(() -> {
+                        boolean hasLeader = false;
+                        for (RaftHandle rh : handles) {
+                            if (!rh.channel().isConnected()) {
+                                continue;
+                            }
+                            if (rh.isLeader()) {
+                                hasLeader = true;
+                            }
+                            if (rh.leader() == null) {
+                                return false;
+                            }
                         }
-                    }
-                    return hasLeader;
-                });
+                        return hasLeader;
+                    });
+        } catch (ConditionTimeoutException e) {
+            throw new ConditionTimeoutException(e.getMessage() + 
System.lineSeparator() + RaftNodesState.describe(handles), e);

Review Comment:
   💡 **Note:** If following @davsclaus's suggestion to drop the 
`RaftNodesState.` qualifier, this would not compile — `describe()` is a 
`static` method of `RaftNodesState` and the current import is a plain class 
import (`import org.apache.camel.component.jgroups.raft.RaftNodesState;`), not 
a static one. The qualifier is correct as-is. To use bare `describe(handles)` 
you would need to add:
   
   ```java
   import static 
org.apache.camel.component.jgroups.raft.RaftNodesState.describe;
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to