You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@bookkeeper.apache.org by iv...@apache.org on 2018/02/19 20:18:31 UTC
[bookkeeper] branch master updated: Cleanup threads from old
clients in BC tests
This is an automated email from the ASF dual-hosted git repository.
ivank 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 d4277c0 Cleanup threads from old clients in BC tests
d4277c0 is described below
commit d4277c06f62f680dba9383e68c0699c343e4e5ca
Author: Ivan Kelly <iv...@apache.org>
AuthorDate: Mon Feb 19 21:18:25 2018 +0100
Cleanup threads from old clients in BC tests
Some old clients don't clean up their threads correctly. This patch
introduces a thread reaper, which will check if a test has left any
threads running, and try to clean them up if they have.
Author: Ivan Kelly <iv...@apache.org>
Reviewers: Sijie Guo <si...@apache.org>
This closes #1177 from ivankelly/thread-reaper
---
.../backwardcompat/TestCompatOldClients.groovy | 13 +++--
.../org/apache/bookkeeper/tests/ThreadReaper.java | 66 ++++++++++++++++++++++
2 files changed, 75 insertions(+), 4 deletions(-)
diff --git a/tests/backward-compat/current-server-old-clients/src/test/groovy/org/apache/bookkeeper/tests/backwardcompat/TestCompatOldClients.groovy b/tests/backward-compat/current-server-old-clients/src/test/groovy/org/apache/bookkeeper/tests/backwardcompat/TestCompatOldClients.groovy
index 9c237cc..a527567 100644
--- a/tests/backward-compat/current-server-old-clients/src/test/groovy/org/apache/bookkeeper/tests/backwardcompat/TestCompatOldClients.groovy
+++ b/tests/backward-compat/current-server-old-clients/src/test/groovy/org/apache/bookkeeper/tests/backwardcompat/TestCompatOldClients.groovy
@@ -21,6 +21,7 @@ import com.github.dockerjava.api.DockerClient
import org.apache.bookkeeper.tests.BookKeeperClusterUtils
import org.apache.bookkeeper.tests.MavenClassLoader
+import org.apache.bookkeeper.tests.ThreadReaper
import org.jboss.arquillian.junit.Arquillian
import org.jboss.arquillian.test.api.ArquillianResource
@@ -110,14 +111,16 @@ class TestCompatOldClients {
@Test
public void testNewClientFencesOldClient() throws Exception {
oldClientVersions.each{
- testFencingOldClient(it, currentVersion)
+ def version = it
+ ThreadReaper.runWithReaper({ testFencingOldClient(version, currentVersion) })
}
}
@Test
public void testOldClientFencesOldClient() throws Exception {
oldClientVersions.each{
- testFencingOldClient(it, it)
+ def version = it
+ ThreadReaper.runWithReaper({ testFencingOldClient(version, version) })
}
}
@@ -161,14 +164,16 @@ class TestCompatOldClients {
@Test
public void testOldClientReadsNewClient() throws Exception {
oldClientVersions.each{
- testReads(currentVersion, it)
+ def version = it
+ ThreadReaper.runWithReaper({ testReads(currentVersion, version) })
}
}
@Test
public void testNewClientReadsNewClient() throws Exception {
oldClientVersions.each{
- testReads(it, currentVersion)
+ def version = it
+ ThreadReaper.runWithReaper({ testReads(version, currentVersion) })
}
}
}
diff --git a/tests/integration-tests-utils/src/main/java/org/apache/bookkeeper/tests/ThreadReaper.java b/tests/integration-tests-utils/src/main/java/org/apache/bookkeeper/tests/ThreadReaper.java
new file mode 100644
index 0000000..abccbd9
--- /dev/null
+++ b/tests/integration-tests-utils/src/main/java/org/apache/bookkeeper/tests/ThreadReaper.java
@@ -0,0 +1,66 @@
+/**
+ *
+ * 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.Callable;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ThreadReaper {
+ private static final Logger LOG = LoggerFactory.getLogger(ThreadReaper.class);
+ private static AtomicInteger groupId = new AtomicInteger(0);
+
+ public static <T> T runWithReaper(Callable<T> callable) throws Exception {
+ ThreadGroup tg = new ThreadGroup("reaper-group-" + groupId.incrementAndGet());
+ CompletableFuture<T> promise = new CompletableFuture<>();
+ Thread t = new Thread(tg, () -> {
+ try {
+ promise.complete(callable.call());
+ } catch (Throwable ex) {
+ promise.completeExceptionally(ex);
+ }
+ }, "reapable-thread");
+ t.start();
+ T ret = promise.get();
+
+ int i = 30; // try to clean up for 3 seconds
+ while (tg.activeCount() > 0 && i > 0) {
+ tg.interrupt();
+ Thread.sleep(100);
+ LOG.info("{} threads still alive", tg.activeCount());
+ i--;
+ }
+ if (tg.activeCount() == 0) {
+ LOG.info("All threads in reaper group dead");
+ } else {
+ Thread[] threads = new Thread[tg.activeCount()];
+ int found = tg.enumerate(threads);
+ LOG.info("Leaked {} threads", found);
+ for (int j = 0; j < found; j++) {
+ LOG.info("Leaked thread {}", threads[j]);
+ }
+ }
+ return ret;
+ }
+}
--
To stop receiving notification emails like this one, please contact
ivank@apache.org.