diff options
author | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-18 20:27:52 +0000 |
---|---|---|
committer | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-18 20:27:52 +0000 |
commit | 59e69e745ba3fa290ff3c50e65c3db03ee9dde6b (patch) | |
tree | 64b82fd1e2375845b59f278f2a1e892dcf54377b /base/message_pump_glib_unittest.cc | |
parent | bd41e70e44d19eb809eb8565b1d8479daef5d8f5 (diff) | |
download | chromium_src-59e69e745ba3fa290ff3c50e65c3db03ee9dde6b.zip chromium_src-59e69e745ba3fa290ff3c50e65c3db03ee9dde6b.tar.gz chromium_src-59e69e745ba3fa290ff3c50e65c3db03ee9dde6b.tar.bz2 |
Move message_pump to base/message_loop.
This also fixes some namespace usage inside the message pump files and updates all users of these files to use the new location.
Reland of 206507.
Original review https://codereview.chromium.org/17078005/
TBR=sky
Review URL: https://codereview.chromium.org/16897006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@207075 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/message_pump_glib_unittest.cc')
-rw-r--r-- | base/message_pump_glib_unittest.cc | 580 |
1 files changed, 0 insertions, 580 deletions
diff --git a/base/message_pump_glib_unittest.cc b/base/message_pump_glib_unittest.cc deleted file mode 100644 index be11c2f..0000000 --- a/base/message_pump_glib_unittest.cc +++ /dev/null @@ -1,580 +0,0 @@ -// 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/message_pump_glib.h" - -#include <glib.h> -#include <math.h> - -#include <algorithm> -#include <vector> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/callback.h" -#include "base/memory/ref_counted.h" -#include "base/message_loop.h" -#include "base/run_loop.h" -#include "base/threading/thread.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(TOOLKIT_GTK) -#include <gtk/gtk.h> -#endif - -namespace base { -namespace { - -// This class injects dummy "events" into the GLib loop. When "handled" these -// events can run tasks. This is intended to mock gtk events (the corresponding -// GLib source runs at the same priority). -class EventInjector { - public: - EventInjector() : processed_events_(0) { - source_ = static_cast<Source*>(g_source_new(&SourceFuncs, sizeof(Source))); - source_->injector = this; - g_source_attach(source_, NULL); - g_source_set_can_recurse(source_, TRUE); - } - - ~EventInjector() { - g_source_destroy(source_); - g_source_unref(source_); - } - - int HandlePrepare() { - // If the queue is empty, block. - if (events_.empty()) - return -1; - base::TimeDelta delta = events_[0].time - base::Time::NowFromSystemTime(); - return std::max(0, static_cast<int>(ceil(delta.InMillisecondsF()))); - } - - bool HandleCheck() { - if (events_.empty()) - return false; - return events_[0].time <= base::Time::NowFromSystemTime(); - } - - void HandleDispatch() { - if (events_.empty()) - return; - Event event = events_[0]; - events_.erase(events_.begin()); - ++processed_events_; - if (!event.callback.is_null()) - event.callback.Run(); - else if (!event.task.is_null()) - event.task.Run(); - } - - // Adds an event to the queue. When "handled", executes |callback|. - // delay_ms is relative to the last event if any, or to Now() otherwise. - void AddEvent(int delay_ms, const base::Closure& callback) { - AddEventHelper(delay_ms, callback, base::Closure()); - } - - void AddDummyEvent(int delay_ms) { - AddEventHelper(delay_ms, base::Closure(), base::Closure()); - } - - void AddEventAsTask(int delay_ms, const base::Closure& task) { - AddEventHelper(delay_ms, base::Closure(), task); - } - - void Reset() { - processed_events_ = 0; - events_.clear(); - } - - int processed_events() const { return processed_events_; } - - private: - struct Event { - base::Time time; - base::Closure callback; - base::Closure task; - }; - - struct Source : public GSource { - EventInjector* injector; - }; - - void AddEventHelper( - int delay_ms, const base::Closure& callback, const base::Closure& task) { - base::Time last_time; - if (!events_.empty()) - last_time = (events_.end()-1)->time; - else - last_time = base::Time::NowFromSystemTime(); - - base::Time future = last_time + base::TimeDelta::FromMilliseconds(delay_ms); - EventInjector::Event event = {future, callback, task}; - events_.push_back(event); - } - - static gboolean Prepare(GSource* source, gint* timeout_ms) { - *timeout_ms = static_cast<Source*>(source)->injector->HandlePrepare(); - return FALSE; - } - - static gboolean Check(GSource* source) { - return static_cast<Source*>(source)->injector->HandleCheck(); - } - - static gboolean Dispatch(GSource* source, - GSourceFunc unused_func, - gpointer unused_data) { - static_cast<Source*>(source)->injector->HandleDispatch(); - return TRUE; - } - - Source* source_; - std::vector<Event> events_; - int processed_events_; - static GSourceFuncs SourceFuncs; - DISALLOW_COPY_AND_ASSIGN(EventInjector); -}; - -GSourceFuncs EventInjector::SourceFuncs = { - EventInjector::Prepare, - EventInjector::Check, - EventInjector::Dispatch, - NULL -}; - -void IncrementInt(int *value) { - ++*value; -} - -// Checks how many events have been processed by the injector. -void ExpectProcessedEvents(EventInjector* injector, int count) { - EXPECT_EQ(injector->processed_events(), count); -} - -// Posts a task on the current message loop. -void PostMessageLoopTask(const tracked_objects::Location& from_here, - const base::Closure& task) { - MessageLoop::current()->PostTask(from_here, task); -} - -// Test fixture. -class MessagePumpGLibTest : public testing::Test { - public: - MessagePumpGLibTest() : loop_(NULL), injector_(NULL) { } - - // Overridden from testing::Test: - virtual void SetUp() OVERRIDE { - loop_ = new MessageLoop(MessageLoop::TYPE_UI); - injector_ = new EventInjector(); - } - virtual void TearDown() OVERRIDE { - delete injector_; - injector_ = NULL; - delete loop_; - loop_ = NULL; - } - - MessageLoop* loop() const { return loop_; } - EventInjector* injector() const { return injector_; } - - private: - MessageLoop* loop_; - EventInjector* injector_; - DISALLOW_COPY_AND_ASSIGN(MessagePumpGLibTest); -}; - -} // namespace - -TEST_F(MessagePumpGLibTest, TestQuit) { - // Checks that Quit works and that the basic infrastructure is working. - - // Quit from a task - RunLoop().RunUntilIdle(); - EXPECT_EQ(0, injector()->processed_events()); - - injector()->Reset(); - // Quit from an event - injector()->AddEvent(0, MessageLoop::QuitWhenIdleClosure()); - loop()->Run(); - EXPECT_EQ(1, injector()->processed_events()); -} - -TEST_F(MessagePumpGLibTest, TestEventTaskInterleave) { - // Checks that tasks posted by events are executed before the next event if - // the posted task queue is empty. - // MessageLoop doesn't make strong guarantees that it is the case, but the - // current implementation ensures it and the tests below rely on it. - // If changes cause this test to fail, it is reasonable to change it, but - // TestWorkWhileWaitingForEvents and TestEventsWhileWaitingForWork have to be - // changed accordingly, otherwise they can become flaky. - injector()->AddEventAsTask(0, base::Bind(&base::DoNothing)); - base::Closure check_task = - base::Bind(&ExpectProcessedEvents, base::Unretained(injector()), 2); - base::Closure posted_task = - base::Bind(&PostMessageLoopTask, FROM_HERE, check_task); - injector()->AddEventAsTask(0, posted_task); - injector()->AddEventAsTask(0, base::Bind(&base::DoNothing)); - injector()->AddEvent(0, MessageLoop::QuitWhenIdleClosure()); - loop()->Run(); - EXPECT_EQ(4, injector()->processed_events()); - - injector()->Reset(); - injector()->AddEventAsTask(0, base::Bind(&base::DoNothing)); - check_task = - base::Bind(&ExpectProcessedEvents, base::Unretained(injector()), 2); - posted_task = base::Bind(&PostMessageLoopTask, FROM_HERE, check_task); - injector()->AddEventAsTask(0, posted_task); - injector()->AddEventAsTask(10, base::Bind(&base::DoNothing)); - injector()->AddEvent(0, MessageLoop::QuitWhenIdleClosure()); - loop()->Run(); - EXPECT_EQ(4, injector()->processed_events()); -} - -TEST_F(MessagePumpGLibTest, TestWorkWhileWaitingForEvents) { - int task_count = 0; - // Tests that we process tasks while waiting for new events. - // The event queue is empty at first. - for (int i = 0; i < 10; ++i) { - loop()->PostTask(FROM_HERE, base::Bind(&IncrementInt, &task_count)); - } - // After all the previous tasks have executed, enqueue an event that will - // quit. - loop()->PostTask( - FROM_HERE, - base::Bind(&EventInjector::AddEvent, base::Unretained(injector()), 0, - MessageLoop::QuitWhenIdleClosure())); - loop()->Run(); - ASSERT_EQ(10, task_count); - EXPECT_EQ(1, injector()->processed_events()); - - // Tests that we process delayed tasks while waiting for new events. - injector()->Reset(); - task_count = 0; - for (int i = 0; i < 10; ++i) { - loop()->PostDelayedTask( - FROM_HERE, - base::Bind(&IncrementInt, &task_count), - base::TimeDelta::FromMilliseconds(10*i)); - } - // After all the previous tasks have executed, enqueue an event that will - // quit. - // This relies on the fact that delayed tasks are executed in delay order. - // That is verified in message_loop_unittest.cc. - loop()->PostDelayedTask( - FROM_HERE, - base::Bind(&EventInjector::AddEvent, base::Unretained(injector()), 10, - MessageLoop::QuitWhenIdleClosure()), - base::TimeDelta::FromMilliseconds(150)); - loop()->Run(); - ASSERT_EQ(10, task_count); - EXPECT_EQ(1, injector()->processed_events()); -} - -TEST_F(MessagePumpGLibTest, TestEventsWhileWaitingForWork) { - // Tests that we process events while waiting for work. - // The event queue is empty at first. - for (int i = 0; i < 10; ++i) { - injector()->AddDummyEvent(0); - } - // After all the events have been processed, post a task that will check that - // the events have been processed (note: the task executes after the event - // that posted it has been handled, so we expect 11 at that point). - base::Closure check_task = - base::Bind(&ExpectProcessedEvents, base::Unretained(injector()), 11); - base::Closure posted_task = - base::Bind(&PostMessageLoopTask, FROM_HERE, check_task); - injector()->AddEventAsTask(10, posted_task); - - // And then quit (relies on the condition tested by TestEventTaskInterleave). - injector()->AddEvent(10, MessageLoop::QuitWhenIdleClosure()); - loop()->Run(); - - EXPECT_EQ(12, injector()->processed_events()); -} - -namespace { - -// This class is a helper for the concurrent events / posted tasks test below. -// It will quit the main loop once enough tasks and events have been processed, -// while making sure there is always work to do and events in the queue. -class ConcurrentHelper : public base::RefCounted<ConcurrentHelper> { - public: - explicit ConcurrentHelper(EventInjector* injector) - : injector_(injector), - event_count_(kStartingEventCount), - task_count_(kStartingTaskCount) { - } - - void FromTask() { - if (task_count_ > 0) { - --task_count_; - } - if (task_count_ == 0 && event_count_ == 0) { - MessageLoop::current()->QuitWhenIdle(); - } else { - MessageLoop::current()->PostTask( - FROM_HERE, base::Bind(&ConcurrentHelper::FromTask, this)); - } - } - - void FromEvent() { - if (event_count_ > 0) { - --event_count_; - } - if (task_count_ == 0 && event_count_ == 0) { - MessageLoop::current()->QuitWhenIdle(); - } else { - injector_->AddEventAsTask( - 0, base::Bind(&ConcurrentHelper::FromEvent, this)); - } - } - - int event_count() const { return event_count_; } - int task_count() const { return task_count_; } - - private: - friend class base::RefCounted<ConcurrentHelper>; - - ~ConcurrentHelper() {} - - static const int kStartingEventCount = 20; - static const int kStartingTaskCount = 20; - - EventInjector* injector_; - int event_count_; - int task_count_; -}; - -} // namespace - -TEST_F(MessagePumpGLibTest, TestConcurrentEventPostedTask) { - // Tests that posted tasks don't starve events, nor the opposite. - // We use the helper class above. We keep both event and posted task queues - // full, the helper verifies that both tasks and events get processed. - // If that is not the case, either event_count_ or task_count_ will not get - // to 0, and MessageLoop::QuitWhenIdle() will never be called. - scoped_refptr<ConcurrentHelper> helper = new ConcurrentHelper(injector()); - - // Add 2 events to the queue to make sure it is always full (when we remove - // the event before processing it). - injector()->AddEventAsTask( - 0, base::Bind(&ConcurrentHelper::FromEvent, helper.get())); - injector()->AddEventAsTask( - 0, base::Bind(&ConcurrentHelper::FromEvent, helper.get())); - - // Similarly post 2 tasks. - loop()->PostTask( - FROM_HERE, base::Bind(&ConcurrentHelper::FromTask, helper.get())); - loop()->PostTask( - FROM_HERE, base::Bind(&ConcurrentHelper::FromTask, helper.get())); - - loop()->Run(); - EXPECT_EQ(0, helper->event_count()); - EXPECT_EQ(0, helper->task_count()); -} - -namespace { - -void AddEventsAndDrainGLib(EventInjector* injector) { - // Add a couple of dummy events - injector->AddDummyEvent(0); - injector->AddDummyEvent(0); - // Then add an event that will quit the main loop. - injector->AddEvent(0, MessageLoop::QuitWhenIdleClosure()); - - // Post a couple of dummy tasks - MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&base::DoNothing)); - MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&base::DoNothing)); - - // Drain the events - while (g_main_context_pending(NULL)) { - g_main_context_iteration(NULL, FALSE); - } -} - -} // namespace - -TEST_F(MessagePumpGLibTest, TestDrainingGLib) { - // Tests that draining events using GLib works. - loop()->PostTask( - FROM_HERE, - base::Bind(&AddEventsAndDrainGLib, base::Unretained(injector()))); - loop()->Run(); - - EXPECT_EQ(3, injector()->processed_events()); -} - - -namespace { - -#if defined(TOOLKIT_GTK) -void AddEventsAndDrainGtk(EventInjector* injector) { - // Add a couple of dummy events - injector->AddDummyEvent(0); - injector->AddDummyEvent(0); - // Then add an event that will quit the main loop. - injector->AddEvent(0, MessageLoop::QuitWhenIdleClosure()); - - // Post a couple of dummy tasks - MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&base::DoNothing)); - MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&base::DoNothing)); - - // Drain the events - while (gtk_events_pending()) { - gtk_main_iteration(); - } -} -#endif - -} // namespace - -#if defined(TOOLKIT_GTK) -TEST_F(MessagePumpGLibTest, TestDrainingGtk) { - // Tests that draining events using Gtk works. - loop()->PostTask( - FROM_HERE, - base::Bind(&AddEventsAndDrainGtk, base::Unretained(injector()))); - loop()->Run(); - - EXPECT_EQ(3, injector()->processed_events()); -} -#endif - -namespace { - -// Helper class that lets us run the GLib message loop. -class GLibLoopRunner : public base::RefCounted<GLibLoopRunner> { - public: - GLibLoopRunner() : quit_(false) { } - - void RunGLib() { - while (!quit_) { - g_main_context_iteration(NULL, TRUE); - } - } - - void RunLoop() { -#if defined(TOOLKIT_GTK) - while (!quit_) { - gtk_main_iteration(); - } -#else - while (!quit_) { - g_main_context_iteration(NULL, TRUE); - } -#endif - } - - void Quit() { - quit_ = true; - } - - void Reset() { - quit_ = false; - } - - private: - friend class base::RefCounted<GLibLoopRunner>; - - ~GLibLoopRunner() {} - - bool quit_; -}; - -void TestGLibLoopInternal(EventInjector* injector) { - // Allow tasks to be processed from 'native' event loops. - MessageLoop::current()->SetNestableTasksAllowed(true); - scoped_refptr<GLibLoopRunner> runner = new GLibLoopRunner(); - - int task_count = 0; - // Add a couple of dummy events - injector->AddDummyEvent(0); - injector->AddDummyEvent(0); - // Post a couple of dummy tasks - MessageLoop::current()->PostTask( - FROM_HERE, base::Bind(&IncrementInt, &task_count)); - MessageLoop::current()->PostTask( - FROM_HERE, base::Bind(&IncrementInt, &task_count)); - // Delayed events - injector->AddDummyEvent(10); - injector->AddDummyEvent(10); - // Delayed work - MessageLoop::current()->PostDelayedTask( - FROM_HERE, - base::Bind(&IncrementInt, &task_count), - base::TimeDelta::FromMilliseconds(30)); - MessageLoop::current()->PostDelayedTask( - FROM_HERE, - base::Bind(&GLibLoopRunner::Quit, runner.get()), - base::TimeDelta::FromMilliseconds(40)); - - // Run a nested, straight GLib message loop. - runner->RunGLib(); - - ASSERT_EQ(3, task_count); - EXPECT_EQ(4, injector->processed_events()); - MessageLoop::current()->QuitWhenIdle(); -} - -void TestGtkLoopInternal(EventInjector* injector) { - // Allow tasks to be processed from 'native' event loops. - MessageLoop::current()->SetNestableTasksAllowed(true); - scoped_refptr<GLibLoopRunner> runner = new GLibLoopRunner(); - - int task_count = 0; - // Add a couple of dummy events - injector->AddDummyEvent(0); - injector->AddDummyEvent(0); - // Post a couple of dummy tasks - MessageLoop::current()->PostTask( - FROM_HERE, base::Bind(&IncrementInt, &task_count)); - MessageLoop::current()->PostTask( - FROM_HERE, base::Bind(&IncrementInt, &task_count)); - // Delayed events - injector->AddDummyEvent(10); - injector->AddDummyEvent(10); - // Delayed work - MessageLoop::current()->PostDelayedTask( - FROM_HERE, - base::Bind(&IncrementInt, &task_count), - base::TimeDelta::FromMilliseconds(30)); - MessageLoop::current()->PostDelayedTask( - FROM_HERE, - base::Bind(&GLibLoopRunner::Quit, runner.get()), - base::TimeDelta::FromMilliseconds(40)); - - // Run a nested, straight Gtk message loop. - runner->RunLoop(); - - ASSERT_EQ(3, task_count); - EXPECT_EQ(4, injector->processed_events()); - MessageLoop::current()->QuitWhenIdle(); -} - -} // namespace - -TEST_F(MessagePumpGLibTest, TestGLibLoop) { - // Tests that events and posted tasks are correctly executed if the message - // loop is not run by MessageLoop::Run() but by a straight GLib loop. - // Note that in this case we don't make strong guarantees about niceness - // between events and posted tasks. - loop()->PostTask( - FROM_HERE, - base::Bind(&TestGLibLoopInternal, base::Unretained(injector()))); - loop()->Run(); -} - -TEST_F(MessagePumpGLibTest, TestGtkLoop) { - // Tests that events and posted tasks are correctly executed if the message - // loop is not run by MessageLoop::Run() but by a straight Gtk loop. - // Note that in this case we don't make strong guarantees about niceness - // between events and posted tasks. - loop()->PostTask( - FROM_HERE, - base::Bind(&TestGtkLoopInternal, base::Unretained(injector()))); - loop()->Run(); -} - -} // namespace base |