PageRenderTime 113ms CodeModel.GetById 24ms RepoModel.GetById 7ms app.codeStats 0ms

/vendor/github.com/prometheus/common/expfmt/text_parse_test.go

https://gitlab.com/CORP-RESELLER/dashboard
Go | 588 lines | 539 code | 12 blank | 37 comment | 16 complexity | 3799e7b9e9ef78ada81a1366f96b3dda MD5 | raw file
  1. // Copyright 2014 The Prometheus Authors
  2. // Licensed under the Apache License, Version 2.0 (the "License");
  3. // you may not use this file except in compliance with the License.
  4. // You may obtain a copy of the License at
  5. //
  6. // http://www.apache.org/licenses/LICENSE-2.0
  7. //
  8. // Unless required by applicable law or agreed to in writing, software
  9. // distributed under the License is distributed on an "AS IS" BASIS,
  10. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. // See the License for the specific language governing permissions and
  12. // limitations under the License.
  13. package expfmt
  14. import (
  15. "math"
  16. "strings"
  17. "testing"
  18. "github.com/golang/protobuf/proto"
  19. dto "github.com/prometheus/client_model/go"
  20. )
  21. func testTextParse(t testing.TB) {
  22. var scenarios = []struct {
  23. in string
  24. out []*dto.MetricFamily
  25. }{
  26. // 0: Empty lines as input.
  27. {
  28. in: `
  29. `,
  30. out: []*dto.MetricFamily{},
  31. },
  32. // 1: Minimal case.
  33. {
  34. in: `
  35. minimal_metric 1.234
  36. another_metric -3e3 103948
  37. # Even that:
  38. no_labels{} 3
  39. # HELP line for non-existing metric will be ignored.
  40. `,
  41. out: []*dto.MetricFamily{
  42. &dto.MetricFamily{
  43. Name: proto.String("minimal_metric"),
  44. Type: dto.MetricType_UNTYPED.Enum(),
  45. Metric: []*dto.Metric{
  46. &dto.Metric{
  47. Untyped: &dto.Untyped{
  48. Value: proto.Float64(1.234),
  49. },
  50. },
  51. },
  52. },
  53. &dto.MetricFamily{
  54. Name: proto.String("another_metric"),
  55. Type: dto.MetricType_UNTYPED.Enum(),
  56. Metric: []*dto.Metric{
  57. &dto.Metric{
  58. Untyped: &dto.Untyped{
  59. Value: proto.Float64(-3e3),
  60. },
  61. TimestampMs: proto.Int64(103948),
  62. },
  63. },
  64. },
  65. &dto.MetricFamily{
  66. Name: proto.String("no_labels"),
  67. Type: dto.MetricType_UNTYPED.Enum(),
  68. Metric: []*dto.Metric{
  69. &dto.Metric{
  70. Untyped: &dto.Untyped{
  71. Value: proto.Float64(3),
  72. },
  73. },
  74. },
  75. },
  76. },
  77. },
  78. // 2: Counters & gauges, docstrings, various whitespace, escape sequences.
  79. {
  80. in: `
  81. # A normal comment.
  82. #
  83. # TYPE name counter
  84. name{labelname="val1",basename="basevalue"} NaN
  85. name {labelname="val2",basename="base\"v\\al\nue"} 0.23 1234567890
  86. # HELP name two-line\n doc str\\ing
  87. # HELP name2 doc str"ing 2
  88. # TYPE name2 gauge
  89. name2{labelname="val2" ,basename = "basevalue2" } +Inf 54321
  90. name2{ labelname = "val1" , }-Inf
  91. `,
  92. out: []*dto.MetricFamily{
  93. &dto.MetricFamily{
  94. Name: proto.String("name"),
  95. Help: proto.String("two-line\n doc str\\ing"),
  96. Type: dto.MetricType_COUNTER.Enum(),
  97. Metric: []*dto.Metric{
  98. &dto.Metric{
  99. Label: []*dto.LabelPair{
  100. &dto.LabelPair{
  101. Name: proto.String("labelname"),
  102. Value: proto.String("val1"),
  103. },
  104. &dto.LabelPair{
  105. Name: proto.String("basename"),
  106. Value: proto.String("basevalue"),
  107. },
  108. },
  109. Counter: &dto.Counter{
  110. Value: proto.Float64(math.NaN()),
  111. },
  112. },
  113. &dto.Metric{
  114. Label: []*dto.LabelPair{
  115. &dto.LabelPair{
  116. Name: proto.String("labelname"),
  117. Value: proto.String("val2"),
  118. },
  119. &dto.LabelPair{
  120. Name: proto.String("basename"),
  121. Value: proto.String("base\"v\\al\nue"),
  122. },
  123. },
  124. Counter: &dto.Counter{
  125. Value: proto.Float64(.23),
  126. },
  127. TimestampMs: proto.Int64(1234567890),
  128. },
  129. },
  130. },
  131. &dto.MetricFamily{
  132. Name: proto.String("name2"),
  133. Help: proto.String("doc str\"ing 2"),
  134. Type: dto.MetricType_GAUGE.Enum(),
  135. Metric: []*dto.Metric{
  136. &dto.Metric{
  137. Label: []*dto.LabelPair{
  138. &dto.LabelPair{
  139. Name: proto.String("labelname"),
  140. Value: proto.String("val2"),
  141. },
  142. &dto.LabelPair{
  143. Name: proto.String("basename"),
  144. Value: proto.String("basevalue2"),
  145. },
  146. },
  147. Gauge: &dto.Gauge{
  148. Value: proto.Float64(math.Inf(+1)),
  149. },
  150. TimestampMs: proto.Int64(54321),
  151. },
  152. &dto.Metric{
  153. Label: []*dto.LabelPair{
  154. &dto.LabelPair{
  155. Name: proto.String("labelname"),
  156. Value: proto.String("val1"),
  157. },
  158. },
  159. Gauge: &dto.Gauge{
  160. Value: proto.Float64(math.Inf(-1)),
  161. },
  162. },
  163. },
  164. },
  165. },
  166. },
  167. // 3: The evil summary, mixed with other types and funny comments.
  168. {
  169. in: `
  170. # TYPE my_summary summary
  171. my_summary{n1="val1",quantile="0.5"} 110
  172. decoy -1 -2
  173. my_summary{n1="val1",quantile="0.9"} 140 1
  174. my_summary_count{n1="val1"} 42
  175. # Latest timestamp wins in case of a summary.
  176. my_summary_sum{n1="val1"} 4711 2
  177. fake_sum{n1="val1"} 2001
  178. # TYPE another_summary summary
  179. another_summary_count{n2="val2",n1="val1"} 20
  180. my_summary_count{n2="val2",n1="val1"} 5 5
  181. another_summary{n1="val1",n2="val2",quantile=".3"} -1.2
  182. my_summary_sum{n1="val2"} 08 15
  183. my_summary{n1="val3", quantile="0.2"} 4711
  184. my_summary{n1="val1",n2="val2",quantile="-12.34",} NaN
  185. # some
  186. # funny comments
  187. # HELP
  188. # HELP
  189. # HELP my_summary
  190. # HELP my_summary
  191. `,
  192. out: []*dto.MetricFamily{
  193. &dto.MetricFamily{
  194. Name: proto.String("fake_sum"),
  195. Type: dto.MetricType_UNTYPED.Enum(),
  196. Metric: []*dto.Metric{
  197. &dto.Metric{
  198. Label: []*dto.LabelPair{
  199. &dto.LabelPair{
  200. Name: proto.String("n1"),
  201. Value: proto.String("val1"),
  202. },
  203. },
  204. Untyped: &dto.Untyped{
  205. Value: proto.Float64(2001),
  206. },
  207. },
  208. },
  209. },
  210. &dto.MetricFamily{
  211. Name: proto.String("decoy"),
  212. Type: dto.MetricType_UNTYPED.Enum(),
  213. Metric: []*dto.Metric{
  214. &dto.Metric{
  215. Untyped: &dto.Untyped{
  216. Value: proto.Float64(-1),
  217. },
  218. TimestampMs: proto.Int64(-2),
  219. },
  220. },
  221. },
  222. &dto.MetricFamily{
  223. Name: proto.String("my_summary"),
  224. Type: dto.MetricType_SUMMARY.Enum(),
  225. Metric: []*dto.Metric{
  226. &dto.Metric{
  227. Label: []*dto.LabelPair{
  228. &dto.LabelPair{
  229. Name: proto.String("n1"),
  230. Value: proto.String("val1"),
  231. },
  232. },
  233. Summary: &dto.Summary{
  234. SampleCount: proto.Uint64(42),
  235. SampleSum: proto.Float64(4711),
  236. Quantile: []*dto.Quantile{
  237. &dto.Quantile{
  238. Quantile: proto.Float64(0.5),
  239. Value: proto.Float64(110),
  240. },
  241. &dto.Quantile{
  242. Quantile: proto.Float64(0.9),
  243. Value: proto.Float64(140),
  244. },
  245. },
  246. },
  247. TimestampMs: proto.Int64(2),
  248. },
  249. &dto.Metric{
  250. Label: []*dto.LabelPair{
  251. &dto.LabelPair{
  252. Name: proto.String("n2"),
  253. Value: proto.String("val2"),
  254. },
  255. &dto.LabelPair{
  256. Name: proto.String("n1"),
  257. Value: proto.String("val1"),
  258. },
  259. },
  260. Summary: &dto.Summary{
  261. SampleCount: proto.Uint64(5),
  262. Quantile: []*dto.Quantile{
  263. &dto.Quantile{
  264. Quantile: proto.Float64(-12.34),
  265. Value: proto.Float64(math.NaN()),
  266. },
  267. },
  268. },
  269. TimestampMs: proto.Int64(5),
  270. },
  271. &dto.Metric{
  272. Label: []*dto.LabelPair{
  273. &dto.LabelPair{
  274. Name: proto.String("n1"),
  275. Value: proto.String("val2"),
  276. },
  277. },
  278. Summary: &dto.Summary{
  279. SampleSum: proto.Float64(8),
  280. },
  281. TimestampMs: proto.Int64(15),
  282. },
  283. &dto.Metric{
  284. Label: []*dto.LabelPair{
  285. &dto.LabelPair{
  286. Name: proto.String("n1"),
  287. Value: proto.String("val3"),
  288. },
  289. },
  290. Summary: &dto.Summary{
  291. Quantile: []*dto.Quantile{
  292. &dto.Quantile{
  293. Quantile: proto.Float64(0.2),
  294. Value: proto.Float64(4711),
  295. },
  296. },
  297. },
  298. },
  299. },
  300. },
  301. &dto.MetricFamily{
  302. Name: proto.String("another_summary"),
  303. Type: dto.MetricType_SUMMARY.Enum(),
  304. Metric: []*dto.Metric{
  305. &dto.Metric{
  306. Label: []*dto.LabelPair{
  307. &dto.LabelPair{
  308. Name: proto.String("n2"),
  309. Value: proto.String("val2"),
  310. },
  311. &dto.LabelPair{
  312. Name: proto.String("n1"),
  313. Value: proto.String("val1"),
  314. },
  315. },
  316. Summary: &dto.Summary{
  317. SampleCount: proto.Uint64(20),
  318. Quantile: []*dto.Quantile{
  319. &dto.Quantile{
  320. Quantile: proto.Float64(0.3),
  321. Value: proto.Float64(-1.2),
  322. },
  323. },
  324. },
  325. },
  326. },
  327. },
  328. },
  329. },
  330. // 4: The histogram.
  331. {
  332. in: `
  333. # HELP request_duration_microseconds The response latency.
  334. # TYPE request_duration_microseconds histogram
  335. request_duration_microseconds_bucket{le="100"} 123
  336. request_duration_microseconds_bucket{le="120"} 412
  337. request_duration_microseconds_bucket{le="144"} 592
  338. request_duration_microseconds_bucket{le="172.8"} 1524
  339. request_duration_microseconds_bucket{le="+Inf"} 2693
  340. request_duration_microseconds_sum 1.7560473e+06
  341. request_duration_microseconds_count 2693
  342. `,
  343. out: []*dto.MetricFamily{
  344. {
  345. Name: proto.String("request_duration_microseconds"),
  346. Help: proto.String("The response latency."),
  347. Type: dto.MetricType_HISTOGRAM.Enum(),
  348. Metric: []*dto.Metric{
  349. &dto.Metric{
  350. Histogram: &dto.Histogram{
  351. SampleCount: proto.Uint64(2693),
  352. SampleSum: proto.Float64(1756047.3),
  353. Bucket: []*dto.Bucket{
  354. &dto.Bucket{
  355. UpperBound: proto.Float64(100),
  356. CumulativeCount: proto.Uint64(123),
  357. },
  358. &dto.Bucket{
  359. UpperBound: proto.Float64(120),
  360. CumulativeCount: proto.Uint64(412),
  361. },
  362. &dto.Bucket{
  363. UpperBound: proto.Float64(144),
  364. CumulativeCount: proto.Uint64(592),
  365. },
  366. &dto.Bucket{
  367. UpperBound: proto.Float64(172.8),
  368. CumulativeCount: proto.Uint64(1524),
  369. },
  370. &dto.Bucket{
  371. UpperBound: proto.Float64(math.Inf(+1)),
  372. CumulativeCount: proto.Uint64(2693),
  373. },
  374. },
  375. },
  376. },
  377. },
  378. },
  379. },
  380. },
  381. }
  382. for i, scenario := range scenarios {
  383. out, err := parser.TextToMetricFamilies(strings.NewReader(scenario.in))
  384. if err != nil {
  385. t.Errorf("%d. error: %s", i, err)
  386. continue
  387. }
  388. if expected, got := len(scenario.out), len(out); expected != got {
  389. t.Errorf(
  390. "%d. expected %d MetricFamilies, got %d",
  391. i, expected, got,
  392. )
  393. }
  394. for _, expected := range scenario.out {
  395. got, ok := out[expected.GetName()]
  396. if !ok {
  397. t.Errorf(
  398. "%d. expected MetricFamily %q, found none",
  399. i, expected.GetName(),
  400. )
  401. continue
  402. }
  403. if expected.String() != got.String() {
  404. t.Errorf(
  405. "%d. expected MetricFamily %s, got %s",
  406. i, expected, got,
  407. )
  408. }
  409. }
  410. }
  411. }
  412. func TestTextParse(t *testing.T) {
  413. testTextParse(t)
  414. }
  415. func BenchmarkTextParse(b *testing.B) {
  416. for i := 0; i < b.N; i++ {
  417. testTextParse(b)
  418. }
  419. }
  420. func testTextParseError(t testing.TB) {
  421. var scenarios = []struct {
  422. in string
  423. err string
  424. }{
  425. // 0: No new-line at end of input.
  426. {
  427. in: `
  428. bla 3.14
  429. blubber 42`,
  430. err: "text format parsing error in line 3: unexpected end of input stream",
  431. },
  432. // 1: Invalid escape sequence in label value.
  433. {
  434. in: `metric{label="\t"} 3.14`,
  435. err: "text format parsing error in line 1: invalid escape sequence",
  436. },
  437. // 2: Newline in label value.
  438. {
  439. in: `
  440. metric{label="new
  441. line"} 3.14
  442. `,
  443. err: `text format parsing error in line 2: label value "new" contains unescaped new-line`,
  444. },
  445. // 3:
  446. {
  447. in: `metric{@="bla"} 3.14`,
  448. err: "text format parsing error in line 1: invalid label name for metric",
  449. },
  450. // 4:
  451. {
  452. in: `metric{__name__="bla"} 3.14`,
  453. err: `text format parsing error in line 1: label name "__name__" is reserved`,
  454. },
  455. // 5:
  456. {
  457. in: `metric{label+="bla"} 3.14`,
  458. err: "text format parsing error in line 1: expected '=' after label name",
  459. },
  460. // 6:
  461. {
  462. in: `metric{label=bla} 3.14`,
  463. err: "text format parsing error in line 1: expected '\"' at start of label value",
  464. },
  465. // 7:
  466. {
  467. in: `
  468. # TYPE metric summary
  469. metric{quantile="bla"} 3.14
  470. `,
  471. err: "text format parsing error in line 3: expected float as value for 'quantile' label",
  472. },
  473. // 8:
  474. {
  475. in: `metric{label="bla"+} 3.14`,
  476. err: "text format parsing error in line 1: unexpected end of label value",
  477. },
  478. // 9:
  479. {
  480. in: `metric{label="bla"} 3.14 2.72
  481. `,
  482. err: "text format parsing error in line 1: expected integer as timestamp",
  483. },
  484. // 10:
  485. {
  486. in: `metric{label="bla"} 3.14 2 3
  487. `,
  488. err: "text format parsing error in line 1: spurious string after timestamp",
  489. },
  490. // 11:
  491. {
  492. in: `metric{label="bla"} blubb
  493. `,
  494. err: "text format parsing error in line 1: expected float as value",
  495. },
  496. // 12:
  497. {
  498. in: `
  499. # HELP metric one
  500. # HELP metric two
  501. `,
  502. err: "text format parsing error in line 3: second HELP line for metric name",
  503. },
  504. // 13:
  505. {
  506. in: `
  507. # TYPE metric counter
  508. # TYPE metric untyped
  509. `,
  510. err: `text format parsing error in line 3: second TYPE line for metric name "metric", or TYPE reported after samples`,
  511. },
  512. // 14:
  513. {
  514. in: `
  515. metric 4.12
  516. # TYPE metric counter
  517. `,
  518. err: `text format parsing error in line 3: second TYPE line for metric name "metric", or TYPE reported after samples`,
  519. },
  520. // 14:
  521. {
  522. in: `
  523. # TYPE metric bla
  524. `,
  525. err: "text format parsing error in line 2: unknown metric type",
  526. },
  527. // 15:
  528. {
  529. in: `
  530. # TYPE met-ric
  531. `,
  532. err: "text format parsing error in line 2: invalid metric name in comment",
  533. },
  534. // 16:
  535. {
  536. in: `@invalidmetric{label="bla"} 3.14 2`,
  537. err: "text format parsing error in line 1: invalid metric name",
  538. },
  539. // 17:
  540. {
  541. in: `{label="bla"} 3.14 2`,
  542. err: "text format parsing error in line 1: invalid metric name",
  543. },
  544. // 18:
  545. {
  546. in: `
  547. # TYPE metric histogram
  548. metric_bucket{le="bla"} 3.14
  549. `,
  550. err: "text format parsing error in line 3: expected float as value for 'le' label",
  551. },
  552. }
  553. for i, scenario := range scenarios {
  554. _, err := parser.TextToMetricFamilies(strings.NewReader(scenario.in))
  555. if err == nil {
  556. t.Errorf("%d. expected error, got nil", i)
  557. continue
  558. }
  559. if expected, got := scenario.err, err.Error(); strings.Index(got, expected) != 0 {
  560. t.Errorf(
  561. "%d. expected error starting with %q, got %q",
  562. i, expected, got,
  563. )
  564. }
  565. }
  566. }
  567. func TestTextParseError(t *testing.T) {
  568. testTextParseError(t)
  569. }
  570. func BenchmarkParseError(b *testing.B) {
  571. for i := 0; i < b.N; i++ {
  572. testTextParseError(b)
  573. }
  574. }