summaryrefslogtreecommitdiffstats
path: root/toolkit/components/glean/pytest
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/glean/pytest')
-rw-r--r--toolkit/components/glean/pytest/metrics_expires_number_test.yaml22
-rw-r--r--toolkit/components/glean/pytest/metrics_expires_versions_test.yaml84
-rw-r--r--toolkit/components/glean/pytest/metrics_test.yaml270
-rw-r--r--toolkit/components/glean/pytest/metrics_test_output542
-rw-r--r--toolkit/components/glean/pytest/metrics_test_output_cpp130
-rw-r--r--toolkit/components/glean/pytest/metrics_test_output_js255
-rw-r--r--toolkit/components/glean/pytest/pings_test.yaml116
-rw-r--r--toolkit/components/glean/pytest/pings_test_output93
-rw-r--r--toolkit/components/glean/pytest/pings_test_output_cpp62
-rw-r--r--toolkit/components/glean/pytest/pings_test_output_js99
-rw-r--r--toolkit/components/glean/pytest/python.ini6
-rw-r--r--toolkit/components/glean/pytest/test_glean_parser_cpp.py77
-rw-r--r--toolkit/components/glean/pytest/test_glean_parser_js.py75
-rw-r--r--toolkit/components/glean/pytest/test_glean_parser_rust.py113
14 files changed, 1944 insertions, 0 deletions
diff --git a/toolkit/components/glean/pytest/metrics_expires_number_test.yaml b/toolkit/components/glean/pytest/metrics_expires_number_test.yaml
new file mode 100644
index 0000000000..701bc00443
--- /dev/null
+++ b/toolkit/components/glean/pytest/metrics_expires_number_test.yaml
@@ -0,0 +1,22 @@
+# 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 http://mozilla.org/MPL/2.0/.
+
+# This file is FOR TESTING PURPOSES ONLY.
+
+---
+$schema: moz://mozilla.org/schemas/glean/metrics/1-0-0
+
+test:
+ expires_number:
+ type: boolean
+ expires: 99
+ description: |
+ A metric with an expires of an invalid type (number)
+ lifetime: application
+ notification_emails:
+ - glean-team@mozilla.com
+ bugs:
+ - https://bugzilla.mozilla.org/1664306
+ data_reviews:
+ - https://example.com
diff --git a/toolkit/components/glean/pytest/metrics_expires_versions_test.yaml b/toolkit/components/glean/pytest/metrics_expires_versions_test.yaml
new file mode 100644
index 0000000000..7520f749e5
--- /dev/null
+++ b/toolkit/components/glean/pytest/metrics_expires_versions_test.yaml
@@ -0,0 +1,84 @@
+# 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 http://mozilla.org/MPL/2.0/.
+
+# This file is FOR TESTING PURPOSES ONLY.
+
+---
+$schema: moz://mozilla.org/schemas/glean/metrics/1-0-0
+
+test:
+ expired1:
+ type: boolean
+ expires: "41"
+ description: |
+ A multi-line
+ description
+ lifetime: application
+ notification_emails:
+ - glean-team@mozilla.com
+ bugs:
+ - https://bugzilla.mozilla.org/1664306
+ data_reviews:
+ - https://example.com
+ no_lint:
+ - EXPIRED
+
+ expired2:
+ type: labeled_boolean
+ expires: "42"
+ description: |
+ A multi-line
+ description
+ lifetime: application
+ notification_emails:
+ - glean-team@mozilla.com
+ bugs:
+ - https://bugzilla.mozilla.org/1664306
+ data_reviews:
+ - https://example.com
+ no_lint:
+ - EXPIRED
+
+ unexpired:
+ type: labeled_boolean
+ expires: "100"
+ description: |
+ A multi-line
+ description
+ lifetime: application
+ notification_emails:
+ - glean-team@mozilla.com
+ bugs:
+ - https://bugzilla.mozilla.org/1664306
+ data_reviews:
+ - https://example.com
+ labels:
+ - one_label
+ - two_labels
+
+ never:
+ type: string
+ expires: never
+ description: A never-expiring metric
+ lifetime: application
+ notification_emails:
+ - glean-team@mozilla.com
+ bugs:
+ - https://bugzilla.mozilla.org/1664306
+ data_reviews:
+ - https://example.com
+
+ always:
+ type: string
+ expires: expired
+ description: An already-expired metric
+ lifetime: application
+ notification_emails:
+ - glean-team@mozilla.com
+ bugs:
+ - https://bugzilla.mozilla.org/1664306
+ data_reviews:
+ - https://example.com
+ no_lint:
+ - EXPIRED
diff --git a/toolkit/components/glean/pytest/metrics_test.yaml b/toolkit/components/glean/pytest/metrics_test.yaml
new file mode 100644
index 0000000000..ead9217466
--- /dev/null
+++ b/toolkit/components/glean/pytest/metrics_test.yaml
@@ -0,0 +1,270 @@
+# 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 http://mozilla.org/MPL/2.0/.
+
+# This file defines the metrics that are recorded by the Glean SDK. They are
+# automatically converted to platform-specific code at build time using the
+# `glean_parser` PyPI package.
+
+# This file is presently for Internal FOG Use Only.
+# You should not add metrics here until probably about January of 2021.
+# If you're looking for the metrics.yaml for Geckoveiw Streaming Telemetry,
+# you can find that one in toolkit/components/telemetry/geckoview/streaming.
+
+---
+$schema: moz://mozilla.org/schemas/glean/metrics/1-0-0
+
+test:
+ boolean_metric:
+ type: boolean
+ expires: never
+ description: |
+ A multi-line
+ description
+ lifetime: application
+ notification_emails:
+ - glean-team@mozilla.com
+ bugs:
+ - https://bugzilla.mozilla.org/1635260/
+ data_reviews:
+ - https://example.com
+
+ labeled_boolean_metric:
+ type: labeled_boolean
+ expires: never
+ description: |
+ A multi-line
+ description
+ lifetime: application
+ notification_emails:
+ - glean-team@mozilla.com
+ bugs:
+ - https://bugzilla.mozilla.org/1635260/
+ data_reviews:
+ - https://example.com
+
+ labeled_boolean_metric_labels:
+ type: labeled_boolean
+ expires: never
+ description: |
+ A multi-line
+ description
+ lifetime: application
+ notification_emails:
+ - glean-team@mozilla.com
+ bugs:
+ - https://bugzilla.mozilla.org/1635260/
+ data_reviews:
+ - https://example.com
+ labels:
+ - one_label
+ - two_labels
+
+ counter_metric:
+ type: counter
+ expires: never
+ description: |
+ A multi-line
+ description
+ lifetime: application
+ notification_emails:
+ - glean-team@mozilla.com
+ bugs:
+ - https://bugzilla.mozilla.org/1635260/
+ data_reviews:
+ - https://example.com
+
+ labeled_counter_metric:
+ type: labeled_counter
+ expires: never
+ description: |
+ A multi-line
+ description
+ lifetime: application
+ notification_emails:
+ - glean-team@mozilla.com
+ bugs:
+ - https://bugzilla.mozilla.org/1635260/
+ data_reviews:
+ - https://example.com
+
+ labeled_counter_metric_labels:
+ type: labeled_counter
+ expires: never
+ description: |
+ A multi-line
+ description
+ lifetime: application
+ notification_emails:
+ - glean-team@mozilla.com
+ bugs:
+ - https://bugzilla.mozilla.org/1635260/
+ data_reviews:
+ - https://example.com
+ labels:
+ - one_label
+ - two_labels
+
+ string_metric:
+ type: string
+ expires: never
+ description: |
+ A multi-line
+ description
+ lifetime: application
+ notification_emails:
+ - glean-team@mozilla.com
+ bugs:
+ - https://bugzilla.mozilla.org/1635260/
+ data_reviews:
+ - https://example.com
+
+ labeled_string_metric:
+ type: labeled_string
+ expires: never
+ description: |
+ A multi-line
+ description
+ lifetime: application
+ notification_emails:
+ - glean-team@mozilla.com
+ bugs:
+ - https://bugzilla.mozilla.org/1635260/
+ data_reviews:
+ - https://example.com
+
+ labeled_string_metric_labels:
+ type: labeled_string
+ expires: never
+ description: |
+ A multi-line
+ description
+ lifetime: application
+ notification_emails:
+ - glean-team@mozilla.com
+ bugs:
+ - https://bugzilla.mozilla.org/1635260/
+ data_reviews:
+ - https://example.com
+ labels:
+ - one_label
+ - two_labels
+
+ string_list_metric:
+ type: string_list
+ expires: never
+ description: |
+ A multi-line
+ description
+ lifetime: application
+ notification_emails:
+ - glean-team@mozilla.com
+ bugs:
+ - https://bugzilla.mozilla.org/1635260/
+ data_reviews:
+ - https://example.com
+
+ timespan_metric:
+ type: timespan
+ expires: never
+ description: |
+ A multi-line
+ description
+ lifetime: application
+ notification_emails:
+ - glean-team@mozilla.com
+ bugs:
+ - https://bugzilla.mozilla.org/1635260/
+ data_reviews:
+ - https://example.com
+
+ timing_distribution_metric:
+ type: timing_distribution
+ expires: never
+ description: |
+ A multi-line
+ description
+ lifetime: application
+ notification_emails:
+ - glean-team@mozilla.com
+ bugs:
+ - https://bugzilla.mozilla.org/1635260/
+ data_reviews:
+ - https://example.com
+
+ memory_distribution_metric:
+ type: memory_distribution
+ expires: never
+ description: |
+ A multi-line
+ description
+ lifetime: application
+ notification_emails:
+ - glean-team@mozilla.com
+ bugs:
+ - https://bugzilla.mozilla.org/1635260/
+ data_reviews:
+ - https://example.com
+ memory_unit: kilobyte
+
+test.nested:
+ uuid_metric:
+ type: uuid
+ expires: never
+ description: |
+ A multi-line
+ description
+ lifetime: application
+ notification_emails:
+ - glean-team@mozilla.com
+ bugs:
+ - https://bugzilla.mozilla.org/1635260/
+ data_reviews:
+ - https://example.com
+
+ datetime_metric:
+ type: datetime
+ expires: never
+ description: |
+ A multi-line
+ description
+ lifetime: application
+ notification_emails:
+ - glean-team@mozilla.com
+ bugs:
+ - https://bugzilla.mozilla.org/1635260/
+ data_reviews:
+ - https://example.com
+
+ event_metric:
+ type: event
+ expires: never
+ description: |
+ A multi-line
+ description
+ lifetime: ping
+ notification_emails:
+ - glean-team@mozilla.com
+ bugs:
+ - https://bugzilla.mozilla.org/1635260/
+ data_reviews:
+ - https://example.com
+
+ event_metric_with_extra:
+ type: event
+ expires: never
+ description: |
+ A multi-line
+ description
+ lifetime: ping
+ notification_emails:
+ - glean-team@mozilla.com
+ bugs:
+ - https://bugzilla.mozilla.org/1635260/
+ data_reviews:
+ - https://example.com
+ extra_keys:
+ an_extra_key:
+ description: An extra key description
+ another_extra_key:
+ description: Another extra key description
diff --git a/toolkit/components/glean/pytest/metrics_test_output b/toolkit/components/glean/pytest/metrics_test_output
new file mode 100644
index 0000000000..0ac9f7b9ba
--- /dev/null
+++ b/toolkit/components/glean/pytest/metrics_test_output
@@ -0,0 +1,542 @@
+// -*- mode: Rust -*-
+
+// AUTOGENERATED BY glean_parser. DO NOT EDIT.
+
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+
+pub mod test {
+ use crate::private::*;
+ use glean_core::CommonMetricData;
+ use once_cell::sync::Lazy;
+
+ #[allow(non_upper_case_globals)]
+ /// generated from test.boolean_metric
+ ///
+ /// A multi-line
+ /// description
+ pub static boolean_metric: Lazy<BooleanMetric> = Lazy::new(|| {
+ BooleanMetric::new(1.into(), CommonMetricData {
+ name: "boolean_metric".into(),
+ category: "test".into(),
+ send_in_pings: vec!["metrics".into()],
+ lifetime: Lifetime::Application,
+ disabled: false,
+ ..Default::default()
+ })
+ });
+
+ #[allow(non_upper_case_globals)]
+ /// generated from test.labeled_boolean_metric
+ ///
+ /// A multi-line
+ /// description
+ pub static labeled_boolean_metric: Lazy<LabeledMetric<BooleanMetric>> = Lazy::new(|| {
+ LabeledMetric::new(2.into(), CommonMetricData {
+ name: "labeled_boolean_metric".into(),
+ category: "test".into(),
+ send_in_pings: vec!["metrics".into()],
+ lifetime: Lifetime::Application,
+ disabled: false,
+ ..Default::default()
+ }, None)
+ });
+
+ #[allow(non_upper_case_globals)]
+ /// generated from test.labeled_boolean_metric_labels
+ ///
+ /// A multi-line
+ /// description
+ pub static labeled_boolean_metric_labels: Lazy<LabeledMetric<BooleanMetric>> = Lazy::new(|| {
+ LabeledMetric::new(3.into(), CommonMetricData {
+ name: "labeled_boolean_metric_labels".into(),
+ category: "test".into(),
+ send_in_pings: vec!["metrics".into()],
+ lifetime: Lifetime::Application,
+ disabled: false,
+ ..Default::default()
+ }, Some(vec!["one_label".into(), "two_labels".into()]))
+ });
+
+ #[allow(non_upper_case_globals)]
+ /// generated from test.counter_metric
+ ///
+ /// A multi-line
+ /// description
+ pub static counter_metric: Lazy<CounterMetric> = Lazy::new(|| {
+ CounterMetric::new(4.into(), CommonMetricData {
+ name: "counter_metric".into(),
+ category: "test".into(),
+ send_in_pings: vec!["metrics".into()],
+ lifetime: Lifetime::Application,
+ disabled: false,
+ ..Default::default()
+ })
+ });
+
+ #[allow(non_upper_case_globals)]
+ /// generated from test.labeled_counter_metric
+ ///
+ /// A multi-line
+ /// description
+ pub static labeled_counter_metric: Lazy<LabeledMetric<CounterMetric>> = Lazy::new(|| {
+ LabeledMetric::new(5.into(), CommonMetricData {
+ name: "labeled_counter_metric".into(),
+ category: "test".into(),
+ send_in_pings: vec!["metrics".into()],
+ lifetime: Lifetime::Application,
+ disabled: false,
+ ..Default::default()
+ }, None)
+ });
+
+ #[allow(non_upper_case_globals)]
+ /// generated from test.labeled_counter_metric_labels
+ ///
+ /// A multi-line
+ /// description
+ pub static labeled_counter_metric_labels: Lazy<LabeledMetric<CounterMetric>> = Lazy::new(|| {
+ LabeledMetric::new(6.into(), CommonMetricData {
+ name: "labeled_counter_metric_labels".into(),
+ category: "test".into(),
+ send_in_pings: vec!["metrics".into()],
+ lifetime: Lifetime::Application,
+ disabled: false,
+ ..Default::default()
+ }, Some(vec!["one_label".into(), "two_labels".into()]))
+ });
+
+ #[allow(non_upper_case_globals)]
+ /// generated from test.string_metric
+ ///
+ /// A multi-line
+ /// description
+ pub static string_metric: Lazy<StringMetric> = Lazy::new(|| {
+ StringMetric::new(7.into(), CommonMetricData {
+ name: "string_metric".into(),
+ category: "test".into(),
+ send_in_pings: vec!["metrics".into()],
+ lifetime: Lifetime::Application,
+ disabled: false,
+ ..Default::default()
+ })
+ });
+
+ #[allow(non_upper_case_globals)]
+ /// generated from test.labeled_string_metric
+ ///
+ /// A multi-line
+ /// description
+ pub static labeled_string_metric: Lazy<LabeledMetric<StringMetric>> = Lazy::new(|| {
+ LabeledMetric::new(8.into(), CommonMetricData {
+ name: "labeled_string_metric".into(),
+ category: "test".into(),
+ send_in_pings: vec!["metrics".into()],
+ lifetime: Lifetime::Application,
+ disabled: false,
+ ..Default::default()
+ }, None)
+ });
+
+ #[allow(non_upper_case_globals)]
+ /// generated from test.labeled_string_metric_labels
+ ///
+ /// A multi-line
+ /// description
+ pub static labeled_string_metric_labels: Lazy<LabeledMetric<StringMetric>> = Lazy::new(|| {
+ LabeledMetric::new(9.into(), CommonMetricData {
+ name: "labeled_string_metric_labels".into(),
+ category: "test".into(),
+ send_in_pings: vec!["metrics".into()],
+ lifetime: Lifetime::Application,
+ disabled: false,
+ ..Default::default()
+ }, Some(vec!["one_label".into(), "two_labels".into()]))
+ });
+
+ #[allow(non_upper_case_globals)]
+ /// generated from test.string_list_metric
+ ///
+ /// A multi-line
+ /// description
+ pub static string_list_metric: Lazy<StringListMetric> = Lazy::new(|| {
+ StringListMetric::new(10.into(), CommonMetricData {
+ name: "string_list_metric".into(),
+ category: "test".into(),
+ send_in_pings: vec!["metrics".into()],
+ lifetime: Lifetime::Application,
+ disabled: false,
+ ..Default::default()
+ })
+ });
+
+ #[allow(non_upper_case_globals)]
+ /// generated from test.timespan_metric
+ ///
+ /// A multi-line
+ /// description
+ pub static timespan_metric: Lazy<TimespanMetric> = Lazy::new(|| {
+ TimespanMetric::new(11.into(), CommonMetricData {
+ name: "timespan_metric".into(),
+ category: "test".into(),
+ send_in_pings: vec!["metrics".into()],
+ lifetime: Lifetime::Application,
+ disabled: false,
+ ..Default::default()
+ }, TimeUnit::Millisecond)
+ });
+
+ #[allow(non_upper_case_globals)]
+ /// generated from test.timing_distribution_metric
+ ///
+ /// A multi-line
+ /// description
+ pub static timing_distribution_metric: Lazy<TimingDistributionMetric> = Lazy::new(|| {
+ TimingDistributionMetric::new(12.into(), CommonMetricData {
+ name: "timing_distribution_metric".into(),
+ category: "test".into(),
+ send_in_pings: vec!["metrics".into()],
+ lifetime: Lifetime::Application,
+ disabled: false,
+ ..Default::default()
+ }, TimeUnit::Nanosecond)
+ });
+
+ #[allow(non_upper_case_globals)]
+ /// generated from test.memory_distribution_metric
+ ///
+ /// A multi-line
+ /// description
+ pub static memory_distribution_metric: Lazy<MemoryDistributionMetric> = Lazy::new(|| {
+ MemoryDistributionMetric::new(13.into(), CommonMetricData {
+ name: "memory_distribution_metric".into(),
+ category: "test".into(),
+ send_in_pings: vec!["metrics".into()],
+ lifetime: Lifetime::Application,
+ disabled: false,
+ ..Default::default()
+ }, MemoryUnit::Kilobyte)
+ });
+
+}
+pub mod test_nested {
+ use crate::private::*;
+ use glean_core::CommonMetricData;
+ use once_cell::sync::Lazy;
+
+ #[allow(non_upper_case_globals)]
+ /// generated from test.nested.uuid_metric
+ ///
+ /// A multi-line
+ /// description
+ pub static uuid_metric: Lazy<UuidMetric> = Lazy::new(|| {
+ UuidMetric::new(14.into(), CommonMetricData {
+ name: "uuid_metric".into(),
+ category: "test.nested".into(),
+ send_in_pings: vec!["metrics".into()],
+ lifetime: Lifetime::Application,
+ disabled: false,
+ ..Default::default()
+ })
+ });
+
+ #[allow(non_upper_case_globals)]
+ /// generated from test.nested.datetime_metric
+ ///
+ /// A multi-line
+ /// description
+ pub static datetime_metric: Lazy<DatetimeMetric> = Lazy::new(|| {
+ DatetimeMetric::new(15.into(), CommonMetricData {
+ name: "datetime_metric".into(),
+ category: "test.nested".into(),
+ send_in_pings: vec!["metrics".into()],
+ lifetime: Lifetime::Application,
+ disabled: false,
+ ..Default::default()
+ }, TimeUnit::Millisecond)
+ });
+
+ #[allow(non_upper_case_globals)]
+ /// generated from test.nested.event_metric
+ ///
+ /// A multi-line
+ /// description
+ pub static event_metric: Lazy<EventMetric<NoExtraKeys>> = Lazy::new(|| {
+ EventMetric::new(16.into(), CommonMetricData {
+ name: "event_metric".into(),
+ category: "test.nested".into(),
+ send_in_pings: vec!["events".into()],
+ lifetime: Lifetime::Ping,
+ disabled: false,
+ ..Default::default()
+ })
+ });
+
+ #[derive(Clone, Copy, Hash, Eq, PartialEq)]
+ pub enum EventMetricWithExtraKeys {
+ AnExtraKey,
+ AnotherExtraKey,
+ }
+
+ impl ExtraKeys for EventMetricWithExtraKeys {
+ const ALLOWED_KEYS: &'static [&'static str] = &["an_extra_key", "another_extra_key"];
+
+ fn index(self) -> i32 {
+ self as i32
+ }
+ }
+
+ /// Convert from an extra key's index to its variant.
+ impl std::convert::TryFrom<i32> for EventMetricWithExtraKeys {
+ type Error = EventRecordingError;
+
+ fn try_from(value: i32) -> Result<Self, Self::Error> {
+ match value {
+ 0 => Ok(Self::AnExtraKey),
+ 1 => Ok(Self::AnotherExtraKey),
+ _ => Err(EventRecordingError::InvalidExtraKey),
+ }
+ }
+ }
+
+ /// Convert from an extra key's string representation to its variant.
+ impl std::convert::TryFrom<&str> for EventMetricWithExtraKeys {
+ type Error = EventRecordingError;
+
+ fn try_from(value: &str) -> Result<Self, Self::Error> {
+ match value {
+ "an_extra_key" => Ok(Self::AnExtraKey),
+ "another_extra_key" => Ok(Self::AnotherExtraKey),
+ _ => Err(EventRecordingError::InvalidExtraKey),
+ }
+ }
+ }
+
+ #[allow(non_upper_case_globals)]
+ /// generated from test.nested.event_metric_with_extra
+ ///
+ /// A multi-line
+ /// description
+ pub static event_metric_with_extra: Lazy<EventMetric<EventMetricWithExtraKeys>> = Lazy::new(|| {
+ EventMetric::new(17.into(), CommonMetricData {
+ name: "event_metric_with_extra".into(),
+ category: "test.nested".into(),
+ send_in_pings: vec!["events".into()],
+ lifetime: Lifetime::Ping,
+ disabled: false,
+ ..Default::default()
+ })
+ });
+
+}
+
+#[allow(dead_code)]
+pub(crate) mod __glean_metric_maps {
+ use std::collections::HashMap;
+ use std::convert::TryInto;
+
+ use crate::private::*;
+ use once_cell::sync::Lazy;
+
+ pub static BOOLEAN_MAP: Lazy<HashMap<MetricId, &Lazy<BooleanMetric>>> = Lazy::new(|| {
+ let mut map = HashMap::with_capacity(1);
+ map.insert(1.into(), &super::test::boolean_metric);
+ map
+ });
+
+ pub static LABELED_BOOLEAN_MAP: Lazy<HashMap<MetricId, &Lazy<LabeledMetric<BooleanMetric>>>> = Lazy::new(|| {
+ let mut map = HashMap::with_capacity(2);
+ map.insert(2.into(), &super::test::labeled_boolean_metric);
+ map.insert(3.into(), &super::test::labeled_boolean_metric_labels);
+ map
+ });
+
+ pub static COUNTER_MAP: Lazy<HashMap<MetricId, &Lazy<CounterMetric>>> = Lazy::new(|| {
+ let mut map = HashMap::with_capacity(1);
+ map.insert(4.into(), &super::test::counter_metric);
+ map
+ });
+
+ pub static LABELED_COUNTER_MAP: Lazy<HashMap<MetricId, &Lazy<LabeledMetric<CounterMetric>>>> = Lazy::new(|| {
+ let mut map = HashMap::with_capacity(2);
+ map.insert(5.into(), &super::test::labeled_counter_metric);
+ map.insert(6.into(), &super::test::labeled_counter_metric_labels);
+ map
+ });
+
+ pub static STRING_MAP: Lazy<HashMap<MetricId, &Lazy<StringMetric>>> = Lazy::new(|| {
+ let mut map = HashMap::with_capacity(1);
+ map.insert(7.into(), &super::test::string_metric);
+ map
+ });
+
+ pub static LABELED_STRING_MAP: Lazy<HashMap<MetricId, &Lazy<LabeledMetric<StringMetric>>>> = Lazy::new(|| {
+ let mut map = HashMap::with_capacity(2);
+ map.insert(8.into(), &super::test::labeled_string_metric);
+ map.insert(9.into(), &super::test::labeled_string_metric_labels);
+ map
+ });
+
+ pub static STRING_LIST_MAP: Lazy<HashMap<MetricId, &Lazy<StringListMetric>>> = Lazy::new(|| {
+ let mut map = HashMap::with_capacity(1);
+ map.insert(10.into(), &super::test::string_list_metric);
+ map
+ });
+
+ pub static TIMESPAN_MAP: Lazy<HashMap<MetricId, &Lazy<TimespanMetric>>> = Lazy::new(|| {
+ let mut map = HashMap::with_capacity(1);
+ map.insert(11.into(), &super::test::timespan_metric);
+ map
+ });
+
+ pub static TIMING_DISTRIBUTION_MAP: Lazy<HashMap<MetricId, &Lazy<TimingDistributionMetric>>> = Lazy::new(|| {
+ let mut map = HashMap::with_capacity(1);
+ map.insert(12.into(), &super::test::timing_distribution_metric);
+ map
+ });
+
+ pub static MEMORY_DISTRIBUTION_MAP: Lazy<HashMap<MetricId, &Lazy<MemoryDistributionMetric>>> = Lazy::new(|| {
+ let mut map = HashMap::with_capacity(1);
+ map.insert(13.into(), &super::test::memory_distribution_metric);
+ map
+ });
+
+ pub static UUID_MAP: Lazy<HashMap<MetricId, &Lazy<UuidMetric>>> = Lazy::new(|| {
+ let mut map = HashMap::with_capacity(1);
+ map.insert(14.into(), &super::test_nested::uuid_metric);
+ map
+ });
+
+ pub static DATETIME_MAP: Lazy<HashMap<MetricId, &Lazy<DatetimeMetric>>> = Lazy::new(|| {
+ let mut map = HashMap::with_capacity(1);
+ map.insert(15.into(), &super::test_nested::datetime_metric);
+ map
+ });
+
+
+ /// Helper to get the number of allowed extra keys for a given event metric.
+ fn extra_keys_len<K: ExtraKeys>(_event: &EventMetric<K>) -> usize {
+ K::ALLOWED_KEYS.len()
+ }
+
+ /// Wrapper to record an event based on its metric ID.
+ ///
+ /// # Arguments
+ ///
+ /// * `metric_id` - The metric's ID to look up
+ /// * `extra` - An (optional) map of (extra key id, string) pairs.
+ /// The map will be decoded into the appropriate `ExtraKeys` type.
+ /// # Returns
+ ///
+ /// Returns `Ok(())` if the event was found and `record` was called with the given `extra`,
+ /// or an `EventRecordingError::InvalidId` if no event by that ID exists
+ /// or an `EventRecordingError::InvalidExtraKey` the `extra` map could not be deserialized.
+ pub(crate) fn event_record_wrapper(metric_id: u32, extra: HashMap<i32, String>) -> Result<(), EventRecordingError> {
+ match metric_id {
+ 16 => {
+ assert!(
+ extra_keys_len(&super::test_nested::event_metric) != 0 || extra.is_empty(),
+ "No extra keys allowed, but some were passed"
+ );
+
+ // In case of `NoExtraKeys` the whole iterator is impossible, so rustc complains.
+ #[allow(unused_variables)]
+ let extra: HashMap<_, _> = extra
+ .into_iter()
+ .map(|(k, v)| k.try_into().map(|k| (k, v)))
+ .collect::<Result<HashMap<_, _>, _>>()?;
+ super::test_nested::event_metric.record(Some(extra));
+ Ok(())
+ }
+ 17 => {
+ assert!(
+ extra_keys_len(&super::test_nested::event_metric_with_extra) != 0 || extra.is_empty(),
+ "No extra keys allowed, but some were passed"
+ );
+
+ // In case of `NoExtraKeys` the whole iterator is impossible, so rustc complains.
+ #[allow(unused_variables)]
+ let extra: HashMap<_, _> = extra
+ .into_iter()
+ .map(|(k, v)| k.try_into().map(|k| (k, v)))
+ .collect::<Result<HashMap<_, _>, _>>()?;
+ super::test_nested::event_metric_with_extra.record(Some(extra));
+ Ok(())
+ }
+ _ => Err(EventRecordingError::InvalidId),
+ }
+ }
+
+ /// Wrapper to record an event based on its metric ID.
+ ///
+ /// # Arguments
+ ///
+ /// * `metric_id` - The metric's ID to look up
+ /// * `extra` - An (optional) map of (string, string) pairs.
+ /// The map will be decoded into the appropriate `ExtraKeys` types.
+ /// # Returns
+ ///
+ /// Returns `Ok(())` if the event was found and `record` was called with the given `extra`,
+ /// or an `EventRecordingError::InvalidId` if no event by that ID exists
+ /// or an `EventRecordingError::InvalidExtraKey` the `extra` map could not be deserialized.
+ pub(crate) fn event_record_wrapper_str(metric_id: u32, extra: HashMap<String, String>) -> Result<(), EventRecordingError> {
+ match metric_id {
+ 16 => {
+ assert!(
+ extra_keys_len(&super::test_nested::event_metric) != 0 || extra.is_empty(),
+ "No extra keys allowed, but some were passed"
+ );
+
+ // In case of `NoExtraKeys` the whole iterator is impossible, so rustc complains.
+ #[allow(unused_variables)]
+ let extra = extra
+ .into_iter()
+ .map(|(k, v)| (&*k).try_into().map(|k| (k, v)))
+ .collect::<Result<HashMap<_, _>, _>>()?;
+ super::test_nested::event_metric.record(Some(extra));
+ Ok(())
+ }
+ 17 => {
+ assert!(
+ extra_keys_len(&super::test_nested::event_metric_with_extra) != 0 || extra.is_empty(),
+ "No extra keys allowed, but some were passed"
+ );
+
+ // In case of `NoExtraKeys` the whole iterator is impossible, so rustc complains.
+ #[allow(unused_variables)]
+ let extra = extra
+ .into_iter()
+ .map(|(k, v)| (&*k).try_into().map(|k| (k, v)))
+ .collect::<Result<HashMap<_, _>, _>>()?;
+ super::test_nested::event_metric_with_extra.record(Some(extra));
+ Ok(())
+ }
+ _ => Err(EventRecordingError::InvalidId),
+ }
+ }
+
+ /// Wrapper to get the currently stored events for event metric.
+ ///
+ /// # Arguments
+ ///
+ /// * `metric_id` - The metric's ID to look up
+ /// * `storage_name` - the storage name to look into.
+ ///
+ /// # Returns
+ ///
+ /// Returns the recorded events or `None` if nothing stored.
+ ///
+ /// # Panics
+ ///
+ /// Panics if no event by the given metric ID could be found.
+ pub(crate) fn event_test_get_value_wrapper(metric_id: u32, storage_name: &str) -> Option<Vec<RecordedEvent>> {
+ match metric_id {
+ 16 => super::test_nested::event_metric.test_get_value(storage_name),
+ 17 => super::test_nested::event_metric_with_extra.test_get_value(storage_name),
+ _ => panic!("No event for metric id {}", metric_id),
+ }
+ }
+}
+
diff --git a/toolkit/components/glean/pytest/metrics_test_output_cpp b/toolkit/components/glean/pytest/metrics_test_output_cpp
new file mode 100644
index 0000000000..73cfc76bc3
--- /dev/null
+++ b/toolkit/components/glean/pytest/metrics_test_output_cpp
@@ -0,0 +1,130 @@
+// -*- mode: C++ -*-
+
+// AUTOGENERATED BY glean_parser. DO NOT EDIT.
+
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_Metrics_h
+#define mozilla_Metrics_h
+
+#include "mozilla/glean/bindings/MetricTypes.h"
+
+namespace mozilla::glean {
+
+enum class NoExtraKeys {};
+
+
+namespace test {
+ /**
+ * generated from test.boolean_metric
+ */
+ /**
+ * A multi-line
+ * description
+ */
+ constexpr impl::BooleanMetric boolean_metric(1);
+
+ /**
+ * generated from test.counter_metric
+ */
+ /**
+ * A multi-line
+ * description
+ */
+ constexpr impl::CounterMetric counter_metric(4);
+
+ /**
+ * generated from test.string_metric
+ */
+ /**
+ * A multi-line
+ * description
+ */
+ constexpr impl::StringMetric string_metric(7);
+
+ /**
+ * generated from test.string_list_metric
+ */
+ /**
+ * A multi-line
+ * description
+ */
+ constexpr impl::StringListMetric string_list_metric(10);
+
+ /**
+ * generated from test.timespan_metric
+ */
+ /**
+ * A multi-line
+ * description
+ */
+ constexpr impl::TimespanMetric timespan_metric(11);
+
+ /**
+ * generated from test.timing_distribution_metric
+ */
+ /**
+ * A multi-line
+ * description
+ */
+ constexpr impl::TimingDistributionMetric timing_distribution_metric(12);
+
+ /**
+ * generated from test.memory_distribution_metric
+ */
+ /**
+ * A multi-line
+ * description
+ */
+ constexpr impl::MemoryDistributionMetric memory_distribution_metric(13);
+
+}
+namespace test_nested {
+ /**
+ * generated from test.nested.uuid_metric
+ */
+ /**
+ * A multi-line
+ * description
+ */
+ constexpr impl::UuidMetric uuid_metric(14);
+
+ /**
+ * generated from test.nested.datetime_metric
+ */
+ /**
+ * A multi-line
+ * description
+ */
+ constexpr impl::DatetimeMetric datetime_metric(15);
+
+ /**
+ * generated from test.nested.event_metric
+ */
+ /**
+ * A multi-line
+ * description
+ */
+ constexpr impl::EventMetric<uint32_t> event_metric(16);
+
+ /**
+ * generated from test.nested.event_metric_with_extra
+ */
+ enum class EventMetricWithExtraKeys : int32_t {
+ AnExtraKey,
+ AnotherExtraKey,
+ };
+
+ /**
+ * A multi-line
+ * description
+ */
+ constexpr impl::EventMetric<EventMetricWithExtraKeys> event_metric_with_extra(17);
+
+}
+
+} // namespace mozilla::glean
+
+#endif // mozilla_Metrics_h
diff --git a/toolkit/components/glean/pytest/metrics_test_output_js b/toolkit/components/glean/pytest/metrics_test_output_js
new file mode 100644
index 0000000000..b9c351baa0
--- /dev/null
+++ b/toolkit/components/glean/pytest/metrics_test_output_js
@@ -0,0 +1,255 @@
+// -*- mode: C++ -*-
+
+// AUTOGENERATED BY glean_parser. DO NOT EDIT.
+
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_GleanJSMetricsLookup_h
+#define mozilla_GleanJSMetricsLookup_h
+
+#include "mozilla/PerfectHash.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/glean/bindings/MetricTypes.h"
+
+#define GLEAN_INDEX_BITS (32)
+#define GLEAN_ID_BITS (27)
+#define GLEAN_TYPE_ID(id) ((id) >> GLEAN_ID_BITS)
+#define GLEAN_METRIC_ID(id) ((id) & ((1ULL << GLEAN_ID_BITS) - 1))
+#define GLEAN_OFFSET(entry) (entry & ((1ULL << GLEAN_INDEX_BITS) - 1))
+
+namespace mozilla::glean {
+
+// The category lookup table's entry type
+using category_entry_t = uint32_t;
+// The metric lookup table's entry type
+using metric_entry_t = uint64_t;
+
+static_assert(GLEAN_INDEX_BITS + GLEAN_ID_BITS < sizeof(metric_entry_t) * 8, "Index and ID bits need to fit into an category_entry_t");
+static_assert(GLEAN_ID_BITS < sizeof(uint32_t) * 8, "Metric IDs need to fit into less than 32 bit");
+static_assert(2 < UINT32_MAX, "Too many metric categories generated.");
+static_assert(17 < 134217728, "Too many metrics generated.");
+static_assert(13 < 32, "Too many different metric types.");
+
+static already_AddRefed<nsISupports> NewMetricFromId(uint32_t id) {
+ uint32_t typeId = GLEAN_TYPE_ID(id);
+ uint32_t metricId = GLEAN_METRIC_ID(id);
+
+ switch (typeId) {
+ case 1: /* Boolean */
+ {
+ return MakeAndAddRef<GleanBoolean>(metricId);
+ }
+ case 3: /* Counter */
+ {
+ return MakeAndAddRef<GleanCounter>(metricId);
+ }
+ case 5: /* String */
+ {
+ return MakeAndAddRef<GleanString>(metricId);
+ }
+ case 7: /* StringList */
+ {
+ return MakeAndAddRef<GleanStringList>(metricId);
+ }
+ case 8: /* Timespan */
+ {
+ return MakeAndAddRef<GleanTimespan>(metricId);
+ }
+ case 9: /* TimingDistribution */
+ {
+ return MakeAndAddRef<GleanTimingDistribution>(metricId);
+ }
+ case 10: /* MemoryDistribution */
+ {
+ return MakeAndAddRef<GleanMemoryDistribution>(metricId);
+ }
+ case 11: /* Uuid */
+ {
+ return MakeAndAddRef<GleanUuid>(metricId);
+ }
+ case 12: /* Datetime */
+ {
+ return MakeAndAddRef<GleanDatetime>(metricId);
+ }
+ case 13: /* Event */
+ {
+ return MakeAndAddRef<GleanEvent>(metricId);
+ }
+ default:
+ MOZ_ASSERT_UNREACHABLE("Invalid type ID reached when trying to instantiate a new metric");
+ return nullptr;
+ }
+}
+
+static Maybe<uint32_t> category_result_check(const nsACString& aKey, category_entry_t entry);
+static Maybe<uint32_t> metric_result_check(const nsACString& aKey, metric_entry_t entry);
+
+#if defined(_MSC_VER) && !defined(__clang__)
+const char gCategoryStringTable[] = {
+#else
+constexpr char gCategoryStringTable[] = {
+#endif
+ /* 0 - "test" */ 't', 'e', 's', 't', '\0',
+ /* 5 - "testNested" */ 't', 'e', 's', 't', 'N', 'e', 's', 't', 'e', 'd', '\0',
+};
+
+
+static_assert(sizeof(gCategoryStringTable) < UINT32_MAX, "Category string table is too large.");
+
+const category_entry_t sCategoryByNameLookupEntries[] = {
+ 5,
+ 0
+};
+
+
+
+static Maybe<uint32_t>
+CategoryByNameLookup(const nsACString& aKey)
+{
+ static const uint8_t BASES[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+
+
+ const char* bytes = aKey.BeginReading();
+ size_t length = aKey.Length();
+ auto& entry = mozilla::perfecthash::Lookup(bytes, length, BASES,
+ sCategoryByNameLookupEntries);
+ return category_result_check(aKey, entry);
+}
+
+
+#if defined(_MSC_VER) && !defined(__clang__)
+const char gMetricStringTable[] = {
+#else
+constexpr char gMetricStringTable[] = {
+#endif
+ /* 0 - "test.booleanMetric" */ 't', 'e', 's', 't', '.', 'b', 'o', 'o', 'l', 'e', 'a', 'n', 'M', 'e', 't', 'r', 'i', 'c', '\0',
+ /* 19 - "test.labeledBooleanMetric" */ 't', 'e', 's', 't', '.', 'l', 'a', 'b', 'e', 'l', 'e', 'd', 'B', 'o', 'o', 'l', 'e', 'a', 'n', 'M', 'e', 't', 'r', 'i', 'c', '\0',
+ /* 45 - "test.labeledBooleanMetricLabels" */ 't', 'e', 's', 't', '.', 'l', 'a', 'b', 'e', 'l', 'e', 'd', 'B', 'o', 'o', 'l', 'e', 'a', 'n', 'M', 'e', 't', 'r', 'i', 'c', 'L', 'a', 'b', 'e', 'l', 's', '\0',
+ /* 77 - "test.counterMetric" */ 't', 'e', 's', 't', '.', 'c', 'o', 'u', 'n', 't', 'e', 'r', 'M', 'e', 't', 'r', 'i', 'c', '\0',
+ /* 96 - "test.labeledCounterMetric" */ 't', 'e', 's', 't', '.', 'l', 'a', 'b', 'e', 'l', 'e', 'd', 'C', 'o', 'u', 'n', 't', 'e', 'r', 'M', 'e', 't', 'r', 'i', 'c', '\0',
+ /* 122 - "test.labeledCounterMetricLabels" */ 't', 'e', 's', 't', '.', 'l', 'a', 'b', 'e', 'l', 'e', 'd', 'C', 'o', 'u', 'n', 't', 'e', 'r', 'M', 'e', 't', 'r', 'i', 'c', 'L', 'a', 'b', 'e', 'l', 's', '\0',
+ /* 154 - "test.stringMetric" */ 't', 'e', 's', 't', '.', 's', 't', 'r', 'i', 'n', 'g', 'M', 'e', 't', 'r', 'i', 'c', '\0',
+ /* 172 - "test.labeledStringMetric" */ 't', 'e', 's', 't', '.', 'l', 'a', 'b', 'e', 'l', 'e', 'd', 'S', 't', 'r', 'i', 'n', 'g', 'M', 'e', 't', 'r', 'i', 'c', '\0',
+ /* 197 - "test.labeledStringMetricLabels" */ 't', 'e', 's', 't', '.', 'l', 'a', 'b', 'e', 'l', 'e', 'd', 'S', 't', 'r', 'i', 'n', 'g', 'M', 'e', 't', 'r', 'i', 'c', 'L', 'a', 'b', 'e', 'l', 's', '\0',
+ /* 228 - "test.stringListMetric" */ 't', 'e', 's', 't', '.', 's', 't', 'r', 'i', 'n', 'g', 'L', 'i', 's', 't', 'M', 'e', 't', 'r', 'i', 'c', '\0',
+ /* 250 - "test.timespanMetric" */ 't', 'e', 's', 't', '.', 't', 'i', 'm', 'e', 's', 'p', 'a', 'n', 'M', 'e', 't', 'r', 'i', 'c', '\0',
+ /* 270 - "test.timingDistributionMetric" */ 't', 'e', 's', 't', '.', 't', 'i', 'm', 'i', 'n', 'g', 'D', 'i', 's', 't', 'r', 'i', 'b', 'u', 't', 'i', 'o', 'n', 'M', 'e', 't', 'r', 'i', 'c', '\0',
+ /* 300 - "test.memoryDistributionMetric" */ 't', 'e', 's', 't', '.', 'm', 'e', 'm', 'o', 'r', 'y', 'D', 'i', 's', 't', 'r', 'i', 'b', 'u', 't', 'i', 'o', 'n', 'M', 'e', 't', 'r', 'i', 'c', '\0',
+ /* 330 - "testNested.uuidMetric" */ 't', 'e', 's', 't', 'N', 'e', 's', 't', 'e', 'd', '.', 'u', 'u', 'i', 'd', 'M', 'e', 't', 'r', 'i', 'c', '\0',
+ /* 352 - "testNested.datetimeMetric" */ 't', 'e', 's', 't', 'N', 'e', 's', 't', 'e', 'd', '.', 'd', 'a', 't', 'e', 't', 'i', 'm', 'e', 'M', 'e', 't', 'r', 'i', 'c', '\0',
+ /* 378 - "testNested.eventMetric" */ 't', 'e', 's', 't', 'N', 'e', 's', 't', 'e', 'd', '.', 'e', 'v', 'e', 'n', 't', 'M', 'e', 't', 'r', 'i', 'c', '\0',
+ /* 401 - "testNested.eventMetricWithExtra" */ 't', 'e', 's', 't', 'N', 'e', 's', 't', 'e', 'd', '.', 'e', 'v', 'e', 'n', 't', 'M', 'e', 't', 'r', 'i', 'c', 'W', 'i', 't', 'h', 'E', 'x', 't', 'r', 'a', '\0',
+};
+
+
+static_assert(sizeof(gMetricStringTable) < 4294967296, "Metric string table is too large.");
+
+const metric_entry_t sMetricByNameLookupEntries[] = {
+ 1729382274090139725,
+ 3458764552475246789,
+ 1152921513196781587,
+ 2305843030688530528,
+ 5188146822270419214,
+ 7493989848663982458,
+ 1152921517491748909,
+ 576460756598390784,
+ 4035225309073637604,
+ 6341068335467200842,
+ 6917529092065591648,
+ 4611686065672028410,
+ 7493989852958949777,
+ 2305843034983497850,
+ 5764607578868810028,
+ 3458764548180279468,
+ 2882303791581888666
+};
+
+
+
+static Maybe<uint32_t>
+MetricByNameLookup(const nsACString& aKey)
+{
+ static const uint8_t BASES[] = {
+ 0, 0, 0, 2, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0,
+ 2, 0, 0, 0, 1, 0, 0, 1, 0, 5, 0, 0, 4, 0, 1, 0,
+ 2, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 2, 0, 6, 0, 0,
+ 0, 0, 20, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10,
+ };
+
+
+ const char* bytes = aKey.BeginReading();
+ size_t length = aKey.Length();
+ auto& entry = mozilla::perfecthash::Lookup(bytes, length, BASES,
+ sMetricByNameLookupEntries);
+ return metric_result_check(aKey, entry);
+}
+
+
+/**
+ * Get a category's name from the string table.
+ */
+static const char* GetCategoryName(category_entry_t entry) {
+ MOZ_ASSERT(entry < sizeof(gCategoryStringTable), "Entry identifier offset larger than string table");
+ return &gCategoryStringTable[entry];
+}
+
+/**
+ * Get a metric's identifier from the string table.
+ */
+static const char* GetMetricIdentifier(metric_entry_t entry) {
+ uint32_t offset = GLEAN_OFFSET(entry);
+ MOZ_ASSERT(offset < sizeof(gMetricStringTable), "Entry identifier offset larger than string table");
+ return &gMetricStringTable[offset];
+}
+
+/**
+ * Check that the found entry is pointing to the right key
+ * and return it.
+ * Or return `Nothing()` if the entry was not found.
+ */
+static Maybe<uint32_t> category_result_check(const nsACString& aKey, category_entry_t entry) {
+ if (MOZ_UNLIKELY(entry > sizeof(gCategoryStringTable))) {
+ return Nothing();
+ }
+ if (aKey.EqualsASCII(gCategoryStringTable + entry)) {
+ return Some(entry);
+ }
+ return Nothing();
+}
+
+/**
+ * Check if the found entry index is pointing to the right key
+ * and return the corresponding metric ID.
+ * Or return `Nothing()` if the entry was not found.
+ */
+static Maybe<uint32_t> metric_result_check(const nsACString& aKey, uint64_t entry) {
+ uint32_t metricId = entry >> GLEAN_INDEX_BITS;
+ uint32_t offset = GLEAN_OFFSET(entry);
+
+ if (offset > sizeof(gMetricStringTable)) {
+ return Nothing();
+ }
+
+ if (aKey.EqualsASCII(gMetricStringTable + offset)) {
+ return Some(metricId);
+ }
+
+ return Nothing();
+}
+
+
+#undef GLEAN_INDEX_BITS
+#undef GLEAN_ID_BITS
+#undef GLEAN_TYPE_ID
+#undef GLEAN_METRIC_ID
+#undef GLEAN_OFFSET
+
+} // namespace mozilla::glean
+#endif // mozilla_GleanJSMetricsLookup_h
diff --git a/toolkit/components/glean/pytest/pings_test.yaml b/toolkit/components/glean/pytest/pings_test.yaml
new file mode 100644
index 0000000000..efa6ba9e0a
--- /dev/null
+++ b/toolkit/components/glean/pytest/pings_test.yaml
@@ -0,0 +1,116 @@
+# 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 http://mozilla.org/MPL/2.0/.
+
+# This file defines the built-in pings that are recorded by the Glean SDK. They
+# are automatically converted to Kotlin code at build time using the
+# `glean_parser` PyPI package.
+
+---
+$schema: moz://mozilla.org/schemas/glean/pings/1-0-0
+
+not-baseline:
+ description: >
+ This ping is intended to provide metrics that are managed by the library
+ itself, and not explicitly set by the application or included in the
+ application's `metrics.yaml` file.
+ The `baseline` ping is automatically sent when the application is moved to
+ the background.
+ include_client_id: true
+ bugs:
+ - https://bugzilla.mozilla.org/1512938
+ - https://bugzilla.mozilla.org/1599877
+ data_reviews:
+ - https://bugzilla.mozilla.org/show_bug.cgi?id=1512938#c3
+ - https://bugzilla.mozilla.org/show_bug.cgi?id=1599877#c25
+ notification_emails:
+ - glean-team@mozilla.com
+ reasons:
+ dirty_startup: |
+ The ping was submitted at startup, because the application process was
+ killed before the Glean SDK had the chance to generate this ping, when
+ going to background, in the last session.
+
+ *Note*: this ping will not contain the `glean.baseline.duration` metric.
+ background: |
+ The ping was submitted before going to background.
+ foreground: |
+ The ping was submitted when the application went to foreground, which
+ includes when the application starts.
+
+ *Note*: this ping will not contain the `glean.baseline.duration` metric.
+
+not-metrics:
+ description: >
+ The `metrics` ping is intended for all of the metrics that are explicitly
+ set by the application or are included in the application's `metrics.yaml`
+ file (except events).
+ The reported data is tied to the ping's *measurement window*, which is the
+ time between the collection of two `metrics` ping. Ideally, this window is
+ expected to be about 24 hours, given that the collection is scheduled daily
+ at 4AM. Data in the `ping_info` section of the ping can be used to infer the
+ length of this window.
+ include_client_id: true
+ bugs:
+ - https://bugzilla.mozilla.org/1512938
+ data_reviews:
+ - https://bugzilla.mozilla.org/show_bug.cgi?id=1512938#c3
+ - https://bugzilla.mozilla.org/show_bug.cgi?id=1557048#c13
+ notification_emails:
+ - glean-team@mozilla.com
+ reasons:
+ overdue: |
+ The last ping wasn't submitted on the current calendar day, but it's after
+ 4am, so this ping submitted immediately
+ today: |
+ The last ping wasn't submitted on the current calendar day, but it is
+ still before 4am, so schedule to send this ping on the current calendar
+ day at 4am.
+ tomorrow: |
+ The last ping was already submitted on the current calendar day, so
+ schedule this ping for the next calendar day at 4am.
+ upgrade: |
+ This ping was submitted at startup because the application was just
+ upgraded.
+ reschedule: |
+ A ping was just submitted. This ping was rescheduled for the next calendar
+ day at 4am.
+
+not-events:
+ description: >
+ The events ping's purpose is to transport all of the event metric
+ information. The `events` ping is automatically sent when the application is
+ moved to the background.
+ include_client_id: true
+ bugs:
+ - https://bugzilla.mozilla.org/1512938
+ data_reviews:
+ - https://bugzilla.mozilla.org/show_bug.cgi?id=1512938#c3
+ notification_emails:
+ - glean-team@mozilla.com
+ reasons:
+ startup: |
+ The ping was submitted at startup. The events ping is always sent if there
+ are any pending events at startup, because event timestamps can not be
+ mixed across runs of the application.
+ background: |
+ The ping was submitted before going to background.
+ max_capacity: |
+ The maximum number of events was reached (default 500 events).
+
+not-deletion-request:
+ description: >
+ This ping is submitted when a user opts out of
+ sending technical and interaction data to Mozilla.
+ This ping is intended to communicate to the Data Pipeline
+ that the user wishes to have their reported Telemetry data deleted.
+ As such it attempts to send itself at the moment the user
+ opts out of data collection.
+ include_client_id: true
+ send_if_empty: true
+ bugs:
+ - https://bugzilla.mozilla.org/1587095
+ data_reviews:
+ - https://bugzilla.mozilla.org/show_bug.cgi?id=1587095#c6
+ notification_emails:
+ - glean-team@mozilla.com
diff --git a/toolkit/components/glean/pytest/pings_test_output b/toolkit/components/glean/pytest/pings_test_output
new file mode 100644
index 0000000000..df705967bc
--- /dev/null
+++ b/toolkit/components/glean/pytest/pings_test_output
@@ -0,0 +1,93 @@
+// -*- mode: Rust -*-
+
+// AUTOGENERATED BY glean_parser. DO NOT EDIT.
+
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+use crate::private::Ping;
+use once_cell::sync::Lazy;
+
+#[allow(non_upper_case_globals)]
+/// This ping is intended to provide metrics that are managed by the library
+/// itself, and not explicitly set by the application or included in the
+/// application's `metrics.yaml` file. The `baseline` ping is automatically sent
+/// when the application is moved to the background.
+pub static not_baseline: Lazy<Ping> = Lazy::new(|| {
+ Ping::new(
+ "not-baseline",
+ true,
+ false,
+ vec!["background".into(), "dirty_startup".into(), "foreground".into()],
+ )
+});
+
+#[allow(non_upper_case_globals)]
+/// The `metrics` ping is intended for all of the metrics that are explicitly set
+/// by the application or are included in the application's `metrics.yaml` file
+/// (except events). The reported data is tied to the ping's *measurement window*,
+/// which is the time between the collection of two `metrics` ping. Ideally, this
+/// window is expected to be about 24 hours, given that the collection is scheduled
+/// daily at 4AM. Data in the `ping_info` section of the ping can be used to infer
+/// the length of this window.
+pub static not_metrics: Lazy<Ping> = Lazy::new(|| {
+ Ping::new(
+ "not-metrics",
+ true,
+ false,
+ vec!["overdue".into(), "reschedule".into(), "today".into(), "tomorrow".into(), "upgrade".into()],
+ )
+});
+
+#[allow(non_upper_case_globals)]
+/// The events ping's purpose is to transport all of the event metric information.
+/// The `events` ping is automatically sent when the application is moved to the
+/// background.
+pub static not_events: Lazy<Ping> = Lazy::new(|| {
+ Ping::new(
+ "not-events",
+ true,
+ false,
+ vec!["background".into(), "max_capacity".into(), "startup".into()],
+ )
+});
+
+#[allow(non_upper_case_globals)]
+/// This ping is submitted when a user opts out of sending technical and
+/// interaction data to Mozilla. This ping is intended to communicate to the Data
+/// Pipeline that the user wishes to have their reported Telemetry data deleted. As
+/// such it attempts to send itself at the moment the user opts out of data
+/// collection.
+pub static not_deletion_request: Lazy<Ping> = Lazy::new(|| {
+ Ping::new(
+ "not-deletion-request",
+ true,
+ true,
+ vec![],
+ )
+});
+
+
+/// Instantiate each custom ping once to trigger registration.
+#[doc(hidden)]
+pub fn register_pings() {
+ let _ = &*not_baseline;
+ let _ = &*not_metrics;
+ let _ = &*not_events;
+ let _ = &*not_deletion_request;
+}
+
+#[cfg(feature = "with_gecko")]
+pub(crate) fn submit_ping_by_id(id: u32, reason: Option<&str>) {
+ match id {
+ 1 => not_baseline.submit(reason),
+ 2 => not_metrics.submit(reason),
+ 3 => not_events.submit(reason),
+ 4 => not_deletion_request.submit(reason),
+ _ => {
+ // TODO: instrument this error.
+ log::error!("Cannot submit unknown ping {} by id.", id);
+ }
+ }
+}
diff --git a/toolkit/components/glean/pytest/pings_test_output_cpp b/toolkit/components/glean/pytest/pings_test_output_cpp
new file mode 100644
index 0000000000..7f9cc03947
--- /dev/null
+++ b/toolkit/components/glean/pytest/pings_test_output_cpp
@@ -0,0 +1,62 @@
+// -*- mode: C++ -*-
+
+// AUTOGENERATED BY glean_parser. DO NOT EDIT.
+
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_glean_Pings_h
+#define mozilla_glean_Pings_h
+
+#include "mozilla/glean/bindings/Ping.h"
+
+namespace mozilla::glean_pings {
+
+/*
+ * Generated from not-baseline.
+ *
+ * This ping is intended to provide metrics that are managed by the library
+ * itself, and not explicitly set by the application or included in the
+ * application's `metrics.yaml` file. The `baseline` ping is automatically sent
+ * when the application is moved to the background.
+ */
+constexpr glean::impl::Ping NotBaseline(1);
+
+/*
+ * Generated from not-metrics.
+ *
+ * The `metrics` ping is intended for all of the metrics that are explicitly set
+ * by the application or are included in the application's `metrics.yaml` file
+ * (except events). The reported data is tied to the ping's *measurement window*,
+ * which is the time between the collection of two `metrics` ping. Ideally, this
+ * window is expected to be about 24 hours, given that the collection is scheduled
+ * daily at 4AM. Data in the `ping_info` section of the ping can be used to infer
+ * the length of this window.
+ */
+constexpr glean::impl::Ping NotMetrics(2);
+
+/*
+ * Generated from not-events.
+ *
+ * The events ping's purpose is to transport all of the event metric information.
+ * The `events` ping is automatically sent when the application is moved to the
+ * background.
+ */
+constexpr glean::impl::Ping NotEvents(3);
+
+/*
+ * Generated from not-deletion-request.
+ *
+ * This ping is submitted when a user opts out of sending technical and
+ * interaction data to Mozilla. This ping is intended to communicate to the Data
+ * Pipeline that the user wishes to have their reported Telemetry data deleted. As
+ * such it attempts to send itself at the moment the user opts out of data
+ * collection.
+ */
+constexpr glean::impl::Ping NotDeletionRequest(4);
+
+
+} // namespace mozilla::glean_pings
+
+#endif // mozilla_glean_Pings_h
diff --git a/toolkit/components/glean/pytest/pings_test_output_js b/toolkit/components/glean/pytest/pings_test_output_js
new file mode 100644
index 0000000000..ecbc6ccf7c
--- /dev/null
+++ b/toolkit/components/glean/pytest/pings_test_output_js
@@ -0,0 +1,99 @@
+// -*- mode: C++ -*-
+
+// AUTOGENERATED BY glean_parser. DO NOT EDIT.
+
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_GleanJSPingsLookup_h
+#define mozilla_GleanJSPingsLookup_h
+
+#define GLEAN_PING_INDEX_BITS (16)
+#define GLEAN_PING_ID(entry) ((entry) >> GLEAN_PING_INDEX_BITS)
+#define GLEAN_PING_INDEX(entry) ((entry) & ((1UL << GLEAN_PING_INDEX_BITS) - 1))
+
+namespace mozilla::glean {
+
+// Contains the ping id and the index into the ping string table.
+using ping_entry_t = uint32_t;
+
+static Maybe<uint32_t> ping_result_check(const nsACString& aKey, ping_entry_t aEntry);
+
+#if defined(_MSC_VER) && !defined(__clang__)
+const char gPingStringTable[] = {
+#else
+constexpr char gPingStringTable[] = {
+#endif
+ /* 0 - "notBaseline" */ 'n', 'o', 't', 'B', 'a', 's', 'e', 'l', 'i', 'n', 'e', '\0',
+ /* 12 - "notMetrics" */ 'n', 'o', 't', 'M', 'e', 't', 'r', 'i', 'c', 's', '\0',
+ /* 23 - "notEvents" */ 'n', 'o', 't', 'E', 'v', 'e', 'n', 't', 's', '\0',
+ /* 33 - "notDeletionRequest" */ 'n', 'o', 't', 'D', 'e', 'l', 'e', 't', 'i', 'o', 'n', 'R', 'e', 'q', 'u', 'e', 's', 't', '\0',
+};
+
+
+
+const ping_entry_t sPingByNameLookupEntries[] = {
+ 65536,
+ 196631,
+ 262177,
+ 131084
+};
+
+
+
+static Maybe<uint32_t>
+PingByNameLookup(const nsACString& aKey)
+{
+ static const uint8_t BASES[] = {
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+
+
+ const char* bytes = aKey.BeginReading();
+ size_t length = aKey.Length();
+ auto& entry = mozilla::perfecthash::Lookup(bytes, length, BASES,
+ sPingByNameLookupEntries);
+ return ping_result_check(aKey, entry);
+}
+
+
+/**
+ * Get a ping's name given its entry from the PHF.
+ */
+static const char* GetPingName(ping_entry_t aEntry) {
+ uint32_t idx = GLEAN_PING_INDEX(aEntry);
+ MOZ_ASSERT(idx < sizeof(gPingStringTable), "Ping index larger than string table");
+ return &gPingStringTable[idx];
+}
+
+/**
+ * Check if the found entry is pointing at the correct ping.
+ * PHF can false-positive a result when the key isn't present, so we check
+ * for a string match. If it fails, return Nothing(). If we found it,
+ * return the ping's id.
+ */
+static Maybe<uint32_t> ping_result_check(const nsACString& aKey, ping_entry_t aEntry) {
+ uint32_t idx = GLEAN_PING_INDEX(aEntry);
+ uint32_t id = GLEAN_PING_ID(aEntry);
+
+ if (MOZ_UNLIKELY(idx > sizeof(gPingStringTable))) {
+ return Nothing();
+ }
+
+ if (aKey.EqualsASCII(&gPingStringTable[idx])) {
+ return Some(id);
+ }
+
+ return Nothing();
+}
+
+#undef GLEAN_PING_INDEX_BITS
+#undef GLEAN_PING_ID
+#undef GLEAN_PING_INDEX
+
+} // namespace mozilla::glean
+#endif // mozilla_GleanJSPingsLookup_h
diff --git a/toolkit/components/glean/pytest/python.ini b/toolkit/components/glean/pytest/python.ini
new file mode 100644
index 0000000000..d91d5bafa2
--- /dev/null
+++ b/toolkit/components/glean/pytest/python.ini
@@ -0,0 +1,6 @@
+[DEFAULT]
+subsuite = fog
+
+[test_glean_parser_rust.py]
+[test_glean_parser_cpp.py]
+[test_glean_parser_js.py]
diff --git a/toolkit/components/glean/pytest/test_glean_parser_cpp.py b/toolkit/components/glean/pytest/test_glean_parser_cpp.py
new file mode 100644
index 0000000000..96bcd241a8
--- /dev/null
+++ b/toolkit/components/glean/pytest/test_glean_parser_cpp.py
@@ -0,0 +1,77 @@
+# 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 http://mozilla.org/MPL/2.0/.
+
+import io
+import mozunit
+from os import path
+from pathlib import Path
+import sys
+
+
+# Shenanigans to import the cpp outputter extension
+FOG_ROOT_PATH = path.abspath(path.join(path.dirname(__file__), path.pardir))
+sys.path.append(path.join(FOG_ROOT_PATH, "build_scripts", "glean_parser_ext"))
+import cpp
+
+# Shenanigans to import the in-tree glean_parser
+GECKO_PATH = path.join(FOG_ROOT_PATH, path.pardir, path.pardir, path.pardir)
+sys.path.append(path.join(GECKO_PATH, "third_party", "python", "glean_parser"))
+from glean_parser import lint, parser, util
+
+
+def test_all_metric_types():
+ """Honestly, this is a pretty bad test.
+ It generates C++ for a given test metrics.yaml and compares it byte-for-byte
+ with an expected output C++ file.
+ Expect it to be fragile.
+ To generate a new expected output file, copy the test yaml over the one in t/c/g,
+ run mach build, then copy the C++ output from objdir/t/c/g/.
+ """
+
+ options = {"allow_reserved": False}
+ input_files = [Path(path.join(path.dirname(__file__), "metrics_test.yaml"))]
+
+ all_objs = parser.parse_objects(input_files, options)
+ assert not util.report_validation_errors(all_objs)
+ assert not lint.lint_metrics(all_objs.value, options)
+
+ output_fd = io.StringIO()
+ cpp.output_cpp(all_objs.value, output_fd, options)
+
+ with open(
+ path.join(path.dirname(__file__), "metrics_test_output_cpp"), "r"
+ ) as file:
+ EXPECTED_CPP = file.read()
+ assert output_fd.getvalue() == EXPECTED_CPP
+
+
+def test_fake_pings():
+ """Another similarly-fragile test.
+ It generates C++ for pings_test.yaml, comparing it byte-for-byte
+ with an expected output C++ file `pings_test_output_cpp`.
+ Expect it to be fragile.
+ To generate a new expected output file, edit t/c/g/metrics_index.py,
+ comment out all other ping yamls, and add one for
+ t/c/g/pytest/pings_test.yaml. Run `mach build` (it'll fail). Copy
+ objdir/t/c/g/GleanPings.h over pings_test_output_cpp.
+ (Don't forget to undo your edits to t/c/g/metrics_index.py)
+ """
+
+ options = {"allow_reserved": False}
+ input_files = [Path(path.join(path.dirname(__file__), "pings_test.yaml"))]
+
+ all_objs = parser.parse_objects(input_files, options)
+ assert not util.report_validation_errors(all_objs)
+ assert not lint.lint_metrics(all_objs.value, options)
+
+ output_fd = io.StringIO()
+ cpp.output_cpp(all_objs.value, output_fd, options)
+
+ with open(path.join(path.dirname(__file__), "pings_test_output_cpp"), "r") as file:
+ EXPECTED_CPP = file.read()
+ assert output_fd.getvalue() == EXPECTED_CPP
+
+
+if __name__ == "__main__":
+ mozunit.main()
diff --git a/toolkit/components/glean/pytest/test_glean_parser_js.py b/toolkit/components/glean/pytest/test_glean_parser_js.py
new file mode 100644
index 0000000000..09ba623fcf
--- /dev/null
+++ b/toolkit/components/glean/pytest/test_glean_parser_js.py
@@ -0,0 +1,75 @@
+# 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 http://mozilla.org/MPL/2.0/.
+
+import io
+import mozunit
+from os import path
+from pathlib import Path
+import sys
+
+
+# Shenanigans to import the js outputter extension
+FOG_ROOT_PATH = path.abspath(path.join(path.dirname(__file__), path.pardir))
+sys.path.append(path.join(FOG_ROOT_PATH, "build_scripts", "glean_parser_ext"))
+import js
+
+# Shenanigans to import the in-tree glean_parser
+GECKO_PATH = path.join(FOG_ROOT_PATH, path.pardir, path.pardir, path.pardir)
+sys.path.append(path.join(GECKO_PATH, "third_party", "python", "glean_parser"))
+from glean_parser import lint, parser, util
+
+
+def test_all_metric_types():
+ """Honestly, this is a pretty bad test.
+ It generates C++ for a given test metrics.yaml and compares it byte-for-byte
+ with an expected output C++ file.
+ Expect it to be fragile.
+ To generate a new expected output file, copy the test yaml over the one in t/c/g,
+ run mach build, then copy the C++ output from objdir/t/c/g/.
+ """
+
+ options = {"allow_reserved": False}
+ input_files = [Path(path.join(path.dirname(__file__), "metrics_test.yaml"))]
+
+ all_objs = parser.parse_objects(input_files, options)
+ assert not util.report_validation_errors(all_objs)
+ assert not lint.lint_metrics(all_objs.value, options)
+
+ output_fd = io.StringIO()
+ js.output_js(all_objs.value, output_fd, options)
+
+ with open(path.join(path.dirname(__file__), "metrics_test_output_js"), "r") as file:
+ EXPECTED_JS = file.read()
+ assert output_fd.getvalue() == EXPECTED_JS
+
+
+def test_fake_pings():
+ """Another similarly-fragile test.
+ It generates C++ for pings_test.yaml, comparing it byte-for-byte
+ with an expected output C++ file `pings_test_output_js`.
+ Expect it to be fragile.
+ To generate a new expected output file, edit t/c/g/metrics_index.py,
+ comment out all other ping yamls, and add one for
+ t/c/g/pytest/pings_test.yaml. Run `mach build` (it'll fail). Copy
+ objdir/t/c/g/GleanJSPingsLookup.h over pings_test_output_js.
+ (Don't forget to undo your edits to t/c/g/metrics_index.py)
+ """
+
+ options = {"allow_reserved": False}
+ input_files = [Path(path.join(path.dirname(__file__), "pings_test.yaml"))]
+
+ all_objs = parser.parse_objects(input_files, options)
+ assert not util.report_validation_errors(all_objs)
+ assert not lint.lint_metrics(all_objs.value, options)
+
+ output_fd = io.StringIO()
+ js.output_js(all_objs.value, output_fd, options)
+
+ with open(path.join(path.dirname(__file__), "pings_test_output_js"), "r") as file:
+ EXPECTED_JS = file.read()
+ assert output_fd.getvalue() == EXPECTED_JS
+
+
+if __name__ == "__main__":
+ mozunit.main()
diff --git a/toolkit/components/glean/pytest/test_glean_parser_rust.py b/toolkit/components/glean/pytest/test_glean_parser_rust.py
new file mode 100644
index 0000000000..6bf3fbe841
--- /dev/null
+++ b/toolkit/components/glean/pytest/test_glean_parser_rust.py
@@ -0,0 +1,113 @@
+# 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 http://mozilla.org/MPL/2.0/.
+
+import io
+import mozunit
+from os import path
+from pathlib import Path
+import re
+import sys
+
+
+# Shenanigans to import the rust outputter extension
+FOG_ROOT_PATH = path.abspath(path.join(path.dirname(__file__), path.pardir))
+sys.path.append(path.join(FOG_ROOT_PATH, "build_scripts", "glean_parser_ext"))
+import run_glean_parser
+import rust
+
+# Shenanigans to import the in-tree glean_parser
+GECKO_PATH = path.join(FOG_ROOT_PATH, path.pardir, path.pardir, path.pardir)
+sys.path.append(path.join(GECKO_PATH, "third_party", "python", "glean_parser"))
+from glean_parser import lint, parser, util
+
+
+def test_all_metric_types():
+ """Honestly, this is a pretty bad test.
+ It generates Rust for a given test metrics.yaml and compares it byte-for-byte
+ with an expected output Rust file.
+ Expect it to be fragile.
+ To generate a new expected output file, copy the test yaml over the one in t/c/g,
+ run mach build, then copy the rust output from objdir/t/c/g/api/src/.
+ """
+
+ options = {"allow_reserved": False}
+ input_files = [Path(path.join(path.dirname(__file__), "metrics_test.yaml"))]
+
+ all_objs = parser.parse_objects(input_files, options)
+ assert not util.report_validation_errors(all_objs)
+ assert not lint.lint_metrics(all_objs.value, options)
+
+ output_fd = io.StringIO()
+ rust.output_rust(all_objs.value, output_fd, options)
+
+ with open(path.join(path.dirname(__file__), "metrics_test_output"), "r") as file:
+ EXPECTED_RUST = file.read()
+ assert output_fd.getvalue() == EXPECTED_RUST
+
+
+def test_fake_pings():
+ """Another similarly-bad test.
+ It generates Rust for pings_test.yaml, comparing it byte-for-byte
+ with an expected output Rust file.
+ Expect it to be fragile.
+ To generate a new expected output file, copy the test yaml over the one in t/c/g,
+ run mach build, then copy the rust output from objdir/t/c/g/api/src/.
+ """
+
+ options = {"allow_reserved": False}
+ input_files = [Path(path.join(path.dirname(__file__), "pings_test.yaml"))]
+
+ all_objs = parser.parse_objects(input_files, options)
+ assert not util.report_validation_errors(all_objs)
+ assert not lint.lint_metrics(all_objs.value, options)
+
+ output_fd = io.StringIO()
+ rust.output_rust(all_objs.value, output_fd, options)
+
+ with open(path.join(path.dirname(__file__), "pings_test_output"), "r") as file:
+ EXPECTED_RUST = file.read()
+ assert output_fd.getvalue() == EXPECTED_RUST
+
+
+def test_expires_version():
+ """This test relies on the intermediary object format output by glean_parser.
+ Expect it to be fragile on glean_parser updates that change that format.
+ """
+
+ # The test file has 41, 42, 100. Use 42.0a1 here to ensure "expires == version" means expired.
+ options = run_glean_parser.get_parser_options("42.0a1")
+ input_files = [
+ Path(path.join(path.dirname(__file__), "metrics_expires_versions_test.yaml"))
+ ]
+
+ all_objs = parser.parse_objects(input_files, options)
+
+ assert not util.report_validation_errors(all_objs)
+ assert not lint.lint_metrics(all_objs.value, options)
+
+ assert all_objs.value["test"]["expired1"].disabled is True
+ assert all_objs.value["test"]["expired2"].disabled is True
+ assert all_objs.value["test"]["unexpired"].disabled is False
+
+
+def test_numeric_expires():
+ """What if the expires value is a number, not a string?
+ This test relies on the intermediary object format output by glean_parser.
+ Expect it to be fragile on glean_parser updates that change that format.
+ """
+
+ # We'll never get to checking expires values, so this app version shouldn't matter.
+ options = run_glean_parser.get_parser_options("42.0a1")
+ input_files = [
+ Path(path.join(path.dirname(__file__), "metrics_expires_number_test.yaml"))
+ ]
+
+ all_objs = parser.parse_objects(input_files, options)
+ errors = list(all_objs)
+ assert len(errors) == 1
+ assert re.search("99 is not of type 'string'", str(errors[0]))
+
+
+if __name__ == "__main__":
+ mozunit.main()