Retry temporary errors by default (#107)

* Adding Aurora URL validator in order to handle scenarios where incomplete information is passed to the client. The client will do its best to guess the missing information such as protocol and port.

* Upgraded to testify 1.3.0.

* Added configuration to fail on a non-temporary error. This is reverting to the original behavior of the retry mechanism. However, this allows the user to opt to fail in a non-temporary error.
This commit is contained in:
Renan DelValle 2019-06-11 11:47:14 -07:00 committed by GitHub
parent 4ffb509939
commit 6dc4bf93b9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
37 changed files with 2795 additions and 1009 deletions

View file

@ -3,6 +3,8 @@ package mock
import (
"errors"
"fmt"
"regexp"
"runtime"
"sync"
"testing"
"time"
@ -30,6 +32,7 @@ func (i *TestExampleImplementation) TheExampleMethod(a, b, c int) (int, error) {
return args.Int(0), errors.New("Whoops")
}
//go:noinline
func (i *TestExampleImplementation) TheExampleMethod2(yesorno bool) {
i.Called(yesorno)
}
@ -90,6 +93,34 @@ func (i *TestExampleImplementation) TheExampleMethodFuncType(fn ExampleFuncType)
return args.Error(0)
}
// MockTestingT mocks a test struct
type MockTestingT struct {
logfCount, errorfCount, failNowCount int
}
const mockTestingTFailNowCalled = "FailNow was called"
func (m *MockTestingT) Logf(string, ...interface{}) {
m.logfCount++
}
func (m *MockTestingT) Errorf(string, ...interface{}) {
m.errorfCount++
}
// FailNow mocks the FailNow call.
// It panics in order to mimic the FailNow behavior in the sense that
// the execution stops.
// When expecting this method, the call that invokes it should use the following code:
//
// assert.PanicsWithValue(t, mockTestingTFailNowCalled, func() {...})
func (m *MockTestingT) FailNow() {
m.failNowCount++
// this function should panic now to stop the execution as expected
panic(mockTestingTFailNowCalled)
}
/*
Mock
*/
@ -119,6 +150,8 @@ func Test_Mock_Chained_On(t *testing.T) {
// make a test impl object
var mockedService = new(TestExampleImplementation)
// determine our current line number so we can assert the expected calls callerInfo properly
_, _, line, _ := runtime.Caller(0)
mockedService.
On("TheExampleMethod", 1, 2, 3).
Return(0).
@ -126,17 +159,19 @@ func Test_Mock_Chained_On(t *testing.T) {
Return(nil)
expectedCalls := []*Call{
&Call{
{
Parent: &mockedService.Mock,
Method: "TheExampleMethod",
Arguments: []interface{}{1, 2, 3},
ReturnArguments: []interface{}{0},
callerInfo: []string{fmt.Sprintf("mock_test.go:%d", line+2)},
},
&Call{
{
Parent: &mockedService.Mock,
Method: "TheExampleMethod3",
Arguments: []interface{}{AnythingOfType("*mock.ExampleType")},
ReturnArguments: []interface{}{nil},
callerInfo: []string{fmt.Sprintf("mock_test.go:%d", line+4)},
},
}
assert.Equal(t, expectedCalls, mockedService.ExpectedCalls)
@ -198,6 +233,34 @@ func Test_Mock_On_WithIntArgMatcher(t *testing.T) {
})
}
func TestMock_WithTest(t *testing.T) {
var (
mockedService TestExampleImplementation
mockedTest MockTestingT
)
mockedService.Test(&mockedTest)
mockedService.On("TheExampleMethod", 1, 2, 3).Return(0, nil)
// Test that on an expected call, the test was not failed
mockedService.TheExampleMethod(1, 2, 3)
// Assert that Errorf and FailNow were not called
assert.Equal(t, 0, mockedTest.errorfCount)
assert.Equal(t, 0, mockedTest.failNowCount)
// Test that on unexpected call, the mocked test was called to fail the test
assert.PanicsWithValue(t, mockTestingTFailNowCalled, func() {
mockedService.TheExampleMethod(1, 1, 1)
})
// Assert that Errorf and FailNow were called once
assert.Equal(t, 1, mockedTest.errorfCount)
assert.Equal(t, 1, mockedTest.failNowCount)
}
func Test_Mock_On_WithPtrArgMatcher(t *testing.T) {
var mockedService TestExampleImplementation
@ -1125,8 +1188,8 @@ func Test_Arguments_Diff(t *testing.T) {
diff, count = args.Diff([]interface{}{"Hello World", 456, "false"})
assert.Equal(t, 2, count)
assert.Contains(t, diff, `%!s(int=456) != %!s(int=123)`)
assert.Contains(t, diff, `false != %!s(bool=true)`)
assert.Contains(t, diff, `(int=456) != (int=123)`)
assert.Contains(t, diff, `(string=false) != (bool=true)`)
}
@ -1138,7 +1201,7 @@ func Test_Arguments_Diff_DifferentNumberOfArgs(t *testing.T) {
diff, count = args.Diff([]interface{}{"string", 456, "false", "extra"})
assert.Equal(t, 3, count)
assert.Contains(t, diff, `extra != (Missing)`)
assert.Contains(t, diff, `(string=extra) != (Missing)`)
}
@ -1180,7 +1243,7 @@ func Test_Arguments_Diff_WithAnythingOfTypeArgument_Failing(t *testing.T) {
diff, count = args.Diff([]interface{}{"string", 123, true})
assert.Equal(t, 1, count)
assert.Contains(t, diff, `string != type int - %!s(int=123)`)
assert.Contains(t, diff, `string != type int - (int=123)`)
}
@ -1192,14 +1255,14 @@ func Test_Arguments_Diff_WithArgMatcher(t *testing.T) {
diff, count := args.Diff([]interface{}{"string", 124, true})
assert.Equal(t, 1, count)
assert.Contains(t, diff, `%!s(int=124) not matched by func(int) bool`)
assert.Contains(t, diff, `(int=124) not matched by func(int) bool`)
diff, count = args.Diff([]interface{}{"string", false, true})
assert.Equal(t, 1, count)
assert.Contains(t, diff, `%!s(bool=false) not matched by func(int) bool`)
assert.Contains(t, diff, `(bool=false) not matched by func(int) bool`)
diff, count = args.Diff([]interface{}{"string", 123, false})
assert.Contains(t, diff, `%!s(int=123) matched by func(int) bool`)
assert.Contains(t, diff, `(int=123) matched by func(int) bool`)
diff, count = args.Diff([]interface{}{"string", 123, true})
assert.Equal(t, 0, count)
@ -1260,7 +1323,7 @@ func Test_Arguments_Bool(t *testing.T) {
func Test_WaitUntil_Parallel(t *testing.T) {
// make a test impl object
var mockedService *TestExampleImplementation = new(TestExampleImplementation)
var mockedService = new(TestExampleImplementation)
ch1 := make(chan time.Time)
ch2 := make(chan time.Time)
@ -1323,6 +1386,37 @@ func (s *timer) GetTime(i int) string {
return s.Called(i).Get(0).(string)
}
type tCustomLogger struct {
*testing.T
logs []string
errs []string
}
func (tc *tCustomLogger) Logf(format string, args ...interface{}) {
tc.T.Logf(format, args...)
tc.logs = append(tc.logs, fmt.Sprintf(format, args...))
}
func (tc *tCustomLogger) Errorf(format string, args ...interface{}) {
tc.errs = append(tc.errs, fmt.Sprintf(format, args...))
}
func (tc *tCustomLogger) FailNow() {}
func TestLoggingAssertExpectations(t *testing.T) {
m := new(timer)
m.On("GetTime", 0).Return("")
tcl := &tCustomLogger{t, []string{}, []string{}}
AssertExpectationsForObjects(tcl, m, new(TestExampleImplementation))
require.Equal(t, 1, len(tcl.errs))
assert.Regexp(t, regexp.MustCompile("(?s)FAIL: 0 out of 1 expectation\\(s\\) were met.*The code you are testing needs to make 1 more call\\(s\\).*"), tcl.errs[0])
require.Equal(t, 2, len(tcl.logs))
assert.Regexp(t, regexp.MustCompile("(?s)FAIL:\tGetTime\\(int\\).*"), tcl.logs[0])
require.Equal(t, "Expectations didn't match for Mock: *mock.timer", tcl.logs[1])
}
func TestAfterTotalWaitTimeWhileExecution(t *testing.T) {
waitDuration := 1
total, waitMs := 5, time.Millisecond*time.Duration(waitDuration)
@ -1342,11 +1436,64 @@ func TestAfterTotalWaitTimeWhileExecution(t *testing.T) {
elapsedTime := end.Sub(start)
assert.True(t, elapsedTime > waitMs, fmt.Sprintf("Total elapsed time:%v should be atleast greater than %v", elapsedTime, waitMs))
assert.Equal(t, total, len(results))
for i, _ := range results {
for i := range results {
assert.Equal(t, fmt.Sprintf("Time%d", i), results[i], "Return value of method should be same")
}
}
func TestArgumentMatcherToPrintMismatch(t *testing.T) {
defer func() {
if r := recover(); r != nil {
matchingExp := regexp.MustCompile(
`\s+mock: Unexpected Method Call\s+-*\s+GetTime\(int\)\s+0: 1\s+The closest call I have is:\s+GetTime\(mock.argumentMatcher\)\s+0: mock.argumentMatcher\{.*?\}\s+Diff:.*\(int=1\) not matched by func\(int\) bool`)
assert.Regexp(t, matchingExp, r)
}
}()
m := new(timer)
m.On("GetTime", MatchedBy(func(i int) bool { return false })).Return("SomeTime").Once()
res := m.GetTime(1)
require.Equal(t, "SomeTime", res)
m.AssertExpectations(t)
}
func TestClosestCallMismatchedArgumentInformationShowsTheClosest(t *testing.T) {
defer func() {
if r := recover(); r != nil {
matchingExp := regexp.MustCompile(unexpectedCallRegex(`TheExampleMethod(int,int,int)`, `0: 1\s+1: 1\s+2: 2`, `0: 1\s+1: 1\s+2: 1`, `0: PASS: \(int=1\) == \(int=1\)\s+1: PASS: \(int=1\) == \(int=1\)\s+2: FAIL: \(int=2\) != \(int=1\)`))
assert.Regexp(t, matchingExp, r)
}
}()
m := new(TestExampleImplementation)
m.On("TheExampleMethod", 1, 1, 1).Return(1, nil).Once()
m.On("TheExampleMethod", 2, 2, 2).Return(2, nil).Once()
m.TheExampleMethod(1, 1, 2)
}
func TestClosestCallMismatchedArgumentValueInformation(t *testing.T) {
defer func() {
if r := recover(); r != nil {
matchingExp := regexp.MustCompile(unexpectedCallRegex(`GetTime(int)`, "0: 1", "0: 999", `0: FAIL: \(int=1\) != \(int=999\)`))
assert.Regexp(t, matchingExp, r)
}
}()
m := new(timer)
m.On("GetTime", 999).Return("SomeTime").Once()
_ = m.GetTime(1)
}
func unexpectedCallRegex(method, calledArg, expectedArg, diff string) string {
rMethod := regexp.QuoteMeta(method)
return fmt.Sprintf(`\s+mock: Unexpected Method Call\s+-*\s+%s\s+%s\s+The closest call I have is:\s+%s\s+%s\s+Diff: %s`,
rMethod, calledArg, rMethod, expectedArg, diff)
}
//go:noinline
func ConcurrencyTestMethod(m *Mock) {
m.Called()
}