You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pulsar.apache.org by si...@apache.org on 2018/07/27 18:10:08 UTC

[incubator-pulsar] branch master updated: Throw exception on non-zero command exit in integ tests (#2249)

This is an automated email from the ASF dual-hosted git repository.

sijie pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-pulsar.git


The following commit(s) were added to refs/heads/master by this push:
     new e2aca36  Throw exception on non-zero command exit in integ tests (#2249)
e2aca36 is described below

commit e2aca368910c437e4d8eefe826ffb6cf86b232da
Author: Ivan Kelly <iv...@apache.org>
AuthorDate: Fri Jul 27 19:10:05 2018 +0100

    Throw exception on non-zero command exit in integ tests (#2249)
    
    This patch replaces the boolean flag to ignore failure, and instead
    always throws an exception if a command exits with non-zero. This
    means that test code doesn't need to check the exit code for each
    invokation. For non-zero exits, the ContainerExecResult is carried as
    part of the exception, so the test can also assert on the contents of
    stdout, stderr and the exit code.
---
 .../pulsar/tests/integration/cli/CLITest.java      | 52 ++++++++++------------
 .../integration/containers/ChaosContainer.java     |  3 +-
 .../integration/docker/ContainerExecException.java | 32 +++++++++++++
 .../runtime/PulsarFunctionsRuntimeTest.java        | 28 ++++++------
 .../tests/integration/io/PulsarIOSinkTest.java     | 40 ++++++++++-------
 .../tests/integration/io/PulsarIOSourceTest.java   | 39 +++++++++-------
 .../tests/integration/utils/DockerUtils.java       | 29 ++++--------
 7 files changed, 129 insertions(+), 94 deletions(-)

diff --git a/tests/integration/src/test/java/org/apache/pulsar/tests/integration/cli/CLITest.java b/tests/integration/src/test/java/org/apache/pulsar/tests/integration/cli/CLITest.java
index 22cc937..acdae26 100644
--- a/tests/integration/src/test/java/org/apache/pulsar/tests/integration/cli/CLITest.java
+++ b/tests/integration/src/test/java/org/apache/pulsar/tests/integration/cli/CLITest.java
@@ -22,8 +22,10 @@ import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertNotEquals;
 import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
 
 import org.apache.pulsar.tests.integration.containers.BrokerContainer;
+import org.apache.pulsar.tests.integration.docker.ContainerExecException;
 import org.apache.pulsar.tests.integration.docker.ContainerExecResult;
 import org.apache.pulsar.tests.integration.topologies.PulsarCluster;
 import org.apache.pulsar.tests.integration.topologies.PulsarClusterTestBase;
@@ -39,7 +41,6 @@ public class CLITest extends PulsarClusterTestBase {
         String tenantName = "test-deprecated-commands";
 
         ContainerExecResult result = pulsarCluster.runAdminCommandOnAnyBroker("--help");
-        assertEquals(0, result.getExitCode());
         assertFalse(result.getStdout().isEmpty());
         assertFalse(result.getStdout().contains("Usage: properties "));
         result = pulsarCluster.runAdminCommandOnAnyBroker(
@@ -73,7 +74,6 @@ public class CLITest extends PulsarClusterTestBase {
                 "--subscription",
                 "" + subscriptionPrefix + i
             );
-            assertEquals(0, result.getExitCode());
             assertTrue(result.getStdout().isEmpty());
             assertTrue(result.getStderr().isEmpty());
             i++;
@@ -93,7 +93,6 @@ public class CLITest extends PulsarClusterTestBase {
             "1",
             topicName);
 
-        assertEquals(0, result.getExitCode());
         assertTrue(result.getStdout().contains("1 messages successfully produced"));
 
         // terminate the topic
@@ -102,20 +101,21 @@ public class CLITest extends PulsarClusterTestBase {
             "persistent",
             "terminate",
             topicName);
-        assertEquals(0, result.getExitCode());
         assertTrue(result.getStdout().contains("Topic succesfully terminated at"));
 
         // try to produce should fail
-        result = pulsarCluster.getAnyBroker().execCmd(
-            PulsarCluster.CLIENT_SCRIPT,
-            "produce",
-            "-m",
-            "\"test topic termination\"",
-            "-n",
-            "1",
-            topicName);
-        assertNotEquals(0, result.getExitCode());
-        assertTrue(result.getStdout().contains("Topic was already terminated"));
+        try {
+            pulsarCluster.getAnyBroker().execCmd(PulsarCluster.CLIENT_SCRIPT,
+                                                 "produce",
+                                                 "-m",
+                                                 "\"test topic termination\"",
+                                                 "-n",
+                                                 "1",
+                                                 topicName);
+            fail("Command should have exited with non-zero");
+        } catch (ContainerExecException e) {
+            assertTrue(e.getResult().getStdout().contains("Topic was already terminated"));
+        }
     }
 
     @Test
@@ -131,7 +131,6 @@ public class CLITest extends PulsarClusterTestBase {
             "-n",
             "1",
             topicName);
-        assertEquals(0, result.getExitCode());
         assertTrue(result.getStdout().contains("1 messages successfully produced"));
 
         result = container.execCmd(
@@ -142,7 +141,6 @@ public class CLITest extends PulsarClusterTestBase {
             "-f",
             "/pulsar/conf/schema_example.conf"
         );
-        assertEquals(0, result.getExitCode());
         assertTrue(result.getStdout().isEmpty());
         assertTrue(result.getStderr().isEmpty());
 
@@ -152,7 +150,6 @@ public class CLITest extends PulsarClusterTestBase {
             "schemas",
             "get",
             topicName);
-        assertEquals(0, result.getExitCode());
         assertTrue(result.getStdout().contains("\"type\" : \"STRING\""));
 
         // delete the schema
@@ -161,19 +158,20 @@ public class CLITest extends PulsarClusterTestBase {
             "schemas",
             "delete",
             topicName);
-        assertEquals(0, result.getExitCode());
         assertTrue(result.getStdout().isEmpty());
         assertTrue(result.getStderr().isEmpty());
 
         // get schema again
-        result = container.execCmd(
-            PulsarCluster.ADMIN_SCRIPT,
-            "schemas",
-            "get",
-            "persistent://public/default/test-schema-cli"
-        );
-        assertNotEquals(0, result.getExitCode());
-        assertTrue(result.getStderr().contains("Reason: HTTP 404 Not Found"));
+        try {
+            container.execCmd(PulsarCluster.ADMIN_SCRIPT,
+                              "schemas",
+                              "get",
+                              "persistent://public/default/test-schema-cli"
+                              );
+            fail("Command should have exited with non-zero");
+        } catch (ContainerExecException e) {
+            assertTrue(e.getResult().getStderr().contains("Reason: HTTP 404 Not Found"));
+        }
     }
 
     @Test
@@ -190,7 +188,6 @@ public class CLITest extends PulsarClusterTestBase {
         };
 
         result = pulsarCluster.runAdminCommandOnAnyBroker(setCommand);
-        assertEquals(0, result.getExitCode());
         assertTrue(
             result.getStdout().isEmpty(),
             result.getStdout()
@@ -205,7 +202,6 @@ public class CLITest extends PulsarClusterTestBase {
         };
 
         result = pulsarCluster.runAdminCommandOnAnyBroker(getCommand);
-        assertEquals(0, result.getExitCode());
         assertTrue(
             result.getStdout().contains("\"retentionTimeInMinutes\" : -1"),
             result.getStdout());
diff --git a/tests/integration/src/test/java/org/apache/pulsar/tests/integration/containers/ChaosContainer.java b/tests/integration/src/test/java/org/apache/pulsar/tests/integration/containers/ChaosContainer.java
index 239954d..b211b5b 100644
--- a/tests/integration/src/test/java/org/apache/pulsar/tests/integration/containers/ChaosContainer.java
+++ b/tests/integration/src/test/java/org/apache/pulsar/tests/integration/containers/ChaosContainer.java
@@ -106,8 +106,7 @@ public class ChaosContainer<SelfT extends ChaosContainer<SelfT>> extends Generic
     public ContainerExecResult execCmd(String... commands) throws Exception {
         DockerClient client = this.getDockerClient();
         String dockerId = this.getContainerId();
-        return DockerUtils.runCommand(
-            client, dockerId, true, commands);
+        return DockerUtils.runCommand(client, dockerId, commands);
     }
 
     @Override
diff --git a/tests/integration/src/test/java/org/apache/pulsar/tests/integration/docker/ContainerExecException.java b/tests/integration/src/test/java/org/apache/pulsar/tests/integration/docker/ContainerExecException.java
new file mode 100644
index 0000000..599b0eb
--- /dev/null
+++ b/tests/integration/src/test/java/org/apache/pulsar/tests/integration/docker/ContainerExecException.java
@@ -0,0 +1,32 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.pulsar.tests.integration.docker;
+
+public class ContainerExecException extends Exception {
+    private final ContainerExecResult result;
+
+    public ContainerExecException(String cmd, String containerId, ContainerExecResult result) {
+        super(String.format("%s failed on %s with error code %d", cmd, containerId, result.getExitCode()));
+        this.result = result;
+    }
+
+    public ContainerExecResult getResult() {
+        return result;
+    }
+}
diff --git a/tests/integration/src/test/java/org/apache/pulsar/tests/integration/functions/runtime/PulsarFunctionsRuntimeTest.java b/tests/integration/src/test/java/org/apache/pulsar/tests/integration/functions/runtime/PulsarFunctionsRuntimeTest.java
index 8b7bafc..a69d137 100644
--- a/tests/integration/src/test/java/org/apache/pulsar/tests/integration/functions/runtime/PulsarFunctionsRuntimeTest.java
+++ b/tests/integration/src/test/java/org/apache/pulsar/tests/integration/functions/runtime/PulsarFunctionsRuntimeTest.java
@@ -21,6 +21,7 @@ package org.apache.pulsar.tests.integration.functions.runtime;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotEquals;
 import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
 
 import lombok.Cleanup;
 import org.apache.pulsar.client.api.Consumer;
@@ -29,6 +30,7 @@ import org.apache.pulsar.client.api.Producer;
 import org.apache.pulsar.client.api.PulsarClient;
 import org.apache.pulsar.client.api.Schema;
 import org.apache.pulsar.client.api.SubscriptionType;
+import org.apache.pulsar.tests.integration.docker.ContainerExecException;
 import org.apache.pulsar.tests.integration.docker.ContainerExecResult;
 import org.apache.pulsar.tests.integration.functions.PulsarFunctionsTestBase;
 import org.apache.pulsar.tests.integration.functions.utils.CommandGenerator;
@@ -107,7 +109,6 @@ public class PulsarFunctionsRuntimeTest extends PulsarFunctionsTestBase {
         };
         ContainerExecResult result = pulsarCluster.getAnyWorker().execCmd(
             commands);
-        assertEquals(0, result.getExitCode());
         assertTrue(result.getStdout().contains("\"Created successfully\""));
     }
 
@@ -120,21 +121,22 @@ public class PulsarFunctionsRuntimeTest extends PulsarFunctionsTestBase {
             "--namespace", "default",
             "--name", functionName
         );
-        assertEquals(0, result.getExitCode());
         assertTrue(result.getStdout().contains("\"name\": \"" + functionName + "\""));
     }
 
     private static void getFunctionInfoNotFound(String functionName) throws Exception {
-        ContainerExecResult result = pulsarCluster.getAnyWorker().execCmd(
-            PulsarCluster.ADMIN_SCRIPT,
-            "functions",
-            "get",
-            "--tenant", "public",
-            "--namespace", "default",
-            "--name", functionName
-        );
-        assertNotEquals(0, result.getExitCode());
-        assertTrue(result.getStderr().contains("Reason: Function " + functionName + " doesn't exist"));
+        try {
+            pulsarCluster.getAnyWorker().execCmd(
+                    PulsarCluster.ADMIN_SCRIPT,
+                    "functions",
+                    "get",
+                    "--tenant", "public",
+                    "--namespace", "default",
+                    "--name", functionName);
+            fail("Command should have exited with non-zero");
+        } catch (ContainerExecException e) {
+            assertTrue(e.getResult().getStderr().contains("Reason: Function " + functionName + " doesn't exist"));
+        }
     }
 
     private static void getFunctionStatus(String functionName, int numMessages) throws Exception {
@@ -146,7 +148,6 @@ public class PulsarFunctionsRuntimeTest extends PulsarFunctionsTestBase {
             "--namespace", "default",
             "--name", functionName
         );
-        assertEquals(0, result.getExitCode());
         assertTrue(result.getStdout().contains("\"running\": true"));
         assertTrue(result.getStdout().contains("\"numProcessed\": \"" + numMessages + "\""));
         assertTrue(result.getStdout().contains("\"numSuccessfullyProcessed\": \"" + numMessages + "\""));
@@ -186,7 +187,6 @@ public class PulsarFunctionsRuntimeTest extends PulsarFunctionsTestBase {
             "--namespace", "default",
             "--name", functionName
         );
-        assertEquals(0, result.getExitCode());
         assertTrue(result.getStdout().contains("Deleted successfully"));
         assertTrue(result.getStderr().isEmpty());
     }
diff --git a/tests/integration/src/test/java/org/apache/pulsar/tests/integration/io/PulsarIOSinkTest.java b/tests/integration/src/test/java/org/apache/pulsar/tests/integration/io/PulsarIOSinkTest.java
index 71cad05..d1c80ea 100644
--- a/tests/integration/src/test/java/org/apache/pulsar/tests/integration/io/PulsarIOSinkTest.java
+++ b/tests/integration/src/test/java/org/apache/pulsar/tests/integration/io/PulsarIOSinkTest.java
@@ -21,6 +21,7 @@ package org.apache.pulsar.tests.integration.io;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotEquals;
 import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
 
 import com.google.common.base.Stopwatch;
 import com.google.gson.Gson;
@@ -34,6 +35,7 @@ import org.apache.pulsar.client.api.Producer;
 import org.apache.pulsar.client.api.PulsarClient;
 import org.apache.pulsar.client.api.Schema;
 import org.apache.pulsar.common.naming.TopicName;
+import org.apache.pulsar.tests.integration.docker.ContainerExecException;
 import org.apache.pulsar.tests.integration.docker.ContainerExecResult;
 import org.apache.pulsar.tests.integration.functions.PulsarFunctionsTestBase;
 import org.apache.pulsar.tests.integration.topologies.FunctionRuntimeType;
@@ -134,7 +136,6 @@ public class PulsarIOSinkTest extends PulsarFunctionsTestBase {
         };
         log.info("Run command : {}", StringUtils.join(commands, ' '));
         ContainerExecResult result = pulsarCluster.getAnyWorker().execCmd(commands);
-        assertEquals(0, result.getExitCode());
         assertTrue(
             result.getStdout().contains("\"Created successfully\""),
             result.getStdout());
@@ -151,7 +152,6 @@ public class PulsarIOSinkTest extends PulsarFunctionsTestBase {
         };
         ContainerExecResult result = pulsarCluster.getAnyWorker().execCmd(commands);
         log.info("Get sink info : {}", result.getStdout());
-        assertEquals(0, result.getExitCode());
         assertTrue(
             result.getStdout().contains("\"builtin\": \"" + tester.sinkType + "\""),
             result.getStdout()
@@ -168,10 +168,14 @@ public class PulsarIOSinkTest extends PulsarFunctionsTestBase {
             "--name", sinkName
         };
         while (true) {
-            ContainerExecResult result = pulsarCluster.getAnyWorker().execCmd(commands);
-            log.info("Get sink status : {}", result.getStdout());
-            if (0 == result.getExitCode() && result.getStdout().contains("\"running\": true")) {
-                return;
+            try {
+                ContainerExecResult result = pulsarCluster.getAnyWorker().execCmd(commands);
+                log.info("Get sink status : {}", result.getStdout());
+                if (result.getStdout().contains("\"running\": true")) {
+                    return;
+                }
+            } catch (ContainerExecException e) {
+                // expected in early iterations
             }
             log.info("Backoff 1 second until the function is running");
             TimeUnit.SECONDS.sleep(1);
@@ -215,12 +219,16 @@ public class PulsarIOSinkTest extends PulsarFunctionsTestBase {
         };
         Stopwatch stopwatch = Stopwatch.createStarted();
         while (true) {
-            ContainerExecResult result = pulsarCluster.getAnyWorker().execCmd(commands);
-            log.info("Get sink status : {}", result.getStdout());
-            if (0 == result.getExitCode()
-                && result.getStdout().contains("\"numProcessed\": \"" + numMessages + "\"")) {
-                return;
+            try {
+                ContainerExecResult result = pulsarCluster.getAnyWorker().execCmd(commands);
+                log.info("Get sink status : {}", result.getStdout());
+                if (result.getStdout().contains("\"numProcessed\": \"" + numMessages + "\"")) {
+                    return;
+                }
+            } catch (ContainerExecException e) {
+                // expected in early iterations
             }
+
             log.info("{} ms has elapsed but the sink hasn't process {} messages, backoff to wait for another 1 second",
                 stopwatch.elapsed(TimeUnit.MILLISECONDS), numMessages);
             TimeUnit.SECONDS.sleep(1);
@@ -237,7 +245,6 @@ public class PulsarIOSinkTest extends PulsarFunctionsTestBase {
             "--name", sinkName
         };
         ContainerExecResult result = pulsarCluster.getAnyWorker().execCmd(commands);
-        assertEquals(0, result.getExitCode());
         assertTrue(
             result.getStdout().contains("Deleted successfully"),
             result.getStdout()
@@ -257,8 +264,11 @@ public class PulsarIOSinkTest extends PulsarFunctionsTestBase {
             "--namespace", namespace,
             "--name", sinkName
         };
-        ContainerExecResult result = pulsarCluster.getAnyWorker().execCmd(commands);
-        assertNotEquals(0, result.getExitCode());
-        assertTrue(result.getStderr().contains("Reason: Function " + sinkName + " doesn't exist"));
+        try {
+            pulsarCluster.getAnyWorker().execCmd(commands);
+            fail("Command should have exited with non-zero");
+        } catch (ContainerExecException e) {
+            assertTrue(e.getResult().getStderr().contains("Reason: Function " + sinkName + " doesn't exist"));
+        }
     }
 }
diff --git a/tests/integration/src/test/java/org/apache/pulsar/tests/integration/io/PulsarIOSourceTest.java b/tests/integration/src/test/java/org/apache/pulsar/tests/integration/io/PulsarIOSourceTest.java
index 8468976..8bd76ef 100644
--- a/tests/integration/src/test/java/org/apache/pulsar/tests/integration/io/PulsarIOSourceTest.java
+++ b/tests/integration/src/test/java/org/apache/pulsar/tests/integration/io/PulsarIOSourceTest.java
@@ -21,6 +21,7 @@ package org.apache.pulsar.tests.integration.io;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotEquals;
 import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
 
 import com.google.common.base.Stopwatch;
 import com.google.gson.Gson;
@@ -35,6 +36,7 @@ import org.apache.pulsar.client.api.PulsarClient;
 import org.apache.pulsar.client.api.Schema;
 import org.apache.pulsar.client.api.SubscriptionType;
 import org.apache.pulsar.common.naming.TopicName;
+import org.apache.pulsar.tests.integration.docker.ContainerExecException;
 import org.apache.pulsar.tests.integration.docker.ContainerExecResult;
 import org.apache.pulsar.tests.integration.functions.PulsarFunctionsTestBase;
 import org.apache.pulsar.tests.integration.topologies.FunctionRuntimeType;
@@ -145,7 +147,6 @@ public class PulsarIOSourceTest extends PulsarFunctionsTestBase {
         };
         log.info("Run command : {}", StringUtils.join(commands, ' '));
         ContainerExecResult result = pulsarCluster.getAnyWorker().execCmd(commands);
-        assertEquals(0, result.getExitCode());
         assertTrue(
             result.getStdout().contains("\"Created successfully\""),
             result.getStdout());
@@ -162,7 +163,6 @@ public class PulsarIOSourceTest extends PulsarFunctionsTestBase {
         };
         ContainerExecResult result = pulsarCluster.getAnyWorker().execCmd(commands);
         log.info("Get source info : {}", result.getStdout());
-        assertEquals(0, result.getExitCode());
         assertTrue(
             result.getStdout().contains("\"builtin\": \"" + tester.sourceType + "\""),
             result.getStdout()
@@ -179,10 +179,14 @@ public class PulsarIOSourceTest extends PulsarFunctionsTestBase {
             "--name", sourceName
         };
         while (true) {
-            ContainerExecResult result = pulsarCluster.getAnyWorker().execCmd(commands);
-            log.info("Get source status : {}", result.getStdout());
-            if (0 == result.getExitCode() && result.getStdout().contains("\"running\": true")) {
-                return;
+            try {
+                ContainerExecResult result = pulsarCluster.getAnyWorker().execCmd(commands);
+                log.info("Get source status : {}", result.getStdout());
+                if (result.getStdout().contains("\"running\": true")) {
+                    return;
+                }
+            } catch (ContainerExecException e) {
+                // expected for early iterations
             }
             log.info("Backoff 1 second until the function is running");
             TimeUnit.SECONDS.sleep(1);
@@ -212,11 +216,14 @@ public class PulsarIOSourceTest extends PulsarFunctionsTestBase {
         };
         Stopwatch stopwatch = Stopwatch.createStarted();
         while (true) {
-            ContainerExecResult result = pulsarCluster.getAnyWorker().execCmd(commands);
-            log.info("Get source status : {}", result.getStdout());
-            if (0 == result.getExitCode()
-                && result.getStdout().contains("\"numProcessed\": \"" + numMessages + "\"")) {
-                return;
+            try {
+                ContainerExecResult result = pulsarCluster.getAnyWorker().execCmd(commands);
+                log.info("Get source status : {}", result.getStdout());
+                if (result.getStdout().contains("\"numProcessed\": \"" + numMessages + "\"")) {
+                    return;
+                }
+            } catch (ContainerExecException e) {
+                // expected for early iterations
             }
             log.info("{} ms has elapsed but the source hasn't process {} messages, backoff to wait for another 1 second",
                 stopwatch.elapsed(TimeUnit.MILLISECONDS), numMessages);
@@ -234,7 +241,6 @@ public class PulsarIOSourceTest extends PulsarFunctionsTestBase {
             "--name", sourceName
         };
         ContainerExecResult result = pulsarCluster.getAnyWorker().execCmd(commands);
-        assertEquals(0, result.getExitCode());
         assertTrue(
             result.getStdout().contains("Delete source successfully"),
             result.getStdout()
@@ -254,8 +260,11 @@ public class PulsarIOSourceTest extends PulsarFunctionsTestBase {
             "--namespace", namespace,
             "--name", sourceName
         };
-        ContainerExecResult result = pulsarCluster.getAnyWorker().execCmd(commands);
-        assertNotEquals(0, result.getExitCode());
-        assertTrue(result.getStderr().contains("Reason: Function " + sourceName + " doesn't exist"));
+        try {
+            pulsarCluster.getAnyWorker().execCmd(commands);
+            fail("Command should have exited with non-zero");
+        } catch (ContainerExecException e) {
+            assertTrue(e.getResult().getStderr().contains("Reason: Function " + sourceName + " doesn't exist"));
+        }
     }
 }
diff --git a/tests/integration/src/test/java/org/apache/pulsar/tests/integration/utils/DockerUtils.java b/tests/integration/src/test/java/org/apache/pulsar/tests/integration/utils/DockerUtils.java
index 8684201..5148a36 100644
--- a/tests/integration/src/test/java/org/apache/pulsar/tests/integration/utils/DockerUtils.java
+++ b/tests/integration/src/test/java/org/apache/pulsar/tests/integration/utils/DockerUtils.java
@@ -45,6 +45,7 @@ import java.util.zip.GZIPOutputStream;
 import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
 import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
 
+import org.apache.pulsar.tests.integration.docker.ContainerExecException;
 import org.apache.pulsar.tests.integration.docker.ContainerExecResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -164,16 +165,10 @@ public class DockerUtils {
         throw new IllegalArgumentException("Container " + containerId + " has no networks");
     }
 
-    public static ContainerExecResult runCommand(DockerClient docker, String containerId, String... cmd)
-            throws Exception {
-        return runCommand(docker, containerId, false, cmd);
-    }
-
     public static ContainerExecResult runCommand(DockerClient docker,
                                                  String containerId,
-                                                 boolean ignoreError,
                                                  String... cmd)
-            throws Exception {
+            throws ContainerExecException {
         CompletableFuture<Boolean> future = new CompletableFuture<>();
         String execid = docker.execCreateCmd(containerId)
             .withCmd(cmd)
@@ -228,23 +223,17 @@ public class DockerUtils {
             resp = docker.inspectExecCmd(execid).exec();
         }
         int retCode = resp.getExitCode();
-        if (retCode != 0) {
-            if (!ignoreError) {
-                LOG.error("DOCKER.exec({}:{}): failed with {} :\nStdout:\n{}\n\nStderr:\n{}",
-                    containerId, cmdString, retCode, stdout.toString(), stderr.toString());
-                throw new Exception(String.format("cmd(%s) failed on %s with exitcode %d",
-                    cmdString, containerId, retCode));
-            } else {
-                LOG.error("DOCKER.exec({}:{}): failed with {}", containerId, cmdString, retCode);
-            }
-        } else {
-            LOG.info("DOCKER.exec({}:{}): completed with {}", containerId, cmdString, retCode);
-        }
-        return ContainerExecResult.of(
+        ContainerExecResult result = ContainerExecResult.of(
             retCode,
             stdout.toString(),
             stderr.toString()
         );
+        LOG.info("DOCKER.exec({}:{}): completed with {}", containerId, cmdString, retCode);
+
+        if (retCode != 0) {
+            throw new ContainerExecException(cmdString, containerId, result);
+        }
+        return result;
     }
 
     public static Optional<String> getContainerCluster(DockerClient docker, String containerId) {