I started with testing GoogleMock (1.8.0 release) on Windows. I wanted to show an example that it is not thread safe. After proving that successfully, I wanted to show that the same test runs fine on Linux. That failed however. That did not match my expectation.
Since the GoogleMock documentation says that it is, or should be, thread safe on systems with pthreads, it should be thread safe on Linux. I did have to add -pthread
to the linker command line to build the executable. That means that GoogleMock or GoogleTest does use pthreads.
This is the code I use for testing:
#include <thread>
#include <vector>
#include "gmock/gmock.h"
class Dummy
{
public:
virtual void SomeMethod(int) {}
};
class DummyMock : public Dummy
{
public:
MOCK_METHOD1(SomeMethod, void(int));
};
using ::testing::Exactly;
constexpr static int nrCallsPerThread = 100 * 1000;
constexpr static int nrThreads = 10;
TEST(SomeTest, Test100)
{
DummyMock dummy;
std::vector<std::thread> threads;
for (int i = 0; i < nrThreads; i++)
{
EXPECT_CALL(dummy, SomeMethod(i)).Times(Exactly(nrCallsPerThread));
threads.emplace_back([&dummy, i]
{
for (int j = 0; j < nrCallsPerThread; j++)
{
dummy.SomeMethod(i);
}
});
}
for (auto& t: threads)
{
t.join();
}
}
int main(int argc, char** argv)
{
testing::InitGoogleMock(&argc, argv);
return RUN_ALL_TESTS();
}
The problem is, on Linux, not exposed every execution. But running the executable with --gtest_repeat=100
has a near 100% hit rate.
On Windows, using Visual Studio 2015, if get a Debug Assertion Failed!
message with Expression: vector iterator not decrementable
.
On Linux, Ubuntu 17.04, when I run the Debug build from the command line I get [ FATAL ] ../googletest-release-1.8.0/googletest/include/gtest/internal/gtest-port.h:1928:: pthread_mutex_lock(&mutex_)failed with error 22
.
When running in a debugger on Linux, the program is (often) interrupted at gtest-port.h line 1100, which is line 2 in this callstack:
0 0x5555555a6633 testing::Cardinality::ConservativeUpperBound() const () (??:??)
1 0x5555555a1a13 testing::internal::ExpectationBase::CheckActionCountIfNotDone() const () (??:??)
2 0x555555563f98 testing::internal::TypedExpectation<void (int)>::ShouldHandleArguments(std::tuple<int> const&) const(this=0x5555557f58a0, args=std::tuple containing = {...}) (../googletest-release-1.8.0/googlemock/include/gmock/gmock-spec-builders.h:1100)
3 0x55555556397d testing::internal::FunctionMockerBase<void (int)>::FindMatchingExpectationLocked(std::tuple<int> const&) const(this=0x7fffffffde38, args=std::tuple containing = {...}) (../googletest-release-1.8.0/googlemock/include/gmock/gmock-spec-builders.h:1723)
4 0x555555563578 testing::internal::FunctionMockerBase<void (int)>::UntypedFindMatchingExpectation(void const*, void const**, bool*, std::ostream*, std::ostream*)(this=0x7fffffffde38, untyped_args=0x7fffde7fbe14, untyped_action=0x7fffde7fb7d0, is_excessive=0x7fffde7fb7c7, what=0x7fffde7fb900, why=0x7fffde7fba90) (../googletest-release-1.8.0/googlemock/include/gmock/gmock-spec-builders.h:1687)
5 0x5555555a265e testing::internal::UntypedFunctionMockerBase::UntypedInvokeWith(void const*) () (??:??)
6 0x55555555fcba testing::internal::FunctionMockerBase<void (int)>::InvokeWith(std::tuple<int> const&)(this=0x7fffffffde38, args=std::tuple containing = {...}) (../googletest-release-1.8.0/googlemock/include/gmock/gmock-spec-builders.h:1585)
7 0x55555555f16c testing::internal::FunctionMocker<void (int)>::Invoke(int)(this=0x7fffffffde38, a1=1) (../googletest-release-1.8.0/googlemock/include/gmock/gmock-generated-function-mockers.h:101)
8 0x55555555ecb6 DummyMock::SomeMethod(this=0x7fffffffde30, gmock_a1=1) (/home/jos/Programming/ThreadSafeGMock/main.cpp:16)
9 0x55555555d31e SomeTest_Test100_Test::<lambda()>::operator()(void) const(__closure=0x5555557f5478) (/home/jos/Programming/ThreadSafeGMock/main.cpp:36)
10 0x55555555de98 std::_Bind_simple<SomeTest_Test100_Test::TestBody()::<lambda()>()>::_M_invoke<>(std::_Index_tuple<>)(this=0x5555557f5478) (/usr/include/c++/6/functional:1391)
11 0x55555555de22 std::_Bind_simple<SomeTest_Test100_Test::TestBody()::<lambda()>()>::operator()(void)(this=0x5555557f5478) (/usr/include/c++/6/functional:1380)
12 0x55555555ddf2 std::thread::_State_impl<std::_Bind_simple<SomeTest_Test100_Test::TestBody()::<lambda()>()> >::_M_run(void)(this=0x5555557f5470) (/usr/include/c++/6/thread:197)
13 0x7ffff7b0a83f ??() (/usr/lib/x86_64-linux-gnu/libstdc++.so.6:??)
14 0x7ffff76216da start_thread(arg=0x7fffde7fc700) (pthread_create.c:456)
15 0x7ffff735b17f clone() (../sysdeps/unix/sysv/linux/x86_64/clone.S:105)
Since it should be thread safe, I suspect that I am doing something wrong. But I do not see what. Or did I hit a bug in GoogleTest or GoogleMock?