Source code
Revision control
Copy as Markdown
Other Tools
/* vim:set ts=2 sw=2 sts=2 et: */
/* Any copyright is dedicated to the Public Domain.
*/
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "mozilla/gtest/MozAssertions.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "mozilla/Telemetry.h"
#include "nsIObserverService.h"
#include "nsThreadUtils.h"
#include "TelemetryFixture.h"
#include "TelemetryTestHelpers.h"
#include "streaming/GeckoViewStreamingTelemetry.h"
using namespace mozilla;
using namespace mozilla::Telemetry;
using namespace TelemetryTestHelpers;
using GeckoViewStreamingTelemetry::StreamingTelemetryDelegate;
using mozilla::Telemetry::ScalarID;
using ::testing::_;
using ::testing::Eq;
using ::testing::StrictMock;
namespace {
const char* kGeckoViewStreamingPref = "toolkit.telemetry.geckoview.streaming";
const char* kBatchTimeoutPref = "toolkit.telemetry.geckoview.batchDurationMS";
constexpr auto kTestHgramName = "TELEMETRY_TEST_STREAMING"_ns;
constexpr auto kTestHgramName2 = "TELEMETRY_TEST_STREAMING_2"_ns;
constexpr auto kTestCategoricalName = "TELEMETRY_TEST_CATEGORICAL_OPTOUT"_ns;
const HistogramID kTestHgram = Telemetry::TELEMETRY_TEST_STREAMING;
const HistogramID kTestHgram2 = Telemetry::TELEMETRY_TEST_STREAMING_2;
class TelemetryStreamingFixture : public TelemetryTestFixture {
protected:
virtual void SetUp() {
TelemetryTestFixture::SetUp();
Preferences::SetBool(kGeckoViewStreamingPref, true);
Preferences::SetInt(kBatchTimeoutPref, 5000);
}
virtual void TearDown() {
TelemetryTestFixture::TearDown();
Preferences::SetBool(kGeckoViewStreamingPref, false);
GeckoViewStreamingTelemetry::RegisterDelegate(nullptr);
}
};
class MockDelegate : public StreamingTelemetryDelegate {
public:
MOCK_METHOD2(ReceiveHistogramSamples,
void(const nsCString& aHistogramName,
const nsTArray<uint32_t>& aSamples));
MOCK_METHOD2(ReceiveCategoricalHistogramSamples,
void(const nsCString& aHistogramName,
const nsTArray<uint32_t>& aSamples));
MOCK_METHOD2(ReceiveBoolScalarValue,
void(const nsCString& aScalarName, bool aValue));
MOCK_METHOD2(ReceiveStringScalarValue,
void(const nsCString& aScalarName, const nsCString& aValue));
MOCK_METHOD2(ReceiveUintScalarValue,
void(const nsCString& aScalarName, uint32_t aValue));
}; // class MockDelegate
TEST_F(TelemetryStreamingFixture, HistogramSamples) {
const uint32_t kSampleOne = 401;
const uint32_t kSampleTwo = 2019;
CopyableTArray<uint32_t> samplesArray;
samplesArray.AppendElement(kSampleOne);
samplesArray.AppendElement(kSampleTwo);
auto md = MakeRefPtr<MockDelegate>();
EXPECT_CALL(*md, ReceiveHistogramSamples(Eq(kTestHgramName),
Eq(std::move(samplesArray))));
GeckoViewStreamingTelemetry::RegisterDelegate(md);
Telemetry::Accumulate(Telemetry::TELEMETRY_TEST_STREAMING, kSampleOne);
Preferences::SetInt(kBatchTimeoutPref, 0);
Telemetry::Accumulate(Telemetry::TELEMETRY_TEST_STREAMING, kSampleTwo);
}
TEST_F(TelemetryStreamingFixture, CategoricalHistogramSamples) {
auto kSampleOne =
Telemetry::LABELS_TELEMETRY_TEST_CATEGORICAL_OPTOUT::CommonLabel;
auto kSampleTwo = Telemetry::LABELS_TELEMETRY_TEST_CATEGORICAL_OPTOUT::Label5;
CopyableTArray<uint32_t> samplesArray;
samplesArray.AppendElement(static_cast<uint32_t>(kSampleOne));
samplesArray.AppendElement(static_cast<uint32_t>(kSampleOne));
samplesArray.AppendElement(static_cast<uint32_t>(kSampleTwo));
auto md = MakeRefPtr<MockDelegate>();
EXPECT_CALL(*md, ReceiveCategoricalHistogramSamples(
Eq(kTestCategoricalName), Eq(std::move(samplesArray))));
GeckoViewStreamingTelemetry::RegisterDelegate(md);
Telemetry::AccumulateCategorical(kSampleOne);
Telemetry::AccumulateCategorical(kSampleOne);
Preferences::SetInt(kBatchTimeoutPref, 0);
Telemetry::AccumulateCategorical(kSampleTwo);
}
TEST_F(TelemetryStreamingFixture, MultipleHistograms) {
const uint32_t kSample1 = 400;
const uint32_t kSample2 = 1 << 31;
const uint32_t kSample3 = 7;
CopyableTArray<uint32_t> samplesArray1;
samplesArray1.AppendElement(kSample1);
samplesArray1.AppendElement(kSample2);
CopyableTArray<uint32_t> samplesArray2;
samplesArray2.AppendElement(kSample3);
auto md = MakeRefPtr<MockDelegate>();
EXPECT_CALL(*md, ReceiveHistogramSamples(Eq(kTestHgramName),
Eq(std::move(samplesArray1))));
EXPECT_CALL(*md, ReceiveHistogramSamples(Eq(kTestHgramName2),
Eq(std::move(samplesArray2))));
GeckoViewStreamingTelemetry::RegisterDelegate(md);
Telemetry::Accumulate(kTestHgram, kSample1);
Telemetry::Accumulate(kTestHgram2, kSample3);
Preferences::SetInt(kBatchTimeoutPref, 0);
Telemetry::Accumulate(kTestHgram, kSample2);
}
// If we can find a way to convert the expectation's arg into an stl container,
// we can use gmock's own ::testing::UnorderedElementsAre() instead.
auto MatchUnordered(uint32_t sample1, uint32_t sample2) {
CopyableTArray<uint32_t> samplesArray1;
samplesArray1.AppendElement(sample1);
samplesArray1.AppendElement(sample2);
CopyableTArray<uint32_t> samplesArray2;
samplesArray2.AppendElement(sample2);
samplesArray2.AppendElement(sample1);
return ::testing::AnyOf(Eq(std::move(samplesArray1)),
Eq(std::move(samplesArray2)));
}
TEST_F(TelemetryStreamingFixture, MultipleThreads) {
const uint32_t kSample1 = 4;
const uint32_t kSample2 = 14;
auto md = MakeRefPtr<MockDelegate>();
// In this test, samples for the second test hgram are uninteresting.
EXPECT_CALL(*md, ReceiveHistogramSamples(Eq(kTestHgramName2), _));
EXPECT_CALL(*md, ReceiveHistogramSamples(Eq(kTestHgramName),
MatchUnordered(kSample1, kSample2)));
GeckoViewStreamingTelemetry::RegisterDelegate(md);
nsCOMPtr<nsIThread> t1;
nsCOMPtr<nsIThread> t2;
nsCOMPtr<nsIThread> t3;
nsCOMPtr<nsIRunnable> r1 = NS_NewRunnableFunction(
"accumulate 4", [&]() { Telemetry::Accumulate(kTestHgram, kSample1); });
nsCOMPtr<nsIRunnable> r2 = NS_NewRunnableFunction(
"accumulate 14", [&]() { Telemetry::Accumulate(kTestHgram, kSample2); });
nsresult rv = NS_NewNamedThread("t1", getter_AddRefs(t1), r1);
EXPECT_NS_SUCCEEDED(rv);
rv = NS_NewNamedThread("t2", getter_AddRefs(t2), r2);
EXPECT_NS_SUCCEEDED(rv);
// Give the threads a chance to do their work.
PR_Sleep(PR_MillisecondsToInterval(1));
Preferences::SetInt(kBatchTimeoutPref, 0);
Telemetry::Accumulate(kTestHgram2, kSample1);
}
TEST_F(TelemetryStreamingFixture, ScalarValues) {
constexpr auto kBoolScalarName = "telemetry.test.boolean_kind"_ns;
constexpr auto kStringScalarName = "telemetry.test.string_kind"_ns;
constexpr auto kUintScalarName = "telemetry.test.unsigned_int_kind"_ns;
const bool kBoolScalarValue = true;
constexpr auto kStringScalarValue = "a string scalar value"_ns;
const uint32_t kUintScalarValue = 42;
auto md = MakeRefPtr<MockDelegate>();
EXPECT_CALL(
*md, ReceiveBoolScalarValue(Eq(kBoolScalarName), Eq(kBoolScalarValue)));
EXPECT_CALL(*md, ReceiveStringScalarValue(Eq(kStringScalarName),
Eq(kStringScalarValue)));
EXPECT_CALL(
*md, ReceiveUintScalarValue(Eq(kUintScalarName), Eq(kUintScalarValue)));
GeckoViewStreamingTelemetry::RegisterDelegate(md);
Telemetry::ScalarSet(ScalarID::TELEMETRY_TEST_BOOLEAN_KIND, kBoolScalarValue);
Telemetry::ScalarSet(ScalarID::TELEMETRY_TEST_STRING_KIND,
NS_ConvertUTF8toUTF16(kStringScalarValue));
Preferences::SetInt(kBatchTimeoutPref,
0); // Trigger batch on next accumulation.
Telemetry::ScalarSet(ScalarID::TELEMETRY_TEST_UNSIGNED_INT_KIND,
kUintScalarValue);
}
TEST_F(TelemetryStreamingFixture, ExpiredHistogram) {
const HistogramID kExpiredHistogram = Telemetry::TELEMETRY_TEST_EXPIRED;
const uint32_t kSample = 401;
// Strict Mock fails on any method calls.
auto md = MakeRefPtr<StrictMock<MockDelegate>>();
GeckoViewStreamingTelemetry::RegisterDelegate(md);
Preferences::SetInt(kBatchTimeoutPref, 0);
Telemetry::Accumulate(kExpiredHistogram, kSample);
}
TEST_F(TelemetryStreamingFixture, SendOnAppBackground) {
constexpr auto kBoolScalarName = "telemetry.test.boolean_kind"_ns;
const bool kBoolScalarValue = true;
const char* kApplicationBackgroundTopic = "application-background";
auto md = MakeRefPtr<MockDelegate>();
EXPECT_CALL(
*md, ReceiveBoolScalarValue(Eq(kBoolScalarName), Eq(kBoolScalarValue)));
GeckoViewStreamingTelemetry::RegisterDelegate(md);
Telemetry::ScalarSet(ScalarID::TELEMETRY_TEST_BOOLEAN_KIND, kBoolScalarValue);
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
ASSERT_TRUE(!!os)
<< "Observer Service unavailable?!?!";
os->NotifyObservers(nullptr, kApplicationBackgroundTopic, nullptr);
}
} // namespace