org.elasticsearch.test.hamcrest.ElasticsearchAssertions.java Source code

Java tutorial

Introduction

Here is the source code for org.elasticsearch.test.hamcrest.ElasticsearchAssertions.java

Source

/*
 * Licensed to Elasticsearch under one or more contributor
 * license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright
 * ownership. Elasticsearch 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.elasticsearch.test.hamcrest;

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.Iterables;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Query;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.ElasticsearchIllegalStateException;
import org.elasticsearch.ExceptionsHelper;
import org.elasticsearch.Version;
import org.elasticsearch.action.ActionFuture;
import org.elasticsearch.action.ActionRequest;
import org.elasticsearch.action.ActionRequestBuilder;
import org.elasticsearch.action.ShardOperationFailedException;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequestBuilder;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse;
import org.elasticsearch.action.admin.cluster.node.info.PluginInfo;
import org.elasticsearch.action.admin.cluster.node.info.PluginsInfo;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequestBuilder;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexResponse;
import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.count.CountResponse;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.percolate.PercolateResponse;
import org.elasticsearch.action.search.SearchPhaseExecutionException;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.ShardSearchFailure;
import org.elasticsearch.action.support.broadcast.BroadcastOperationResponse;
import org.elasticsearch.action.support.master.AcknowledgedRequestBuilder;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.cluster.metadata.IndexTemplateMetaData;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.stream.BytesStreamInput;
import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.Streamable;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.suggest.Suggest;
import org.elasticsearch.test.engine.MockInternalEngine;
import org.elasticsearch.test.store.MockDirectoryHelper;
import org.hamcrest.Matcher;
import org.hamcrest.Matchers;
import org.junit.Assert;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.concurrent.TimeUnit;

import static com.google.common.base.Predicates.isNull;
import static org.elasticsearch.test.ElasticsearchTestCase.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

/**
 *
 */
public class ElasticsearchAssertions {

    public static void assertAcked(AcknowledgedRequestBuilder<?, ?, ?> builder) {
        assertAcked(builder.get());
    }

    public static void assertNoTimeout(ClusterHealthRequestBuilder requestBuilder) {
        assertNoTimeout(requestBuilder.get());
    }

    public static void assertNoTimeout(ClusterHealthResponse response) {
        assertThat("ClusterHealthResponse has timed out - returned status: [" + response.getStatus() + "]",
                response.isTimedOut(), is(false));
    }

    public static void assertAcked(AcknowledgedResponse response) {
        assertThat(response.getClass().getSimpleName() + " failed - not acked", response.isAcknowledged(),
                equalTo(true));
        assertVersionSerializable(response);
    }

    public static void assertAcked(DeleteIndexRequestBuilder builder) {
        assertAcked(builder.get());
    }

    public static void assertAcked(DeleteIndexResponse response) {
        assertThat("Delete Index failed - not acked", response.isAcknowledged(), equalTo(true));
        assertVersionSerializable(response);
    }

    public static String formatShardStatus(BroadcastOperationResponse response) {
        String msg = " Total shards: " + response.getTotalShards() + " Successful shards: "
                + response.getSuccessfulShards() + " & " + response.getFailedShards() + " shard failures:";
        for (ShardOperationFailedException failure : response.getShardFailures()) {
            msg += "\n " + failure.toString();
        }
        return msg;
    }

    public static String formatShardStatus(SearchResponse response) {
        String msg = " Total shards: " + response.getTotalShards() + " Successful shards: "
                + response.getSuccessfulShards() + " & " + response.getFailedShards() + " shard failures:";
        for (ShardSearchFailure failure : response.getShardFailures()) {
            msg += "\n " + failure.toString();
        }
        return msg;
    }

    /*
     * assertions
     */
    public static void assertHitCount(SearchResponse searchResponse, long expectedHitCount) {
        if (searchResponse.getHits().totalHits() != expectedHitCount) {
            fail("Hit count is " + searchResponse.getHits().totalHits() + " but " + expectedHitCount
                    + " was expected. " + formatShardStatus(searchResponse));
        }
        assertVersionSerializable(searchResponse);
    }

    public static void assertSearchHits(SearchResponse searchResponse, String... ids) {
        String shardStatus = formatShardStatus(searchResponse);
        assertThat("Expected different hit count. " + shardStatus, searchResponse.getHits().hits().length,
                equalTo(ids.length));

        Set<String> idsSet = new HashSet<>(Arrays.asList(ids));
        for (SearchHit hit : searchResponse.getHits()) {
            assertThat("Expected id: " + hit.getId() + " in the result but wasn't." + shardStatus,
                    idsSet.remove(hit.getId()), equalTo(true));
        }
        assertThat("Expected ids: " + Arrays.toString(idsSet.toArray(new String[idsSet.size()]))
                + " in the result - result size differs." + shardStatus, idsSet.size(), equalTo(0));
        assertVersionSerializable(searchResponse);
    }

    public static void assertOrderedSearchHits(SearchResponse searchResponse, String... ids) {
        String shardStatus = formatShardStatus(searchResponse);
        assertThat("Expected different hit count. " + shardStatus, searchResponse.getHits().hits().length,
                equalTo(ids.length));
        for (int i = 0; i < ids.length; i++) {
            SearchHit hit = searchResponse.getHits().hits()[i];
            assertThat("Expected id: " + ids[i] + " at position " + i + " but wasn't." + shardStatus, hit.getId(),
                    equalTo(ids[i]));
        }
        assertVersionSerializable(searchResponse);
    }

    public static void assertHitCount(CountResponse countResponse, long expectedHitCount) {
        if (countResponse.getCount() != expectedHitCount) {
            fail("Count is " + countResponse.getCount() + " but " + expectedHitCount + " was expected. "
                    + formatShardStatus(countResponse));
        }
        assertVersionSerializable(countResponse);
    }

    public static void assertMatchCount(PercolateResponse percolateResponse, long expectedHitCount) {
        if (percolateResponse.getCount() != expectedHitCount) {
            fail("Count is " + percolateResponse.getCount() + " but " + expectedHitCount + " was expected. "
                    + formatShardStatus(percolateResponse));
        }
        assertVersionSerializable(percolateResponse);
    }

    public static void assertExists(GetResponse response) {
        String message = String.format(Locale.ROOT, "Expected %s/%s/%s to exist, but does not", response.getIndex(),
                response.getType(), response.getId());
        assertThat(message, response.isExists(), is(true));
    }

    public static void assertFirstHit(SearchResponse searchResponse, Matcher<SearchHit> matcher) {
        assertSearchHit(searchResponse, 1, matcher);
    }

    public static void assertSecondHit(SearchResponse searchResponse, Matcher<SearchHit> matcher) {
        assertSearchHit(searchResponse, 2, matcher);
    }

    public static void assertThirdHit(SearchResponse searchResponse, Matcher<SearchHit> matcher) {
        assertSearchHit(searchResponse, 3, matcher);
    }

    public static void assertSearchHit(SearchResponse searchResponse, int number, Matcher<SearchHit> matcher) {
        assertThat(number, greaterThan(0));
        assertThat("SearchHit number must be greater than 0", number, greaterThan(0));
        assertThat(searchResponse.getHits().totalHits(), greaterThanOrEqualTo((long) number));
        assertSearchHit(searchResponse.getHits().getAt(number - 1), matcher);
        assertVersionSerializable(searchResponse);
    }

    public static void assertNoFailures(SearchResponse searchResponse) {
        assertThat("Unexpected ShardFailures: " + Arrays.toString(searchResponse.getShardFailures()),
                searchResponse.getShardFailures().length, equalTo(0));
        assertVersionSerializable(searchResponse);
    }

    public static void assertFailures(SearchResponse searchResponse) {
        assertThat("Expected at least one shard failure, got none", searchResponse.getShardFailures().length,
                greaterThan(0));
        assertVersionSerializable(searchResponse);
    }

    public static void assertNoFailures(BulkResponse response) {
        assertThat("Unexpected ShardFailures: " + response.buildFailureMessage(), response.hasFailures(),
                is(false));
        assertVersionSerializable(response);
    }

    public static void assertFailures(SearchRequestBuilder searchRequestBuilder, RestStatus restStatus,
            Matcher<String> reasonMatcher) {
        //when the number for shards is randomized and we expect failures
        //we can either run into partial or total failures depending on the current number of shards
        try {
            SearchResponse searchResponse = searchRequestBuilder.get();
            assertThat("Expected shard failures, got none", searchResponse.getShardFailures().length,
                    greaterThan(0));
            for (ShardSearchFailure shardSearchFailure : searchResponse.getShardFailures()) {
                assertThat(shardSearchFailure.status(), equalTo(restStatus));
                assertThat(shardSearchFailure.reason(), reasonMatcher);
            }
            assertVersionSerializable(searchResponse);
        } catch (SearchPhaseExecutionException e) {
            assertThat(e.status(), equalTo(restStatus));
            assertThat(e.getMessage(), reasonMatcher);
            for (ShardSearchFailure shardSearchFailure : e.shardFailures()) {
                assertThat(shardSearchFailure.status(), equalTo(restStatus));
                assertThat(shardSearchFailure.reason(), reasonMatcher);
            }
        } catch (Exception e) {
            fail("SearchPhaseExecutionException expected but got " + e.getClass());
        }
    }

    public static void assertNoFailures(BroadcastOperationResponse response) {
        assertThat("Unexpected ShardFailures: " + Arrays.toString(response.getShardFailures()),
                response.getFailedShards(), equalTo(0));
        assertVersionSerializable(response);
    }

    public static void assertAllSuccessful(BroadcastOperationResponse response) {
        assertNoFailures(response);
        assertThat(
                "Expected all shards successful but got successful [" + response.getSuccessfulShards() + "] total ["
                        + response.getTotalShards() + "]",
                response.getTotalShards(), equalTo(response.getSuccessfulShards()));
        assertVersionSerializable(response);
    }

    public static void assertAllSuccessful(SearchResponse response) {
        assertNoFailures(response);
        assertThat(
                "Expected all shards successful but got successful [" + response.getSuccessfulShards() + "] total ["
                        + response.getTotalShards() + "]",
                response.getTotalShards(), equalTo(response.getSuccessfulShards()));
        assertVersionSerializable(response);
    }

    public static void assertSearchHit(SearchHit searchHit, Matcher<SearchHit> matcher) {
        assertThat(searchHit, matcher);
        assertVersionSerializable(searchHit);
    }

    public static void assertHighlight(SearchResponse resp, int hit, String field, int fragment,
            Matcher<String> matcher) {
        assertHighlight(resp, hit, field, fragment, greaterThan(fragment), matcher);
    }

    public static void assertHighlight(SearchResponse resp, int hit, String field, int fragment, int totalFragments,
            Matcher<String> matcher) {
        assertHighlight(resp, hit, field, fragment, equalTo(totalFragments), matcher);
    }

    public static void assertHighlight(SearchHit hit, String field, int fragment, Matcher<String> matcher) {
        assertHighlight(hit, field, fragment, greaterThan(fragment), matcher);
    }

    public static void assertHighlight(SearchHit hit, String field, int fragment, int totalFragments,
            Matcher<String> matcher) {
        assertHighlight(hit, field, fragment, equalTo(totalFragments), matcher);
    }

    private static void assertHighlight(SearchResponse resp, int hit, String field, int fragment,
            Matcher<Integer> fragmentsMatcher, Matcher<String> matcher) {
        assertNoFailures(resp);
        assertThat("not enough hits", resp.getHits().hits().length, greaterThan(hit));
        assertHighlight(resp.getHits().hits()[hit], field, fragment, fragmentsMatcher, matcher);
        assertVersionSerializable(resp);
    }

    private static void assertHighlight(SearchHit hit, String field, int fragment,
            Matcher<Integer> fragmentsMatcher, Matcher<String> matcher) {
        assertThat(hit.getHighlightFields(), hasKey(field));
        assertThat(hit.getHighlightFields().get(field).fragments().length, fragmentsMatcher);
        assertThat(hit.highlightFields().get(field).fragments()[fragment].string(), matcher);
    }

    public static void assertNotHighlighted(SearchResponse resp, int hit, String field) {
        assertNoFailures(resp);
        assertThat("not enough hits", resp.getHits().hits().length, greaterThan(hit));
        assertThat(resp.getHits().hits()[hit].getHighlightFields(), not(hasKey(field)));
    }

    public static void assertSuggestionSize(Suggest searchSuggest, int entry, int size, String key) {
        assertThat(searchSuggest, notNullValue());
        String msg = "Suggest result: " + searchSuggest.toString();
        assertThat(msg, searchSuggest.size(), greaterThanOrEqualTo(1));
        assertThat(msg, searchSuggest.getSuggestion(key).getName(), equalTo(key));
        assertThat(msg, searchSuggest.getSuggestion(key).getEntries().size(), greaterThanOrEqualTo(entry));
        assertThat(msg, searchSuggest.getSuggestion(key).getEntries().get(entry).getOptions().size(),
                equalTo(size));
        assertVersionSerializable(searchSuggest);
    }

    public static void assertSuggestion(Suggest searchSuggest, int entry, int ord, String key, String text) {
        assertThat(searchSuggest, notNullValue());
        String msg = "Suggest result: " + searchSuggest.toString();
        assertThat(msg, searchSuggest.size(), greaterThanOrEqualTo(1));
        assertThat(msg, searchSuggest.getSuggestion(key).getName(), equalTo(key));
        assertThat(msg, searchSuggest.getSuggestion(key).getEntries().size(), greaterThanOrEqualTo(entry));
        assertThat(msg, searchSuggest.getSuggestion(key).getEntries().get(entry).getOptions().size(),
                greaterThan(ord));
        assertThat(msg,
                searchSuggest.getSuggestion(key).getEntries().get(entry).getOptions().get(ord).getText().string(),
                equalTo(text));
        assertVersionSerializable(searchSuggest);
    }

    /**
     * Assert suggestion returns exactly the provided text.
     */
    public static void assertSuggestion(Suggest searchSuggest, int entry, String key, String... text) {
        assertSuggestion(searchSuggest, entry, key, text.length, text);
    }

    /**
     * Assert suggestion returns size suggestions and the first are the provided
     * text.
     */
    public static void assertSuggestion(Suggest searchSuggest, int entry, String key, int size, String... text) {
        assertSuggestionSize(searchSuggest, entry, size, key);
        for (int i = 0; i < text.length; i++) {
            assertSuggestion(searchSuggest, entry, i, key, text[i]);
        }
    }

    /**
     * Assert that an index template is missing
     */
    public static void assertIndexTemplateMissing(GetIndexTemplatesResponse templatesResponse, String name) {
        List<String> templateNames = new ArrayList<>();
        for (IndexTemplateMetaData indexTemplateMetaData : templatesResponse.getIndexTemplates()) {
            templateNames.add(indexTemplateMetaData.name());
        }
        assertThat(templateNames, not(hasItem(name)));
    }

    /**
     * Assert that an index template exists
     */
    public static void assertIndexTemplateExists(GetIndexTemplatesResponse templatesResponse, String name) {
        List<String> templateNames = new ArrayList<>();
        for (IndexTemplateMetaData indexTemplateMetaData : templatesResponse.getIndexTemplates()) {
            templateNames.add(indexTemplateMetaData.name());
        }
        assertThat(templateNames, hasItem(name));
    }

    /*
     * matchers
     */
    public static Matcher<SearchHit> hasId(final String id) {
        return new ElasticsearchMatchers.SearchHitHasIdMatcher(id);
    }

    public static Matcher<SearchHit> hasType(final String type) {
        return new ElasticsearchMatchers.SearchHitHasTypeMatcher(type);
    }

    public static Matcher<SearchHit> hasIndex(final String index) {
        return new ElasticsearchMatchers.SearchHitHasIndexMatcher(index);
    }

    public static Matcher<SearchHit> hasScore(final float score) {
        return new ElasticsearchMatchers.SearchHitHasScoreMatcher(score);
    }

    public static <T extends Query> T assertBooleanSubQuery(Query query, Class<T> subqueryType, int i) {
        assertThat(query, instanceOf(BooleanQuery.class));
        BooleanQuery q = (BooleanQuery) query;
        assertThat(q.getClauses().length, greaterThan(i));
        assertThat(q.getClauses()[i].getQuery(), instanceOf(subqueryType));
        return (T) q.getClauses()[i].getQuery();
    }

    public static <E extends Throwable> void assertThrows(ActionRequestBuilder<?, ?, ?> builder,
            Class<E> exceptionClass) {
        assertThrows(builder.execute(), exceptionClass);
    }

    public static <E extends Throwable> void assertThrows(ActionRequestBuilder<?, ?, ?> builder,
            Class<E> exceptionClass, String extraInfo) {
        assertThrows(builder.execute(), exceptionClass, extraInfo);
    }

    public static <E extends Throwable> void assertThrows(ActionFuture future, Class<E> exceptionClass) {
        assertThrows(future, exceptionClass, null);
    }

    public static <E extends Throwable> void assertThrows(ActionFuture future, Class<E> exceptionClass,
            String extraInfo) {
        boolean fail = false;
        extraInfo = extraInfo == null || extraInfo.isEmpty() ? "" : extraInfo + ": ";
        extraInfo += "expected a " + exceptionClass + " exception to be thrown";

        try {
            future.actionGet();
            fail = true;

        } catch (ElasticsearchException esException) {
            assertThat(extraInfo, esException.unwrapCause(), instanceOf(exceptionClass));
        } catch (Throwable e) {
            assertThat(extraInfo, e, instanceOf(exceptionClass));
        }
        // has to be outside catch clause to get a proper message
        if (fail) {
            throw new AssertionError(extraInfo);
        }
    }

    public static <E extends Throwable> void assertThrows(ActionRequestBuilder<?, ?, ?> builder,
            RestStatus status) {
        assertThrows(builder.execute(), status);
    }

    public static <E extends Throwable> void assertThrows(ActionRequestBuilder<?, ?, ?> builder, RestStatus status,
            String extraInfo) {
        assertThrows(builder.execute(), status, extraInfo);
    }

    public static <E extends Throwable> void assertThrows(ActionFuture future, RestStatus status) {
        assertThrows(future, status, null);
    }

    public static void assertThrows(ActionFuture future, RestStatus status, String extraInfo) {
        boolean fail = false;
        extraInfo = extraInfo == null || extraInfo.isEmpty() ? "" : extraInfo + ": ";
        extraInfo += "expected a " + status + " status exception to be thrown";

        try {
            future.actionGet();
            fail = true;
        } catch (Throwable e) {
            assertThat(extraInfo, ExceptionsHelper.status(e), equalTo(status));
        }
        // has to be outside catch clause to get a proper message
        if (fail) {
            throw new AssertionError(extraInfo);
        }
    }

    private static BytesReference serialize(Version version, Streamable streamable) throws IOException {
        BytesStreamOutput output = new BytesStreamOutput();
        output.setVersion(version);
        streamable.writeTo(output);
        output.flush();
        return output.bytes();
    }

    public static void assertVersionSerializable(Streamable streamable) {
        assertTrue(Version.CURRENT.after(getPreviousVersion()));
        assertVersionSerializable(randomVersion(), streamable);
    }

    public static void assertVersionSerializable(Version version, Streamable streamable) {
        try {
            Streamable newInstance = tryCreateNewInstance(streamable);
            if (newInstance == null) {
                return; // can't create a new instance - we never modify a
                        // streamable that comes in.
            }
            if (streamable instanceof ActionRequest) {
                ((ActionRequest<?>) streamable).validate();
            }
            BytesReference orig = serialize(version, streamable);
            StreamInput input = new BytesStreamInput(orig);
            input.setVersion(version);
            newInstance.readFrom(input);
            assertThat("Stream should be fully read with version [" + version + "] for streamable [" + streamable
                    + "]", input.available(), equalTo(0));
            assertThat("Serialization failed with version [" + version + "] bytes should be equal for streamable ["
                    + streamable + "]", serialize(version, streamable), equalTo(orig));
        } catch (Throwable ex) {
            throw new RuntimeException(
                    "failed to check serialization - version [" + version + "] for streamable [" + streamable + "]",
                    ex);
        }

    }

    private static Streamable tryCreateNewInstance(Streamable streamable) throws NoSuchMethodException,
            InstantiationException, IllegalAccessException, InvocationTargetException {
        try {
            Class<? extends Streamable> clazz = streamable.getClass();
            Constructor<? extends Streamable> constructor = clazz.getDeclaredConstructor();
            assertThat(constructor, Matchers.notNullValue());
            constructor.setAccessible(true);
            Streamable newInstance = constructor.newInstance();
            return newInstance;
        } catch (Throwable e) {
            return null;
        }
    }

    /**
     * Applies basic assertions on the SearchResponse. This method checks if all shards were successful, if
     * any of the shards threw an exception and if the response is serializeable.
     */
    public static SearchResponse assertSearchResponse(SearchRequestBuilder request) {
        return assertSearchResponse(request.get());
    }

    /**
     * Applies basic assertions on the SearchResponse. This method checks if all shards were successful, if
     * any of the shards threw an exception and if the response is serializeable.
     */
    public static SearchResponse assertSearchResponse(SearchResponse response) {
        assertNoFailures(response);
        assertThat("One or more shards were not successful but didn't trigger a failure",
                response.getSuccessfulShards(), equalTo(response.getTotalShards()));
        return response;
    }

    public static void assertAllSearchersClosed() {
        /* in some cases we finish a test faster than the freeContext calls make it to the
         * shards. Let's wait for some time if there are still searchers. If the are really
         * pending we will fail anyway.*/
        try {
            if (awaitBusy(new Predicate<Object>() {
                public boolean apply(Object o) {
                    return MockInternalEngine.INFLIGHT_ENGINE_SEARCHERS.isEmpty();
                }
            }, 5, TimeUnit.SECONDS)) {
                return;
            }
        } catch (InterruptedException ex) {
            if (MockInternalEngine.INFLIGHT_ENGINE_SEARCHERS.isEmpty()) {
                return;
            }
        }
        try {
            RuntimeException ex = null;
            StringBuilder builder = new StringBuilder("Unclosed Searchers instance for shards: [");
            for (Map.Entry<MockInternalEngine.AssertingSearcher, RuntimeException> entry : MockInternalEngine.INFLIGHT_ENGINE_SEARCHERS
                    .entrySet()) {
                ex = entry.getValue();
                builder.append(entry.getKey().shardId()).append(",");
            }
            builder.append("]");
            throw new RuntimeException(builder.toString(), ex);
        } finally {
            MockInternalEngine.INFLIGHT_ENGINE_SEARCHERS.clear();
        }
    }

    public static void assertAllFilesClosed() {
        try {
            for (final MockDirectoryHelper.ElasticsearchMockDirectoryWrapper w : MockDirectoryHelper.wrappers) {
                try {
                    awaitBusy(new Predicate<Object>() {
                        @Override
                        public boolean apply(Object input) {
                            return !w.isOpen();
                        }
                    });
                } catch (InterruptedException e) {
                    Thread.interrupted();
                }
                if (!w.successfullyClosed()) {
                    if (w.closeException() == null) {
                        try {
                            w.close();
                        } catch (IOException e) {
                            throw new ElasticsearchIllegalStateException("directory close threw IOException", e);
                        }
                        if (w.closeException() != null) {
                            throw w.closeException();
                        }
                    } else {
                        throw w.closeException();
                    }
                }
                assertThat(w.isOpen(), is(false));
            }
        } finally {
            MockDirectoryHelper.wrappers.clear();
        }
    }

    public static void assertNodeContainsPlugins(NodesInfoResponse response, String nodeId,
            List<String> expectedJvmPluginNames, List<String> expectedJvmPluginDescriptions,
            List<String> expectedJvmVersions, List<String> expectedSitePluginNames,
            List<String> expectedSitePluginDescriptions, List<String> expectedSiteVersions) {

        Assert.assertThat(response.getNodesMap().get(nodeId), notNullValue());

        PluginsInfo plugins = response.getNodesMap().get(nodeId).getPlugins();
        Assert.assertThat(plugins, notNullValue());

        List<String> pluginNames = FluentIterable.from(plugins.getInfos()).filter(jvmPluginPredicate)
                .transform(nameFunction).toList();
        for (String expectedJvmPluginName : expectedJvmPluginNames) {
            Assert.assertThat(pluginNames, hasItem(expectedJvmPluginName));
        }

        List<String> pluginDescriptions = FluentIterable.from(plugins.getInfos()).filter(jvmPluginPredicate)
                .transform(descriptionFunction).toList();
        for (String expectedJvmPluginDescription : expectedJvmPluginDescriptions) {
            Assert.assertThat(pluginDescriptions, hasItem(expectedJvmPluginDescription));
        }

        List<String> jvmPluginVersions = FluentIterable.from(plugins.getInfos()).filter(jvmPluginPredicate)
                .transform(versionFunction).toList();
        for (String pluginVersion : expectedJvmVersions) {
            Assert.assertThat(jvmPluginVersions, hasItem(pluginVersion));
        }

        FluentIterable<String> jvmUrls = FluentIterable.from(plugins.getInfos())
                .filter(Predicates.and(jvmPluginPredicate, Predicates.not(sitePluginPredicate))).filter(isNull())
                .transform(urlFunction);
        Assert.assertThat(Iterables.size(jvmUrls), is(0));

        List<String> sitePluginNames = FluentIterable.from(plugins.getInfos()).filter(sitePluginPredicate)
                .transform(nameFunction).toList();
        Assert.assertThat(sitePluginNames.isEmpty(), is(expectedSitePluginNames.isEmpty()));
        for (String expectedSitePluginName : expectedSitePluginNames) {
            Assert.assertThat(sitePluginNames, hasItem(expectedSitePluginName));
        }

        List<String> sitePluginDescriptions = FluentIterable.from(plugins.getInfos()).filter(sitePluginPredicate)
                .transform(descriptionFunction).toList();
        Assert.assertThat(sitePluginDescriptions.isEmpty(), is(expectedSitePluginDescriptions.isEmpty()));
        for (String sitePluginDescription : expectedSitePluginDescriptions) {
            Assert.assertThat(sitePluginDescriptions, hasItem(sitePluginDescription));
        }

        List<String> sitePluginUrls = FluentIterable.from(plugins.getInfos()).filter(sitePluginPredicate)
                .transform(urlFunction).toList();
        Assert.assertThat(sitePluginUrls, not(contains(nullValue())));

        List<String> sitePluginVersions = FluentIterable.from(plugins.getInfos()).filter(sitePluginPredicate)
                .transform(versionFunction).toList();
        Assert.assertThat(sitePluginVersions.isEmpty(), is(expectedSiteVersions.isEmpty()));
        for (String pluginVersion : expectedSiteVersions) {
            Assert.assertThat(sitePluginVersions, hasItem(pluginVersion));
        }
    }

    private static Predicate<PluginInfo> jvmPluginPredicate = new Predicate<PluginInfo>() {
        public boolean apply(PluginInfo pluginInfo) {
            return pluginInfo.isJvm();
        }
    };

    private static Predicate<PluginInfo> sitePluginPredicate = new Predicate<PluginInfo>() {
        public boolean apply(PluginInfo pluginInfo) {
            return pluginInfo.isSite();
        }
    };

    private static Function<PluginInfo, String> nameFunction = new Function<PluginInfo, String>() {
        public String apply(PluginInfo pluginInfo) {
            return pluginInfo.getName();
        }
    };

    private static Function<PluginInfo, String> descriptionFunction = new Function<PluginInfo, String>() {
        public String apply(PluginInfo pluginInfo) {
            return pluginInfo.getDescription();
        }
    };

    private static Function<PluginInfo, String> urlFunction = new Function<PluginInfo, String>() {
        public String apply(PluginInfo pluginInfo) {
            return pluginInfo.getUrl();
        }
    };

    private static Function<PluginInfo, String> versionFunction = new Function<PluginInfo, String>() {
        public String apply(PluginInfo pluginInfo) {
            return pluginInfo.getVersion();
        }
    };
}