summaryrefslogtreecommitdiffstats
path: root/toolkit/components/glean/tests/pytest
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/glean/tests/pytest')
-rw-r--r--toolkit/components/glean/tests/pytest/expect_helper.py34
-rw-r--r--toolkit/components/glean/tests/pytest/gifft_output_Event67
-rw-r--r--toolkit/components/glean/tests/pytest/gifft_output_EventExtra35
-rw-r--r--toolkit/components/glean/tests/pytest/gifft_output_Histogram70
-rw-r--r--toolkit/components/glean/tests/pytest/gifft_output_Scalar102
-rw-r--r--toolkit/components/glean/tests/pytest/jogfile_output344
-rw-r--r--toolkit/components/glean/tests/pytest/metrics_expires_versions_test.yaml84
-rw-r--r--toolkit/components/glean/tests/pytest/metrics_test.yaml398
-rw-r--r--toolkit/components/glean/tests/pytest/metrics_test_output918
-rw-r--r--toolkit/components/glean/tests/pytest/metrics_test_output_cpp287
-rw-r--r--toolkit/components/glean/tests/pytest/metrics_test_output_js_cpp473
-rw-r--r--toolkit/components/glean/tests/pytest/metrics_test_output_js_h75
-rw-r--r--toolkit/components/glean/tests/pytest/pings_test.yaml116
-rw-r--r--toolkit/components/glean/tests/pytest/pings_test_output118
-rw-r--r--toolkit/components/glean/tests/pytest/pings_test_output_cpp62
-rw-r--r--toolkit/components/glean/tests/pytest/pings_test_output_js_cpp162
-rw-r--r--toolkit/components/glean/tests/pytest/pings_test_output_js_h33
-rw-r--r--toolkit/components/glean/tests/pytest/python.toml16
-rw-r--r--toolkit/components/glean/tests/pytest/test_gifft.py49
-rw-r--r--toolkit/components/glean/tests/pytest/test_glean_parser_cpp.py70
-rw-r--r--toolkit/components/glean/tests/pytest/test_glean_parser_js.py84
-rw-r--r--toolkit/components/glean/tests/pytest/test_glean_parser_rust.py89
-rw-r--r--toolkit/components/glean/tests/pytest/test_jogfile_output.py50
-rw-r--r--toolkit/components/glean/tests/pytest/test_no_expired_metrics.py46
-rw-r--r--toolkit/components/glean/tests/pytest/test_yaml_indices.py42
25 files changed, 3824 insertions, 0 deletions
diff --git a/toolkit/components/glean/tests/pytest/expect_helper.py b/toolkit/components/glean/tests/pytest/expect_helper.py
new file mode 100644
index 0000000000..543ef04026
--- /dev/null
+++ b/toolkit/components/glean/tests/pytest/expect_helper.py
@@ -0,0 +1,34 @@
+# 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 inspect
+import os
+
+
+def expect(path, actual):
+ """
+ Assert that the content of the file at `path` contains `actual`.
+
+ If the environment variable `UPDATE_EXPECT` is set, the path content is updated to `actual`.
+ This allows to update the file contents easily.
+ """
+
+ callerframerecord = inspect.stack()[1]
+ frame = callerframerecord[0]
+ info = inspect.getframeinfo(frame)
+ msg = f"""
+Unexpected content in {path} (at {info.filename}:{info.lineno})
+
+If the code generation was changed,
+run the test suite again with `UPDATE_EXPECT=1` set to update the test files.
+""".strip()
+
+ if "UPDATE_EXPECT" in os.environ:
+ with open(path, "w") as file:
+ file.write(actual)
+
+ expected = None
+ with open(path, "r") as file:
+ expected = file.read()
+ assert actual == expected, msg
diff --git a/toolkit/components/glean/tests/pytest/gifft_output_Event b/toolkit/components/glean/tests/pytest/gifft_output_Event
new file mode 100644
index 0000000000..ba80e3300b
--- /dev/null
+++ b/toolkit/components/glean/tests/pytest/gifft_output_Event
@@ -0,0 +1,67 @@
+// -*- mode: C++ -*-
+
+/* This file is auto-generated by run_glean_parser.py.
+ It is only for internal use by types in
+ toolkit/components/glean/bindings/private */
+
+#include "mozilla/AppShutdown.h"
+#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/glean/bindings/GleanJSMetricsLookup.h"
+#include "mozilla/glean/bindings/jog/JOG.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/Telemetry.h"
+#include "nsIThread.h"
+#include "nsThreadUtils.h"
+
+#ifndef mozilla_glean_EventGifftMap_h
+#define mozilla_glean_EventGifftMap_h
+
+#define DYNAMIC_METRIC_BIT (26)
+#define GLEAN_METRIC_ID(id) ((id) & ((1ULL << 27) - 1))
+
+namespace mozilla::glean {
+
+using Telemetry::EventID;
+
+
+static inline Maybe<EventID> EventIdForMetric(uint32_t aId) {
+ switch(aId) {
+ case 17: { // test.nested.event_metric
+ return Some(EventID::EventMetric_EnumNames_AreStrange);
+ }
+ case 18: { // test.nested.event_metric_with_extra
+ return Some(EventID::EventMetric_EnumName_WithExtra);
+ }
+ default: {
+ if (MOZ_UNLIKELY(aId & (1 << DYNAMIC_METRIC_BIT))) {
+ // Dynamic (runtime-registered) metric. Use its static (compiletime-
+ // registered) metric's telemetry_mirror mapping.
+ // ...if applicable.
+
+ // Only JS can use dynamic (runtime-registered) metric ids.
+ MOZ_ASSERT(NS_IsMainThread());
+
+ auto metricName = JOG::GetMetricName(aId);
+ // All of these should have names, but the storage only lasts until
+ // XPCOMWillShutdown, so it might return `Nothing()`.
+ if (metricName.isSome()) {
+ auto maybeMetric = MetricByNameLookup(metricName.ref());
+ if (maybeMetric.isSome()) {
+ uint32_t staticId = GLEAN_METRIC_ID(maybeMetric.value());
+ // Let's ensure we don't infinite loop, huh.
+ MOZ_ASSERT(!(staticId & (1 << DYNAMIC_METRIC_BIT)));
+ return EventIdForMetric(staticId);
+ }
+ }
+ }
+ return Nothing();
+ }
+ }
+}
+
+} // namespace mozilla::glean
+
+#undef GLEAN_METRIC_ID
+#undef DYNAMIC_METRIC_BIT
+
+#endif // mozilla_glean_EventGifftMaps_h
diff --git a/toolkit/components/glean/tests/pytest/gifft_output_EventExtra b/toolkit/components/glean/tests/pytest/gifft_output_EventExtra
new file mode 100644
index 0000000000..f5f2671d99
--- /dev/null
+++ b/toolkit/components/glean/tests/pytest/gifft_output_EventExtra
@@ -0,0 +1,35 @@
+// -*- mode: C++ -*-
+
+/* This file is auto-generated by run_glean_parser.py.
+ It is only for internal use by types in
+ toolkit/components/glean/bindings/private */
+
+#include "mozilla/glean/bindings/Event.h"
+#include "mozilla/glean/GleanMetrics.h"
+
+namespace mozilla::glean {
+
+template <>
+/*static*/ const nsCString impl::EventMetric<NoExtraKeys>::ExtraStringForKey(uint32_t aKey) {
+ MOZ_ASSERT_UNREACHABLE("What are you doing here? No extra keys!");
+ return ""_ns;
+}
+
+template <>
+/*static*/ const nsCString impl::EventMetric<test_nested::EventMetricWithExtraExtra>::ExtraStringForKey(uint32_t aKey) {
+ using test_nested::EventMetricWithExtraExtra;
+ switch (aKey) {
+ case 0: {
+ return "an_extra_key"_ns;
+ }
+ case 1: {
+ return "another_extra_key"_ns;
+ }
+ default: {
+ MOZ_ASSERT_UNREACHABLE("Impossible event key reached.");
+ return ""_ns;
+ }
+ }
+}
+
+}; // namespace mozilla::glean
diff --git a/toolkit/components/glean/tests/pytest/gifft_output_Histogram b/toolkit/components/glean/tests/pytest/gifft_output_Histogram
new file mode 100644
index 0000000000..40a33dd27f
--- /dev/null
+++ b/toolkit/components/glean/tests/pytest/gifft_output_Histogram
@@ -0,0 +1,70 @@
+// -*- mode: C++ -*-
+
+/* This file is auto-generated by run_glean_parser.py.
+ It is only for internal use by types in
+ toolkit/components/glean/bindings/private */
+
+#include "mozilla/AppShutdown.h"
+#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/glean/bindings/GleanJSMetricsLookup.h"
+#include "mozilla/glean/bindings/jog/JOG.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/Telemetry.h"
+#include "nsIThread.h"
+#include "nsThreadUtils.h"
+
+#ifndef mozilla_glean_HistogramGifftMap_h
+#define mozilla_glean_HistogramGifftMap_h
+
+#define DYNAMIC_METRIC_BIT (26)
+#define GLEAN_METRIC_ID(id) ((id) & ((1ULL << 27) - 1))
+
+namespace mozilla::glean {
+
+using Telemetry::HistogramID;
+
+
+static Maybe<HistogramID> HistogramIdForMetric(uint32_t aId) {
+ switch(aId) {
+ case 3: { // test.custom_distribution_metric
+ return Some(HistogramID::SOME_LINEAR_HISTOGRAM);
+ }
+ case 10: { // test.memory_distribution_metric
+ return Some(HistogramID::SOME_MEM_HISTOGRAM_KB);
+ }
+ case 15: { // test.timing_distribution_metric
+ return Some(HistogramID::SOME_TIME_HISTOGRAM_MS);
+ }
+ default: {
+ if (MOZ_UNLIKELY(aId & (1 << DYNAMIC_METRIC_BIT))) {
+ // Dynamic (runtime-registered) metric. Use its static (compiletime-
+ // registered) metric's telemetry_mirror mapping.
+ // ...if applicable.
+
+ // Only JS can use dynamic (runtime-registered) metric ids.
+ MOZ_ASSERT(NS_IsMainThread());
+
+ auto metricName = JOG::GetMetricName(aId);
+ // All of these should have names, but the storage only lasts until
+ // XPCOMWillShutdown, so it might return `Nothing()`.
+ if (metricName.isSome()) {
+ auto maybeMetric = MetricByNameLookup(metricName.ref());
+ if (maybeMetric.isSome()) {
+ uint32_t staticId = GLEAN_METRIC_ID(maybeMetric.value());
+ // Let's ensure we don't infinite loop, huh.
+ MOZ_ASSERT(!(staticId & (1 << DYNAMIC_METRIC_BIT)));
+ return HistogramIdForMetric(staticId);
+ }
+ }
+ }
+ return Nothing();
+ }
+ }
+}
+
+} // namespace mozilla::glean
+
+#undef GLEAN_METRIC_ID
+#undef DYNAMIC_METRIC_BIT
+
+#endif // mozilla_glean_HistogramGifftMaps_h
diff --git a/toolkit/components/glean/tests/pytest/gifft_output_Scalar b/toolkit/components/glean/tests/pytest/gifft_output_Scalar
new file mode 100644
index 0000000000..854455b584
--- /dev/null
+++ b/toolkit/components/glean/tests/pytest/gifft_output_Scalar
@@ -0,0 +1,102 @@
+// -*- mode: C++ -*-
+
+/* This file is auto-generated by run_glean_parser.py.
+ It is only for internal use by types in
+ toolkit/components/glean/bindings/private */
+
+#include "mozilla/AppShutdown.h"
+#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/glean/bindings/GleanJSMetricsLookup.h"
+#include "mozilla/glean/bindings/jog/JOG.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/Telemetry.h"
+#include "nsIThread.h"
+#include "nsThreadUtils.h"
+
+#ifndef mozilla_glean_ScalarGifftMap_h
+#define mozilla_glean_ScalarGifftMap_h
+
+#define DYNAMIC_METRIC_BIT (26)
+#define GLEAN_METRIC_ID(id) ((id) & ((1ULL << 27) - 1))
+
+namespace mozilla::glean {
+
+using Telemetry::ScalarID;
+
+static inline bool IsSubmetricId(uint32_t aId) {
+ // Submetrics have the 2^25 bit set.
+ // (ID_BITS - ID_SIGNAL_BITS, keep it in sync with js.py).
+ return (aId & (1 << 25)) > 0;
+}
+
+static inline Maybe<ScalarID> ScalarIdForMetric(uint32_t aId) {
+ switch(aId) {
+ case 1: { // test.boolean_metric
+ return Some(ScalarID::SOME_BOOL_SCALAR);
+ }
+ case 2: { // test.counter_metric
+ return Some(ScalarID::SOME_UINT_SCALAR);
+ }
+ case 4: { // test.labeled_boolean_metric
+ return Some(ScalarID::SOME_KEYED_BOOL_SCALAR);
+ }
+ case 5: { // test.labeled_boolean_metric_labels
+ return Some(ScalarID::SOME_OTHER_KEYED_BOOL_SCALAR);
+ }
+ case 6: { // test.labeled_counter_metric
+ return Some(ScalarID::SOME_KEYED_UINT_SCALAR);
+ }
+ case 7: { // test.labeled_counter_metric_labels
+ return Some(ScalarID::SOME_OTHER_KEYED_UINT_SCALAR);
+ }
+ case 11: { // test.string_list_metric
+ return Some(ScalarID::YET_ANOTHER_KEYED_BOOL_SCALAR);
+ }
+ case 12: { // test.string_metric
+ return Some(ScalarID::SOME_STRING_SCALAR);
+ }
+ case 14: { // test.timespan_metric
+ return Some(ScalarID::SOME_OTHER_UINT_SCALAR);
+ }
+ case 16: { // test.nested.datetime_metric
+ return Some(ScalarID::SOME_STILL_OTHER_STRING_SCALAR);
+ }
+ case 21: { // test.nested.quantity_metric
+ return Some(ScalarID::TELEMETRY_TEST_MIRROR_FOR_QUANTITY);
+ }
+ case 24: { // test.nested.uuid_metric
+ return Some(ScalarID::SOME_OTHER_STRING_SCALAR);
+ }
+ default: {
+ if (MOZ_UNLIKELY(aId & (1 << DYNAMIC_METRIC_BIT))) {
+ // Dynamic (runtime-registered) metric. Use its static (compiletime-
+ // registered) metric's telemetry_mirror mapping.
+ // ...if applicable.
+
+ // Only JS can use dynamic (runtime-registered) metric ids.
+ MOZ_ASSERT(NS_IsMainThread());
+
+ auto metricName = JOG::GetMetricName(aId);
+ // All of these should have names, but the storage only lasts until
+ // XPCOMWillShutdown, so it might return `Nothing()`.
+ if (metricName.isSome()) {
+ auto maybeMetric = MetricByNameLookup(metricName.ref());
+ if (maybeMetric.isSome()) {
+ uint32_t staticId = GLEAN_METRIC_ID(maybeMetric.value());
+ // Let's ensure we don't infinite loop, huh.
+ MOZ_ASSERT(!(staticId & (1 << DYNAMIC_METRIC_BIT)));
+ return ScalarIdForMetric(staticId);
+ }
+ }
+ }
+ return Nothing();
+ }
+ }
+}
+
+} // namespace mozilla::glean
+
+#undef GLEAN_METRIC_ID
+#undef DYNAMIC_METRIC_BIT
+
+#endif // mozilla_glean_ScalarGifftMaps_h
diff --git a/toolkit/components/glean/tests/pytest/jogfile_output b/toolkit/components/glean/tests/pytest/jogfile_output
new file mode 100644
index 0000000000..d75c08c8ba
--- /dev/null
+++ b/toolkit/components/glean/tests/pytest/jogfile_output
@@ -0,0 +1,344 @@
+{
+ "metrics": {
+ "test": [
+ [
+ "boolean",
+ "boolean_metric",
+ [
+ "metrics"
+ ],
+ "application",
+ false
+ ],
+ [
+ "counter",
+ "counter_metric",
+ [
+ "metrics"
+ ],
+ "application",
+ false
+ ],
+ [
+ "custom_distribution",
+ "custom_distribution_metric",
+ [
+ "metrics"
+ ],
+ "application",
+ false,
+ {
+ "bucket_count": 100,
+ "histogram_type": "linear",
+ "range_max": 100,
+ "range_min": 0
+ }
+ ],
+ [
+ "labeled_boolean",
+ "labeled_boolean_metric",
+ [
+ "metrics"
+ ],
+ "application",
+ false,
+ {
+ "ordered_labels": null
+ }
+ ],
+ [
+ "labeled_boolean",
+ "labeled_boolean_metric_labels",
+ [
+ "metrics"
+ ],
+ "application",
+ false,
+ {
+ "ordered_labels": [
+ "one_label",
+ "two_labels",
+ "three_labels",
+ "four_labels",
+ "five_labels",
+ "six_labels",
+ "seven_labels",
+ "eight_labels",
+ "nine_labels",
+ "ten_labels"
+ ]
+ }
+ ],
+ [
+ "labeled_counter",
+ "labeled_counter_metric",
+ [
+ "metrics"
+ ],
+ "application",
+ false,
+ {
+ "ordered_labels": null
+ }
+ ],
+ [
+ "labeled_counter",
+ "labeled_counter_metric_labels",
+ [
+ "metrics"
+ ],
+ "application",
+ false,
+ {
+ "ordered_labels": [
+ "one_label",
+ "two_labels"
+ ]
+ }
+ ],
+ [
+ "labeled_string",
+ "labeled_string_metric",
+ [
+ "metrics"
+ ],
+ "application",
+ false,
+ {
+ "ordered_labels": null
+ }
+ ],
+ [
+ "labeled_string",
+ "labeled_string_metric_labels",
+ [
+ "metrics"
+ ],
+ "application",
+ false,
+ {
+ "ordered_labels": [
+ "one_label",
+ "two_labels"
+ ]
+ }
+ ],
+ [
+ "memory_distribution",
+ "memory_distribution_metric",
+ [
+ "metrics"
+ ],
+ "application",
+ false,
+ {
+ "memory_unit": "kilobyte"
+ }
+ ],
+ [
+ "string_list",
+ "string_list_metric",
+ [
+ "metrics"
+ ],
+ "application",
+ false
+ ],
+ [
+ "string",
+ "string_metric",
+ [
+ "metrics"
+ ],
+ "application",
+ false
+ ],
+ [
+ "text",
+ "text_metric",
+ [
+ "metrics"
+ ],
+ "application",
+ false
+ ],
+ [
+ "timespan",
+ "timespan_metric",
+ [
+ "metrics"
+ ],
+ "application",
+ false,
+ {
+ "time_unit": "millisecond"
+ }
+ ],
+ [
+ "timing_distribution",
+ "timing_distribution_metric",
+ [
+ "metrics"
+ ],
+ "application",
+ false,
+ {
+ "time_unit": "nanosecond"
+ }
+ ]
+ ],
+ "test.nested": [
+ [
+ "datetime",
+ "datetime_metric",
+ [
+ "metrics"
+ ],
+ "application",
+ false,
+ {
+ "time_unit": "millisecond"
+ }
+ ],
+ [
+ "event",
+ "event_metric",
+ [
+ "events"
+ ],
+ "ping",
+ false,
+ {
+ "allowed_extra_keys": []
+ }
+ ],
+ [
+ "event",
+ "event_metric_with_extra",
+ [
+ "events"
+ ],
+ "ping",
+ false,
+ {
+ "allowed_extra_keys": [
+ "an_extra_key",
+ "another_extra_key"
+ ]
+ }
+ ],
+ [
+ "denominator",
+ "external_denominator",
+ [
+ "metrics"
+ ],
+ "ping",
+ false,
+ {
+ "numerators": [
+ [
+ "rate_with_external_denominator",
+ "test.nested",
+ [
+ "metrics"
+ ],
+ "ping",
+ false,
+ null
+ ]
+ ]
+ }
+ ],
+ [
+ "counter",
+ "optimizable_counter_metric",
+ [
+ "metrics"
+ ],
+ "ping",
+ false
+ ],
+ [
+ "quantity",
+ "quantity_metric",
+ [
+ "metrics"
+ ],
+ "ping",
+ false
+ ],
+ [
+ "rate",
+ "rate_metric",
+ [
+ "metrics"
+ ],
+ "ping",
+ false
+ ],
+ [
+ "rate",
+ "rate_with_external_denominator",
+ [
+ "metrics"
+ ],
+ "ping",
+ false
+ ],
+ [
+ "uuid",
+ "uuid_metric",
+ [
+ "metrics"
+ ],
+ "application",
+ false
+ ]
+ ]
+ },
+ "pings": [
+ [
+ "not-baseline",
+ true,
+ false,
+ true,
+ [
+ "background",
+ "dirty_startup",
+ "foreground"
+ ]
+ ],
+ [
+ "not-deletion-request",
+ true,
+ true,
+ true,
+ []
+ ],
+ [
+ "not-events",
+ true,
+ false,
+ true,
+ [
+ "background",
+ "max_capacity",
+ "startup"
+ ]
+ ],
+ [
+ "not-metrics",
+ true,
+ false,
+ true,
+ [
+ "overdue",
+ "reschedule",
+ "today",
+ "tomorrow",
+ "upgrade"
+ ]
+ ]
+ ]
+} \ No newline at end of file
diff --git a/toolkit/components/glean/tests/pytest/metrics_expires_versions_test.yaml b/toolkit/components/glean/tests/pytest/metrics_expires_versions_test.yaml
new file mode 100644
index 0000000000..ea73a6465e
--- /dev/null
+++ b/toolkit/components/glean/tests/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/2-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/tests/pytest/metrics_test.yaml b/toolkit/components/glean/tests/pytest/metrics_test.yaml
new file mode 100644
index 0000000000..cbbb0220b5
--- /dev/null
+++ b/toolkit/components/glean/tests/pytest/metrics_test.yaml
@@ -0,0 +1,398 @@
+# 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/2-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
+ telemetry_mirror: SOME_BOOL_SCALAR
+
+ 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
+ telemetry_mirror: SOME_KEYED_BOOL_SCALAR
+
+ 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
+ - three_labels
+ - four_labels
+ - five_labels
+ - six_labels
+ - seven_labels
+ - eight_labels
+ - nine_labels
+ - ten_labels
+ telemetry_mirror: SOME_OTHER_KEYED_BOOL_SCALAR
+
+ 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
+ telemetry_mirror: SOME_UINT_SCALAR
+
+ 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
+ telemetry_mirror: SOME_KEYED_UINT_SCALAR
+
+ 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
+ telemetry_mirror: SOME_OTHER_KEYED_UINT_SCALAR
+
+ 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
+ telemetry_mirror: SOME_STRING_SCALAR
+
+ 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
+ telemetry_mirror: YET_ANOTHER_KEYED_BOOL_SCALAR
+
+ text_metric:
+ type: text
+ expires: never
+ description: |
+ A multi-line
+ description
+ lifetime: application
+ notification_emails:
+ - glean-team@mozilla.com
+ bugs:
+ - https://bugzilla.mozilla.org/show_bug.cgi?id=1828528
+ 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
+ telemetry_mirror: SOME_OTHER_UINT_SCALAR
+
+ 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
+ telemetry_mirror: SOME_TIME_HISTOGRAM_MS
+
+ 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
+ telemetry_mirror: SOME_MEM_HISTOGRAM_KB
+
+ custom_distribution_metric:
+ type: custom_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
+ range_min: 0
+ range_max: 100
+ bucket_count: 100
+ histogram_type: linear
+ telemetry_mirror: SOME_LINEAR_HISTOGRAM
+
+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
+ telemetry_mirror: SOME_OTHER_STRING_SCALAR
+
+ 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
+ telemetry_mirror: SOME_STILL_OTHER_STRING_SCALAR
+
+ 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
+ telemetry_mirror: EventMetric_EnumNames_AreStrange
+
+ 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:
+ type: string
+ description: An extra key description
+ another_extra_key:
+ type: string
+ description: Another extra key description
+ telemetry_mirror: EventMetric_EnumName_WithExtra
+
+ quantity_metric:
+ type: quantity
+ unit: someunit
+ expires: never
+ description: |
+ A multi-line
+ description
+ notification_emails:
+ - glean-team@mozilla.com
+ bugs:
+ - https://bugzilla.mozilla.org/1704846/
+ data_reviews:
+ - https://example.com
+ telemetry_mirror: TELEMETRY_TEST_MIRROR_FOR_QUANTITY
+
+ rate_metric:
+ type: rate
+ expires: never
+ description: |
+ A multi-line
+ description
+ notification_emails:
+ - glean-team@mozilla.com
+ bugs:
+ - https://bugzilla.mozilla.org/1704846/
+ data_reviews:
+ - https://example.com
+
+ rate_with_external_denominator:
+ type: rate
+ denominator_metric: test.nested.external_denominator
+ expires: never
+ description: |
+ A multi-line
+ description
+ notification_emails:
+ - glean-team@mozilla.com
+ bugs:
+ - https://bugzilla.mozilla.org/1704846/
+ data_reviews:
+ - https://example.com
+
+ external_denominator:
+ type: counter
+ expires: never
+ description: |
+ A multi-line
+ description
+ notification_emails:
+ - glean-team@mozilla.com
+ bugs:
+ - https://bugzilla.mozilla.org/1704846/
+ data_reviews:
+ - https://example.com
+
+ optimizable_counter_metric:
+ type: counter
+ 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
diff --git a/toolkit/components/glean/tests/pytest/metrics_test_output b/toolkit/components/glean/tests/pytest/metrics_test_output
new file mode 100644
index 0000000000..76808cc984
--- /dev/null
+++ b/toolkit/components/glean/tests/pytest/metrics_test_output
@@ -0,0 +1,918 @@
+// -*- 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 enum DynamicLabel { }
+
+pub mod test {
+ use crate::private::*;
+ #[allow(unused_imports)] // CommonMetricData might be unused, let's avoid warnings
+ use glean::CommonMetricData;
+ #[allow(unused_imports)] // HistogramType might be unusued, let's avoid warnings
+ use glean::HistogramType;
+ 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.counter_metric
+ ///
+ /// A multi-line
+ /// description
+ pub static counter_metric: Lazy<CounterMetric> = Lazy::new(|| {
+ CounterMetric::new(2.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.custom_distribution_metric
+ ///
+ /// A multi-line
+ /// description
+ pub static custom_distribution_metric: Lazy<CustomDistributionMetric> = Lazy::new(|| {
+ CustomDistributionMetric::new(3.into(), CommonMetricData {
+ name: "custom_distribution_metric".into(),
+ category: "test".into(),
+ send_in_pings: vec!["metrics".into()],
+ lifetime: Lifetime::Application,
+ disabled: false,
+ ..Default::default()
+ }, 0, 100, 100, HistogramType::Linear)
+ });
+
+ #[allow(non_upper_case_globals)]
+ /// generated from test.labeled_boolean_metric
+ ///
+ /// A multi-line
+ /// description
+ pub static labeled_boolean_metric: Lazy<LabeledMetric<LabeledBooleanMetric, super::DynamicLabel>> = Lazy::new(|| {
+ LabeledMetric::new(4.into(), CommonMetricData {
+ name: "labeled_boolean_metric".into(),
+ category: "test".into(),
+ send_in_pings: vec!["metrics".into()],
+ lifetime: Lifetime::Application,
+ disabled: false,
+ ..Default::default()
+ }, None)
+ });
+
+ #[repr(u16)]
+ pub enum LabeledBooleanMetricLabelsLabel {
+ OneLabel = 0,
+ TwoLabels = 1,
+ ThreeLabels = 2,
+ FourLabels = 3,
+ FiveLabels = 4,
+ SixLabels = 5,
+ SevenLabels = 6,
+ EightLabels = 7,
+ NineLabels = 8,
+ TenLabels = 9,
+ __Other__,
+ }
+ impl From<u16> for LabeledBooleanMetricLabelsLabel {
+ fn from(v: u16) -> Self {
+ match v {
+ 0 => Self::OneLabel,
+ 1 => Self::TwoLabels,
+ 2 => Self::ThreeLabels,
+ 3 => Self::FourLabels,
+ 4 => Self::FiveLabels,
+ 5 => Self::SixLabels,
+ 6 => Self::SevenLabels,
+ 7 => Self::EightLabels,
+ 8 => Self::NineLabels,
+ 9 => Self::TenLabels,
+ _ => Self::__Other__,
+ }
+ }
+ }
+ impl Into<&'static str> for LabeledBooleanMetricLabelsLabel {
+ fn into(self) -> &'static str {
+ match self {
+ Self::OneLabel => "one_label",
+ Self::TwoLabels => "two_labels",
+ Self::ThreeLabels => "three_labels",
+ Self::FourLabels => "four_labels",
+ Self::FiveLabels => "five_labels",
+ Self::SixLabels => "six_labels",
+ Self::SevenLabels => "seven_labels",
+ Self::EightLabels => "eight_labels",
+ Self::NineLabels => "nine_labels",
+ Self::TenLabels => "ten_labels",
+ Self::__Other__ => "__other__",
+ }
+ }
+ }
+ #[allow(non_upper_case_globals)]
+ /// generated from test.labeled_boolean_metric_labels
+ ///
+ /// A multi-line
+ /// description
+ pub static labeled_boolean_metric_labels: Lazy<LabeledMetric<LabeledBooleanMetric, LabeledBooleanMetricLabelsLabel>> = Lazy::new(|| {
+ LabeledMetric::new(5.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![::std::borrow::Cow::from("eight_labels"), ::std::borrow::Cow::from("five_labels"), ::std::borrow::Cow::from("four_labels"), ::std::borrow::Cow::from("nine_labels"), ::std::borrow::Cow::from("one_label"), ::std::borrow::Cow::from("seven_labels"), ::std::borrow::Cow::from("six_labels"), ::std::borrow::Cow::from("ten_labels"), ::std::borrow::Cow::from("three_labels"), ::std::borrow::Cow::from("two_labels")]))
+ });
+
+ #[allow(non_upper_case_globals)]
+ /// generated from test.labeled_counter_metric
+ ///
+ /// A multi-line
+ /// description
+ pub static labeled_counter_metric: Lazy<LabeledMetric<LabeledCounterMetric, super::DynamicLabel>> = Lazy::new(|| {
+ LabeledMetric::new(6.into(), CommonMetricData {
+ name: "labeled_counter_metric".into(),
+ category: "test".into(),
+ send_in_pings: vec!["metrics".into()],
+ lifetime: Lifetime::Application,
+ disabled: false,
+ ..Default::default()
+ }, None)
+ });
+
+ #[repr(u16)]
+ pub enum LabeledCounterMetricLabelsLabel {
+ OneLabel = 0,
+ TwoLabels = 1,
+ __Other__,
+ }
+ impl From<u16> for LabeledCounterMetricLabelsLabel {
+ fn from(v: u16) -> Self {
+ match v {
+ 0 => Self::OneLabel,
+ 1 => Self::TwoLabels,
+ _ => Self::__Other__,
+ }
+ }
+ }
+ impl Into<&'static str> for LabeledCounterMetricLabelsLabel {
+ fn into(self) -> &'static str {
+ match self {
+ Self::OneLabel => "one_label",
+ Self::TwoLabels => "two_labels",
+ Self::__Other__ => "__other__",
+ }
+ }
+ }
+ #[allow(non_upper_case_globals)]
+ /// generated from test.labeled_counter_metric_labels
+ ///
+ /// A multi-line
+ /// description
+ pub static labeled_counter_metric_labels: Lazy<LabeledMetric<LabeledCounterMetric, LabeledCounterMetricLabelsLabel>> = Lazy::new(|| {
+ LabeledMetric::new(7.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![::std::borrow::Cow::from("one_label"), ::std::borrow::Cow::from("two_labels")]))
+ });
+
+ #[allow(non_upper_case_globals)]
+ /// generated from test.labeled_string_metric
+ ///
+ /// A multi-line
+ /// description
+ pub static labeled_string_metric: Lazy<LabeledMetric<LabeledStringMetric, super::DynamicLabel>> = 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)
+ });
+
+ #[repr(u16)]
+ pub enum LabeledStringMetricLabelsLabel {
+ OneLabel = 0,
+ TwoLabels = 1,
+ __Other__,
+ }
+ impl From<u16> for LabeledStringMetricLabelsLabel {
+ fn from(v: u16) -> Self {
+ match v {
+ 0 => Self::OneLabel,
+ 1 => Self::TwoLabels,
+ _ => Self::__Other__,
+ }
+ }
+ }
+ impl Into<&'static str> for LabeledStringMetricLabelsLabel {
+ fn into(self) -> &'static str {
+ match self {
+ Self::OneLabel => "one_label",
+ Self::TwoLabels => "two_labels",
+ Self::__Other__ => "__other__",
+ }
+ }
+ }
+ #[allow(non_upper_case_globals)]
+ /// generated from test.labeled_string_metric_labels
+ ///
+ /// A multi-line
+ /// description
+ pub static labeled_string_metric_labels: Lazy<LabeledMetric<LabeledStringMetric, LabeledStringMetricLabelsLabel>> = 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![::std::borrow::Cow::from("one_label"), ::std::borrow::Cow::from("two_labels")]))
+ });
+
+ #[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(10.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)
+ });
+
+ #[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(11.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.string_metric
+ ///
+ /// A multi-line
+ /// description
+ pub static string_metric: Lazy<StringMetric> = Lazy::new(|| {
+ StringMetric::new(12.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.text_metric
+ ///
+ /// A multi-line
+ /// description
+ pub static text_metric: Lazy<TextMetric> = Lazy::new(|| {
+ TextMetric::new(13.into(), CommonMetricData {
+ name: "text_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(14.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(15.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)
+ });
+
+}
+pub mod test_nested {
+ use crate::private::*;
+ #[allow(unused_imports)] // CommonMetricData might be unused, let's avoid warnings
+ use glean::CommonMetricData;
+ #[allow(unused_imports)] // HistogramType might be unusued, let's avoid warnings
+ use glean::HistogramType;
+ use once_cell::sync::Lazy;
+
+ #[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(16.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(17.into(), CommonMetricData {
+ name: "event_metric".into(),
+ category: "test.nested".into(),
+ send_in_pings: vec!["events".into()],
+ lifetime: Lifetime::Ping,
+ disabled: false,
+ ..Default::default()
+ })
+ });
+
+ #[derive(Default, Debug, Clone, Hash, Eq, PartialEq)]
+ pub struct EventMetricWithExtraExtra {
+ pub an_extra_key: Option<String>,
+ pub another_extra_key: Option<String>,
+ }
+
+ impl ExtraKeys for EventMetricWithExtraExtra {
+ const ALLOWED_KEYS: &'static [&'static str] = &["an_extra_key", "another_extra_key"];
+
+ fn into_ffi_extra(self) -> ::std::collections::HashMap<String, String> {
+ let mut map = ::std::collections::HashMap::new();
+ self.an_extra_key.and_then(|val| map.insert("an_extra_key".into(), val.to_string()));
+ self.another_extra_key.and_then(|val| map.insert("another_extra_key".into(), val.to_string()));
+ map
+ }
+ }
+ #[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<EventMetricWithExtraExtra>> = Lazy::new(|| {
+ EventMetric::new(18.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(non_upper_case_globals)]
+ /// generated from test.nested.external_denominator
+ ///
+ /// A multi-line
+ /// description
+ pub static external_denominator: Lazy<DenominatorMetric> = Lazy::new(|| {
+ DenominatorMetric::new(19.into(), CommonMetricData {
+ name: "external_denominator".into(),
+ category: "test.nested".into(),
+ send_in_pings: vec!["metrics".into()],
+ lifetime: Lifetime::Ping,
+ disabled: false,
+ ..Default::default()
+ }, vec![CommonMetricData {name: "rate_with_external_denominator".into(), category: "test.nested".into(), send_in_pings: vec!["metrics".into()], lifetime: Lifetime::Ping, disabled: false, ..Default::default()}])
+ });
+
+ #[allow(non_upper_case_globals)]
+ /// generated from test.nested.optimizable_counter_metric
+ ///
+ /// A multi-line
+ /// description
+ pub static optimizable_counter_metric: Lazy<CounterMetric> = Lazy::new(|| {
+ CounterMetric::codegen_new(
+ 20,
+ "test.nested",
+ "optimizable_counter_metric",
+ "metrics"
+ )
+ });
+
+ #[allow(non_upper_case_globals)]
+ /// generated from test.nested.quantity_metric
+ ///
+ /// A multi-line
+ /// description
+ pub static quantity_metric: Lazy<QuantityMetric> = Lazy::new(|| {
+ QuantityMetric::new(21.into(), CommonMetricData {
+ name: "quantity_metric".into(),
+ category: "test.nested".into(),
+ send_in_pings: vec!["metrics".into()],
+ lifetime: Lifetime::Ping,
+ disabled: false,
+ ..Default::default()
+ })
+ });
+
+ #[allow(non_upper_case_globals)]
+ /// generated from test.nested.rate_metric
+ ///
+ /// A multi-line
+ /// description
+ pub static rate_metric: Lazy<RateMetric> = Lazy::new(|| {
+ RateMetric::new(22.into(), CommonMetricData {
+ name: "rate_metric".into(),
+ category: "test.nested".into(),
+ send_in_pings: vec!["metrics".into()],
+ lifetime: Lifetime::Ping,
+ disabled: false,
+ ..Default::default()
+ })
+ });
+
+ #[allow(non_upper_case_globals)]
+ /// generated from test.nested.rate_with_external_denominator
+ ///
+ /// A multi-line
+ /// description
+ pub static rate_with_external_denominator: Lazy<NumeratorMetric> = Lazy::new(|| {
+ NumeratorMetric::new(23.into(), CommonMetricData {
+ name: "rate_with_external_denominator".into(),
+ category: "test.nested".into(),
+ send_in_pings: vec!["metrics".into()],
+ lifetime: Lifetime::Ping,
+ disabled: false,
+ ..Default::default()
+ })
+ });
+
+ #[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(24.into(), CommonMetricData {
+ name: "uuid_metric".into(),
+ category: "test.nested".into(),
+ send_in_pings: vec!["metrics".into()],
+ lifetime: Lifetime::Application,
+ disabled: false,
+ ..Default::default()
+ })
+ });
+
+}
+
+#[allow(dead_code)]
+pub(crate) mod __glean_metric_maps {
+ use std::collections::HashMap;
+
+ use crate::metrics::extra_keys_len;
+ 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 COUNTER_MAP: Lazy<HashMap<MetricId, &Lazy<CounterMetric>>> = Lazy::new(|| {
+ let mut map = HashMap::with_capacity(2);
+ map.insert(2.into(), &super::test::counter_metric);
+ map.insert(20.into(), &super::test_nested::optimizable_counter_metric);
+ map
+ });
+
+ pub static CUSTOM_DISTRIBUTION_MAP: Lazy<HashMap<MetricId, &Lazy<CustomDistributionMetric>>> = Lazy::new(|| {
+ let mut map = HashMap::with_capacity(1);
+ map.insert(3.into(), &super::test::custom_distribution_metric);
+ map
+ });
+
+ pub static MEMORY_DISTRIBUTION_MAP: Lazy<HashMap<MetricId, &Lazy<MemoryDistributionMetric>>> = Lazy::new(|| {
+ let mut map = HashMap::with_capacity(1);
+ map.insert(10.into(), &super::test::memory_distribution_metric);
+ map
+ });
+
+ pub static STRING_LIST_MAP: Lazy<HashMap<MetricId, &Lazy<StringListMetric>>> = Lazy::new(|| {
+ let mut map = HashMap::with_capacity(1);
+ map.insert(11.into(), &super::test::string_list_metric);
+ map
+ });
+
+ pub static STRING_MAP: Lazy<HashMap<MetricId, &Lazy<StringMetric>>> = Lazy::new(|| {
+ let mut map = HashMap::with_capacity(1);
+ map.insert(12.into(), &super::test::string_metric);
+ map
+ });
+
+ pub static TEXT_MAP: Lazy<HashMap<MetricId, &Lazy<TextMetric>>> = Lazy::new(|| {
+ let mut map = HashMap::with_capacity(1);
+ map.insert(13.into(), &super::test::text_metric);
+ map
+ });
+
+ pub static TIMESPAN_MAP: Lazy<HashMap<MetricId, &Lazy<TimespanMetric>>> = Lazy::new(|| {
+ let mut map = HashMap::with_capacity(1);
+ map.insert(14.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(15.into(), &super::test::timing_distribution_metric);
+ map
+ });
+
+ pub static DATETIME_MAP: Lazy<HashMap<MetricId, &Lazy<DatetimeMetric>>> = Lazy::new(|| {
+ let mut map = HashMap::with_capacity(1);
+ map.insert(16.into(), &super::test_nested::datetime_metric);
+ map
+ });
+
+ pub static DENOMINATOR_MAP: Lazy<HashMap<MetricId, &Lazy<DenominatorMetric>>> = Lazy::new(|| {
+ let mut map = HashMap::with_capacity(1);
+ map.insert(19.into(), &super::test_nested::external_denominator);
+ map
+ });
+
+ pub static QUANTITY_MAP: Lazy<HashMap<MetricId, &Lazy<QuantityMetric>>> = Lazy::new(|| {
+ let mut map = HashMap::with_capacity(1);
+ map.insert(21.into(), &super::test_nested::quantity_metric);
+ map
+ });
+
+ pub static RATE_MAP: Lazy<HashMap<MetricId, &Lazy<RateMetric>>> = Lazy::new(|| {
+ let mut map = HashMap::with_capacity(1);
+ map.insert(22.into(), &super::test_nested::rate_metric);
+ map
+ });
+
+ pub static NUMERATOR_MAP: Lazy<HashMap<MetricId, &Lazy<NumeratorMetric>>> = Lazy::new(|| {
+ let mut map = HashMap::with_capacity(1);
+ map.insert(23.into(), &super::test_nested::rate_with_external_denominator);
+ map
+ });
+
+ pub static UUID_MAP: Lazy<HashMap<MetricId, &Lazy<UuidMetric>>> = Lazy::new(|| {
+ let mut map = HashMap::with_capacity(1);
+ map.insert(24.into(), &super::test_nested::uuid_metric);
+ map
+ });
+
+
+ /// Wrapper to record an event based on its metric ID.
+ ///
+ /// # Arguments
+ ///
+ /// * `metric_id` - The metric's ID to look up
+ /// * `extra` - An 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` if the `extra` map could not be deserialized.
+ pub(crate) fn record_event_by_id(metric_id: u32, extra: HashMap<String, String>) -> Result<(), EventRecordingError> {
+ match metric_id {
+ 17 => {
+ assert!(
+ extra_keys_len(&super::test_nested::event_metric) != 0 || extra.is_empty(),
+ "No extra keys allowed, but some were passed"
+ );
+
+ super::test_nested::event_metric.record_raw(extra);
+ Ok(())
+ }
+ 18 => {
+ assert!(
+ extra_keys_len(&super::test_nested::event_metric_with_extra) != 0 || extra.is_empty(),
+ "No extra keys allowed, but some were passed"
+ );
+
+ super::test_nested::event_metric_with_extra.record_raw(extra);
+ Ok(())
+ }
+ _ => Err(EventRecordingError::InvalidId),
+ }
+ }
+
+ /// Wrapper to record an event based on its metric ID, with a provided timestamp.
+ ///
+ /// # Arguments
+ ///
+ /// * `metric_id` - The metric's ID to look up
+ /// * `timestamp` - The time at which this event was recorded.
+ /// * `extra` - An 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` if the event doesn't take extra pairs,
+ /// but some are passed in.
+ pub(crate) fn record_event_by_id_with_time(metric_id: MetricId, timestamp: u64, extra: HashMap<String, String>) -> Result<(), EventRecordingError> {
+ match metric_id {
+ MetricId(17) => {
+ if extra_keys_len(&super::test_nested::event_metric) == 0 && !extra.is_empty() {
+ return Err(EventRecordingError::InvalidExtraKey);
+ }
+
+ super::test_nested::event_metric.record_with_time(timestamp, extra);
+ Ok(())
+ }
+ MetricId(18) => {
+ if extra_keys_len(&super::test_nested::event_metric_with_extra) == 0 && !extra.is_empty() {
+ return Err(EventRecordingError::InvalidExtraKey);
+ }
+
+ super::test_nested::event_metric_with_extra.record_with_time(timestamp, 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
+ /// * `ping_name` - (Optional) The ping name to look into.
+ /// Defaults to the first value in `send_in_pings`.
+ ///
+ /// # 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, ping_name: Option<String>) -> Option<Vec<RecordedEvent>> {
+ match metric_id {
+ 17 => super::test_nested::event_metric.test_get_value(ping_name.as_deref()),
+ 18 => super::test_nested::event_metric_with_extra.test_get_value(ping_name.as_deref()),
+ _ => panic!("No event for metric id {}", metric_id),
+ }
+ }
+
+ /// Check the provided event for errors.
+ ///
+ /// # Arguments
+ ///
+ /// * `metric_id` - The metric's ID to look up
+ /// * `ping_name` - (Optional) The ping name to look into.
+ /// Defaults to the first value in `send_in_pings`.
+ ///
+ /// # Returns
+ ///
+ /// Returns a string for the recorded error or `None`.
+ ///
+ /// # Panics
+ ///
+ /// Panics if no event by the given metric ID could be found.
+ #[allow(unused_variables)]
+ pub(crate) fn event_test_get_error(metric_id: u32) -> Option<String> {
+ #[cfg(feature = "with_gecko")]
+ match metric_id {
+ 17 => test_get_errors!(super::test_nested::event_metric),
+ 18 => test_get_errors!(super::test_nested::event_metric_with_extra),
+ _ => panic!("No event for metric id {}", metric_id),
+ }
+
+ #[cfg(not(feature = "with_gecko"))]
+ {
+ return None;
+ }
+ }
+
+ /// Gets the submetric from the specified labeled_boolean metric.
+ ///
+ /// # Arguments
+ ///
+ /// * `metric_id` - The metric's ID to look up
+ /// * `label` - The label identifying the boolean submetric.
+ ///
+ /// # Returns
+ ///
+ /// Returns the boolean submetric.
+ ///
+ /// # Panics
+ ///
+ /// Panics if no labeled_boolean by the given metric ID could be found.
+ #[allow(unused_variables)]
+ pub(crate) fn labeled_boolean_get(metric_id: u32, label: &str) -> LabeledBooleanMetric {
+ match metric_id {
+ 4 => super::test::labeled_boolean_metric.get(label),
+ 5 => super::test::labeled_boolean_metric_labels.get(label),
+ _ => panic!("No labeled_boolean for metric id {}", metric_id),
+ }
+ }
+
+ /// Gets the submetric from the specified labeled_boolean metric, by enum.
+ ///
+ /// # Arguments
+ ///
+ /// * `metric_id` - The metric's ID to look up
+ /// * `label_enum` - The label enum identifying the boolean submetric.
+ ///
+ /// # Returns
+ ///
+ /// Returns the boolean submetric.
+ ///
+ /// # Panics
+ ///
+ /// Panics if no labeled_boolean by the given metric ID could be found.
+ #[allow(unused_variables)]
+ pub(crate) fn labeled_boolean_enum_get(metric_id: u32, label_enum: u16) -> LabeledBooleanMetric {
+ match metric_id {
+ 5 => super::test::labeled_boolean_metric_labels.get(labeled_enum_to_str(metric_id, label_enum)),
+ _ => panic!("No labeled_boolean for metric id {}", metric_id),
+ }
+ }
+ /// Gets the submetric from the specified labeled_counter metric.
+ ///
+ /// # Arguments
+ ///
+ /// * `metric_id` - The metric's ID to look up
+ /// * `label` - The label identifying the counter submetric.
+ ///
+ /// # Returns
+ ///
+ /// Returns the counter submetric.
+ ///
+ /// # Panics
+ ///
+ /// Panics if no labeled_counter by the given metric ID could be found.
+ #[allow(unused_variables)]
+ pub(crate) fn labeled_counter_get(metric_id: u32, label: &str) -> LabeledCounterMetric {
+ match metric_id {
+ 6 => super::test::labeled_counter_metric.get(label),
+ 7 => super::test::labeled_counter_metric_labels.get(label),
+ _ => panic!("No labeled_counter for metric id {}", metric_id),
+ }
+ }
+
+ /// Gets the submetric from the specified labeled_counter metric, by enum.
+ ///
+ /// # Arguments
+ ///
+ /// * `metric_id` - The metric's ID to look up
+ /// * `label_enum` - The label enum identifying the counter submetric.
+ ///
+ /// # Returns
+ ///
+ /// Returns the counter submetric.
+ ///
+ /// # Panics
+ ///
+ /// Panics if no labeled_counter by the given metric ID could be found.
+ #[allow(unused_variables)]
+ pub(crate) fn labeled_counter_enum_get(metric_id: u32, label_enum: u16) -> LabeledCounterMetric {
+ match metric_id {
+ 7 => super::test::labeled_counter_metric_labels.get(labeled_enum_to_str(metric_id, label_enum)),
+ _ => panic!("No labeled_counter for metric id {}", metric_id),
+ }
+ }
+ /// Gets the submetric from the specified labeled_string metric.
+ ///
+ /// # Arguments
+ ///
+ /// * `metric_id` - The metric's ID to look up
+ /// * `label` - The label identifying the string submetric.
+ ///
+ /// # Returns
+ ///
+ /// Returns the string submetric.
+ ///
+ /// # Panics
+ ///
+ /// Panics if no labeled_string by the given metric ID could be found.
+ #[allow(unused_variables)]
+ pub(crate) fn labeled_string_get(metric_id: u32, label: &str) -> LabeledStringMetric {
+ match metric_id {
+ 8 => super::test::labeled_string_metric.get(label),
+ 9 => super::test::labeled_string_metric_labels.get(label),
+ _ => panic!("No labeled_string for metric id {}", metric_id),
+ }
+ }
+
+ /// Gets the submetric from the specified labeled_string metric, by enum.
+ ///
+ /// # Arguments
+ ///
+ /// * `metric_id` - The metric's ID to look up
+ /// * `label_enum` - The label enum identifying the string submetric.
+ ///
+ /// # Returns
+ ///
+ /// Returns the string submetric.
+ ///
+ /// # Panics
+ ///
+ /// Panics if no labeled_string by the given metric ID could be found.
+ #[allow(unused_variables)]
+ pub(crate) fn labeled_string_enum_get(metric_id: u32, label_enum: u16) -> LabeledStringMetric {
+ match metric_id {
+ 9 => super::test::labeled_string_metric_labels.get(labeled_enum_to_str(metric_id, label_enum)),
+ _ => panic!("No labeled_string for metric id {}", metric_id),
+ }
+ }
+
+ pub(crate) fn labeled_enum_to_str(metric_id: u32, label: u16) -> &'static str {
+ match metric_id {
+ 5 => super::test::LabeledBooleanMetricLabelsLabel::from(label).into(),
+ 7 => super::test::LabeledCounterMetricLabelsLabel::from(label).into(),
+ 9 => super::test::LabeledStringMetricLabelsLabel::from(label).into(),
+ _ => panic!("Can't turn label enum to string for metric {} which isn't a labeled metric with static labels", metric_id),
+ }
+ }
+
+ pub(crate) mod submetric_maps {
+ use std::sync::{
+ atomic::AtomicU32,
+ RwLock,
+ };
+ use super::*;
+
+ pub(crate) const SUBMETRIC_BIT: u32 = 25;
+ pub(crate) static NEXT_LABELED_SUBMETRIC_ID: AtomicU32 = AtomicU32::new((1 << SUBMETRIC_BIT) + 1);
+ pub(crate) static LABELED_METRICS_TO_IDS: Lazy<RwLock<HashMap<(u32, String), u32>>> = Lazy::new(||
+ RwLock::new(HashMap::new())
+ );
+ pub(crate) static LABELED_ENUMS_TO_IDS: Lazy<RwLock<HashMap<(u32, u16), u32>>> = Lazy::new(||
+ RwLock::new(HashMap::new())
+ );
+
+ pub static BOOLEAN_MAP: Lazy<RwLock<HashMap<MetricId, LabeledBooleanMetric>>> = Lazy::new(||
+ RwLock::new(HashMap::new())
+ );
+ pub static COUNTER_MAP: Lazy<RwLock<HashMap<MetricId, LabeledCounterMetric>>> = Lazy::new(||
+ RwLock::new(HashMap::new())
+ );
+ pub static STRING_MAP: Lazy<RwLock<HashMap<MetricId, LabeledStringMetric>>> = Lazy::new(||
+ RwLock::new(HashMap::new())
+ );
+ }
+}
+
diff --git a/toolkit/components/glean/tests/pytest/metrics_test_output_cpp b/toolkit/components/glean/tests/pytest/metrics_test_output_cpp
new file mode 100644
index 0000000000..5b9c7bfae4
--- /dev/null
+++ b/toolkit/components/glean/tests/pytest/metrics_test_output_cpp
@@ -0,0 +1,287 @@
+// -*- 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"
+#include "mozilla/Maybe.h"
+#include "nsTArray.h"
+#include "nsPrintfCString.h"
+
+#include <tuple>
+
+namespace mozilla::glean {
+struct NoExtraKeys;
+enum class DynamicLabel: uint16_t { };
+
+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(2);
+
+ /**
+ * generated from test.custom_distribution_metric
+ */
+ /**
+ * A multi-line
+ * description
+ */
+ constexpr impl::CustomDistributionMetric custom_distribution_metric(3);
+
+ /**
+ * generated from test.labeled_boolean_metric
+ */
+ /**
+ * A multi-line
+ * description
+ */
+ constexpr impl::Labeled<impl::BooleanMetric, DynamicLabel> labeled_boolean_metric(4);
+
+ /**
+ * generated from test.labeled_boolean_metric_labels
+ */
+ enum class LabeledBooleanMetricLabelsLabel: uint16_t {
+ eOneLabel = 0,
+ eTwoLabels = 1,
+ eThreeLabels = 2,
+ eFourLabels = 3,
+ eFiveLabels = 4,
+ eSixLabels = 5,
+ eSevenLabels = 6,
+ eEightLabels = 7,
+ eNineLabels = 8,
+ eTenLabels = 9,
+ e__Other__,
+ };
+ /**
+ * A multi-line
+ * description
+ */
+ constexpr impl::Labeled<impl::BooleanMetric, LabeledBooleanMetricLabelsLabel> labeled_boolean_metric_labels(5);
+
+ /**
+ * generated from test.labeled_counter_metric
+ */
+ /**
+ * A multi-line
+ * description
+ */
+ constexpr impl::Labeled<impl::CounterMetric, DynamicLabel> labeled_counter_metric(6);
+
+ /**
+ * generated from test.labeled_counter_metric_labels
+ */
+ enum class LabeledCounterMetricLabelsLabel: uint16_t {
+ eOneLabel = 0,
+ eTwoLabels = 1,
+ e__Other__,
+ };
+ /**
+ * A multi-line
+ * description
+ */
+ constexpr impl::Labeled<impl::CounterMetric, LabeledCounterMetricLabelsLabel> labeled_counter_metric_labels(7);
+
+ /**
+ * generated from test.labeled_string_metric
+ */
+ /**
+ * A multi-line
+ * description
+ */
+ constexpr impl::Labeled<impl::StringMetric, DynamicLabel> labeled_string_metric(8);
+
+ /**
+ * generated from test.labeled_string_metric_labels
+ */
+ enum class LabeledStringMetricLabelsLabel: uint16_t {
+ eOneLabel = 0,
+ eTwoLabels = 1,
+ e__Other__,
+ };
+ /**
+ * A multi-line
+ * description
+ */
+ constexpr impl::Labeled<impl::StringMetric, LabeledStringMetricLabelsLabel> labeled_string_metric_labels(9);
+
+ /**
+ * generated from test.memory_distribution_metric
+ */
+ /**
+ * A multi-line
+ * description
+ */
+ constexpr impl::MemoryDistributionMetric memory_distribution_metric(10);
+
+ /**
+ * generated from test.string_list_metric
+ */
+ /**
+ * A multi-line
+ * description
+ */
+ constexpr impl::StringListMetric string_list_metric(11);
+
+ /**
+ * generated from test.string_metric
+ */
+ /**
+ * A multi-line
+ * description
+ */
+ constexpr impl::StringMetric string_metric(12);
+
+ /**
+ * generated from test.text_metric
+ */
+ /**
+ * A multi-line
+ * description
+ */
+ constexpr impl::TextMetric text_metric(13);
+
+ /**
+ * generated from test.timespan_metric
+ */
+ /**
+ * A multi-line
+ * description
+ */
+ constexpr impl::TimespanMetric timespan_metric(14);
+
+ /**
+ * generated from test.timing_distribution_metric
+ */
+ /**
+ * A multi-line
+ * description
+ */
+ constexpr impl::TimingDistributionMetric timing_distribution_metric(15);
+
+}
+namespace test_nested {
+ /**
+ * generated from test.nested.datetime_metric
+ */
+ /**
+ * A multi-line
+ * description
+ */
+ constexpr impl::DatetimeMetric datetime_metric(16);
+
+ /**
+ * generated from test.nested.event_metric
+ */
+ /**
+ * A multi-line
+ * description
+ */
+ constexpr impl::EventMetric<NoExtraKeys> event_metric(17);
+
+ /**
+ * generated from test.nested.event_metric_with_extra
+ */
+ struct EventMetricWithExtraExtra {
+ mozilla::Maybe<nsCString> anExtraKey;
+ mozilla::Maybe<nsCString> anotherExtraKey;
+
+ std::tuple<nsTArray<nsCString>, nsTArray<nsCString>> ToFfiExtra() const {
+ nsTArray<nsCString> extraKeys;
+ nsTArray<nsCString> extraValues;
+ if (anExtraKey) {
+ extraKeys.AppendElement()->AssignASCII("an_extra_key");
+ extraValues.EmplaceBack(anExtraKey.value());
+ }
+ if (anotherExtraKey) {
+ extraKeys.AppendElement()->AssignASCII("another_extra_key");
+ extraValues.EmplaceBack(anotherExtraKey.value());
+ }
+ return std::make_tuple(std::move(extraKeys), std::move(extraValues));
+ }
+ };
+ /**
+ * A multi-line
+ * description
+ */
+ constexpr impl::EventMetric<EventMetricWithExtraExtra> event_metric_with_extra(18);
+
+ /**
+ * generated from test.nested.external_denominator
+ */
+ /**
+ * A multi-line
+ * description
+ */
+ constexpr impl::DenominatorMetric external_denominator(19);
+
+ /**
+ * generated from test.nested.optimizable_counter_metric
+ */
+ /**
+ * A multi-line
+ * description
+ */
+ constexpr impl::CounterMetric optimizable_counter_metric(20);
+
+ /**
+ * generated from test.nested.quantity_metric
+ */
+ /**
+ * A multi-line
+ * description
+ */
+ constexpr impl::QuantityMetric quantity_metric(21);
+
+ /**
+ * generated from test.nested.rate_metric
+ */
+ /**
+ * A multi-line
+ * description
+ */
+ constexpr impl::RateMetric rate_metric(22);
+
+ /**
+ * generated from test.nested.rate_with_external_denominator
+ */
+ /**
+ * A multi-line
+ * description
+ */
+ constexpr impl::NumeratorMetric rate_with_external_denominator(23);
+
+ /**
+ * generated from test.nested.uuid_metric
+ */
+ /**
+ * A multi-line
+ * description
+ */
+ constexpr impl::UuidMetric uuid_metric(24);
+
+}
+
+} // namespace mozilla::glean
+
+#endif // mozilla_Metrics_h
diff --git a/toolkit/components/glean/tests/pytest/metrics_test_output_js_cpp b/toolkit/components/glean/tests/pytest/metrics_test_output_js_cpp
new file mode 100644
index 0000000000..ba4619bb57
--- /dev/null
+++ b/toolkit/components/glean/tests/pytest/metrics_test_output_js_cpp
@@ -0,0 +1,473 @@
+// -*- 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/. */
+
+#include "mozilla/glean/bindings/GleanJSMetricsLookup.h"
+
+#include "mozilla/PerfectHash.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/glean/bindings/MetricTypes.h"
+#include "mozilla/glean/fog_ffi_generated.h"
+#include "nsString.h"
+
+#define GLEAN_INDEX_BITS (32)
+#define GLEAN_TYPE_BITS (5)
+#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
+// This is a bitpacked type with 32 bits available to index into
+// the string table, 5 bits available to signify the metric type,
+// and the remaining 27 bits devoted to 2 "signal"
+// bits to signify important characteristics (metric's a labeled metric's
+// submetric, metric's been registered at runtime) and 25 bits
+// for built-in metric ids.
+// Gives room for 33554432 of each combination of
+// characteristics (which hopefully will prove to be enough).
+using metric_entry_t = uint64_t;
+
+static_assert(GLEAN_INDEX_BITS + GLEAN_TYPE_BITS + GLEAN_ID_BITS == sizeof(metric_entry_t) * 8, "Index, Type, and ID bits need to fit into a metric_entry_t");
+static_assert(GLEAN_TYPE_BITS + GLEAN_ID_BITS <= sizeof(uint32_t) * 8, "Metric Types and IDs need to fit into at most 32 bits");
+static_assert(2 < UINT32_MAX, "Too many metric categories generated.");
+static_assert(24 < 33554432, "Too many metrics generated. Need room for 2 signal bits.");
+static_assert(19 < 32, "Too many different metric types.");
+
+already_AddRefed<GleanMetric> NewMetricFromId(uint32_t id, nsISupports* aParent) {
+ uint32_t typeId = GLEAN_TYPE_ID(id);
+ uint32_t metricId = GLEAN_METRIC_ID(id);
+
+ switch (typeId) {
+ case 1: /* boolean */
+ {
+ return MakeAndAddRef<GleanBoolean>(metricId, aParent);
+ }
+ case 2: /* counter */
+ {
+ return MakeAndAddRef<GleanCounter>(metricId, aParent);
+ }
+ case 3: /* custom_distribution */
+ {
+ return MakeAndAddRef<GleanCustomDistribution>(metricId, aParent);
+ }
+ case 4: /* labeled_boolean */
+ {
+ return MakeAndAddRef<GleanLabeled>(metricId, 4, aParent);
+ }
+ case 5: /* labeled_counter */
+ {
+ return MakeAndAddRef<GleanLabeled>(metricId, 5, aParent);
+ }
+ case 6: /* labeled_string */
+ {
+ return MakeAndAddRef<GleanLabeled>(metricId, 6, aParent);
+ }
+ case 7: /* memory_distribution */
+ {
+ return MakeAndAddRef<GleanMemoryDistribution>(metricId, aParent);
+ }
+ case 8: /* string_list */
+ {
+ return MakeAndAddRef<GleanStringList>(metricId, aParent);
+ }
+ case 9: /* string */
+ {
+ return MakeAndAddRef<GleanString>(metricId, aParent);
+ }
+ case 10: /* text */
+ {
+ return MakeAndAddRef<GleanText>(metricId, aParent);
+ }
+ case 11: /* timespan */
+ {
+ return MakeAndAddRef<GleanTimespan>(metricId, aParent);
+ }
+ case 12: /* timing_distribution */
+ {
+ return MakeAndAddRef<GleanTimingDistribution>(metricId, aParent);
+ }
+ case 13: /* datetime */
+ {
+ return MakeAndAddRef<GleanDatetime>(metricId, aParent);
+ }
+ case 14: /* event */
+ {
+ return MakeAndAddRef<GleanEvent>(metricId, aParent);
+ }
+ case 15: /* denominator */
+ {
+ return MakeAndAddRef<GleanDenominator>(metricId, aParent);
+ }
+ case 16: /* quantity */
+ {
+ return MakeAndAddRef<GleanQuantity>(metricId, aParent);
+ }
+ case 17: /* rate */
+ {
+ return MakeAndAddRef<GleanRate>(metricId, aParent);
+ }
+ case 18: /* numerator */
+ {
+ return MakeAndAddRef<GleanNumerator>(metricId, aParent);
+ }
+ case 19: /* uuid */
+ {
+ return MakeAndAddRef<GleanUuid>(metricId, aParent);
+ }
+ default:
+ MOZ_ASSERT_UNREACHABLE("Invalid type ID reached when trying to instantiate a new metric");
+ return nullptr;
+ }
+}
+
+/**
+ * Create a submetric instance for a labeled metric of the provided type and id for the given label.
+ * Assigns or retrieves an id for the submetric from the SDK.
+ *
+ * @param aParentTypeId - The type of the parent labeled metric identified as a number generated during codegen.
+ * Only used to identify which X of LabeledX you are so that X can be created here.
+ * @param aParentMetricId - The metric id for the parent labeled metric.
+ * @param aLabel - The label for the submetric. Might not adhere to the SDK label format.
+ * @param aSubmetricId - an outparam which is assigned the submetric's SDK-generated submetric id.
+ * Used only by GIFFT.
+ */
+already_AddRefed<GleanMetric> NewSubMetricFromIds(uint32_t aParentTypeId,
+ uint32_t aParentMetricId,
+ const nsACString& aLabel,
+ uint32_t* aSubmetricId,
+ nsISupports* aParent) {
+ switch (aParentTypeId) {
+ case 4: { /* labeled_boolean */
+ auto id = impl::fog_labeled_boolean_get(aParentMetricId, &aLabel);
+ *aSubmetricId = id;
+ return MakeAndAddRef<GleanBoolean>(id, aParent);
+ }
+ case 5: { /* labeled_counter */
+ auto id = impl::fog_labeled_counter_get(aParentMetricId, &aLabel);
+ *aSubmetricId = id;
+ return MakeAndAddRef<GleanCounter>(id, aParent);
+ }
+ case 6: { /* labeled_string */
+ auto id = impl::fog_labeled_string_get(aParentMetricId, &aLabel);
+ *aSubmetricId = id;
+ return MakeAndAddRef<GleanString>(id, aParent);
+ }
+ default: {
+ MOZ_ASSERT_UNREACHABLE("Invalid type ID for submetric.");
+ 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[] = {
+ 5ul,
+ 0ul
+};
+
+
+
+Maybe<uint32_t>
+CategoryByNameLookup(const nsACString& aKey)
+{
+ static const uint8_t BASES[] = {
+ 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, 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, 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, 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, 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, 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, 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, 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,
+ 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, 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, 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, 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, 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, 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, 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, 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,
+ 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, 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, 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,
+ 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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.counterMetric" */ 't', 'e', 's', 't', '.', 'c', 'o', 'u', 'n', 't', 'e', 'r', 'M', 'e', 't', 'r', 'i', 'c', '\0',
+ /* 38 - "test.customDistributionMetric" */ 't', 'e', 's', 't', '.', 'c', 'u', 's', 't', 'o', 'm', 'D', 'i', 's', 't', 'r', 'i', 'b', 'u', 't', 'i', 'o', 'n', 'M', 'e', 't', 'r', 'i', 'c', '\0',
+ /* 68 - "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',
+ /* 94 - "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',
+ /* 126 - "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',
+ /* 152 - "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',
+ /* 184 - "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',
+ /* 209 - "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',
+ /* 240 - "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',
+ /* 270 - "test.stringListMetric" */ 't', 'e', 's', 't', '.', 's', 't', 'r', 'i', 'n', 'g', 'L', 'i', 's', 't', 'M', 'e', 't', 'r', 'i', 'c', '\0',
+ /* 292 - "test.stringMetric" */ 't', 'e', 's', 't', '.', 's', 't', 'r', 'i', 'n', 'g', 'M', 'e', 't', 'r', 'i', 'c', '\0',
+ /* 310 - "test.textMetric" */ 't', 'e', 's', 't', '.', 't', 'e', 'x', 't', 'M', 'e', 't', 'r', 'i', 'c', '\0',
+ /* 326 - "test.timespanMetric" */ 't', 'e', 's', 't', '.', 't', 'i', 'm', 'e', 's', 'p', 'a', 'n', 'M', 'e', 't', 'r', 'i', 'c', '\0',
+ /* 346 - "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',
+ /* 376 - "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',
+ /* 402 - "testNested.eventMetric" */ 't', 'e', 's', 't', 'N', 'e', 's', 't', 'e', 'd', '.', 'e', 'v', 'e', 'n', 't', 'M', 'e', 't', 'r', 'i', 'c', '\0',
+ /* 425 - "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',
+ /* 457 - "testNested.externalDenominator" */ 't', 'e', 's', 't', 'N', 'e', 's', 't', 'e', 'd', '.', 'e', 'x', 't', 'e', 'r', 'n', 'a', 'l', 'D', 'e', 'n', 'o', 'm', 'i', 'n', 'a', 't', 'o', 'r', '\0',
+ /* 488 - "testNested.optimizableCounterMetric" */ 't', 'e', 's', 't', 'N', 'e', 's', 't', 'e', 'd', '.', 'o', 'p', 't', 'i', 'm', 'i', 'z', 'a', 'b', 'l', 'e', 'C', 'o', 'u', 'n', 't', 'e', 'r', 'M', 'e', 't', 'r', 'i', 'c', '\0',
+ /* 524 - "testNested.quantityMetric" */ 't', 'e', 's', 't', 'N', 'e', 's', 't', 'e', 'd', '.', 'q', 'u', 'a', 'n', 't', 'i', 't', 'y', 'M', 'e', 't', 'r', 'i', 'c', '\0',
+ /* 550 - "testNested.rateMetric" */ 't', 'e', 's', 't', 'N', 'e', 's', 't', 'e', 'd', '.', 'r', 'a', 't', 'e', 'M', 'e', 't', 'r', 'i', 'c', '\0',
+ /* 572 - "testNested.rateWithExternalDenominator" */ 't', 'e', 's', 't', 'N', 'e', 's', 't', 'e', 'd', '.', 'r', 'a', 't', 'e', 'W', 'i', 't', 'h', 'E', 'x', 't', 'e', 'r', 'n', 'a', 'l', 'D', 'e', 'n', 'o', 'm', 'i', 'n', 'a', 't', 'o', 'r', '\0',
+ /* 611 - "testNested.uuidMetric" */ 't', 'e', 's', 't', 'N', 'e', 's', 't', 'e', 'd', '.', 'u', 'u', 'i', 'd', 'M', 'e', 't', 'r', 'i', 'c', '\0',
+};
+
+
+static_assert(sizeof(gMetricStringTable) < 4294967296, "Metric string table is too large.");
+
+const metric_entry_t sMetricByNameLookupEntries[] = {
+ 6341068335467200838ull,
+ 3458764548180279480ull,
+ 1152921590506193384ull,
+ 576460756598390784ull,
+ 2882303787286921342ull,
+ 6917529092065591642ull,
+ 9799832883647480358ull,
+ 2305843026393563204ull,
+ 7493989848663982456ull,
+ 1152921513196781587ull,
+ 8070450609557340585ull,
+ 2305843030688530526ull,
+ 5188146822270419236ull,
+ 8646911366155731401ull,
+ 1729382269795172390ull,
+ 10952754396844261987ull,
+ 4035225309073637616ull,
+ 10376293640245871164ull,
+ 9223372127049089548ull,
+ 5764607578868810038ull,
+ 8070450605262373266ull,
+ 2882303791581888664ull,
+ 4611686065672028430ull,
+ 3458764552475246801ull
+};
+
+
+
+Maybe<uint32_t>
+MetricByNameLookup(const nsACString& aKey)
+{
+ static const uint8_t BASES[] = {
+ 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 1, 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, 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, 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, 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, 3, 0, 4, 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,
+ 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, 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, 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, 0, 0,
+ 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 6, 0, 12, 0, 0, 0, 0, 0, 0, 0,
+ 11, 0, 0, 0, 3, 0, 0, 3, 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, 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,
+ sMetricByNameLookupEntries);
+ return metric_result_check(aKey, entry);
+}
+
+
+/**
+ * Get a category's name from the string table.
+ */
+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.
+ */
+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
diff --git a/toolkit/components/glean/tests/pytest/metrics_test_output_js_h b/toolkit/components/glean/tests/pytest/metrics_test_output_js_h
new file mode 100644
index 0000000000..6ce9833732
--- /dev/null
+++ b/toolkit/components/glean/tests/pytest/metrics_test_output_js_h
@@ -0,0 +1,75 @@
+// -*- 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 <cstdint>
+
+#include "mozilla/AlreadyAddRefed.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/glean/bindings/GleanMetric.h"
+#include "nsStringFwd.h"
+
+class nsISupports;
+
+namespace mozilla::glean {
+
+// The category lookup table's entry type
+using category_entry_t = uint32_t;
+// The metric lookup table's entry type
+// This is a bitpacked type with 32 bits available to index into
+// the string table, 5 bits available to signify the metric type,
+// and the remaining 27 bits devoted to 2 "signal"
+// bits to signify important characteristics (metric's a labeled metric's
+// submetric, metric's been registered at runtime) and 25 bits
+// for built-in metric ids.
+// Gives room for 33554432 of each combination of
+// characteristics (which hopefully will prove to be enough).
+using metric_entry_t = uint64_t;
+
+already_AddRefed<GleanMetric> NewMetricFromId(uint32_t id, nsISupports* aParent);
+
+/**
+ * Create a submetric instance for a labeled metric of the provided type and id for the given label.
+ * Assigns or retrieves an id for the submetric from the SDK.
+ *
+ * @param aParentTypeId - The type of the parent labeled metric identified as a number generated during codegen.
+ * Only used to identify which X of LabeledX you are so that X can be created here.
+ * @param aParentMetricId - The metric id for the parent labeled metric.
+ * @param aLabel - The label for the submetric. Might not adhere to the SDK label format.
+ * @param aSubmetricId - an outparam which is assigned the submetric's SDK-generated submetric id.
+ * Used only by GIFFT.
+ */
+already_AddRefed<GleanMetric> NewSubMetricFromIds(uint32_t aParentTypeId, uint32_t aParentMetricId, const nsACString& aLabel, uint32_t* aSubmetricId, nsISupports* aParent);
+
+/**
+ * Get a category's name from the string table.
+ */
+const char* GetCategoryName(category_entry_t entry);
+
+/**
+ * Get a metric's identifier from the string table.
+ */
+const char* GetMetricIdentifier(metric_entry_t entry);
+
+/**
+ * Get a metric's id given its name.
+ */
+Maybe<uint32_t> MetricByNameLookup(const nsACString&);
+
+/**
+ * Get a category's id given its name.
+ */
+Maybe<uint32_t> CategoryByNameLookup(const nsACString&);
+
+extern const category_entry_t sCategoryByNameLookupEntries[2];
+extern const metric_entry_t sMetricByNameLookupEntries[24];
+
+} // namespace mozilla::glean
+#endif // mozilla_GleanJSMetricsLookup_h
diff --git a/toolkit/components/glean/tests/pytest/pings_test.yaml b/toolkit/components/glean/tests/pytest/pings_test.yaml
new file mode 100644
index 0000000000..efa6ba9e0a
--- /dev/null
+++ b/toolkit/components/glean/tests/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/tests/pytest/pings_test_output b/toolkit/components/glean/tests/pytest/pings_test_output
new file mode 100644
index 0000000000..9e037eb22a
--- /dev/null
+++ b/toolkit/components/glean/tests/pytest/pings_test_output
@@ -0,0 +1,118 @@
+// -*- 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,
+ true,
+ vec!["background".into(), "dirty_startup".into(), "foreground".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,
+ true,
+ vec![],
+ )
+});
+
+#[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,
+ true,
+ vec!["background".into(), "max_capacity".into(), "startup".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,
+ true,
+ vec!["overdue".into(), "reschedule".into(), "today".into(), "tomorrow".into(), "upgrade".into()],
+ )
+});
+
+
+/// Instantiate custom pings once to trigger registration.
+///
+/// # Arguments
+///
+/// application_id: If present, limit to only registering custom pings
+/// assigned to the identified application.
+#[doc(hidden)]
+pub fn register_pings(application_id: Option<&str>) {
+ match application_id {
+ _ => {
+ let _ = &*not_baseline;
+ let _ = &*not_deletion_request;
+ let _ = &*not_events;
+ let _ = &*not_metrics;
+ }
+ }
+}
+
+#[cfg(feature = "with_gecko")]
+pub(crate) fn submit_ping_by_id(id: u32, reason: Option<&str>) {
+ if id & (1 << crate::factory::DYNAMIC_PING_BIT) > 0 {
+ let map = crate::factory::__jog_metric_maps::PING_MAP
+ .read()
+ .expect("Read lock for dynamic ping map was poisoned!");
+ if let Some(ping) = map.get(&id) {
+ ping.submit(reason);
+ } else {
+ // TODO: instrument this error.
+ log::error!("Cannot submit unknown dynamic ping {} by id.", id);
+ }
+ return;
+ }
+ match id {
+ 1 => not_baseline.submit(reason),
+ 2 => not_deletion_request.submit(reason),
+ 3 => not_events.submit(reason),
+ 4 => not_metrics.submit(reason),
+ _ => {
+ // TODO: instrument this error.
+ log::error!("Cannot submit unknown ping {} by id.", id);
+ }
+ }
+}
diff --git a/toolkit/components/glean/tests/pytest/pings_test_output_cpp b/toolkit/components/glean/tests/pytest/pings_test_output_cpp
new file mode 100644
index 0000000000..289529b118
--- /dev/null
+++ b/toolkit/components/glean/tests/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-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(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-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(4);
+
+
+} // namespace mozilla::glean_pings
+
+#endif // mozilla_glean_Pings_h
diff --git a/toolkit/components/glean/tests/pytest/pings_test_output_js_cpp b/toolkit/components/glean/tests/pytest/pings_test_output_js_cpp
new file mode 100644
index 0000000000..139eb29148
--- /dev/null
+++ b/toolkit/components/glean/tests/pytest/pings_test_output_js_cpp
@@ -0,0 +1,162 @@
+// -*- 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/. */
+
+#include "mozilla/glean/bindings/GleanJSPingsLookup.h"
+
+#include "mozilla/PerfectHash.h"
+#include "nsString.h"
+
+#include "mozilla/PerfectHash.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;
+
+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 - "notDeletionRequest" */ 'n', 'o', 't', 'D', 'e', 'l', 'e', 't', 'i', 'o', 'n', 'R', 'e', 'q', 'u', 'e', 's', 't', '\0',
+ /* 31 - "notEvents" */ 'n', 'o', 't', 'E', 'v', 'e', 'n', 't', 's', '\0',
+ /* 41 - "notMetrics" */ 'n', 'o', 't', 'M', 'e', 't', 'r', 'i', 'c', 's', '\0',
+};
+
+
+
+const ping_entry_t sPingByNameLookupEntries[] = {
+ 65536,
+ 131084,
+ 196639,
+ 262185
+};
+
+
+
+Maybe<uint32_t>
+PingByNameLookup(const nsACString& aKey)
+{
+ static const uint8_t BASES[] = {
+ 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, 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, 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, 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, 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, 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, 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, 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, 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,
+ 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, 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, 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, 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, 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, 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, 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, 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,
+ 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, 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, 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, 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,
+ 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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,
+ sPingByNameLookupEntries);
+ return ping_result_check(aKey, entry);
+}
+
+
+/**
+ * Get a ping's name given its entry from the PHF.
+ */
+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.
+ */
+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
diff --git a/toolkit/components/glean/tests/pytest/pings_test_output_js_h b/toolkit/components/glean/tests/pytest/pings_test_output_js_h
new file mode 100644
index 0000000000..0c89de93ae
--- /dev/null
+++ b/toolkit/components/glean/tests/pytest/pings_test_output_js_h
@@ -0,0 +1,33 @@
+// -*- 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
+
+#include <cstdint>
+#include "mozilla/Maybe.h"
+#include "nsStringFwd.h"
+
+namespace mozilla::glean {
+
+// Contains the ping id and the index into the ping string table.
+using ping_entry_t = uint32_t;
+
+/**
+ * Get a ping's name given its entry in the PHF.
+ */
+const char* GetPingName(ping_entry_t aEntry);
+
+/**
+ * Get a ping's id given its name.
+ */
+Maybe<uint32_t> PingByNameLookup(const nsACString&);
+
+extern const ping_entry_t sPingByNameLookupEntries[4];
+} // namespace mozilla::glean
+#endif // mozilla_GleanJSPingsLookup_h
diff --git a/toolkit/components/glean/tests/pytest/python.toml b/toolkit/components/glean/tests/pytest/python.toml
new file mode 100644
index 0000000000..86c0f55cfa
--- /dev/null
+++ b/toolkit/components/glean/tests/pytest/python.toml
@@ -0,0 +1,16 @@
+[DEFAULT]
+subsuite = "fog"
+
+["test_gifft.py"]
+
+["test_glean_parser_cpp.py"]
+
+["test_glean_parser_js.py"]
+
+["test_glean_parser_rust.py"]
+
+["test_jogfile_output.py"]
+
+["test_no_expired_metrics.py"]
+
+["test_yaml_indices.py"]
diff --git a/toolkit/components/glean/tests/pytest/test_gifft.py b/toolkit/components/glean/tests/pytest/test_gifft.py
new file mode 100644
index 0000000000..5de0640bca
--- /dev/null
+++ b/toolkit/components/glean/tests/pytest/test_gifft.py
@@ -0,0 +1,49 @@
+# 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 sys
+from os import path
+from pathlib import Path
+
+import mozunit
+from expect_helper import expect
+
+# Shenanigans to import the FOG glean_parser runner
+FOG_ROOT_PATH = path.abspath(
+ path.join(path.dirname(__file__), path.pardir, path.pardir)
+)
+sys.path.append(path.join(FOG_ROOT_PATH, "build_scripts", "glean_parser_ext"))
+import run_glean_parser
+
+
+def test_gifft_codegen():
+ """
+ A regression test. Very fragile.
+ It generates C++ for GIFFT for metrics_test.yaml and compares it
+ byte-for-byte with expected output C++ files.
+ To generate new expected output files, set `UPDATE_EXPECT=1` when running the test suite:
+
+ UPDATE_EXPECT=1 mach test toolkit/components/glean/pytest
+ """
+
+ options = {"allow_reserved": False}
+ here_path = Path(path.dirname(__file__))
+ input_files = [here_path / "metrics_test.yaml"]
+
+ all_objs, options = run_glean_parser.parse_with_options(input_files, options)
+
+ for probe_type in ("Event", "Histogram", "Scalar"):
+ output_fd = io.StringIO()
+ cpp_fd = io.StringIO()
+ run_glean_parser.output_gifft_map(output_fd, probe_type, all_objs, cpp_fd)
+
+ expect(here_path / f"gifft_output_{probe_type}", output_fd.getvalue())
+
+ if probe_type == "Event":
+ expect(here_path / "gifft_output_EventExtra", cpp_fd.getvalue())
+
+
+if __name__ == "__main__":
+ mozunit.main()
diff --git a/toolkit/components/glean/tests/pytest/test_glean_parser_cpp.py b/toolkit/components/glean/tests/pytest/test_glean_parser_cpp.py
new file mode 100644
index 0000000000..05fd691782
--- /dev/null
+++ b/toolkit/components/glean/tests/pytest/test_glean_parser_cpp.py
@@ -0,0 +1,70 @@
+# 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 sys
+from os import path
+from pathlib import Path
+
+import mozunit
+from expect_helper import expect
+
+# Shenanigans to import the cpp outputter extension
+FOG_ROOT_PATH = path.abspath(
+ path.join(path.dirname(__file__), path.pardir, path.pardir)
+)
+sys.path.append(path.join(FOG_ROOT_PATH, "build_scripts", "glean_parser_ext"))
+import cpp
+import run_glean_parser
+
+
+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 new expected output files, set `UPDATE_EXPECT=1` when running the test suite:
+
+ UPDATE_EXPECT=1 mach test toolkit/components/glean/pytest
+ """
+
+ options = {"allow_reserved": False}
+ input_files = [Path(path.join(path.dirname(__file__), "metrics_test.yaml"))]
+
+ all_objs, options = run_glean_parser.parse_with_options(input_files, options)
+
+ output_fd = io.StringIO()
+ cpp.output_cpp(all_objs, output_fd, options)
+
+ expect(
+ path.join(path.dirname(__file__), "metrics_test_output_cpp"),
+ output_fd.getvalue(),
+ )
+
+
+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 new expected output files, set `UPDATE_EXPECT=1` when running the test suite:
+
+ UPDATE_EXPECT=1 mach test toolkit/components/glean/pytest
+ """
+
+ options = {"allow_reserved": False}
+ input_files = [Path(path.join(path.dirname(__file__), "pings_test.yaml"))]
+
+ all_objs, options = run_glean_parser.parse_with_options(input_files, options)
+
+ output_fd = io.StringIO()
+ cpp.output_cpp(all_objs, output_fd, options)
+
+ expect(
+ path.join(path.dirname(__file__), "pings_test_output_cpp"), output_fd.getvalue()
+ )
+
+
+if __name__ == "__main__":
+ mozunit.main()
diff --git a/toolkit/components/glean/tests/pytest/test_glean_parser_js.py b/toolkit/components/glean/tests/pytest/test_glean_parser_js.py
new file mode 100644
index 0000000000..3f4a37e797
--- /dev/null
+++ b/toolkit/components/glean/tests/pytest/test_glean_parser_js.py
@@ -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/.
+
+import io
+import sys
+from os import path
+from pathlib import Path
+
+import mozunit
+from expect_helper import expect
+
+# Shenanigans to import the js outputter extension
+FOG_ROOT_PATH = path.abspath(
+ path.join(path.dirname(__file__), path.pardir, path.pardir)
+)
+sys.path.append(path.join(FOG_ROOT_PATH, "build_scripts", "glean_parser_ext"))
+import run_glean_parser
+
+import js
+
+
+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 new expected output files, set `UPDATE_EXPECT=1` when running the test suite:
+
+ UPDATE_EXPECT=1 mach test toolkit/components/glean/tests/pytest
+ """
+
+ options = {"allow_reserved": False}
+ input_files = [Path(path.join(path.dirname(__file__), "metrics_test.yaml"))]
+
+ all_objs, options = run_glean_parser.parse_with_options(input_files, options)
+
+ output_fd_h = io.StringIO()
+ output_fd_cpp = io.StringIO()
+ js.output_js(all_objs, output_fd_h, output_fd_cpp, options)
+
+ expect(
+ path.join(path.dirname(__file__), "metrics_test_output_js_h"),
+ output_fd_h.getvalue(),
+ )
+
+ expect(
+ path.join(path.dirname(__file__), "metrics_test_output_js_cpp"),
+ output_fd_cpp.getvalue(),
+ )
+
+
+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 new expected output files, set `UPDATE_EXPECT=1` when running the test suite:
+
+ UPDATE_EXPECT=1 mach test toolkit/components/glean/tests/pytest
+ """
+
+ options = {"allow_reserved": False}
+ input_files = [Path(path.join(path.dirname(__file__), "pings_test.yaml"))]
+
+ all_objs, options = run_glean_parser.parse_with_options(input_files, options)
+
+ output_fd_h = io.StringIO()
+ output_fd_cpp = io.StringIO()
+ js.output_js(all_objs, output_fd_h, output_fd_cpp, options)
+
+ expect(
+ path.join(path.dirname(__file__), "pings_test_output_js_h"),
+ output_fd_h.getvalue(),
+ )
+
+ expect(
+ path.join(path.dirname(__file__), "pings_test_output_js_cpp"),
+ output_fd_cpp.getvalue(),
+ )
+
+
+if __name__ == "__main__":
+ mozunit.main()
diff --git a/toolkit/components/glean/tests/pytest/test_glean_parser_rust.py b/toolkit/components/glean/tests/pytest/test_glean_parser_rust.py
new file mode 100644
index 0000000000..329c7ed348
--- /dev/null
+++ b/toolkit/components/glean/tests/pytest/test_glean_parser_rust.py
@@ -0,0 +1,89 @@
+# 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 sys
+from os import path
+from pathlib import Path
+
+import mozunit
+from expect_helper import expect
+
+# Shenanigans to import the rust outputter extension
+FOG_ROOT_PATH = path.abspath(
+ path.join(path.dirname(__file__), path.pardir, 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"))
+
+
+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 new expected output files, set `UPDATE_EXPECT=1` when running the test suite:
+
+ UPDATE_EXPECT=1 mach test toolkit/components/glean/pytest
+ """
+
+ options = {"allow_reserved": False}
+ input_files = [Path(path.join(path.dirname(__file__), "metrics_test.yaml"))]
+
+ all_objs, options = run_glean_parser.parse_with_options(input_files, options)
+
+ output_fd = io.StringIO()
+ rust.output_rust(all_objs, output_fd, {}, options)
+
+ expect(
+ path.join(path.dirname(__file__), "metrics_test_output"), output_fd.getvalue()
+ )
+
+
+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 new expected output files, set `UPDATE_EXPECT=1` when running the test suite:
+
+ UPDATE_EXPECT=1 mach test toolkit/components/glean/pytest
+ """
+
+ options = {"allow_reserved": False}
+ input_files = [Path(path.join(path.dirname(__file__), "pings_test.yaml"))]
+
+ all_objs, options = run_glean_parser.parse_with_options(input_files, options)
+
+ output_fd = io.StringIO()
+ rust.output_rust(all_objs, output_fd, {}, options)
+
+ expect(path.join(path.dirname(__file__), "pings_test_output"), output_fd.getvalue())
+
+
+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, options = run_glean_parser.parse_with_options(input_files, options)
+
+ assert all_objs["test"]["expired1"].disabled is True
+ assert all_objs["test"]["expired2"].disabled is True
+ assert all_objs["test"]["unexpired"].disabled is False
+
+
+if __name__ == "__main__":
+ mozunit.main()
diff --git a/toolkit/components/glean/tests/pytest/test_jogfile_output.py b/toolkit/components/glean/tests/pytest/test_jogfile_output.py
new file mode 100644
index 0000000000..801c0967ff
--- /dev/null
+++ b/toolkit/components/glean/tests/pytest/test_jogfile_output.py
@@ -0,0 +1,50 @@
+# 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 sys
+from os import path
+from pathlib import Path
+
+import mozunit
+from expect_helper import expect
+
+# Shenanigans to import the FOG glean_parser runner
+FOG_ROOT_PATH = path.abspath(
+ path.join(path.dirname(__file__), path.pardir, path.pardir)
+)
+sys.path.append(path.join(FOG_ROOT_PATH, "build_scripts", "glean_parser_ext"))
+import jog
+import run_glean_parser
+
+
+def test_jogfile_output():
+ """
+ A regression test. Very fragile.
+ It generates a jogfile for metrics_test.yaml and compares it
+ byte-for-byte with an expected output file.
+
+ Also, part one of a two-part test.
+ The generated jogfile is consumed in Rust_TestJogfile in t/c/g/tests/gtest/test.rs
+ This is to ensure that the jogfile we generate in Python can be consumed in Rust.
+
+ To generate new expected output files, set `UPDATE_EXPECT=1` when running the test suite:
+
+ UPDATE_EXPECT=1 mach test toolkit/components/glean/pytest
+ """
+
+ options = {"allow_reserved": False}
+ here_path = Path(path.dirname(__file__))
+ input_files = [here_path / "metrics_test.yaml", here_path / "pings_test.yaml"]
+
+ all_objs, options = run_glean_parser.parse_with_options(input_files, options)
+
+ output_fd = io.StringIO()
+ jog.output_file(all_objs, output_fd, options)
+
+ expect(here_path / "jogfile_output", output_fd.getvalue())
+
+
+if __name__ == "__main__":
+ mozunit.main()
diff --git a/toolkit/components/glean/tests/pytest/test_no_expired_metrics.py b/toolkit/components/glean/tests/pytest/test_no_expired_metrics.py
new file mode 100644
index 0000000000..9783acaf0a
--- /dev/null
+++ b/toolkit/components/glean/tests/pytest/test_no_expired_metrics.py
@@ -0,0 +1,46 @@
+# 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 sys
+from os import path
+from pathlib import Path
+
+import mozunit
+
+# Shenanigans to import the metrics index's list of metrics.yamls
+FOG_ROOT_PATH = path.abspath(
+ path.join(path.dirname(__file__), path.pardir, path.pardir)
+)
+sys.path.append(FOG_ROOT_PATH)
+from metrics_index import metrics_yamls, tags_yamls
+
+# Shenanigans to import run_glean_parser
+sys.path.append(path.join(FOG_ROOT_PATH, "build_scripts", "glean_parser_ext"))
+import run_glean_parser
+
+# 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_no_metrics_expired():
+ """
+ Of all the metrics included in this build, are any expired?
+ If so, they must be removed or renewed.
+
+ (This also checks other lints, as a treat.)
+ """
+ with open("browser/config/version.txt", "r") as version_file:
+ app_version = version_file.read().strip()
+
+ options = run_glean_parser.get_parser_options(app_version)
+ paths = [Path(x) for x in metrics_yamls] + [Path(x) for x in tags_yamls]
+ all_objs = parser.parse_objects(paths, options)
+ assert not util.report_validation_errors(all_objs)
+ assert not lint.lint_metrics(all_objs.value, options)
+
+
+if __name__ == "__main__":
+ mozunit.main()
diff --git a/toolkit/components/glean/tests/pytest/test_yaml_indices.py b/toolkit/components/glean/tests/pytest/test_yaml_indices.py
new file mode 100644
index 0000000000..9ccde409e5
--- /dev/null
+++ b/toolkit/components/glean/tests/pytest/test_yaml_indices.py
@@ -0,0 +1,42 @@
+# 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 sys
+from os import path
+
+import mozunit
+
+# Shenanigans to import the metrics index's lists of yamls
+FOG_ROOT_PATH = path.abspath(
+ path.join(path.dirname(__file__), path.pardir, path.pardir)
+)
+sys.path.append(FOG_ROOT_PATH)
+import metrics_index
+
+
+def test_yamls_sorted():
+ """
+ Ensure the yamls indices are sorted lexicographically.
+ """
+ # Ignore lists that are the concatenation of others.
+ to_ignore = ["metrics_yamls", "pings_yamls"]
+
+ # Fetch names of all variables defined in the `metrics_index` module.
+ yaml_lists = [
+ item
+ for item in dir(metrics_index)
+ if isinstance(getattr(metrics_index, item), list) and not item.startswith("__")
+ ]
+ for name in yaml_lists:
+ if name in to_ignore:
+ continue
+
+ yamls_to_test = metrics_index.__dict__[name]
+ assert (
+ sorted(yamls_to_test) == yamls_to_test
+ ), f"{name} must be be lexicographically sorted."
+
+
+if __name__ == "__main__":
+ mozunit.main()