| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "base/mac/libdispatch_task_runner.h" | |
| 6 | |
| 7 #include <stddef.h> | |
| 8 | |
| 9 #include "base/bind.h" | |
| 10 #include "base/mac/bind_objc_block.h" | |
| 11 #include "base/macros.h" | |
| 12 #include "base/message_loop/message_loop.h" | |
| 13 #include "base/run_loop.h" | |
| 14 #include "base/single_thread_task_runner.h" | |
| 15 #include "base/strings/stringprintf.h" | |
| 16 #include "testing/gtest/include/gtest/gtest.h" | |
| 17 | |
| 18 class LibDispatchTaskRunnerTest : public testing::Test { | |
| 19 public: | |
| 20 void SetUp() override { | |
| 21 task_runner_ = new base::mac::LibDispatchTaskRunner( | |
| 22 "org.chromium.LibDispatchTaskRunnerTest"); | |
| 23 } | |
| 24 | |
| 25 // DispatchLastTask is used to run the main test thread's MessageLoop until | |
| 26 // all non-delayed tasks are run on the LibDispatchTaskRunner. | |
| 27 void DispatchLastTask() { | |
| 28 dispatch_async(task_runner_->GetDispatchQueue(), ^{ | |
| 29 message_loop_.task_runner()->PostTask( | |
| 30 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); | |
| 31 }); | |
| 32 base::RunLoop().Run(); | |
| 33 task_runner_->Shutdown(); | |
| 34 } | |
| 35 | |
| 36 // VerifyTaskOrder takes the expectations from TaskOrderMarkers and compares | |
| 37 // them against the recorded values. | |
| 38 void VerifyTaskOrder(const char* const expectations[], | |
| 39 size_t num_expectations) { | |
| 40 size_t actual_size = task_order_.size(); | |
| 41 | |
| 42 for (size_t i = 0; i < num_expectations; ++i) { | |
| 43 if (i >= actual_size) { | |
| 44 EXPECT_LE(i, actual_size) << "Expected " << expectations[i]; | |
| 45 continue; | |
| 46 } | |
| 47 | |
| 48 EXPECT_EQ(expectations[i], task_order_[i]); | |
| 49 } | |
| 50 | |
| 51 if (actual_size > num_expectations) { | |
| 52 EXPECT_LE(actual_size, num_expectations) << "Extra tasks were run:"; | |
| 53 for (size_t i = num_expectations; i < actual_size; ++i) { | |
| 54 EXPECT_EQ("<none>", task_order_[i]) << " (i=" << i << ")"; | |
| 55 } | |
| 56 } | |
| 57 } | |
| 58 | |
| 59 // The message loop for the test main thread. | |
| 60 base::MessageLoop message_loop_; | |
| 61 | |
| 62 // The task runner under test. | |
| 63 scoped_refptr<base::mac::LibDispatchTaskRunner> task_runner_; | |
| 64 | |
| 65 // Vector that records data from TaskOrderMarker. | |
| 66 std::vector<std::string> task_order_; | |
| 67 }; | |
| 68 | |
| 69 // Scoper that records the beginning and end of a running task. | |
| 70 class TaskOrderMarker { | |
| 71 public: | |
| 72 TaskOrderMarker(LibDispatchTaskRunnerTest* test, const std::string& name) | |
| 73 : test_(test), | |
| 74 name_(name) { | |
| 75 test->task_order_.push_back(std::string("BEGIN ") + name); | |
| 76 } | |
| 77 ~TaskOrderMarker() { | |
| 78 test_->task_order_.push_back(std::string("END ") + name_); | |
| 79 } | |
| 80 | |
| 81 private: | |
| 82 LibDispatchTaskRunnerTest* test_; | |
| 83 std::string name_; | |
| 84 }; | |
| 85 | |
| 86 void RecordTaskOrder(LibDispatchTaskRunnerTest* test, const std::string& name) { | |
| 87 TaskOrderMarker marker(test, name); | |
| 88 } | |
| 89 | |
| 90 // Returns a closure that records the task order. | |
| 91 base::Closure BoundRecordTaskOrder(LibDispatchTaskRunnerTest* test, | |
| 92 const std::string& name) { | |
| 93 return base::Bind(&RecordTaskOrder, base::Unretained(test), name); | |
| 94 } | |
| 95 | |
| 96 TEST_F(LibDispatchTaskRunnerTest, PostTask) { | |
| 97 task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "Basic Task")); | |
| 98 DispatchLastTask(); | |
| 99 const char* const expectations[] = { | |
| 100 "BEGIN Basic Task", | |
| 101 "END Basic Task" | |
| 102 }; | |
| 103 VerifyTaskOrder(expectations, arraysize(expectations)); | |
| 104 } | |
| 105 | |
| 106 TEST_F(LibDispatchTaskRunnerTest, PostTaskWithinTask) { | |
| 107 task_runner_->PostTask(FROM_HERE, base::BindBlock(^{ | |
| 108 TaskOrderMarker marker(this, "Outer"); | |
| 109 task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "Inner")); | |
| 110 })); | |
| 111 DispatchLastTask(); | |
| 112 | |
| 113 const char* const expectations[] = { | |
| 114 "BEGIN Outer", | |
| 115 "END Outer", | |
| 116 "BEGIN Inner", | |
| 117 "END Inner" | |
| 118 }; | |
| 119 VerifyTaskOrder(expectations, arraysize(expectations)); | |
| 120 } | |
| 121 | |
| 122 TEST_F(LibDispatchTaskRunnerTest, NoMessageLoop) { | |
| 123 task_runner_->PostTask(FROM_HERE, base::BindBlock(^{ | |
| 124 TaskOrderMarker marker(this, | |
| 125 base::StringPrintf("MessageLoop = %p", base::MessageLoop::current())); | |
| 126 })); | |
| 127 DispatchLastTask(); | |
| 128 | |
| 129 const char* const expectations[] = { | |
| 130 "BEGIN MessageLoop = 0x0", | |
| 131 "END MessageLoop = 0x0" | |
| 132 }; | |
| 133 VerifyTaskOrder(expectations, arraysize(expectations)); | |
| 134 } | |
| 135 | |
| 136 TEST_F(LibDispatchTaskRunnerTest, DispatchAndPostTasks) { | |
| 137 dispatch_async(task_runner_->GetDispatchQueue(), ^{ | |
| 138 TaskOrderMarker marker(this, "First Block"); | |
| 139 }); | |
| 140 task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "First Task")); | |
| 141 dispatch_async(task_runner_->GetDispatchQueue(), ^{ | |
| 142 TaskOrderMarker marker(this, "Second Block"); | |
| 143 }); | |
| 144 task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "Second Task")); | |
| 145 DispatchLastTask(); | |
| 146 | |
| 147 const char* const expectations[] = { | |
| 148 "BEGIN First Block", | |
| 149 "END First Block", | |
| 150 "BEGIN First Task", | |
| 151 "END First Task", | |
| 152 "BEGIN Second Block", | |
| 153 "END Second Block", | |
| 154 "BEGIN Second Task", | |
| 155 "END Second Task", | |
| 156 }; | |
| 157 VerifyTaskOrder(expectations, arraysize(expectations)); | |
| 158 } | |
| 159 | |
| 160 TEST_F(LibDispatchTaskRunnerTest, NonNestable) { | |
| 161 task_runner_->PostTask(FROM_HERE, base::BindBlock(^{ | |
| 162 TaskOrderMarker marker(this, "First"); | |
| 163 task_runner_->PostNonNestableTask(FROM_HERE, base::BindBlock(^{ | |
| 164 TaskOrderMarker marker(this, "Second NonNestable"); | |
| 165 message_loop_.task_runner()->PostTask( | |
| 166 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); | |
| 167 })); | |
| 168 })); | |
| 169 base::RunLoop().Run(); | |
| 170 task_runner_->Shutdown(); | |
| 171 | |
| 172 const char* const expectations[] = { | |
| 173 "BEGIN First", | |
| 174 "END First", | |
| 175 "BEGIN Second NonNestable", | |
| 176 "END Second NonNestable" | |
| 177 }; | |
| 178 VerifyTaskOrder(expectations, arraysize(expectations)); | |
| 179 } | |
| 180 | |
| 181 TEST_F(LibDispatchTaskRunnerTest, PostDelayed) { | |
| 182 base::TimeTicks post_time; | |
| 183 __block base::TimeTicks run_time; | |
| 184 const base::TimeDelta delta = base::TimeDelta::FromMilliseconds(50); | |
| 185 | |
| 186 task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "First")); | |
| 187 post_time = base::TimeTicks::Now(); | |
| 188 task_runner_->PostDelayedTask(FROM_HERE, base::BindBlock(^{ | |
| 189 TaskOrderMarker marker(this, "Timed"); | |
| 190 run_time = base::TimeTicks::Now(); | |
| 191 message_loop_.task_runner()->PostTask( | |
| 192 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); | |
| 193 }), delta); | |
| 194 task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "Second")); | |
| 195 base::RunLoop().Run(); | |
| 196 task_runner_->Shutdown(); | |
| 197 | |
| 198 const char* const expectations[] = { | |
| 199 "BEGIN First", | |
| 200 "END First", | |
| 201 "BEGIN Second", | |
| 202 "END Second", | |
| 203 "BEGIN Timed", | |
| 204 "END Timed", | |
| 205 }; | |
| 206 VerifyTaskOrder(expectations, arraysize(expectations)); | |
| 207 | |
| 208 EXPECT_GE(run_time, post_time + delta); | |
| 209 } | |
| 210 | |
| 211 TEST_F(LibDispatchTaskRunnerTest, PostAfterShutdown) { | |
| 212 EXPECT_TRUE(task_runner_->PostTask(FROM_HERE, | |
| 213 BoundRecordTaskOrder(this, "First"))); | |
| 214 EXPECT_TRUE(task_runner_->PostTask(FROM_HERE, | |
| 215 BoundRecordTaskOrder(this, "Second"))); | |
| 216 task_runner_->Shutdown(); | |
| 217 EXPECT_FALSE(task_runner_->PostTask(FROM_HERE, base::BindBlock(^{ | |
| 218 TaskOrderMarker marker(this, "Not Run"); | |
| 219 ADD_FAILURE() << "Should not run a task after Shutdown"; | |
| 220 }))); | |
| 221 | |
| 222 const char* const expectations[] = { | |
| 223 "BEGIN First", | |
| 224 "END First", | |
| 225 "BEGIN Second", | |
| 226 "END Second" | |
| 227 }; | |
| 228 VerifyTaskOrder(expectations, arraysize(expectations)); | |
| 229 } | |
| OLD | NEW |