blob: 451c6f5caa244de927b4d123113951d19bd5c1a8 [file] [log] [blame]
[email protected]ac4c6682012-01-04 00:57:391// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]b44d5cc2009-06-15 10:30:442// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]59e69e742013-06-18 20:27:525#include "base/message_loop/message_pump_glib.h"
[email protected]b44d5cc2009-06-15 10:30:446
[email protected]d90efd52012-06-28 19:57:267#include <glib.h>
[email protected]23d35392009-06-15 19:53:088#include <math.h>
9
[email protected]b44d5cc2009-06-15 10:30:4410#include <algorithm>
11#include <vector>
[email protected]23d35392009-06-15 19:53:0812
[email protected]8f5a7e492012-01-01 02:14:4713#include "base/bind.h"
14#include "base/bind_helpers.h"
[email protected]763839e2011-12-09 23:06:0215#include "base/callback.h"
avi9b6f42932015-12-26 22:15:1416#include "base/macros.h"
[email protected]3b63f8f42011-03-28 01:54:1517#include "base/memory/ref_counted.h"
[email protected]495cad92013-07-18 08:12:4018#include "base/message_loop/message_loop.h"
[email protected]7ff48ca2013-02-06 16:56:1919#include "base/run_loop.h"
fdoray6ef45cf2016-08-25 15:36:3720#include "base/single_thread_task_runner.h"
[email protected]34b99632011-01-01 01:01:0621#include "base/threading/thread.h"
fdoray2df4a9e2016-07-18 23:47:1622#include "base/threading/thread_task_runner_handle.h"
[email protected]b44d5cc2009-06-15 10:30:4423#include "testing/gtest/include/gtest/gtest.h"
24
[email protected]7ff48ca2013-02-06 16:56:1925namespace base {
[email protected]b44d5cc2009-06-15 10:30:4426namespace {
27
28// This class injects dummy "events" into the GLib loop. When "handled" these
29// events can run tasks. This is intended to mock gtk events (the corresponding
30// GLib source runs at the same priority).
31class EventInjector {
32 public:
33 EventInjector() : processed_events_(0) {
34 source_ = static_cast<Source*>(g_source_new(&SourceFuncs, sizeof(Source)));
35 source_->injector = this;
Ivan Kotenkova16212a52017-11-08 12:37:3336 g_source_attach(source_, nullptr);
[email protected]b44d5cc2009-06-15 10:30:4437 g_source_set_can_recurse(source_, TRUE);
38 }
39
40 ~EventInjector() {
41 g_source_destroy(source_);
42 g_source_unref(source_);
43 }
44
45 int HandlePrepare() {
46 // If the queue is empty, block.
47 if (events_.empty())
48 return -1;
[email protected]59e69e742013-06-18 20:27:5249 TimeDelta delta = events_[0].time - Time::NowFromSystemTime();
[email protected]b44d5cc2009-06-15 10:30:4450 return std::max(0, static_cast<int>(ceil(delta.InMillisecondsF())));
51 }
52
53 bool HandleCheck() {
54 if (events_.empty())
55 return false;
[email protected]59e69e742013-06-18 20:27:5256 return events_[0].time <= Time::NowFromSystemTime();
[email protected]b44d5cc2009-06-15 10:30:4457 }
58
59 void HandleDispatch() {
60 if (events_.empty())
61 return;
tzika8cc2202017-04-18 07:01:1562 Event event = std::move(events_[0]);
[email protected]b44d5cc2009-06-15 10:30:4463 events_.erase(events_.begin());
64 ++processed_events_;
[email protected]8f5a7e492012-01-01 02:14:4765 if (!event.callback.is_null())
tzika8cc2202017-04-18 07:01:1566 std::move(event.callback).Run();
[email protected]8f5a7e492012-01-01 02:14:4767 else if (!event.task.is_null())
tzika8cc2202017-04-18 07:01:1568 std::move(event.task).Run();
[email protected]b44d5cc2009-06-15 10:30:4469 }
70
[email protected]763839e2011-12-09 23:06:0271 // Adds an event to the queue. When "handled", executes |callback|.
[email protected]b44d5cc2009-06-15 10:30:4472 // delay_ms is relative to the last event if any, or to Now() otherwise.
tzika8cc2202017-04-18 07:01:1573 void AddEvent(int delay_ms, OnceClosure callback) {
74 AddEventHelper(delay_ms, std::move(callback), OnceClosure());
[email protected]763839e2011-12-09 23:06:0275 }
76
77 void AddDummyEvent(int delay_ms) {
tzika8cc2202017-04-18 07:01:1578 AddEventHelper(delay_ms, OnceClosure(), OnceClosure());
[email protected]763839e2011-12-09 23:06:0279 }
80
tzika8cc2202017-04-18 07:01:1581 void AddEventAsTask(int delay_ms, OnceClosure task) {
82 AddEventHelper(delay_ms, OnceClosure(), std::move(task));
[email protected]b44d5cc2009-06-15 10:30:4483 }
84
85 void Reset() {
86 processed_events_ = 0;
87 events_.clear();
88 }
89
90 int processed_events() const { return processed_events_; }
91
92 private:
93 struct Event {
[email protected]59e69e742013-06-18 20:27:5294 Time time;
tzika8cc2202017-04-18 07:01:1595 OnceClosure callback;
96 OnceClosure task;
[email protected]b44d5cc2009-06-15 10:30:4497 };
98
99 struct Source : public GSource {
100 EventInjector* injector;
101 };
102
tzika8cc2202017-04-18 07:01:15103 void AddEventHelper(int delay_ms, OnceClosure callback, OnceClosure task) {
[email protected]59e69e742013-06-18 20:27:52104 Time last_time;
[email protected]8f5a7e492012-01-01 02:14:47105 if (!events_.empty())
[email protected]763839e2011-12-09 23:06:02106 last_time = (events_.end()-1)->time;
[email protected]8f5a7e492012-01-01 02:14:47107 else
[email protected]59e69e742013-06-18 20:27:52108 last_time = Time::NowFromSystemTime();
[email protected]8f5a7e492012-01-01 02:14:47109
[email protected]59e69e742013-06-18 20:27:52110 Time future = last_time + TimeDelta::FromMilliseconds(delay_ms);
tzika8cc2202017-04-18 07:01:15111 EventInjector::Event event = {future, std::move(callback), std::move(task)};
112 events_.push_back(std::move(event));
[email protected]763839e2011-12-09 23:06:02113 }
114
[email protected]b44d5cc2009-06-15 10:30:44115 static gboolean Prepare(GSource* source, gint* timeout_ms) {
116 *timeout_ms = static_cast<Source*>(source)->injector->HandlePrepare();
117 return FALSE;
118 }
119
120 static gboolean Check(GSource* source) {
121 return static_cast<Source*>(source)->injector->HandleCheck();
122 }
123
124 static gboolean Dispatch(GSource* source,
125 GSourceFunc unused_func,
126 gpointer unused_data) {
127 static_cast<Source*>(source)->injector->HandleDispatch();
128 return TRUE;
129 }
130
131 Source* source_;
132 std::vector<Event> events_;
133 int processed_events_;
134 static GSourceFuncs SourceFuncs;
135 DISALLOW_COPY_AND_ASSIGN(EventInjector);
136};
137
Ivan Kotenkova16212a52017-11-08 12:37:33138GSourceFuncs EventInjector::SourceFuncs = {EventInjector::Prepare,
139 EventInjector::Check,
140 EventInjector::Dispatch, nullptr};
[email protected]b44d5cc2009-06-15 10:30:44141
[email protected]b44d5cc2009-06-15 10:30:44142void IncrementInt(int *value) {
143 ++*value;
144}
145
146// Checks how many events have been processed by the injector.
147void ExpectProcessedEvents(EventInjector* injector, int count) {
148 EXPECT_EQ(injector->processed_events(), count);
149}
150
[email protected]b44d5cc2009-06-15 10:30:44151// Posts a task on the current message loop.
Brett Wilson8e88b312017-09-12 05:22:16152void PostMessageLoopTask(const Location& from_here, OnceClosure task) {
tzika8cc2202017-04-18 07:01:15153 ThreadTaskRunnerHandle::Get()->PostTask(from_here, std::move(task));
[email protected]b44d5cc2009-06-15 10:30:44154}
155
156// Test fixture.
157class MessagePumpGLibTest : public testing::Test {
158 public:
Ivan Kotenkova16212a52017-11-08 12:37:33159 MessagePumpGLibTest() : loop_(nullptr), injector_(nullptr) {}
[email protected]b44d5cc2009-06-15 10:30:44160
[email protected]c19003d2012-07-31 01:38:18161 // Overridden from testing::Test:
dcheng8aef37612014-12-23 02:56:47162 void SetUp() override {
[email protected]b44d5cc2009-06-15 10:30:44163 loop_ = new MessageLoop(MessageLoop::TYPE_UI);
164 injector_ = new EventInjector();
165 }
dcheng8aef37612014-12-23 02:56:47166 void TearDown() override {
[email protected]b44d5cc2009-06-15 10:30:44167 delete injector_;
Ivan Kotenkova16212a52017-11-08 12:37:33168 injector_ = nullptr;
[email protected]b44d5cc2009-06-15 10:30:44169 delete loop_;
Ivan Kotenkova16212a52017-11-08 12:37:33170 loop_ = nullptr;
[email protected]b44d5cc2009-06-15 10:30:44171 }
172
173 MessageLoop* loop() const { return loop_; }
174 EventInjector* injector() const { return injector_; }
175
176 private:
177 MessageLoop* loop_;
178 EventInjector* injector_;
179 DISALLOW_COPY_AND_ASSIGN(MessagePumpGLibTest);
180};
181
182} // namespace
183
[email protected]b44d5cc2009-06-15 10:30:44184TEST_F(MessagePumpGLibTest, TestQuit) {
185 // Checks that Quit works and that the basic infrastructure is working.
186
187 // Quit from a task
[email protected]7ff48ca2013-02-06 16:56:19188 RunLoop().RunUntilIdle();
[email protected]b44d5cc2009-06-15 10:30:44189 EXPECT_EQ(0, injector()->processed_events());
190
191 injector()->Reset();
192 // Quit from an event
[email protected]a085953f2013-02-04 23:40:00193 injector()->AddEvent(0, MessageLoop::QuitWhenIdleClosure());
fdoray6ef45cf2016-08-25 15:36:37194 RunLoop().Run();
[email protected]b44d5cc2009-06-15 10:30:44195 EXPECT_EQ(1, injector()->processed_events());
196}
197
198TEST_F(MessagePumpGLibTest, TestEventTaskInterleave) {
199 // Checks that tasks posted by events are executed before the next event if
200 // the posted task queue is empty.
201 // MessageLoop doesn't make strong guarantees that it is the case, but the
202 // current implementation ensures it and the tests below rely on it.
203 // If changes cause this test to fail, it is reasonable to change it, but
204 // TestWorkWhileWaitingForEvents and TestEventsWhileWaitingForWork have to be
205 // changed accordingly, otherwise they can become flaky.
Peter Kasting341e1fb2018-02-24 00:03:01206 injector()->AddEventAsTask(0, DoNothing());
tzika8cc2202017-04-18 07:01:15207 OnceClosure check_task =
208 BindOnce(&ExpectProcessedEvents, Unretained(injector()), 2);
209 OnceClosure posted_task =
210 BindOnce(&PostMessageLoopTask, FROM_HERE, std::move(check_task));
211 injector()->AddEventAsTask(0, std::move(posted_task));
Peter Kasting341e1fb2018-02-24 00:03:01212 injector()->AddEventAsTask(0, DoNothing());
[email protected]a085953f2013-02-04 23:40:00213 injector()->AddEvent(0, MessageLoop::QuitWhenIdleClosure());
fdoray6ef45cf2016-08-25 15:36:37214 RunLoop().Run();
[email protected]b44d5cc2009-06-15 10:30:44215 EXPECT_EQ(4, injector()->processed_events());
216
217 injector()->Reset();
Peter Kasting341e1fb2018-02-24 00:03:01218 injector()->AddEventAsTask(0, DoNothing());
tzika8cc2202017-04-18 07:01:15219 check_task = BindOnce(&ExpectProcessedEvents, Unretained(injector()), 2);
220 posted_task =
221 BindOnce(&PostMessageLoopTask, FROM_HERE, std::move(check_task));
222 injector()->AddEventAsTask(0, std::move(posted_task));
Peter Kasting341e1fb2018-02-24 00:03:01223 injector()->AddEventAsTask(10, DoNothing());
[email protected]a085953f2013-02-04 23:40:00224 injector()->AddEvent(0, MessageLoop::QuitWhenIdleClosure());
fdoray6ef45cf2016-08-25 15:36:37225 RunLoop().Run();
[email protected]b44d5cc2009-06-15 10:30:44226 EXPECT_EQ(4, injector()->processed_events());
227}
228
229TEST_F(MessagePumpGLibTest, TestWorkWhileWaitingForEvents) {
230 int task_count = 0;
231 // Tests that we process tasks while waiting for new events.
232 // The event queue is empty at first.
233 for (int i = 0; i < 10; ++i) {
fdoray6ef45cf2016-08-25 15:36:37234 loop()->task_runner()->PostTask(FROM_HERE,
tzik92b7a422017-04-11 15:00:44235 BindOnce(&IncrementInt, &task_count));
[email protected]b44d5cc2009-06-15 10:30:44236 }
237 // After all the previous tasks have executed, enqueue an event that will
238 // quit.
fdoray6ef45cf2016-08-25 15:36:37239 loop()->task_runner()->PostTask(
tzik92b7a422017-04-11 15:00:44240 FROM_HERE, BindOnce(&EventInjector::AddEvent, Unretained(injector()), 0,
241 MessageLoop::QuitWhenIdleClosure()));
fdoray6ef45cf2016-08-25 15:36:37242 RunLoop().Run();
[email protected]b44d5cc2009-06-15 10:30:44243 ASSERT_EQ(10, task_count);
244 EXPECT_EQ(1, injector()->processed_events());
245
246 // Tests that we process delayed tasks while waiting for new events.
247 injector()->Reset();
248 task_count = 0;
249 for (int i = 0; i < 10; ++i) {
fdoray6ef45cf2016-08-25 15:36:37250 loop()->task_runner()->PostDelayedTask(FROM_HERE,
tzik92b7a422017-04-11 15:00:44251 BindOnce(&IncrementInt, &task_count),
fdoray6ef45cf2016-08-25 15:36:37252 TimeDelta::FromMilliseconds(10 * i));
[email protected]b44d5cc2009-06-15 10:30:44253 }
254 // After all the previous tasks have executed, enqueue an event that will
255 // quit.
256 // This relies on the fact that delayed tasks are executed in delay order.
257 // That is verified in message_loop_unittest.cc.
fdoray6ef45cf2016-08-25 15:36:37258 loop()->task_runner()->PostDelayedTask(
tzik92b7a422017-04-11 15:00:44259 FROM_HERE,
260 BindOnce(&EventInjector::AddEvent, Unretained(injector()), 10,
261 MessageLoop::QuitWhenIdleClosure()),
[email protected]59e69e742013-06-18 20:27:52262 TimeDelta::FromMilliseconds(150));
fdoray6ef45cf2016-08-25 15:36:37263 RunLoop().Run();
[email protected]b44d5cc2009-06-15 10:30:44264 ASSERT_EQ(10, task_count);
265 EXPECT_EQ(1, injector()->processed_events());
266}
267
268TEST_F(MessagePumpGLibTest, TestEventsWhileWaitingForWork) {
269 // Tests that we process events while waiting for work.
270 // The event queue is empty at first.
271 for (int i = 0; i < 10; ++i) {
[email protected]763839e2011-12-09 23:06:02272 injector()->AddDummyEvent(0);
[email protected]b44d5cc2009-06-15 10:30:44273 }
274 // After all the events have been processed, post a task that will check that
275 // the events have been processed (note: the task executes after the event
276 // that posted it has been handled, so we expect 11 at that point).
tzika8cc2202017-04-18 07:01:15277 OnceClosure check_task =
278 BindOnce(&ExpectProcessedEvents, Unretained(injector()), 11);
279 OnceClosure posted_task =
280 BindOnce(&PostMessageLoopTask, FROM_HERE, std::move(check_task));
281 injector()->AddEventAsTask(10, std::move(posted_task));
[email protected]b44d5cc2009-06-15 10:30:44282
283 // And then quit (relies on the condition tested by TestEventTaskInterleave).
[email protected]a085953f2013-02-04 23:40:00284 injector()->AddEvent(10, MessageLoop::QuitWhenIdleClosure());
fdoray6ef45cf2016-08-25 15:36:37285 RunLoop().Run();
[email protected]b44d5cc2009-06-15 10:30:44286
287 EXPECT_EQ(12, injector()->processed_events());
288}
289
290namespace {
291
292// This class is a helper for the concurrent events / posted tasks test below.
293// It will quit the main loop once enough tasks and events have been processed,
294// while making sure there is always work to do and events in the queue.
[email protected]59e69e742013-06-18 20:27:52295class ConcurrentHelper : public RefCounted<ConcurrentHelper> {
[email protected]b44d5cc2009-06-15 10:30:44296 public:
[email protected]2fdc86a2010-01-26 23:08:02297 explicit ConcurrentHelper(EventInjector* injector)
[email protected]b44d5cc2009-06-15 10:30:44298 : injector_(injector),
299 event_count_(kStartingEventCount),
300 task_count_(kStartingTaskCount) {
301 }
302
303 void FromTask() {
304 if (task_count_ > 0) {
305 --task_count_;
306 }
307 if (task_count_ == 0 && event_count_ == 0) {
Gabriel Charette53a9ef812017-07-26 12:36:23308 RunLoop::QuitCurrentWhenIdleDeprecated();
[email protected]b44d5cc2009-06-15 10:30:44309 } else {
fdoray2df4a9e2016-07-18 23:47:16310 ThreadTaskRunnerHandle::Get()->PostTask(
tzik92b7a422017-04-11 15:00:44311 FROM_HERE, BindOnce(&ConcurrentHelper::FromTask, this));
[email protected]b44d5cc2009-06-15 10:30:44312 }
313 }
314
315 void FromEvent() {
316 if (event_count_ > 0) {
317 --event_count_;
318 }
319 if (task_count_ == 0 && event_count_ == 0) {
Gabriel Charette53a9ef812017-07-26 12:36:23320 RunLoop::QuitCurrentWhenIdleDeprecated();
[email protected]b44d5cc2009-06-15 10:30:44321 } else {
tzika8cc2202017-04-18 07:01:15322 injector_->AddEventAsTask(0,
323 BindOnce(&ConcurrentHelper::FromEvent, this));
[email protected]b44d5cc2009-06-15 10:30:44324 }
325 }
326
327 int event_count() const { return event_count_; }
328 int task_count() const { return task_count_; }
329
330 private:
[email protected]59e69e742013-06-18 20:27:52331 friend class RefCounted<ConcurrentHelper>;
[email protected]877d55d2009-11-05 21:53:08332
333 ~ConcurrentHelper() {}
334
[email protected]b44d5cc2009-06-15 10:30:44335 static const int kStartingEventCount = 20;
336 static const int kStartingTaskCount = 20;
337
338 EventInjector* injector_;
339 int event_count_;
340 int task_count_;
341};
342
343} // namespace
344
345TEST_F(MessagePumpGLibTest, TestConcurrentEventPostedTask) {
346 // Tests that posted tasks don't starve events, nor the opposite.
347 // We use the helper class above. We keep both event and posted task queues
348 // full, the helper verifies that both tasks and events get processed.
349 // If that is not the case, either event_count_ or task_count_ will not get
[email protected]91cae2592013-01-10 14:56:17350 // to 0, and MessageLoop::QuitWhenIdle() will never be called.
[email protected]b44d5cc2009-06-15 10:30:44351 scoped_refptr<ConcurrentHelper> helper = new ConcurrentHelper(injector());
352
353 // Add 2 events to the queue to make sure it is always full (when we remove
354 // the event before processing it).
tzika8cc2202017-04-18 07:01:15355 injector()->AddEventAsTask(0, BindOnce(&ConcurrentHelper::FromEvent, helper));
356 injector()->AddEventAsTask(0, BindOnce(&ConcurrentHelper::FromEvent, helper));
[email protected]b44d5cc2009-06-15 10:30:44357
358 // Similarly post 2 tasks.
fdoray6ef45cf2016-08-25 15:36:37359 loop()->task_runner()->PostTask(
tzik92b7a422017-04-11 15:00:44360 FROM_HERE, BindOnce(&ConcurrentHelper::FromTask, helper));
fdoray6ef45cf2016-08-25 15:36:37361 loop()->task_runner()->PostTask(
tzik92b7a422017-04-11 15:00:44362 FROM_HERE, BindOnce(&ConcurrentHelper::FromTask, helper));
[email protected]b44d5cc2009-06-15 10:30:44363
fdoray6ef45cf2016-08-25 15:36:37364 RunLoop().Run();
[email protected]b44d5cc2009-06-15 10:30:44365 EXPECT_EQ(0, helper->event_count());
366 EXPECT_EQ(0, helper->task_count());
367}
368
369namespace {
370
371void AddEventsAndDrainGLib(EventInjector* injector) {
372 // Add a couple of dummy events
[email protected]763839e2011-12-09 23:06:02373 injector->AddDummyEvent(0);
374 injector->AddDummyEvent(0);
[email protected]b44d5cc2009-06-15 10:30:44375 // Then add an event that will quit the main loop.
[email protected]a085953f2013-02-04 23:40:00376 injector->AddEvent(0, MessageLoop::QuitWhenIdleClosure());
[email protected]b44d5cc2009-06-15 10:30:44377
378 // Post a couple of dummy tasks
Peter Kasting341e1fb2018-02-24 00:03:01379 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, DoNothing());
380 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, DoNothing());
[email protected]b44d5cc2009-06-15 10:30:44381
382 // Drain the events
Ivan Kotenkova16212a52017-11-08 12:37:33383 while (g_main_context_pending(nullptr)) {
384 g_main_context_iteration(nullptr, FALSE);
[email protected]b44d5cc2009-06-15 10:30:44385 }
386}
387
388} // namespace
389
390TEST_F(MessagePumpGLibTest, TestDrainingGLib) {
391 // Tests that draining events using GLib works.
fdoray6ef45cf2016-08-25 15:36:37392 loop()->task_runner()->PostTask(
tzik92b7a422017-04-11 15:00:44393 FROM_HERE, BindOnce(&AddEventsAndDrainGLib, Unretained(injector())));
fdoray6ef45cf2016-08-25 15:36:37394 RunLoop().Run();
[email protected]b44d5cc2009-06-15 10:30:44395
396 EXPECT_EQ(3, injector()->processed_events());
397}
398
[email protected]b44d5cc2009-06-15 10:30:44399namespace {
400
401// Helper class that lets us run the GLib message loop.
[email protected]59e69e742013-06-18 20:27:52402class GLibLoopRunner : public RefCounted<GLibLoopRunner> {
[email protected]b44d5cc2009-06-15 10:30:44403 public:
404 GLibLoopRunner() : quit_(false) { }
405
406 void RunGLib() {
407 while (!quit_) {
Ivan Kotenkova16212a52017-11-08 12:37:33408 g_main_context_iteration(nullptr, TRUE);
[email protected]b44d5cc2009-06-15 10:30:44409 }
410 }
411
[email protected]258dca42011-09-21 00:17:19412 void RunLoop() {
[email protected]258dca42011-09-21 00:17:19413 while (!quit_) {
Ivan Kotenkova16212a52017-11-08 12:37:33414 g_main_context_iteration(nullptr, TRUE);
[email protected]258dca42011-09-21 00:17:19415 }
[email protected]b44d5cc2009-06-15 10:30:44416 }
417
418 void Quit() {
419 quit_ = true;
420 }
421
422 void Reset() {
423 quit_ = false;
424 }
425
426 private:
[email protected]59e69e742013-06-18 20:27:52427 friend class RefCounted<GLibLoopRunner>;
[email protected]877d55d2009-11-05 21:53:08428
429 ~GLibLoopRunner() {}
430
[email protected]b44d5cc2009-06-15 10:30:44431 bool quit_;
432};
433
434void TestGLibLoopInternal(EventInjector* injector) {
435 // Allow tasks to be processed from 'native' event loops.
436 MessageLoop::current()->SetNestableTasksAllowed(true);
437 scoped_refptr<GLibLoopRunner> runner = new GLibLoopRunner();
438
439 int task_count = 0;
440 // Add a couple of dummy events
[email protected]763839e2011-12-09 23:06:02441 injector->AddDummyEvent(0);
442 injector->AddDummyEvent(0);
[email protected]b44d5cc2009-06-15 10:30:44443 // Post a couple of dummy tasks
fdoray2df4a9e2016-07-18 23:47:16444 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
tzik92b7a422017-04-11 15:00:44445 BindOnce(&IncrementInt, &task_count));
fdoray2df4a9e2016-07-18 23:47:16446 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
tzik92b7a422017-04-11 15:00:44447 BindOnce(&IncrementInt, &task_count));
[email protected]b44d5cc2009-06-15 10:30:44448 // Delayed events
[email protected]763839e2011-12-09 23:06:02449 injector->AddDummyEvent(10);
450 injector->AddDummyEvent(10);
[email protected]b44d5cc2009-06-15 10:30:44451 // Delayed work
fdoray2df4a9e2016-07-18 23:47:16452 ThreadTaskRunnerHandle::Get()->PostDelayedTask(
tzik92b7a422017-04-11 15:00:44453 FROM_HERE, BindOnce(&IncrementInt, &task_count),
[email protected]59e69e742013-06-18 20:27:52454 TimeDelta::FromMilliseconds(30));
fdoray2df4a9e2016-07-18 23:47:16455 ThreadTaskRunnerHandle::Get()->PostDelayedTask(
tzik92b7a422017-04-11 15:00:44456 FROM_HERE, BindOnce(&GLibLoopRunner::Quit, runner),
[email protected]59e69e742013-06-18 20:27:52457 TimeDelta::FromMilliseconds(40));
[email protected]b44d5cc2009-06-15 10:30:44458
459 // Run a nested, straight GLib message loop.
460 runner->RunGLib();
461
462 ASSERT_EQ(3, task_count);
463 EXPECT_EQ(4, injector->processed_events());
Gabriel Charette53a9ef812017-07-26 12:36:23464 RunLoop::QuitCurrentWhenIdleDeprecated();
[email protected]b44d5cc2009-06-15 10:30:44465}
466
467void TestGtkLoopInternal(EventInjector* injector) {
468 // Allow tasks to be processed from 'native' event loops.
469 MessageLoop::current()->SetNestableTasksAllowed(true);
470 scoped_refptr<GLibLoopRunner> runner = new GLibLoopRunner();
471
472 int task_count = 0;
473 // Add a couple of dummy events
[email protected]763839e2011-12-09 23:06:02474 injector->AddDummyEvent(0);
475 injector->AddDummyEvent(0);
[email protected]b44d5cc2009-06-15 10:30:44476 // Post a couple of dummy tasks
fdoray2df4a9e2016-07-18 23:47:16477 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
tzik92b7a422017-04-11 15:00:44478 BindOnce(&IncrementInt, &task_count));
fdoray2df4a9e2016-07-18 23:47:16479 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
tzik92b7a422017-04-11 15:00:44480 BindOnce(&IncrementInt, &task_count));
[email protected]b44d5cc2009-06-15 10:30:44481 // Delayed events
[email protected]763839e2011-12-09 23:06:02482 injector->AddDummyEvent(10);
483 injector->AddDummyEvent(10);
[email protected]b44d5cc2009-06-15 10:30:44484 // Delayed work
fdoray2df4a9e2016-07-18 23:47:16485 ThreadTaskRunnerHandle::Get()->PostDelayedTask(
tzik92b7a422017-04-11 15:00:44486 FROM_HERE, BindOnce(&IncrementInt, &task_count),
[email protected]59e69e742013-06-18 20:27:52487 TimeDelta::FromMilliseconds(30));
fdoray2df4a9e2016-07-18 23:47:16488 ThreadTaskRunnerHandle::Get()->PostDelayedTask(
tzik92b7a422017-04-11 15:00:44489 FROM_HERE, BindOnce(&GLibLoopRunner::Quit, runner),
[email protected]59e69e742013-06-18 20:27:52490 TimeDelta::FromMilliseconds(40));
[email protected]b44d5cc2009-06-15 10:30:44491
492 // Run a nested, straight Gtk message loop.
[email protected]258dca42011-09-21 00:17:19493 runner->RunLoop();
[email protected]b44d5cc2009-06-15 10:30:44494
495 ASSERT_EQ(3, task_count);
496 EXPECT_EQ(4, injector->processed_events());
Gabriel Charette53a9ef812017-07-26 12:36:23497 RunLoop::QuitCurrentWhenIdleDeprecated();
[email protected]b44d5cc2009-06-15 10:30:44498}
499
500} // namespace
501
502TEST_F(MessagePumpGLibTest, TestGLibLoop) {
[email protected]8f5a7e492012-01-01 02:14:47503 // Tests that events and posted tasks are correctly executed if the message
[email protected]b44d5cc2009-06-15 10:30:44504 // loop is not run by MessageLoop::Run() but by a straight GLib loop.
505 // Note that in this case we don't make strong guarantees about niceness
506 // between events and posted tasks.
fdoray6ef45cf2016-08-25 15:36:37507 loop()->task_runner()->PostTask(
tzik92b7a422017-04-11 15:00:44508 FROM_HERE, BindOnce(&TestGLibLoopInternal, Unretained(injector())));
fdoray6ef45cf2016-08-25 15:36:37509 RunLoop().Run();
[email protected]b44d5cc2009-06-15 10:30:44510}
511
512TEST_F(MessagePumpGLibTest, TestGtkLoop) {
[email protected]8f5a7e492012-01-01 02:14:47513 // Tests that events and posted tasks are correctly executed if the message
[email protected]b44d5cc2009-06-15 10:30:44514 // loop is not run by MessageLoop::Run() but by a straight Gtk loop.
515 // Note that in this case we don't make strong guarantees about niceness
516 // between events and posted tasks.
fdoray6ef45cf2016-08-25 15:36:37517 loop()->task_runner()->PostTask(
tzik92b7a422017-04-11 15:00:44518 FROM_HERE, BindOnce(&TestGtkLoopInternal, Unretained(injector())));
fdoray6ef45cf2016-08-25 15:36:37519 RunLoop().Run();
[email protected]b44d5cc2009-06-15 10:30:44520}
[email protected]7ff48ca2013-02-06 16:56:19521
522} // namespace base