github.com/m3db/m3@v1.5.0/src/query/api/v1/handler/prometheus/response_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 "encoding/json" 25 "fmt" 26 "testing" 27 28 "github.com/stretchr/testify/assert" 29 "github.com/stretchr/testify/require" 30 ) 31 32 var ( 33 fullMatch = MatchInformation{FullMatch: true} 34 noMatch = MatchInformation{NoMatch: true} 35 ) 36 37 func TestUnmarshalPrometheusResponse(t *testing.T) { 38 tests := []struct { 39 name string 40 givenJson string 41 wantResponse Response 42 }{ 43 { 44 name: "status: error", 45 givenJson: `{ 46 "status": "error", 47 "errorType": "bad_data", 48 "error": "invalid parameter" 49 }`, 50 wantResponse: Response{ 51 Status: "error", 52 }, 53 }, 54 { 55 name: "resultType: scalar", 56 givenJson: `{ 57 "status": "success", 58 "data": { 59 "resultType": "scalar", 60 "result": [1590605774, "84"] 61 } 62 }`, 63 wantResponse: Response{ 64 "success", 65 data{ 66 "scalar", 67 &ScalarResult{Value{1590605774.0, "84"}}, 68 }, 69 }, 70 }, 71 { 72 name: "resultType: string", 73 givenJson: `{ 74 "status": "success", 75 "data": { 76 "resultType": "string", 77 "result": [1590605775, "FOO"] 78 } 79 }`, 80 wantResponse: Response{ 81 "success", 82 data{ 83 "string", 84 &StringResult{Value{1590605775.0, "FOO"}}, 85 }, 86 }, 87 }, 88 { 89 name: "resultType: vector", 90 givenJson: `{ 91 "status": "success", 92 "data": { 93 "resultType": "vector", 94 "result": [ 95 { 96 "metric": { 97 "__name__": "foo", 98 "bar": "1" 99 }, 100 "value": [1590605775, "0.5"] 101 }, 102 { 103 "metric": { 104 "__name__": "foo", 105 "bar": "2" 106 }, 107 "value": [1590605776, "2"] 108 } 109 ] 110 } 111 }`, 112 wantResponse: Response{ 113 "success", 114 data{ 115 "vector", 116 &VectorResult{[]vectorItem{ 117 { 118 Metric: Tags{"__name__": "foo", "bar": "1"}, 119 Value: Value{1590605775.0, "0.5"}, 120 }, 121 { 122 Metric: Tags{"__name__": "foo", "bar": "2"}, 123 Value: Value{1590605776.0, "2"}, 124 }, 125 }}, 126 }, 127 }, 128 }, 129 { 130 name: "resultType: matrix", 131 givenJson: `{ 132 "status": "success", 133 "data": { 134 "resultType": "matrix", 135 "result": [ 136 { 137 "metric": { 138 "__name__": "foo", 139 "bar": "1" 140 }, 141 "values": [[1590605775, "1"], [1590605785, "11"]] 142 }, 143 { 144 "metric": { 145 "__name__": "foo", 146 "bar": "2" 147 }, 148 "values": [[1590605776, "2"], [1590605786, "22"]] 149 } 150 ] 151 } 152 }`, 153 wantResponse: Response{ 154 "success", 155 data{ 156 "matrix", 157 &MatrixResult{[]matrixRow{ 158 { 159 Metric: Tags{"__name__": "foo", "bar": "1"}, 160 Values: Values{{1590605775.0, "1"}, {1590605785.0, "11"}}, 161 }, 162 { 163 Metric: Tags{"__name__": "foo", "bar": "2"}, 164 Values: Values{{1590605776.0, "2"}, {1590605786.0, "22"}}, 165 }, 166 }}, 167 }, 168 }, 169 }, 170 } 171 172 for _, tt := range tests { 173 t.Run(tt.name, func(t *testing.T) { 174 response := &Response{} 175 err := json.Unmarshal([]byte(tt.givenJson), response) 176 require.NoError(t, err) 177 assert.Equal(t, tt.wantResponse, *response) 178 }) 179 } 180 } 181 182 func TestResponseMatching(t *testing.T) { 183 tests := []struct { 184 name string 185 response Response 186 }{ 187 { 188 name: "error", 189 response: Response{ 190 Status: "error", 191 }, 192 }, 193 194 { 195 name: "scalar", 196 response: Response{ 197 "success", 198 data{ 199 "scalar", 200 &ScalarResult{Value{1590605774.0, "1"}}, 201 }, 202 }, 203 }, 204 { 205 name: "scalar other timestamp", 206 response: Response{ 207 "success", 208 data{ 209 "scalar", 210 &ScalarResult{Value{1590605775.0, "1"}}, 211 }, 212 }, 213 }, 214 { 215 name: "scalar other value", 216 response: Response{ 217 "success", 218 data{ 219 "scalar", 220 &ScalarResult{Value{1590605774.0, "2"}}, 221 }, 222 }, 223 }, 224 225 { 226 name: "vector", 227 response: Response{ 228 "success", 229 data{ 230 "vector", 231 &VectorResult{[]vectorItem{ 232 { 233 Metric: Tags{"__name__": "foo"}, 234 Value: Value{1590605775.0, "0.5"}, 235 }, 236 }}, 237 }, 238 }, 239 }, 240 { 241 name: "vector more tags", 242 response: Response{ 243 "success", 244 data{ 245 "vector", 246 &VectorResult{[]vectorItem{ 247 { 248 Metric: Tags{"__name__": "foo", "bar": "1"}, 249 Value: Value{1590605775.0, "0.5"}, 250 }, 251 }}, 252 }, 253 }, 254 }, 255 { 256 name: "vector more items", 257 response: Response{ 258 "success", 259 data{ 260 "vector", 261 &VectorResult{[]vectorItem{ 262 { 263 Metric: Tags{"__name__": "foo", "bar": "1"}, 264 Value: Value{1590605775.0, "0.5"}, 265 }, 266 { 267 Metric: Tags{"__name__": "foo", "bar": "2"}, 268 Value: Value{1590605775.0, "0.5"}, 269 }, 270 }}, 271 }, 272 }, 273 }, 274 { 275 name: "vector different tag", 276 response: Response{ 277 "success", 278 data{ 279 "vector", 280 &VectorResult{[]vectorItem{ 281 { 282 Metric: Tags{"__name__": "bar"}, 283 Value: Value{1590605775.0, "0.5"}, 284 }, 285 }}, 286 }, 287 }, 288 }, 289 { 290 name: "vector different value", 291 response: Response{ 292 "success", 293 data{ 294 "vector", 295 &VectorResult{[]vectorItem{ 296 { 297 Metric: Tags{"__name__": "foo"}, 298 Value: Value{1590605775.0, "1"}, 299 }, 300 }}, 301 }, 302 }, 303 }, 304 { 305 name: "vector different timestamp", 306 response: Response{ 307 "success", 308 data{ 309 "vector", 310 &VectorResult{[]vectorItem{ 311 { 312 Metric: Tags{"__name__": "foo"}, 313 Value: Value{1590605774.0, "0.5"}, 314 }, 315 }}, 316 }, 317 }, 318 }, 319 320 { 321 name: "matrix", 322 response: Response{ 323 "success", 324 data{ 325 "matrix", 326 &MatrixResult{[]matrixRow{ 327 { 328 Metric: Tags{"__name__": "foo"}, 329 Values: Values{{1590605775.0, "1"}}, 330 }, 331 }}, 332 }, 333 }, 334 }, 335 { 336 name: "matrix other tag", 337 response: Response{ 338 "success", 339 data{ 340 "matrix", 341 &MatrixResult{[]matrixRow{ 342 { 343 Metric: Tags{"__name__": "bar"}, 344 Values: Values{{1590605775.0, "1"}}, 345 }, 346 }}, 347 }, 348 }, 349 }, 350 { 351 name: "matrix other value", 352 response: Response{ 353 "success", 354 data{ 355 "matrix", 356 &MatrixResult{[]matrixRow{ 357 { 358 Metric: Tags{"__name__": "foo"}, 359 Values: Values{{1590605775.0, "2"}}, 360 }, 361 }}, 362 }, 363 }, 364 }, 365 { 366 name: "matrix other timestamp", 367 response: Response{ 368 "success", 369 data{ 370 "matrix", 371 &MatrixResult{[]matrixRow{ 372 { 373 Metric: Tags{"__name__": "foo"}, 374 Values: Values{{1590605776.0, "1"}}, 375 }, 376 }}, 377 }, 378 }, 379 }, 380 { 381 name: "matrix more tags", 382 response: Response{ 383 "success", 384 data{ 385 "matrix", 386 &MatrixResult{[]matrixRow{ 387 { 388 Metric: Tags{"__name__": "foo", "bar": "1"}, 389 Values: Values{{1590605775.0, "1"}}, 390 }, 391 }}, 392 }, 393 }, 394 }, 395 { 396 name: "matrix more values", 397 response: Response{ 398 "success", 399 data{ 400 "matrix", 401 &MatrixResult{[]matrixRow{ 402 { 403 Metric: Tags{"__name__": "foo"}, 404 Values: Values{{1590605775.0, "1"}, {1590605776.0, "2"}}, 405 }, 406 }}, 407 }, 408 }, 409 }, 410 { 411 name: "matrix more rows", 412 response: Response{ 413 "success", 414 data{ 415 "matrix", 416 &MatrixResult{[]matrixRow{ 417 { 418 Metric: Tags{"__name__": "foo"}, 419 Values: Values{{1590605775.0, "1"}}, 420 }, 421 { 422 Metric: Tags{"__name__": "bar"}, 423 Values: Values{{1590605775.0, "1"}}, 424 }, 425 }}, 426 }, 427 }, 428 }, 429 } 430 431 for i, ti := range tests { 432 for j, tj := range tests { 433 t.Run(fmt.Sprintf("%s vs %s", ti.name, tj.name), func(t *testing.T) { 434 matchResult, err := ti.response.Matches(tj.response) 435 if i == j { // should match 436 require.NoError(t, err) 437 assert.Equal(t, fullMatch, matchResult) 438 } else { // should not match 439 require.Error(t, err) 440 assert.Equal(t, noMatch, matchResult) 441 } 442 }) 443 } 444 } 445 } 446 447 func TestResponseMatchingOrderInsensitive(t *testing.T) { 448 tests := []struct { 449 name string 450 left Response 451 right Response 452 }{ 453 { 454 name: "vector", 455 left: Response{ 456 "success", 457 data{ 458 "vector", 459 &VectorResult{[]vectorItem{ 460 { 461 Metric: Tags{"__name__": "first"}, 462 Value: Value{1590605775.0, "1"}, 463 }, 464 { 465 Metric: Tags{"__name__": "second"}, 466 Value: Value{1590605775.0, "2"}, 467 }, 468 }}, 469 }, 470 }, 471 right: Response{ 472 "success", 473 data{ 474 "vector", 475 &VectorResult{[]vectorItem{ 476 { 477 Metric: Tags{"__name__": "second"}, 478 Value: Value{1590605775.0, "2"}, 479 }, 480 { 481 Metric: Tags{"__name__": "first"}, 482 Value: Value{1590605775.0, "1"}, 483 }, 484 }}, 485 }, 486 }, 487 }, 488 { 489 name: "matrix", 490 left: Response{ 491 "success", 492 data{ 493 "matrix", 494 &MatrixResult{[]matrixRow{ 495 { 496 Metric: Tags{"__name__": "first"}, 497 Values: Values{{1590605775.0, "1"}}, 498 }, 499 { 500 Metric: Tags{"__name__": "second"}, 501 Values: Values{{1590605775.0, "2"}}, 502 }, 503 }}, 504 }, 505 }, 506 right: Response{ 507 "success", 508 data{ 509 "matrix", 510 &MatrixResult{[]matrixRow{ 511 { 512 Metric: Tags{"__name__": "second"}, 513 Values: Values{{1590605775.0, "2"}}, 514 }, 515 { 516 Metric: Tags{"__name__": "first"}, 517 Values: Values{{1590605775.0, "1"}}, 518 }, 519 }}, 520 }, 521 }, 522 }, 523 } 524 525 for _, tt := range tests { 526 t.Run(fmt.Sprintf(tt.name), func(t *testing.T) { 527 matchResult, err := tt.left.Matches(tt.right) 528 require.NoError(t, err) 529 assert.Equal(t, fullMatch, matchResult) 530 }) 531 } 532 }