elastic/elasticsearch
Testing
Elasticsearch has one of the most elaborate testing infrastructures of any open-source Java project. There are several layers; pick the lightest one that exercises the change.
The full reference is TESTING.asciidoc. This page is a high-density tour.
Test types
| Type | Base class | When to use |
|---|---|---|
| Unit | ESTestCase (test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java) |
Almost always. Fastest, deterministic, no node started. |
| Single node | ESSingleNodeTestCase |
Need a real Node (e.g. testing real IndexShard behavior) without the cost of multi-node. |
| Integration cluster | ESIntegTestCase |
Need real cross-node communication. |
| REST (Java) | ESRestTestCase |
Black-box against a running cluster. |
| REST (YAML) | ESClientYamlSuiteTestCase |
Preferred for new REST surface; also runs against the BWC matrix. |
The project guidance is: YAML REST tests are preferred for integration/API testing. Use real classes over mocks unless the real class is too heavy (in which case extend with a simplified subclass; mocks/stubs are a last resort and require a comment explaining why).
Unit tests
Unit tests live next to the production code under src/test/java. Naming: *Tests.java (note the trailing 's'). All unit tests extend ESTestCase, which:
- Seeds a deterministic
Randomper test from thetests.seedsystem property. - Resets static state and detects thread leaks.
- Provides helpers like
randomAlphaOfLength(),randomFrom(),randomInstantBetween(),mockTransport().
Example:
public class MyServiceTests extends ESTestCase {
public void testThing() {
var subject = new MyService(...);
assertThat(subject.compute(...), equalTo(...));
}
}Integration tests
Integration tests use the suffix *IT.java and run via per-module Gradle tasks: internalClusterTest, javaRestTest, yamlRestTest. They start a small in-process cluster (InternalTestCluster) and exercise the full transport + cluster state stack.
./gradlew :server:internalClusterTest --tests org.elasticsearch.cluster.SomeIT
./gradlew :x-pack:plugin:esql:internalClusterTest --tests "org.elasticsearch.xpack.esql.CsvIT.*stats_first_last*"YAML REST tests
YAML REST tests are the project's preferred form for any change visible at the REST surface. They live under rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/ (default-distribution endpoints) and per-module src/yamlRestTest/resources/.
Each .yml file is a list of named test cases. Skipping based on cluster version uses requires/skip:
'my new endpoint':
- requires:
capabilities:
- method: PUT
path: /_my/{name}
capabilities: [my_new_capability]
- do:
my.endpoint:
name: foo
body: { ... }
- match: { acknowledged: true }Run a single YAML case:
./gradlew ":rest-api-spec:yamlRestTest" \
--tests "org.elasticsearch.test.rest.ClientYamlTestSuiteIT.test {yaml=indices.create/10_basic/Create index}"ES|QL CSV tests
ES|QL has its own CSV-driven test framework. Each *.csv-spec file under x-pack/plugin/esql/qa/testFixtures/src/main/resources/ is a sequence of <name> blocks each containing an ES|QL query and the expected tabular result. They run via CsvIT:
./gradlew ":x-pack:plugin:esql:internalClusterTest" \
--tests "org.elasticsearch.xpack.esql.CsvIT.*stats_first_last*"Append *<test-name>* to target a single test within a file.
BWC and multi-version testing
Elasticsearch ships rolling upgrades and full-cluster restarts. The qa/full-cluster-restart and qa/rolling-upgrade projects start two clusters at different versions and exercise upgrade paths. The :bwc Gradle subprojects build prior majors from source and run the matrix.
Determinism, seeds, and iteration
# Reproduce
-Dtests.seed=DEADBEEF
# Re-run N times (use to flush out flaky tests)
-Dtests.iters=20
# Bypass test cache when re-running with the same seed
-Dtests.timestamp=$(date +%s)
# Tune test JVMs
-Dtests.jvms=8
-Dtests.heap.size=4G
-Dtests.jvm.argline="-verbose:gc"
-Dtests.output=alwaysMocking and assertion idioms
MockLog(test/framework/src/main/java/org/elasticsearch/test/MockLog.java) — assert that specific log messages were or were not emitted.DeterministicTaskQueue— drive virtual time forward in coordination/scheduling tests.TransportInterceptorandMockTransportService— wrap the transport for failure-injection tests.assertBusy(Runnable)— poll a condition with a timeout for flake-resistant assertions on async behavior.assertAcked,assertHitCount,assertSearchHits— high-level cluster assertions.
Where to put new tests
- A unit test next to the production class is mandatory for almost every change.
- If the change is observable through REST, add a YAML REST test (preferred) or a Java REST test.
- If the change is cross-node, add an integration test in the same module under
internalClusterTest. - Add to
qa/only when the test crosses module boundaries, exercises packaging, or needs a special fixture (Docker, Kerberos, etc.).
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.