All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.dasasian.chok.testutil.TestUtil Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (C) 2014 Dasasian ([email protected])
 *
 * Licensed 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 com.dasasian.chok.testutil;

import com.dasasian.chok.client.Client;
import com.dasasian.chok.master.Master;
import com.dasasian.chok.node.Node;
import com.dasasian.chok.protocol.InteractionProtocol;
import com.dasasian.chok.protocol.metadata.IndexMetaData;
import com.dasasian.chok.protocol.metadata.IndexMetaData.Shard;
import com.dasasian.chok.util.ZkConfiguration;
import com.dasasian.chok.util.ZkConfiguration.PathDef;
import org.I0Itec.zkclient.exception.ZkNoNodeException;
import org.mockito.Mockito;
import org.mockito.exceptions.base.MockitoAssertionError;
import org.mockito.stubbing.Stubber;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import static org.fest.assertions.Assertions.assertThat;
import static org.junit.Assert.assertEquals;

public class TestUtil {

    private static final Logger LOG = LoggerFactory.getLogger(TestUtil.class);

    /**
     * This waits until the provided {@link Callable} returns an object that is
     * equals to the given expected value or the timeout has been reached. In both
     * cases this method will return the return value of the latest
     * {@link Callable} execution.
     *
     * @param expectedValue The expected value of the callable.
     * @param callable      The callable.
     * @param            The return type of the callable.
     * @param timeUnit      The timeout timeunit.
     * @param timeout       The timeout.
     * @return the return value of the latest {@link Callable} execution.
     * @throws Exception when an error occurs
     * @throws InterruptedException when interrupted
     */
    public static  T waitUntil(T expectedValue, Callable callable, TimeUnit timeUnit, long timeout) throws Exception {
        long startTime = System.currentTimeMillis();
        do {
            T actual = callable.call();
            if (expectedValue.equals(actual)) {
                return actual;
            }
            if (System.currentTimeMillis() > startTime + timeUnit.toMillis(timeout)) {
                return actual;
            }
            Thread.sleep(50);
        } while (true);
    }

    /**
     * This waits until a mockito verification passed (which is provided in the
     * runnable). This waits until the virification passed or the timeout has been
     * reached. If the timeout has been reached this method will rethrow the
     * {@link MockitoAssertionError} that comes from the mockito verification
     * code.
     *
     * @param runnable The runnable containing the mockito verification.
     * @param timeUnit The timeout timeunit.
     * @param timeout  The timeout.
     * @throws InterruptedException when interrupted
     */
    public static void waitUntilVerified(Runnable runnable, TimeUnit timeUnit, int timeout) throws InterruptedException {
        LOG.debug("Waiting for " + timeout + " " + timeUnit + " until verified.");
        long startTime = System.currentTimeMillis();
        do {
            MockitoAssertionError exception = null;
            try {
                runnable.run();
            } catch (MockitoAssertionError e) {
                exception = e;
            }
            if (exception == null) {
                return;
            }
            if (System.currentTimeMillis() > startTime + timeUnit.toMillis(timeout)) {
                LOG.debug("Timeout reached without satifying expectations.");
                throw exception;
            }
            Thread.sleep(50);
        } while (true);
    }

    public static void waitUntilNoExceptionThrown(Runnable runnable, TimeUnit timeUnit, int timeout) throws InterruptedException {
        long startTime = System.currentTimeMillis();
        do {
            RuntimeException exception = null;
            try {
                runnable.run();
            } catch (RuntimeException e) {
                exception = e;
            }
            if (exception == null) {
                return;
            }
            if (System.currentTimeMillis() > startTime + timeUnit.toMillis(timeout)) {
                throw exception;
            }
            Thread.sleep(50);
        } while (true);
    }

    /**
     * Creates a Mockito answer object that can be used for asynchronously
     * stubbing. For example:
     * 
*
     * final CountDownLatch countDownLatch = new CountDownLatch(1);
     * Mockito.doAnswer(TestUtil.createCountDownAnswer(countDownLatch)).when(listener).announceNode(nodeName);
     * mock.someMethod(someValue);
     * countDownLatch.await(10, TimeUnit.SECONDS);
     * Assert.assertEquals("expecting invocation within 10 seconds", 0, countDownLatch.getCount());
     * 
* @param countDownLatch the countdown latch * @return the stubber */ public static Stubber createCountDownAnswer(final CountDownLatch countDownLatch) { return Mockito.doAnswer(invocation -> { countDownLatch.countDown(); return null; }); } public static boolean indexHasDeployError(final InteractionProtocol protocol, final String indexName) throws Exception { IndexMetaData indexMetaData = protocol.getIndexMD(indexName); return indexMetaData.hasDeployError(); } public static void waitUntilLeaveSafeMode(final Master master) throws Exception { waitUntil(false, master::isInSafeMode, TimeUnit.SECONDS, 30); assertEquals(false, master.isInSafeMode()); } public static void waitUntilBecomeMaster(final Master master) throws Exception { waitUntil(false, () -> !master.isMaster(), TimeUnit.SECONDS, 30); assertEquals(true, master.isMaster()); } public static void waitUntilIndexDeployed(final InteractionProtocol protocol, final String indexName) throws Exception { waitUntil(false, () -> protocol.getIndexMD(indexName) == null, TimeUnit.SECONDS, 30); } public static void waitUntilIndexBalanced(final InteractionProtocol protocol, final String indexName) throws Exception { waitUntil(true, () -> { IndexMetaData indexMD = protocol.getIndexMD(indexName); if (indexMD.hasDeployError()) { throw new IllegalStateException("index " + indexName + " has a deploy error"); } return protocol.getReplicationReport(indexMD, protocol.getLiveNodeCount()).isBalanced(); }, TimeUnit.SECONDS, 30); } public static void waitUntilShardsUndeployed(final InteractionProtocol protocol, final IndexMetaData indexMD) throws Exception { TestUtil.waitUntil(false, () -> { int nodeCount = 0; Set shards = indexMD.getShards(); for (Shard shard : shards) { try { nodeCount += protocol.getShardNodes(shard.getName()).size(); } catch (ZkNoNodeException e) { // deleted already } } return nodeCount != 0; }, TimeUnit.SECONDS, 30); } public static void waitUntilNodeServesShards(final InteractionProtocol protocol, final String nodeName, final int shardCount) throws Exception { waitUntil(true, () -> protocol.getNodeShards(nodeName).size() == shardCount, TimeUnit.SECONDS, 30); assertEquals(shardCount, protocol.getNodeShards(nodeName).size()); } public static void waitUntilNumberOfLiveNode(final InteractionProtocol protocol, final int nodeCount) throws Exception { waitUntil(true, () -> protocol.getLiveNodeCount() == nodeCount, TimeUnit.SECONDS, 30); assertEquals(nodeCount, protocol.getLiveNodeCount()); } public static void waitUntilEmptyOperationQueues(final InteractionProtocol protocol, final Master master, final List nodes) throws Exception { waitUntil(true, () -> operationQueuesEmpty(protocol, master, nodes), TimeUnit.SECONDS, 30); assertThat(operationQueuesEmpty(protocol, master, nodes)).as("node operation queues are empty").isTrue(); } private static Boolean operationQueuesEmpty(final InteractionProtocol protocol, Master master, final List nodes) { ZkConfiguration zkConf = protocol.getZkConfiguration(); if (protocol.getZkClient().countChildren(zkConf.getPath(PathDef.MASTER_QUEUE, "operations")) > 0) { return false; } for (Node node : nodes) { if (protocol.getZkClient().countChildren(zkConf.getPath(PathDef.NODE_QUEUE, node.getName(), "operations")) > 0) { return false; } } return true; } public static void waitUntilClientHasIndex(Client client, String indexName) throws InterruptedException { while (!client.hasIndex(indexName)) { Thread.sleep(10); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy