Files
platform-external-webrtc/webrtc/base/sequenced_task_checker_unittest.cc
tommi 0f8b403eb5 Introduce a new constructor to PlatformThread.
The new constructor introduces two new changes:

* Support specifying thread priority at construction time.
  - Moving forward, the SetPriority() method will be removed.
* New thread function type.
  - The new type has 'void' as a return type and a polling loop
    inside PlatformThread, is not used.

The old function type is still supported until all places have been moved over.

In this CL, the first steps towards deprecating the old mechanism are taken
by moving parts of the code that were simple to move, over to the new callback
type.

BUG=webrtc:7187

Review-Url: https://codereview.webrtc.org/2708723003
Cr-Commit-Position: refs/heads/master@{#16779}
2017-02-22 19:22:05 +00:00

274 lines
8.4 KiB
C++

/*
* Copyright (c) 2016 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 "webrtc/base/checks.h"
#include "webrtc/base/constructormagic.h"
#include "webrtc/base/platform_thread.h"
#include "webrtc/base/sequenced_task_checker.h"
#include "webrtc/base/task_queue.h"
#include "webrtc/test/gtest.h"
namespace rtc {
namespace {
// Calls SequencedTaskChecker::CalledSequentially on another thread.
class CallCalledSequentiallyOnThread {
public:
CallCalledSequentiallyOnThread(bool expect_true,
SequencedTaskChecker* sequenced_task_checker)
: expect_true_(expect_true),
thread_has_run_event_(false, false),
thread_(&Run, this, "call_do_stuff_on_thread"),
sequenced_task_checker_(sequenced_task_checker) {
thread_.Start();
}
~CallCalledSequentiallyOnThread() {
EXPECT_TRUE(thread_has_run_event_.Wait(1000));
thread_.Stop();
}
private:
static void Run(void* obj) {
CallCalledSequentiallyOnThread* call_stuff_on_thread =
static_cast<CallCalledSequentiallyOnThread*>(obj);
EXPECT_EQ(
call_stuff_on_thread->expect_true_,
call_stuff_on_thread->sequenced_task_checker_->CalledSequentially());
call_stuff_on_thread->thread_has_run_event_.Set();
}
const bool expect_true_;
Event thread_has_run_event_;
PlatformThread thread_;
SequencedTaskChecker* const sequenced_task_checker_;
RTC_DISALLOW_COPY_AND_ASSIGN(CallCalledSequentiallyOnThread);
};
// Deletes SequencedTaskChecker on a different thread.
class DeleteSequencedCheckerOnThread {
public:
explicit DeleteSequencedCheckerOnThread(
std::unique_ptr<SequencedTaskChecker> sequenced_task_checker)
: thread_(&Run, this, "delete_sequenced_task_checker_on_thread"),
thread_has_run_event_(false, false),
sequenced_task_checker_(std::move(sequenced_task_checker)) {
thread_.Start();
}
~DeleteSequencedCheckerOnThread() {
EXPECT_TRUE(thread_has_run_event_.Wait(1000));
thread_.Stop();
}
private:
static bool Run(void* obj) {
DeleteSequencedCheckerOnThread* instance =
static_cast<DeleteSequencedCheckerOnThread*>(obj);
instance->sequenced_task_checker_.reset();
instance->thread_has_run_event_.Set();
return false;
}
private:
PlatformThread thread_;
Event thread_has_run_event_;
std::unique_ptr<SequencedTaskChecker> sequenced_task_checker_;
RTC_DISALLOW_COPY_AND_ASSIGN(DeleteSequencedCheckerOnThread);
};
void RunMethodOnDifferentThread(bool expect_true) {
std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
new SequencedTaskChecker());
CallCalledSequentiallyOnThread call_on_thread(expect_true,
sequenced_task_checker.get());
}
void RunMethodOnDifferentTaskQueue(bool expect_true) {
std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
new SequencedTaskChecker());
static const char kQueueName[] = "MethodNotAllowedOnDifferentTq";
TaskQueue queue(kQueueName);
Event done_event(false, false);
queue.PostTask([&sequenced_task_checker, &done_event, expect_true] {
if (expect_true)
EXPECT_TRUE(sequenced_task_checker->CalledSequentially());
else
EXPECT_FALSE(sequenced_task_checker->CalledSequentially());
done_event.Set();
});
EXPECT_TRUE(done_event.Wait(1000));
}
void DetachThenCallFromDifferentTaskQueue(bool expect_true) {
std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
new SequencedTaskChecker());
sequenced_task_checker->Detach();
Event done_event(false, false);
TaskQueue queue1("DetachThenCallFromDifferentTaskQueueImpl1");
queue1.PostTask([&sequenced_task_checker, &done_event] {
EXPECT_TRUE(sequenced_task_checker->CalledSequentially());
done_event.Set();
});
EXPECT_TRUE(done_event.Wait(1000));
// CalledSequentially should return false in debug builds after moving to
// another task queue.
TaskQueue queue2("DetachThenCallFromDifferentTaskQueueImpl2");
queue2.PostTask([&sequenced_task_checker, &done_event, expect_true] {
if (expect_true)
EXPECT_TRUE(sequenced_task_checker->CalledSequentially());
else
EXPECT_FALSE(sequenced_task_checker->CalledSequentially());
done_event.Set();
});
EXPECT_TRUE(done_event.Wait(1000));
}
} // namespace
TEST(SequencedTaskCheckerTest, CallsAllowedOnSameThread) {
std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
new SequencedTaskChecker());
EXPECT_TRUE(sequenced_task_checker->CalledSequentially());
// Verify that the destructor doesn't assert.
sequenced_task_checker.reset();
}
TEST(SequencedTaskCheckerTest, DestructorAllowedOnDifferentThread) {
std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
new SequencedTaskChecker());
// Verify that the destructor doesn't assert when called on a different
// thread.
DeleteSequencedCheckerOnThread delete_on_thread(
std::move(sequenced_task_checker));
}
TEST(SequencedTaskCheckerTest, DetachFromThread) {
std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
new SequencedTaskChecker());
sequenced_task_checker->Detach();
CallCalledSequentiallyOnThread call_on_thread(true,
sequenced_task_checker.get());
}
TEST(SequencedTaskCheckerTest, DetachFromThreadAndUseOnTaskQueue) {
std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
new SequencedTaskChecker());
sequenced_task_checker->Detach();
static const char kQueueName[] = "DetachFromThreadAndUseOnTaskQueue";
TaskQueue queue(kQueueName);
Event done_event(false, false);
queue.PostTask([&sequenced_task_checker, &done_event] {
EXPECT_TRUE(sequenced_task_checker->CalledSequentially());
done_event.Set();
});
EXPECT_TRUE(done_event.Wait(1000));
}
TEST(SequencedTaskCheckerTest, DetachFromTaskQueueAndUseOnThread) {
TaskQueue queue("DetachFromTaskQueueAndUseOnThread");
Event done_event(false, false);
queue.PostTask([&done_event] {
std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
new SequencedTaskChecker());
sequenced_task_checker->Detach();
CallCalledSequentiallyOnThread call_on_thread(true,
sequenced_task_checker.get());
done_event.Set();
});
EXPECT_TRUE(done_event.Wait(1000));
}
#if RTC_DCHECK_IS_ON
TEST(SequencedTaskCheckerTest, MethodNotAllowedOnDifferentThreadInDebug) {
RunMethodOnDifferentThread(false);
}
#else
TEST(SequencedTaskCheckerTest, MethodAllowedOnDifferentThreadInRelease) {
RunMethodOnDifferentThread(true);
}
#endif
#if RTC_DCHECK_IS_ON
TEST(SequencedTaskCheckerTest, MethodNotAllowedOnDifferentTaskQueueInDebug) {
RunMethodOnDifferentTaskQueue(false);
}
#else
TEST(SequencedTaskCheckerTest, MethodAllowedOnDifferentTaskQueueInRelease) {
RunMethodOnDifferentTaskQueue(true);
}
#endif
#if RTC_DCHECK_IS_ON
TEST(SequencedTaskCheckerTest, DetachFromTaskQueueInDebug) {
DetachThenCallFromDifferentTaskQueue(false);
}
#else
TEST(SequencedTaskCheckerTest, DetachFromTaskQueueInRelease) {
DetachThenCallFromDifferentTaskQueue(true);
}
#endif
class TestAnnotations {
public:
TestAnnotations() : test_var_(false) {}
void ModifyTestVar() {
RTC_DCHECK_CALLED_SEQUENTIALLY(&checker_);
test_var_ = true;
}
private:
bool test_var_ GUARDED_BY(&checker_);
SequencedTaskChecker checker_;
};
TEST(SequencedTaskCheckerTest, TestAnnotations) {
TestAnnotations annotations;
annotations.ModifyTestVar();
}
#if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
void TestAnnotationsOnWrongQueue() {
TestAnnotations annotations;
static const char kQueueName[] = "TestAnnotationsOnWrongQueueDebug";
TaskQueue queue(kQueueName);
Event done_event(false, false);
queue.PostTask([&annotations, &done_event] {
annotations.ModifyTestVar();
done_event.Set();
});
EXPECT_TRUE(done_event.Wait(1000));
}
#if RTC_DCHECK_IS_ON
TEST(SequencedTaskCheckerTest, TestAnnotationsOnWrongQueueDebug) {
ASSERT_DEATH({ TestAnnotationsOnWrongQueue(); }, "");
}
#else
TEST(SequencedTaskCheckerTest, TestAnnotationsOnWrongQueueRelease) {
TestAnnotationsOnWrongQueue();
}
#endif
#endif // GTEST_HAS_DEATH_TEST
} // namespace rtc