mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-13 05:40:42 +01:00

This CL adds TimeDelta support to the rtc::Event, and updates the Wait implementations to work with the improved precision. Bug: webrtc:14366 Change-Id: Iefeb638b18176a34f4ed2a5131754a7b7e6c9e99 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/272002 Reviewed-by: Danil Chapovalov <danilchap@webrtc.org> Reviewed-by: Erik Språng <sprang@webrtc.org> Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org> Commit-Queue: Markus Handell <handellm@webrtc.org> Cr-Commit-Position: refs/heads/main@{#37831}
182 lines
6.7 KiB
C++
182 lines
6.7 KiB
C++
/*
|
|
* 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/location.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->Invoke<void>(RTC_FROM_HERE, [&]() { 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->Invoke<void>(RTC_FROM_HERE, [&]() { 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_ms=*/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
|