Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
35b97a7
all tests working
jmarantz Jan 24, 2019
4ab3d4c
Merge branch 'master' into test-time-global
jmarantz Jan 24, 2019
43bcff1
cleanup
jmarantz Jan 24, 2019
43cf4ba
Enforce TimeSystem being a true singleton. Share delagation logic via…
jmarantz Jan 24, 2019
8ecee51
Removed some TimeProviders.
jmarantz Jan 24, 2019
d5d2c68
Remove rest of time-system providers.
jmarantz Jan 24, 2019
71cd01c
Merge branch 'master' into test-time-global
jmarantz Jan 24, 2019
9950c87
Clean up comments, add unit test.
jmarantz Jan 25, 2019
41a9341
Merge branch 'master' into test-time-global
jmarantz Jan 25, 2019
27037c7
Retain a context for sharing the time-system in the contention test. …
jmarantz Jan 25, 2019
ebc3115
Cleanup some superfluous declarations and commented-out code.
jmarantz Jan 25, 2019
5a12891
Remove expected-output string from EXPECT_DEATH, as it seemed to fail…
jmarantz Jan 25, 2019
00e8e27
Use EXPECT_DEATH_LOG_TO_STDERR which appears to work with assertion m…
jmarantz Jan 25, 2019
e14f910
format fix.
jmarantz Jan 25, 2019
7987eec
Merge branch 'master' into test-time-global
jmarantz Jan 25, 2019
52cfeb7
Change the commenting to encourage users to use SimulatedTimeSystem
jmarantz Jan 25, 2019
5f74b89
Merge branch 'master' into test-time-global
jmarantz Jan 25, 2019
0cc864f
Merge branch 'master' into test-time-global
jmarantz Jan 26, 2019
5024e2c
Merge branch 'master' into test-time-global
jmarantz Jan 28, 2019
70d4261
Convert ASSERT to RELEASE_ASSERT.
jmarantz Jan 28, 2019
25a8190
Merge branch 'master' into test-time-global
jmarantz Jan 28, 2019
4ab76c8
Add description in test/README.md of the time-system and how to test …
jmarantz Jan 28, 2019
6712708
grammar tweaks
jmarantz Jan 28, 2019
a35d223
Switch TODO to reference #4160
jmarantz Jan 28, 2019
32ce33e
Fix typos.
jmarantz Jan 28, 2019
d45dd4a
fix grammar error.
jmarantz Jan 29, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion include/envoy/common/time.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ typedef std::chrono::time_point<std::chrono::steady_clock> MonotonicTime;
*/
class TimeSource {
public:
virtual ~TimeSource() {}
virtual ~TimeSource() = default;

/**
* @return the current system time; not guaranteed to be monotonically increasing.
Expand Down
2 changes: 1 addition & 1 deletion include/envoy/event/timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ typedef std::unique_ptr<Scheduler> SchedulerPtr;
*/
class TimeSystem : public TimeSource {
public:
virtual ~TimeSystem() {}
virtual ~TimeSystem() = default;

using Duration = MonotonicTime::duration;

Expand Down
30 changes: 30 additions & 0 deletions test/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,33 @@ 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`](https://github.com/envoyproxy/envoy/blob/master/include/envoy/event/timer.h),
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`](test_common/test_time_system.h) 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`.
3 changes: 2 additions & 1 deletion test/common/common/mutex_tracer_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,9 @@ TEST_F(MutexTracerTest, TwoThreadsWithContention) {
for (int i = 1; i <= 10; ++i) {
int64_t curr_num_lifetime_wait_cycles = tracer_.lifetimeWaitCycles();

Thread::TestUtil::ContentionGenerator::generateContention(tracer_);
Thread::TestUtil::ContentionGenerator contention_generator;

contention_generator.generateContention(tracer_);
EXPECT_EQ(tracer_.numContentions(), i);
EXPECT_GT(tracer_.currentWaitCycles(), 0); // This shouldn't be hardcoded.
EXPECT_GT(tracer_.lifetimeWaitCycles(), 0);
Expand Down
1 change: 1 addition & 0 deletions test/common/config/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -223,5 +223,6 @@ envoy_cc_test(
"//source/common/config:config_provider_lib",
"//source/common/protobuf:utility_lib",
"//test/mocks/server:server_mocks",
"//test/test_common:simulated_time_system_lib",
],
)
4 changes: 3 additions & 1 deletion test/common/config/config_provider_impl_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include "test/common/config/dummy_config.pb.h"
#include "test/mocks/server/mocks.h"
#include "test/test_common/simulated_time_system.h"

#include "gmock/gmock.h"
#include "gtest/gtest.h"
Expand Down Expand Up @@ -211,9 +212,10 @@ class ConfigProviderImplTest : public testing::Test {
provider_manager_ = std::make_unique<DummyConfigProviderManager>(factory_context_.admin_);
}

Event::SimulatedTimeSystem& timeSystem() { return factory_context_.timeSystem(); }
Event::SimulatedTimeSystem& timeSystem() { return time_system_; }

protected:
Event::SimulatedTimeSystem time_system_;
NiceMock<Server::Configuration::MockFactoryContext> factory_context_;
std::unique_ptr<DummyConfigProviderManager> provider_manager_;
};
Expand Down
25 changes: 13 additions & 12 deletions test/common/config/grpc_mux_impl_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "test/mocks/runtime/mocks.h"
#include "test/test_common/logging.h"
#include "test/test_common/simulated_time_system.h"
#include "test/test_common/test_time.h"
#include "test/test_common/utility.h"

#include "gmock/gmock.h"
Expand All @@ -37,11 +38,9 @@ namespace {

// We test some mux specific stuff below, other unit test coverage for singleton use of GrpcMuxImpl
// is provided in [grpc_]subscription_impl_test.cc.
class GrpcMuxImplTest : public testing::Test {
class GrpcMuxImplTestBase : public testing::Test {
public:
GrpcMuxImplTest() : async_client_(new Grpc::MockAsyncClient()) {
dispatcher_.setTimeSystem(time_system_);
}
GrpcMuxImplTestBase() : async_client_(new Grpc::MockAsyncClient()) {}

void setup() {
grpc_mux_ = std::make_unique<GrpcMuxImpl>(
Expand Down Expand Up @@ -88,12 +87,16 @@ class GrpcMuxImplTest : public testing::Test {
Grpc::MockAsyncStream async_stream_;
std::unique_ptr<GrpcMuxImpl> grpc_mux_;
NiceMock<MockGrpcMuxCallbacks> callbacks_;
Event::SimulatedTimeSystem time_system_;
NiceMock<LocalInfo::MockLocalInfo> local_info_;
Stats::IsolatedStoreImpl stats_;
Envoy::Config::RateLimitSettings rate_limit_settings_;
};

class GrpcMuxImplTest : public GrpcMuxImplTestBase {
public:
Event::SimulatedTimeSystem time_system_;
};

// Validate behavior when multiple type URL watches are maintained, watches are created/destroyed
// (via RAII).
TEST_F(GrpcMuxImplTest, MultipleTypeUrlStreams) {
Expand Down Expand Up @@ -328,11 +331,9 @@ TEST_F(GrpcMuxImplTest, WatchDemux) {

// Exactly one test requires a mock time system to provoke behavior that cannot
// easily be achieved with a SimulatedTimeSystem.
class GrpcMuxImplTestWithMockTimeSystem : public GrpcMuxImplTest {
protected:
GrpcMuxImplTestWithMockTimeSystem() { dispatcher_.setTimeSystem(mock_time_system_); }

MockTimeSystem mock_time_system_;
class GrpcMuxImplTestWithMockTimeSystem : public GrpcMuxImplTestBase {
public:
Event::DelegatingTestTimeSystem<MockTimeSystem> mock_time_system_;
};

// Verifies that rate limiting is not enforced with defaults.
Expand All @@ -348,7 +349,7 @@ TEST_F(GrpcMuxImplTestWithMockTimeSystem, TooManyRequestsWithDefaultSettings) {
}));

// Validate that rate limiter is not created.
EXPECT_CALL(mock_time_system_, monotonicTime()).Times(0);
EXPECT_CALL(*mock_time_system_, monotonicTime()).Times(0);

setup();

Expand Down Expand Up @@ -398,7 +399,7 @@ TEST_F(GrpcMuxImplTestWithMockTimeSystem, TooManyRequestsWithEmptyRateLimitSetti
drain_request_timer = new Event::MockTimer();
return drain_request_timer;
}));
EXPECT_CALL(mock_time_system_, monotonicTime())
EXPECT_CALL(*mock_time_system_, monotonicTime())
.WillRepeatedly(Return(std::chrono::steady_clock::time_point{}));

RateLimitSettings custom_rate_limit_settings;
Expand Down
1 change: 1 addition & 0 deletions test/common/router/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ envoy_cc_test(
"//test/mocks/server:server_mocks",
"//test/mocks/thread_local:thread_local_mocks",
"//test/mocks/upstream:upstream_mocks",
"//test/test_common:simulated_time_system_lib",
"//test/test_common:utility_lib",
],
)
Expand Down
4 changes: 3 additions & 1 deletion test/common/router/rds_impl_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "test/mocks/thread_local/mocks.h"
#include "test/mocks/upstream/mocks.h"
#include "test/test_common/printers.h"
#include "test/test_common/simulated_time_system.h"
#include "test/test_common/utility.h"

#include "gmock/gmock.h"
Expand Down Expand Up @@ -67,8 +68,9 @@ class RdsTestBase : public testing::Test {
}));
}

Event::SimulatedTimeSystem& timeSystem() { return factory_context_.timeSystem(); }
Event::SimulatedTimeSystem& timeSystem() { return time_system_; }

Event::SimulatedTimeSystem time_system_;
NiceMock<Server::Configuration::MockFactoryContext> factory_context_;
Http::MockAsyncClientRequest request_;
Http::AsyncClient::Callbacks* callbacks_{};
Expand Down
6 changes: 2 additions & 4 deletions test/common/upstream/cluster_manager_impl_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,7 @@ envoy::config::bootstrap::v2::Bootstrap parseBootstrapFromV2Yaml(const std::stri

class ClusterManagerImplTest : public testing::Test {
public:
ClusterManagerImplTest() : api_(Api::createApiForTest(stats_store_)) {
factory_.dispatcher_.setTimeSystem(time_system_);
}
ClusterManagerImplTest() : api_(Api::createApiForTest(stats_store_)) {}

void create(const envoy::config::bootstrap::v2::Bootstrap& bootstrap) {
cluster_manager_ = std::make_unique<ClusterManagerImpl>(
Expand Down Expand Up @@ -241,12 +239,12 @@ class ClusterManagerImplTest : public testing::Test {
}

Stats::IsolatedStoreImpl stats_store_;
Event::SimulatedTimeSystem time_system_;
Api::ApiPtr api_;
NiceMock<TestClusterManagerFactory> factory_;
std::unique_ptr<ClusterManagerImpl> cluster_manager_;
AccessLog::MockAccessLogManager log_manager_;
NiceMock<Server::MockAdmin> admin_;
Event::SimulatedTimeSystem time_system_;
MockLocalClusterUpdate local_cluster_update_;
Http::ContextImpl http_context_;
};
Expand Down
6 changes: 2 additions & 4 deletions test/common/upstream/load_stats_reporter_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,7 @@ class LoadStatsReporterTest : public testing::Test {
public:
LoadStatsReporterTest()
: retry_timer_(new Event::MockTimer()), response_timer_(new Event::MockTimer()),
async_client_(new Grpc::MockAsyncClient()) {
dispatcher_.setTimeSystem(time_system_);
}
async_client_(new Grpc::MockAsyncClient()) {}

void createLoadStatsReporter() {
InSequence s;
Expand Down Expand Up @@ -68,6 +66,7 @@ class LoadStatsReporterTest : public testing::Test {
load_stats_reporter_->onReceiveMessage(std::move(response));
}

Event::SimulatedTimeSystem time_system_;
NiceMock<Upstream::MockClusterManager> cm_;
Event::MockDispatcher dispatcher_;
Stats::IsolatedStoreImpl stats_store_;
Expand All @@ -78,7 +77,6 @@ class LoadStatsReporterTest : public testing::Test {
Event::TimerCb response_timer_cb_;
Grpc::MockAsyncStream async_stream_;
Grpc::MockAsyncClient* async_client_;
Event::SimulatedTimeSystem time_system_;
NiceMock<LocalInfo::MockLocalInfo> local_info_;
};

Expand Down
3 changes: 2 additions & 1 deletion test/exe/main_common_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,8 @@ TEST_P(AdminRequestTest, AdminRequestContentionEnabled) {
started_.WaitForNotification();

// Induce contention to guarantee a non-zero num_contentions count.
Thread::TestUtil::ContentionGenerator::generateContention(MutexTracerImpl::getOrCreateTracer());
Thread::TestUtil::ContentionGenerator contention_generator;
contention_generator.generateContention(MutexTracerImpl::getOrCreateTracer());

std::string response = adminRequest("/contention", "GET");
EXPECT_THAT(response, Not(HasSubstr("not enabled")));
Expand Down
Loading