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 use inherent::inherent; 6 7 use uuid::Uuid; 8 9 use super::{CommonMetricData, MetricId}; 10 11 use crate::ipc::need_ipc; 12 13 /// A UUID metric. 14 /// 15 /// Stores UUID values. 16 pub enum UuidMetric { 17 Parent(glean::private::UuidMetric), 18 Child(UuidMetricIpc), 19 } 20 21 #[derive(Debug)] 22 pub struct UuidMetricIpc; 23 24 impl UuidMetric { 25 /// Create a new UUID metric. new(_id: MetricId, meta: CommonMetricData) -> Self26 pub fn new(_id: MetricId, meta: CommonMetricData) -> Self { 27 if need_ipc() { 28 UuidMetric::Child(UuidMetricIpc) 29 } else { 30 UuidMetric::Parent(glean::private::UuidMetric::new(meta)) 31 } 32 } 33 34 #[cfg(test)] child_metric(&self) -> Self35 pub(crate) fn child_metric(&self) -> Self { 36 match self { 37 UuidMetric::Parent(_) => UuidMetric::Child(UuidMetricIpc), 38 UuidMetric::Child(_) => panic!("Can't get a child metric from a child metric"), 39 } 40 } 41 } 42 43 #[inherent(pub)] 44 impl glean::traits::Uuid for UuidMetric { 45 /// Set to the specified value. 46 /// 47 /// ## Arguments 48 /// 49 /// * `value` - The UUID to set the metric to. set(&self, value: Uuid)50 fn set(&self, value: Uuid) { 51 match self { 52 UuidMetric::Parent(p) => { 53 glean::traits::Uuid::set(&*p, value); 54 } 55 UuidMetric::Child(_c) => { 56 log::error!("Unable to set the uuid metric in non-main process. Ignoring."); 57 // TODO: Record an error. 58 } 59 }; 60 } 61 62 /// Generate a new random UUID and set the metric to it. 63 /// 64 /// ## Return value 65 /// 66 /// Returns the stored UUID value or `Uuid::nil` if called from 67 /// a non-parent process. generate_and_set(&self) -> Uuid68 fn generate_and_set(&self) -> Uuid { 69 match self { 70 UuidMetric::Parent(p) => glean::traits::Uuid::generate_and_set(&*p), 71 UuidMetric::Child(_c) => { 72 log::error!("Unable to set the uuid metric in non-main process. Ignoring."); 73 // TODO: Record an error. 74 Uuid::nil() 75 } 76 } 77 } 78 79 /// **Test-only API.** 80 /// 81 /// Get the stored UUID value. 82 /// This doesn't clear the stored value. 83 /// 84 /// ## Arguments 85 /// 86 /// * `storage_name` - the storage name to look into. 87 /// 88 /// ## Return value 89 /// 90 /// Returns the stored value or `None` if nothing stored. test_get_value<'a, S: Into<Option<&'a str>>>(&self, storage_name: S) -> Option<Uuid>91 fn test_get_value<'a, S: Into<Option<&'a str>>>(&self, storage_name: S) -> Option<Uuid> { 92 match self { 93 UuidMetric::Parent(p) => p.test_get_value(storage_name), 94 UuidMetric::Child(_c) => panic!("Cannot get test value for in non-parent process!"), 95 } 96 } 97 98 /// **Exported for test purposes.** 99 /// 100 /// Gets the number of recorded errors for the given metric and error type. 101 /// 102 /// # Arguments 103 /// 104 /// * `error` - The type of error 105 /// * `ping_name` - represents the optional name of the ping to retrieve the 106 /// metric for. Defaults to the first value in `send_in_pings`. 107 /// 108 /// # Returns 109 /// 110 /// The number of errors reported. test_get_num_recorded_errors<'a, S: Into<Option<&'a str>>>( &self, error: glean::ErrorType, ping_name: S, ) -> i32111 fn test_get_num_recorded_errors<'a, S: Into<Option<&'a str>>>( 112 &self, 113 error: glean::ErrorType, 114 ping_name: S, 115 ) -> i32 { 116 match self { 117 UuidMetric::Parent(p) => p.test_get_num_recorded_errors(error, ping_name), 118 UuidMetric::Child(_c) => { 119 panic!("Cannot get test value for UuidMetric in non-parent process!") 120 } 121 } 122 } 123 } 124 125 #[cfg(test)] 126 mod test { 127 use super::*; 128 use crate::{common_test::*, ipc, metrics}; 129 130 #[test] sets_uuid_value()131 fn sets_uuid_value() { 132 let _lock = lock_test(); 133 134 let metric = &metrics::test_only_ipc::a_uuid; 135 let expected = Uuid::new_v4(); 136 metric.set(expected.clone()); 137 138 assert_eq!(expected, metric.test_get_value("store1").unwrap()); 139 } 140 141 #[test] uuid_ipc()142 fn uuid_ipc() { 143 // UuidMetric doesn't support IPC. 144 let _lock = lock_test(); 145 146 let parent_metric = &metrics::test_only_ipc::a_uuid; 147 let expected = Uuid::new_v4(); 148 parent_metric.set(expected.clone()); 149 150 { 151 let child_metric = parent_metric.child_metric(); 152 153 // Instrumentation calls do not panic. 154 child_metric.set(Uuid::new_v4()); 155 156 // (They also shouldn't do anything, 157 // but that's not something we can inspect in this test) 158 } 159 160 assert!(ipc::replay_from_buf(&ipc::take_buf().unwrap()).is_ok()); 161 162 assert_eq!( 163 expected, 164 parent_metric.test_get_value("store1").unwrap(), 165 "UUID metrics should only work in the parent process" 166 ); 167 } 168 } 169