/* * JBoss, Home of Professional Open Source * Copyright 2011 Red Hat Inc. and/or its affiliates and other * contributors as indicated by the @author tags. All rights reserved. * See the copyright.txt in the distribution for a full listing of * individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.infinispan.test; import org.infinispan.util.logging.Log; import org.infinispan.util.logging.LogFactory; import org.testng.annotations.AfterTest; import java.util.HashSet; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.Future; import java.util.concurrent.FutureTask; import static org.testng.Assert.assertEquals; /** * AbstractInfinispanTest is a superclass of all Infinispan tests. * * @author Vladimir Blagojevic * @author Mircea.Markus@jboss.com * @since 4.0 */ public class AbstractInfinispanTest { protected final Log log = LogFactory.getLog(getClass()); private Set<Thread> spawnedThreads = new HashSet<Thread>(); @AfterTest(alwaysRun = true) protected void killSpawnedThreads() { for (Thread t : spawnedThreads) { if (t.isAlive()) t.interrupt(); } } protected void eventually(Condition ec, long timeout) { int loops = 10; long sleepDuration = timeout / loops; try { for (int i = 0; i < loops; i++) { if (ec.isSatisfied()) break; Thread.sleep(sleepDuration); } assertEquals(true, ec.isSatisfied()); } catch (Exception e) { throw new RuntimeException("Unexpected!", e); } } protected Thread fork(Runnable r, boolean waitForCompletion) { final String name = "ForkThread-" + getClass().getSimpleName() + "-" + r.hashCode(); log.tracef("About to start thread '%s' as child of thread '%s'", name, Thread.currentThread().getName()); final Thread t = new Thread(new RunnableWrapper(r), name); spawnedThreads.add(t); t.start(); if (waitForCompletion) { eventually(new Condition() { @Override public boolean isSatisfied() throws Exception { return t.getState().equals(Thread.State.TERMINATED); } }); } return t; } protected <T> Future<T> fork(Callable<T> c) { final String name = "ForkThread-" + getClass().getSimpleName() + "-" + c.hashCode(); log.tracef("About to start thread '%s' as child of thread '%s'", name, Thread.currentThread().getName()); FutureTask future = new FutureTask(c); final Thread t = new Thread(future); spawnedThreads.add(t); t.start(); return future; } public final class RunnableWrapper implements Runnable { final Runnable realOne; public RunnableWrapper(Runnable realOne) { this.realOne = realOne; } @Override public void run() { try { log.trace("Started fork thread.."); realOne.run(); } catch (Throwable e) { log.trace("Exiting fork thread due to exception", e); } finally { log.trace("Exiting fork thread."); } } } protected void eventually(Condition ec) { eventually(ec, 10000); } protected interface Condition { public boolean isSatisfied() throws Exception; } }