github.com/m3db/m3@v1.5.0/src/query/api/v1/handler/search_test.go (about) 1 // Copyright (c) 2018 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package handler 22 23 import ( 24 "bytes" 25 "context" 26 "encoding/json" 27 "fmt" 28 "io" 29 "net/http" 30 "net/http/httptest" 31 "testing" 32 "time" 33 34 "github.com/m3db/m3/src/dbnode/client" 35 "github.com/m3db/m3/src/query/api/v1/handler/prometheus/handleroptions" 36 "github.com/m3db/m3/src/query/api/v1/options" 37 "github.com/m3db/m3/src/query/models" 38 "github.com/m3db/m3/src/query/storage" 39 "github.com/m3db/m3/src/query/test" 40 "github.com/m3db/m3/src/query/test/m3" 41 "github.com/m3db/m3/src/query/test/seriesiter" 42 "github.com/m3db/m3/src/x/ident" 43 xhttp "github.com/m3db/m3/src/x/net/http" 44 xtest "github.com/m3db/m3/src/x/test" 45 46 "github.com/golang/mock/gomock" 47 "github.com/stretchr/testify/assert" 48 "github.com/stretchr/testify/require" 49 ) 50 51 const ( 52 testID = "test_id" 53 ) 54 55 func generateSearchReq() *storage.FetchQuery { 56 matchers := models.Matchers{ 57 { 58 Type: models.MatchEqual, 59 Name: []byte("foo"), 60 Value: []byte("bar"), 61 }, 62 { 63 Type: models.MatchEqual, 64 Name: []byte("biz"), 65 Value: []byte("baz"), 66 }, 67 } 68 return &storage.FetchQuery{ 69 TagMatchers: matchers, 70 Start: time.Now().Add(-10 * time.Minute), 71 End: time.Now(), 72 } 73 } 74 75 func generateSearchBody(t *testing.T) io.Reader { 76 req := generateSearchReq() 77 data, err := json.Marshal(req) 78 require.NoError(t, err) 79 80 return bytes.NewReader(data) 81 } 82 83 func generateTagIters(ctrl *gomock.Controller) *client.MockTaggedIDsIterator { 84 mockTaggedIDsIter := client.NewMockTaggedIDsIterator(ctrl) 85 mockTaggedIDsIter.EXPECT().Next().Return(true).MaxTimes(1) 86 mockTaggedIDsIter.EXPECT().Next().Return(false) 87 mockTaggedIDsIter.EXPECT().Current().Return(ident.StringID("ns"), 88 ident.StringID(testID), seriesiter.GenerateSingleSampleTagIterator(ctrl, seriesiter.GenerateTag())) 89 mockTaggedIDsIter.EXPECT().Err().Return(nil).MinTimes(1) 90 mockTaggedIDsIter.EXPECT().Finalize() 91 92 return mockTaggedIDsIter 93 } 94 95 func searchServer(t *testing.T) *SearchHandler { 96 ctrl := xtest.NewController(t) 97 98 mockTaggedIDsIter := generateTagIters(ctrl) 99 100 storage, session := m3.NewStorageAndSession(t, ctrl) 101 session.EXPECT().FetchTaggedIDs(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). 102 Return(mockTaggedIDsIter, client.FetchResponseMetadata{Exhaustive: false}, nil).AnyTimes() 103 104 builder, err := handleroptions.NewFetchOptionsBuilder( 105 handleroptions.FetchOptionsBuilderOptions{ 106 Timeout: 15 * time.Second, 107 }) 108 require.NoError(t, err) 109 opts := options.EmptyHandlerOptions(). 110 SetStorage(storage).SetFetchOptionsBuilder(builder) 111 search := NewSearchHandler(opts) 112 h, ok := search.(*SearchHandler) 113 require.True(t, ok) 114 return h 115 } 116 117 func TestSearchResponse(t *testing.T) { 118 searchHandler := searchServer(t) 119 120 opts := storage.NewFetchOptions() 121 opts.SeriesLimit = 100 122 results, err := searchHandler.search(context.TODO(), generateSearchReq(), opts) 123 require.NoError(t, err) 124 125 assert.Equal(t, []byte(testID), results.Metrics[0].ID) 126 expected := test.TagSliceToTags([]models.Tag{{Name: []byte("foo"), Value: []byte("bar")}}) 127 assert.Equal(t, expected.Tags, results.Metrics[0].Tags.Tags) 128 } 129 130 func TestSearchEndpoint(t *testing.T) { 131 searchHandler := searchServer(t) 132 server := httptest.NewServer(searchHandler) 133 defer server.Close() 134 135 urlWithLimit := fmt.Sprintf("%s%s", server.URL, "?limit=90") 136 req, _ := http.NewRequest("POST", urlWithLimit, generateSearchBody(t)) 137 req.Header.Add(xhttp.HeaderContentType, xhttp.ContentTypeJSON) 138 resp, err := http.DefaultClient.Do(req) 139 require.NoError(t, err) 140 defer resp.Body.Close() 141 require.NotNil(t, resp) 142 }