Index: base/sequence_checker_unittest.cc |
diff --git a/base/sequence_checker_unittest.cc b/base/sequence_checker_unittest.cc |
index 196bb1cc7972309ddba5c85ba42d074ddb3138c3..0d4a0c20c7953b92edb71cbfae7d4409263fae17 100644 |
--- a/base/sequence_checker_unittest.cc |
+++ b/base/sequence_checker_unittest.cc |
@@ -2,334 +2,271 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
-#include "base/sequence_checker.h" |
- |
#include <stddef.h> |
#include <memory> |
-#include <utility> |
+#include <string> |
#include "base/bind.h" |
#include "base/bind_helpers.h" |
-#include "base/location.h" |
-#include "base/logging.h" |
+#include "base/callback_forward.h" |
#include "base/macros.h" |
-#include "base/memory/ref_counted.h" |
+#include "base/message_loop/message_loop.h" |
+#include "base/sequence_checker_impl.h" |
+#include "base/sequence_token.h" |
#include "base/single_thread_task_runner.h" |
#include "base/test/sequenced_worker_pool_owner.h" |
-#include "base/threading/thread.h" |
+#include "base/threading/simple_thread.h" |
#include "testing/gtest/include/gtest/gtest.h" |
-// Duplicated from base/sequence_checker.h so that we can be good citizens |
-// there and undef the macro. |
-#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) |
-#define ENABLE_SEQUENCE_CHECKER 1 |
-#else |
-#define ENABLE_SEQUENCE_CHECKER 0 |
-#endif |
- |
namespace base { |
namespace { |
-const size_t kNumWorkerThreads = 3; |
+constexpr size_t kNumWorkerThreads = 3; |
-// Simple class to exercise the basics of SequenceChecker. |
-// DoStuff should verify that it's called on a valid sequenced thread. |
-// SequenceCheckedObject can be destroyed on any thread (like WeakPtr). |
-class SequenceCheckedObject { |
+// Runs a callback on another thread. |
+class RunCallbackThread : public SimpleThread { |
public: |
- SequenceCheckedObject() {} |
- ~SequenceCheckedObject() {} |
- |
- // Verifies that it was called on the same thread as the constructor. |
- void DoStuff() { |
- DCHECK(sequence_checker_.CalledOnValidSequencedThread()); |
- } |
- |
- void DetachFromSequence() { |
- sequence_checker_.DetachFromSequence(); |
+ explicit RunCallbackThread(const Closure& callback) |
+ : SimpleThread("RunCallbackThread"), callback_(callback) { |
+ Start(); |
+ Join(); |
} |
private: |
- SequenceChecker sequence_checker_; |
+ // SimpleThread: |
+ void Run() override { callback_.Run(); } |
+ |
+ const Closure callback_; |
- DISALLOW_COPY_AND_ASSIGN(SequenceCheckedObject); |
+ DISALLOW_COPY_AND_ASSIGN(RunCallbackThread); |
}; |
class SequenceCheckerTest : public testing::Test { |
- public: |
- SequenceCheckerTest() : other_thread_("sequence_checker_test_other_thread") {} |
- |
- void SetUp() override { |
- other_thread_.Start(); |
- ResetPool(); |
- } |
- |
- void TearDown() override { |
- other_thread_.Stop(); |
- } |
- |
protected: |
- base::Thread* other_thread() { return &other_thread_; } |
+ SequenceCheckerTest() : pool_owner_(kNumWorkerThreads, "test") {} |
- const scoped_refptr<SequencedWorkerPool>& pool() { |
- return pool_owner_->pool(); |
+ void PostToSequencedWorkerPool(const Closure& callback, |
+ const std::string& token_name) { |
+ pool_owner_.pool()->PostNamedSequencedWorkerTask(token_name, FROM_HERE, |
+ callback); |
} |
- void PostDoStuffToWorkerPool(SequenceCheckedObject* sequence_checked_object, |
- const std::string& token_name) { |
- pool()->PostNamedSequencedWorkerTask( |
- token_name, |
- FROM_HERE, |
- base::Bind(&SequenceCheckedObject::DoStuff, |
- base::Unretained(sequence_checked_object))); |
+ void FlushSequencedWorkerPoolForTesting() { |
+ pool_owner_.pool()->FlushForTesting(); |
} |
- void PostDoStuffToOtherThread( |
- SequenceCheckedObject* sequence_checked_object) { |
- other_thread()->task_runner()->PostTask( |
- FROM_HERE, base::Bind(&SequenceCheckedObject::DoStuff, |
- base::Unretained(sequence_checked_object))); |
- } |
- |
- void PostDeleteToOtherThread( |
- std::unique_ptr<SequenceCheckedObject> sequence_checked_object) { |
- other_thread()->message_loop()->task_runner()->DeleteSoon( |
- FROM_HERE, sequence_checked_object.release()); |
- } |
- |
- // Destroys the SequencedWorkerPool instance, blocking until it is fully shut |
- // down, and creates a new instance. |
- void ResetPool() { |
- pool_owner_.reset(new SequencedWorkerPoolOwner(kNumWorkerThreads, "test")); |
- } |
- |
- void MethodOnDifferentThreadDeathTest(); |
- void DetachThenCallFromDifferentThreadDeathTest(); |
- void DifferentSequenceTokensDeathTest(); |
- void WorkerPoolAndSimpleThreadDeathTest(); |
- void TwoDifferentWorkerPoolsDeathTest(); |
- |
private: |
MessageLoop message_loop_; // Needed by SequencedWorkerPool to function. |
- base::Thread other_thread_; |
- std::unique_ptr<SequencedWorkerPoolOwner> pool_owner_; |
+ SequencedWorkerPoolOwner pool_owner_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(SequenceCheckerTest); |
}; |
-TEST_F(SequenceCheckerTest, CallsAllowedOnSameThread) { |
- std::unique_ptr<SequenceCheckedObject> sequence_checked_object( |
- new SequenceCheckedObject); |
+void ExpectCalledOnValidSequencedThread(SequenceCheckerImpl* sequence_checker) { |
+ ASSERT_TRUE(sequence_checker); |
- // Verify that DoStuff doesn't assert. |
- sequence_checked_object->DoStuff(); |
+ // This should bind |sequence_checker| to the current sequence if it wasn't |
+ // already bound to a sequence. |
+ EXPECT_TRUE(sequence_checker->CalledOnValidSequencedThread()); |
- // Verify that the destructor doesn't assert. |
- sequence_checked_object.reset(); |
+ // Since |sequence_checker| is now bound to the current sequence, another call |
+ // to CalledOnValidSequencedThread() should return true. |
+ EXPECT_TRUE(sequence_checker->CalledOnValidSequencedThread()); |
} |
-TEST_F(SequenceCheckerTest, DestructorAllowedOnDifferentThread) { |
- std::unique_ptr<SequenceCheckedObject> sequence_checked_object( |
- new SequenceCheckedObject); |
- |
- // Verify the destructor doesn't assert when called on a different thread. |
- PostDeleteToOtherThread(std::move(sequence_checked_object)); |
- other_thread()->Stop(); |
+void ExpectCalledOnValidSequencedThreadWithSequenceToken( |
+ SequenceCheckerImpl* sequence_checker, |
+ SequenceToken sequence_token) { |
+ ScopedSetSequenceTokenForCurrentThread |
+ scoped_set_sequence_token_for_current_thread(sequence_token); |
+ ExpectCalledOnValidSequencedThread(sequence_checker); |
} |
-TEST_F(SequenceCheckerTest, DetachFromSequence) { |
- std::unique_ptr<SequenceCheckedObject> sequence_checked_object( |
- new SequenceCheckedObject); |
- |
- // Verify that DoStuff doesn't assert when called on a different thread after |
- // a call to DetachFromSequence. |
- sequence_checked_object->DetachFromSequence(); |
- |
- PostDoStuffToOtherThread(sequence_checked_object.get()); |
- other_thread()->Stop(); |
+void ExpectNotCalledOnValidSequencedThread( |
+ SequenceCheckerImpl* sequence_checker) { |
+ ASSERT_TRUE(sequence_checker); |
+ EXPECT_FALSE(sequence_checker->CalledOnValidSequencedThread()); |
} |
-TEST_F(SequenceCheckerTest, SameSequenceTokenValid) { |
- std::unique_ptr<SequenceCheckedObject> sequence_checked_object( |
- new SequenceCheckedObject); |
+} // namespace |
- sequence_checked_object->DetachFromSequence(); |
- PostDoStuffToWorkerPool(sequence_checked_object.get(), "A"); |
- PostDoStuffToWorkerPool(sequence_checked_object.get(), "A"); |
- PostDoStuffToWorkerPool(sequence_checked_object.get(), "A"); |
- PostDoStuffToWorkerPool(sequence_checked_object.get(), "A"); |
- pool()->FlushForTesting(); |
+TEST_F(SequenceCheckerTest, CallsAllowedOnSameThreadNoSequenceToken) { |
+ SequenceCheckerImpl sequence_checker; |
+ EXPECT_TRUE(sequence_checker.CalledOnValidSequencedThread()); |
+} |
- PostDeleteToOtherThread(std::move(sequence_checked_object)); |
- other_thread()->Stop(); |
+TEST_F(SequenceCheckerTest, CallsAllowedOnSameThreadSameSequenceToken) { |
+ ScopedSetSequenceTokenForCurrentThread |
+ scoped_set_sequence_token_for_current_thread(SequenceToken::Create()); |
+ SequenceCheckerImpl sequence_checker; |
+ EXPECT_TRUE(sequence_checker.CalledOnValidSequencedThread()); |
} |
-TEST_F(SequenceCheckerTest, DetachSequenceTokenValid) { |
- std::unique_ptr<SequenceCheckedObject> sequence_checked_object( |
- new SequenceCheckedObject); |
+TEST_F(SequenceCheckerTest, CallsDisallowedOnDifferentThreadsNoSequenceToken) { |
+ SequenceCheckerImpl sequence_checker; |
+ RunCallbackThread thread(Bind(&ExpectNotCalledOnValidSequencedThread, |
+ Unretained(&sequence_checker))); |
+} |
- sequence_checked_object->DetachFromSequence(); |
- PostDoStuffToWorkerPool(sequence_checked_object.get(), "A"); |
- PostDoStuffToWorkerPool(sequence_checked_object.get(), "A"); |
- pool()->FlushForTesting(); |
+TEST_F(SequenceCheckerTest, CallsAllowedOnDifferentThreadsSameSequenceToken) { |
+ const SequenceToken sequence_token(SequenceToken::Create()); |
- sequence_checked_object->DetachFromSequence(); |
- PostDoStuffToWorkerPool(sequence_checked_object.get(), "B"); |
- PostDoStuffToWorkerPool(sequence_checked_object.get(), "B"); |
- pool()->FlushForTesting(); |
+ ScopedSetSequenceTokenForCurrentThread |
+ scoped_set_sequence_token_for_current_thread(sequence_token); |
+ SequenceCheckerImpl sequence_checker; |
+ EXPECT_TRUE(sequence_checker.CalledOnValidSequencedThread()); |
- PostDeleteToOtherThread(std::move(sequence_checked_object)); |
- other_thread()->Stop(); |
+ RunCallbackThread thread( |
+ Bind(&ExpectCalledOnValidSequencedThreadWithSequenceToken, |
+ Unretained(&sequence_checker), sequence_token)); |
} |
-#if GTEST_HAS_DEATH_TEST || !ENABLE_SEQUENCE_CHECKER |
+TEST_F(SequenceCheckerTest, CallsDisallowedOnSameThreadDifferentSequenceToken) { |
+ std::unique_ptr<SequenceCheckerImpl> sequence_checker; |
-void SequenceCheckerTest::MethodOnDifferentThreadDeathTest() { |
- std::unique_ptr<SequenceCheckedObject> sequence_checked_object( |
- new SequenceCheckedObject); |
+ { |
+ ScopedSetSequenceTokenForCurrentThread |
+ scoped_set_sequence_token_for_current_thread(SequenceToken::Create()); |
+ sequence_checker.reset(new SequenceCheckerImpl); |
+ } |
- // DoStuff should assert in debug builds only when called on a |
- // different thread. |
- PostDoStuffToOtherThread(sequence_checked_object.get()); |
- other_thread()->Stop(); |
-} |
+ { |
+ // Different SequenceToken. |
+ ScopedSetSequenceTokenForCurrentThread |
+ scoped_set_sequence_token_for_current_thread(SequenceToken::Create()); |
+ EXPECT_FALSE(sequence_checker->CalledOnValidSequencedThread()); |
+ } |
-#if ENABLE_SEQUENCE_CHECKER |
-TEST_F(SequenceCheckerTest, MethodNotAllowedOnDifferentThreadDeathTestInDebug) { |
- // The default style "fast" does not support multi-threaded tests. |
- ::testing::FLAGS_gtest_death_test_style = "threadsafe"; |
- ASSERT_DEATH({ |
- MethodOnDifferentThreadDeathTest(); |
- }, ""); |
+ // No SequenceToken. |
+ EXPECT_FALSE(sequence_checker->CalledOnValidSequencedThread()); |
} |
-#else |
-TEST_F(SequenceCheckerTest, MethodAllowedOnDifferentThreadDeathTestInRelease) { |
- MethodOnDifferentThreadDeathTest(); |
-} |
-#endif // ENABLE_SEQUENCE_CHECKER |
-void SequenceCheckerTest::DetachThenCallFromDifferentThreadDeathTest() { |
- std::unique_ptr<SequenceCheckedObject> sequence_checked_object( |
- new SequenceCheckedObject); |
+TEST_F(SequenceCheckerTest, DetachFromSequence) { |
+ std::unique_ptr<SequenceCheckerImpl> sequence_checker; |
- // DoStuff doesn't assert when called on a different thread |
- // after a call to DetachFromSequence. |
- sequence_checked_object->DetachFromSequence(); |
- PostDoStuffToOtherThread(sequence_checked_object.get()); |
- other_thread()->Stop(); |
+ { |
+ ScopedSetSequenceTokenForCurrentThread |
+ scoped_set_sequence_token_for_current_thread(SequenceToken::Create()); |
+ sequence_checker.reset(new SequenceCheckerImpl); |
+ } |
- // DoStuff should assert in debug builds only after moving to |
- // another thread. |
- sequence_checked_object->DoStuff(); |
-} |
+ sequence_checker->DetachFromSequence(); |
-#if ENABLE_SEQUENCE_CHECKER |
-TEST_F(SequenceCheckerTest, DetachFromSequenceDeathTestInDebug) { |
- // The default style "fast" does not support multi-threaded tests. |
- ::testing::FLAGS_gtest_death_test_style = "threadsafe"; |
- ASSERT_DEATH({ |
- DetachThenCallFromDifferentThreadDeathTest(); |
- }, ""); |
-} |
-#else |
-TEST_F(SequenceCheckerTest, DetachFromThreadDeathTestInRelease) { |
- DetachThenCallFromDifferentThreadDeathTest(); |
+ { |
+ // Verify that CalledOnValidSequencedThread() returns true when called with |
+ // a different sequence token after a call to DetachFromSequence(). |
+ ScopedSetSequenceTokenForCurrentThread |
+ scoped_set_sequence_token_for_current_thread(SequenceToken::Create()); |
+ EXPECT_TRUE(sequence_checker->CalledOnValidSequencedThread()); |
+ } |
} |
-#endif // ENABLE_SEQUENCE_CHECKER |
-void SequenceCheckerTest::DifferentSequenceTokensDeathTest() { |
- std::unique_ptr<SequenceCheckedObject> sequence_checked_object( |
- new SequenceCheckedObject); |
+TEST_F(SequenceCheckerTest, DetachFromSequenceNoSequenceToken) { |
+ SequenceCheckerImpl sequence_checker; |
+ sequence_checker.DetachFromSequence(); |
- sequence_checked_object->DetachFromSequence(); |
- PostDoStuffToWorkerPool(sequence_checked_object.get(), "A"); |
- PostDoStuffToWorkerPool(sequence_checked_object.get(), "A"); |
- PostDoStuffToWorkerPool(sequence_checked_object.get(), "B"); |
- PostDoStuffToWorkerPool(sequence_checked_object.get(), "B"); |
- pool()->FlushForTesting(); |
+ // Verify that CalledOnValidSequencedThread() returns true when called on a |
+ // different thread after a call to DetachFromSequence(). |
+ RunCallbackThread thread( |
+ Bind(&ExpectCalledOnValidSequencedThread, Unretained(&sequence_checker))); |
- PostDeleteToOtherThread(std::move(sequence_checked_object)); |
- other_thread()->Stop(); |
+ EXPECT_FALSE(sequence_checker.CalledOnValidSequencedThread()); |
} |
-#if ENABLE_SEQUENCE_CHECKER |
-TEST_F(SequenceCheckerTest, DifferentSequenceTokensDeathTestInDebug) { |
- // The default style "fast" does not support multi-threaded tests. |
- ::testing::FLAGS_gtest_death_test_style = "threadsafe"; |
- ASSERT_DEATH({ |
- DifferentSequenceTokensDeathTest(); |
- }, ""); |
+TEST_F(SequenceCheckerTest, SequencedWorkerPool_SameSequenceTokenValid) { |
+ SequenceCheckerImpl sequence_checker; |
+ sequence_checker.DetachFromSequence(); |
+ |
+ PostToSequencedWorkerPool( |
+ Bind(&ExpectCalledOnValidSequencedThread, Unretained(&sequence_checker)), |
+ "A"); |
+ PostToSequencedWorkerPool( |
+ Bind(&ExpectCalledOnValidSequencedThread, Unretained(&sequence_checker)), |
+ "A"); |
+ FlushSequencedWorkerPoolForTesting(); |
} |
-#else |
-TEST_F(SequenceCheckerTest, DifferentSequenceTokensDeathTestInRelease) { |
- DifferentSequenceTokensDeathTest(); |
+ |
+TEST_F(SequenceCheckerTest, SequencedWorkerPool_DetachSequenceTokenValid) { |
+ SequenceCheckerImpl sequence_checker; |
+ sequence_checker.DetachFromSequence(); |
+ |
+ PostToSequencedWorkerPool( |
+ Bind(&ExpectCalledOnValidSequencedThread, Unretained(&sequence_checker)), |
+ "A"); |
+ PostToSequencedWorkerPool( |
+ Bind(&ExpectCalledOnValidSequencedThread, Unretained(&sequence_checker)), |
+ "A"); |
+ FlushSequencedWorkerPoolForTesting(); |
+ |
+ sequence_checker.DetachFromSequence(); |
+ |
+ PostToSequencedWorkerPool( |
+ Bind(&ExpectCalledOnValidSequencedThread, Unretained(&sequence_checker)), |
+ "B"); |
+ PostToSequencedWorkerPool( |
+ Bind(&ExpectCalledOnValidSequencedThread, Unretained(&sequence_checker)), |
+ "B"); |
+ FlushSequencedWorkerPoolForTesting(); |
} |
-#endif // ENABLE_SEQUENCE_CHECKER |
-void SequenceCheckerTest::WorkerPoolAndSimpleThreadDeathTest() { |
- std::unique_ptr<SequenceCheckedObject> sequence_checked_object( |
- new SequenceCheckedObject); |
+TEST_F(SequenceCheckerTest, |
+ SequencedWorkerPool_DifferentSequenceTokensInvalid) { |
+ SequenceCheckerImpl sequence_checker; |
+ sequence_checker.DetachFromSequence(); |
+ |
+ PostToSequencedWorkerPool( |
+ Bind(&ExpectCalledOnValidSequencedThread, Unretained(&sequence_checker)), |
+ "A"); |
+ PostToSequencedWorkerPool( |
+ Bind(&ExpectCalledOnValidSequencedThread, Unretained(&sequence_checker)), |
+ "A"); |
+ FlushSequencedWorkerPoolForTesting(); |
+ |
+ PostToSequencedWorkerPool(Bind(&ExpectNotCalledOnValidSequencedThread, |
+ Unretained(&sequence_checker)), |
+ "B"); |
+ PostToSequencedWorkerPool(Bind(&ExpectNotCalledOnValidSequencedThread, |
+ Unretained(&sequence_checker)), |
+ "B"); |
+ FlushSequencedWorkerPoolForTesting(); |
+} |
- sequence_checked_object->DetachFromSequence(); |
- PostDoStuffToWorkerPool(sequence_checked_object.get(), "A"); |
- PostDoStuffToWorkerPool(sequence_checked_object.get(), "A"); |
- pool()->FlushForTesting(); |
+TEST_F(SequenceCheckerTest, |
+ SequencedWorkerPool_WorkerPoolAndSimpleThreadInvalid) { |
+ SequenceCheckerImpl sequence_checker; |
+ sequence_checker.DetachFromSequence(); |
- PostDoStuffToOtherThread(sequence_checked_object.get()); |
- other_thread()->Stop(); |
-} |
+ PostToSequencedWorkerPool( |
+ Bind(&ExpectCalledOnValidSequencedThread, Unretained(&sequence_checker)), |
+ "A"); |
+ PostToSequencedWorkerPool( |
+ Bind(&ExpectCalledOnValidSequencedThread, Unretained(&sequence_checker)), |
+ "A"); |
+ FlushSequencedWorkerPoolForTesting(); |
-#if ENABLE_SEQUENCE_CHECKER |
-TEST_F(SequenceCheckerTest, WorkerPoolAndSimpleThreadDeathTestInDebug) { |
- // The default style "fast" does not support multi-threaded tests. |
- ::testing::FLAGS_gtest_death_test_style = "threadsafe"; |
- ASSERT_DEATH({ |
- WorkerPoolAndSimpleThreadDeathTest(); |
- }, ""); |
+ EXPECT_FALSE(sequence_checker.CalledOnValidSequencedThread()); |
} |
-#else |
-TEST_F(SequenceCheckerTest, WorkerPoolAndSimpleThreadDeathTestInRelease) { |
- WorkerPoolAndSimpleThreadDeathTest(); |
-} |
-#endif // ENABLE_SEQUENCE_CHECKER |
-void SequenceCheckerTest::TwoDifferentWorkerPoolsDeathTest() { |
- std::unique_ptr<SequenceCheckedObject> sequence_checked_object( |
- new SequenceCheckedObject); |
+TEST_F(SequenceCheckerTest, |
+ SequencedWorkerPool_TwoDifferentWorkerPoolsInvalid) { |
+ SequenceCheckerImpl sequence_checker; |
+ sequence_checker.DetachFromSequence(); |
- sequence_checked_object->DetachFromSequence(); |
- PostDoStuffToWorkerPool(sequence_checked_object.get(), "A"); |
- PostDoStuffToWorkerPool(sequence_checked_object.get(), "A"); |
- pool()->FlushForTesting(); |
+ PostToSequencedWorkerPool( |
+ Bind(&ExpectCalledOnValidSequencedThread, Unretained(&sequence_checker)), |
+ "A"); |
+ PostToSequencedWorkerPool( |
+ Bind(&ExpectCalledOnValidSequencedThread, Unretained(&sequence_checker)), |
+ "A"); |
+ FlushSequencedWorkerPoolForTesting(); |
SequencedWorkerPoolOwner second_pool_owner(kNumWorkerThreads, "test2"); |
second_pool_owner.pool()->PostNamedSequencedWorkerTask( |
- "A", |
- FROM_HERE, |
- base::Bind(&SequenceCheckedObject::DoStuff, |
- base::Unretained(sequence_checked_object.get()))); |
+ "A", FROM_HERE, base::Bind(&ExpectNotCalledOnValidSequencedThread, |
+ base::Unretained(&sequence_checker))); |
second_pool_owner.pool()->FlushForTesting(); |
} |
-#if ENABLE_SEQUENCE_CHECKER |
-TEST_F(SequenceCheckerTest, TwoDifferentWorkerPoolsDeathTestInDebug) { |
- // The default style "fast" does not support multi-threaded tests. |
- ::testing::FLAGS_gtest_death_test_style = "threadsafe"; |
- ASSERT_DEATH({ |
- TwoDifferentWorkerPoolsDeathTest(); |
- }, ""); |
-} |
-#else |
-TEST_F(SequenceCheckerTest, TwoDifferentWorkerPoolsDeathTestInRelease) { |
- TwoDifferentWorkerPoolsDeathTest(); |
-} |
-#endif // ENABLE_SEQUENCE_CHECKER |
- |
-#endif // GTEST_HAS_DEATH_TEST || !ENABLE_SEQUENCE_CHECKER |
- |
-} // namespace |
- |
} // namespace base |
- |
-// Just in case we ever get lumped together with other compilation units. |
-#undef ENABLE_SEQUENCE_CHECKER |