github.com/yandex/pandora@v0.5.32/lib/testutil/matchers.go (about) 1 package testutil 2 3 import ( 4 "fmt" 5 "testing" 6 7 "github.com/stretchr/testify/mock" 8 "go.uber.org/atomic" 9 ) 10 11 type TestingT interface { 12 mock.TestingT 13 } 14 15 type flakyT struct { 16 t *testing.T 17 failed atomic.Bool 18 } 19 20 var _ TestingT = &flakyT{} 21 22 func (ff *flakyT) Logf(format string, args ...interface{}) { 23 getHelper(ff.t).Helper() 24 ff.t.Logf(format, args...) 25 } 26 27 func (ff *flakyT) Errorf(format string, args ...interface{}) { 28 getHelper(ff.t).Helper() 29 ff.t.Logf(format, args...) 30 ff.failed.Store(true) 31 } 32 33 func (ff *flakyT) FailNow() { 34 // WARN: that may not work in complex case. 35 panic("Failing now!") 36 } 37 38 func RunFlaky(t *testing.T, test func(t TestingT)) { 39 const retries = 5 40 var passed bool 41 for i := 1; i <= retries && !passed; i++ { 42 t.Run(fmt.Sprintf("Retry_%v", i), func(t *testing.T) { 43 if i == retries { 44 t.Log("Last retry.") 45 test(t) 46 return 47 } 48 ff := &flakyT{t: t} 49 50 var hasPanic bool 51 func() { 52 defer func() { 53 hasPanic = recover() != nil 54 }() 55 test(ff) 56 }() 57 58 passed = !ff.failed.Load() && !hasPanic 59 if passed { 60 t.Log("Passed!") 61 } else { 62 t.Log("Failed! Retrying.") 63 } 64 }) 65 } 66 } 67 68 // getHelper allows to call t.Helper() without breaking compatibility with go version < 1.9 69 func getHelper(t TestingT) helper { 70 var tInterface interface{} = t 71 if h, ok := tInterface.(helper); ok { 72 return h 73 } 74 return nopHelper{} 75 } 76 77 type nopHelper struct{} 78 79 func (nopHelper) Helper() {} 80 81 type helper interface { 82 Helper() 83 }