github.com/go-graphite/carbonapi@v0.17.0/cmd/carbonapi/http/main_test.go (about) 1 package http 2 3 import ( 4 "context" 5 "encoding/json" 6 "math" 7 "net/http" 8 "net/http/httptest" 9 "testing" 10 11 "github.com/ansel1/merry" 12 "github.com/go-graphite/carbonapi/cmd/carbonapi/config" 13 "github.com/go-graphite/carbonapi/expr/types" 14 zipperTypes "github.com/go-graphite/carbonapi/zipper/types" 15 pb "github.com/go-graphite/protocol/carbonapi_v3_pb" 16 "github.com/lomik/zapwriter" 17 "github.com/stretchr/testify/assert" 18 ) 19 20 type mockCarbonZipper struct{} 21 22 func newMockCarbonZipper() *mockCarbonZipper { 23 return new(mockCarbonZipper) 24 } 25 26 func (z mockCarbonZipper) Find(ctx context.Context, request pb.MultiGlobRequest) (*pb.MultiGlobResponse, *zipperTypes.Stats, merry.Error) { 27 return getGlobResponse(), nil, nil 28 } 29 30 func (z mockCarbonZipper) Info(ctx context.Context, metrics []string) (*pb.ZipperInfoResponse, *zipperTypes.Stats, merry.Error) { 31 response := getMockInfoResponse() 32 33 return response, nil, nil 34 } 35 36 func (z mockCarbonZipper) Render(ctx context.Context, request pb.MultiFetchRequest) ([]*types.MetricData, *zipperTypes.Stats, merry.Error) { 37 return z.RenderCompat(ctx, []string{""}, 0, 0) 38 } 39 40 func (z mockCarbonZipper) RenderCompat(ctx context.Context, metrics []string, from, until int64) ([]*types.MetricData, *zipperTypes.Stats, merry.Error) { 41 var result []*types.MetricData 42 multiFetchResponse := getMultiFetchResponse() 43 result = append(result, &types.MetricData{FetchResponse: multiFetchResponse.Metrics[0]}) 44 return result, nil, nil 45 } 46 47 func (z mockCarbonZipper) TagNames(ctx context.Context, query string, limit int64) ([]string, merry.Error) { 48 return []string{}, nil 49 } 50 51 func (z mockCarbonZipper) TagValues(ctx context.Context, query string, limit int64) ([]string, merry.Error) { 52 return []string{}, nil 53 } 54 55 func (z mockCarbonZipper) ScaleToCommonStep() bool { 56 return true 57 } 58 59 func getGlobResponse() *pb.MultiGlobResponse { 60 globMtach := pb.GlobMatch{Path: "foo.bar", IsLeaf: true} 61 var matches []pb.GlobMatch 62 matches = append(matches, globMtach) 63 globResponse := &pb.MultiGlobResponse{ 64 Metrics: []pb.GlobResponse{ 65 { 66 Name: "foo.bar", 67 Matches: matches, 68 }, 69 }, 70 } 71 return globResponse 72 } 73 74 func getMultiFetchResponse() pb.MultiFetchResponse { 75 mfr := pb.FetchResponse{ 76 Name: "foo.bar", 77 PathExpression: "foo.bar", 78 StartTime: 1510913280, 79 StopTime: 1510913880, 80 StepTime: 60, 81 Values: []float64{math.NaN(), 1510913759, 1510913818}, 82 } 83 84 result := pb.MultiFetchResponse{Metrics: []pb.FetchResponse{mfr}} 85 return result 86 } 87 88 func getMockInfoResponse() *pb.ZipperInfoResponse { 89 r := pb.Retention{ 90 SecondsPerPoint: 60, 91 NumberOfPoints: 43200, 92 } 93 decoded := &pb.ZipperInfoResponse{ 94 Info: map[string]pb.MultiMetricsInfoResponse{ 95 "http://127.0.0.1:8080": { 96 Metrics: []pb.MetricsInfoResponse{{ 97 Name: "foo.bar", 98 ConsolidationFunc: "average", 99 MaxRetention: 157680000, 100 XFilesFactor: 0.5, 101 Retentions: []pb.Retention{r}, 102 }}, 103 }, 104 }, 105 } 106 107 return decoded 108 } 109 110 func init() { 111 cfg := config.DefaultLoggerConfig 112 cfg.Level = "debug" 113 zapwriter.ApplyConfig([]zapwriter.Config{cfg}) 114 logger := zapwriter.Logger("main") 115 116 cfgFile := "" 117 config.SetUpViper(logger, &cfgFile, false, "CARBONAPI_") 118 config.Config.Upstreams.Backends = []string{"dummy"} 119 config.SetUpConfigUpstreams(logger) 120 config.SetUpConfig(logger, "(test)") 121 config.Config.SetZipper(newMockCarbonZipper()) 122 emptyStringList := make([]string, 0) 123 InitHandlers(emptyStringList, emptyStringList) 124 } 125 126 func setUpRequest(t *testing.T, url string) (*http.Request, *httptest.ResponseRecorder) { 127 req, err := http.NewRequest("GET", url, nil) 128 if err != nil { 129 t.Fatal(err) 130 } 131 132 // We create a ResponseRecorder (which satisfies http.ResponseWriter) to record the response. 133 rr := httptest.NewRecorder() 134 return req, rr 135 } 136 137 func TestRenderHandler(t *testing.T) { 138 req, rr := setUpRequest(t, "/render/?target=fallbackSeries(foo.bar,foo.baz)&from=-10minutes&format=json") 139 renderHandler(rr, req) 140 141 expected := `[{"target":"foo.bar","datapoints":[[null,1510913280],[1510913759,1510913340],[1510913818,1510913400]],"tags":{}}]` 142 143 // Check the status code is what we expect. 144 r := assert.Equal(t, rr.Code, http.StatusOK, "HttpStatusCode should be 200 OK.") 145 if !r { 146 t.Error("HttpStatusCode should be 200 OK.") 147 } 148 r = assert.Equal(t, expected, rr.Body.String(), "Http response should be same.") 149 if !r { 150 t.Error("Http response should be same.") 151 } 152 } 153 154 func TestFindHandler(t *testing.T) { 155 req, rr := setUpRequest(t, "/metrics/find/?query=foo.bar&format=json") 156 findHandler(rr, req) 157 158 body := rr.Body.String() 159 expected := `[{"allowChildren":0,"expandable":0,"leaf":1,"id":"foo.bar","text":"bar","context":{}}]` + "\n" 160 r := assert.Equal(t, rr.Code, http.StatusOK, "HttpStatusCode should be 200 OK.") 161 if !r { 162 t.Error("HttpStatusCode should be 200 OK.") 163 } 164 r = assert.Equal(t, expected, body, "Http response should be same.") 165 if !r { 166 t.Error("Http response should be same.") 167 } 168 } 169 170 func TestInfoHandler(t *testing.T) { 171 req, rr := setUpRequest(t, "/info/?target=foo.bar&format=json") 172 infoHandler(rr, req) 173 174 body := rr.Body.String() 175 expected := getMockInfoResponse() 176 expectedJson, err := json.Marshal(expected) 177 r := assert.Nil(t, err) 178 if !r { 179 t.Errorf("err should be nil, %v instead", err) 180 } 181 182 r = assert.Equal(t, rr.Code, http.StatusOK, "HttpStatusCode should be 200 OK.") 183 if !r { 184 t.Error("Http response should be same.") 185 } 186 r = assert.Equal(t, string(expectedJson), body, "Http response should be same.") 187 if !r { 188 t.Error("Http response should be same.") 189 } 190 }