summaryrefslogtreecommitdiffstats
path: root/toolkit/components/glean/gtest
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /toolkit/components/glean/gtest
parentInitial commit. (diff)
downloadfirefox-upstream.tar.xz
firefox-upstream.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/components/glean/gtest')
-rw-r--r--toolkit/components/glean/gtest/Cargo.toml12
-rw-r--r--toolkit/components/glean/gtest/TestFog.cpp220
-rw-r--r--toolkit/components/glean/gtest/TestFogIPC.cpp47
-rw-r--r--toolkit/components/glean/gtest/moz.build13
-rw-r--r--toolkit/components/glean/gtest/test.rs44
5 files changed, 336 insertions, 0 deletions
diff --git a/toolkit/components/glean/gtest/Cargo.toml b/toolkit/components/glean/gtest/Cargo.toml
new file mode 100644
index 0000000000..83bfd3d244
--- /dev/null
+++ b/toolkit/components/glean/gtest/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "fog-gtest"
+version = "0.1.0"
+authors = ["glean-team@mozilla.com"]
+license = "MPL-2.0"
+description = "Tests for the FOG crate"
+
+[dependencies]
+fog = { path = "../api" }
+
+[lib]
+path = "test.rs"
diff --git a/toolkit/components/glean/gtest/TestFog.cpp b/toolkit/components/glean/gtest/TestFog.cpp
new file mode 100644
index 0000000000..16add5b973
--- /dev/null
+++ b/toolkit/components/glean/gtest/TestFog.cpp
@@ -0,0 +1,220 @@
+/* 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 "gtest/gtest.h"
+#include "mozilla/glean/GleanMetrics.h"
+#include "mozilla/glean/GleanPings.h"
+#include "mozilla/glean/fog_ffi_generated.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/Tuple.h"
+#include "nsTArray.h"
+
+#include "mozilla/Preferences.h"
+#include "mozilla/Unused.h"
+#include "nsString.h"
+#include "prtime.h"
+
+using mozilla::Preferences;
+using namespace mozilla::glean;
+using namespace mozilla::glean::impl;
+
+#define DATA_PREF "datareporting.healthreport.uploadEnabled"
+
+extern "C" {
+// This function is called by the rust code in test.rs if a non-fatal test
+// failure occurs.
+void GTest_FOG_ExpectFailure(const char* aMessage) {
+ EXPECT_STREQ(aMessage, "");
+}
+}
+
+// Initialize FOG exactly once.
+// This needs to be the first test to run!
+TEST(FOG, FogInitDoesntCrash)
+{
+ Preferences::SetInt("telemetry.fog.test.localhost_port", -1);
+ ASSERT_EQ(NS_OK, fog_init());
+ // Fog init isn't actually done (it passes work to a background thread)
+ Preferences::SetBool(DATA_PREF, false);
+ Preferences::SetBool(DATA_PREF, true);
+}
+
+// TODO: to be enabled after changes from bug 1677455 are vendored.
+// extern "C" void Rust_MeasureInitializeTime();
+// TEST(FOG, TestMeasureInitializeTime)
+// { Rust_MeasureInitializeTime(); }
+
+TEST(FOG, BuiltinPingsRegistered)
+{
+ Preferences::SetInt("telemetry.fog.test.localhost_port", -1);
+ nsAutoCString metricsPingName("metrics");
+ nsAutoCString baselinePingName("baseline");
+ nsAutoCString eventsPingName("events");
+ ASSERT_EQ(NS_OK, fog_submit_ping(&metricsPingName));
+ ASSERT_EQ(NS_OK, fog_submit_ping(&baselinePingName));
+ ASSERT_EQ(NS_OK, fog_submit_ping(&eventsPingName));
+}
+
+TEST(FOG, TestCppCounterWorks)
+{
+ mozilla::glean::test_only::bad_code.Add(42);
+
+ ASSERT_EQ(
+ 42,
+ mozilla::glean::test_only::bad_code.TestGetValue("test-ping"_ns).value());
+ // And test that the ping name's optional, while you're at it:
+ ASSERT_EQ(42, test_only::bad_code.TestGetValue().value());
+}
+
+TEST(FOG, TestCppStringWorks)
+{
+ auto kValue = "cheez!"_ns;
+ mozilla::glean::test_only::cheesy_string.Set(kValue);
+
+ ASSERT_STREQ(kValue.get(), mozilla::glean::test_only::cheesy_string
+ .TestGetValue("test-ping"_ns)
+ .value()
+ .get());
+}
+
+TEST(FOG, TestCppTimespanWorks)
+{
+ mozilla::glean::test_only::can_we_time_it.Start();
+ PR_Sleep(PR_MillisecondsToInterval(10));
+ mozilla::glean::test_only::can_we_time_it.Stop();
+
+ ASSERT_TRUE(
+ mozilla::glean::test_only::can_we_time_it.TestGetValue("test-ping"_ns)
+ .value() > 0);
+}
+
+TEST(FOG, TestCppUuidWorks)
+{
+ nsCString kTestUuid("decafdec-afde-cafd-ecaf-decafdecafde");
+ test_only::what_id_it.Set(kTestUuid);
+ ASSERT_STREQ(
+ kTestUuid.get(),
+ test_only::what_id_it.TestGetValue("test-ping"_ns).value().get());
+
+ test_only::what_id_it.GenerateAndSet();
+ // Since we generate v4 UUIDs, and the first character of the third group
+ // isn't 4, this won't ever collide with kTestUuid.
+ ASSERT_STRNE(
+ kTestUuid.get(),
+ test_only::what_id_it.TestGetValue("test-ping"_ns).value().get());
+}
+
+TEST(FOG, TestCppBooleanWorks)
+{
+ mozilla::glean::test_only::can_we_flag_it.Set(false);
+
+ ASSERT_EQ(false, mozilla::glean::test_only::can_we_flag_it
+ .TestGetValue("test-ping"_ns)
+ .value());
+}
+
+// TODO: to be enabled after changes from bug 1677448 are vendored.
+// TEST(FOG, TestCppDatetimeWorks)
+// {
+// PRExplodedTime date = {0, 35, 10, 12, 6, 10, 2020, 0, 0, {5 * 60 * 60, 0}};
+// test_only::what_a_date.Set(&date);
+//
+// auto received = test_only::what_a_date.TestGetValue("test-ping");
+// ASSERT_STREQ(received.value().get(), "2020-11-06T12:10:35+05:00");
+// }
+
+using mozilla::MakeTuple;
+using mozilla::Tuple;
+using mozilla::glean::test_only_ipc::AnEventKeys;
+
+TEST(FOG, TestCppEventWorks)
+{
+ test_only_ipc::no_extra_event.Record();
+ ASSERT_TRUE(test_only_ipc::no_extra_event.TestGetValue("store1"_ns).isSome());
+
+ // Ugh, this API...
+ nsTArray<Tuple<test_only_ipc::AnEventKeys, nsCString>> extra;
+ nsCString val = "can set extras"_ns;
+ extra.AppendElement(MakeTuple(AnEventKeys::Extra1, val));
+
+ test_only_ipc::an_event.Record(std::move(extra));
+ ASSERT_TRUE(test_only_ipc::an_event.TestGetValue("store1"_ns).isSome());
+}
+
+TEST(FOG, TestCppMemoryDistWorks)
+{
+ test_only::do_you_remember.Accumulate(7);
+ test_only::do_you_remember.Accumulate(17);
+
+ DistributionData data =
+ test_only::do_you_remember.TestGetValue("test-ping"_ns).ref();
+ // Sum is in bytes, test_only::do_you_remember is in megabytes. So
+ // multiplication ahoy!
+ ASSERT_EQ(data.sum, 24UL * 1024 * 1024);
+ for (auto iter = data.values.Iter(); !iter.Done(); iter.Next()) {
+ const uint64_t bucket = iter.Key();
+ const uint64_t count = iter.UserData();
+ ASSERT_TRUE(count == 0 ||
+ (count == 1 && (bucket == 17520006 || bucket == 7053950)))
+ << "Only two occupied buckets";
+ }
+}
+
+TEST(FOG, TestCppPings)
+{
+ auto ping = mozilla::glean_pings::OnePingOnly;
+ mozilla::Unused << ping;
+ // That's it. That's the test. It will fail to compile if it's missing.
+ // For a test that actually submits the ping, we have integration tests.
+ // See also bug 1681742.
+}
+
+TEST(FOG, TestCppStringLists)
+{
+ auto kValue = "cheez!"_ns;
+ auto kValue2 = "cheezier!"_ns;
+ auto kValue3 = "cheeziest."_ns;
+
+ nsTArray<nsCString> cheezList;
+ cheezList.EmplaceBack(kValue);
+ cheezList.EmplaceBack(kValue2);
+
+ test_only::cheesy_string_list.Set(cheezList);
+
+ auto val = test_only::cheesy_string_list.TestGetValue().value();
+ // Note: This is fragile if the order is ever not preserved.
+ ASSERT_STREQ(kValue.get(), val[0].get());
+ ASSERT_STREQ(kValue2.get(), val[1].get());
+
+ test_only::cheesy_string_list.Add(kValue3);
+
+ val = test_only::cheesy_string_list.TestGetValue().value();
+ ASSERT_STREQ(kValue3.get(), val[2].get());
+}
+
+TEST(FOG, TestCppTimingDistWorks)
+{
+ auto id1 = test_only::what_time_is_it.Start();
+ auto id2 = test_only::what_time_is_it.Start();
+ PR_Sleep(PR_MillisecondsToInterval(5));
+ auto id3 = test_only::what_time_is_it.Start();
+ test_only::what_time_is_it.Cancel(std::move(id1));
+ PR_Sleep(PR_MillisecondsToInterval(5));
+ test_only::what_time_is_it.StopAndAccumulate(std::move(id2));
+ test_only::what_time_is_it.StopAndAccumulate(std::move(id3));
+
+ DistributionData data = test_only::what_time_is_it.TestGetValue().ref();
+ const uint64_t NANOS_IN_MILLIS = 1e6;
+
+ // We don't know exactly how long those sleeps took, only that it was at
+ // least 15ms total.
+ ASSERT_GT(data.sum, (uint64_t)(15 * NANOS_IN_MILLIS));
+
+ // We also can't guarantee the buckets, but we can guarantee two samples.
+ uint64_t sampleCount = 0;
+ for (auto iter = data.values.Iter(); !iter.Done(); iter.Next()) {
+ sampleCount += iter.UserData();
+ }
+ ASSERT_EQ(sampleCount, (uint64_t)2);
+}
diff --git a/toolkit/components/glean/gtest/TestFogIPC.cpp b/toolkit/components/glean/gtest/TestFogIPC.cpp
new file mode 100644
index 0000000000..f0ac9c85ac
--- /dev/null
+++ b/toolkit/components/glean/gtest/TestFogIPC.cpp
@@ -0,0 +1,47 @@
+/* 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 "gtest/gtest.h"
+
+// NOTE: No ContentChild/Parent tests because it includes headers that aren't
+// present in GTest builds (or something).
+
+#include "mozilla/FOGIPC.h"
+#include <functional>
+#include "mozilla/ipc/ByteBuf.h"
+#include "nsTArray.h"
+#include "nsXULAppAPI.h"
+
+using mozilla::ipc::ByteBuf;
+
+TEST(FOG, TestFlushFOGData)
+{
+ // A "It doesn't explode" test.
+ std::function<void(ByteBuf &&)> resolver = [](ByteBuf&& bufs) {};
+ mozilla::glean::FlushFOGData(std::move(resolver));
+}
+
+TEST(FOG, TestFlushAllChildData)
+{
+ std::function<void(const nsTArray<ByteBuf>&&)> resolver =
+ [](const nsTArray<ByteBuf>&& bufs) {
+ ASSERT_TRUE(bufs.Length() == 0)
+ << "Not expecting any bufs yet.";
+ };
+ mozilla::glean::FlushAllChildData(std::move(resolver));
+}
+
+TEST(FOG, FOGData)
+{
+ // Another "It doesn't explode" test.
+ ByteBuf buf;
+ mozilla::glean::FOGData(std::move(buf));
+}
+
+TEST(FOG, SendFOGData)
+{
+ ASSERT_EQ(XRE_GetProcessType(), GeckoProcessType_Default)
+ << "If we can run a test as a different process type, we can write a "
+ "test for this function.";
+}
diff --git a/toolkit/components/glean/gtest/moz.build b/toolkit/components/glean/gtest/moz.build
new file mode 100644
index 0000000000..f70313c7d0
--- /dev/null
+++ b/toolkit/components/glean/gtest/moz.build
@@ -0,0 +1,13 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+if CONFIG["MOZ_GLEAN"]:
+ UNIFIED_SOURCES += [
+ "TestFog.cpp",
+ "TestFogIPC.cpp",
+ ]
+
+FINAL_LIBRARY = "xul-gtest"
diff --git a/toolkit/components/glean/gtest/test.rs b/toolkit/components/glean/gtest/test.rs
new file mode 100644
index 0000000000..27af068734
--- /dev/null
+++ b/toolkit/components/glean/gtest/test.rs
@@ -0,0 +1,44 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+fn nonfatal_fail(msg: String) {
+ extern "C" {
+ fn GTest_FOG_ExpectFailure(message: *const ::std::os::raw::c_char);
+ }
+ unsafe {
+ let msg = ::std::ffi::CString::new(msg).unwrap();
+ GTest_FOG_ExpectFailure(msg.as_ptr());
+ }
+}
+
+/// This macro checks if the expression evaluates to true,
+/// and causes a non-fatal GTest test failure if it doesn't.
+macro_rules! expect {
+ ($x:expr) => {
+ match (&$x) {
+ true => {}
+ false => nonfatal_fail(format!(
+ "check failed: (`{}`) at {}:{}",
+ stringify!($x),
+ file!(),
+ line!()
+ )),
+ }
+ };
+}
+
+#[no_mangle]
+pub extern "C" fn Rust_MeasureInitializeTime() {
+ // At this point FOG is already initialized.
+ // We still need for it to finish, as it is running in a separate thread.
+
+ let metric = &*fog::metrics::fog::initialization;
+ while metric.test_get_value("metrics").is_none() {
+ // We _know_ this value is recorded early, so let's just yield
+ // and try again quickly.
+ std::thread::yield_now();
+ }
+
+ let value = metric.test_get_value("metrics").unwrap();
+ expect!(value > 0);
+}