...
1
18
19
20 package grpctest
21
22 import (
23 "reflect"
24 "strings"
25 "sync/atomic"
26 "testing"
27
28 "google.golang.org/grpc/internal/leakcheck"
29 )
30
31 var lcFailed uint32
32
33 type errorer struct {
34 t *testing.T
35 }
36
37 func (e errorer) Errorf(format string, args ...any) {
38 atomic.StoreUint32(&lcFailed, 1)
39 e.t.Errorf(format, args...)
40 }
41
42
43
44
45
46 type Tester struct{}
47
48
49 func (Tester) Setup(t *testing.T) {
50 TLogger.Update(t)
51 }
52
53
54 func (Tester) Teardown(t *testing.T) {
55 if atomic.LoadUint32(&lcFailed) == 1 {
56 return
57 }
58 leakcheck.Check(errorer{t: t})
59 if atomic.LoadUint32(&lcFailed) == 1 {
60 t.Log("Leak check disabled for future tests")
61 }
62 TLogger.EndTest(t)
63 }
64
65
66 type Interface interface {
67 Setup(*testing.T)
68 Teardown(*testing.T)
69 }
70
71 func getTestFunc(t *testing.T, xv reflect.Value, name string) func(*testing.T) {
72 if m := xv.MethodByName(name); m.IsValid() {
73 if f, ok := m.Interface().(func(*testing.T)); ok {
74 return f
75 }
76
77 t.Fatalf("grpctest: function %v has unexpected signature (%T)", name, m.Interface())
78 }
79 return func(*testing.T) {}
80 }
81
82
83
84
85
86
87
88
89
90
91
92
93 func RunSubTests(t *testing.T, x Interface) {
94 xt := reflect.TypeOf(x)
95 xv := reflect.ValueOf(x)
96
97 for i := 0; i < xt.NumMethod(); i++ {
98 methodName := xt.Method(i).Name
99 if !strings.HasPrefix(methodName, "Test") {
100 continue
101 }
102 tfunc := getTestFunc(t, xv, methodName)
103 t.Run(strings.TrimPrefix(methodName, "Test"), func(t *testing.T) {
104
105
106
107
108
109 t.Cleanup(func() { x.Teardown(t) })
110 x.Setup(t)
111 tfunc(t)
112 })
113 }
114 }
115
View as plain text