2121package metrics
2222
2323import (
24+ "fmt"
2425 "io"
2526 "reflect"
27+ "strings"
2628 "testing"
2729 "time"
2830
2931 "github.com/golang/mock/gomock"
3032 "github.com/stretchr/testify/require"
33+ "github.com/uber-go/tally"
3134 "github.com/uber/tchannel-go/thrift"
3235 "go.uber.org/cadence/.gen/go/cadence/workflowserviceclient"
3336 "go.uber.org/cadence/.gen/go/cadence/workflowservicetest"
3437 s "go.uber.org/cadence/.gen/go/shared"
3538 "go.uber.org/yarpc"
3639)
3740
41+ var (
42+ safeCharacters = []rune {'_' }
43+
44+ sanitizeOptions = tally.SanitizeOptions {
45+ NameCharacters : tally.ValidCharacters {
46+ Ranges : tally .AlphanumericRange ,
47+ Characters : safeCharacters ,
48+ },
49+ KeyCharacters : tally.ValidCharacters {
50+ Ranges : tally .AlphanumericRange ,
51+ Characters : safeCharacters ,
52+ },
53+ ValueCharacters : tally.ValidCharacters {
54+ Ranges : tally .AlphanumericRange ,
55+ Characters : safeCharacters ,
56+ },
57+ ReplacementCharacter : tally .DefaultReplacementCharacter ,
58+ }
59+ )
60+
3861type testCase struct {
3962 serviceMethod string
4063 callArgs []interface {}
@@ -44,7 +67,6 @@ type testCase struct {
4467
4568func Test_Wrapper (t * testing.T ) {
4669 ctx , _ := thrift .NewContext (time .Minute )
47- callOption := yarpc.CallOption {}
4870 tests := []testCase {
4971 // one case for each service call
5072 {"DeprecateDomain" , []interface {}{ctx , & s.DeprecateDomainRequest {}}, []interface {}{nil }, []string {CadenceRequest }},
@@ -77,9 +99,22 @@ func Test_Wrapper(t *testing.T) {
7799 {"RespondQueryTaskCompleted" , []interface {}{ctx , & s.RespondQueryTaskCompletedRequest {}}, []interface {}{& s.InternalServiceError {}}, []string {CadenceRequest , CadenceError }},
78100 }
79101
102+ // run each test twice - once with the regular scope, once with a sanitized metrics scope
80103 for _ , test := range tests {
81- mockService , wrapperService , closer , reporter := newService (t )
104+ runTest (t , test , newService , assertMetrics , fmt .Sprintf ("%v_normal" , test .serviceMethod ))
105+ runTest (t , test , newPromService , assertPromMetrics , fmt .Sprintf ("%v_prom_sanitized" , test .serviceMethod ))
106+ }
107+ }
82108
109+ func runTest (
110+ t * testing.T ,
111+ test testCase ,
112+ serviceFunc func (* testing.T ) (* workflowservicetest.MockClient , workflowserviceclient.Interface , io.Closer , * CapturingStatsReporter ),
113+ validationFunc func (* testing.T , * CapturingStatsReporter , string , []string ),
114+ name string ,
115+ ) {
116+ t .Run (name , func (t * testing.T ) {
117+ mockService , wrapperService , closer , reporter := serviceFunc (t )
83118 switch test .serviceMethod {
84119 case "DeprecateDomain" :
85120 mockService .EXPECT ().DeprecateDomain (gomock .Any (), gomock .Any (), gomock .Any ()).Return (test .mockReturns ... )
@@ -135,6 +170,7 @@ func Test_Wrapper(t *testing.T) {
135170 mockService .EXPECT ().RespondQueryTaskCompleted (gomock .Any (), gomock .Any (), gomock .Any ()).Return (test .mockReturns ... )
136171 }
137172
173+ callOption := yarpc.CallOption {}
138174 inputs := make ([]reflect.Value , len (test .callArgs ))
139175 for i , arg := range test .callArgs {
140176 inputs [i ] = reflect .ValueOf (arg )
@@ -143,8 +179,8 @@ func Test_Wrapper(t *testing.T) {
143179 method := reflect .ValueOf (wrapperService ).MethodByName (test .serviceMethod )
144180 method .Call (inputs )
145181 closer .Close ()
146- assertMetrics (t , reporter , test .serviceMethod , test .expectedCounters )
147- }
182+ validationFunc (t , reporter , test .serviceMethod , test .expectedCounters )
183+ })
148184}
149185
150186func assertMetrics (t * testing.T , reporter * CapturingStatsReporter , methodName string , counterNames []string ) {
@@ -165,7 +201,33 @@ func assertMetrics(t *testing.T, reporter *CapturingStatsReporter, methodName st
165201 require .Equal (t , CadenceMetricsPrefix + methodName + "." + CadenceLatency , reporter .timers [0 ].name )
166202}
167203
168- func newService (t * testing.T ) (mockService * workflowservicetest.MockClient ,
204+ func assertPromMetrics (t * testing.T , reporter * CapturingStatsReporter , methodName string , counterNames []string ) {
205+ require .Equal (t , len (counterNames ), len (reporter .counts ))
206+ for _ , name := range counterNames {
207+ counterName := makePromCompatible (CadenceMetricsPrefix + methodName + "." + name )
208+ find := false
209+ // counters are not in order
210+ for _ , counter := range reporter .counts {
211+ if counterName == counter .name {
212+ find = true
213+ break
214+ }
215+ }
216+ require .True (t , find )
217+ }
218+ require .Equal (t , 1 , len (reporter .timers ))
219+ expected := makePromCompatible (CadenceMetricsPrefix + methodName + "." + CadenceLatency )
220+ require .Equal (t , expected , reporter .timers [0 ].name )
221+ }
222+
223+ func makePromCompatible (name string ) string {
224+ name = strings .Replace (name , "-" , "_" , - 1 )
225+ name = strings .Replace (name , "." , "_" , - 1 )
226+ return name
227+ }
228+
229+ func newService (t * testing.T ) (
230+ mockService * workflowservicetest.MockClient ,
169231 wrapperService workflowserviceclient.Interface ,
170232 closer io.Closer ,
171233 reporter * CapturingStatsReporter ,
@@ -177,3 +239,27 @@ func newService(t *testing.T) (mockService *workflowservicetest.MockClient,
177239 wrapperService = NewWorkflowServiceWrapper (mockService , scope )
178240 return
179241}
242+
243+ func newPromService (t * testing.T ) (
244+ mockService * workflowservicetest.MockClient ,
245+ wrapperService workflowserviceclient.Interface ,
246+ closer io.Closer ,
247+ reporter * CapturingStatsReporter ,
248+ ) {
249+ mockCtrl := gomock .NewController (t )
250+ mockService = workflowservicetest .NewMockClient (mockCtrl )
251+ isReplay := false
252+ scope , closer , reporter := newPromScope (& isReplay )
253+ wrapperService = NewWorkflowServiceWrapper (mockService , scope )
254+ return
255+ }
256+
257+ func newPromScope (isReplay * bool ) (tally.Scope , io.Closer , * CapturingStatsReporter ) {
258+ reporter := & CapturingStatsReporter {}
259+ opts := tally.ScopeOptions {
260+ Reporter : reporter ,
261+ SanitizeOptions : & sanitizeOptions ,
262+ }
263+ scope , closer := tally .NewRootScope (opts , time .Second )
264+ return WrapScope (isReplay , scope , & realClock {}), closer , reporter
265+ }
0 commit comments