blob: 7c7a45787009c8bb2201ae898d389d0ae7cf79fd [file] [log] [blame]
Avi Drissman4e1b7bc32022-09-15 14:03:501// Copyright 2012 The Chromium Authors
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit09911bf2008-07-26 23:55:294
Carlos Caballero4118f7e2019-05-28 13:54:005#include "content/public/browser/browser_thread.h"
6
dcheng59716272016-04-09 05:19:087#include <memory>
8
Avi Drissmanadac21992023-01-11 23:46:399#include "base/functional/bind.h"
10#include "base/functional/callback.h"
11#include "base/functional/callback_helpers.h"
skyostil95082a62015-06-05 19:53:0712#include "base/location.h"
Keishi Hattori0e45c022021-11-27 09:25:5213#include "base/memory/raw_ptr.h"
Alex Clarke636e7052019-05-30 10:49:3714#include "base/message_loop/message_pump.h"
Chris Sharp7840c582019-08-02 15:45:3215#include "base/message_loop/message_pump_type.h"
fdoraye716a902016-07-05 16:05:4916#include "base/run_loop.h"
Carlos Caballerob25fe8472020-07-17 10:27:1717#include "base/task/current_thread.h"
Gabriel Charette067dc8a2022-12-01 17:53:2918#include "base/task/sequence_manager/sequence_manager.h"
Sean Mahere672a662023-01-09 21:42:2819#include "base/task/sequenced_task_runner.h"
Patrick Monette643cdf62021-10-15 19:13:4220#include "base/task/sequenced_task_runner_helpers.h"
21#include "base/task/single_thread_task_runner.h"
Carlos Caballero4118f7e2019-05-28 13:54:0022#include "base/test/mock_callback.h"
Gabriel Charettec7108742019-08-23 03:31:4023#include "base/test/task_environment.h"
Gabriel Charetted87f10f2022-03-31 00:44:2224#include "base/time/time.h"
Eric Secklere329cb92018-08-28 16:09:4025#include "build/build_config.h"
John Abd-El-Malekf3243dc2021-05-07 16:20:0126#include "content/browser/browser_process_io_thread.h"
[email protected]c38831a12011-10-28 12:44:4927#include "content/browser/browser_thread_impl.h"
Gabriel Charette748577aa2019-08-12 12:53:5528#include "content/browser/scheduler/browser_io_thread_delegate.h"
Alex Clarke7dc412d2018-09-14 10:02:3129#include "content/browser/scheduler/browser_task_executor.h"
Scott Haseley72d89b02023-02-17 03:29:2530#include "content/browser/scheduler/browser_task_priority.h"
Alex Clarke831ed1e62019-02-18 21:10:0831#include "content/browser/scheduler/browser_ui_thread_scheduler.h"
initial.commit09911bf2008-07-26 23:55:2932#include "testing/gtest/include/gtest/gtest.h"
[email protected]23887f04f2008-12-02 19:20:1533#include "testing/platform_test.h"
initial.commit09911bf2008-07-26 23:55:2934
[email protected]c38831a12011-10-28 12:44:4935namespace content {
36
Alex Clarke636d6b62019-02-22 01:39:0437namespace {
38
Carlos Caballero4118f7e2019-05-28 13:54:0039using ::testing::Invoke;
40
Gabriel Charette748577aa2019-08-12 12:53:5541class SequenceManagerThreadDelegate : public base::Thread::Delegate {
Alex Clarke636d6b62019-02-22 01:39:0442 public:
Gabriel Charette748577aa2019-08-12 12:53:5543 SequenceManagerThreadDelegate() {
Scott Haseley72d89b02023-02-17 03:29:2544 ui_sequence_manager_ = base::sequence_manager::CreateUnboundSequenceManager(
45 base::sequence_manager::SequenceManager::Settings::Builder()
46 .SetPrioritySettings(internal::CreateBrowserTaskPrioritySettings())
47 .Build());
Carlos Caballero12a834ad2019-04-23 13:48:2848 auto browser_ui_thread_scheduler =
Etienne Pierre-doray40545ac2021-11-11 13:34:2849 BrowserUIThreadScheduler::CreateForTesting(ui_sequence_manager_.get());
Carlos Caballero12a834ad2019-04-23 13:48:2850
Carlos Caballero72e8a202019-05-21 16:51:1751 default_task_runner_ =
Alex Clarke49854cc2019-06-27 08:25:4952 browser_ui_thread_scheduler->GetHandle()->GetDefaultTaskRunner();
Carlos Caballero12a834ad2019-04-23 13:48:2853
Alex Clarkebbf891dc2019-10-09 14:18:0254 ui_sequence_manager_->SetDefaultTaskRunner(default_task_runner_);
Carlos Caballero12a834ad2019-04-23 13:48:2855
Carlos Caballeroe840fc32019-05-27 14:16:3756 BrowserTaskExecutor::CreateForTesting(
57 std::move(browser_ui_thread_scheduler),
Alex Clarkebbf891dc2019-10-09 14:18:0258 std::make_unique<BrowserIOThreadDelegate>());
Minoru Chikamunea0317562022-03-22 15:30:2159 BrowserTaskExecutor::OnStartupComplete();
Alex Clarke636d6b62019-02-22 01:39:0460 }
61
Peter Boström828b9022021-09-21 02:28:4362 SequenceManagerThreadDelegate(const SequenceManagerThreadDelegate&) = delete;
63 SequenceManagerThreadDelegate& operator=(
64 const SequenceManagerThreadDelegate&) = delete;
65
Gabriel Charette748577aa2019-08-12 12:53:5566 ~SequenceManagerThreadDelegate() override {
Carlos Caballero1209b312019-04-01 13:30:4167 BrowserTaskExecutor::ResetForTesting();
68 }
Alex Clarke636d6b62019-02-22 01:39:0469
Gabriel Charette748577aa2019-08-12 12:53:5570 // Thread::Delegate:
Alex Clarke636d6b62019-02-22 01:39:0471 scoped_refptr<base::SingleThreadTaskRunner> GetDefaultTaskRunner() override {
72 return default_task_runner_;
73 }
74
Etienne Pierre-dorayef5dcca2023-07-11 16:46:2775 void BindToCurrentThread() override {
Alex Clarkebbf891dc2019-10-09 14:18:0276 ui_sequence_manager_->BindToMessagePump(
Chris Sharp7840c582019-08-02 15:45:3277 base::MessagePump::Create(base::MessagePumpType::DEFAULT));
Alex Clarke636d6b62019-02-22 01:39:0478 }
79
Jiahe Zhang93e2eda2025-07-16 03:32:3480 void AddTaskObserver(base::TaskObserver* observer) override {
81 ui_sequence_manager_->AddTaskObserver(observer);
82 }
83
Alex Clarke636d6b62019-02-22 01:39:0484 private:
Alex Clarkebbf891dc2019-10-09 14:18:0285 std::unique_ptr<base::sequence_manager::SequenceManager> ui_sequence_manager_;
Alex Clarke636d6b62019-02-22 01:39:0486 scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_;
Alex Clarke636d6b62019-02-22 01:39:0487};
88
89} // namespace
90
[email protected]092b04e2010-10-12 23:23:4491class BrowserThreadTest : public testing::Test {
[email protected]f6710622009-11-02 06:10:3092 public:
[email protected]00ed48f2010-10-22 22:19:2493 void Release() const {
John Abd-El-Malekf3243dc2021-05-07 16:20:0194 EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
Gabriel Charette697593402018-04-30 21:23:4095 EXPECT_TRUE(on_release_);
96 std::move(on_release_).Run();
[email protected]f6710622009-11-02 06:10:3097 }
[email protected]64cd0d122008-10-17 21:16:1398
CJ DiMeglio638cf542018-12-08 02:22:1499 void AddRef() {}
100
[email protected]f6710622009-11-02 06:10:30101 protected:
dchengfa85b152014-10-28 01:13:42102 void SetUp() override {
John Abd-El-Malekf3243dc2021-05-07 16:20:01103 ui_thread_ = std::make_unique<base::Thread>(
104 BrowserThreadImpl::GetThreadName(BrowserThread::UI));
Alex Clarke4779e4bd2019-02-15 22:32:03105 base::Thread::Options ui_options;
Olivier Li89911c42021-07-02 21:27:02106 ui_options.delegate = std::make_unique<SequenceManagerThreadDelegate>();
107 ui_thread_->StartWithOptions(std::move(ui_options));
Gabriel Charette8eb4dff2018-03-27 14:22:54108
Carlos Caballeroe840fc32019-05-27 14:16:37109 io_thread_ = BrowserTaskExecutor::CreateIOThread();
Gabriel Charette8eb4dff2018-03-27 14:22:54110 io_thread_->RegisterAsBrowserThread();
[email protected]f6710622009-11-02 06:10:30111 }
initial.commit09911bf2008-07-26 23:55:29112
dchengfa85b152014-10-28 01:13:42113 void TearDown() override {
Gabriel Charette8eb4dff2018-03-27 14:22:54114 io_thread_.reset();
115 ui_thread_.reset();
116
Gabriel Charettee9748f272017-10-25 19:31:15117 BrowserThreadImpl::ResetGlobalsForTesting(BrowserThread::IO);
Karolina Soltysb083f932019-09-25 16:18:06118 BrowserTaskExecutor::ResetForTesting();
[email protected]f6710622009-11-02 06:10:30119 }
initial.commit09911bf2008-07-26 23:55:29120
Gabriel Charette697593402018-04-30 21:23:40121 // Prepares this BrowserThreadTest for Release() to be invoked. |on_release|
122 // will be invoked when this occurs.
123 void ExpectRelease(base::OnceClosure on_release) {
124 on_release_ = std::move(on_release);
125 }
126
Eric Secklere329cb92018-08-28 16:09:40127 static void BasicFunction(base::OnceClosure continuation,
128 BrowserThread::ID target) {
129 EXPECT_TRUE(BrowserThread::CurrentlyOn(target));
Gabriel Charette697593402018-04-30 21:23:40130 std::move(continuation).Run();
[email protected]f6710622009-11-02 06:10:30131 }
initial.commit09911bf2008-07-26 23:55:29132
Gabriel Charettee9748f272017-10-25 19:31:15133 class DeletedOnIO
134 : public base::RefCountedThreadSafe<DeletedOnIO,
135 BrowserThread::DeleteOnIOThread> {
[email protected]f6710622009-11-02 06:10:30136 public:
Gabriel Charette697593402018-04-30 21:23:40137 explicit DeletedOnIO(base::OnceClosure on_deletion)
138 : on_deletion_(std::move(on_deletion)) {}
initial.commit09911bf2008-07-26 23:55:29139
[email protected]fb90c942012-04-27 23:40:50140 private:
Gabriel Charettee9748f272017-10-25 19:31:15141 friend struct BrowserThread::DeleteOnThread<BrowserThread::IO>;
142 friend class base::DeleteHelper<DeletedOnIO>;
[email protected]fb90c942012-04-27 23:40:50143
Gabriel Charettee9748f272017-10-25 19:31:15144 ~DeletedOnIO() {
Gabriel Charette697593402018-04-30 21:23:40145 EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
146 std::move(on_deletion_).Run();
[email protected]f6710622009-11-02 06:10:30147 }
initial.commit09911bf2008-07-26 23:55:29148
Gabriel Charette697593402018-04-30 21:23:40149 base::OnceClosure on_deletion_;
[email protected]f6710622009-11-02 06:10:30150 };
initial.commit09911bf2008-07-26 23:55:29151
[email protected]f6710622009-11-02 06:10:30152 private:
John Abd-El-Malekf3243dc2021-05-07 16:20:01153 std::unique_ptr<base::Thread> ui_thread_;
154 std::unique_ptr<BrowserProcessIOThread> io_thread_;
Gabriel Charette697593402018-04-30 21:23:40155
Gabriel Charette694c3c332019-08-19 14:53:05156 base::test::TaskEnvironment task_environment_;
Gabriel Charette697593402018-04-30 21:23:40157 // Must be set before Release() to verify the deletion is intentional. Will be
158 // run from the next call to Release(). mutable so it can be consumed from
159 // Release().
160 mutable base::OnceClosure on_release_;
[email protected]f6710622009-11-02 06:10:30161};
initial.commit09911bf2008-07-26 23:55:29162
fdorayf854c912016-10-10 14:51:07163class UIThreadDestructionObserver
Carlos Caballerob25fe8472020-07-17 10:27:17164 : public base::CurrentThread::DestructionObserver {
rockot48a6aac2016-07-28 17:23:54165 public:
fdorayf854c912016-10-10 14:51:07166 explicit UIThreadDestructionObserver(bool* did_shutdown,
danakj151f8fdd2019-12-11 03:11:14167 base::OnceClosure callback)
Sean Maher5b9af51f2022-11-21 15:32:47168 : callback_task_runner_(
169 base::SingleThreadTaskRunner::GetCurrentDefault()),
Gabriel Charette49e3cd02020-01-28 03:45:27170 ui_task_runner_(GetUIThreadTaskRunner({})),
danakj151f8fdd2019-12-11 03:11:14171 callback_(std::move(callback)),
rockot48a6aac2016-07-28 17:23:54172 did_shutdown_(did_shutdown) {
Eric Seckler4d89f642018-09-20 18:16:16173 ui_task_runner_->PostTask(FROM_HERE, base::BindOnce(&Watch, this));
rockot48a6aac2016-07-28 17:23:54174 }
175
176 private:
fdorayf854c912016-10-10 14:51:07177 static void Watch(UIThreadDestructionObserver* observer) {
Carlos Caballerob25fe8472020-07-17 10:27:17178 base::CurrentThread::Get()->AddDestructionObserver(observer);
rockot48a6aac2016-07-28 17:23:54179 }
180
Carlos Caballerob25fe8472020-07-17 10:27:17181 // base::CurrentThread::DestructionObserver:
rockot48a6aac2016-07-28 17:23:54182 void WillDestroyCurrentMessageLoop() override {
183 // Ensure that even during MessageLoop teardown the BrowserThread ID is
184 // correctly associated with this thread and the BrowserThreadTaskRunner
185 // knows it's on the right thread.
fdorayf854c912016-10-10 14:51:07186 EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
187 EXPECT_TRUE(ui_task_runner_->BelongsToCurrentThread());
rockot48a6aac2016-07-28 17:23:54188
Carlos Caballerob25fe8472020-07-17 10:27:17189 base::CurrentThread::Get()->RemoveDestructionObserver(this);
rockot48a6aac2016-07-28 17:23:54190 *did_shutdown_ = true;
danakj151f8fdd2019-12-11 03:11:14191 callback_task_runner_->PostTask(FROM_HERE, std::move(callback_));
rockot48a6aac2016-07-28 17:23:54192 }
193
194 const scoped_refptr<base::SingleThreadTaskRunner> callback_task_runner_;
fdorayf854c912016-10-10 14:51:07195 const scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
danakj151f8fdd2019-12-11 03:11:14196 base::OnceClosure callback_;
Keishi Hattori0e45c022021-11-27 09:25:52197 raw_ptr<bool> did_shutdown_;
rockot48a6aac2016-07-28 17:23:54198};
199
Sami Kyostila8e4d5a92019-08-02 12:45:05200TEST_F(BrowserThreadTest, PostTask) {
Eric Secklere329cb92018-08-28 16:09:40201 base::RunLoop run_loop;
Michael Thiessenab67d392023-03-16 03:14:53202 EXPECT_TRUE(GetIOThreadTaskRunner({})->PostTask(
203 FROM_HERE, base::BindOnce(&BasicFunction, run_loop.QuitWhenIdleClosure(),
204 BrowserThread::IO)));
Gabriel Charette697593402018-04-30 21:23:40205 run_loop.Run();
[email protected]f6710622009-11-02 06:10:30206}
initial.commit09911bf2008-07-26 23:55:29207
[email protected]092b04e2010-10-12 23:23:44208TEST_F(BrowserThreadTest, ReleasedOnCorrectThread) {
Gabriel Charette697593402018-04-30 21:23:40209 base::RunLoop run_loop;
[email protected]f6710622009-11-02 06:10:30210 {
Gabriel Charettee9748f272017-10-25 19:31:15211 scoped_refptr<DeletedOnIO> test(
Gabriel Charette697593402018-04-30 21:23:40212 new DeletedOnIO(run_loop.QuitWhenIdleClosure()));
[email protected]f6710622009-11-02 06:10:30213 }
Gabriel Charette697593402018-04-30 21:23:40214 run_loop.Run();
[email protected]f6710622009-11-02 06:10:30215}
216
Sami Kyostila8e4d5a92019-08-02 12:45:05217TEST_F(BrowserThreadTest, PostTaskViaTaskRunner) {
Gabriel Charette49e3cd02020-01-28 03:45:27218 scoped_refptr<base::TaskRunner> task_runner = GetIOThreadTaskRunner({});
Eric Secklere329cb92018-08-28 16:09:40219 base::RunLoop run_loop;
220 EXPECT_TRUE(task_runner->PostTask(
221 FROM_HERE, base::BindOnce(&BasicFunction, run_loop.QuitWhenIdleClosure(),
222 BrowserThread::IO)));
223 run_loop.Run();
224}
225
Sami Kyostila8e4d5a92019-08-02 12:45:05226TEST_F(BrowserThreadTest, PostTaskViaSequencedTaskRunner) {
Eric Secklere329cb92018-08-28 16:09:40227 scoped_refptr<base::SequencedTaskRunner> task_runner =
Gabriel Charette49e3cd02020-01-28 03:45:27228 GetIOThreadTaskRunner({});
Eric Secklere329cb92018-08-28 16:09:40229 base::RunLoop run_loop;
230 EXPECT_TRUE(task_runner->PostTask(
231 FROM_HERE, base::BindOnce(&BasicFunction, run_loop.QuitWhenIdleClosure(),
232 BrowserThread::IO)));
233 run_loop.Run();
234}
235
Sami Kyostila8e4d5a92019-08-02 12:45:05236TEST_F(BrowserThreadTest, PostTaskViaSingleThreadTaskRunner) {
Eric Secklere329cb92018-08-28 16:09:40237 scoped_refptr<base::SingleThreadTaskRunner> task_runner =
Gabriel Charette49e3cd02020-01-28 03:45:27238 GetIOThreadTaskRunner({});
Eric Secklere329cb92018-08-28 16:09:40239 base::RunLoop run_loop;
240 EXPECT_TRUE(task_runner->PostTask(
241 FROM_HERE, base::BindOnce(&BasicFunction, run_loop.QuitWhenIdleClosure(),
242 BrowserThread::IO)));
243 run_loop.Run();
244}
245
Eric Secklere329cb92018-08-28 16:09:40246
Sami Kyostila8e4d5a92019-08-02 12:45:05247TEST_F(BrowserThreadTest, ReleaseViaTaskRunner) {
Eric Secklere329cb92018-08-28 16:09:40248 scoped_refptr<base::SingleThreadTaskRunner> task_runner =
John Abd-El-Malekf3243dc2021-05-07 16:20:01249 GetIOThreadTaskRunner({});
Eric Secklere329cb92018-08-28 16:09:40250 base::RunLoop run_loop;
251 ExpectRelease(run_loop.QuitWhenIdleClosure());
CJ DiMeglio638cf542018-12-08 02:22:14252 task_runner->ReleaseSoon(FROM_HERE, base::WrapRefCounted(this));
Eric Secklere329cb92018-08-28 16:09:40253 run_loop.Run();
254}
255
Sami Kyostila8e4d5a92019-08-02 12:45:05256TEST_F(BrowserThreadTest, PostTaskAndReply) {
Eric Secklere329cb92018-08-28 16:09:40257 // Most of the heavy testing for PostTaskAndReply() is done inside the
258 // task runner test. This just makes sure we get piped through at all.
259 base::RunLoop run_loop;
Gabriel Charette49e3cd02020-01-28 03:45:27260 ASSERT_TRUE(GetIOThreadTaskRunner({})->PostTaskAndReply(
261 FROM_HERE, base::DoNothing(), run_loop.QuitWhenIdleClosure()));
Eric Secklere329cb92018-08-28 16:09:40262 run_loop.Run();
263}
264
Carlos Caballero4118f7e2019-05-28 13:54:00265class BrowserThreadWithCustomSchedulerTest : public testing::Test {
266 private:
Gabriel Charette694c3c332019-08-19 14:53:05267 class TaskEnvironmentWithCustomScheduler
268 : public base::test::TaskEnvironment {
Carlos Caballero4118f7e2019-05-28 13:54:00269 public:
Gabriel Charette694c3c332019-08-19 14:53:05270 TaskEnvironmentWithCustomScheduler()
Scott Haseley72d89b02023-02-17 03:29:25271 : base::test::TaskEnvironment(
272 internal::CreateBrowserTaskPrioritySettings(),
273 SubclassCreatesDefaultTaskRunner{}) {
Carlos Caballero4118f7e2019-05-28 13:54:00274 std::unique_ptr<BrowserUIThreadScheduler> browser_ui_thread_scheduler =
Etienne Pierre-doray40545ac2021-11-11 13:34:28275 BrowserUIThreadScheduler::CreateForTesting(sequence_manager());
Carlos Caballero4118f7e2019-05-28 13:54:00276 DeferredInitFromSubclass(
Alex Clarke49854cc2019-06-27 08:25:49277 browser_ui_thread_scheduler->GetHandle()->GetBrowserTaskRunner(
Carlos Caballero4118f7e2019-05-28 13:54:00278 QueueType::kDefault));
279 BrowserTaskExecutor::CreateForTesting(
280 std::move(browser_ui_thread_scheduler),
Alex Clarkebbf891dc2019-10-09 14:18:02281 std::make_unique<BrowserIOThreadDelegate>());
Carlos Caballero4118f7e2019-05-28 13:54:00282
John Abd-El-Malekf3243dc2021-05-07 16:20:01283 io_thread_ = BrowserTaskExecutor::CreateIOThread();
Carlos Caballero4118f7e2019-05-28 13:54:00284 BrowserTaskExecutor::InitializeIOThread();
John Abd-El-Malekf3243dc2021-05-07 16:20:01285 io_thread_->RegisterAsBrowserThread();
Carlos Caballero4118f7e2019-05-28 13:54:00286 }
287
Gabriel Charette694c3c332019-08-19 14:53:05288 ~TaskEnvironmentWithCustomScheduler() override {
John Abd-El-Malekf3243dc2021-05-07 16:20:01289 io_thread_.reset();
Carlos Caballero4118f7e2019-05-28 13:54:00290 BrowserThreadImpl::ResetGlobalsForTesting(BrowserThread::IO);
291 BrowserTaskExecutor::ResetForTesting();
292 }
293
294 private:
John Abd-El-Malekf3243dc2021-05-07 16:20:01295 std::unique_ptr<BrowserProcessIOThread> io_thread_;
Carlos Caballero4118f7e2019-05-28 13:54:00296 };
297
298 public:
299 using QueueType = BrowserTaskQueues::QueueType;
300
301 protected:
Gabriel Charette694c3c332019-08-19 14:53:05302 TaskEnvironmentWithCustomScheduler task_environment_;
Carlos Caballero4118f7e2019-05-28 13:54:00303};
304
305TEST_F(BrowserThreadWithCustomSchedulerTest, PostBestEffortTask) {
danakj151f8fdd2019-12-11 03:11:14306 base::MockOnceClosure best_effort_task;
307 base::MockOnceClosure regular_task;
Carlos Caballero4118f7e2019-05-28 13:54:00308
Gabriel Charettee7cdc5cd2020-05-27 23:35:05309 auto task_runner = GetUIThreadTaskRunner({base::TaskPriority::HIGHEST});
Carlos Caballero4118f7e2019-05-28 13:54:00310
311 task_runner->PostTask(FROM_HERE, regular_task.Get());
312 BrowserThread::PostBestEffortTask(FROM_HERE, task_runner,
313 best_effort_task.Get());
314
danakj151f8fdd2019-12-11 03:11:14315 EXPECT_CALL(regular_task, Run).Times(1);
316 EXPECT_CALL(best_effort_task, Run).Times(0);
Gabriel Charette694c3c332019-08-19 14:53:05317 task_environment_.RunUntilIdle();
Carlos Caballero4118f7e2019-05-28 13:54:00318
319 testing::Mock::VerifyAndClearExpectations(&regular_task);
320
Minoru Chikamunea0317562022-03-22 15:30:21321 BrowserTaskExecutor::OnStartupComplete();
Carlos Caballero4118f7e2019-05-28 13:54:00322 base::RunLoop run_loop;
323 EXPECT_CALL(best_effort_task, Run).WillOnce(Invoke([&]() {
324 run_loop.Quit();
325 }));
326 run_loop.Run();
327}
328
[email protected]2b9eb3872013-03-30 18:58:30329} // namespace content