aws_runtime/user_agent/
test_util.rs

1/*
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6//! Utilities for testing the User-Agent header
7
8use regex_lite::Regex;
9use std::sync::LazyLock;
10
11// regular expression pattern for base64 numeric values
12#[allow(dead_code)]
13static RE: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"m/([A-Za-z0-9+/=_,-]+)").unwrap());
14
15/// Helper function to check metric values in user agent
16fn check_ua_metric_values(user_agent: &str, values: &[&str], should_contain: bool) {
17    match extract_ua_values(user_agent) {
18        Some(metrics) => {
19            let mut problematic_values = vec![];
20
21            for value in values.iter() {
22                let contains = metrics.contains(value);
23                if (should_contain && !contains) || (!should_contain && contains) {
24                    problematic_values.push(value);
25                }
26            }
27
28            if !problematic_values.is_empty() {
29                if should_contain {
30                    panic!("metric values {problematic_values:?} not found in `{user_agent}`");
31                } else {
32                    panic!(
33                        "metric values {problematic_values:?} unexpectedly found in `{user_agent}`"
34                    );
35                }
36            }
37        }
38        None => {
39            if should_contain {
40                panic!("the pattern for business-metrics `m/(metric_id) *(comma metric_id)` not found in `{user_agent}`");
41            }
42            // For "does not contain", no metrics pattern means the assertion passes
43        }
44    }
45}
46
47/// Asserts `user_agent` contains all metric values `values`
48///
49/// Refer to the end of the parent module file `user_agent.rs` for the complete ABNF specification
50/// of `business-metrics`.
51pub fn assert_ua_contains_metric_values(user_agent: &str, values: &[&str]) {
52    check_ua_metric_values(user_agent, values, true);
53}
54
55/// Asserts `user_agent` does NOT contain any of the metric values `values`
56///
57/// Refer to the end of the parent module file `user_agent.rs` for the complete ABNF specification
58/// of `business-metrics`.
59pub fn assert_ua_does_not_contain_metric_values(user_agent: &str, values: &[&str]) {
60    check_ua_metric_values(user_agent, values, false);
61}
62
63/// Extract the metric values from the `user_agent` string
64pub fn extract_ua_values(user_agent: &str) -> Option<Vec<&str>> {
65    RE.find(user_agent).map(|matched| {
66        matched
67            .as_str()
68            .strip_prefix("m/")
69            .expect("prefix `m/` is guaranteed to exist by regex match")
70            .split(',')
71            .collect()
72    })
73}
74
75#[cfg(test)]
76mod tests {
77    use super::*;
78
79    #[test]
80    fn test_assert_ua_contains_metric_values() {
81        assert_ua_contains_metric_values("m/A", &[]);
82        assert_ua_contains_metric_values("m/A", &["A"]);
83        assert_ua_contains_metric_values(" m/A", &["A"]);
84        assert_ua_contains_metric_values("m/A ", &["A"]);
85        assert_ua_contains_metric_values(" m/A ", &["A"]);
86        assert_ua_contains_metric_values("m/A,B", &["B"]);
87        assert_ua_contains_metric_values("m/A,B", &["A", "B"]);
88        assert_ua_contains_metric_values("m/A,B", &["B", "A"]);
89        assert_ua_contains_metric_values("m/A,B,C", &["B"]);
90        assert_ua_contains_metric_values("m/A,B,C", &["B", "C"]);
91        assert_ua_contains_metric_values("m/A,B,C", &["A", "B", "C"]);
92        assert_ua_contains_metric_values("m/A,B,C,AA", &["AA"]);
93        assert_ua_contains_metric_values("m/A,B,C=,AA", &["C="]);
94        assert_ua_contains_metric_values(
95            "aws-sdk-rust/0.123.test api/test-service/0.123 os/windows/XPSP3 lang/rust/1.50.0 m/A",
96            &["A"],
97        );
98        assert_ua_contains_metric_values(
99            "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",
100            &["A"]
101        );
102    }
103
104    #[test]
105    #[should_panic(expected = "the pattern for business-metrics")]
106    fn empty_ua_fails_assert() {
107        assert_ua_contains_metric_values("", &["A"]);
108    }
109
110    #[test]
111    #[should_panic(expected = "the pattern for business-metrics")]
112    fn invalid_business_metrics_pattern_fails_assert() {
113        assert_ua_contains_metric_values("mA", &["A"]);
114    }
115
116    #[test]
117    #[should_panic(expected = "the pattern for business-metrics")]
118    fn another_invalid_business_metrics_pattern_fails_assert() {
119        assert_ua_contains_metric_values("m/", &["A"]);
120    }
121
122    #[test]
123    #[should_panic(expected = "metric values [\"\"] not found in `m/A`")]
124    fn empty_metric_value_fails_assert() {
125        assert_ua_contains_metric_values("m/A", &[""]);
126    }
127
128    #[test]
129    #[should_panic(expected = "metric values [\"A\"] not found in `m/AA`")]
130    fn business_metrics_do_not_contain_given_metric_value() {
131        assert_ua_contains_metric_values("m/AA", &["A"]);
132    }
133
134    #[test]
135    #[should_panic(expected = "the pattern for business-metrics")]
136    fn ua_containing_no_business_metrics_fails_assert() {
137        assert_ua_contains_metric_values(
138            "aws-sdk-rust/0.123.test api/test-service/0.123 os/windows/XPSP3 lang/rust/1.50.0",
139            &["A"],
140        );
141    }
142
143    #[test]
144    #[should_panic(expected = "the pattern for business-metrics")]
145    fn ua_containing_invalid_business_metrics_fails_assert() {
146        assert_ua_contains_metric_values(
147            "aws-sdk-rust/0.123.test api/test-service/0.123 os/windows/XPSP3 lang/rust/1.50.0 mA",
148            &["A"],
149        );
150    }
151}