Chromium Code Reviews| Index: base/task_unittest.cc |
| diff --git a/base/task_unittest.cc b/base/task_unittest.cc |
| index e0cb659cf094c01db34730189989efef07a243d2..26397d3632fd6d00c9bd03f1998a01723c110ab6 100644 |
| --- a/base/task_unittest.cc |
| +++ b/base/task_unittest.cc |
| @@ -2,8 +2,12 @@ |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| -#include "base/memory/ref_counted.h" |
| #include "base/task.h" |
| + |
| +#include "base/bind.h" |
| +#include "base/memory/ref_counted.h" |
| +#include "base/message_loop.h" |
| +#include "base/threading/thread.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| namespace { |
| @@ -107,4 +111,168 @@ TEST(TaskTest, TestScopedTaskRunnerManualRun) { |
| EXPECT_TRUE(was_deleted); |
| } |
| +class LoopRecorder : public base::RefCountedThreadSafe<LoopRecorder> { |
|
willchan no longer on Chromium
2011/08/17 04:36:07
I'm not sure why you make this RefCountedThreadSaf
awong
2011/08/17 05:16:00
I figured that in the case that someone introduced
|
| + public: |
| + LoopRecorder(MessageLoop** run_on, MessageLoop** deleted_on) |
| + : run_on_(run_on), |
| + deleted_on_(deleted_on) { |
| + } |
| + |
| + void RecordRun() { |
| + *run_on_ = MessageLoop::current(); |
| + } |
| + |
| + private: |
| + friend class base::RefCountedThreadSafe<LoopRecorder>; |
| + ~LoopRecorder() { |
| + *deleted_on_ = MessageLoop::current(); |
| + } |
| + |
| + MessageLoop** run_on_; |
| + MessageLoop** deleted_on_; |
| +}; |
| + |
| +void RecordLoop(scoped_refptr<LoopRecorder> recorder) { |
| + recorder->RecordRun(); |
| +} |
| + |
| +void RecordLoopAndQuit(scoped_refptr<LoopRecorder> recorder) { |
| + recorder->RecordRun(); |
| + MessageLoop::current()->Quit(); |
| +} |
| + |
| +TEST(TaskTest, TestPostTaskAndReplyRelay_Basic) { |
| + using base::internal::PostTaskAndReplyRelay; |
| + |
| + MessageLoop current_loop; |
| + |
| + MessageLoop* task_run_on = NULL; |
| + MessageLoop* task_deleted_on = NULL; |
| + MessageLoop* reply_run_on = NULL; |
| + MessageLoop* reply_deleted_on = NULL; |
| + |
| + scoped_refptr<LoopRecorder> task_recoder = |
|
willchan no longer on Chromium
2011/08/17 04:36:07
s/task_recoder/task_recorder/?
awong
2011/08/17 05:16:00
Will fix tomorrow.
|
| + new LoopRecorder(&task_run_on, &task_deleted_on); |
| + scoped_refptr<LoopRecorder> reply_recoder = |
| + new LoopRecorder(&reply_run_on, &reply_deleted_on); |
| + |
| + PostTaskAndReplyRelay* relay = |
| + new PostTaskAndReplyRelay( |
| + FROM_HERE, |
| + base::Bind(&RecordLoop, task_recoder), |
| + base::Bind(&RecordLoopAndQuit, reply_recoder)); |
| + |
| + // Die if base::Bind doesn't retain a reference to the recorders. |
| + task_recoder = NULL; |
| + reply_recoder = NULL; |
| + ASSERT_FALSE(task_deleted_on); |
| + ASSERT_FALSE(reply_deleted_on); |
| + |
| + // Run the relay. |
| + base::Thread task_thread("task_thread"); |
| + task_thread.Start(); |
| + task_thread.message_loop()->PostTask( |
| + FROM_HERE, |
| + base::Bind(&PostTaskAndReplyRelay::Run, base::Unretained(relay))); |
| + |
| + current_loop.Run(); |
| + |
| + EXPECT_EQ(task_thread.message_loop(), task_run_on); |
| + EXPECT_EQ(¤t_loop, task_deleted_on); |
| + EXPECT_EQ(¤t_loop, reply_run_on); |
| + EXPECT_EQ(¤t_loop, reply_deleted_on); |
| +} |
| + |
| +TEST(TaskTest, TestPostTaskAndReplyRelay_SameLoop) { |
| + using base::internal::PostTaskAndReplyRelay; |
| + |
| + MessageLoop current_loop; |
| + |
| + MessageLoop* task_run_on = NULL; |
| + MessageLoop* task_deleted_on = NULL; |
| + MessageLoop* reply_run_on = NULL; |
| + MessageLoop* reply_deleted_on = NULL; |
| + |
| + scoped_refptr<LoopRecorder> task_recoder = |
| + new LoopRecorder(&task_run_on, &task_deleted_on); |
| + scoped_refptr<LoopRecorder> reply_recoder = |
| + new LoopRecorder(&reply_run_on, &reply_deleted_on); |
| + |
| + PostTaskAndReplyRelay* relay = |
| + new PostTaskAndReplyRelay( |
| + FROM_HERE, |
| + base::Bind(&RecordLoop, task_recoder), |
| + base::Bind(&RecordLoopAndQuit, reply_recoder)); |
| + |
| + // Die if base::Bind doesn't retain a reference to the recorders. |
| + task_recoder = NULL; |
| + reply_recoder = NULL; |
| + ASSERT_FALSE(task_deleted_on); |
| + ASSERT_FALSE(reply_deleted_on); |
| + |
| + // Run the relay. |
| + current_loop.PostTask( |
| + FROM_HERE, |
| + base::Bind(&PostTaskAndReplyRelay::Run, base::Unretained(relay))); |
| + |
| + current_loop.Run(); |
| + |
| + EXPECT_EQ(¤t_loop, task_run_on); |
| + EXPECT_EQ(¤t_loop, task_deleted_on); |
| + EXPECT_EQ(¤t_loop, reply_run_on); |
| + EXPECT_EQ(¤t_loop, reply_deleted_on); |
| +} |
| + |
| +TEST(TaskTest, TestPostTaskAndReplyRelay_DeadReplyLoopDoesNotDelete) { |
| + using base::internal::PostTaskAndReplyRelay; |
| + |
| + scoped_ptr<MessageLoop> current_loop(new MessageLoop()); |
| + |
| + MessageLoop* task_run_on = NULL; |
| + MessageLoop* task_deleted_on = NULL; |
| + MessageLoop* reply_run_on = NULL; |
| + MessageLoop* reply_deleted_on = NULL; |
| + |
| + scoped_refptr<LoopRecorder> task_recoder = |
| + new LoopRecorder(&task_run_on, &task_deleted_on); |
| + scoped_refptr<LoopRecorder> reply_recoder = |
| + new LoopRecorder(&reply_run_on, &reply_deleted_on); |
| + |
| + PostTaskAndReplyRelay* relay = |
| + new PostTaskAndReplyRelay( |
| + FROM_HERE, |
| + base::Bind(&RecordLoop, task_recoder), |
| + base::Bind(&RecordLoopAndQuit, reply_recoder)); |
| + |
| + // Die if base::Bind doesn't retain a reference to the recorders. |
| + task_recoder = NULL; |
| + reply_recoder = NULL; |
| + ASSERT_FALSE(task_deleted_on); |
| + ASSERT_FALSE(reply_deleted_on); |
| + |
| + // Run the relay. |
| + base::Thread task_thread("task_thread"); |
| + task_thread.Start(); |
| + task_thread.message_loop()->PostTask( |
| + FROM_HERE, |
| + base::Bind(&PostTaskAndReplyRelay::Run, base::Unretained(relay))); |
| + |
| + // Mercilessly whack the current loop before |reply| gets to run. |
| + current_loop.reset(); |
| + |
| + // This should ensure the relay has been run. We need to record the |
| + // MessageLoop pointer before stopping the thread because Thread::Stop() will |
| + // NULL out its own pointer. |
| + MessageLoop* task_loop = task_thread.message_loop(); |
| + task_thread.Stop(); |
| + |
| + EXPECT_EQ(task_loop, task_run_on); |
| + ASSERT_FALSE(task_deleted_on); |
| + EXPECT_FALSE(reply_run_on); |
| + ASSERT_FALSE(reply_deleted_on); |
| + |
| + // Relay is leaked here. |
| + // TODO(ajwong): Is there a way to make Valgrind not hate us? |
|
willchan no longer on Chromium
2011/08/17 04:36:07
delete relay; :)
awong
2011/08/17 05:16:00
Tried that. Dies cause the Relay asserts that it i
|
| +} |
| + |
| } // namespace |