/* 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> 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 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); }