Home | About | Sematext search-lucene.com search-hadoop.com
 Search Hadoop and all its subprojects:

Switch to Threaded View
Zookeeper, mail # user - Embedded ZK instance for unit testing


Copy link to this message
-
Embedded ZK instance for unit testing
Joshua Blatt 2012-12-03, 19:39
Hi guys,

I've seen a few threads on why it's a bad idea to try to embed ZK in your app.   I'm not trying to do that for my production app.   I am trying to do that for unit tests.   I could try to mock out ZK but I'm concerned that'd be both a lot of typing and wouldn't, well, test against the real thing.

Has anyone done this before?

When I tried doing this I saw the ZK session request initiated by the unit test go through (after first trying IPv6, then falling back to IPv4), but then the first operation attempted timed out after 40 seconds.   The same test case passes against a 3 node external ZK cluster.

Note that I'm spinning up a new ZK instance for every test run - I've tried inserting a several minute sleep after startup to give it time to initialize, but that didn't make a difference.
import java.io.File;
import java.util.UUID;
import java.util.concurrent.Semaphore;
import org.apache.commons.io.FileUtils;
import org.apache.zookeeper.server.ZooKeeperServerMain;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * A single-node embedded zookeeper server. <p>
 * WARNING: This class is only intended for unit testing. It's not production-
 * grade.
 *
 * @author jblatt
 */
public class EmbeddedZooKeeper extends ZooKeeperServerMain {

    private static final Logger LOGGER             LoggerFactory.getLogger(EmbeddedZooKeeper.class);
    private final File dataDir = new File(
            FileUtils.getTempDirectoryPath() + "/"
            + UUID.randomUUID().toString());
    private final int clientPort;
    private final Semaphore isRunning = new Semaphore(0);
    private Thread thread;

    public EmbeddedZooKeeper(int clientPort) throws ZooKeeperException {
        this.clientPort = clientPort;
    }

    public void start() throws ZooKeeperException {
        try {
            FileUtils.forceMkdir(dataDir);

            final EmbeddedZooKeeper self = this;

            thread = new Thread() {

                @Override
                public void run() {
                    try {
                        LOGGER.info("Starting ZK server");

                        self.initializeAndRun(new String[]{
                                    Integer.toString(clientPort),
                                    dataDir.getAbsolutePath()});

                        LOGGER.info("Started ZK server");

                        isRunning.acquire();

                        LOGGER.info("Stopped ZK server");

                    } catch (Throwable t) {
                        LOGGER.error("Failure in embedded ZooKeeper", t);
                    }
                }
            };

            thread.start();
        } catch (Throwable t) {
            throw new ZooKeeperException("Cannot start embedded zookeeper", t);
        }
    }

    public void stop() throws ZooKeeperException {
        try {
            LOGGER.info("Stopping ZK server");

            super.shutdown();

            isRunning.release();

            thread.join();
        } catch (Throwable t) {
            throw new ZooKeeperException("Cannot stop embedded zookeeper", t);
        } finally {
            // Unconditionally try to cleanup tmp dirs even if this is done
            // on a running ZK server.   We don't want to clutter up the user's
            // local fs.

            try {
                FileUtils.deleteDirectory(dataDir);
            } catch (Throwable t) {
                LOGGER.error("Cannot cleanup tmp dirs {}",
                        dataDir.getAbsolutePath());
            }
        }
    }
}

Log output:

11:07:24.064 INFO  [main] st.ata.vcc.proxy.common.model.EmbeddedZooKeeperForUnitTest - Begin EmbeddedZooKeeperForUnitTests.start()
11:07:24.066 INFO  [main] st.ata.vcc.proxy.common.model.EmbeddedZooKeeperForUnitTest - Embedded ZooKeeper started
11:07:24.066 INFO  [Thread-1] st.ata.vcc.control.core.zookeeper.EmbeddedZooKeeper - Starting ZK server
11:07:24.086 INFO  [main] st.ata.vcc.proxy.common.model.RoutePublisherTest - Begin RoutePublisherTest.start()
11:07:24.087 DEBUG [main] st.ata.vcc.proxy.common.model.RoutePublisher - Starting ZK connection on st.ata.vcc.proxy.common.model.RoutePublisher@6b08d7cf
11:07:24.087 INFO  [main] st.ata.vcc.control.core.zookeeper.ZooKeeperConnection - Connecting to localhost:2181
11:07:24.093 INFO  [main] org.apache.zookeeper.ZooKeeper - Client environment:zookeeper.version=3.4.5-1392090, built on 09/30/2012 17:52 GMT
11:07:24.093 INFO  [main] org.apache.zookeeper.ZooKeeper - Client environment:host.name=10.66.225.162
11:07:24.093 INFO  [main] org.apache.zookeeper.ZooKeeper - Client environment:java.version=1.7.0_05
11:07:24.093 INFO  [main] org.apache.zookeeper.ZooKeeper - Client environment:java.vendor=Oracle Corporation
11:07:24.093 INFO  [main] org.apache.zookeeper.ZooKeeper - Client environment:java.home=/Library/Java/JavaVirtualMachines/1.7.0.jdk/Contents/Home/jre
11:07:24.093 INFO  [main] org.apache.zookeeper.ZooKeeper - Client environment:java.class.path=/Users/jblatt/dev/proxy/common/target/test-classes:/Users/jblatt/dev/proxy/common/target/classes:/Users/jblatt/.m2/repository/st/ata/control/core/0.2.67/core-0.2.67.jar:/Users/jblatt/.m2/repository/org/mortbay/jetty/jetty/7.0.0.pre5/jetty-7.0.0.pre5.jar:/Users/jblatt/.m2/repository/org/mortbay/jetty/servlet-api/3.0.pre4/servlet-api-3.0.pre4.jar:/Users/jblatt/.m2/repository/org/mortbay/jetty/jetty-util/7.0.0.pre5/jetty-util-7.0.0.pre5.jar:/Users/jblatt/.m2/repository/org/mortbay/jetty/jetty-ssl/7.0.0.pre5/jetty-ssl-7.0.0.pre5.jar:/Users/jblatt/.m2/repository/org/mortbay/jetty/jetty-security/7.0.0.pre5/jetty-security-7.0.0.pre5.jar:/Users/jblatt/.m2/repository/org/mortbay/jetty/jetty-xml/7.0.0.pre5/jetty-xml-7.0.0.pre5.jar:/Users/jblatt/.m2/repository/com/sun/jersey/jersey-grizzly2/1.12/jersey-grizzly2-1.12.jar:/Users/jblatt/.m2/repository/com/sun/jersey/jersey-server/1.12/jersey-server-1.12.jar:/Users/jblatt/.m2/repository/asm/asm/3.1/asm-3.1.jar:/Users/jblatt/.m2/repository/com/sun/jersey/jersey-core/1