| // Copyright 2012 The Chromium Authors | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "components/webrtc/thread_wrapper.h" | 
 |  | 
 | #include <stdint.h> | 
 |  | 
 | #include "base/memory/raw_ptr.h" | 
 | #include "base/run_loop.h" | 
 | #include "base/synchronization/waitable_event.h" | 
 | #include "base/task/single_thread_task_runner.h" | 
 | #include "base/test/task_environment.h" | 
 | #include "base/threading/thread.h" | 
 | #include "testing/gmock/include/gmock/gmock.h" | 
 | #include "testing/gtest/include/gtest/gtest.h" | 
 | #include "third_party/webrtc/api/task_queue/task_queue_factory.h" | 
 | #include "third_party/webrtc/api/task_queue/task_queue_test.h" | 
 | #include "third_party/webrtc_overrides/metronome_source.h" | 
 | #include "third_party/webrtc_overrides/test/metronome_like_task_queue_test.h" | 
 | #include "third_party/webrtc_overrides/timer_based_tick_provider.h" | 
 |  | 
 | namespace webrtc { | 
 | namespace { | 
 |  | 
 | using ::blink::MetronomeLikeTaskQueueTest; | 
 | using ::testing::InSequence; | 
 | using ::testing::Invoke; | 
 | using ::testing::MockFunction; | 
 |  | 
 | constexpr TimeDelta kTestDelay1 = TimeDelta::Millis(10); | 
 | constexpr TimeDelta kTestDelay2 = TimeDelta::Millis(20); | 
 | constexpr TimeDelta kTestDelay3 = TimeDelta::Millis(30); | 
 | constexpr TimeDelta kTestDelay4 = TimeDelta::Millis(40); | 
 | constexpr base::TimeDelta kMaxTestDelay = base::Milliseconds(40); | 
 |  | 
 | class ThreadWrapperTest : public testing::Test { | 
 |  public: | 
 |   // This method is used by the BlockingCallDuringBlockingCall test. | 
 |   // It sends message to the main thread synchronously using BlockingCall(). | 
 |   void PingMainThread() { | 
 |     MockFunction<void()> handler; | 
 |     EXPECT_CALL(handler, Call); | 
 |     thread_->BlockingCall(handler.AsStdFunction()); | 
 |   } | 
 |  | 
 |  protected: | 
 |   ThreadWrapperTest() : thread_(nullptr) {} | 
 |  | 
 |   void SetUp() override { | 
 |     ThreadWrapper::EnsureForCurrentMessageLoop(); | 
 |     thread_ = ThreadWrapper::current(); | 
 |   } | 
 |  | 
 |   // ThreadWrapper destroys itself when |message_loop_| is destroyed. | 
 |   base::test::SingleThreadTaskEnvironment task_environment_; | 
 |   raw_ptr<ThreadWrapper> thread_; | 
 | }; | 
 |  | 
 | TEST_F(ThreadWrapperTest, PostTask) { | 
 |   MockFunction<void()> handler1; | 
 |   MockFunction<void()> handler2; | 
 |   MockFunction<void()> handler3; | 
 |   MockFunction<void()> handler4; | 
 |  | 
 |   thread_->PostTask(handler1.AsStdFunction()); | 
 |   thread_->PostTask(handler2.AsStdFunction()); | 
 |   thread_->PostTask(handler3.AsStdFunction()); | 
 |   thread_->PostTask(handler4.AsStdFunction()); | 
 |  | 
 |   InSequence in_seq; | 
 |   EXPECT_CALL(handler1, Call); | 
 |   EXPECT_CALL(handler2, Call); | 
 |   EXPECT_CALL(handler3, Call); | 
 |   EXPECT_CALL(handler4, Call); | 
 |  | 
 |   base::RunLoop().RunUntilIdle(); | 
 | } | 
 |  | 
 | TEST_F(ThreadWrapperTest, PostDelayedTask) { | 
 |   MockFunction<void()> handler1; | 
 |   MockFunction<void()> handler2; | 
 |   MockFunction<void()> handler3; | 
 |   MockFunction<void()> handler4; | 
 |  | 
 |   thread_->PostDelayedHighPrecisionTask(handler1.AsStdFunction(), kTestDelay1); | 
 |   thread_->PostDelayedHighPrecisionTask(handler2.AsStdFunction(), kTestDelay2); | 
 |   thread_->PostDelayedHighPrecisionTask(handler3.AsStdFunction(), kTestDelay3); | 
 |   thread_->PostDelayedHighPrecisionTask(handler4.AsStdFunction(), kTestDelay4); | 
 |  | 
 |   InSequence in_seq; | 
 |   EXPECT_CALL(handler1, Call); | 
 |   EXPECT_CALL(handler2, Call); | 
 |   EXPECT_CALL(handler3, Call); | 
 |   EXPECT_CALL(handler4, Call); | 
 |  | 
 |   base::RunLoop run_loop; | 
 |   task_environment_.GetMainThreadTaskRunner()->PostDelayedTask( | 
 |       FROM_HERE, run_loop.QuitClosure(), kMaxTestDelay); | 
 |   run_loop.Run(); | 
 | } | 
 |  | 
 | // Verify that BlockingCall() calls handler synchronously when called on the | 
 | // same thread. | 
 | TEST_F(ThreadWrapperTest, BlockingCallSameThread) { | 
 |   MockFunction<void()> handler; | 
 |   EXPECT_CALL(handler, Call); | 
 |   thread_->BlockingCall(handler.AsStdFunction()); | 
 | } | 
 |  | 
 | void InitializeWrapperForNewThread(ThreadWrapper** thread, | 
 |                                    base::WaitableEvent* done_event) { | 
 |   ThreadWrapper::EnsureForCurrentMessageLoop(); | 
 |   ThreadWrapper::current()->set_send_allowed(true); | 
 |   *thread = ThreadWrapper::current(); | 
 |   done_event->Signal(); | 
 | } | 
 |  | 
 | // Verify that BlockingCall() calls handler synchronously when called for a | 
 | // different thread. | 
 | TEST_F(ThreadWrapperTest, BlockingCallToOtherThread) { | 
 |   ThreadWrapper::current()->set_send_allowed(true); | 
 |  | 
 |   base::Thread second_thread("adWrapperTest"); | 
 |   second_thread.Start(); | 
 |  | 
 |   base::WaitableEvent initialized_event( | 
 |       base::WaitableEvent::ResetPolicy::MANUAL, | 
 |       base::WaitableEvent::InitialState::NOT_SIGNALED); | 
 |   ThreadWrapper* target; | 
 |   second_thread.task_runner()->PostTask( | 
 |       FROM_HERE, base::BindOnce(&InitializeWrapperForNewThread, &target, | 
 |                                 &initialized_event)); | 
 |   initialized_event.Wait(); | 
 |  | 
 |   ASSERT_TRUE(target != nullptr); | 
 |  | 
 |   MockFunction<void()> handler; | 
 |   EXPECT_CALL(handler, Call); | 
 |   target->BlockingCall(handler.AsStdFunction()); | 
 | } | 
 |  | 
 | // Verify that thread handles BlockingCall() while another BlockingCall() is | 
 | // pending. The test creates second thread and BlockingCall()s | 
 | // to that thread. handler calls PingMainThread() on the BlockingCall which | 
 | // tries to BlockingCall() to the main thread. | 
 | TEST_F(ThreadWrapperTest, BlockingCallDuringBlockingCall) { | 
 |   ThreadWrapper::current()->set_send_allowed(true); | 
 |  | 
 |   base::Thread second_thread("adWrapperTest"); | 
 |   second_thread.Start(); | 
 |  | 
 |   base::WaitableEvent initialized_event( | 
 |       base::WaitableEvent::ResetPolicy::MANUAL, | 
 |       base::WaitableEvent::InitialState::NOT_SIGNALED); | 
 |   ThreadWrapper* target; | 
 |   second_thread.task_runner()->PostTask( | 
 |       FROM_HERE, base::BindOnce(&InitializeWrapperForNewThread, &target, | 
 |                                 &initialized_event)); | 
 |   initialized_event.Wait(); | 
 |  | 
 |   ASSERT_TRUE(target != nullptr); | 
 |  | 
 |   MockFunction<void()> handler; | 
 |   EXPECT_CALL(handler, Call) | 
 |       .WillOnce(Invoke(this, &ThreadWrapperTest::PingMainThread)); | 
 |   target->BlockingCall(handler.AsStdFunction()); | 
 | } | 
 |  | 
 | // Provider needed for the MetronomeLikeTaskQueueTest suite. | 
 | class ThreadWrapperProvider : public blink::MetronomeLikeTaskQueueProvider { | 
 |  public: | 
 |   void Initialize() override { | 
 |     ThreadWrapper::EnsureForCurrentMessageLoop(); | 
 |     thread_ = rtc::Thread::Current(); | 
 |   } | 
 |  | 
 |   base::TimeDelta DeltaToNextTick() const override { | 
 |     base::TimeTicks now = base::TimeTicks::Now(); | 
 |     return blink::TimerBasedTickProvider::TimeSnappedToNextTick( | 
 |                now, blink::TimerBasedTickProvider::kDefaultPeriod) - | 
 |            now; | 
 |   } | 
 |   base::TimeDelta MetronomeTick() const override { | 
 |     return blink::TimerBasedTickProvider::kDefaultPeriod; | 
 |   } | 
 |   webrtc::TaskQueueBase* TaskQueue() const override { return thread_; } | 
 |  | 
 |  private: | 
 |   // ThreadWrapper destroys itself when |message_loop_| is destroyed. | 
 |   raw_ptr<rtc::Thread> thread_; | 
 | }; | 
 |  | 
 | // Instantiate suite to run all tests defined in | 
 | // third_party/webrtc_overrides/test/metronome_like_task_queue_test.h | 
 | INSTANTIATE_TEST_SUITE_P( | 
 |     ThreadWrapper, | 
 |     MetronomeLikeTaskQueueTest, | 
 |     ::testing::Values(std::make_unique<ThreadWrapperProvider>)); | 
 |  | 
 | class ThreadWrapperTaskQueueFactory : public TaskQueueFactory { | 
 |  public: | 
 |   std::unique_ptr<TaskQueueBase, TaskQueueDeleter> CreateTaskQueue( | 
 |       absl::string_view name, | 
 |       Priority priority) const override { | 
 |     std::unique_ptr<rtc::Thread> thread = rtc::Thread::Create(); | 
 |     thread->Start(); | 
 |     return std::unique_ptr<webrtc::TaskQueueBase, webrtc::TaskQueueDeleter>( | 
 |         thread.release()); | 
 |   } | 
 | }; | 
 |  | 
 | std::unique_ptr<TaskQueueFactory> CreateTaskQueueFactory( | 
 |     const webrtc::FieldTrialsView*) { | 
 |   return std::make_unique<ThreadWrapperTaskQueueFactory>(); | 
 | } | 
 |  | 
 | // Instantiate suite to run all tests defined in | 
 | // //third_party/webrtc/api/task_queue:task_queue_test. | 
 | INSTANTIATE_TEST_SUITE_P(ThreadWrapper, | 
 |                          TaskQueueTest, | 
 |                          ::testing::Values(CreateTaskQueueFactory)); | 
 |  | 
 | }  // namespace | 
 |  | 
 | }  // namespace webrtc |