diff --git a/toolkit/components/glean/bindings/private/Event.h b/toolkit/components/glean/bindings/private/Event.h index 72fd70410c3d..bf890e4c143f 100644 --- a/toolkit/components/glean/bindings/private/Event.h +++ b/toolkit/components/glean/bindings/private/Event.h @@ -63,17 +63,22 @@ class EventMetric { // twice the required allocation. We could be smarter and reuse the data. // But this is GIFFT-only allocation, so wait to be told it's a problem. Maybe> telExtras; + Maybe telValue; if (aExtras) { CopyableTArray extras; auto serializedExtras = aExtras->ToFfiExtra(); auto keys = std::move(std::get<0>(serializedExtras)); auto values = std::move(std::get<1>(serializedExtras)); for (size_t i = 0; i < keys.Length(); i++) { + if (keys[i].EqualsLiteral("value")) { + telValue = Some(values[i]); + continue; + } extras.EmplaceBack(Telemetry::EventExtraEntry{keys[i], values[i]}); } telExtras = Some(extras); } - Telemetry::RecordEvent(id.extract(), Nothing(), telExtras); + Telemetry::RecordEvent(id.extract(), telValue, telExtras); } if (aExtras) { auto extra = aExtras->ToFfiExtra(); diff --git a/toolkit/components/telemetry/tests/gtest/TestEvents.cpp b/toolkit/components/telemetry/tests/gtest/TestEvents.cpp index be08f234a99c..fb719a2803a5 100644 --- a/toolkit/components/telemetry/tests/gtest/TestEvents.cpp +++ b/toolkit/components/telemetry/tests/gtest/TestEvents.cpp @@ -10,6 +10,8 @@ #include "mozilla/Maybe.h" #include "mozilla/Telemetry.h" #include "mozilla/Unused.h" +#include "mozilla/glean/fog_ffi_generated.h" +#include "mozilla/glean/GleanMetrics.h" #include "TelemetryFixture.h" #include "TelemetryTestHelpers.h" @@ -113,3 +115,67 @@ TEST_F(TelemetryTestFixture, RecordEventNative) { ASSERT_EQ(NS_ConvertUTF16toUTF8(jsStr).Length(), (uint32_t)80) << "Extra must have been truncated to 80 bytes."; } + +using mozilla::Some; +using mozilla::glean::test_only_ipc::AnEventExtra; +// Test that we get a mirrored value from the C++ Glean API. +TEST_F(TelemetryTestFixture, GIFFTValue) { + // Reset FOG to clear the stores. + const nsCString empty; + mozilla::glean::impl::fog_test_reset(&empty, &empty); + + // Make sure we don't get events from other tests. + Unused << mTelemetry->ClearEvents(); + + // Enable recording of telemetry.test events. + const nsCString category("telemetry.test"); + const nsCString method("mirror_with_extra"); + const nsCString object("object1"); + Telemetry::SetEventRecordingEnabled(category, true); + + // Record in Glean. + // We include an extra extra key (extra1, here) to ensure there's always six + // items in the record array. + AnEventExtra extra = { + .extra1 = Some("a"_ns), + .value = Some("some value"_ns), + }; + mozilla::glean::test_only_ipc::an_event.Record(Some(extra)); + auto optEvents = + mozilla::glean::test_only_ipc::an_event.TestGetValue().unwrap(); + ASSERT_TRUE(optEvents.isSome()) + << "There are Glean events."; + auto events = optEvents.extract(); + ASSERT_EQ(1UL, events.Length()) << "There is exactly one Glean event."; + + // Assert in Telemetry. + AutoJSContextWithGlobal cx(mCleanGlobal); + JS::Rooted eventsSnapshot(cx.GetJSContext()); + GetEventSnapshot(cx.GetJSContext(), &eventsSnapshot); + + ASSERT_TRUE( + EventPresent(cx.GetJSContext(), eventsSnapshot, category, method, object)) + << "Test event must be present."; + + // Ensure that the `value` value was mapped appropriately. + JSContext* aCx = cx.GetJSContext(); + JS::Rooted arrayObj(aCx, &eventsSnapshot.toObject()); + JS::Rooted eventRecord(aCx); + ASSERT_TRUE(JS_GetElement(aCx, arrayObj, 0, &eventRecord)) + << "Must be able to get record."; + JS::Rooted recordArray(aCx, &eventRecord.toObject()); + uint32_t recordLength; + ASSERT_TRUE(JS::GetArrayLength(aCx, recordArray, &recordLength)) + << "Event record array must have length."; + ASSERT_EQ(6UL, recordLength) << "Event record array must have 6 elements."; + + JS::Rooted str(aCx); + nsAutoJSString jsStr; + // The value string is at index 4 + ASSERT_TRUE(JS_GetElement(aCx, recordArray, 4, &str)) + << "Must be able to get value."; + ASSERT_TRUE(jsStr.init(aCx, str)) + << "Value must be able to be init'd to a jsstring."; + ASSERT_STREQ(NS_ConvertUTF16toUTF8(jsStr).get(), "some value") + << "The value of the value must be 'some value'"; +}