Skip to content

Latest commit

 

History

History

test

Envoy tests

Envoy uses the Google Test framework for tests, including Google Mock for mocks and matchers. See the documentation on those pages for information on the various classes, macros, and matchers that Envoy uses from those frameworks.

Integration tests

Envoy contains an integration testing framework, for testing downstream-Envoy-upstream communication. See the framework's README for more information.

Custom matchers

Envoy includes some custom Google Mock matchers to make test expectation statements simpler to write and easier to understand.

HeaderValueOf

Tests that a HeaderMap argument contains exactly one header with the given key, whose value satisfies the given expectation. The expectation can be a matcher, or a string that the value should equal.

Examples:

EXPECT_THAT(response->headers(), HeaderValueOf(Headers::get().Server, "envoy"));
using testing::HasSubstr;
EXPECT_THAT(request->headers(),
            HeaderValueOf(Headers::get().AcceptEncoding, HasSubstr("gzip")));

HttpStatusIs

Tests that a HeaderMap argument has the provided HTTP status code. The status code can be passed in as a string or an integer.

Example:

EXPECT_THAT(response->headers(), HttpStatusIs("200"));

HeaderMapEqual and HeaderMapEqualRef

HeaderMapEqualRef tests that two HeaderMap arguments are equal. HeaderMapEqual is the same, but it compares two pointers to HeaderMaps, and the matcher's argument must be a HeaderMapPtr.

Example:

EXPECT_THAT(response->headers(), HeaderMapEqualRef(expected_headers));

IsSubsetOfHeaders and IsSupersetOfHeaders

Tests that one HeaderMap argument contains every header in another HeaderMap.

Examples:

EXPECT_THAT(response->headers(), IsSubsetOfHeaders(allowed_headers));
EXPECT_THAT(response->headers(), IsSupersetOfHeaders(required_headers));

Controlling time in tests

In Envoy production code, time and timers are managed via Event::TimeSystem, which provides a mechanism for querying the time and setting up time-based callbacks. Bypassing this abstraction in Envoy code is flagged as a format violation in CI.

In tests we use a derivation Event::TestTimeSystem which adds the ability to sleep or do a blocking timed wait on a condition variable. There are two implementations of the Event::TestTimeSystem interface: Event::TestRealTimeSystem, and Event::SimulatedTimeSystem. The latter is recommended for all new tests, as it helps avoid flaky tests on slow machines, and makes tests run faster.

Typically we do not want to have both real-time and simulated-time in the same test; that could lead to hard-to-reproduce results. Thus both implementations have a mechanism to enforce that only one of them can be instantiated at once. A runtime assertion occurs if an Event::TestRealTimeSystem and Event::SimulatedTimeSystem are instantiated at the same time. Once the time-system goes out of scope, usually at the end of a test method, the slate is clean and a new test-method can use a different time system.

There is also Event::GlobalTimeSystem, which can be instantiated in shared test infrastructure that wants to be agnostic to which TimeSystem is used in a test. When no TimeSystem is instantiated in a test, the Event::GlobalTimeSystem will lazy-initialize itself into a concrete TimeSystem. Currently this is TestRealTimeSystem but will be changed in the future to SimulatedTimeSystem.