diff options
Diffstat (limited to '')
-rw-r--r-- | third_party/libwebrtc/test/time_controller/time_controller_conformance_test.cc | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/third_party/libwebrtc/test/time_controller/time_controller_conformance_test.cc b/third_party/libwebrtc/test/time_controller/time_controller_conformance_test.cc new file mode 100644 index 0000000000..300dd9175c --- /dev/null +++ b/third_party/libwebrtc/test/time_controller/time_controller_conformance_test.cc @@ -0,0 +1,181 @@ +/* + * Copyright 2020 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <memory> +#include <vector> + +#include "api/test/time_controller.h" +#include "api/units/time_delta.h" +#include "rtc_base/event.h" +#include "rtc_base/synchronization/mutex.h" +#include "rtc_base/thread.h" +#include "rtc_base/thread_annotations.h" +#include "test/gmock.h" +#include "test/gtest.h" +#include "test/time_controller/real_time_controller.h" +#include "test/time_controller/simulated_time_controller.h" + +namespace webrtc { +namespace { + +using ::testing::ElementsAreArray; +using ::testing::TestParamInfo; +using ::testing::TestWithParam; +using ::testing::Values; + +enum class TimeMode { kRealTime, kSimulated }; + +std::unique_ptr<TimeController> CreateTimeController(TimeMode mode) { + switch (mode) { + case TimeMode::kRealTime: + return std::make_unique<RealTimeController>(); + case TimeMode::kSimulated: + // Using an offset of 100000 to get nice fixed width and readable + // timestamps in typical test scenarios. + constexpr Timestamp kSimulatedStartTime = Timestamp::Seconds(100000); + return std::make_unique<GlobalSimulatedTimeController>( + kSimulatedStartTime); + } +} + +std::string ParamsToString(const TestParamInfo<webrtc::TimeMode>& param) { + switch (param.param) { + case webrtc::TimeMode::kRealTime: + return "RealTime"; + case webrtc::TimeMode::kSimulated: + return "SimulatedTime"; + default: + RTC_DCHECK_NOTREACHED() << "Time mode not supported"; + } +} + +// Keeps order of executions. May be called from different threads. +class ExecutionOrderKeeper { + public: + void Executed(int execution_id) { + MutexLock lock(&mutex_); + order_.push_back(execution_id); + } + + std::vector<int> order() const { + MutexLock lock(&mutex_); + return order_; + } + + private: + mutable Mutex mutex_; + std::vector<int> order_ RTC_GUARDED_BY(mutex_); +}; + +// Tests conformance between real time and simulated time time controller. +class SimulatedRealTimeControllerConformanceTest + : public TestWithParam<webrtc::TimeMode> {}; + +TEST_P(SimulatedRealTimeControllerConformanceTest, ThreadPostOrderTest) { + std::unique_ptr<TimeController> time_controller = + CreateTimeController(GetParam()); + std::unique_ptr<rtc::Thread> thread = time_controller->CreateThread("thread"); + + // Tasks on thread have to be executed in order in which they were + // posted. + ExecutionOrderKeeper execution_order; + thread->PostTask([&]() { execution_order.Executed(1); }); + thread->PostTask([&]() { execution_order.Executed(2); }); + time_controller->AdvanceTime(TimeDelta::Millis(100)); + EXPECT_THAT(execution_order.order(), ElementsAreArray({1, 2})); + // Destroy `thread` before `execution_order` to be sure `execution_order` + // is not accessed on the posted task after it is destroyed. + thread = nullptr; +} + +TEST_P(SimulatedRealTimeControllerConformanceTest, ThreadPostDelayedOrderTest) { + std::unique_ptr<TimeController> time_controller = + CreateTimeController(GetParam()); + std::unique_ptr<rtc::Thread> thread = time_controller->CreateThread("thread"); + + ExecutionOrderKeeper execution_order; + thread->PostDelayedTask([&]() { execution_order.Executed(2); }, + TimeDelta::Millis(500)); + thread->PostTask([&]() { execution_order.Executed(1); }); + time_controller->AdvanceTime(TimeDelta::Millis(600)); + EXPECT_THAT(execution_order.order(), ElementsAreArray({1, 2})); + // Destroy `thread` before `execution_order` to be sure `execution_order` + // is not accessed on the posted task after it is destroyed. + thread = nullptr; +} + +TEST_P(SimulatedRealTimeControllerConformanceTest, ThreadPostInvokeOrderTest) { + std::unique_ptr<TimeController> time_controller = + CreateTimeController(GetParam()); + std::unique_ptr<rtc::Thread> thread = time_controller->CreateThread("thread"); + + // Tasks on thread have to be executed in order in which they were + // posted/invoked. + ExecutionOrderKeeper execution_order; + thread->PostTask([&]() { execution_order.Executed(1); }); + thread->BlockingCall([&]() { execution_order.Executed(2); }); + time_controller->AdvanceTime(TimeDelta::Millis(100)); + EXPECT_THAT(execution_order.order(), ElementsAreArray({1, 2})); + // Destroy `thread` before `execution_order` to be sure `execution_order` + // is not accessed on the posted task after it is destroyed. + thread = nullptr; +} + +TEST_P(SimulatedRealTimeControllerConformanceTest, + ThreadPostInvokeFromThreadOrderTest) { + std::unique_ptr<TimeController> time_controller = + CreateTimeController(GetParam()); + std::unique_ptr<rtc::Thread> thread = time_controller->CreateThread("thread"); + + // If task is invoked from thread X on thread X it has to be executed + // immediately. + ExecutionOrderKeeper execution_order; + thread->PostTask([&]() { + thread->PostTask([&]() { execution_order.Executed(2); }); + thread->BlockingCall([&]() { execution_order.Executed(1); }); + }); + time_controller->AdvanceTime(TimeDelta::Millis(100)); + EXPECT_THAT(execution_order.order(), ElementsAreArray({1, 2})); + // Destroy `thread` before `execution_order` to be sure `execution_order` + // is not accessed on the posted task after it is destroyed. + thread = nullptr; +} + +TEST_P(SimulatedRealTimeControllerConformanceTest, + TaskQueuePostEventWaitOrderTest) { + std::unique_ptr<TimeController> time_controller = + CreateTimeController(GetParam()); + auto task_queue = time_controller->GetTaskQueueFactory()->CreateTaskQueue( + "task_queue", webrtc::TaskQueueFactory::Priority::NORMAL); + + // Tasks on thread have to be executed in order in which they were + // posted/invoked. + ExecutionOrderKeeper execution_order; + rtc::Event event; + task_queue->PostTask([&]() { execution_order.Executed(1); }); + task_queue->PostTask([&]() { + execution_order.Executed(2); + event.Set(); + }); + EXPECT_TRUE(event.Wait(/*give_up_after=*/TimeDelta::Millis(100))); + time_controller->AdvanceTime(TimeDelta::Millis(100)); + EXPECT_THAT(execution_order.order(), ElementsAreArray({1, 2})); + // Destroy `task_queue` before `execution_order` to be sure `execution_order` + // is not accessed on the posted task after it is destroyed. + task_queue = nullptr; +} + +INSTANTIATE_TEST_SUITE_P(ConformanceTest, + SimulatedRealTimeControllerConformanceTest, + Values(TimeMode::kRealTime, TimeMode::kSimulated), + ParamsToString); + +} // namespace +} // namespace webrtc |