1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0
 */

//! Utilities for testing the User-Agent header

use once_cell::sync::Lazy;
use regex_lite::Regex;

// regular expression pattern for base64 numeric values
#[allow(dead_code)]
static RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"m/([A-Za-z0-9+/=_,-]+)").unwrap());

/// Asserts `user_agent` contains all metric values `values`
///
/// Refer to the end of the parent module file `user_agent.rs` for the complete ABNF specification
/// of `business-metrics`.
pub fn assert_ua_contains_metric_values(user_agent: &str, values: &[&str]) {
    match RE.find(user_agent) {
        Some(matched) => {
            let csv = matched
                .as_str()
                .strip_prefix("m/")
                .expect("prefix `m/` is guaranteed to exist by regex match");
            let metrics: Vec<&str> = csv.split(',').collect();
            let mut missed = vec![];

            for value in values.iter() {
                if !metrics.contains(value) {
                    missed.push(value);
                }
            }
            assert!(
                missed.is_empty(),
                "{}",
                format!("metric values {missed:?} not found in `{user_agent}`")
            );
        }
        None => {
            panic!("{}", format!("the pattern for business-metrics `m/(metric_id) *(comma metric_id)` not found in `{user_agent}`"))
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_assert_ua_contains_metric_values() {
        assert_ua_contains_metric_values("m/A", &[]);
        assert_ua_contains_metric_values("m/A", &["A"]);
        assert_ua_contains_metric_values(" m/A", &["A"]);
        assert_ua_contains_metric_values("m/A ", &["A"]);
        assert_ua_contains_metric_values(" m/A ", &["A"]);
        assert_ua_contains_metric_values("m/A,B", &["B"]);
        assert_ua_contains_metric_values("m/A,B", &["A", "B"]);
        assert_ua_contains_metric_values("m/A,B", &["B", "A"]);
        assert_ua_contains_metric_values("m/A,B,C", &["B"]);
        assert_ua_contains_metric_values("m/A,B,C", &["B", "C"]);
        assert_ua_contains_metric_values("m/A,B,C", &["A", "B", "C"]);
        assert_ua_contains_metric_values("m/A,B,C,AA", &["AA"]);
        assert_ua_contains_metric_values("m/A,B,C=,AA", &["C="]);
        assert_ua_contains_metric_values(
            "aws-sdk-rust/0.123.test api/test-service/0.123 os/windows/XPSP3 lang/rust/1.50.0 m/A",
            &["A"],
        );
        assert_ua_contains_metric_values(
            "aws-sdk-rust/0.123.test api/test-service/0.123 os/windows/XPSP3 lang/rust/1.50.0 m/A md/http#capture-request-handler",
            &["A"]
        );
    }

    #[test]
    #[should_panic(expected = "the pattern for business-metrics")]
    fn empty_ua_fails_assert() {
        assert_ua_contains_metric_values("", &["A"]);
    }

    #[test]
    #[should_panic(expected = "the pattern for business-metrics")]
    fn invalid_business_metrics_pattern_fails_assert() {
        assert_ua_contains_metric_values("mA", &["A"]);
    }

    #[test]
    #[should_panic(expected = "the pattern for business-metrics")]
    fn another_invalid_business_metrics_pattern_fails_assert() {
        assert_ua_contains_metric_values("m/", &["A"]);
    }

    #[test]
    #[should_panic(expected = "metric values [\"\"] not found in `m/A`")]
    fn empty_metric_value_fails_assert() {
        assert_ua_contains_metric_values("m/A", &[""]);
    }

    #[test]
    #[should_panic(expected = "metric values [\"A\"] not found in `m/AA`")]
    fn business_metrics_do_not_contain_given_metric_value() {
        assert_ua_contains_metric_values("m/AA", &["A"]);
    }

    #[test]
    #[should_panic(expected = "the pattern for business-metrics")]
    fn ua_containing_no_business_metrics_fails_assert() {
        assert_ua_contains_metric_values(
            "aws-sdk-rust/0.123.test api/test-service/0.123 os/windows/XPSP3 lang/rust/1.50.0",
            &["A"],
        );
    }

    #[test]
    #[should_panic(expected = "the pattern for business-metrics")]
    fn ua_containing_invalid_business_metrics_fails_assert() {
        assert_ua_contains_metric_values(
            "aws-sdk-rust/0.123.test api/test-service/0.123 os/windows/XPSP3 lang/rust/1.50.0 mA",
            &["A"],
        );
    }
}