simple_test/label/
mod.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Label matchers and Well-known label names used by Prometheus components.
16
17use std::collections::HashSet;
18use std::fmt;
19
20mod matcher;
21pub use matcher::{MatchOp, Matcher, Matchers};
22
23/// "__name__"
24pub const METRIC_NAME: &str = "__name__";
25/// "alertname"
26pub const ALERT_NAME: &str = "alertname";
27/// "le"
28pub const BUCKET_LABEL: &str = "le";
29/// "instance"
30pub const INSTANCE_NAME: &str = "instance";
31
32pub type Label = String;
33
34#[derive(Debug, Clone, PartialEq, Eq)]
35pub struct Labels {
36    pub labels: Vec<Label>,
37}
38
39impl Labels {
40    pub fn append(mut self, l: Label) -> Self {
41        self.labels.push(l);
42        self
43    }
44
45    pub fn new(ls: Vec<&str>) -> Self {
46        let labels = ls.iter().map(|s| s.to_string()).collect();
47        Self { labels }
48    }
49
50    pub fn is_empty(&self) -> bool {
51        self.labels.is_empty()
52    }
53
54    pub fn is_joint(&self, ls: &Labels) -> bool {
55        let s1: HashSet<&String> = self.labels.iter().collect();
56        let s2: HashSet<&String> = ls.labels.iter().collect();
57
58        !s1.is_disjoint(&s2)
59    }
60
61    pub fn intersect(&self, ls: &Labels) -> Labels {
62        let s1: HashSet<&String> = self.labels.iter().collect();
63        let s2: HashSet<&String> = ls.labels.iter().collect();
64        let labels = s1.intersection(&s2).map(|s| s.to_string()).collect();
65
66        Self { labels }
67    }
68}
69
70impl fmt::Display for Labels {
71    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
72        write!(f, "{}", self.labels.join(", "))
73    }
74}
75
76#[cfg(test)]
77mod tests {
78    use super::*;
79
80    #[test]
81    fn test_to_string() {
82        let cases = vec![
83            (vec![], ""),
84            (vec!["foo"], "foo"),
85            (vec!["foo", "bar"], "foo, bar"),
86            (vec!["foo", "foo", "bar"], "foo, foo, bar"),
87        ];
88
89        for (ls, expect) in cases {
90            let lb = Labels::new(ls);
91            assert_eq!(expect, lb.to_string())
92        }
93    }
94
95    #[test]
96    fn test_is_joint() {
97        let cases = vec![
98            (vec!["foo"], vec!["bar"], false),
99            (vec!["foo"], vec!["foo", "bar"], true),
100            (vec!["foo"], vec!["foo"], true),
101        ];
102
103        for (lb1, lb2, is) in cases {
104            let lb1 = Labels::new(lb1);
105            let lb2 = Labels::new(lb2);
106            assert_eq!(is, lb1.is_joint(&lb2), "{:?} and {:?}", lb1, lb2)
107        }
108    }
109
110    #[test]
111    fn test_intersect() {
112        let cases = vec![
113            (vec!["foo"], vec!["bar"], vec![]),
114            (vec!["foo"], vec!["foo", "bar"], vec!["foo"]),
115            (vec!["foo"], vec!["foo"], vec!["foo"]),
116            (vec!["foo", "bar"], vec!["bar", "foo"], vec!["foo", "bar"]),
117        ];
118
119        for (lb1, lb2, common) in cases {
120            let lb1 = Labels::new(lb1);
121            let lb2 = Labels::new(lb2);
122            let intersection: HashSet<_> = lb1.intersect(&lb2).labels.into_iter().collect();
123            let expect: HashSet<_> = common.iter().map(|s| s.to_string()).collect();
124            assert_eq!(expect, intersection)
125        }
126    }
127}