1 // This Source Code Form is subject to the terms of the Mozilla Public
2 // License, v. 2.0. If a copy of the MPL was not distributed with this
3 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
5 mod common;
6 use crate::common::*;
7
8 use serde_json::json;
9
10 use glean_core::metrics::*;
11 use glean_core::storage::StorageManager;
12 use glean_core::{test_get_num_recorded_errors, CommonMetricData, ErrorType, Lifetime};
13
14 #[test]
list_can_store_multiple_items()15 fn list_can_store_multiple_items() {
16 let (glean, _t) = new_glean(None);
17
18 let list: StringListMetric = StringListMetric::new(CommonMetricData {
19 name: "list".into(),
20 category: "local".into(),
21 send_in_pings: vec!["core".into()],
22 ..Default::default()
23 });
24
25 list.add(&glean, "first");
26 assert_eq!(list.test_get_value(&glean, "core").unwrap(), vec!["first"]);
27
28 list.add(&glean, "second");
29 assert_eq!(
30 list.test_get_value(&glean, "core").unwrap(),
31 vec!["first", "second"]
32 );
33
34 list.set(&glean, vec!["third".into()]);
35 assert_eq!(list.test_get_value(&glean, "core").unwrap(), vec!["third"]);
36
37 list.add(&glean, "fourth");
38 assert_eq!(
39 list.test_get_value(&glean, "core").unwrap(),
40 vec!["third", "fourth"]
41 );
42 }
43
44 #[test]
stringlist_serializer_should_correctly_serialize_stringlists()45 fn stringlist_serializer_should_correctly_serialize_stringlists() {
46 let (mut tempdir, _) = tempdir();
47
48 {
49 // We give tempdir to the `new_glean` function...
50 let (glean, dir) = new_glean(Some(tempdir));
51 // And then we get it back once that function returns.
52 tempdir = dir;
53
54 let metric = StringListMetric::new(CommonMetricData {
55 name: "string_list_metric".into(),
56 category: "telemetry.test".into(),
57 send_in_pings: vec!["store1".into()],
58 disabled: false,
59 lifetime: Lifetime::User,
60 ..Default::default()
61 });
62 metric.set(&glean, vec!["test_string_1".into(), "test_string_2".into()]);
63 }
64
65 {
66 let (glean, _) = new_glean(Some(tempdir));
67
68 let snapshot = StorageManager
69 .snapshot_as_json(glean.storage(), "store1", true)
70 .unwrap();
71 assert_eq!(
72 json!({"string_list": {"telemetry.test.string_list_metric": ["test_string_1", "test_string_2"]}}),
73 snapshot
74 );
75 }
76 }
77
78 #[test]
set_properly_sets_the_value_in_all_stores()79 fn set_properly_sets_the_value_in_all_stores() {
80 let (glean, _t) = new_glean(None);
81 let store_names: Vec<String> = vec!["store1".into(), "store2".into()];
82
83 let metric = StringListMetric::new(CommonMetricData {
84 name: "string_list_metric".into(),
85 category: "telemetry.test".into(),
86 send_in_pings: store_names.clone(),
87 disabled: false,
88 lifetime: Lifetime::Ping,
89 ..Default::default()
90 });
91
92 metric.set(&glean, vec!["test_string_1".into(), "test_string_2".into()]);
93
94 for store_name in store_names {
95 let snapshot = StorageManager
96 .snapshot_as_json(glean.storage(), &store_name, true)
97 .unwrap();
98
99 assert_eq!(
100 json!({"string_list": {"telemetry.test.string_list_metric": ["test_string_1", "test_string_2"]}}),
101 snapshot
102 );
103 }
104 }
105
106 #[test]
long_string_values_are_truncated()107 fn long_string_values_are_truncated() {
108 let (glean, _t) = new_glean(None);
109
110 let metric = StringListMetric::new(CommonMetricData {
111 name: "string_list_metric".into(),
112 category: "telemetry.test".into(),
113 send_in_pings: vec!["store1".into()],
114 disabled: false,
115 lifetime: Lifetime::Ping,
116 ..Default::default()
117 });
118
119 let test_string = "0123456789".repeat(20);
120 metric.add(&glean, test_string.clone());
121
122 // Ensure the string was truncated to the proper length.
123 assert_eq!(
124 vec![test_string[..50].to_string()],
125 metric.test_get_value(&glean, "store1").unwrap()
126 );
127
128 // Ensure the error has been recorded.
129 assert_eq!(
130 Ok(1),
131 test_get_num_recorded_errors(&glean, metric.meta(), ErrorType::InvalidOverflow, None)
132 );
133
134 metric.set(&glean, vec![test_string.clone()]);
135
136 // Ensure the string was truncated to the proper length.
137 assert_eq!(
138 vec![test_string[..50].to_string()],
139 metric.test_get_value(&glean, "store1").unwrap()
140 );
141
142 // Ensure the error has been recorded.
143 assert_eq!(
144 Ok(2),
145 test_get_num_recorded_errors(&glean, metric.meta(), ErrorType::InvalidOverflow, None)
146 );
147 }
148
149 #[test]
disabled_string_lists_dont_record()150 fn disabled_string_lists_dont_record() {
151 let (glean, _t) = new_glean(None);
152
153 let metric = StringListMetric::new(CommonMetricData {
154 name: "string_list_metric".into(),
155 category: "telemetry.test".into(),
156 send_in_pings: vec!["store1".into()],
157 disabled: true,
158 lifetime: Lifetime::Ping,
159 ..Default::default()
160 });
161
162 metric.add(&glean, "test_string".repeat(20));
163
164 // Ensure the string was not added.
165 assert_eq!(None, metric.test_get_value(&glean, "store1"));
166
167 metric.set(&glean, vec!["test_string_2".repeat(20)]);
168
169 // Ensure the stringlist was not set.
170 assert_eq!(None, metric.test_get_value(&glean, "store1"));
171
172 // Ensure no error was recorded.
173 assert!(
174 test_get_num_recorded_errors(&glean, metric.meta(), ErrorType::InvalidValue, None).is_err()
175 );
176 }
177
178 #[test]
string_lists_dont_exceed_max_items()179 fn string_lists_dont_exceed_max_items() {
180 let (glean, _t) = new_glean(None);
181
182 let metric = StringListMetric::new(CommonMetricData {
183 name: "string_list_metric".into(),
184 category: "telemetry.test".into(),
185 send_in_pings: vec!["store1".into()],
186 disabled: false,
187 lifetime: Lifetime::Ping,
188 ..Default::default()
189 });
190
191 for _n in 1..21 {
192 metric.add(&glean, "test_string");
193 }
194
195 let expected: Vec<String> = "test_string "
196 .repeat(20)
197 .split_whitespace()
198 .map(|s| s.to_string())
199 .collect();
200 assert_eq!(expected, metric.test_get_value(&glean, "store1").unwrap());
201
202 // Ensure the 21st string wasn't added.
203 metric.add(&glean, "test_string");
204 assert_eq!(expected, metric.test_get_value(&glean, "store1").unwrap());
205
206 // Ensure we recorded the error.
207 assert_eq!(
208 Ok(1),
209 test_get_num_recorded_errors(&glean, metric.meta(), ErrorType::InvalidValue, None)
210 );
211
212 // Try to set it to a list that's too long. Ensure it cuts off at 20 elements.
213 let too_many: Vec<String> = "test_string "
214 .repeat(21)
215 .split_whitespace()
216 .map(|s| s.to_string())
217 .collect();
218 metric.set(&glean, too_many);
219 assert_eq!(expected, metric.test_get_value(&glean, "store1").unwrap());
220
221 assert_eq!(
222 Ok(2),
223 test_get_num_recorded_errors(&glean, metric.meta(), ErrorType::InvalidValue, None)
224 );
225 }
226
227 #[test]
set_does_not_record_error_when_receiving_empty_list()228 fn set_does_not_record_error_when_receiving_empty_list() {
229 let (glean, _t) = new_glean(None);
230
231 let metric = StringListMetric::new(CommonMetricData {
232 name: "string_list_metric".into(),
233 category: "telemetry.test".into(),
234 send_in_pings: vec!["store1".into()],
235 disabled: false,
236 lifetime: Lifetime::Ping,
237 ..Default::default()
238 });
239
240 metric.set(&glean, vec![]);
241
242 // Ensure the empty list was added
243 assert_eq!(Some(vec![]), metric.test_get_value(&glean, "store1"));
244
245 // Ensure we didn't record an error.
246 assert!(
247 test_get_num_recorded_errors(&glean, metric.meta(), ErrorType::InvalidValue, None).is_err()
248 );
249 }
250