// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
mod common;
use crate::common::*;
use glean_core::metrics::*;
use glean_core::ping::PingMaker;
use glean_core::{CommonMetricData, Glean, Lifetime};
fn set_up_basic_ping() -> (Glean, PingMaker, PingType, tempfile::TempDir) {
let (tempdir, _) = tempdir();
let (
mut glean, t) = new_glean(Some(tempdir));
let ping_maker = PingMaker::new();
let ping_type = new_test_ping(&
mut glean,
"store1");
// Record something, so the ping will have data
let metric = BooleanMetric::new(CommonMetricData {
name:
"boolean_metric".into(),
category:
"telemetry".into(),
send_in_pings: vec![
"store1".into()],
disabled:
false,
lifetime: Lifetime::User,
..Default::default()
});
metric.set_sync(&glean,
true);
(glean, ping_maker, ping_type, t)
}
#[test]
fn ping_info_must_contain_a_nonempty_start_and_end_time() {
let (glean, ping_maker, ping_type, _t) = set_up_basic_ping();
let ping = ping_maker
.collect(&glean, &ping_type, None,
"",
"")
.unwrap();
let ping_info = ping.content[
"ping_info"].as_object().unwrap();
let start_time_str = ping_info[
"start_time"].as_str().unwrap();
let start_time_date = iso8601_to_chrono(&iso8601::datetime(start_time_str).unwrap());
let end_time_str = ping_info[
"end_time"].as_str().unwrap();
let end_time_date = iso8601_to_chrono(&iso8601::datetime(end_time_str).unwrap());
assert!(start_time_date <= end_time_date);
}
#[test]
fn get_ping_info_must_report_all_the_required_fields() {
let (glean, ping_maker, ping_type, _t) = set_up_basic_ping();
let ping = ping_maker
.collect(&glean, &ping_type, None,
"",
"")
.unwrap();
let ping_info = ping.content[
"ping_info"].as_object().unwrap();
assert!(ping_info.get(
"start_time").is_some());
assert!(ping_info.get(
"end_time").is_some());
assert!(ping_info.get(
"seq").is_some());
}
#[test]
fn get_client_info_must_report_all_the_available_data() {
let (glean, ping_maker, ping_type, _t) = set_up_basic_ping();
let ping = ping_maker
.collect(&glean, &ping_type, None,
"",
"")
.unwrap();
let client_info = ping.content[
"client_info"].as_object().unwrap();
client_info[
"telemetry_sdk_build"].as_str().unwrap();
}
#[test]
fn test_metrics_must_report_experimentation_id() {
let (tempdir, _) = tempdir();
let mut glean = Glean::new(glean_core::InternalConfiguration {
data_path: tempdir.path().display().to_string(),
application_id: GLOBAL_APPLICATION_ID.into(),
language_binding_name:
"Rust".into(),
upload_enabled:
true,
max_events: None,
delay_ping_lifetime_io:
false,
app_build:
"Unknown".into(),
use_core_mps:
false,
trim_data_to_registered_pings:
false,
log_level: None,
rate_limit: None,
enable_event_timestamps:
true,
experimentation_id: Some(
"test-experimentation-id".to_string()),
enable_internal_pings:
true,
ping_schedule: Default::default(),
ping_lifetime_threshold:
0,
ping_lifetime_max_time:
0,
})
.unwrap();
let ping_maker = PingMaker::new();
let ping_type = PingType::new(
"store1",
true,
false,
true,
true,
true,
vec![],
vec![],
true,
);
glean.register_ping_type(&ping_type);
// Record something, so the ping will have data
let metric = BooleanMetric::new(CommonMetricData {
name:
"boolean_metric".into(),
category:
"telemetry".into(),
send_in_pings: vec![
"store1".into()],
disabled:
false,
lifetime: Lifetime::User,
..Default::default()
});
metric.set_sync(&glean,
true);
let ping = ping_maker
.collect(&glean, &ping_type, None,
"",
"")
.unwrap();
let metrics = ping.content[
"metrics"].as_object().unwrap();
println!(
"TLDEBUG Metrics:\n{:?}", metrics);
let strings = metrics[
"string"].as_object().unwrap();
assert_eq!(
strings[
"glean.client.annotation.experimentation_id"]
.as_str()
.unwrap(),
"test-experimentation-id",
"experimentation ids must match"
);
}
#[test]
fn experimentation_id_is_removed_if_send_if_empty_is_false() {
// Initialize Glean with an experimentation id, it should be removed if the ping is empty
// and send_if_empty is false.
let (tempdir, _) = tempdir();
let mut glean = Glean::new(glean_core::InternalConfiguration {
data_path: tempdir.path().display().to_string(),
application_id: GLOBAL_APPLICATION_ID.into(),
language_binding_name:
"Rust".into(),
upload_enabled:
true,
max_events: None,
delay_ping_lifetime_io:
false,
app_build:
"Unknown".into(),
use_core_mps:
false,
trim_data_to_registered_pings:
false,
log_level: None,
rate_limit: None,
enable_event_timestamps:
true,
experimentation_id: Some(
"test-experimentation-id".to_string()),
enable_internal_pings:
true,
ping_schedule: Default::default(),
ping_lifetime_threshold:
0,
ping_lifetime_max_time:
0,
})
.unwrap();
let ping_maker = PingMaker::new();
let unknown_ping_type = PingType::new(
"unknown",
true,
false,
true,
true,
true,
vec![],
vec![],
true,
);
glean.register_ping_type(&unknown_ping_type);
assert!(ping_maker
.collect(&glean, &unknown_ping_type, None,
"",
"")
.is_none());
}
#[test]
fn collect_must_report_none_when_no_data_is_stored() {
// NOTE: This is a behavior change from glean-ac which returned an empty
// string in this case. As this is an implementation detail and not part of
// the public API, it's safe to change this.
let (
mut glean, ping_maker, ping_type, _t) = set_up_basic_ping();
let unknown_ping_type = PingType::new(
"unknown",
true,
false,
true,
true,
true,
vec![],
vec![],
true,
);
glean.register_ping_type(&ping_type);
assert!(ping_maker
.collect(&glean, &unknown_ping_type, None,
"",
"")
.is_none());
}
#[test]
fn seq_number_must_be_sequential() {
let (
mut glean, ping_maker, _ping_type, _t) = set_up_basic_ping();
let metric = BooleanMetric::new(CommonMetricData {
name:
"boolean_metric".into(),
category:
"telemetry".into(),
send_in_pings: vec![
"store2".into()],
disabled:
false,
lifetime: Lifetime::User,
..Default::default()
});
metric.set_sync(&glean,
true);
for i
in 0..=
1 {
for ping_name
in [
"store1",
"store2"].iter() {
let ping_type = PingType::new(
*ping_name,
true,
false,
true,
true,
true,
vec![],
vec![],
true,
);
let ping = ping_maker
.collect(&glean, &ping_type, None,
"",
"")
.unwrap();
let seq_num = ping.content[
"ping_info"][
"seq"].as_i64().unwrap();
// Ensure sequence numbers in different stores are independent of
// each other
assert_eq!(i, seq_num);
}
}
// Test that ping sequence numbers increase independently.
{
let ping_type = new_test_ping(&
mut glean,
"store1");
// 3rd ping of store1
let ping = ping_maker
.collect(&glean, &ping_type, None,
"",
"")
.unwrap();
let seq_num = ping.content[
"ping_info"][
"seq"].as_i64().unwrap();
assert_eq!(
2, seq_num);
// 4th ping of store1
let ping = ping_maker
.collect(&glean, &ping_type, None,
"",
"")
.unwrap();
let seq_num = ping.content[
"ping_info"][
"seq"].as_i64().unwrap();
assert_eq!(
3, seq_num);
}
{
let ping_type = new_test_ping(&
mut glean,
"store2");
// 3rd ping of store2
let ping = ping_maker
.collect(&glean, &ping_type, None,
"",
"")
.unwrap();
let seq_num = ping.content[
"ping_info"][
"seq"].as_i64().unwrap();
assert_eq!(
2, seq_num);
}
{
let ping_type = new_test_ping(&
mut glean,
"store1");
// 5th ping of store1
let ping = ping_maker
.collect(&glean, &ping_type, None,
"",
"")
.unwrap();
let seq_num = ping.content[
"ping_info"][
"seq"].as_i64().unwrap();
assert_eq!(
4, seq_num);
}
}
#[test]
fn clear_pending_pings() {
let (
mut glean, _t) = new_glean(None);
let ping_maker = PingMaker::new();
let ping_type = new_test_ping(&
mut glean,
"store1");
// Record something, so the ping will have data
let metric = BooleanMetric::new(CommonMetricData {
name:
"boolean_metric".into(),
category:
"telemetry".into(),
send_in_pings: vec![
"store1".into()],
disabled:
false,
lifetime: Lifetime::User,
..Default::default()
});
metric.set_sync(&glean,
true);
assert!(ping_type.submit_sync(&glean, None));
assert_eq!(
1, get_queued_pings(glean.get_data_path()).unwrap().len());
let disabled_pings = &[
"store1"][..];
assert!(ping_maker
.clear_pending_pings(glean.get_data_path(), disabled_pings)
.is_ok());
assert_eq!(
0, get_queued_pings(glean.get_data_path()).unwrap().len());
}
#[test]
fn no_pings_submitted_if_upload_disabled() {
// Regression test, bug 1603571
let (
mut glean, _t) = new_glean(None);
let ping_type = PingType::new(
"store1",
true,
true,
true,
true,
true, vec![], vec![],
true)
;
glean.register_ping_type(&ping_type);
assert!(ping_type.submit_sync(&glean, None));
assert_eq!(1, get_queued_pings(glean.get_data_path()).unwrap().len());
// Disable upload, then try to sumbit
glean.set_upload_enabled(false);
// Test again through the direct call
assert!(!ping_type.submit_sync(&glean, None));
assert_eq!(0, get_queued_pings(glean.get_data_path()).unwrap().len());
}
#[test]
fn metadata_is_correctly_added_when_necessary() {
let (mut glean, _t) = new_glean(None);
glean.set_debug_view_tag("valid-tag");
let ping_type = PingType::new("store1", true, true, true, true, true, vec![], vec![], true);
glean.register_ping_type(&ping_type);
assert!(ping_type.submit_sync(&glean, None));
let (_, _, metadata) = &get_queued_pings(glean.get_data_path()).unwrap()[0];
let headers = metadata.as_ref().unwrap().get("headers").unwrap();
assert_eq!(headers.get("X-Debug-ID").unwrap(), "valid-tag");
}