aboutsummaryrefslogtreecommitdiffstats
path: root/gtest/test/gtest_stress_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gtest/test/gtest_stress_test.cc')
-rw-r--r--gtest/test/gtest_stress_test.cc150
1 files changed, 128 insertions, 22 deletions
diff --git a/gtest/test/gtest_stress_test.cc b/gtest/test/gtest_stress_test.cc
index 0034bb8..f5af78c 100644
--- a/gtest/test/gtest_stress_test.cc
+++ b/gtest/test/gtest_stress_test.cc
@@ -32,9 +32,11 @@
// Tests that SCOPED_TRACE() and various Google Test assertions can be
// used in a large number of threads concurrently.
-#include <iostream>
#include <gtest/gtest.h>
+#include <iostream>
+#include <vector>
+
// We must define this macro in order to #include
// gtest-internal-inl.h. This is how Google Test prevents a user from
// accidentally depending on its internal implementation.
@@ -42,12 +44,20 @@
#include "src/gtest-internal-inl.h"
#undef GTEST_IMPLEMENTATION_
+#if GTEST_IS_THREADSAFE
+
namespace testing {
namespace {
+using internal::Notification;
using internal::String;
using internal::TestPropertyKeyIs;
-using internal::Vector;
+using internal::ThreadWithParam;
+using internal::scoped_ptr;
+
+// In order to run tests in this file, for platforms where Google Test is
+// thread safe, implement ThreadWithParam. See the description of its API
+// in gtest-port.h, where it is defined for already supported platforms.
// How many threads to create?
const int kThreadCount = 50;
@@ -64,12 +74,13 @@ String IdToString(int id) {
return id_message.GetString();
}
-void ExpectKeyAndValueWereRecordedForId(const Vector<TestProperty>& properties,
- int id,
- const char* suffix) {
+void ExpectKeyAndValueWereRecordedForId(
+ const std::vector<TestProperty>& properties,
+ int id, const char* suffix) {
TestPropertyKeyIs matches_key(IdToKey(id, suffix).c_str());
- const TestProperty* property = properties.FindIf(matches_key);
- ASSERT_TRUE(property != NULL)
+ const std::vector<TestProperty>::const_iterator property =
+ std::find_if(properties.begin(), properties.end(), matches_key);
+ ASSERT_TRUE(property != properties.end())
<< "expecting " << suffix << " value for id " << id;
EXPECT_STREQ(IdToString(id).c_str(), property->value());
}
@@ -77,7 +88,7 @@ void ExpectKeyAndValueWereRecordedForId(const Vector<TestProperty>& properties,
// Calls a large number of Google Test assertions, where exactly one of them
// will fail.
void ManyAsserts(int id) {
- ::std::cout << "Thread #" << id << " running...\n";
+ GTEST_LOG_(INFO) << "Thread #" << id << " running...";
SCOPED_TRACE(Message() << "Thread #" << id);
@@ -104,41 +115,121 @@ 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
// concurrently.
TEST(StressTest, CanUseScopedTraceAndAssertionsInManyThreads) {
- // TODO(wan): when Google Test is made thread-safe, run
- // ManyAsserts() in many threads here.
+ {
+ scoped_ptr<ThreadWithParam<int> > threads[kThreadCount];
+ Notification threads_can_start;
+ for (int i = 0; i != kThreadCount; i++)
+ threads[i].reset(new ThreadWithParam<int>(&ManyAsserts,
+ i,
+ &threads_can_start));
+
+ threads_can_start.Notify();
+
+ // Blocks until all the threads are done.
+ for (int i = 0; i != kThreadCount; i++)
+ threads[i]->Join();
+ }
+
+ // Ensures that kThreadCount*kThreadCount failures have been reported.
+ const TestInfo* const info = UnitTest::GetInstance()->current_test_info();
+ const TestResult* const result = info->result();
+
+ std::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.push_back(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, NULL);
+ thread.Join();
}
TEST(NoFatalFailureTest, ExpectNoFatalFailureIgnoresFailuresInOtherThreads) {
- // TODO(mheule@google.com): Test this works correctly when Google
- // Test is made thread-safe.
+ EXPECT_NO_FATAL_FAILURE(GenerateFatalFailureInAnotherThread(true));
+ // 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) {
- // TODO(mheule@google.com): Test this works correctly when Google
- // Test is made thread-safe.
+ // Using a subroutine, to make sure, that the test continues.
+ AssertNoFatalFailureIgnoresFailuresInOtherThreads();
+ // We should only have one failure (the one from
+ // GenerateFatalFailureInAnotherThread()), since the EXPECT_NO_FATAL_FAILURE
+ // should succeed.
+ CheckTestFailureCount(1);
}
TEST(FatalFailureTest, ExpectFatalFailureIgnoresFailuresInOtherThreads) {
- // TODO(mheule@google.com): Test this works correctly when Google
- // Test is made thread-safe.
+ // This statement should fail, since the current thread doesn't generate a
+ // fatal failure, only another one does.
+ EXPECT_FATAL_FAILURE(GenerateFatalFailureInAnotherThread(true), "expected");
+ CheckTestFailureCount(2);
}
TEST(FatalFailureOnAllThreadsTest, ExpectFatalFailureOnAllThreads) {
- // TODO(wan@google.com): Test this works correctly when Google Test
- // is made thread-safe.
+ // This statement should succeed, because failures in all threads are
+ // 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) {
- // TODO(mheule@google.com): Test this works correctly when Google
- // Test is made thread-safe.
+ // This statement should fail, since the current thread doesn't generate a
+ // fatal failure, only another one does.
+ EXPECT_NONFATAL_FAILURE(GenerateFatalFailureInAnotherThread(false),
+ "expected");
+ CheckTestFailureCount(2);
}
TEST(NonFatalFailureOnAllThreadsTest, ExpectNonFatalFailureOnAllThreads) {
- // TODO(wan@google.com): Test this works correctly when Google Test
- // is made thread-safe.
+ // This statement should succeed, because failures in all threads are
+ // 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
@@ -147,5 +238,20 @@ TEST(NonFatalFailureOnAllThreadsTest, ExpectNonFatalFailureOnAllThreads) {
int main(int argc, char **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("\nPASS\n");
+ return 0;
+}
+
+#else
+TEST(StressTest,
+ DISABLED_ThreadSafetyTestsAreSkippedWhenGoogleTestIsNotThreadSafe) {
+}
+
+int main(int argc, char **argv) {
+ testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
+#endif // GTEST_IS_THREADSAFE