You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@bookkeeper.apache.org by si...@apache.org on 2018/01/18 00:44:43 UTC
[bookkeeper] branch master updated: Utilities for working with
Arquillian and Docker
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/bookkeeper.git
The following commit(s) were added to refs/heads/master by this push:
new 1f66e47 Utilities for working with Arquillian and Docker
1f66e47 is described below
commit 1f66e478dd78fb2f9ba66b7c92da2ec17c5be089
Author: Ivan Kelly <iv...@apache.org>
AuthorDate: Wed Jan 17 16:44:37 2018 -0800
Utilities for working with Arquillian and Docker
This patch contains the following utilities.
- An arquillian StopAction which copy logs from /var/log/bookkeeper to
the target/ directory.
- An arquillian StopAction which dumps the docker log to the target/
directory.
- An arquillian AwaitStrategy which checks whether a zookeeper cluster
is running.
- An arquillian AwaitStrategy which returns immediately (surprising
arquillian didn't already have this).
- Utilities for working with a cluster of zookeeper/bookkeeper running
on docker.
Master Issue: #903
Author: Ivan Kelly <iv...@apache.org>
Reviewers: Enrico Olivelli <eo...@gmail.com>, Jia Zhai <None>
This closes #974 from ivankelly/arquillian-util
---
tests/integration-tests-utils/pom.xml | 84 ++++++++++
.../bookkeeper/tests/BookKeeperClusterUtils.java | 153 +++++++++++++++++++
.../tests/BookKeeperLogsToTargetDirStopAction.java | 43 ++++++
.../org/apache/bookkeeper/tests/DockerUtils.java | 170 +++++++++++++++++++++
.../bookkeeper/tests/LogToTargetDirStopAction.java | 41 +++++
.../apache/bookkeeper/tests/NoopAwaitStrategy.java | 30 ++++
.../bookkeeper/tests/ZooKeeperAwaitStrategy.java | 57 +++++++
.../src/main/resources/log4j.properties | 37 +++++
tests/pom.xml | 1 +
9 files changed, 616 insertions(+)
diff --git a/tests/integration-tests-utils/pom.xml b/tests/integration-tests-utils/pom.xml
new file mode 100644
index 0000000..3593ec5
--- /dev/null
+++ b/tests/integration-tests-utils/pom.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="
+ http://maven.apache.org/POM/4.0.0
+ http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.bookkeeper.tests</groupId>
+ <artifactId>tests-parent</artifactId>
+ <version>4.7.0-SNAPSHOT</version>
+ </parent>
+
+ <groupId>org.apache.bookkeeper.tests</groupId>
+ <artifactId>integration-tests-utils</artifactId>
+ <packaging>jar</packaging>
+
+ <name>Apache BookKeeper :: Tests :: Utility module for Arquillian based integration tests</name>
+
+ <properties>
+ <arquillian-cube.version>1.13.0</arquillian-cube.version>
+ <commons-compress.version>1.15</commons-compress.version>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-compress</artifactId>
+ <version>${commons-compress.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.zookeeper</groupId>
+ <artifactId>zookeeper</artifactId>
+ <version>${zookeeper.version}</version>
+ <scope>compile</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>net.java.dev.javacc</groupId>
+ <artifactId>javacc</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>io.netty</groupId>
+ <artifactId>netty</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <dependency>
+ <groupId>org.arquillian.cube</groupId>
+ <artifactId>arquillian-cube-docker</artifactId>
+ <version>${arquillian-cube.version}</version>
+ </dependency>
+
+ </dependencies>
+</project>
diff --git a/tests/integration-tests-utils/src/main/java/org/apache/bookkeeper/tests/BookKeeperClusterUtils.java b/tests/integration-tests-utils/src/main/java/org/apache/bookkeeper/tests/BookKeeperClusterUtils.java
new file mode 100644
index 0000000..d70d543
--- /dev/null
+++ b/tests/integration-tests-utils/src/main/java/org/apache/bookkeeper/tests/BookKeeperClusterUtils.java
@@ -0,0 +1,153 @@
+/**
+ * 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.bookkeeper.tests;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import com.github.dockerjava.api.DockerClient;
+
+import java.io.IOException;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+import java.net.Socket;
+
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.ZooDefs.Ids;
+import org.apache.zookeeper.Watcher.Event.KeeperState;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class BookKeeperClusterUtils {
+ private static final Logger LOG = LoggerFactory.getLogger(BookKeeperClusterUtils.class);
+
+ public static String zookeeperConnectString(DockerClient docker) {
+ return DockerUtils.cubeIdsMatching("zookeeper").stream()
+ .map((id) -> DockerUtils.getContainerIP(docker, id)).collect(Collectors.joining(":"));
+ }
+
+ public static ZooKeeper zookeeperClient(DockerClient docker) throws Exception {
+ String connectString = BookKeeperClusterUtils.zookeeperConnectString(docker);
+ CompletableFuture<Void> future = new CompletableFuture<>();
+ ZooKeeper zk = new ZooKeeper(connectString, 10000,
+ (e) -> {
+ if (e.getState().equals(KeeperState.SyncConnected)) {
+ future.complete(null);
+ }
+ });
+ future.get();
+ return zk;
+ }
+
+ public static boolean zookeeperRunning(DockerClient docker, String containerId) {
+ String ip = DockerUtils.getContainerIP(docker, containerId);
+ try (Socket socket = new Socket(ip, 2181)) {
+ socket.setSoTimeout(1000);
+ socket.getOutputStream().write("ruok".getBytes(UTF_8));
+ byte[] resp = new byte[4];
+ if (socket.getInputStream().read(resp) == 4) {
+ return new String(resp, UTF_8).equals("imok");
+ }
+ } catch (IOException e) {
+ // ignore, we'll return fallthrough to return false
+ }
+ return false;
+ }
+
+ public static void legacyMetadataFormat(DockerClient docker) throws Exception {
+ try (ZooKeeper zk = BookKeeperClusterUtils.zookeeperClient(docker)) {
+ zk.create("/ledgers", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
+ zk.create("/ledgers/available", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
+ }
+ }
+
+ private static boolean waitBookieState(DockerClient docker, String containerId,
+ int timeout, TimeUnit timeoutUnit,
+ boolean upOrDown) {
+ long timeoutMillis = timeoutUnit.toMillis(timeout);
+ long pollMillis = 1000;
+ String bookieId = DockerUtils.getContainerIP(docker, containerId) + ":3181";
+ try (ZooKeeper zk = BookKeeperClusterUtils.zookeeperClient(docker)) {
+ String path = "/ledgers/available/" + bookieId;
+ while (timeoutMillis > 0) {
+ if ((zk.exists(path, false) != null) == upOrDown) {
+ return true;
+ }
+ Thread.sleep(pollMillis);
+ timeoutMillis -= pollMillis;
+ }
+ } catch (Exception e) {
+ LOG.error("Exception checking for bookie state", e);
+ return false;
+ }
+ LOG.warn("Bookie {} didn't go {} after {} seconds",
+ containerId, upOrDown ? "up" : "down",
+ timeoutUnit.toSeconds(timeout));
+ return false;
+ }
+
+ public static boolean waitBookieUp(DockerClient docker, String containerId,
+ int timeout, TimeUnit timeoutUnit) {
+ return waitBookieState(docker, containerId, timeout, timeoutUnit, true);
+ }
+
+ public static boolean waitBookieDown(DockerClient docker, String containerId,
+ int timeout, TimeUnit timeoutUnit) {
+ return waitBookieState(docker, containerId, timeout, timeoutUnit, false);
+ }
+
+ public static boolean startBookieWithVersion(DockerClient docker, String containerId, String version) {
+ try {
+ DockerUtils.runCommand(docker, containerId, "supervisorctl", "start", "bookkeeper-" + version);
+ } catch (Exception e) {
+ LOG.error("Exception starting bookie", e);
+ return false;
+ }
+ return waitBookieUp(docker, containerId, 10, TimeUnit.SECONDS);
+ }
+
+ private static boolean allTrue(boolean accumulator, boolean result) {
+ return accumulator && result;
+ }
+
+ public static boolean startAllBookiesWithVersion(DockerClient docker, String version)
+ throws Exception {
+ return DockerUtils.cubeIdsMatching("bookkeeper").stream()
+ .map((b) -> startBookieWithVersion(docker, b, version))
+ .reduce(true, BookKeeperClusterUtils::allTrue);
+ }
+
+ public static boolean stopBookie(DockerClient docker, String containerId) {
+ try {
+ DockerUtils.runCommand(docker, containerId, "supervisorctl", "stop", "all");
+ } catch (Exception e) {
+ LOG.error("Exception stopping bookie", e);
+ return false;
+ }
+ return waitBookieDown(docker, containerId, 10, TimeUnit.SECONDS);
+ }
+
+ public static boolean stopAllBookies(DockerClient docker) {
+ return DockerUtils.cubeIdsMatching("bookkeeper").stream()
+ .map((b) -> stopBookie(docker, b))
+ .reduce(true, BookKeeperClusterUtils::allTrue);
+ }
+}
diff --git a/tests/integration-tests-utils/src/main/java/org/apache/bookkeeper/tests/BookKeeperLogsToTargetDirStopAction.java b/tests/integration-tests-utils/src/main/java/org/apache/bookkeeper/tests/BookKeeperLogsToTargetDirStopAction.java
new file mode 100644
index 0000000..cab00f8
--- /dev/null
+++ b/tests/integration-tests-utils/src/main/java/org/apache/bookkeeper/tests/BookKeeperLogsToTargetDirStopAction.java
@@ -0,0 +1,43 @@
+/**
+ * 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.bookkeeper.tests;
+
+import org.arquillian.cube.docker.impl.docker.DockerClientExecutor;
+import org.arquillian.cube.impl.model.CubeId;
+import org.arquillian.cube.spi.beforeStop.BeforeStopAction;
+
+public class BookKeeperLogsToTargetDirStopAction implements BeforeStopAction {
+ private DockerClientExecutor dockerClientExecutor;
+ private CubeId containerID;
+
+ public void setDockerClientExecutor(DockerClientExecutor executor) {
+ this.dockerClientExecutor = executor;
+ }
+
+ public void setContainerID(CubeId containerID) {
+ this.containerID = containerID;
+ }
+
+ @Override
+ public void doBeforeStop() {
+ DockerUtils.dumpContainerLogToTarget(dockerClientExecutor.getDockerClient(), containerID.getId());
+ DockerUtils.dumpContainerLogDirToTarget(dockerClientExecutor.getDockerClient(),
+ containerID.getId(), "/var/log/bookkeeper");
+ }
+}
diff --git a/tests/integration-tests-utils/src/main/java/org/apache/bookkeeper/tests/DockerUtils.java b/tests/integration-tests-utils/src/main/java/org/apache/bookkeeper/tests/DockerUtils.java
new file mode 100644
index 0000000..7d183a1
--- /dev/null
+++ b/tests/integration-tests-utils/src/main/java/org/apache/bookkeeper/tests/DockerUtils.java
@@ -0,0 +1,170 @@
+/**
+ * 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.bookkeeper.tests;
+
+import com.github.dockerjava.api.DockerClient;
+import com.github.dockerjava.api.async.ResultCallback;
+import com.github.dockerjava.api.model.Frame;
+import com.github.dockerjava.api.model.ContainerNetwork;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
+import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DockerUtils {
+ private static final Logger LOG = LoggerFactory.getLogger(DockerUtils.class);
+
+ private static File getTargetDirectory(String containerId) {
+ String base = System.getProperty("maven.buildDirectory");
+ if (base == null) {
+ base = "target";
+ }
+ File directory = new File(base + "/container-logs/" + containerId);
+ if (!directory.exists() && !directory.mkdirs()) {
+ LOG.error("Error creating directory for container logs.");
+ }
+ return directory;
+ }
+
+ public static void dumpContainerLogToTarget(DockerClient docker, String containerId) {
+ File output = new File(getTargetDirectory(containerId), "docker.log");
+ try (FileOutputStream os = new FileOutputStream(output)) {
+ CompletableFuture<Boolean> future = new CompletableFuture<>();
+ docker.logContainerCmd(containerId).withStdOut(true)
+ .withStdErr(true).withTimestamps(true).exec(new ResultCallback<Frame>() {
+ @Override
+ public void close() {}
+
+ @Override
+ public void onStart(Closeable closeable) {}
+
+ @Override
+ public void onNext(Frame object) {
+ try {
+ os.write(object.getPayload());
+ } catch (IOException e) {
+ onError(e);
+ }
+ }
+
+ @Override
+ public void onError(Throwable throwable) {
+ future.completeExceptionally(throwable);
+ }
+
+ @Override
+ public void onComplete() {
+ future.complete(true);
+ }
+ });
+ future.get();
+ } catch (ExecutionException|IOException e) {
+ LOG.error("Error dumping log for {}", containerId, e);
+ } catch (InterruptedException ie) {
+ Thread.currentThread().interrupt();
+ LOG.info("Interrupted dumping log from container {}", containerId, ie);
+ }
+ }
+
+ public static void dumpContainerLogDirToTarget(DockerClient docker, String containerId, String path) {
+ final int READ_BLOCK_SIZE = 10000;
+
+ try (InputStream dockerStream = docker.copyArchiveFromContainerCmd(containerId, path).exec();
+ TarArchiveInputStream stream = new TarArchiveInputStream(dockerStream)) {
+ TarArchiveEntry entry = stream.getNextTarEntry();
+ while (entry != null) {
+ if (entry.isFile()) {
+ File output = new File(getTargetDirectory(containerId), entry.getName().replace("/", "-"));
+ try (FileOutputStream os = new FileOutputStream(output)) {
+ byte[] block = new byte[READ_BLOCK_SIZE];
+ int read = stream.read(block, 0, READ_BLOCK_SIZE);
+ while (read > -1) {
+ os.write(block, 0, read);
+ read = stream.read(block, 0, READ_BLOCK_SIZE);
+ }
+ }
+ }
+ entry = stream.getNextTarEntry();
+ }
+ } catch (IOException e) {
+ LOG.error("Error reading bk logs from container {}", containerId, e);
+ }
+ }
+
+ public static String getContainerIP(DockerClient docker, String containerId) {
+ for (Map.Entry<String, ContainerNetwork> e : docker.inspectContainerCmd(containerId)
+ .exec().getNetworkSettings().getNetworks().entrySet()) {
+ return e.getValue().getIpAddress();
+ }
+ throw new IllegalArgumentException("Container " + containerId + " has no networks");
+ }
+
+ public static void runCommand(DockerClient docker, String containerId, String... cmd) throws Exception {
+ CompletableFuture<Boolean> future = new CompletableFuture<>();
+ String execid = docker.execCreateCmd(containerId).withCmd(cmd).exec().getId();
+ docker.execStartCmd(execid).withDetach(false).exec(new ResultCallback<Frame>() {
+ @Override
+ public void close() {}
+
+ @Override
+ public void onStart(Closeable closeable) {
+ }
+
+ @Override
+ public void onNext(Frame object) {
+ LOG.info("DOCKER.exec({}): {}", cmd, object);
+ }
+
+ @Override
+ public void onError(Throwable throwable) {
+ future.completeExceptionally(throwable);
+ }
+
+ @Override
+ public void onComplete() {
+ future.complete(true);
+ }
+ });
+ future.get();
+ }
+
+ public static Set<String> cubeIdsMatching(String needle) {
+ Pattern pattern = Pattern.compile("^arq.cube.docker.([^.]*).ip$");
+ return System.getProperties().keySet().stream()
+ .map(k -> pattern.matcher(k.toString()))
+ .filter(m -> m.matches())
+ .map(m -> m.group(1))
+ .filter(m -> m.contains(needle))
+ .collect(Collectors.toSet());
+ }
+}
diff --git a/tests/integration-tests-utils/src/main/java/org/apache/bookkeeper/tests/LogToTargetDirStopAction.java b/tests/integration-tests-utils/src/main/java/org/apache/bookkeeper/tests/LogToTargetDirStopAction.java
new file mode 100644
index 0000000..24f9761
--- /dev/null
+++ b/tests/integration-tests-utils/src/main/java/org/apache/bookkeeper/tests/LogToTargetDirStopAction.java
@@ -0,0 +1,41 @@
+/**
+ * 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.bookkeeper.tests;
+
+import org.arquillian.cube.docker.impl.docker.DockerClientExecutor;
+import org.arquillian.cube.impl.model.CubeId;
+import org.arquillian.cube.spi.beforeStop.BeforeStopAction;
+
+public class LogToTargetDirStopAction implements BeforeStopAction {
+ private DockerClientExecutor dockerClientExecutor;
+ private CubeId containerID;
+
+ public void setDockerClientExecutor(DockerClientExecutor executor) {
+ this.dockerClientExecutor = executor;
+ }
+
+ public void setContainerID(CubeId containerID) {
+ this.containerID = containerID;
+ }
+
+ @Override
+ public void doBeforeStop() {
+ DockerUtils.dumpContainerLogToTarget(dockerClientExecutor.getDockerClient(), containerID.getId());
+ }
+}
diff --git a/tests/integration-tests-utils/src/main/java/org/apache/bookkeeper/tests/NoopAwaitStrategy.java b/tests/integration-tests-utils/src/main/java/org/apache/bookkeeper/tests/NoopAwaitStrategy.java
new file mode 100644
index 0000000..6df8167
--- /dev/null
+++ b/tests/integration-tests-utils/src/main/java/org/apache/bookkeeper/tests/NoopAwaitStrategy.java
@@ -0,0 +1,30 @@
+/**
+ *
+ * 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.bookkeeper.tests;
+
+import org.arquillian.cube.spi.await.AwaitStrategy;
+
+public class NoopAwaitStrategy implements AwaitStrategy {
+ @Override
+ public boolean await() {
+ return true;
+ }
+}
diff --git a/tests/integration-tests-utils/src/main/java/org/apache/bookkeeper/tests/ZooKeeperAwaitStrategy.java b/tests/integration-tests-utils/src/main/java/org/apache/bookkeeper/tests/ZooKeeperAwaitStrategy.java
new file mode 100644
index 0000000..86d2d69
--- /dev/null
+++ b/tests/integration-tests-utils/src/main/java/org/apache/bookkeeper/tests/ZooKeeperAwaitStrategy.java
@@ -0,0 +1,57 @@
+/**
+ *
+ * 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.bookkeeper.tests;
+
+import java.util.concurrent.TimeUnit;
+
+import org.arquillian.cube.spi.Cube;
+import org.arquillian.cube.spi.await.AwaitStrategy;
+import org.arquillian.cube.spi.metadata.HasPortBindings;
+import org.arquillian.cube.docker.impl.client.config.Await;
+import org.arquillian.cube.docker.impl.docker.DockerClientExecutor;
+import org.arquillian.cube.docker.impl.util.Ping;
+import org.arquillian.cube.docker.impl.util.PingCommand;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ZooKeeperAwaitStrategy implements AwaitStrategy {
+ private static final Logger LOG = LoggerFactory.getLogger(ZooKeeperAwaitStrategy.class);
+
+ private static final int DEFAULT_POLL_ITERATIONS = 10;
+ private static final int DEFAULT_SLEEP_TIME = 1;
+ private static final TimeUnit DEFAULT_SLEEP_TIMEUNIT = TimeUnit.SECONDS;
+
+ private Cube<?> cube;
+ private DockerClientExecutor dockerClientExecutor;
+
+ @Override
+ public boolean await() {
+ return Ping.ping(DEFAULT_POLL_ITERATIONS, DEFAULT_SLEEP_TIME, DEFAULT_SLEEP_TIMEUNIT,
+ new PingCommand() {
+ @Override
+ public boolean call() {
+ return BookKeeperClusterUtils.zookeeperRunning(dockerClientExecutor.getDockerClient(),
+ cube.getId());
+ }
+ });
+ }
+}
diff --git a/tests/integration-tests-utils/src/main/resources/log4j.properties b/tests/integration-tests-utils/src/main/resources/log4j.properties
new file mode 100644
index 0000000..09ac2e7
--- /dev/null
+++ b/tests/integration-tests-utils/src/main/resources/log4j.properties
@@ -0,0 +1,37 @@
+#
+#
+# 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.
+#
+#
+
+# Format is "<default threshold> (, <appender>)+
+
+# DEFAULT: console appender only, level INFO
+log4j.rootLogger=INFO,CONSOLE
+
+#
+# Log INFO level and above messages to the console
+#
+log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
+log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
+log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} - %-5p - [%t:%C{1}@%L] - %m%n
+
+#disable zookeeper logging
+log4j.logger.org.apache.zookeeper=OFF
+log4j.logger.org.apache.bookkeeper.bookie=INFO
+log4j.logger.org.apache.bookkeeper.meta=INFO
diff --git a/tests/pom.xml b/tests/pom.xml
index 2bc561d..f817001 100644
--- a/tests/pom.xml
+++ b/tests/pom.xml
@@ -36,6 +36,7 @@
<module>bookkeeper-server-shaded-test</module>
<module>bookkeeper-server-tests-shaded-test</module>
<module>docker-all-versions-image</module>
+ <module>integration-tests-utils</module>
</modules>
<build>
<plugins>
--
To stop receiving notification emails like this one, please contact
['"commits@bookkeeper.apache.org" <co...@bookkeeper.apache.org>'].