Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
yangql
googletest
Commits
47be72a9
Commit
47be72a9
authored
May 11, 2011
by
vladlosev
Browse files
A test to verify correcteness of Google Mock on multiple threads.
parent
a63da041
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
326 additions
and
1 deletion
+326
-1
CMakeLists.txt
CMakeLists.txt
+4
-1
test/gmock_stress_test.cc
test/gmock_stress_test.cc
+322
-0
No files found.
CMakeLists.txt
View file @
47be72a9
...
...
@@ -114,9 +114,12 @@ if (gmock_build_tests)
cxx_test
(
gmock-port_test gmock_main
)
cxx_test
(
gmock-spec-builders_test gmock_main
)
cxx_test
(
gmock_link_test gmock_main test/gmock_link2_test.cc
)
# cxx_test(gmock_stress_test gmock)
cxx_test
(
gmock_test gmock_main
)
if
(
CMAKE_USE_PTHREADS_INIT
)
cxx_test
(
gmock_stress_test gmock
)
endif
()
# gmock_all_test is commented to save time building and running tests.
# Uncomment if necessary.
# cxx_test(gmock_all_test gmock_main)
...
...
test/gmock_stress_test.cc
0 → 100644
View file @
47be72a9
// Copyright 2007, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: wan@google.com (Zhanyong Wan)
// Tests that Google Mock constructs can be used in a large number of
// threads concurrently.
#include "gmock/gmock.h"
#include "gtest/gtest.h"
namespace
testing
{
namespace
{
// From <gtest/internal/gtest-port.h>.
using
::
testing
::
internal
::
ThreadWithParam
;
// The maximum number of test threads (not including helper threads)
// to create.
const
int
kMaxTestThreads
=
50
;
// How many times to repeat a task in a test thread.
const
int
kRepeat
=
50
;
class
MockFoo
{
public:
MOCK_METHOD1
(
Bar
,
int
(
int
n
));
// NOLINT
MOCK_METHOD2
(
Baz
,
char
(
const
char
*
s1
,
const
internal
::
string
&
s2
));
// NOLINT
};
// Helper for waiting for the given thread to finish and then deleting it.
template
<
typename
T
>
void
JoinAndDelete
(
ThreadWithParam
<
T
>*
t
)
{
t
->
Join
();
delete
t
;
}
using
internal
::
linked_ptr
;
// Helper classes for testing using linked_ptr concurrently.
class
Base
{
public:
explicit
Base
(
int
a_x
)
:
x_
(
a_x
)
{}
virtual
~
Base
()
{}
int
x
()
const
{
return
x_
;
}
private:
int
x_
;
};
class
Derived1
:
public
Base
{
public:
Derived1
(
int
a_x
,
int
a_y
)
:
Base
(
a_x
),
y_
(
a_y
)
{}
int
y
()
const
{
return
y_
;
}
private:
int
y_
;
};
class
Derived2
:
public
Base
{
public:
Derived2
(
int
a_x
,
int
a_z
)
:
Base
(
a_x
),
z_
(
a_z
)
{}
int
z
()
const
{
return
z_
;
}
private:
int
z_
;
};
linked_ptr
<
Derived1
>
pointer1
(
new
Derived1
(
1
,
2
));
linked_ptr
<
Derived2
>
pointer2
(
new
Derived2
(
3
,
4
));
struct
Dummy
{};
// Tests that we can copy from a linked_ptr and read it concurrently.
void
TestConcurrentCopyAndReadLinkedPtr
(
Dummy
/* dummy */
)
{
// Reads pointer1 and pointer2 while they are being copied from in
// another thread.
EXPECT_EQ
(
1
,
pointer1
->
x
());
EXPECT_EQ
(
2
,
pointer1
->
y
());
EXPECT_EQ
(
3
,
pointer2
->
x
());
EXPECT_EQ
(
4
,
pointer2
->
z
());
// Copies from pointer1.
linked_ptr
<
Derived1
>
p1
(
pointer1
);
EXPECT_EQ
(
1
,
p1
->
x
());
EXPECT_EQ
(
2
,
p1
->
y
());
// Assigns from pointer2 where the LHS was empty.
linked_ptr
<
Base
>
p2
;
p2
=
pointer1
;
EXPECT_EQ
(
1
,
p2
->
x
());
// Assigns from pointer2 where the LHS was not empty.
p2
=
pointer2
;
EXPECT_EQ
(
3
,
p2
->
x
());
}
const
linked_ptr
<
Derived1
>
p0
(
new
Derived1
(
1
,
2
));
// Tests that we can concurrently modify two linked_ptrs that point to
// the same object.
void
TestConcurrentWriteToEqualLinkedPtr
(
Dummy
/* dummy */
)
{
// p1 and p2 point to the same, shared thing. One thread resets p1.
// Another thread assigns to p2. This will cause the same
// underlying "ring" to be updated concurrently.
linked_ptr
<
Derived1
>
p1
(
p0
);
linked_ptr
<
Derived1
>
p2
(
p0
);
EXPECT_EQ
(
1
,
p1
->
x
());
EXPECT_EQ
(
2
,
p1
->
y
());
EXPECT_EQ
(
1
,
p2
->
x
());
EXPECT_EQ
(
2
,
p2
->
y
());
p1
.
reset
();
p2
=
p0
;
EXPECT_EQ
(
1
,
p2
->
x
());
EXPECT_EQ
(
2
,
p2
->
y
());
}
// Tests that different mock objects can be used in their respective
// threads. This should generate no Google Test failure.
void
TestConcurrentMockObjects
(
Dummy
/* dummy */
)
{
// Creates a mock and does some typical operations on it.
MockFoo
foo
;
ON_CALL
(
foo
,
Bar
(
_
))
.
WillByDefault
(
Return
(
1
));
ON_CALL
(
foo
,
Baz
(
_
,
_
))
.
WillByDefault
(
Return
(
'b'
));
ON_CALL
(
foo
,
Baz
(
_
,
"you"
))
.
WillByDefault
(
Return
(
'a'
));
EXPECT_CALL
(
foo
,
Bar
(
0
))
.
Times
(
AtMost
(
3
));
EXPECT_CALL
(
foo
,
Baz
(
_
,
_
));
EXPECT_CALL
(
foo
,
Baz
(
"hi"
,
"you"
))
.
WillOnce
(
Return
(
'z'
))
.
WillRepeatedly
(
DoDefault
());
EXPECT_EQ
(
1
,
foo
.
Bar
(
0
));
EXPECT_EQ
(
1
,
foo
.
Bar
(
0
));
EXPECT_EQ
(
'z'
,
foo
.
Baz
(
"hi"
,
"you"
));
EXPECT_EQ
(
'a'
,
foo
.
Baz
(
"hi"
,
"you"
));
EXPECT_EQ
(
'b'
,
foo
.
Baz
(
"hi"
,
"me"
));
}
// Tests invoking methods of the same mock object in multiple threads.
struct
Helper1Param
{
MockFoo
*
mock_foo
;
int
*
count
;
};
void
Helper1
(
Helper1Param
param
)
{
for
(
int
i
=
0
;
i
<
kRepeat
;
i
++
)
{
const
char
ch
=
param
.
mock_foo
->
Baz
(
"a"
,
"b"
);
if
(
ch
==
'a'
)
{
// It was an expected call.
(
*
param
.
count
)
++
;
}
else
{
// It was an excessive call.
EXPECT_EQ
(
'\0'
,
ch
);
}
// An unexpected call.
EXPECT_EQ
(
'\0'
,
param
.
mock_foo
->
Baz
(
"x"
,
"y"
))
<<
"Expected failure."
;
// An uninteresting call.
EXPECT_EQ
(
1
,
param
.
mock_foo
->
Bar
(
5
));
}
}
// This should generate 3*kRepeat + 1 failures in total.
void
TestConcurrentCallsOnSameObject
(
Dummy
/* dummy */
)
{
MockFoo
foo
;
ON_CALL
(
foo
,
Bar
(
_
))
.
WillByDefault
(
Return
(
1
));
EXPECT_CALL
(
foo
,
Baz
(
_
,
"b"
))
.
Times
(
kRepeat
)
.
WillRepeatedly
(
Return
(
'a'
));
EXPECT_CALL
(
foo
,
Baz
(
_
,
"c"
));
// Expected to be unsatisfied.
// This chunk of code should generate kRepeat failures about
// excessive calls, and 2*kRepeat failures about unexpected calls.
int
count1
=
0
;
const
Helper1Param
param
=
{
&
foo
,
&
count1
};
ThreadWithParam
<
Helper1Param
>*
const
t
=
new
ThreadWithParam
<
Helper1Param
>
(
Helper1
,
param
,
NULL
);
int
count2
=
0
;
const
Helper1Param
param2
=
{
&
foo
,
&
count2
};
Helper1
(
param2
);
JoinAndDelete
(
t
);
EXPECT_EQ
(
kRepeat
,
count1
+
count2
);
// foo's destructor should generate one failure about unsatisfied
// expectation.
}
// Tests using the same mock object in multiple threads when the
// expectations are partially ordered.
void
Helper2
(
MockFoo
*
foo
)
{
for
(
int
i
=
0
;
i
<
kRepeat
;
i
++
)
{
foo
->
Bar
(
2
);
foo
->
Bar
(
3
);
}
}
// This should generate no Google Test failures.
void
TestPartiallyOrderedExpectationsWithThreads
(
Dummy
/* dummy */
)
{
MockFoo
foo
;
Sequence
s1
,
s2
;
{
InSequence
dummy
;
EXPECT_CALL
(
foo
,
Bar
(
0
));
EXPECT_CALL
(
foo
,
Bar
(
1
))
.
InSequence
(
s1
,
s2
);
}
EXPECT_CALL
(
foo
,
Bar
(
2
))
.
Times
(
2
*
kRepeat
)
.
InSequence
(
s1
)
.
RetiresOnSaturation
();
EXPECT_CALL
(
foo
,
Bar
(
3
))
.
Times
(
2
*
kRepeat
)
.
InSequence
(
s2
);
{
InSequence
dummy
;
EXPECT_CALL
(
foo
,
Bar
(
2
))
.
InSequence
(
s1
,
s2
);
EXPECT_CALL
(
foo
,
Bar
(
4
));
}
foo
.
Bar
(
0
);
foo
.
Bar
(
1
);
ThreadWithParam
<
MockFoo
*>*
const
t
=
new
ThreadWithParam
<
MockFoo
*>
(
Helper2
,
&
foo
,
NULL
);
Helper2
(
&
foo
);
JoinAndDelete
(
t
);
foo
.
Bar
(
2
);
foo
.
Bar
(
4
);
}
// Tests using Google Mock constructs in many threads concurrently.
TEST
(
StressTest
,
CanUseGMockWithThreads
)
{
void
(
*
test_routines
[])(
Dummy
dummy
)
=
{
&
TestConcurrentCopyAndReadLinkedPtr
,
&
TestConcurrentWriteToEqualLinkedPtr
,
&
TestConcurrentMockObjects
,
&
TestConcurrentCallsOnSameObject
,
&
TestPartiallyOrderedExpectationsWithThreads
,
};
const
int
kRoutines
=
sizeof
(
test_routines
)
/
sizeof
(
test_routines
[
0
]);
const
int
kCopiesOfEachRoutine
=
kMaxTestThreads
/
kRoutines
;
const
int
kTestThreads
=
kCopiesOfEachRoutine
*
kRoutines
;
ThreadWithParam
<
Dummy
>*
threads
[
kTestThreads
]
=
{};
for
(
int
i
=
0
;
i
<
kTestThreads
;
i
++
)
{
// Creates a thread to run the test function.
threads
[
i
]
=
new
ThreadWithParam
<
Dummy
>
(
test_routines
[
i
%
kRoutines
],
Dummy
(),
NULL
);
GTEST_LOG_
(
INFO
)
<<
"Thread #"
<<
i
<<
" running . . ."
;
}
// At this point, we have many threads running.
for
(
int
i
=
0
;
i
<
kTestThreads
;
i
++
)
{
JoinAndDelete
(
threads
[
i
]);
}
// Ensures that the correct number of failures have been reported.
const
TestInfo
*
const
info
=
UnitTest
::
GetInstance
()
->
current_test_info
();
const
TestResult
&
result
=
*
info
->
result
();
const
int
kExpectedFailures
=
(
3
*
kRepeat
+
1
)
*
kCopiesOfEachRoutine
;
GTEST_CHECK_
(
kExpectedFailures
==
result
.
total_part_count
())
<<
"Expected "
<<
kExpectedFailures
<<
" failures, but got "
<<
result
.
total_part_count
();
}
}
// namespace
}
// namespace testing
int
main
(
int
argc
,
char
**
argv
)
{
testing
::
InitGoogleMock
(
&
argc
,
argv
);
const
int
exit_code
=
RUN_ALL_TESTS
();
// Expected to fail.
GTEST_CHECK_
(
exit_code
!=
0
)
<<
"RUN_ALL_TESTS() did not fail as expected"
;
printf
(
"
\n
PASS
\n
"
);
return
0
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment