// 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::CommonMetricData; use glean_core::Glean; use glean_core::Lifetime; fn nofollows_ping(glean: &mut Glean) -> PingType { // When `follows_collection_enabled=false` then by default `enabled=false` let ping = PingType::new( "nofollows", /* include_client_id */ false, /* send_if_empty */ true, /* precise_timestamps */ true, /* include_info_sections */ false, /* enabled */ false, vec![], vec![], /* follows_collection_enabled */ false, ); glean.register_ping_type(&ping); ping } fn manual_ping(glean: &mut Glean) -> PingType { let ping = PingType::new( "manual", /* include_client_id */ true, /* send_if_empty */ false, /* precise_timestamps */ true, /* include_info_sections */ true, /* enabled */ true, vec![], vec![], /* collection_enabled */ true, ); glean.register_ping_type(&ping); ping } #[test] fn pings_with_follows_false_are_exempt() { let (mut glean, _t) = new_glean(None); let ping = nofollows_ping(&mut glean); // We need to store a metric as an empty ping is not stored. let counter = CounterMetric::new(CommonMetricData { name: "counter".into(), category: "local".into(), send_in_pings: vec!["nofollows".into()], ..Default::default() }); counter.add_sync(&glean, 1); assert!(!ping.submit_sync(&glean, None)); glean.set_ping_enabled(&ping, true); counter.add_sync(&glean, 2); assert!(ping.submit_sync(&glean, None)); let mut queued_pings = get_queued_pings(glean.get_data_path()).unwrap(); assert_eq!(1, queued_pings.len()); let json = queued_pings.pop().unwrap().1; let counter_val = json["metrics"]["counter"]["local.counter"] .as_i64() .unwrap(); assert_eq!(2, counter_val); glean.set_upload_enabled(false); assert_eq!(1, get_queued_pings(glean.get_data_path()).unwrap().len()); // Disabling upload generates a deletion ping assert_eq!(1, get_deletion_pings(glean.get_data_path()).unwrap().len()); // Regardless, the `nofollows` ping is still enabled. counter.add_sync(&glean, 10); assert!(ping.submit_sync(&glean, None)); let queued_pings = get_queued_pings(glean.get_data_path()).unwrap(); // both `nofollows` pings remain in the queue assert_eq!(2, queued_pings.len()); let mut values = vec![2, 10]; for ping in queued_pings { let json = ping.1; let counter_val = json["metrics"]["counter"]["local.counter"] .as_i64() .unwrap(); assert!(values.contains(&counter_val)); values.retain(|&x| x != counter_val); } } #[test] fn nofollows_ping_can_ride_along() { let (mut glean, _t) = new_glean(None); let nofollows_ping = nofollows_ping(&mut glean); // Basically `manual_ping` but with a ride-along let manual_ping = PingType::new( "manual", /* include_client_id */ true, /* send_if_empty */ false, /* precise_timestamps */ true, /* include_info_sections */ true, /* enabled */ true, vec!["nofollows".to_string()], vec![], /* collection_enabled */ true, ); glean.register_ping_type(&manual_ping); // We need to store a metric as an empty ping is not stored. let counter = CounterMetric::new(CommonMetricData { name: "counter".into(), category: "local".into(), send_in_pings: vec!["manual".into(), "nofollows".into()], lifetime: Lifetime::Application, ..Default::default() }); // Trigger a ping with data. counter.add_sync(&glean, 1); assert!(manual_ping.submit_sync(&glean, None)); assert_eq!(1, get_queued_pings(glean.get_data_path()).unwrap().len()); // Enable one more ping, trigger it with more data glean.set_ping_enabled(&nofollows_ping, true); counter.add_sync(&glean, 2); assert!(manual_ping.submit_sync(&glean, None)); // The previous one, plus 2 new ones let queued_pings = get_queued_pings(glean.get_data_path()).unwrap(); assert_eq!(3, queued_pings.len()); for (_url, json, info) in queued_pings { let Some(obj) = info else { panic!("no ping info") }; let counter_val = json["metrics"]["counter"]["local.counter"] .as_i64() .unwrap(); if obj["ping_name"].as_str().unwrap() == "nofollows" { assert_eq!(2, counter_val, "{:?}", json); } else { let seq = json["ping_info"]["seq"].as_i64().unwrap(); match seq { 0 => assert_eq!(1, counter_val), 1 => assert_eq!(3, counter_val), 2 => assert_eq!(8, counter_val), _ => panic!("unexpected sequence number: {}", seq), } } } // Disable it again glean.set_ping_enabled(&nofollows_ping, false); counter.add_sync(&glean, 5); assert!(manual_ping.submit_sync(&glean, None)); let queued_pings = get_queued_pings(glean.get_data_path()).unwrap(); // The 2 previous `manual` pings, the `nofollows` was removed, plus the new `manual` one assert_eq!(3, queued_pings.len()); // Check that all follows are as expected. // We cannot guarantee order, so we need to look at some values for (_url, json, info) in queued_pings { let Some(obj) = info else { panic!("no ping info") }; let counter_val = json["metrics"]["counter"]["local.counter"] .as_i64() .unwrap(); assert_ne!("nofollows", obj["ping_name"].as_str().unwrap()); let seq = json["ping_info"]["seq"].as_i64().unwrap(); match seq { 0 => assert_eq!(1, counter_val), 1 => assert_eq!(3, counter_val), 2 => assert_eq!(8, counter_val), _ => panic!("unexpected sequence number: {}", seq), } } } #[test] fn queued_nofollows_pings_are_not_removed() { let (mut glean, t) = new_glean(None); let nofollows_ping = nofollows_ping(&mut glean); let manual_ping = manual_ping(&mut glean); glean.set_ping_enabled(&nofollows_ping, true); // We need to store a metric as an empty ping is not stored. let counter = CounterMetric::new(CommonMetricData { name: "counter".into(), category: "local".into(), send_in_pings: vec!["manual".into(), "nofollows".into()], lifetime: Lifetime::Application, ..Default::default() }); // Trigger a ping with data. counter.add_sync(&glean, 1); assert!(manual_ping.submit_sync(&glean, None)); assert!(nofollows_ping.submit_sync(&glean, None)); assert_eq!(2, get_queued_pings(glean.get_data_path()).unwrap().len()); glean.set_upload_enabled(false); assert_eq!(1, get_queued_pings(glean.get_data_path()).unwrap().len()); // Ping is still there after a Glean restart let (glean, _t) = new_glean(Some(t)); assert_eq!(1, get_queued_pings(glean.get_data_path()).unwrap().len()); }