diff --git a/hadoop-hdds/tools/pom.xml b/hadoop-hdds/tools/pom.xml
index 071e972f6651..7f37a36b6555 100644
--- a/hadoop-hdds/tools/pom.xml
+++ b/hadoop-hdds/tools/pom.xml
@@ -140,6 +140,11 @@
test-jar
test
+
+ org.apache.ozone
+ hdds-test-utils
+ test
+
diff --git a/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/ContainerBalancerStatusSubcommand.java b/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/ContainerBalancerStatusSubcommand.java
index 8abc7a2dd5cb..7edecd782207 100644
--- a/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/ContainerBalancerStatusSubcommand.java
+++ b/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/ContainerBalancerStatusSubcommand.java
@@ -26,6 +26,7 @@
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.hadoop.hdds.cli.HddsVersionProvider;
@@ -69,7 +70,9 @@ public void execute(ScmClient scmClient) throws IOException {
System.out.println("ContainerBalancer is Running.");
if (verbose) {
- System.out.printf("Started at: %s %s%n", dateTime.toLocalDate(), dateTime.toLocalTime());
+ System.out.printf("Started at: %s %s%n",
+ dateTime.toLocalDate().format(DateTimeFormatter.ISO_LOCAL_DATE),
+ dateTime.toLocalTime().format(DateTimeFormatter.ISO_LOCAL_TIME));
Duration balancingDuration = Duration.between(startedAtInstant, OffsetDateTime.now());
System.out.printf("Balancing duration: %s%n%n", getPrettyDuration(balancingDuration));
System.out.println(getConfigurationPrettyString(balancerStatusInfo.getConfiguration()));
diff --git a/hadoop-hdds/tools/src/test/java/org/apache/hadoop/hdds/scm/cli/datanode/TestContainerBalancerSubCommand.java b/hadoop-hdds/tools/src/test/java/org/apache/hadoop/hdds/scm/cli/datanode/TestContainerBalancerSubCommand.java
index 0594ae38abf5..30919d525fef 100644
--- a/hadoop-hdds/tools/src/test/java/org/apache/hadoop/hdds/scm/cli/datanode/TestContainerBalancerSubCommand.java
+++ b/hadoop-hdds/tools/src/test/java/org/apache/hadoop/hdds/scm/cli/datanode/TestContainerBalancerSubCommand.java
@@ -18,19 +18,13 @@
package org.apache.hadoop.hdds.scm.cli.datanode;
import static org.apache.hadoop.ozone.OzoneConsts.GB;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-import java.io.ByteArrayOutputStream;
import java.io.IOException;
-import java.io.PrintStream;
-import java.io.UnsupportedEncodingException;
-import java.nio.charset.StandardCharsets;
import java.time.OffsetDateTime;
import java.util.Arrays;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.hadoop.hdds.protocol.proto.StorageContainerLocationProtocolProtos;
import org.apache.hadoop.hdds.protocol.proto.StorageContainerLocationProtocolProtos.ContainerBalancerStatusInfoProto;
@@ -40,6 +34,8 @@
import org.apache.hadoop.hdds.scm.cli.ContainerBalancerStopSubcommand;
import org.apache.hadoop.hdds.scm.client.ScmClient;
import org.apache.hadoop.hdds.scm.container.balancer.ContainerBalancerConfiguration;
+import org.apache.hadoop.hdds.utils.IOUtils;
+import org.apache.ozone.test.GenericTestUtils;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -51,14 +47,44 @@
*/
class TestContainerBalancerSubCommand {
- private static final String DEFAULT_ENCODING = StandardCharsets.UTF_8.name();
- private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
- private final ByteArrayOutputStream errContent = new ByteArrayOutputStream();
- private final PrintStream originalOut = System.out;
- private final PrintStream originalErr = System.err;
+ private static final Pattern DURATION = Pattern.compile(
+ "^Balancing duration: \\d{1}s$", Pattern.MULTILINE);
+ private static final Pattern FAILED_TO_START = Pattern.compile(
+ "^Failed\\sto\\sstart\\sContainer\\sBalancer.");
+ private static final Pattern IS_NOT_RUNNING = Pattern.compile(
+ "^ContainerBalancer\\sis\\sNot\\sRunning.");
+ private static final Pattern IS_RUNNING = Pattern.compile(
+ "^ContainerBalancer\\sis\\sRunning.$", Pattern.MULTILINE);
+ private static final Pattern STARTED_AT = Pattern.compile(
+ "^Started at: (\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2})$", Pattern.MULTILINE);
+ private static final Pattern STARTED_SUCCESSFULLY = Pattern.compile(
+ "^Container\\sBalancer\\sstarted\\ssuccessfully.");
+ private static final Pattern WAITING_TO_STOP = Pattern.compile(
+ "^Sending\\sstop\\scommand.\\sWaiting\\sfor\\sContainer\\sBalancer\\sto\\sstop...\\n" +
+ "Container\\sBalancer\\sstopped.");
+
+ private static final String BALANCER_CONFIG_OUTPUT = "Container Balancer Configuration values:\n" +
+ "Key Value\n" +
+ "Threshold 10.0\n" +
+ "Max Datanodes to Involve per Iteration(percent) 20\n" +
+ "Max Size to Move per Iteration 0GB\n" +
+ "Max Size Entering Target per Iteration 26GB\n" +
+ "Max Size Leaving Source per Iteration 26GB\n" +
+ "Number of Iterations 3\n" +
+ "Time Limit for Single Container's Movement 65min\n" +
+ "Time Limit for Single Container's Replication 50min\n" +
+ "Interval between each Iteration 0min\n" +
+ "Whether to Enable Network Topology false\n" +
+ "Whether to Trigger Refresh Datanode Usage Info false\n" +
+ "Container IDs to Exclude from Balancing None\n" +
+ "Datanodes Specified to be Balanced None\n" +
+ "Datanodes Excluded from Balancing None";
+
private ContainerBalancerStopSubcommand stopCmd;
private ContainerBalancerStartSubcommand startCmd;
private ContainerBalancerStatusSubcommand statusCmd;
+ private GenericTestUtils.PrintStreamCapturer out;
+ private GenericTestUtils.PrintStreamCapturer err;
private static ContainerBalancerStatusInfoResponseProto getContainerBalancerStatusInfoResponseProto(
ContainerBalancerConfiguration config) {
@@ -203,18 +229,17 @@ private static ContainerBalancerConfiguration getContainerBalancerConfiguration(
}
@BeforeEach
- public void setup() throws UnsupportedEncodingException {
+ void setup() {
stopCmd = new ContainerBalancerStopSubcommand();
startCmd = new ContainerBalancerStartSubcommand();
statusCmd = new ContainerBalancerStatusSubcommand();
- System.setOut(new PrintStream(outContent, false, DEFAULT_ENCODING));
- System.setErr(new PrintStream(errContent, false, DEFAULT_ENCODING));
+ out = GenericTestUtils.captureOut();
+ err = GenericTestUtils.captureErr();
}
@AfterEach
- public void tearDown() {
- System.setOut(originalOut);
- System.setErr(originalErr);
+ void tearDown() {
+ IOUtils.closeQuietly(out, err);
}
@Test
@@ -230,30 +255,6 @@ void testContainerBalancerStatusInfoSubcommandRunningWithoutFlags()
//test status is running
when(scmClient.getContainerBalancerStatusInfo()).thenReturn(statusInfoResponseProto);
statusCmd.execute(scmClient);
- Pattern p = Pattern.compile(
- "^ContainerBalancer\\sis\\sRunning.");
- String output = outContent.toString(DEFAULT_ENCODING);
- Matcher m = p.matcher(output);
- assertTrue(m.find());
-
- String balancerConfigOutput =
- "Container Balancer Configuration values:\n" +
- "Key Value\n" +
- "Threshold 10.0\n" +
- "Max Datanodes to Involve per Iteration(percent) 20\n" +
- "Max Size to Move per Iteration 0GB\n" +
- "Max Size Entering Target per Iteration 26GB\n" +
- "Max Size Leaving Source per Iteration 26GB\n" +
- "Number of Iterations 3\n" +
- "Time Limit for Single Container's Movement 65min\n" +
- "Time Limit for Single Container's Replication 50min\n" +
- "Interval between each Iteration 0min\n" +
- "Whether to Enable Network Topology false\n" +
- "Whether to Trigger Refresh Datanode Usage Info false\n" +
- "Container IDs to Exclude from Balancing None\n" +
- "Datanodes Specified to be Balanced None\n" +
- "Datanodes Excluded from Balancing None";
- assertFalse(output.contains(balancerConfigOutput));
String currentIterationOutput =
"Current iteration info:\n" +
@@ -273,9 +274,11 @@ void testContainerBalancerStatusInfoSubcommandRunningWithoutFlags()
"Exited data from nodes \n" +
"b8b9c511-c30f-4933-8938-2f272e307070 -> 30 GB\n" +
"7bd99815-47e7-4015-bc61-ca6ef6dfd130 -> 18 GB";
- assertFalse(output.contains(currentIterationOutput));
- assertFalse(output.contains("Iteration history list:"));
+ assertThat(out.get()).containsPattern(IS_RUNNING)
+ .doesNotContain(BALANCER_CONFIG_OUTPUT)
+ .doesNotContain(currentIterationOutput)
+ .doesNotContain("Iteration history list:");
}
@Test
@@ -293,42 +296,7 @@ void testContainerBalancerStatusInfoSubcommandVerboseHistory()
CommandLine c = new CommandLine(statusCmd);
c.parseArgs("--verbose", "--history");
statusCmd.execute(scmClient);
- String output = outContent.toString(DEFAULT_ENCODING);
- Pattern p = Pattern.compile(
- "^ContainerBalancer\\sis\\sRunning.$", Pattern.MULTILINE);
- Matcher m = p.matcher(output);
- assertTrue(m.find());
-
- p = Pattern.compile(
- "^Started at: (\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2})$", Pattern.MULTILINE);
- m = p.matcher(output);
- assertTrue(m.find());
-
- p = Pattern.compile(
- "^Balancing duration: \\d{1}s$", Pattern.MULTILINE);
- m = p.matcher(output);
- assertTrue(m.find());
-
- String balancerConfigOutput =
- "Container Balancer Configuration values:\n" +
- "Key Value\n" +
- "Threshold 10.0\n" +
- "Max Datanodes to Involve per Iteration(percent) 20\n" +
- "Max Size to Move per Iteration 0GB\n" +
- "Max Size Entering Target per Iteration 26GB\n" +
- "Max Size Leaving Source per Iteration 26GB\n" +
- "Number of Iterations 3\n" +
- "Time Limit for Single Container's Movement 65min\n" +
- "Time Limit for Single Container's Replication 50min\n" +
- "Interval between each Iteration 0min\n" +
- "Whether to Enable Network Topology false\n" +
- "Whether to Trigger Refresh Datanode Usage Info false\n" +
- "Container IDs to Exclude from Balancing None\n" +
- "Datanodes Specified to be Balanced None\n" +
- "Datanodes Excluded from Balancing None";
- assertTrue(output.contains(balancerConfigOutput));
-
- assertTrue(output.contains("Iteration history list:"));
+
String firstHistoryIterationOutput =
"Key Value\n" +
"Iteration number 3\n" +
@@ -346,7 +314,6 @@ void testContainerBalancerStatusInfoSubcommandVerboseHistory()
"Exited data from nodes \n" +
"b8b9c511-c30f-4933-8938-2f272e307070 -> 30 GB\n" +
"7bd99815-47e7-4015-bc61-ca6ef6dfd130 -> 18 GB";
- assertTrue(output.contains(firstHistoryIterationOutput));
String secondHistoryIterationOutput =
"Key Value\n" +
@@ -365,7 +332,15 @@ void testContainerBalancerStatusInfoSubcommandVerboseHistory()
"Exited data from nodes \n" +
"b8b9c511-c30f-4933-8938-2f272e307070 -> 15 GB\n" +
"7bd99815-47e7-4015-bc61-ca6ef6dfd130 -> 15 GB";
- assertTrue(output.contains(secondHistoryIterationOutput));
+
+ assertThat(out.get())
+ .containsPattern(IS_RUNNING)
+ .containsPattern(STARTED_AT)
+ .containsPattern(DURATION)
+ .contains(BALANCER_CONFIG_OUTPUT)
+ .contains("Iteration history list:")
+ .contains(firstHistoryIterationOutput)
+ .contains(secondHistoryIterationOutput);
}
@Test
@@ -383,40 +358,6 @@ void testContainerBalancerStatusInfoSubcommandVerbose()
CommandLine c = new CommandLine(statusCmd);
c.parseArgs("--verbose");
statusCmd.execute(scmClient);
- String output = outContent.toString(DEFAULT_ENCODING);
- Pattern p = Pattern.compile(
- "^ContainerBalancer\\sis\\sRunning.$", Pattern.MULTILINE);
- Matcher m = p.matcher(output);
- assertTrue(m.find());
-
- p = Pattern.compile(
- "^Started at: (\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2})$", Pattern.MULTILINE);
- m = p.matcher(output);
- assertTrue(m.find());
-
- p = Pattern.compile(
- "^Balancing duration: \\d{1}s$", Pattern.MULTILINE);
- m = p.matcher(output);
- assertTrue(m.find());
-
- String balancerConfigOutput =
- "Container Balancer Configuration values:\n" +
- "Key Value\n" +
- "Threshold 10.0\n" +
- "Max Datanodes to Involve per Iteration(percent) 20\n" +
- "Max Size to Move per Iteration 0GB\n" +
- "Max Size Entering Target per Iteration 26GB\n" +
- "Max Size Leaving Source per Iteration 26GB\n" +
- "Number of Iterations 3\n" +
- "Time Limit for Single Container's Movement 65min\n" +
- "Time Limit for Single Container's Replication 50min\n" +
- "Interval between each Iteration 0min\n" +
- "Whether to Enable Network Topology false\n" +
- "Whether to Trigger Refresh Datanode Usage Info false\n" +
- "Container IDs to Exclude from Balancing None\n" +
- "Datanodes Specified to be Balanced None\n" +
- "Datanodes Excluded from Balancing None";
- assertTrue(output.contains(balancerConfigOutput));
String currentIterationOutput =
"Current iteration info:\n" +
@@ -436,9 +377,14 @@ void testContainerBalancerStatusInfoSubcommandVerbose()
"Exited data from nodes \n" +
"b8b9c511-c30f-4933-8938-2f272e307070 -> 30 GB\n" +
"7bd99815-47e7-4015-bc61-ca6ef6dfd130 -> 18 GB";
- assertTrue(output.contains(currentIterationOutput));
- assertFalse(output.contains("Iteration history list:"));
+ assertThat(out.get())
+ .containsPattern(IS_RUNNING)
+ .containsPattern(STARTED_AT)
+ .containsPattern(DURATION)
+ .contains(BALANCER_CONFIG_OUTPUT)
+ .contains(currentIterationOutput)
+ .doesNotContain("Iteration history list:");
}
@Test
@@ -453,10 +399,7 @@ void testContainerBalancerStatusInfoSubcommandRunningOnStoppedBalancer()
.build());
statusCmd.execute(scmClient);
- Pattern p = Pattern.compile(
- "^ContainerBalancer\\sis\\sNot\\sRunning.");
- Matcher m = p.matcher(outContent.toString(DEFAULT_ENCODING));
- assertTrue(m.find());
+ assertThat(out.get()).containsPattern(IS_NOT_RUNNING);
}
@Test
@@ -471,10 +414,7 @@ void testContainerBalancerStatusSubcommandNotRunning()
statusCmd.execute(scmClient);
- Pattern p = Pattern.compile(
- "^ContainerBalancer\\sis\\sNot\\sRunning.");
- Matcher m = p.matcher(outContent.toString(DEFAULT_ENCODING));
- assertTrue(m.find());
+ assertThat(out.get()).containsPattern(IS_NOT_RUNNING);
}
@Test
@@ -482,12 +422,7 @@ public void testContainerBalancerStopSubcommand() throws IOException {
ScmClient scmClient = mock(ScmClient.class);
stopCmd.execute(scmClient);
- Pattern p = Pattern.compile("^Sending\\sstop\\scommand." +
- "\\sWaiting\\sfor\\sContainer\\sBalancer\\sto\\sstop...\\n" +
- "Container\\sBalancer\\sstopped.");
-
- Matcher m = p.matcher(outContent.toString(DEFAULT_ENCODING));
- assertTrue(m.find());
+ assertThat(out.get()).containsPattern(WAITING_TO_STOP);
}
@Test
@@ -503,10 +438,7 @@ public void testContainerBalancerStartSubcommandWhenBalancerIsNotRunning()
.build());
startCmd.execute(scmClient);
- Pattern p = Pattern.compile("^Container\\sBalancer\\sstarted" +
- "\\ssuccessfully.");
- Matcher m = p.matcher(outContent.toString(DEFAULT_ENCODING));
- assertTrue(m.find());
+ assertThat(out.get()).containsPattern(STARTED_SUCCESSFULLY);
}
@Test
@@ -522,11 +454,7 @@ public void testContainerBalancerStartSubcommandWhenBalancerIsRunning()
.build());
startCmd.execute(scmClient);
- Pattern p = Pattern.compile("^Failed\\sto\\sstart\\sContainer" +
- "\\sBalancer.");
-
- Matcher m = p.matcher(outContent.toString(DEFAULT_ENCODING));
- assertTrue(m.find());
+ assertThat(out.get()).containsPattern(FAILED_TO_START);
}
}