Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
G
googletest
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Chen Yisong
googletest
Commits
47be72a9
Commit
47be72a9
authored
May 11, 2011
by
vladlosev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
A test to verify correcteness of Google Mock on multiple threads.
parent
a63da041
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
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)
...
@@ -114,9 +114,12 @@ if (gmock_build_tests)
cxx_test
(
gmock-port_test gmock_main
)
cxx_test
(
gmock-port_test gmock_main
)
cxx_test
(
gmock-spec-builders_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_link_test gmock_main test/gmock_link2_test.cc
)
# cxx_test(gmock_stress_test gmock)
cxx_test
(
gmock_test gmock_main
)
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.
# gmock_all_test is commented to save time building and running tests.
# Uncomment if necessary.
# Uncomment if necessary.
# cxx_test(gmock_all_test gmock_main)
# 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