mirror of https://github.com/apache/kafka.git
KAFKA-16410 kafka-leader-election / LeaderElectionCommand doesn't set exit code on error (#15591)
Reviewers: Chia-Ping Tsai <chia7712@gmail.com>
This commit is contained in:
parent
0434c29e58
commit
7b2fc469ad
|
@ -28,6 +28,7 @@ import org.apache.kafka.common.TopicPartition;
|
||||||
import org.apache.kafka.common.errors.ClusterAuthorizationException;
|
import org.apache.kafka.common.errors.ClusterAuthorizationException;
|
||||||
import org.apache.kafka.common.errors.ElectionNotNeededException;
|
import org.apache.kafka.common.errors.ElectionNotNeededException;
|
||||||
import org.apache.kafka.common.errors.TimeoutException;
|
import org.apache.kafka.common.errors.TimeoutException;
|
||||||
|
import org.apache.kafka.common.utils.Exit;
|
||||||
import org.apache.kafka.common.utils.Utils;
|
import org.apache.kafka.common.utils.Utils;
|
||||||
import org.apache.kafka.server.common.AdminCommandFailedException;
|
import org.apache.kafka.server.common.AdminCommandFailedException;
|
||||||
import org.apache.kafka.server.common.AdminOperationException;
|
import org.apache.kafka.server.common.AdminOperationException;
|
||||||
|
@ -62,11 +63,17 @@ public class LeaderElectionCommand {
|
||||||
private static final DecodeJson.DecodeInteger INT = new DecodeJson.DecodeInteger();
|
private static final DecodeJson.DecodeInteger INT = new DecodeJson.DecodeInteger();
|
||||||
|
|
||||||
public static void main(String... args) {
|
public static void main(String... args) {
|
||||||
|
Exit.exit(mainNoExit(args));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mainNoExit(String... args) {
|
||||||
try {
|
try {
|
||||||
run(Duration.ofMillis(30000), args);
|
run(Duration.ofMillis(30000), args);
|
||||||
} catch (Exception e) {
|
return 0;
|
||||||
|
} catch (Throwable e) {
|
||||||
System.err.println(e.getMessage());
|
System.err.println(e.getMessage());
|
||||||
System.err.println(Utils.stackTrace(e));
|
System.err.println(Utils.stackTrace(e));
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
@ -31,46 +32,54 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
* cluster creation and cleanup because the command is expected to fail immediately.
|
* cluster creation and cleanup because the command is expected to fail immediately.
|
||||||
*/
|
*/
|
||||||
public class LeaderElectionCommandErrorTest {
|
public class LeaderElectionCommandErrorTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTopicWithoutPartition() {
|
public void testTopicWithoutPartition() {
|
||||||
String out = ToolsTestUtils.captureStandardErr(() -> LeaderElectionCommand.main(
|
String[] args = {
|
||||||
"--bootstrap-server", "nohost:9092",
|
"--bootstrap-server", "nohost:9092",
|
||||||
"--election-type", "unclean",
|
"--election-type", "unclean",
|
||||||
"--topic", "some-topic"
|
"--topic", "some-topic"
|
||||||
));
|
};
|
||||||
|
assertEquals(1, LeaderElectionCommand.mainNoExit(args));
|
||||||
|
String out = ToolsTestUtils.captureStandardErr(() -> LeaderElectionCommand.mainNoExit(args));
|
||||||
assertTrue(out.startsWith("Missing required option(s)"));
|
assertTrue(out.startsWith("Missing required option(s)"));
|
||||||
assertTrue(out.contains(" partition"));
|
assertTrue(out.contains(" partition"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPartitionWithoutTopic() {
|
public void testPartitionWithoutTopic() {
|
||||||
String out = ToolsTestUtils.captureStandardErr(() -> LeaderElectionCommand.main(
|
String[] args = {
|
||||||
"--bootstrap-server", "nohost:9092",
|
"--bootstrap-server", "nohost:9092",
|
||||||
"--election-type", "unclean",
|
"--election-type", "unclean",
|
||||||
"--all-topic-partitions",
|
"--all-topic-partitions",
|
||||||
"--partition", "0"
|
"--partition", "0"
|
||||||
));
|
};
|
||||||
String[] rows = out.split("\n");
|
assertEquals(1, LeaderElectionCommand.mainNoExit(args));
|
||||||
|
String out = ToolsTestUtils.captureStandardErr(() -> LeaderElectionCommand.mainNoExit(args));
|
||||||
assertTrue(out.startsWith("Option partition is only allowed if topic is used"));
|
assertTrue(out.startsWith("Option partition is only allowed if topic is used"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMissingElectionType() {
|
public void testMissingElectionType() {
|
||||||
String out = ToolsTestUtils.captureStandardErr(() -> LeaderElectionCommand.main(
|
String[] args = {
|
||||||
"--bootstrap-server", "nohost:9092",
|
"--bootstrap-server", "nohost:9092",
|
||||||
"--topic", "some-topic",
|
"--topic", "some-topic",
|
||||||
"--partition", "0"
|
"--partition", "0"
|
||||||
));
|
};
|
||||||
|
assertEquals(1, LeaderElectionCommand.mainNoExit(args));
|
||||||
|
String out = ToolsTestUtils.captureStandardErr(() -> LeaderElectionCommand.mainNoExit(args));
|
||||||
assertTrue(out.startsWith("Missing required option(s)"));
|
assertTrue(out.startsWith("Missing required option(s)"));
|
||||||
assertTrue(out.contains(" election-type"));
|
assertTrue(out.contains(" election-type"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMissingTopicPartitionSelection() {
|
public void testMissingTopicPartitionSelection() {
|
||||||
String out = ToolsTestUtils.captureStandardErr(() -> LeaderElectionCommand.main(
|
String[] args = {
|
||||||
"--bootstrap-server", "nohost:9092",
|
"--bootstrap-server", "nohost:9092",
|
||||||
"--election-type", "preferred"
|
"--election-type", "preferred"
|
||||||
));
|
};
|
||||||
|
assertEquals(1, LeaderElectionCommand.mainNoExit(args));
|
||||||
|
String out = ToolsTestUtils.captureStandardErr(() -> LeaderElectionCommand.mainNoExit(args));
|
||||||
assertTrue(out.startsWith("One and only one of the following options is required: "));
|
assertTrue(out.startsWith("One and only one of the following options is required: "));
|
||||||
assertTrue(out.contains(" all-topic-partitions"));
|
assertTrue(out.contains(" all-topic-partitions"));
|
||||||
assertTrue(out.contains(" topic"));
|
assertTrue(out.contains(" topic"));
|
||||||
|
|
|
@ -105,11 +105,11 @@ public class LeaderElectionCommandTest {
|
||||||
cluster.startBroker(broker3);
|
cluster.startBroker(broker3);
|
||||||
TestUtils.waitForOnlineBroker(client, broker3);
|
TestUtils.waitForOnlineBroker(client, broker3);
|
||||||
|
|
||||||
LeaderElectionCommand.main(
|
assertEquals(0, LeaderElectionCommand.mainNoExit(
|
||||||
"--bootstrap-server", cluster.bootstrapServers(),
|
"--bootstrap-server", cluster.bootstrapServers(),
|
||||||
"--election-type", "unclean",
|
"--election-type", "unclean",
|
||||||
"--all-topic-partitions"
|
"--all-topic-partitions"
|
||||||
);
|
));
|
||||||
|
|
||||||
TestUtils.assertLeader(client, topicPartition, broker3);
|
TestUtils.assertLeader(client, topicPartition, broker3);
|
||||||
}
|
}
|
||||||
|
@ -121,11 +121,11 @@ public class LeaderElectionCommandTest {
|
||||||
Path adminConfigPath = tempAdminConfig(defaultApiTimeoutMs, requestTimeoutMs);
|
Path adminConfigPath = tempAdminConfig(defaultApiTimeoutMs, requestTimeoutMs);
|
||||||
|
|
||||||
try (final MockedStatic<Admin> mockedAdmin = Mockito.mockStatic(Admin.class)) {
|
try (final MockedStatic<Admin> mockedAdmin = Mockito.mockStatic(Admin.class)) {
|
||||||
LeaderElectionCommand.main(
|
assertEquals(1, LeaderElectionCommand.mainNoExit(
|
||||||
"--bootstrap-server", cluster.bootstrapServers(),
|
"--bootstrap-server", cluster.bootstrapServers(),
|
||||||
"--election-type", "unclean", "--all-topic-partitions",
|
"--election-type", "unclean", "--all-topic-partitions",
|
||||||
"--admin.config", adminConfigPath.toString()
|
"--admin.config", adminConfigPath.toString()
|
||||||
);
|
));
|
||||||
|
|
||||||
ArgumentCaptor<Properties> argumentCaptor = ArgumentCaptor.forClass(Properties.class);
|
ArgumentCaptor<Properties> argumentCaptor = ArgumentCaptor.forClass(Properties.class);
|
||||||
mockedAdmin.verify(() -> Admin.create(argumentCaptor.capture()));
|
mockedAdmin.verify(() -> Admin.create(argumentCaptor.capture()));
|
||||||
|
@ -161,12 +161,12 @@ public class LeaderElectionCommandTest {
|
||||||
cluster.startBroker(broker3);
|
cluster.startBroker(broker3);
|
||||||
TestUtils.waitForOnlineBroker(client, broker3);
|
TestUtils.waitForOnlineBroker(client, broker3);
|
||||||
|
|
||||||
LeaderElectionCommand.main(
|
assertEquals(0, LeaderElectionCommand.mainNoExit(
|
||||||
"--bootstrap-server", cluster.bootstrapServers(),
|
"--bootstrap-server", cluster.bootstrapServers(),
|
||||||
"--election-type", "unclean",
|
"--election-type", "unclean",
|
||||||
"--topic", topic,
|
"--topic", topic,
|
||||||
"--partition", Integer.toString(partition)
|
"--partition", Integer.toString(partition)
|
||||||
);
|
));
|
||||||
|
|
||||||
TestUtils.assertLeader(client, topicPartition, broker3);
|
TestUtils.assertLeader(client, topicPartition, broker3);
|
||||||
}
|
}
|
||||||
|
@ -200,11 +200,11 @@ public class LeaderElectionCommandTest {
|
||||||
|
|
||||||
Path topicPartitionPath = tempTopicPartitionFile(Collections.singletonList(topicPartition));
|
Path topicPartitionPath = tempTopicPartitionFile(Collections.singletonList(topicPartition));
|
||||||
|
|
||||||
LeaderElectionCommand.main(
|
assertEquals(0, LeaderElectionCommand.mainNoExit(
|
||||||
"--bootstrap-server", cluster.bootstrapServers(),
|
"--bootstrap-server", cluster.bootstrapServers(),
|
||||||
"--election-type", "unclean",
|
"--election-type", "unclean",
|
||||||
"--path-to-json-file", topicPartitionPath.toString()
|
"--path-to-json-file", topicPartitionPath.toString()
|
||||||
);
|
));
|
||||||
|
|
||||||
TestUtils.assertLeader(client, topicPartition, broker3);
|
TestUtils.assertLeader(client, topicPartition, broker3);
|
||||||
}
|
}
|
||||||
|
@ -233,11 +233,11 @@ public class LeaderElectionCommandTest {
|
||||||
JavaConverters.asScalaBuffer(Collections.singletonList(broker2)).toSet()
|
JavaConverters.asScalaBuffer(Collections.singletonList(broker2)).toSet()
|
||||||
);
|
);
|
||||||
|
|
||||||
LeaderElectionCommand.main(
|
assertEquals(0, LeaderElectionCommand.mainNoExit(
|
||||||
"--bootstrap-server", cluster.bootstrapServers(),
|
"--bootstrap-server", cluster.bootstrapServers(),
|
||||||
"--election-type", "preferred",
|
"--election-type", "preferred",
|
||||||
"--all-topic-partitions"
|
"--all-topic-partitions"
|
||||||
);
|
));
|
||||||
|
|
||||||
TestUtils.assertLeader(client, topicPartition, broker2);
|
TestUtils.assertLeader(client, topicPartition, broker2);
|
||||||
}
|
}
|
||||||
|
@ -288,7 +288,7 @@ public class LeaderElectionCommandTest {
|
||||||
|
|
||||||
Path topicPartitionPath = tempTopicPartitionFile(Arrays.asList(topicPartition0, topicPartition1));
|
Path topicPartitionPath = tempTopicPartitionFile(Arrays.asList(topicPartition0, topicPartition1));
|
||||||
String output = ToolsTestUtils.captureStandardOut(() ->
|
String output = ToolsTestUtils.captureStandardOut(() ->
|
||||||
LeaderElectionCommand.main(
|
LeaderElectionCommand.mainNoExit(
|
||||||
"--bootstrap-server", cluster.bootstrapServers(),
|
"--bootstrap-server", cluster.bootstrapServers(),
|
||||||
"--election-type", "preferred",
|
"--election-type", "preferred",
|
||||||
"--path-to-json-file", topicPartitionPath.toString()
|
"--path-to-json-file", topicPartitionPath.toString()
|
||||||
|
|
Loading…
Reference in New Issue