Skip to content

Commit

Permalink
Mock can be deadlocked by a panic (#1157)
Browse files Browse the repository at this point in the history
If an argumentMatcher function panics and AssertExpectations is deferred then the test would deadlock.
  • Loading branch information
brackendawson authored Jun 23, 2022
1 parent 1b73601 commit c206b2e
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 1 deletion.
11 changes: 10 additions & 1 deletion mock/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -858,7 +858,16 @@ func (args Arguments) Diff(objects []interface{}) (string, int) {
}

if matcher, ok := expected.(argumentMatcher); ok {
if matcher.Matches(actual) {
var matches bool
func() {
defer func() {
if r := recover(); r != nil {
actualFmt = fmt.Sprintf("panic in argument matcher: %v", r)
}
}()
matches = matcher.Matches(actual)
}()
if matches {
output = fmt.Sprintf("%s\t%d: PASS: %s matched by %s\n", output, i, actualFmt, matcher)
} else {
differences++
Expand Down
26 changes: 26 additions & 0 deletions mock/mock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,32 @@ func Test_Mock_On_WithIntArgMatcher(t *testing.T) {
})
}

func Test_Mock_On_WithArgMatcherThatPanics(t *testing.T) {
var mockedService TestExampleImplementation

mockedService.On("TheExampleMethod2", MatchedBy(func(_ interface{}) bool {
panic("try to lock mockedService")
})).Return()

defer func() {
assertedExpectations := make(chan struct{})
go func() {
tt := new(testing.T)
mockedService.AssertExpectations(tt)
close(assertedExpectations)
}()
select {
case <-assertedExpectations:
case <-time.After(time.Second):
t.Fatal("AssertExpectations() deadlocked, did the panic leave mockedService locked?")
}
}()

assert.Panics(t, func() {
mockedService.TheExampleMethod2(false)
})
}

func TestMock_WithTest(t *testing.T) {
var (
mockedService TestExampleImplementation
Expand Down

0 comments on commit c206b2e

Please sign in to comment.