Commit 54ef8356 authored by gab's avatar gab Committed by Commit bot

Add FlushForTesting to base::Thread.

Grew tired of the post+wait pattern in many tests to flush a base::Thread.
Was going to need it again in https://codereview.chromium.org/2333023003/
and decided to add an API for everyone's sake instead :-).

Off the top of my head, will also be useful in
https://codereview.chromium.org/2299523003/

BUG=646443

Review-Url: https://codereview.chromium.org/2337253003
Cr-Commit-Position: refs/heads/master@{#419026}
parent 22ce2899
...@@ -144,6 +144,18 @@ bool Thread::WaitUntilThreadStarted() const { ...@@ -144,6 +144,18 @@ bool Thread::WaitUntilThreadStarted() const {
return true; return true;
} }
void Thread::FlushForTesting() {
DCHECK(owning_sequence_checker_.CalledOnValidSequence());
if (!message_loop_)
return;
WaitableEvent done(WaitableEvent::ResetPolicy::AUTOMATIC,
WaitableEvent::InitialState::NOT_SIGNALED);
task_runner()->PostTask(FROM_HERE,
Bind(&WaitableEvent::Signal, Unretained(&done)));
done.Wait();
}
void Thread::Stop() { void Thread::Stop() {
DCHECK(joinable_); DCHECK(joinable_);
......
...@@ -140,6 +140,9 @@ class BASE_EXPORT Thread : PlatformThread::Delegate { ...@@ -140,6 +140,9 @@ class BASE_EXPORT Thread : PlatformThread::Delegate {
// carefully for production code. // carefully for production code.
bool WaitUntilThreadStarted() const; bool WaitUntilThreadStarted() const;
// Blocks until all tasks previously posted to this thread have been executed.
void FlushForTesting();
// Signals the thread to exit and returns once the thread has exited. The // Signals the thread to exit and returns once the thread has exited. The
// Thread object is completely reset and may be used as if it were newly // Thread object is completely reset and may be used as if it were newly
// constructed (i.e., Start may be called again). Can only be called if // constructed (i.e., Start may be called again). Can only be called if
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "base/test/gtest_util.h" #include "base/test/gtest_util.h"
#include "base/third_party/dynamic_annotations/dynamic_annotations.h" #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
#include "base/threading/platform_thread.h" #include "base/threading/platform_thread.h"
#include "base/time/time.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h" #include "testing/platform_test.h"
...@@ -436,6 +437,39 @@ TEST_F(ThreadTest, MultipleWaitUntilThreadStarted) { ...@@ -436,6 +437,39 @@ TEST_F(ThreadTest, MultipleWaitUntilThreadStarted) {
EXPECT_TRUE(a.WaitUntilThreadStarted()); EXPECT_TRUE(a.WaitUntilThreadStarted());
} }
TEST_F(ThreadTest, FlushForTesting) {
Thread a("FlushForTesting");
// Flushing a non-running thread should be a no-op.
a.FlushForTesting();
ASSERT_TRUE(a.Start());
// Flushing a thread with no tasks shouldn't block.
a.FlushForTesting();
constexpr base::TimeDelta kSleepPerTestTask =
base::TimeDelta::FromMilliseconds(50);
constexpr size_t kNumSleepTasks = 5;
const base::TimeTicks ticks_before_post = base::TimeTicks::Now();
for (size_t i = 0; i < kNumSleepTasks; ++i) {
a.task_runner()->PostTask(
FROM_HERE, base::Bind(&base::PlatformThread::Sleep, kSleepPerTestTask));
}
// All tasks should have executed, as reflected by the elapsed time.
a.FlushForTesting();
EXPECT_GE(base::TimeTicks::Now() - ticks_before_post,
kNumSleepTasks * kSleepPerTestTask);
a.Stop();
// Flushing a stopped thread should be a no-op.
a.FlushForTesting();
}
namespace { namespace {
// A Thread which uses a MessageLoop on the stack. It won't start a real // A Thread which uses a MessageLoop on the stack. It won't start a real
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment