diff options
Diffstat (limited to 'toolkit/components/glean/tests/pytest')
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() |