github.com/letsencrypt/trillian@v1.1.2-0.20180615153820-ae375a99d36a/monitoring/rpc_stats_interceptor_test.go (about)

     1  // Copyright 2016 Google Inc. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package monitoring_test
    16  
    17  import (
    18  	"context"
    19  	"errors"
    20  	"fmt"
    21  	"testing"
    22  	"time"
    23  
    24  	"github.com/google/trillian/monitoring"
    25  	"github.com/google/trillian/util"
    26  	"google.golang.org/grpc"
    27  )
    28  
    29  // Arbitrary time for use in tests
    30  var fakeTime = time.Date(2016, 10, 3, 12, 38, 27, 36, time.UTC)
    31  
    32  type recordingUnaryHandler struct {
    33  	// ctx and req are recorded on invocation
    34  	ctx context.Context
    35  	req interface{}
    36  	// rsp and err are returned on invocation
    37  	rsp interface{}
    38  	err error
    39  }
    40  
    41  func (r recordingUnaryHandler) handler() grpc.UnaryHandler {
    42  	return func(ctx context.Context, req interface{}) (interface{}, error) {
    43  		r.ctx = ctx
    44  		r.req = req
    45  		return r.rsp, r.err
    46  	}
    47  }
    48  
    49  func TestSingleRequests(t *testing.T) {
    50  	var tests = []struct {
    51  		name       string
    52  		method     string
    53  		handler    recordingUnaryHandler
    54  		timeSource util.IncrementingFakeTimeSource
    55  	}{
    56  		// This is an OK request with 500ms latency
    57  		{
    58  			name:    "ok_request",
    59  			method:  "getmethod",
    60  			handler: recordingUnaryHandler{req: "OK", err: nil},
    61  			timeSource: util.IncrementingFakeTimeSource{
    62  				BaseTime:   fakeTime,
    63  				Increments: []time.Duration{0, time.Millisecond * 500},
    64  			},
    65  		},
    66  		// This is an errored request with 3000ms latency
    67  		{
    68  			name:    "error_request",
    69  			method:  "setmethod",
    70  			handler: recordingUnaryHandler{err: errors.New("bang")},
    71  			timeSource: util.IncrementingFakeTimeSource{
    72  				BaseTime:   fakeTime,
    73  				Increments: []time.Duration{0, time.Millisecond * 3000},
    74  			},
    75  		},
    76  	}
    77  
    78  	for _, test := range tests {
    79  		prefix := fmt.Sprintf("test_%s", test.name)
    80  		stats := monitoring.NewRPCStatsInterceptor(&test.timeSource, prefix, monitoring.InertMetricFactory{})
    81  		i := stats.Interceptor()
    82  
    83  		// Invoke the test handler wrapped by the interceptor.
    84  		got, err := i(context.Background(), "wibble", &grpc.UnaryServerInfo{FullMethod: test.method}, test.handler.handler())
    85  
    86  		// Check the interceptor passed through the results.
    87  		if got != test.handler.rsp || (err != nil) != (test.handler.err != nil) {
    88  			t.Errorf("interceptor(%s)=%v,%v; want %v,%v", test.name, got, err, test.handler.rsp, test.handler.err)
    89  		}
    90  
    91  		// Now check the resulting state of the metrics.
    92  		if got, want := stats.ReqCount.Value(test.method), 1.0; got != want {
    93  			t.Errorf("stats.ReqCount=%v; want %v", got, want)
    94  		}
    95  		wantLatency := test.timeSource.Increments[1].Seconds()
    96  		wantErrors := 0.0
    97  		wantSuccess := 0.0
    98  		if test.handler.err == nil {
    99  			wantSuccess = 1.0
   100  		} else {
   101  			wantErrors = 1.0
   102  		}
   103  		if got := stats.ReqSuccessCount.Value(test.method); got != wantSuccess {
   104  			t.Errorf("stats.ReqSuccessCount=%v; want %v", got, wantSuccess)
   105  		}
   106  		if got := stats.ReqErrorCount.Value(test.method); got != wantErrors {
   107  			t.Errorf("stats.ReqErrorCount=%v; want %v", got, wantSuccess)
   108  		}
   109  
   110  		if gotCount, gotSum := stats.ReqSuccessLatency.Info(test.method); gotCount != uint64(wantSuccess) {
   111  			t.Errorf("stats.ReqSuccessLatency.Count=%v; want %v", gotCount, wantSuccess)
   112  		} else if gotSum != wantLatency*wantSuccess {
   113  			t.Errorf("stats.ReqSuccessLatency.Sum=%v; want %v", gotSum, wantLatency*wantSuccess)
   114  		}
   115  		if gotCount, gotSum := stats.ReqErrorLatency.Info(test.method); gotCount != uint64(wantErrors) {
   116  			t.Errorf("stats.ReqErrorLatency.Count=%v; want %v", gotCount, wantErrors)
   117  		} else if gotSum != wantLatency*wantErrors {
   118  			t.Errorf("stats.ReqErrorLatency.Sum=%v; want %v", gotSum, wantLatency*wantErrors)
   119  		}
   120  	}
   121  }
   122  
   123  func TestMultipleOKRequestsTotalLatency(t *testing.T) {
   124  	// We're going to make 3 requests so set up the time source appropriately
   125  	ts := util.IncrementingFakeTimeSource{
   126  		BaseTime: fakeTime,
   127  		Increments: []time.Duration{
   128  			0,
   129  			time.Millisecond * 500,
   130  			0,
   131  			time.Millisecond * 2000,
   132  			0,
   133  			time.Millisecond * 1337,
   134  		},
   135  	}
   136  	handler := recordingUnaryHandler{rsp: "OK", err: nil}
   137  	stats := monitoring.NewRPCStatsInterceptor(&ts, "test_multi_ok", monitoring.InertMetricFactory{})
   138  	i := stats.Interceptor()
   139  
   140  	for r := 0; r < 3; r++ {
   141  		rsp, err := i(context.Background(), "wibble", &grpc.UnaryServerInfo{FullMethod: "testmethod"}, handler.handler())
   142  		if rsp != "OK" || err != nil {
   143  			t.Fatalf("interceptor()=%v,%v; want 'OK',nil", rsp, err)
   144  		}
   145  	}
   146  	count, sum := stats.ReqSuccessLatency.Info("testmethod")
   147  	if wantCount, wantSum := uint64(3), time.Duration(3837*time.Millisecond).Seconds(); count != wantCount || sum != wantSum {
   148  		t.Errorf("stats.ReqSuccessLatency.Info=%v,%v; want %v,%v", count, sum, wantCount, wantSum)
   149  	}
   150  }
   151  
   152  func TestMultipleErrorRequestsTotalLatency(t *testing.T) {
   153  	// We're going to make 3 requests so set up the time source appropriately
   154  	ts := util.IncrementingFakeTimeSource{
   155  		BaseTime: fakeTime,
   156  		Increments: []time.Duration{
   157  			0,
   158  			time.Millisecond * 427,
   159  			0,
   160  			time.Millisecond * 1066,
   161  			0,
   162  			time.Millisecond * 1123,
   163  		},
   164  	}
   165  	handler := recordingUnaryHandler{rsp: "", err: errors.New("bang")}
   166  	stats := monitoring.NewRPCStatsInterceptor(&ts, "test_multi_err", monitoring.InertMetricFactory{})
   167  	i := stats.Interceptor()
   168  
   169  	for r := 0; r < 3; r++ {
   170  		_, err := i(context.Background(), "wibble", &grpc.UnaryServerInfo{FullMethod: "testmethod"}, handler.handler())
   171  		if err == nil {
   172  			t.Fatalf("interceptor()=_,%v; want _,'bang'", err)
   173  		}
   174  	}
   175  
   176  	count, sum := stats.ReqErrorLatency.Info("testmethod")
   177  	if wantCount, wantSum := uint64(3), 2.6160; count != wantCount || sum != wantSum {
   178  		t.Errorf("stats.ReqSuccessLatency.Info=%v,%v; want %v,%v", count, sum, wantCount, wantSum)
   179  	}
   180  }