github.com/m3db/m3@v1.5.0/src/query/storage/prometheus/prometheus_storage_test.go (about) 1 // Copyright (c) 2020 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 prometheus 22 23 import ( 24 "context" 25 "sync" 26 "testing" 27 "time" 28 29 "github.com/golang/mock/gomock" 30 "github.com/m3db/m3/src/query/block" 31 "github.com/m3db/m3/src/query/generated/proto/prompb" 32 "github.com/m3db/m3/src/query/models" 33 "github.com/m3db/m3/src/query/storage" 34 "github.com/m3db/m3/src/x/instrument" 35 xtest "github.com/m3db/m3/src/x/test" 36 37 "github.com/prometheus/prometheus/pkg/labels" 38 promstorage "github.com/prometheus/prometheus/storage" 39 "github.com/stretchr/testify/assert" 40 "github.com/stretchr/testify/require" 41 ) 42 43 func TestSelectWithMetaInContext(t *testing.T) { 44 ctrl := xtest.NewController(t) 45 defer ctrl.Finish() 46 47 var resMutex sync.Mutex 48 res := block.NewResultMetadata() 49 resultMetadataReceiveFn := func(m block.ResultMetadata) { 50 resMutex.Lock() 51 defer resMutex.Unlock() 52 res = res.CombineMetadata(m) 53 } 54 ctx := context.Background() 55 ctx = context.WithValue(ctx, FetchOptionsContextKey, storage.NewFetchOptions()) 56 ctx = context.WithValue(ctx, BlockResultMetadataFnKey, resultMetadataReceiveFn) 57 58 store := storage.NewMockStorage(ctrl) 59 opts := PrometheusOptions{ 60 Storage: store, 61 InstrumentOptions: instrument.NewOptions(), 62 } 63 64 queryable := NewPrometheusQueryable(opts) 65 q, err := queryable.Querier(ctx, 0, 0) 66 require.NoError(t, err) 67 68 start := time.Now().Truncate(time.Hour) 69 end := start.Add(time.Hour) 70 step := int64(time.Second) 71 72 hints := &promstorage.SelectHints{ 73 Start: start.Unix() * 1000, 74 End: end.Unix() * 1000, 75 76 Step: step / int64(time.Millisecond), 77 } 78 79 matchers := []*labels.Matcher{ 80 labels.MustNewMatcher(labels.MatchEqual, "foo", "bar"), 81 labels.MustNewMatcher(labels.MatchRegexp, "qux", "q.z"), 82 } 83 84 m, err := models.NewMatcher(models.MatchEqual, []byte("foo"), []byte("bar")) 85 require.NoError(t, err) 86 m2, err := models.NewMatcher(models.MatchRegexp, []byte("qux"), []byte("q.z")) 87 require.NoError(t, err) 88 89 exQuery := &storage.FetchQuery{ 90 TagMatchers: models.Matchers{m, m2}, 91 Start: start, 92 End: end, 93 Interval: time.Duration(step), 94 } 95 96 meta := block.NewResultMetadata() 97 meta.AddWarning("warn", "warning") 98 store.EXPECT().FetchProm(ctx, exQuery, gomock.Any()).DoAndReturn( 99 func(_ context.Context, arg1 *storage.FetchQuery, _ *storage.FetchOptions) (storage.PromResult, error) { 100 return storage.PromResult{ 101 Metadata: meta, 102 PromResult: &prompb.QueryResult{ 103 Timeseries: []*prompb.TimeSeries{ 104 { 105 Labels: []prompb.Label{ 106 {Name: []byte("foo"), Value: []byte("bar")}, 107 {Name: []byte("qux"), Value: []byte("qzz")}, 108 }, 109 Samples: []prompb.Sample{ 110 prompb.Sample{Value: 1, Timestamp: 100}, 111 }, 112 }, 113 { 114 Labels: []prompb.Label{ 115 {Name: []byte("foo"), Value: []byte("bar")}, 116 {Name: []byte("qux"), Value: []byte("qaz")}, 117 }, 118 Samples: []prompb.Sample{ 119 prompb.Sample{Value: 100, Timestamp: 200}, 120 }, 121 }, 122 }, 123 }, 124 }, nil 125 }) 126 127 series := q.Select(true, hints, matchers...) 128 warnings := series.Warnings() 129 assert.NoError(t, series.Err()) 130 131 type dp struct { 132 v float64 133 t int64 134 } 135 136 acDp := make([][]dp, 0, 2) 137 acTags := make([]string, 0, 2) 138 for series.Next() { 139 curr := series.At() 140 acTags = append(acTags, curr.Labels().String()) 141 it := curr.Iterator() 142 ac := make([]dp, 0, 1) 143 for it.Next() { 144 t, v := it.At() 145 ac = append(ac, dp{t: t, v: v}) 146 } 147 148 assert.NoError(t, it.Err()) 149 acDp = append(acDp, ac) 150 } 151 152 assert.NoError(t, series.Err()) 153 154 exDp := [][]dp{{{v: 100, t: 200}}, {{v: 1, t: 100}}} 155 exTags := []string{`{foo="bar", qux="qaz"}`, `{foo="bar", qux="qzz"}`} 156 assert.Equal(t, exTags, acTags) 157 assert.Equal(t, exDp, acDp) 158 require.Equal(t, 1, len(warnings)) 159 require.EqualError(t, warnings[0], "warn_warning") 160 require.NoError(t, q.Close()) 161 162 // NB: assert warnings on context were propagated. 163 assert.Equal(t, []string{"warn_warning"}, res.WarningStrings()) 164 }