github.com/m3db/m3@v1.5.0/src/query/storage/converter_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 storage 22 23 import ( 24 "fmt" 25 "math" 26 "testing" 27 "time" 28 29 "github.com/m3db/m3/src/dbnode/generated/proto/annotation" 30 "github.com/m3db/m3/src/query/generated/proto/prompb" 31 "github.com/m3db/m3/src/query/models" 32 "github.com/m3db/m3/src/query/ts" 33 xtest "github.com/m3db/m3/src/x/test" 34 xtime "github.com/m3db/m3/src/x/time" 35 36 "github.com/stretchr/testify/assert" 37 "github.com/stretchr/testify/require" 38 ) 39 40 func TestLabelConversion(t *testing.T) { 41 // NB: sorted order (__name__, foo, le) 42 labels := []prompb.Label{ 43 {Name: promDefaultName, Value: []byte("name-val")}, 44 {Name: []byte("foo"), Value: []byte("bar")}, 45 {Name: promDefaultBucketName, Value: []byte("bucket-val")}, 46 } 47 48 opts := models.NewTagOptions(). 49 SetMetricName([]byte("name")). 50 SetBucketName([]byte("bucket")) 51 52 tags := PromLabelsToM3Tags(labels, opts) 53 name, found := tags.Name() 54 assert.True(t, found) 55 assert.Equal(t, []byte("name-val"), name) 56 name, found = tags.Get([]byte("name")) 57 assert.True(t, found) 58 assert.Equal(t, []byte("name-val"), name) 59 60 bucket, found := tags.Bucket() 61 assert.True(t, found) 62 assert.Equal(t, []byte("bucket-val"), bucket) 63 bucket, found = tags.Get([]byte("bucket")) 64 assert.True(t, found) 65 assert.Equal(t, []byte("bucket-val"), bucket) 66 67 reverted := TagsToPromLabels(tags) 68 assert.Equal(t, labels, reverted) 69 } 70 71 var ( 72 name = []byte("foo") 73 value = []byte("bar") 74 ) 75 76 func TestPromReadQueryToM3BadStartEnd(t *testing.T) { 77 q, err := PromReadQueryToM3(&prompb.Query{ 78 StartTimestampMs: 100, 79 EndTimestampMs: -100, 80 }) 81 82 require.NoError(t, err) 83 assert.Equal(t, time.Time{}, q.Start) 84 // NB: check end is approximately correct. 85 diff := math.Abs(float64(time.Since(q.End))) 86 assert.True(t, diff < float64(time.Minute)) 87 } 88 89 func TestPromReadQueryToM3(t *testing.T) { 90 tests := []struct { 91 name string 92 matchers []*prompb.LabelMatcher 93 expected []*models.Matcher 94 expectError bool 95 }{ 96 { 97 name: "single exact match", 98 matchers: []*prompb.LabelMatcher{ 99 {Type: prompb.LabelMatcher_EQ, Name: name, Value: value}, 100 }, 101 expected: []*models.Matcher{ 102 {Type: models.MatchEqual, Name: name, Value: value}, 103 }, 104 }, 105 { 106 name: "single exact match negated", 107 matchers: []*prompb.LabelMatcher{ 108 {Type: prompb.LabelMatcher_NEQ, Name: name, Value: value}, 109 }, 110 expected: []*models.Matcher{ 111 {Type: models.MatchNotEqual, Name: name, Value: value}, 112 }, 113 }, 114 { 115 name: "single regexp match", 116 matchers: []*prompb.LabelMatcher{ 117 {Type: prompb.LabelMatcher_RE, Name: name, Value: value}, 118 }, 119 expected: []*models.Matcher{ 120 {Type: models.MatchRegexp, Name: name, Value: value}, 121 }, 122 }, 123 { 124 name: "single regexp match negated", 125 matchers: []*prompb.LabelMatcher{ 126 {Type: prompb.LabelMatcher_NRE, Name: name, Value: value}, 127 }, 128 expected: []*models.Matcher{ 129 {Type: models.MatchNotRegexp, Name: name, Value: value}, 130 }, 131 }, 132 { 133 name: "mixed exact match and regexp match", 134 matchers: []*prompb.LabelMatcher{ 135 {Type: prompb.LabelMatcher_EQ, Name: name, Value: value}, 136 {Type: prompb.LabelMatcher_RE, Name: []byte("baz"), Value: []byte("qux")}, 137 }, 138 expected: []*models.Matcher{ 139 {Type: models.MatchEqual, Name: name, Value: value}, 140 {Type: models.MatchRegexp, Name: []byte("baz"), Value: []byte("qux")}, 141 }, 142 }, 143 { 144 name: "unrecognized matcher type", 145 matchers: []*prompb.LabelMatcher{ 146 {Type: prompb.LabelMatcher_Type(math.MaxInt32), Name: name, Value: value}, 147 }, 148 expectError: true, 149 }, 150 } 151 152 for _, test := range tests { 153 t.Run(test.name, func(t *testing.T) { 154 input := &prompb.Query{ 155 StartTimestampMs: 123000, 156 EndTimestampMs: 456000, 157 Matchers: test.matchers, 158 } 159 result, err := PromReadQueryToM3(input) 160 if test.expectError { 161 assert.Error(t, err) 162 } else { 163 assert.True(t, result.Start.Equal(time.Unix(123, 0)), "start does not match") 164 assert.True(t, result.End.Equal(time.Unix(456, 0)), "end does not match") 165 require.Equal(t, len(test.expected), len(result.TagMatchers), 166 "tag matchers length not match") 167 for i, expected := range test.expected { 168 expectedStr := expected.String() 169 actualStr := result.TagMatchers[i].String() 170 assert.Equal(t, expectedStr, actualStr, 171 fmt.Sprintf("matcher does not match: idx=%d, expected=%s, actual=%s", 172 i, expectedStr, actualStr)) 173 } 174 } 175 }) 176 } 177 } 178 179 var ( 180 benchResult *prompb.QueryResult 181 ) 182 183 func TestFetchResultToPromResult(t *testing.T) { 184 ctrl := xtest.NewController(t) 185 defer ctrl.Finish() 186 187 now := xtime.Now() 188 promNow := TimeToPromTimestamp(now) 189 190 vals := ts.NewMockValues(ctrl) 191 vals.EXPECT().Len().Return(0).Times(2) 192 vals.EXPECT().Datapoints().Return(ts.Datapoints{}) 193 194 tags := models.NewTags(1, models.NewTagOptions()). 195 AddTag(models.Tag{Name: []byte("a"), Value: []byte("b")}) 196 197 valsNonEmpty := ts.NewMockValues(ctrl) 198 valsNonEmpty.EXPECT().Len().Return(1).Times(3) 199 dp := ts.Datapoints{{Timestamp: now, Value: 1}} 200 valsNonEmpty.EXPECT().Datapoints().Return(dp).Times(2) 201 tagsNonEmpty := models.NewTags(1, models.NewTagOptions()). 202 AddTag(models.Tag{Name: []byte("c"), Value: []byte("d")}) 203 204 r := &FetchResult{ 205 SeriesList: ts.SeriesList{ 206 ts.NewSeries([]byte("a"), vals, tags), 207 ts.NewSeries([]byte("c"), valsNonEmpty, tagsNonEmpty), 208 }, 209 } 210 211 // NB: not keeping empty series. 212 result := FetchResultToPromResult(r, false) 213 expected := &prompb.QueryResult{ 214 Timeseries: []*prompb.TimeSeries{ 215 { 216 Labels: []prompb.Label{{Name: []byte("c"), Value: []byte("d")}}, 217 Samples: []prompb.Sample{{Timestamp: promNow, Value: 1}}, 218 }, 219 }, 220 } 221 222 assert.Equal(t, expected, result) 223 224 // NB: keeping empty series. 225 result = FetchResultToPromResult(r, true) 226 expected = &prompb.QueryResult{ 227 Timeseries: []*prompb.TimeSeries{ 228 { 229 Labels: []prompb.Label{{Name: []byte("a"), Value: []byte("b")}}, 230 Samples: []prompb.Sample{}, 231 }, 232 { 233 Labels: []prompb.Label{{Name: []byte("c"), Value: []byte("d")}}, 234 Samples: []prompb.Sample{{Timestamp: promNow, Value: 1}}, 235 }, 236 }, 237 } 238 239 assert.Equal(t, expected, result) 240 } 241 242 // BenchmarkFetchResultToPromResult-8 100 10563444 ns/op 25368543 B/op 4443 allocs/op 243 func BenchmarkFetchResultToPromResult(b *testing.B) { 244 var ( 245 numSeries = 1000 246 numDatapointsPerSeries = 1000 247 numTagsPerSeries = 10 248 fr = &FetchResult{ 249 SeriesList: make(ts.SeriesList, 0, numSeries), 250 } 251 ) 252 253 for i := 0; i < numSeries; i++ { 254 values := make(ts.Datapoints, 0, numDatapointsPerSeries) 255 for i := 0; i < numDatapointsPerSeries; i++ { 256 values = append(values, ts.Datapoint{ 257 Timestamp: 0, 258 Value: float64(i), 259 }) 260 } 261 262 tags := models.NewTags(numTagsPerSeries, nil) 263 for i := 0; i < numTagsPerSeries; i++ { 264 tags = tags.AddTag(models.Tag{ 265 Name: []byte(fmt.Sprintf("name-%d", i)), 266 Value: []byte(fmt.Sprintf("value-%d", i)), 267 }) 268 } 269 270 series := ts.NewSeries( 271 []byte(fmt.Sprintf("series-%d", i)), values, tags) 272 273 fr.SeriesList = append(fr.SeriesList, series) 274 } 275 276 for i := 0; i < b.N; i++ { 277 benchResult = FetchResultToPromResult(fr, false) 278 } 279 } 280 281 func TestPromTimeSeriesToSeriesAttributesSource(t *testing.T) { 282 attrs, err := PromTimeSeriesToSeriesAttributes(prompb.TimeSeries{}) 283 require.NoError(t, err) 284 assert.Equal(t, ts.SourceTypePrometheus, attrs.Source) 285 286 attrs, err = PromTimeSeriesToSeriesAttributes(prompb.TimeSeries{Source: prompb.Source_PROMETHEUS}) 287 require.NoError(t, err) 288 assert.Equal(t, ts.SourceTypePrometheus, attrs.Source) 289 290 attrs, err = PromTimeSeriesToSeriesAttributes(prompb.TimeSeries{Source: prompb.Source_OPEN_METRICS}) 291 require.NoError(t, err) 292 assert.Equal(t, ts.SourceTypeOpenMetrics, attrs.Source) 293 294 attrs, err = PromTimeSeriesToSeriesAttributes(prompb.TimeSeries{Source: prompb.Source_GRAPHITE}) 295 require.NoError(t, err) 296 assert.Equal(t, ts.SourceTypeGraphite, attrs.Source) 297 298 attrs, err = PromTimeSeriesToSeriesAttributes(prompb.TimeSeries{Source: -1}) 299 require.Error(t, err) 300 } 301 302 func TestPromTimeSeriesToSeriesAttributesPromMetricsTypeFromPrometheus(t *testing.T) { 303 mapping := map[prompbMetricTypeWithNameSuffix]promMetricTypeWithBool{ 304 {metricType: prompb.MetricType_UNKNOWN}: {metricType: ts.PromMetricTypeUnknown}, 305 {metricType: prompb.MetricType_COUNTER}: {metricType: ts.PromMetricTypeCounter, handleValueResets: true}, 306 {metricType: prompb.MetricType_GAUGE}: {metricType: ts.PromMetricTypeGauge}, 307 {metricType: prompb.MetricType_INFO}: {metricType: ts.PromMetricTypeInfo}, 308 {metricType: prompb.MetricType_STATESET}: {metricType: ts.PromMetricTypeStateSet}, 309 310 {prompb.MetricType_HISTOGRAM, "bucket"}: {metricType: ts.PromMetricTypeHistogram, handleValueResets: true}, 311 {prompb.MetricType_HISTOGRAM, "count"}: {metricType: ts.PromMetricTypeHistogram, handleValueResets: true}, 312 {prompb.MetricType_HISTOGRAM, "sum"}: {metricType: ts.PromMetricTypeHistogram, handleValueResets: true}, 313 314 {prompb.MetricType_GAUGE_HISTOGRAM, "bucket"}: {metricType: ts.PromMetricTypeGaugeHistogram}, 315 {prompb.MetricType_GAUGE_HISTOGRAM, "count"}: {metricType: ts.PromMetricTypeGaugeHistogram, handleValueResets: true}, 316 {prompb.MetricType_GAUGE_HISTOGRAM, "gcount"}: {metricType: ts.PromMetricTypeGaugeHistogram, handleValueResets: true}, 317 {prompb.MetricType_GAUGE_HISTOGRAM, "sum"}: {metricType: ts.PromMetricTypeGaugeHistogram}, 318 319 {metricType: prompb.MetricType_SUMMARY}: {metricType: ts.PromMetricTypeSummary}, 320 {prompb.MetricType_SUMMARY, "count"}: {metricType: ts.PromMetricTypeSummary, handleValueResets: true}, 321 {prompb.MetricType_SUMMARY, "sum"}: {metricType: ts.PromMetricTypeSummary, handleValueResets: true}, 322 } 323 324 for proto, expected := range mapping { // nolint: dupl 325 var ( 326 name = fmt.Sprintf("Prometheus type: %s, name suffix: '%s'", proto.metricType, proto.nameSuffix) 327 proto = proto 328 expected = expected 329 ) 330 331 t.Run(name, func(t *testing.T) { 332 var labels []prompb.Label 333 if proto.nameSuffix != "" { 334 labels = append(labels, prompb.Label{Name: promDefaultName, Value: []byte("foo_" + proto.nameSuffix)}) 335 } 336 337 attrs, err := PromTimeSeriesToSeriesAttributes(prompb.TimeSeries{ 338 Source: prompb.Source_PROMETHEUS, 339 Type: proto.metricType, 340 Labels: labels, 341 }) 342 343 require.NoError(t, err) 344 assert.Equal(t, expected.metricType, attrs.PromType) 345 assert.Equal(t, expected.handleValueResets, attrs.HandleValueResets) 346 assert.Equal(t, ts.SourceTypePrometheus, attrs.Source) 347 }) 348 } 349 350 _, err := PromTimeSeriesToSeriesAttributes(prompb.TimeSeries{ 351 Source: prompb.Source_PROMETHEUS, 352 Type: -1, 353 }) 354 require.Error(t, err) 355 } 356 357 func TestPromTimeSeriesToSeriesAttributesM3TypeFromPrometheus(t *testing.T) { 358 testPromTimeSeriesToSeriesAttributesM3Type(t, prompb.Source_PROMETHEUS) 359 } 360 361 func TestPromTimeSeriesToSeriesAttributesM3TypeFromOpenMetrics(t *testing.T) { 362 testPromTimeSeriesToSeriesAttributesM3Type(t, prompb.Source_OPEN_METRICS) 363 } 364 365 func testPromTimeSeriesToSeriesAttributesM3Type(t *testing.T, source prompb.Source) { 366 mapping := map[prompb.M3Type]ts.M3MetricType{ 367 prompb.M3Type_M3_GAUGE: ts.M3MetricTypeGauge, 368 prompb.M3Type_M3_COUNTER: ts.M3MetricTypeCounter, 369 prompb.M3Type_M3_TIMER: ts.M3MetricTypeTimer, 370 } 371 372 for proto, expected := range mapping { 373 attrs, err := PromTimeSeriesToSeriesAttributes(prompb.TimeSeries{ 374 Source: source, 375 M3Type: proto, 376 }) 377 require.NoError(t, err) 378 assert.Equal(t, expected, attrs.M3Type) 379 } 380 381 _, err := PromTimeSeriesToSeriesAttributes(prompb.TimeSeries{ 382 Source: source, 383 M3Type: -1, 384 }) 385 require.Error(t, err) 386 } 387 388 func TestPromTimeSeriesToSeriesAttributesMetricsTypeFromOpenMetrics(t *testing.T) { 389 mapping := map[prompbMetricTypeWithNameSuffix]promMetricTypeWithBool{ 390 {metricType: prompb.MetricType_UNKNOWN}: {metricType: ts.PromMetricTypeUnknown}, 391 392 {prompb.MetricType_COUNTER, "total"}: {metricType: ts.PromMetricTypeCounter, handleValueResets: true}, 393 {prompb.MetricType_COUNTER, "created"}: {metricType: ts.PromMetricTypeCounter}, 394 395 {metricType: prompb.MetricType_GAUGE}: {metricType: ts.PromMetricTypeGauge}, 396 {metricType: prompb.MetricType_INFO}: {metricType: ts.PromMetricTypeInfo}, 397 {metricType: prompb.MetricType_STATESET}: {metricType: ts.PromMetricTypeStateSet}, 398 399 {prompb.MetricType_HISTOGRAM, "bucket"}: {metricType: ts.PromMetricTypeHistogram, handleValueResets: true}, 400 {prompb.MetricType_HISTOGRAM, "count"}: {metricType: ts.PromMetricTypeHistogram, handleValueResets: true}, 401 {prompb.MetricType_HISTOGRAM, "sum"}: {metricType: ts.PromMetricTypeHistogram, handleValueResets: true}, 402 {prompb.MetricType_HISTOGRAM, "created"}: {metricType: ts.PromMetricTypeHistogram}, 403 404 {prompb.MetricType_GAUGE_HISTOGRAM, "bucket"}: {metricType: ts.PromMetricTypeGaugeHistogram}, 405 {prompb.MetricType_GAUGE_HISTOGRAM, "gcount"}: {metricType: ts.PromMetricTypeGaugeHistogram, handleValueResets: true}, 406 {prompb.MetricType_GAUGE_HISTOGRAM, "gsum"}: {metricType: ts.PromMetricTypeGaugeHistogram}, 407 408 {metricType: prompb.MetricType_SUMMARY}: {metricType: ts.PromMetricTypeSummary}, 409 {prompb.MetricType_SUMMARY, "count"}: {metricType: ts.PromMetricTypeSummary, handleValueResets: true}, 410 {prompb.MetricType_SUMMARY, "sum"}: {metricType: ts.PromMetricTypeSummary, handleValueResets: true}, 411 {prompb.MetricType_SUMMARY, "created"}: {metricType: ts.PromMetricTypeSummary}, 412 } 413 414 for proto, expected := range mapping { // nolint: dupl 415 var ( 416 name = fmt.Sprintf("Open Metrics type: %s, name suffix: '%s'", proto.metricType, proto.nameSuffix) 417 proto = proto 418 expected = expected 419 ) 420 421 t.Run(name, func(t *testing.T) { 422 var labels []prompb.Label 423 if proto.nameSuffix != "" { 424 labels = append(labels, prompb.Label{Name: promDefaultName, Value: []byte("foo_" + proto.nameSuffix)}) 425 } 426 427 attrs, err := PromTimeSeriesToSeriesAttributes(prompb.TimeSeries{ 428 Source: prompb.Source_OPEN_METRICS, 429 Type: proto.metricType, 430 Labels: labels, 431 }) 432 433 require.NoError(t, err) 434 assert.Equal(t, expected.metricType, attrs.PromType) 435 assert.Equal(t, expected.handleValueResets, attrs.HandleValueResets) 436 assert.Equal(t, ts.SourceTypeOpenMetrics, attrs.Source) 437 }) 438 } 439 440 _, err := PromTimeSeriesToSeriesAttributes(prompb.TimeSeries{ 441 Source: prompb.Source_OPEN_METRICS, 442 Type: -1, 443 }) 444 require.Error(t, err) 445 } 446 447 func TestPromTimeSeriesToSeriesAttributesMetricsTypeFromGraphite(t *testing.T) { 448 mapping := map[prompb.M3Type]struct { 449 m3Type ts.M3MetricType 450 promType ts.PromMetricType 451 }{ 452 prompb.M3Type_M3_GAUGE: {ts.M3MetricTypeGauge, ts.PromMetricTypeGauge}, 453 prompb.M3Type_M3_COUNTER: {ts.M3MetricTypeCounter, ts.PromMetricTypeCounter}, 454 prompb.M3Type_M3_TIMER: {ts.M3MetricTypeTimer, ts.PromMetricTypeUnknown}, 455 } 456 457 for proto, expected := range mapping { 458 attrs, err := PromTimeSeriesToSeriesAttributes(prompb.TimeSeries{ 459 Source: prompb.Source_GRAPHITE, 460 M3Type: proto, 461 }) 462 require.NoError(t, err) 463 assert.Equal(t, expected.promType, attrs.PromType, "PromType") 464 assert.Equal(t, expected.m3Type, attrs.M3Type, "M3Type") 465 assert.False(t, attrs.HandleValueResets) 466 } 467 468 _, err := PromTimeSeriesToSeriesAttributes(prompb.TimeSeries{ 469 Source: prompb.Source_GRAPHITE, 470 M3Type: -1, 471 }) 472 require.Error(t, err) 473 } 474 475 func TestPrometheusSeriesAttributesToAnnotationPayload(t *testing.T) { 476 testSeriesAttributesToAnnotationPayload(t, ts.SourceTypePrometheus) 477 } 478 479 func TestOpenMetricsSeriesAttributesToAnnotationPayload(t *testing.T) { 480 testSeriesAttributesToAnnotationPayload(t, ts.SourceTypeOpenMetrics) 481 } 482 483 func testSeriesAttributesToAnnotationPayload(t *testing.T, source ts.SourceType) { 484 mapping := map[ts.PromMetricType]annotation.OpenMetricsFamilyType{ 485 ts.PromMetricTypeUnknown: annotation.OpenMetricsFamilyType_UNKNOWN, 486 ts.PromMetricTypeCounter: annotation.OpenMetricsFamilyType_COUNTER, 487 ts.PromMetricTypeGauge: annotation.OpenMetricsFamilyType_GAUGE, 488 ts.PromMetricTypeHistogram: annotation.OpenMetricsFamilyType_HISTOGRAM, 489 ts.PromMetricTypeGaugeHistogram: annotation.OpenMetricsFamilyType_GAUGE_HISTOGRAM, 490 ts.PromMetricTypeSummary: annotation.OpenMetricsFamilyType_SUMMARY, 491 ts.PromMetricTypeInfo: annotation.OpenMetricsFamilyType_INFO, 492 ts.PromMetricTypeStateSet: annotation.OpenMetricsFamilyType_STATESET, 493 } 494 495 for promType, expectedType := range mapping { 496 payload, err := SeriesAttributesToAnnotationPayload(ts.SeriesAttributes{ 497 Source: source, 498 PromType: promType, 499 }) 500 require.NoError(t, err) 501 502 expectedPayload := annotation.Payload{ 503 SourceFormat: annotation.SourceFormat_OPEN_METRICS, 504 OpenMetricsFamilyType: expectedType, 505 } 506 assert.Equal(t, expectedPayload, payload) 507 } 508 509 _, err := SeriesAttributesToAnnotationPayload(ts.SeriesAttributes{PromType: math.MaxUint8}) 510 require.Error(t, err) 511 512 payload, err := SeriesAttributesToAnnotationPayload(ts.SeriesAttributes{ 513 Source: source, 514 HandleValueResets: true, 515 }) 516 require.NoError(t, err) 517 assert.True(t, payload.OpenMetricsHandleValueResets) 518 519 payload, err = SeriesAttributesToAnnotationPayload(ts.SeriesAttributes{ 520 Source: source, 521 HandleValueResets: false, 522 }) 523 require.NoError(t, err) 524 assert.False(t, payload.OpenMetricsHandleValueResets) 525 } 526 527 func TestGraphiteSeriesAttributesToAnnotationPayload(t *testing.T) { 528 mapping := map[ts.M3MetricType]annotation.GraphiteType{ 529 ts.M3MetricTypeGauge: annotation.GraphiteType_GRAPHITE_GAUGE, 530 ts.M3MetricTypeCounter: annotation.GraphiteType_GRAPHITE_COUNTER, 531 ts.M3MetricTypeTimer: annotation.GraphiteType_GRAPHITE_TIMER, 532 } 533 534 for graphiteType, expectedType := range mapping { 535 payload, err := SeriesAttributesToAnnotationPayload(ts.SeriesAttributes{ 536 Source: ts.SourceTypeGraphite, 537 M3Type: graphiteType, 538 }) 539 require.NoError(t, err) 540 541 expectedPayload := annotation.Payload{ 542 SourceFormat: annotation.SourceFormat_GRAPHITE, 543 GraphiteType: expectedType, 544 } 545 assert.Equal(t, expectedPayload, payload) 546 } 547 548 _, err := SeriesAttributesToAnnotationPayload(ts.SeriesAttributes{ 549 Source: ts.SourceTypeGraphite, 550 M3Type: math.MaxUint8, 551 }) 552 require.EqualError(t, err, "invalid Graphite metric type 255") 553 } 554 555 func TestPromTimestampToTime(t *testing.T) { 556 var ( 557 now = time.Now() 558 xNow = xtime.ToUnixNano(now) 559 560 xNowMillis = xNow.Truncate(time.Millisecond) 561 nowMillis = now.Truncate(time.Millisecond) 562 563 timestampMs = int64(xNow) / int64(time.Millisecond) 564 ) 565 566 require.Equal(t, xNowMillis, promTimestampToUnixNanos(timestampMs)) 567 require.Equal(t, nowMillis, PromTimestampToTime(timestampMs)) 568 } 569 570 type prompbMetricTypeWithNameSuffix struct { 571 metricType prompb.MetricType 572 nameSuffix string 573 } 574 575 type promMetricTypeWithBool struct { 576 metricType ts.PromMetricType 577 handleValueResets bool 578 }