225 lines
6.9 KiB
C++
225 lines
6.9 KiB
C++
|
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||
|
// Use of this source code is governed by a BSD-style license that can be
|
||
|
// found in the LICENSE file.
|
||
|
|
||
|
#include "base/mac/libdispatch_task_runner.h"
|
||
|
|
||
|
#include "base/bind.h"
|
||
|
#include "base/mac/bind_objc_block.h"
|
||
|
#include "base/message_loop/message_loop.h"
|
||
|
#include "base/strings/stringprintf.h"
|
||
|
#include "testing/gtest/include/gtest/gtest.h"
|
||
|
|
||
|
class LibDispatchTaskRunnerTest : public testing::Test {
|
||
|
public:
|
||
|
virtual void SetUp() OVERRIDE {
|
||
|
task_runner_ = new base::mac::LibDispatchTaskRunner(
|
||
|
"org.chromium.LibDispatchTaskRunnerTest");
|
||
|
}
|
||
|
|
||
|
// DispatchLastTask is used to run the main test thread's MessageLoop until
|
||
|
// all non-delayed tasks are run on the LibDispatchTaskRunner.
|
||
|
void DispatchLastTask() {
|
||
|
dispatch_async(task_runner_->GetDispatchQueue(), ^{
|
||
|
message_loop_.PostTask(FROM_HERE,
|
||
|
base::MessageLoop::QuitWhenIdleClosure());
|
||
|
});
|
||
|
message_loop_.Run();
|
||
|
task_runner_->Shutdown();
|
||
|
}
|
||
|
|
||
|
// VerifyTaskOrder takes the expectations from TaskOrderMarkers and compares
|
||
|
// them against the recorded values.
|
||
|
void VerifyTaskOrder(const char* const expectations[],
|
||
|
size_t num_expectations) {
|
||
|
size_t actual_size = task_order_.size();
|
||
|
|
||
|
for (size_t i = 0; i < num_expectations; ++i) {
|
||
|
if (i >= actual_size) {
|
||
|
EXPECT_LE(i, actual_size) << "Expected " << expectations[i];
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
EXPECT_EQ(expectations[i], task_order_[i]);
|
||
|
}
|
||
|
|
||
|
if (actual_size > num_expectations) {
|
||
|
EXPECT_LE(actual_size, num_expectations) << "Extra tasks were run:";
|
||
|
for (size_t i = num_expectations; i < actual_size; ++i) {
|
||
|
EXPECT_EQ("<none>", task_order_[i]) << " (i=" << i << ")";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// The message loop for the test main thread.
|
||
|
base::MessageLoop message_loop_;
|
||
|
|
||
|
// The task runner under test.
|
||
|
scoped_refptr<base::mac::LibDispatchTaskRunner> task_runner_;
|
||
|
|
||
|
// Vector that records data from TaskOrderMarker.
|
||
|
std::vector<std::string> task_order_;
|
||
|
};
|
||
|
|
||
|
// Scoper that records the beginning and end of a running task.
|
||
|
class TaskOrderMarker {
|
||
|
public:
|
||
|
TaskOrderMarker(LibDispatchTaskRunnerTest* test, const std::string& name)
|
||
|
: test_(test),
|
||
|
name_(name) {
|
||
|
test->task_order_.push_back(std::string("BEGIN ") + name);
|
||
|
}
|
||
|
~TaskOrderMarker() {
|
||
|
test_->task_order_.push_back(std::string("END ") + name_);
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
LibDispatchTaskRunnerTest* test_;
|
||
|
std::string name_;
|
||
|
};
|
||
|
|
||
|
void RecordTaskOrder(LibDispatchTaskRunnerTest* test, const std::string& name) {
|
||
|
TaskOrderMarker marker(test, name);
|
||
|
}
|
||
|
|
||
|
// Returns a closure that records the task order.
|
||
|
base::Closure BoundRecordTaskOrder(LibDispatchTaskRunnerTest* test,
|
||
|
const std::string& name) {
|
||
|
return base::Bind(&RecordTaskOrder, base::Unretained(test), name);
|
||
|
}
|
||
|
|
||
|
TEST_F(LibDispatchTaskRunnerTest, PostTask) {
|
||
|
task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "Basic Task"));
|
||
|
DispatchLastTask();
|
||
|
const char* const expectations[] = {
|
||
|
"BEGIN Basic Task",
|
||
|
"END Basic Task"
|
||
|
};
|
||
|
VerifyTaskOrder(expectations, arraysize(expectations));
|
||
|
}
|
||
|
|
||
|
TEST_F(LibDispatchTaskRunnerTest, PostTaskWithinTask) {
|
||
|
task_runner_->PostTask(FROM_HERE, base::BindBlock(^{
|
||
|
TaskOrderMarker marker(this, "Outer");
|
||
|
task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "Inner"));
|
||
|
}));
|
||
|
DispatchLastTask();
|
||
|
|
||
|
const char* const expectations[] = {
|
||
|
"BEGIN Outer",
|
||
|
"END Outer",
|
||
|
"BEGIN Inner",
|
||
|
"END Inner"
|
||
|
};
|
||
|
VerifyTaskOrder(expectations, arraysize(expectations));
|
||
|
}
|
||
|
|
||
|
TEST_F(LibDispatchTaskRunnerTest, NoMessageLoop) {
|
||
|
task_runner_->PostTask(FROM_HERE, base::BindBlock(^{
|
||
|
TaskOrderMarker marker(this,
|
||
|
base::StringPrintf("MessageLoop = %p", base::MessageLoop::current()));
|
||
|
}));
|
||
|
DispatchLastTask();
|
||
|
|
||
|
const char* const expectations[] = {
|
||
|
"BEGIN MessageLoop = 0x0",
|
||
|
"END MessageLoop = 0x0"
|
||
|
};
|
||
|
VerifyTaskOrder(expectations, arraysize(expectations));
|
||
|
}
|
||
|
|
||
|
TEST_F(LibDispatchTaskRunnerTest, DispatchAndPostTasks) {
|
||
|
dispatch_async(task_runner_->GetDispatchQueue(), ^{
|
||
|
TaskOrderMarker marker(this, "First Block");
|
||
|
});
|
||
|
task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "First Task"));
|
||
|
dispatch_async(task_runner_->GetDispatchQueue(), ^{
|
||
|
TaskOrderMarker marker(this, "Second Block");
|
||
|
});
|
||
|
task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "Second Task"));
|
||
|
DispatchLastTask();
|
||
|
|
||
|
const char* const expectations[] = {
|
||
|
"BEGIN First Block",
|
||
|
"END First Block",
|
||
|
"BEGIN First Task",
|
||
|
"END First Task",
|
||
|
"BEGIN Second Block",
|
||
|
"END Second Block",
|
||
|
"BEGIN Second Task",
|
||
|
"END Second Task",
|
||
|
};
|
||
|
VerifyTaskOrder(expectations, arraysize(expectations));
|
||
|
}
|
||
|
|
||
|
TEST_F(LibDispatchTaskRunnerTest, NonNestable) {
|
||
|
task_runner_->PostTask(FROM_HERE, base::BindBlock(^{
|
||
|
TaskOrderMarker marker(this, "First");
|
||
|
task_runner_->PostNonNestableTask(FROM_HERE, base::BindBlock(^{
|
||
|
TaskOrderMarker marker(this, "Second NonNestable");
|
||
|
message_loop_.PostTask(FROM_HERE,
|
||
|
base::MessageLoop::QuitWhenIdleClosure());
|
||
|
}));
|
||
|
}));
|
||
|
message_loop_.Run();
|
||
|
task_runner_->Shutdown();
|
||
|
|
||
|
const char* const expectations[] = {
|
||
|
"BEGIN First",
|
||
|
"END First",
|
||
|
"BEGIN Second NonNestable",
|
||
|
"END Second NonNestable"
|
||
|
};
|
||
|
VerifyTaskOrder(expectations, arraysize(expectations));
|
||
|
}
|
||
|
|
||
|
TEST_F(LibDispatchTaskRunnerTest, PostDelayed) {
|
||
|
base::TimeTicks post_time;
|
||
|
__block base::TimeTicks run_time;
|
||
|
const base::TimeDelta delta = base::TimeDelta::FromMilliseconds(50);
|
||
|
|
||
|
task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "First"));
|
||
|
post_time = base::TimeTicks::Now();
|
||
|
task_runner_->PostDelayedTask(FROM_HERE, base::BindBlock(^{
|
||
|
TaskOrderMarker marker(this, "Timed");
|
||
|
run_time = base::TimeTicks::Now();
|
||
|
message_loop_.PostTask(FROM_HERE,
|
||
|
base::MessageLoop::QuitWhenIdleClosure());
|
||
|
}), delta);
|
||
|
task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "Second"));
|
||
|
message_loop_.Run();
|
||
|
task_runner_->Shutdown();
|
||
|
|
||
|
const char* const expectations[] = {
|
||
|
"BEGIN First",
|
||
|
"END First",
|
||
|
"BEGIN Second",
|
||
|
"END Second",
|
||
|
"BEGIN Timed",
|
||
|
"END Timed",
|
||
|
};
|
||
|
VerifyTaskOrder(expectations, arraysize(expectations));
|
||
|
|
||
|
EXPECT_GE(run_time, post_time + delta);
|
||
|
}
|
||
|
|
||
|
TEST_F(LibDispatchTaskRunnerTest, PostAfterShutdown) {
|
||
|
EXPECT_TRUE(task_runner_->PostTask(FROM_HERE,
|
||
|
BoundRecordTaskOrder(this, "First")));
|
||
|
EXPECT_TRUE(task_runner_->PostTask(FROM_HERE,
|
||
|
BoundRecordTaskOrder(this, "Second")));
|
||
|
task_runner_->Shutdown();
|
||
|
EXPECT_FALSE(task_runner_->PostTask(FROM_HERE, base::BindBlock(^{
|
||
|
TaskOrderMarker marker(this, "Not Run");
|
||
|
ADD_FAILURE() << "Should not run a task after Shutdown";
|
||
|
})));
|
||
|
|
||
|
const char* const expectations[] = {
|
||
|
"BEGIN First",
|
||
|
"END First",
|
||
|
"BEGIN Second",
|
||
|
"END Second"
|
||
|
};
|
||
|
VerifyTaskOrder(expectations, arraysize(expectations));
|
||
|
}
|