github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/querier/queryrange/stats_test.go (about) 1 package queryrange 2 3 import ( 4 "context" 5 "fmt" 6 "net/http" 7 "net/http/httptest" 8 strings "strings" 9 "testing" 10 "time" 11 12 "github.com/stretchr/testify/require" 13 14 "github.com/grafana/loki/pkg/logproto" 15 "github.com/grafana/loki/pkg/logqlmodel/stats" 16 "github.com/grafana/loki/pkg/querier/queryrange/queryrangebase" 17 ) 18 19 func TestStatsCollectorMiddleware(t *testing.T) { 20 // no stats 21 var ( 22 data = &queryData{} 23 now = time.Now() 24 ) 25 ctx := context.WithValue(context.Background(), ctxKey, data) 26 _, _ = StatsCollectorMiddleware().Wrap(queryrangebase.HandlerFunc(func(ctx context.Context, r queryrangebase.Request) (queryrangebase.Response, error) { 27 return nil, nil 28 })).Do(ctx, &LokiRequest{ 29 Query: "foo", 30 StartTs: now, 31 }) 32 require.Equal(t, "foo", data.params.Query()) 33 require.Equal(t, true, data.recorded) 34 require.Equal(t, now, data.params.Start()) 35 require.Nil(t, data.statistics) 36 37 // no context. 38 data = &queryData{} 39 _, _ = StatsCollectorMiddleware().Wrap(queryrangebase.HandlerFunc(func(ctx context.Context, r queryrangebase.Request) (queryrangebase.Response, error) { 40 return nil, nil 41 })).Do(context.Background(), &LokiRequest{ 42 Query: "foo", 43 StartTs: now, 44 }) 45 require.Equal(t, false, data.recorded) 46 47 // stats 48 data = &queryData{} 49 ctx = context.WithValue(context.Background(), ctxKey, data) 50 _, _ = StatsCollectorMiddleware().Wrap(queryrangebase.HandlerFunc(func(ctx context.Context, r queryrangebase.Request) (queryrangebase.Response, error) { 51 return &LokiPromResponse{ 52 Statistics: stats.Result{ 53 Ingester: stats.Ingester{ 54 TotalReached: 10, 55 }, 56 }, 57 }, nil 58 })).Do(ctx, &LokiRequest{ 59 Query: "foo", 60 StartTs: now, 61 }) 62 require.Equal(t, "foo", data.params.Query()) 63 require.Equal(t, true, data.recorded) 64 require.Equal(t, now, data.params.Start()) 65 require.Equal(t, int32(10), data.statistics.Ingester.TotalReached) 66 } 67 68 func Test_StatsHTTP(t *testing.T) { 69 for _, test := range []struct { 70 name string 71 next http.Handler 72 expect func(t *testing.T, data *queryData) 73 }{ 74 { 75 "should not record metric if nothing is recorded", 76 http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 77 data := r.Context().Value(ctxKey).(*queryData) 78 data.recorded = false 79 }), 80 func(t *testing.T, data *queryData) { 81 t.Fail() 82 }, 83 }, 84 { 85 "empty statistics success", 86 http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 87 data := r.Context().Value(ctxKey).(*queryData) 88 data.recorded = true 89 data.params, _ = paramsFromRequest(&LokiRequest{ 90 Query: "foo", 91 Direction: logproto.BACKWARD, 92 Limit: 100, 93 }) 94 data.statistics = nil 95 }), 96 func(t *testing.T, data *queryData) { 97 require.Equal(t, fmt.Sprintf("%d", http.StatusOK), data.status) 98 require.Equal(t, "foo", data.params.Query()) 99 require.Equal(t, logproto.BACKWARD, data.params.Direction()) 100 require.Equal(t, uint32(100), data.params.Limit()) 101 require.Equal(t, stats.Result{}, *data.statistics) 102 }, 103 }, 104 { 105 "statuscode", 106 http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 107 data := r.Context().Value(ctxKey).(*queryData) 108 data.recorded = true 109 data.params, _ = paramsFromRequest(&LokiRequest{ 110 Query: "foo", 111 Direction: logproto.BACKWARD, 112 Limit: 100, 113 }) 114 data.statistics = &statsResult 115 w.WriteHeader(http.StatusTeapot) 116 }), 117 func(t *testing.T, data *queryData) { 118 require.Equal(t, fmt.Sprintf("%d", http.StatusTeapot), data.status) 119 require.Equal(t, "foo", data.params.Query()) 120 require.Equal(t, logproto.BACKWARD, data.params.Direction()) 121 require.Equal(t, uint32(100), data.params.Limit()) 122 require.Equal(t, statsResult, *data.statistics) 123 }, 124 }, 125 { 126 "result", 127 http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 128 data := r.Context().Value(ctxKey).(*queryData) 129 data.recorded = true 130 data.params, _ = paramsFromRequest(&LokiRequest{ 131 Query: "foo", 132 Direction: logproto.BACKWARD, 133 Limit: 100, 134 }) 135 data.statistics = &statsResult 136 data.result = streams 137 w.WriteHeader(http.StatusTeapot) 138 }), 139 func(t *testing.T, data *queryData) { 140 require.Equal(t, fmt.Sprintf("%d", http.StatusTeapot), data.status) 141 require.Equal(t, "foo", data.params.Query()) 142 require.Equal(t, logproto.BACKWARD, data.params.Direction()) 143 require.Equal(t, uint32(100), data.params.Limit()) 144 require.Equal(t, statsResult, *data.statistics) 145 require.Equal(t, streams, data.result) 146 }, 147 }, 148 } { 149 t.Run(test.name, func(t *testing.T) { 150 statsHTTPMiddleware(metricRecorderFn(func(data *queryData) { 151 test.expect(t, data) 152 })).Wrap(test.next).ServeHTTP(httptest.NewRecorder(), httptest.NewRequest("GET", "/foo", strings.NewReader(""))) 153 }) 154 } 155 } 156 157 func Test_StatsUpdateResult(t *testing.T) { 158 resp, err := StatsCollectorMiddleware().Wrap(queryrangebase.HandlerFunc(func(c context.Context, r queryrangebase.Request) (queryrangebase.Response, error) { 159 time.Sleep(20 * time.Millisecond) 160 return &LokiResponse{}, nil 161 })).Do(context.Background(), &LokiRequest{ 162 Query: "foo", 163 EndTs: time.Now(), 164 }) 165 require.NoError(t, err) 166 require.GreaterOrEqual(t, resp.(*LokiResponse).Statistics.Summary.ExecTime, (20 * time.Millisecond).Seconds()) 167 }