envoyproxy/envoy
Testing
Envoy ships ~15× more lines of test code than core data-plane code (see by the numbers). Almost any non-trivial change is expected to come with both unit and integration coverage. This page is a tour of the test tree.
Test taxonomy
| Type | Lives under | Runs as | Purpose |
|---|---|---|---|
| Unit | test/common/, test/server/, test/extensions/ |
bazel test |
Single class or small graph in isolation, with mocks |
| Integration | test/integration/ |
bazel test |
Full Envoy process + fake upstreams + fake xDS, real sockets |
| Benchmark | test/benchmark/, inline *_benchmark_test.cc |
bazel run |
Microbenchmarks via google-benchmark |
| Fuzz | test/fuzz/, inline *_fuzz_test.cc |
bazel test --config=asan-fuzzer |
libfuzzer-based fuzzing, also run by OSS-Fuzz |
| Coverage | run via run_envoy_bazel_coverage.sh |
LLVM coverage | Per-directory thresholds in test/coverage.yaml |
| Mocks | test/mocks/ |
(library only) | gMock implementations of every public interface |
Running tests
# Run a focused unit test
bazel test //test/common/http:filter_manager_test
# Filter inside a single suite
bazel test //test/common/http:filter_manager_test --test_filter=*WatermarkTest*
# Run all tests for a package
bazel test //test/extensions/filters/http/jwt_authn/...
# Run with sanitizers
bazel test --config=asan //test/common/upstream/...
bazel test --config=tsan //test/common/upstream/...
bazel test --config=msan //test/common/upstream/...
# Run with extra logging (printed for failed tests by default)
bazel test --test_output=streamed //test/common/http:filter_manager_test
# Re-run a single failing test target
bazel test --test_arg=--gtest_filter=FilterManagerTest.MyTest //test/common/http:filter_manager_testBazel caches everything; passes are reported as (cached). Pass --cache_test_results=no to force re-execution.
Mocks
test/mocks/ shadows envoy/ one-for-one. Every abstract class in envoy/foo/bar.h has a MockBar in test/mocks/foo/bar.h. Examples:
test/mocks/upstream/cluster_manager.h—MockClusterManager.test/mocks/server/instance.h—MockInstance.test/mocks/http/conn_pool.h—MockConnPool.
When you add a new public interface, add the matching mock in the same PR. The check_format.py script will not catch a missing mock, but reviewers will.
Integration tests
The integration framework starts a real Envoy in-process, with fake downstream clients (TCP, HTTP/1, HTTP/2, HTTP/3) and fake upstreams. The base classes are in test/integration/:
integration_test.h— minimal HTTP/1 + TCP test base.http_integration.h— HTTP test fixture parameterised over HTTP versions.base_integration_test.h— the underlying machinery (config templating, port allocation, fake upstreams).fake_upstream.h— the fake upstream server used by every test.
Specialised flavours:
http_protocol_integration.h— runs the same test across HTTP/1, HTTP/2, HTTP/3 ("protocol fanout" tests).ads_integration.h— adds a fake ADS server.tcp_proxy_integration.h— TCP-only fixtures.
Tests follow this skeleton:
TEST_P(MyIntegrationTest, MyScenario) {
initialize(); // start Envoy + fake upstreams
codec_client_ = makeHttpConnection(makeClientConnection(lookupPort("http")));
IntegrationStreamDecoderPtr response =
codec_client_->makeRequestWithBody(
Http::TestRequestHeaderMapImpl{{":method", "GET"}, ...}, 1024);
waitForNextUpstreamRequest(); // upstream side
upstream_request_->encodeHeaders(...);
ASSERT_TRUE(response->waitForEndStream());
EXPECT_EQ("200", response->headers().getStatusValue());
}The INSTANTIATE_TEST_SUITE_P macro at the bottom of each file expands the test across IP versions and HTTP versions; this is how a single test can produce dozens of test runs.
The integration README.md has the canonical guide: test/integration/README.md.
Test utilities
test/test_common/ provides fixtures and matchers:
Utility::loadFromYaml<T>(...)for parsing protobuf YAML.MockFunctionandTest::Globalfor managing global state across tests.Event::SimulatedTimeSystemfor tests that need controlled time.- The thread-aware
TestRandomGeneratorfor reproducibility.
Fuzz tests
Fuzzers live in two places:
- Generic infrastructure:
test/fuzz/— base classes, corpora, and the libprotobuf-mutator integration. - Per-component:
*_fuzz_test.ccnext to the code being fuzzed (e.g.test/common/json/json_sanitizer_fuzz_test.cc).
Common patterns:
- Code-driven fuzzers use libfuzzer directly with a raw byte input.
- Protobuf-driven fuzzers use libprotobuf-mutator to fuzz typed inputs (e.g. an
envoy::config::route::v3::RouteConfiguration). - Capture-replay fuzzers (
h1_capture_fuzz_test.cc,h2_capture_fuzz_test.cc) replay captured wire traffic against a real Envoy.
OSS-Fuzz runs all of them continuously and files issues against the Envoy security team.
Coverage gates
test/coverage.yaml lists per-directory minimum coverage. CI fails if a directory drops below its target. The default is high (≥ 96% for most of source/common/ and source/extensions/); some carve-outs exist for hard-to-test areas.
Run a coverage build locally with:
test/run_envoy_bazel_coverage.shThe HTML report lands in generated/coverage/.
Adding a test
The pragmatic checklist when you change source/common/foo/bar.cc:
- Add or extend a unit test in
test/common/foo/bar_test.cc. Use mocks for everything outsidebar.cc. - If you changed observable behaviour, add or extend an integration test under
test/integration/. - If you fixed a parser/codec bug, add a corpus seed under the appropriate
*_corpus/directory and let OSS-Fuzz exercise it. - Run
bazel test //test/common/foo/...andbazel test --config=asan //test/integration:filter_integration_test(or the relevant integration target). - If you added a new public interface in
envoy/, add the matching mock intest/mocks/.
See also
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.