Introduce TaskQueueForTest.

This class adds a convenience method that allows *sending* a task
to the queue (as opposed to posting). Sending is essentially
Post+Wait, a pattern that we don't want to encourage use of
in production code, but is convenient to have from a testing
perspective and there are already several places in the
source code where we use it.

Change-Id: I6efd1b2257e6c641294bb6e4eb53b0021d9553ca
Bug: webrtc:8848
Reviewed-on: https://webrtc-review.googlesource.com/50441
Reviewed-by: Magnus Jedvert <magjed@webrtc.org>
Commit-Queue: Tommi <tommi@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#22022}
This commit is contained in:
Tommi 2018-02-13 19:47:50 +01:00 committed by Commit Bot
parent db6145f055
commit 685615678a
11 changed files with 141 additions and 63 deletions

View File

@ -491,6 +491,7 @@ if (rtc_include_tests) {
"../rtc_base:rtc_base",
"../rtc_base:rtc_base_approved",
"../rtc_base:rtc_base_tests_utils",
"../rtc_base:rtc_task_queue_for_test",
"../test:test_support",
"//testing/gtest",
]

View File

@ -137,15 +137,19 @@ FakeVideoCapturerWithTaskQueue::FakeVideoCapturerWithTaskQueue(
FakeVideoCapturerWithTaskQueue::FakeVideoCapturerWithTaskQueue() {}
bool FakeVideoCapturerWithTaskQueue::CaptureFrame() {
if (task_queue_.IsCurrent())
return FakeVideoCapturer::CaptureFrame();
bool ret = false;
RunSynchronouslyOnTaskQueue(
task_queue_.SendTask(
[this, &ret]() { ret = FakeVideoCapturer::CaptureFrame(); });
return ret;
}
bool FakeVideoCapturerWithTaskQueue::CaptureCustomFrame(int width, int height) {
if (task_queue_.IsCurrent())
return FakeVideoCapturer::CaptureCustomFrame(width, height);
bool ret = false;
RunSynchronouslyOnTaskQueue([this, &ret, width, height]() {
task_queue_.SendTask([this, &ret, width, height]() {
ret = FakeVideoCapturer::CaptureCustomFrame(width, height);
});
return ret;

View File

@ -21,8 +21,7 @@
#include "media/base/fakeframesource.h"
#include "media/base/videocapturer.h"
#include "media/base/videocommon.h"
#include "rtc_base/event.h"
#include "rtc_base/task_queue.h"
#include "rtc_base/task_queue_for_test.h"
#include "rtc_base/timeutils.h"
namespace cricket {
@ -73,21 +72,7 @@ class FakeVideoCapturerWithTaskQueue : public FakeVideoCapturer {
bool CaptureCustomFrame(int width, int height) override;
protected:
template <class Closure>
void RunSynchronouslyOnTaskQueue(Closure&& closure) {
if (task_queue_.IsCurrent()) {
closure();
return;
}
rtc::Event event(false, false);
task_queue_.PostTask([&closure, &event]() {
closure();
event.Set();
});
event.Wait(rtc::Event::kForever);
}
rtc::TaskQueue task_queue_{"FakeVideoCapturerWithTaskQueue"};
rtc::test::TaskQueueForTest task_queue_{"FakeVideoCapturerWithTaskQueue"};
};
} // namespace cricket

View File

@ -16,6 +16,7 @@
#include "api/video/i420_buffer.h"
#include "media/base/testutils.h"
#include "media/engine/webrtcvideocapturer.h"
#include "rtc_base/task_queue_for_test.h"
class FakeWebRtcVcmFactory;
@ -60,17 +61,18 @@ class FakeWebRtcVideoCaptureModule : public webrtc::VideoCaptureModule {
return true; // Rotation compensation is turned on.
}
void SendFrame(int w, int h) {
if (!running_) return;
if (!running_ || !callback_)
return;
rtc::scoped_refptr<webrtc::I420Buffer> buffer =
webrtc::I420Buffer::Create(w, h);
// Initialize memory to satisfy DrMemory tests. See
// https://bugs.chromium.org/p/libyuv/issues/detail?id=377
buffer->InitializeData();
if (callback_) {
task_queue_.SendTask([this, w, h]() {
rtc::scoped_refptr<webrtc::I420Buffer> buffer =
webrtc::I420Buffer::Create(w, h);
// Initialize memory to satisfy DrMemory tests. See
// https://bugs.chromium.org/p/libyuv/issues/detail?id=377
buffer->InitializeData();
callback_->OnFrame(
webrtc::VideoFrame(buffer, 0, 0, webrtc::kVideoRotation_0));
}
});
}
const webrtc::VideoCaptureCapability& cap() const {
@ -78,6 +80,7 @@ class FakeWebRtcVideoCaptureModule : public webrtc::VideoCaptureModule {
}
private:
rtc::test::TaskQueueForTest task_queue_{"FakeWebRtcVideoCaptureModule"};
FakeWebRtcVcmFactory* factory_;
rtc::VideoSinkInterface<webrtc::VideoFrame>* callback_;
bool running_;

View File

@ -88,7 +88,7 @@ if (rtc_include_tests) {
"../../audio/utility:audio_frame_operations",
"../../rtc_base:checks",
"../../rtc_base:rtc_base_approved",
"../../rtc_base:rtc_task_queue",
"../../rtc_base:rtc_task_queue_for_test",
"../../test:test_support",
]
}

View File

@ -21,8 +21,7 @@
#include "modules/audio_mixer/default_output_rate_calculator.h"
#include "rtc_base/bind.h"
#include "rtc_base/checks.h"
#include "rtc_base/event.h"
#include "rtc_base/task_queue.h"
#include "rtc_base/task_queue_for_test.h"
#include "test/gmock.h"
using testing::_;
@ -372,14 +371,9 @@ TEST(AudioMixer, RampedOutSourcesShouldNotBeMarkedMixed) {
// This test checks that the initialization and participant addition
// can be done on a different thread.
TEST(AudioMixer, ConstructFromOtherThread) {
rtc::TaskQueue init_queue("init");
rtc::test::TaskQueueForTest init_queue("init");
rtc::scoped_refptr<AudioMixer> mixer;
rtc::Event event(false, false);
init_queue.PostTask([&mixer, &event]() {
mixer = AudioMixerImpl::Create();
event.Set();
});
event.Wait(rtc::Event::kForever);
init_queue.SendTask([&mixer]() { mixer = AudioMixerImpl::Create(); });
MockMixerAudioSource participant;
EXPECT_CALL(participant, PreferredSampleRate())
@ -387,12 +381,9 @@ TEST(AudioMixer, ConstructFromOtherThread) {
ResetFrame(participant.fake_frame());
rtc::TaskQueue participant_queue("participant");
participant_queue.PostTask([&mixer, &event, &participant]() {
mixer->AddSource(&participant);
event.Set();
});
event.Wait(rtc::Event::kForever);
rtc::test::TaskQueueForTest participant_queue("participant");
participant_queue.SendTask(
[&mixer, &participant]() { mixer->AddSource(&participant); });
EXPECT_CALL(participant, GetAudioFrameWithInfo(kDefaultSampleRateHz, _))
.Times(Exactly(1));

View File

@ -52,7 +52,7 @@ class FakePeriodicVideoCapturer
// So, in order to allow tests to stop frame delivery directly from the
// test thread, we expose this method publicly.
void StopFrameDelivery() {
RunSynchronouslyOnTaskQueue([this]() {
task_queue_.SendTask([this]() {
RTC_DCHECK_RUN_ON(&task_queue_);
deliver_frames_ = false;
});

View File

@ -996,6 +996,21 @@ if (rtc_include_tests) {
]
}
rtc_source_set("rtc_task_queue_for_test") {
visibility = [ "*" ]
testonly = true
sources = [
"task_queue_for_test.cc",
"task_queue_for_test.h",
]
deps = [
":checks",
":rtc_base_approved",
":rtc_task_queue",
]
}
rtc_source_set("rtc_task_queue_unittests") {
visibility = [ "*" ]
testonly = true
@ -1008,6 +1023,7 @@ if (rtc_include_tests) {
":rtc_base_tests_main",
":rtc_base_tests_utils",
":rtc_task_queue",
":rtc_task_queue_for_test",
"../test:test_support",
]
}

View File

@ -0,0 +1,19 @@
/*
* Copyright 2018 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 "rtc_base/task_queue_for_test.h"
namespace rtc {
namespace test {
TaskQueueForTest::TaskQueueForTest(const char* queue_name, Priority priority)
: TaskQueue(queue_name, priority) {}
TaskQueueForTest::~TaskQueueForTest() {}
} // namespace test
} // namespace rtc

View File

@ -0,0 +1,61 @@
/*
* Copyright 2018 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.
*/
#ifndef RTC_BASE_TASK_QUEUE_FOR_TEST_H_
#define RTC_BASE_TASK_QUEUE_FOR_TEST_H_
#include <utility>
#include "rtc_base/checks.h"
#include "rtc_base/event.h"
#include "rtc_base/task_queue.h"
namespace rtc {
namespace test {
class RTC_LOCKABLE TaskQueueForTest : public TaskQueue {
public:
explicit TaskQueueForTest(const char* queue_name,
Priority priority = Priority::NORMAL);
~TaskQueueForTest();
// A convenience, test-only method that blocks the current thread while
// a task executes on the task queue.
// This variant is specifically for posting custom QueuedTask derived
// implementations that tests do not want to pass ownership of over to the
// task queue (i.e. the Run() method always returns |false|.).
template <class Closure>
void SendTask(Closure* task) {
RTC_DCHECK(!IsCurrent());
rtc::Event event(false, false);
PostTask(rtc::NewClosure(
[&task]() {
RTC_CHECK_EQ(false, static_cast<QueuedTask*>(task)->Run());
},
[&event]() { event.Set(); }));
event.Wait(rtc::Event::kForever);
}
// A convenience, test-only method that blocks the current thread while
// a task executes on the task queue.
template <class Closure>
void SendTask(Closure&& task) {
RTC_DCHECK(!IsCurrent());
rtc::Event event(false, false);
PostTask(rtc::NewClosure(std::move(task), [&event]() { event.Set(); }));
event.Wait(rtc::Event::kForever);
}
private:
RTC_DISALLOW_COPY_AND_ASSIGN(TaskQueueForTest);
};
} // namespace test
} // namespace rtc
#endif // RTC_BASE_TASK_QUEUE_FOR_TEST_H_

View File

@ -21,10 +21,13 @@
#include "rtc_base/bind.h"
#include "rtc_base/event.h"
#include "rtc_base/gunit.h"
#include "rtc_base/task_queue.h"
#include "rtc_base/task_queue_for_test.h"
#include "rtc_base/timeutils.h"
using rtc::test::TaskQueueForTest;
namespace rtc {
namespace {
// Noop on all platforms except Windows, where it turns on high precision
// multimedia timers which increases the precision of TimeMillis() while in
@ -44,9 +47,7 @@ class EnableHighResTimers {
const bool enabled_;
#endif
};
}
namespace {
void CheckCurrent(Event* signal, TaskQueue* queue) {
EXPECT_TRUE(queue->IsCurrent());
if (signal)
@ -76,34 +77,31 @@ TEST(TaskQueueTest, PostAndCheckCurrent) {
TEST(TaskQueueTest, PostCustomTask) {
static const char kQueueName[] = "PostCustomImplementation";
Event event(false, false);
TaskQueue queue(kQueueName);
TaskQueueForTest queue(kQueueName);
class CustomTask : public QueuedTask {
public:
explicit CustomTask(Event* event) : event_(event) {}
CustomTask() {}
bool ran() const { return ran_; }
private:
bool Run() override {
event_->Set();
return false; // Never allows the task to be deleted by the queue.
ran_ = true;
return false; // Never allow the task to be deleted by the queue.
}
Event* const event_;
} my_task(&event);
bool ran_ = false;
} my_task;
// Please don't do this in production code! :)
queue.PostTask(std::unique_ptr<QueuedTask>(&my_task));
EXPECT_TRUE(event.Wait(1000));
queue.SendTask(&my_task);
EXPECT_TRUE(my_task.ran());
}
TEST(TaskQueueTest, PostLambda) {
static const char kQueueName[] = "PostLambda";
Event event(false, false);
TaskQueue queue(kQueueName);
queue.PostTask([&event]() { event.Set(); });
EXPECT_TRUE(event.Wait(1000));
TaskQueueForTest queue("PostLambda");
bool ran = false;
queue.SendTask([&ran]() { ran = true; });
EXPECT_TRUE(ran);
}
TEST(TaskQueueTest, PostDelayedZero) {