@ -32,9 +32,10 @@
// Tests that SCOPED_TRACE() and various Google Test assertions can be
// Tests that SCOPED_TRACE() and various Google Test assertions can be
// used in a large number of threads concurrently.
// used in a large number of threads concurrently.
# include <iostream>
# include <gtest/gtest.h>
# include <gtest/gtest.h>
# include <iostream>
// We must define this macro in order to #include
// We must define this macro in order to #include
// gtest-internal-inl.h. This is how Google Test prevents a user from
// gtest-internal-inl.h. This is how Google Test prevents a user from
// accidentally depending on its internal implementation.
// accidentally depending on its internal implementation.
@ -42,6 +43,8 @@
# include "src/gtest-internal-inl.h"
# include "src/gtest-internal-inl.h"
# undef GTEST_IMPLEMENTATION_
# undef GTEST_IMPLEMENTATION_
# if GTEST_IS_THREADSAFE
namespace testing {
namespace testing {
namespace {
namespace {
@ -49,6 +52,20 @@ using internal::String;
using internal : : TestPropertyKeyIs ;
using internal : : TestPropertyKeyIs ;
using internal : : Vector ;
using internal : : Vector ;
// In order to run tests in this file, for platforms where Google Test is
// thread safe, implement ThreadWithParam with the following interface:
//
// template <typename T> class ThreadWithParam {
// public:
// // Creates the thread. The thread should execute thread_func(param) when
// // started by a call to Start().
// ThreadWithParam(void (*thread_func)(T), T param);
// // Starts the thread.
// void Start();
// // Waits for the thread to finish.
// void Join();
// };
// How many threads to create?
// How many threads to create?
const int kThreadCount = 50 ;
const int kThreadCount = 50 ;
@ -77,7 +94,7 @@ void ExpectKeyAndValueWereRecordedForId(const Vector<TestProperty>& properties,
// Calls a large number of Google Test assertions, where exactly one of them
// Calls a large number of Google Test assertions, where exactly one of them
// will fail.
// will fail.
void ManyAsserts ( int id ) {
void ManyAsserts ( int id ) {
: : std : : cout < < " Thread # " < < id < < " running... \n " ;
GTEST_LOG_ ( INFO ) < < " Thread # " < < id < < " running... " ;
SCOPED_TRACE ( Message ( ) < < " Thread # " < < id ) ;
SCOPED_TRACE ( Message ( ) < < " Thread # " < < id ) ;
@ -104,41 +121,125 @@ void ManyAsserts(int id) {
}
}
}
}
void CheckTestFailureCount ( int expected_failures ) {
const TestInfo * const info = UnitTest : : GetInstance ( ) - > current_test_info ( ) ;
const TestResult * const result = info - > result ( ) ;
GTEST_CHECK_ ( expected_failures = = result - > total_part_count ( ) )
< < " Logged " < < result - > total_part_count ( ) < < " failures "
< < " vs. " < < expected_failures < < " expected " ;
}
// Tests using SCOPED_TRACE() and Google Test assertions in many threads
// Tests using SCOPED_TRACE() and Google Test assertions in many threads
// concurrently.
// concurrently.
TEST ( StressTest , CanUseScopedTraceAndAssertionsInManyThreads ) {
TEST ( StressTest , CanUseScopedTraceAndAssertionsInManyThreads ) {
// TODO(wan): when Google Test is made thread-safe, run
ThreadWithParam < int > * threads [ kThreadCount ] = { } ;
// ManyAsserts() in many threads here.
for ( int i = 0 ; i ! = kThreadCount ; i + + ) {
// Creates a thread to run the ManyAsserts() function.
threads [ i ] = new ThreadWithParam < int > ( & ManyAsserts , i ) ;
// Starts the thread.
threads [ i ] - > Start ( ) ;
}
// At this point, we have many threads running.
for ( int i = 0 ; i ! = kThreadCount ; i + + ) {
// We block until the thread is done.
threads [ i ] - > Join ( ) ;
delete threads [ i ] ;
threads [ i ] = NULL ;
}
// Ensures that kThreadCount*kThreadCount failures have been reported.
const TestInfo * const info = UnitTest : : GetInstance ( ) - > current_test_info ( ) ;
const TestResult * const result = info - > result ( ) ;
Vector < TestProperty > properties ;
// We have no access to the TestResult's list of properties but we can
// copy them one by one.
for ( int i = 0 ; i < result - > test_property_count ( ) ; + + i )
properties . PushBack ( result - > GetTestProperty ( i ) ) ;
EXPECT_EQ ( kThreadCount * 2 + 1 , result - > test_property_count ( ) )
< < " String and int values recorded on each thread, "
< < " as well as one shared_key " ;
for ( int i = 0 ; i < kThreadCount ; + + i ) {
ExpectKeyAndValueWereRecordedForId ( properties , i , " string " ) ;
ExpectKeyAndValueWereRecordedForId ( properties , i , " int " ) ;
}
CheckTestFailureCount ( kThreadCount * kThreadCount ) ;
}
void FailingThread ( bool is_fatal ) {
if ( is_fatal )
FAIL ( ) < < " Fatal failure in some other thread. "
< < " (This failure is expected.) " ;
else
ADD_FAILURE ( ) < < " Non-fatal failure in some other thread. "
< < " (This failure is expected.) " ;
}
void GenerateFatalFailureInAnotherThread ( bool is_fatal ) {
ThreadWithParam < bool > thread ( & FailingThread , is_fatal ) ;
thread . Start ( ) ;
thread . Join ( ) ;
}
}
TEST ( NoFatalFailureTest , ExpectNoFatalFailureIgnoresFailuresInOtherThreads ) {
TEST ( NoFatalFailureTest , ExpectNoFatalFailureIgnoresFailuresInOtherThreads ) {
// TODO(mheule@google.com): Test this works correctly when Google
EXPECT_NO_FATAL_FAILURE ( GenerateFatalFailureInAnotherThread ( true ) ) ;
// Test is made thread-safe.
// We should only have one failure (the one from
// GenerateFatalFailureInAnotherThread()), since the EXPECT_NO_FATAL_FAILURE
// should succeed.
CheckTestFailureCount ( 1 ) ;
}
}
void AssertNoFatalFailureIgnoresFailuresInOtherThreads ( ) {
ASSERT_NO_FATAL_FAILURE ( GenerateFatalFailureInAnotherThread ( true ) ) ;
}
TEST ( NoFatalFailureTest , AssertNoFatalFailureIgnoresFailuresInOtherThreads ) {
TEST ( NoFatalFailureTest , AssertNoFatalFailureIgnoresFailuresInOtherThreads ) {
// TODO(mheule@google.com): Test this works correctly when Google
// Using a subroutine, to make sure, that the test continues.
// Test is made thread-safe.
AssertNoFatalFailureIgnoresFailuresInOtherThreads ( ) ;
// We should only have one failure (the one from
// GenerateFatalFailureInAnotherThread()), since the EXPECT_NO_FATAL_FAILURE
// should succeed.
CheckTestFailureCount ( 1 ) ;
}
}
TEST ( FatalFailureTest , ExpectFatalFailureIgnoresFailuresInOtherThreads ) {
TEST ( FatalFailureTest , ExpectFatalFailureIgnoresFailuresInOtherThreads ) {
// TODO(mheule@google.com): Test this works correctly when Google
// This statement should fail, since the current thread doesn't generate a
// Test is made thread-safe.
// fatal failure, only another one does.
EXPECT_FATAL_FAILURE ( GenerateFatalFailureInAnotherThread ( true ) , " expected " ) ;
CheckTestFailureCount ( 2 ) ;
}
}
TEST ( FatalFailureOnAllThreadsTest , ExpectFatalFailureOnAllThreads ) {
TEST ( FatalFailureOnAllThreadsTest , ExpectFatalFailureOnAllThreads ) {
// TODO(wan@google.com): Test this works correctly when Google Test
// This statement should succeed, because failures in all threads are
// is made thread-safe.
// considered.
EXPECT_FATAL_FAILURE_ON_ALL_THREADS (
GenerateFatalFailureInAnotherThread ( true ) , " expected " ) ;
CheckTestFailureCount ( 0 ) ;
// We need to add a failure, because main() checks that there are failures.
// But when only this test is run, we shouldn't have any failures.
ADD_FAILURE ( ) < < " This is an expected non-fatal failure. " ;
}
}
TEST ( NonFatalFailureTest , ExpectNonFatalFailureIgnoresFailuresInOtherThreads ) {
TEST ( NonFatalFailureTest , ExpectNonFatalFailureIgnoresFailuresInOtherThreads ) {
// TODO(mheule@google.com): Test this works correctly when Google
// This statement should fail, since the current thread doesn't generate a
// Test is made thread-safe.
// fatal failure, only another one does.
EXPECT_NONFATAL_FAILURE ( GenerateFatalFailureInAnotherThread ( false ) ,
" expected " ) ;
CheckTestFailureCount ( 2 ) ;
}
}
TEST ( NonFatalFailureOnAllThreadsTest , ExpectNonFatalFailureOnAllThreads ) {
TEST ( NonFatalFailureOnAllThreadsTest , ExpectNonFatalFailureOnAllThreads ) {
// TODO(wan@google.com): Test this works correctly when Google Test
// This statement should succeed, because failures in all threads are
// is made thread-safe.
// considered.
EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS (
GenerateFatalFailureInAnotherThread ( false ) , " expected " ) ;
CheckTestFailureCount ( 0 ) ;
// We need to add a failure, because main() checks that there are failures,
// But when only this test is run, we shouldn't have any failures.
ADD_FAILURE ( ) < < " This is an expected non-fatal failure. " ;
}
}
} // namespace
} // namespace
@ -147,5 +248,20 @@ TEST(NonFatalFailureOnAllThreadsTest, ExpectNonFatalFailureOnAllThreads) {
int main ( int argc , char * * argv ) {
int main ( int argc , char * * argv ) {
testing : : InitGoogleTest ( & argc , argv ) ;
testing : : InitGoogleTest ( & argc , argv ) ;
const int result = RUN_ALL_TESTS ( ) ; // Expected to fail.
GTEST_CHECK_ ( result = = 1 ) < < " RUN_ALL_TESTS() did not fail as expected " ;
printf ( " \n PASS \n " ) ;
return 0 ;
}
# else
TEST ( StressTest ,
DISABLED_ThreadSafetyTestsAreSkippedWhenGoogleTestIsNotThreadSafe ) {
}
int main ( int argc , char * * argv ) {
testing : : InitGoogleTest ( & argc , argv ) ;
return RUN_ALL_TESTS ( ) ;
return RUN_ALL_TESTS ( ) ;
}
}
# endif // GTEST_IS_THREADSAFE