CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-elasticsearch--elasticsearch-test-framework

Test framework library for Elasticsearch providing comprehensive testing utilities, base test classes, cluster management, and assertion helpers for unit and integration testing of Elasticsearch plugins and applications

Pending
Overview
Eval results
Files

assertions-matchers.mddocs/

Assertions and Matchers

The Elasticsearch test framework provides extensive assertion utilities and custom Hamcrest matchers for validating search results, cluster state, responses, and other Elasticsearch-specific data structures. These utilities enable expressive and maintainable test assertions.

ElasticsearchAssertions

The core assertion utility class providing high-level assertions for Elasticsearch operations and responses.

package org.elasticsearch.test.hamcrest;

import org.elasticsearch.action.ActionFuture;
import org.elasticsearch.action.ActionResponse;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.cluster.health.ClusterHealthStatus;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.hamcrest.Matcher;

/**
 * Static utility methods for creating Elasticsearch-specific assertions and matchers.
 * Provides fluent, readable assertions for common Elasticsearch testing scenarios.
 */
public class ElasticsearchAssertions {
    
    /**
     * Asserts that an ActionFuture completes successfully within the default timeout.
     * 
     * @param future the future to wait for
     * @param <T> response type
     * @return the response from the future
     * @throws AssertionError if future fails or times out
     */
    public static <T extends ActionResponse> T assertAcked(ActionFuture<T> future);
    
    /**
     * Asserts that a response indicates an acknowledged operation.
     * 
     * @param response response to check
     * @throws AssertionError if operation was not acknowledged
     */
    public static void assertAcked(IsAcknowledgedSupplier response);
    
    /**
     * Asserts that a bulk response has no failures.
     * 
     * @param response bulk response to check
     * @throws AssertionError if any items in the bulk response failed
     */
    public static void assertNoFailures(BulkResponse response);
    
    /**
     * Asserts that a search response completed successfully with no failures.
     * 
     * @param response search response to check
     * @throws AssertionError if search had shard failures or timed out
     */
    public static void assertNoFailures(SearchResponse response);
    
    /**
     * Asserts that a cluster health response indicates the expected health status.
     * 
     * @param response cluster health response
     * @param expectedStatus expected health status
     * @throws AssertionError if health status doesn't match
     */
    public static void assertHealthStatus(ClusterHealthResponse response, 
                                        ClusterHealthStatus expectedStatus);
    
    /**
     * Asserts that a search response contains the expected number of hits.
     * 
     * @param response search response to check
     * @param expectedHits expected total hit count
     * @throws AssertionError if hit count doesn't match
     */
    public static void assertHitCount(SearchResponse response, long expectedHits);
    
    /**
     * Asserts that a search response contains exactly one hit.
     * 
     * @param response search response to check
     * @throws AssertionError if hit count is not exactly 1
     */
    public static void assertSingleHit(SearchResponse response);
    
    /**
     * Asserts that a search response contains no hits.
     * 
     * @param response search response to check  
     * @throws AssertionError if any hits are found
     */
    public static void assertNoSearchHits(SearchResponse response);
    
    /**
     * Asserts that search hits are ordered according to the specified sort criteria.
     * 
     * @param response search response to check
     * @param sortField field used for sorting
     * @param ascending true if sort should be ascending, false for descending
     * @throws AssertionError if hits are not properly sorted
     */
    public static void assertOrderedSearchHits(SearchResponse response, 
                                             String sortField, 
                                             boolean ascending);
    
    /**
     * Asserts that a SearchHit contains a field with the expected value.
     * 
     * @param hit search hit to check
     * @param field field name to check
     * @param expectedValue expected field value
     * @throws AssertionError if field value doesn't match
     */
    public static void assertSearchHitHasField(SearchHit hit, String field, Object expectedValue);
    
    /**
     * Asserts that a GetResponse indicates a document exists.
     * 
     * @param response get response to check
     * @throws AssertionError if document doesn't exist
     */
    public static void assertDocumentExists(GetResponse response);
    
    /**
     * Asserts that a GetResponse indicates a document does not exist.
     * 
     * @param response get response to check
     * @throws AssertionError if document exists
     */
    public static void assertDocumentMissing(GetResponse response);
    
    /**
     * Waits for and asserts cluster health reaches the specified status.
     * 
     * @param client client to use for health checks
     * @param status expected health status
     * @param indices indices to check (empty for all indices)
     */
    public static void ensureHealth(Client client, 
                                  ClusterHealthStatus status, 
                                  String... indices);
    
    /**
     * Waits for cluster to reach green health status.
     * 
     * @param client client to use for health checks
     * @param indices indices to check (empty for all indices)
     */
    public static void ensureGreen(Client client, String... indices);
    
    /**
     * Waits for cluster to reach yellow or green health status.
     * 
     * @param client client to use for health checks
     * @param indices indices to check (empty for all indices)
     */
    public static void ensureYellow(Client client, String... indices);
    
    /**
     * Asserts that two BytesReference objects are equal.
     * 
     * @param expected expected bytes
     * @param actual actual bytes
     * @throws AssertionError if bytes don't match
     */
    public static void assertBytesEqual(BytesReference expected, BytesReference actual);
    
    /**
     * Asserts that an exception was caused by a specific root cause.
     * 
     * @param exception exception to examine
     * @param expectedCause expected root cause class
     * @throws AssertionError if root cause doesn't match
     */
    public static void assertCausedBy(Throwable exception, Class<? extends Throwable> expectedCause);
}

Custom Hamcrest Matchers

Search Response Matchers

package org.elasticsearch.test.hamcrest;

import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.search.SearchHit;
import org.hamcrest.Matcher;

/**
 * Custom Hamcrest matchers for SearchResponse validation.
 */
public class SearchMatchers {
    
    /**
     * Matches SearchResponse with expected hit count.
     * 
     * @param expectedCount expected number of hits
     * @return matcher for hit count
     */
    public static Matcher<SearchResponse> hasHitCount(long expectedCount);
    
    /**
     * Matches SearchResponse with hit count in specified range.
     * 
     * @param min minimum hit count (inclusive)
     * @param max maximum hit count (inclusive) 
     * @return matcher for hit count range
     */
    public static Matcher<SearchResponse> hasHitCount(long min, long max);
    
    /**
     * Matches SearchResponse with no search failures.
     * 
     * @return matcher for successful search
     */
    public static Matcher<SearchResponse> isSuccessfulSearchResponse();
    
    /**
     * Matches SearchResponse that completed without timeout.
     * 
     * @return matcher for non-timed-out search
     */
    public static Matcher<SearchResponse> searchNotTimedOut();
    
    /**
     * Matches SearchResponse containing a hit with specified ID.
     * 
     * @param id document ID to match
     * @return matcher for document ID
     */
    public static Matcher<SearchResponse> hasHitWithId(String id);
    
    /**
     * Matches SearchResponse where hits are ordered by specified field.
     * 
     * @param field field name used for ordering
     * @param ascending true for ascending order, false for descending
     * @return matcher for search hit ordering
     */
    public static Matcher<SearchResponse> orderedBy(String field, boolean ascending);
    
    /**
     * Matches SearchHit containing a field with the expected value.
     * 
     * @param fieldName field name to check
     * @param expectedValue expected field value
     * @return matcher for search hit field
     */
    public static Matcher<SearchHit> hasField(String fieldName, Object expectedValue);
    
    /**
     * Matches SearchHit with expected document ID.
     * 
     * @param expectedId expected document ID
     * @return matcher for document ID
     */
    public static Matcher<SearchHit> hasId(String expectedId);
    
    /**
     * Matches SearchHit with expected document type.
     * 
     * @param expectedType expected document type
     * @return matcher for document type
     */
    public static Matcher<SearchHit> hasType(String expectedType);
    
    /**
     * Matches SearchHit with expected index name.
     * 
     * @param expectedIndex expected index name
     * @return matcher for index name
     */
    public static Matcher<SearchHit> hasIndex(String expectedIndex);
    
    /**
     * Matches SearchHit with score greater than or equal to minimum.
     * 
     * @param minScore minimum score threshold
     * @return matcher for minimum score
     */
    public static Matcher<SearchHit> hasScore(float minScore);
    
    /**
     * Matches SearchHit containing highlighted fields.
     * 
     * @param fieldName field that should be highlighted
     * @return matcher for highlighted field
     */
    public static Matcher<SearchHit> hasHighlighting(String fieldName);
}

Cluster Health Matchers

package org.elasticsearch.test.hamcrest;

import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
import org.elasticsearch.cluster.health.ClusterHealthStatus;
import org.hamcrest.Matcher;

/**
 * Hamcrest matchers for cluster health assertions.
 */
public class ClusterHealthMatchers {
    
    /**
     * Matches ClusterHealthResponse with expected status.
     * 
     * @param expectedStatus expected cluster health status
     * @return matcher for health status
     */
    public static Matcher<ClusterHealthResponse> hasStatus(ClusterHealthStatus expectedStatus);
    
    /**
     * Matches ClusterHealthResponse indicating cluster is not timed out.
     * 
     * @return matcher for non-timed-out cluster
     */
    public static Matcher<ClusterHealthResponse> isNotTimedOut();
    
    /**
     * Matches ClusterHealthResponse with expected number of nodes.
     * 
     * @param expectedNodes expected node count
     * @return matcher for node count
     */
    public static Matcher<ClusterHealthResponse> hasNodes(int expectedNodes);
    
    /**
     * Matches ClusterHealthResponse with expected number of data nodes.
     * 
     * @param expectedDataNodes expected data node count
     * @return matcher for data node count
     */
    public static Matcher<ClusterHealthResponse> hasDataNodes(int expectedDataNodes);
    
    /**
     * Matches ClusterHealthResponse with no relocating shards.
     * 
     * @return matcher for no relocating shards
     */
    public static Matcher<ClusterHealthResponse> hasNoRelocatingShards();
    
    /**
     * Matches ClusterHealthResponse with no initializing shards.
     * 
     * @return matcher for no initializing shards
     */
    public static Matcher<ClusterHealthResponse> hasNoInitializingShards();
    
    /**
     * Matches ClusterHealthResponse with no unassigned shards.
     * 
     * @return matcher for no unassigned shards  
     */
    public static Matcher<ClusterHealthResponse> hasNoUnassignedShards();
}

Optional and Collection Matchers

package org.elasticsearch.test.hamcrest;

import java.util.Collection;
import java.util.Optional;
import org.hamcrest.Matcher;

/**
 * Hamcrest matchers for Optional and Collection types.
 */
public class OptionalMatchers {
    
    /**
     * Matches Optional that is present.
     * 
     * @param <T> type of Optional content
     * @return matcher for present Optional
     */
    public static <T> Matcher<Optional<T>> isPresent();
    
    /**
     * Matches Optional that is present and contains the expected value.
     * 
     * @param expectedValue expected Optional content
     * @param <T> type of Optional content
     * @return matcher for Optional with specific value
     */
    public static <T> Matcher<Optional<T>> isPresentWith(T expectedValue);
    
    /**
     * Matches Optional that is empty.
     * 
     * @param <T> type of Optional content
     * @return matcher for empty Optional
     */
    public static <T> Matcher<Optional<T>> isEmpty();
    
    /**
     * Matches Collection containing all specified items.
     * 
     * @param items items that should be present
     * @param <T> type of Collection elements
     * @return matcher for Collection containing items
     */
    public static <T> Matcher<Collection<T>> containsAll(T... items);
    
    /**
     * Matches Collection with expected size.
     * 
     * @param expectedSize expected collection size
     * @param <T> type of Collection elements
     * @return matcher for Collection size
     */
    public static <T> Matcher<Collection<T>> hasSize(int expectedSize);
    
    /**
     * Matches empty Collection.
     * 
     * @param <T> type of Collection elements
     * @return matcher for empty Collection
     */
    public static <T> Matcher<Collection<T>> emptyCollection();
}

Tuple and Rectangle Matchers

package org.elasticsearch.test.hamcrest;

import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.geometry.Rectangle;
import org.elasticsearch.common.collect.Tuple;
import org.hamcrest.Matcher;

/**
 * Specialized matchers for geometric and tuple data structures.
 */
public class TupleMatchers {
    
    /**
     * Matches Tuple with expected first element.
     * 
     * @param expectedFirst expected first tuple element
     * @param <T1> type of first element
     * @param <T2> type of second element
     * @return matcher for first tuple element
     */
    public static <T1, T2> Matcher<Tuple<T1, T2>> hasFirst(T1 expectedFirst);
    
    /**
     * Matches Tuple with expected second element.
     * 
     * @param expectedSecond expected second tuple element
     * @param <T1> type of first element
     * @param <T2> type of second element
     * @return matcher for second tuple element
     */
    public static <T1, T2> Matcher<Tuple<T1, T2>> hasSecond(T2 expectedSecond);
    
    /**
     * Matches Tuple with both expected elements.
     * 
     * @param expectedFirst expected first element
     * @param expectedSecond expected second element
     * @param <T1> type of first element
     * @param <T2> type of second element
     * @return matcher for complete tuple
     */
    public static <T1, T2> Matcher<Tuple<T1, T2>> isTuple(T1 expectedFirst, T2 expectedSecond);
}

/**
 * Matchers for geometric Rectangle objects.
 */
public class RectangleMatchers {
    
    /**
     * Matches Rectangle containing the specified point.
     * 
     * @param point point that should be contained
     * @return matcher for point containment
     */
    public static Matcher<Rectangle> containsPoint(GeoPoint point);
    
    /**
     * Matches Rectangle with expected bounds.
     * 
     * @param minLon minimum longitude
     * @param maxLon maximum longitude
     * @param minLat minimum latitude
     * @param maxLat maximum latitude
     * @return matcher for rectangle bounds
     */
    public static Matcher<Rectangle> hasBounds(double minLon, double maxLon, 
                                             double minLat, double maxLat);
    
    /**
     * Matches Rectangle that intersects with another rectangle.
     * 
     * @param other rectangle to check intersection with
     * @return matcher for rectangle intersection
     */
    public static Matcher<Rectangle> intersects(Rectangle other);
}

Usage Examples

Search Assertion Examples

import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.*;
import static org.elasticsearch.test.hamcrest.SearchMatchers.*;

public class SearchAssertionTest extends ESIntegTestCase {
    
    public void testSearchAssertions() {
        createIndex("test-index");
        
        // Index test documents
        client().prepareIndex("test-index")
            .setId("1")
            .setSource("title", "First Document", "score", 85)
            .get();
        client().prepareIndex("test-index")
            .setId("2") 
            .setSource("title", "Second Document", "score", 92)
            .get();
        
        refresh("test-index");
        
        // Search and use assertions
        SearchResponse response = client().prepareSearch("test-index")
            .setQuery(QueryBuilders.matchAllQuery())
            .addSort("score", SortOrder.DESC)
            .get();
        
        // Basic assertions
        assertNoFailures(response);
        assertHitCount(response, 2);
        
        // Hamcrest matchers
        assertThat(response, hasHitCount(2));
        assertThat(response, isSuccessfulSearchResponse());
        assertThat(response, hasHitWithId("1"));
        assertThat(response, orderedBy("score", false)); // descending
        
        // Individual hit assertions
        SearchHit firstHit = response.getHits().getHits()[0];
        assertThat(firstHit, hasId("2")); // Higher score document first
        assertThat(firstHit, hasField("title", "Second Document"));
        assertThat(firstHit, hasScore(0.0f)); // Match all query has score
        
        // Combined assertions
        assertSingleHit(client().prepareSearch("test-index")
            .setQuery(QueryBuilders.termQuery("title", "first"))
            .get());
    }
    
    public void testClusterHealthAssertions() {
        createIndex("health-test");
        
        // Wait for and assert cluster health
        ensureGreen("health-test");
        
        // Manual health check with assertions
        ClusterHealthResponse health = client().admin().cluster()
            .prepareHealth("health-test")
            .get();
        
        assertHealthStatus(health, ClusterHealthStatus.GREEN);
        assertThat(health, hasStatus(ClusterHealthStatus.GREEN));
        assertThat(health, isNotTimedOut());
        assertThat(health, hasNoUnassignedShards());
        assertThat(health, hasDataNodes(numDataNodes()));
    }
    
    public void testBulkOperationAssertions() {
        createIndex("bulk-test");
        
        BulkRequestBuilder bulk = client().prepareBulk();
        for (int i = 0; i < 10; i++) {
            bulk.add(client().prepareIndex("bulk-test")
                .setId(String.valueOf(i))
                .setSource("field", "value" + i));
        }
        
        BulkResponse bulkResponse = bulk.get();
        
        // Assert no bulk failures
        assertNoFailures(bulkResponse);
        assertThat("All items should succeed", 
                   bulkResponse.hasFailures(), equalTo(false));
        assertThat("Should have 10 items", 
                   bulkResponse.getItems().length, equalTo(10));
    }
}

Custom Matcher Usage

import static org.elasticsearch.test.hamcrest.OptionalMatchers.*;
import static org.elasticsearch.test.hamcrest.TupleMatchers.*;

public class CustomMatcherTest extends ESTestCase {
    
    public void testOptionalMatchers() {
        Optional<String> presentValue = Optional.of("test");
        Optional<String> emptyValue = Optional.empty();
        
        assertThat(presentValue, isPresent());
        assertThat(presentValue, isPresentWith("test"));
        assertThat(emptyValue, isEmpty());
    }
    
    public void testTupleMatchers() {
        Tuple<String, Integer> tuple = new Tuple<>("hello", 42);
        
        assertThat(tuple, hasFirst("hello"));
        assertThat(tuple, hasSecond(42));
        assertThat(tuple, isTuple("hello", 42));
    }
    
    public void testCollectionMatchers() {
        List<String> items = Arrays.asList("a", "b", "c");
        
        assertThat(items, hasSize(3));
        assertThat(items, containsAll("a", "c"));
        assertThat(Collections.emptyList(), emptyCollection());
    }
}

Exception and Error Assertion Examples

public class ExceptionAssertionTest extends ESTestCase {
    
    public void testExceptionAssertions() {
        // Test expected exceptions with root cause checking
        ElasticsearchException ex = expectThrows(ElasticsearchException.class, () -> {
            throw new ElasticsearchException("Test error", 
                new IllegalArgumentException("Root cause"));
        });
        
        assertCausedBy(ex, IllegalArgumentException.class);
        assertThat(ex.getMessage(), containsString("Test error"));
    }
    
    public void testSearchFailureAssertions() {
        createIndex("test-index");
        
        // Test search with invalid query
        SearchPhaseExecutionException ex = expectThrows(
            SearchPhaseExecutionException.class, 
            () -> client().prepareSearch("test-index")
                .setQuery(QueryBuilders.scriptQuery(
                    new Script("invalid script that will fail")))
                .get()
        );
        
        assertThat("Should have shard failures", 
                   ex.shardFailures().length, greaterThan(0));
    }
}

Best Practices

Assertion Selection

  • Use ElasticsearchAssertions static methods for common scenarios
  • Prefer Hamcrest matchers for complex or reusable assertions
  • Combine basic assertions with custom matchers for comprehensive validation

Readability

  • Use descriptive matcher names that clearly express intent
  • Chain matchers with allOf() and anyOf() for complex conditions
  • Include meaningful assertion messages for better test failure diagnostics

Performance

  • Avoid overly complex matcher chains that impact test performance
  • Use targeted assertions rather than comprehensive validation when appropriate
  • Cache frequently used matchers in test utilities

Maintainability

  • Create custom matchers for domain-specific assertion patterns
  • Extract common assertion patterns into utility methods
  • Keep assertion logic close to the test scenarios that use them

The assertion and matcher utilities provide a rich vocabulary for expressing test expectations clearly and maintaining readable, reliable test code.

Install with Tessl CLI

npx tessl i tessl/maven-org-elasticsearch--elasticsearch-test-framework

docs

assertions-matchers.md

cluster-management.md

core-testing.md

data-generation.md

index.md

mock-implementations.md

specialized-testing.md

tile.json