Skip to content

Commit c4900e2

Browse files
committed
Pin raw Prometheus parser fidelity regressions
1 parent afde954 commit c4900e2

1 file changed

Lines changed: 34 additions & 6 deletions

File tree

crates/timeless-core/tests/prom_ingest.rs

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
//! 2. Explicit timestamps > 1e12 (the Prometheus wire unit: epoch
88
//! MILLISECONDS) are normalized to SECONDS (/1000). This is the fact
99
//! that forces the vtab's "default_ts is seconds" unit decision.
10-
//! 3. Malformed non-comment lines and NaN values are COUNTED as errors
10+
//! 3. Malformed non-comment lines and non-finite values are COUNTED as errors
1111
//! but never abort the body — partial success is the contract.
1212
//! 4. Comments / HELP / TYPE / blank lines are free: neither samples nor
1313
//! errors.
@@ -38,13 +38,18 @@ fn prometheus_ingest_semantics() {
3838
http_requests_total 1027\n\
3939
node_temp_celsius{sensor=\"cpu0\",host=\"pvm1\"} 42.5 1753000000123\n\
4040
this line is definitely not prometheus !!!\n\
41-
bad_metric NaN\n";
41+
bad_metric NaN\n\
42+
positive_inf Inf\n\
43+
negative_inf -Inf\n";
4244

4345
// default_ts is deterministic here (no wall clock in a unit test).
4446
let default_ts: i64 = 1_800_000_000;
4547
let (count, errors) = engine.ingest_prometheus(body, default_ts).unwrap();
4648
assert_eq!(count, 2, "counter + gauge ingested; comments are free");
47-
assert_eq!(errors, 2, "malformed line + NaN line each count once");
49+
assert_eq!(
50+
errors, 4,
51+
"malformed line + three non-finite lines count once"
52+
);
4853

4954
// Rule 1: no-timestamp sample carries default_ts VERBATIM (seconds).
5055
let sid = engine
@@ -73,6 +78,29 @@ fn prometheus_ingest_semantics() {
7378
"explicit 1753000000123 ms must be stored as 1753000000 s"
7479
);
7580

81+
let escaped_body =
82+
b"escaped_labels{path=\"a\\\"b\",note=\"x\\\\y\"} 7 1800000000000\r\ncrlf_metric 9\r\n";
83+
let (count, errors) = engine.ingest_prometheus(escaped_body, default_ts).unwrap();
84+
assert_eq!((count, errors), (2, 0));
85+
let escaped: HashMap<String, String> = [
86+
("path".to_string(), r#"a\"b"#.to_string()),
87+
("note".to_string(), r#"x\\y"#.to_string()),
88+
]
89+
.into_iter()
90+
.collect();
91+
let sid = engine.resolve_cached("escaped_labels", &escaped).unwrap();
92+
assert_eq!(
93+
engine.query_range_by_id(sid, 0, i64::MAX - 1).unwrap(),
94+
vec![(1_800_000_000, 7.0)]
95+
);
96+
let sid = engine
97+
.resolve_cached("crlf_metric", &HashMap::new())
98+
.unwrap();
99+
assert_eq!(
100+
engine.query_range_by_id(sid, 0, i64::MAX - 1).unwrap(),
101+
vec![(default_ts, 9.0)]
102+
);
103+
76104
// Rule 3 corollary: an all-garbage body yields (0, N) — the vtab
77105
// turns exactly that shape into its "0 samples ingested" error.
78106
let (count, errors) = engine
@@ -81,9 +109,9 @@ fn prometheus_ingest_semantics() {
81109
assert_eq!((count, errors), (0, 2));
82110

83111
let info = engine.info();
84-
assert_eq!(info.prometheus_ingest_batches, 2);
85-
assert_eq!(info.prometheus_ingest_points, 2);
86-
assert_eq!(info.prometheus_ingest_errors, 4);
112+
assert_eq!(info.prometheus_ingest_batches, 3);
113+
assert_eq!(info.prometheus_ingest_points, 4);
114+
assert_eq!(info.prometheus_ingest_errors, 6);
87115
assert!(info.prometheus_ingest_total_ns > 0);
88116

89117
engine.shutdown().unwrap();

0 commit comments

Comments
 (0)