brandboat commented on code in PR #22531:
URL: https://github.com/apache/kafka/pull/22531#discussion_r3488265083


##########
tools/src/test/java/org/apache/kafka/tools/MetadataQuorumCommandTest.java:
##########
@@ -194,4 +198,60 @@ private static void assertHumanReadable(String output) {
         assertTrue(lastCaughtUpTimestamp.contains("ms ago"));
         assertTrue(lastCaughtUpTimestampValue.matches("\\d*"));
     }
+
+    /**
+     * Verify that add-controller and remove-controller work using only the
+     * controller node ID (no directory ID or endpoints required from the 
user).
+     */
+    @ClusterTest(types = {Type.KRAFT}, controllers = 2, standalone = true)
+    public void testAddAndRemoveControllerByIdSuccessful(ClusterInstance 
cluster) throws Exception {

Review Comment:
   > Could we addVoter with [node ID, directory ID] or [node ID, endpoint] ?
   
   Sure, I've refined the test case, please check 
`KafkaRaftClientReconfigTest#testAddVoterDerivesMissingDirectoryIdAndEndpoints`
   
   > If [node ID, directory ID] or [node ID, endpoint] doesn't match with each 
other, ex: wrong directory ID/endpoint to the node, what will happen? Could we 
also add tests for them?
   
   This should behave the same in both v1 and v2 as I didn't do validation if 
user explicitly specify both directory and endpoints, and should make 
AddVoterHandler returns 
REQUEST_TIMED_OUT[[1](https://github.com/apache/kafka/blob/1d953172b99306e5c31982a08a58ecc90130c96d/raft/src/main/java/org/apache/kafka/raft/LeaderState.java#L419)][[2](https://github.com/apache/kafka/blob/1d953172b99306e5c31982a08a58ecc90130c96d/raft/src/main/java/org/apache/kafka/raft/internals/AddVoterHandler.java#L294)].
   
   Regarding the test, I currently have the integration test below, but I think 
this behavior is better covered by a unit test (it's much easier to test 
different protocol version). I'll try to figure out how to implement it as a 
unit test tomorrow.
   
   ```java
       @ClusterTest(controllers = 3, standalone = true)
       public void testAddRaftVoterWithMismatchedDirectoryId(ClusterInstance 
clusterInstance) throws Exception {
           for (boolean usingBootstrapControllers : List.of(false, true)) {
               try (Admin admin = Admin.create(adminConfig(clusterInstance, 
usingBootstrapControllers))) {
                   QuorumInfo quorumInfo = 
admin.describeMetadataQuorum().quorumInfo().get();
                   QuorumInfo.ReplicaState observer = 
controllerObserver(clusterInstance, quorumInfo);
                   Uuid anotherObserverDirectoryId = 
quorumInfo.observers().stream()
                       .filter(replica -> replica.replicaId() != 
observer.replicaId())
                       .map(QuorumInfo.ReplicaState::replicaDirectoryId)
                       .filter(directoryId -> 
!directoryId.equals(observer.replicaDirectoryId()))
                       .findFirst()
                       .orElseGet(Uuid::randomUuid);
   
                   TestUtils.assertFutureThrowsWithMessageMatching(
                       TimeoutException.class,
                       admin.addRaftVoter(
                           observer.replicaId(),
                           anotherObserverDirectoryId,
                           Set.of(controllerEndpoint(clusterInstance, 
observer.replicaId())),
                           new AddRaftVoterOptions().timeoutMs(5_000)
                       ).all(),
                       "Aborted add voter operation for .* since it is lagging 
behind"
                   );
                   
assertFalse(voterIds(admin.describeMetadataQuorum().quorumInfo().get()).contains(observer.replicaId()));
               }
           }
       }
   
       private static QuorumInfo.ReplicaState controllerObserver(
           ClusterInstance clusterInstance,
           QuorumInfo quorumInfo
       ) {
           return quorumInfo.observers().stream()
               .filter(observer -> 
clusterInstance.controllerIds().contains(observer.replicaId()))
               .findFirst()
               .orElseThrow(() -> new AssertionError("Expected at least one 
controller observer in quorum info " + quorumInfo));
       }
   
       private static RaftVoterEndpoint controllerEndpoint(ClusterInstance 
clusterInstance, int nodeId) {
           var controller = clusterInstance.controllers().get(nodeId);
           if (controller == null) {
               throw new AssertionError("Expected controller " + nodeId + " in 
cluster " + clusterInstance.controllers().keySet());
           }
           return new RaftVoterEndpoint(
               clusterInstance.controllerListenerName().value(),
               "localhost",
               
controller.socketServer().boundPort(clusterInstance.controllerListenerName())
           );
       }
   ```



-- 
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