summaryrefslogtreecommitdiffstats
path: root/toolkit/components/telemetry/tests/gtest/TestHistograms.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/telemetry/tests/gtest/TestHistograms.cpp')
-rw-r--r--toolkit/components/telemetry/tests/gtest/TestHistograms.cpp891
1 files changed, 891 insertions, 0 deletions
diff --git a/toolkit/components/telemetry/tests/gtest/TestHistograms.cpp b/toolkit/components/telemetry/tests/gtest/TestHistograms.cpp
new file mode 100644
index 0000000000..28b6cce751
--- /dev/null
+++ b/toolkit/components/telemetry/tests/gtest/TestHistograms.cpp
@@ -0,0 +1,891 @@
+/* vim:set ts=2 sw=2 sts=0 et: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+#include "gtest/gtest.h"
+#include "js/Conversions.h"
+#include "mozilla/Telemetry.h"
+#include "TelemetryFixture.h"
+#include "TelemetryTestHelpers.h"
+
+using namespace mozilla;
+using namespace TelemetryTestHelpers;
+
+TEST_F(TelemetryTestFixture, AccumulateCountHistogram) {
+ const uint32_t kExpectedValue = 200;
+ AutoJSContextWithGlobal cx(mCleanGlobal);
+
+ const char* telemetryTestCountName =
+ Telemetry::GetHistogramName(Telemetry::TELEMETRY_TEST_COUNT);
+ ASSERT_STREQ(telemetryTestCountName, "TELEMETRY_TEST_COUNT")
+ << "The histogram name is wrong";
+
+ GetAndClearHistogram(cx.GetJSContext(), mTelemetry, "TELEMETRY_TEST_COUNT"_ns,
+ false);
+
+ // Accumulate in the histogram
+ Telemetry::Accumulate(Telemetry::TELEMETRY_TEST_COUNT, kExpectedValue / 2);
+ Telemetry::Accumulate("TELEMETRY_TEST_COUNT", kExpectedValue / 2);
+
+ // Get a snapshot for all the histograms
+ JS::Rooted<JS::Value> snapshot(cx.GetJSContext());
+ GetSnapshots(cx.GetJSContext(), mTelemetry, telemetryTestCountName, &snapshot,
+ false);
+
+ // Get the histogram from the snapshot
+ JS::Rooted<JS::Value> histogram(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), telemetryTestCountName, snapshot, &histogram);
+
+ // Get "sum" property from histogram
+ JS::Rooted<JS::Value> sum(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "sum", histogram, &sum);
+
+ // Check that the "sum" stored in the histogram matches with |kExpectedValue|
+ uint32_t uSum = 0;
+ JS::ToUint32(cx.GetJSContext(), sum, &uSum);
+ ASSERT_EQ(uSum, kExpectedValue)
+ << "The histogram is not returning expected value";
+}
+
+TEST_F(TelemetryTestFixture, AccumulateKeyedCountHistogram) {
+ const uint32_t kExpectedValue = 100;
+ AutoJSContextWithGlobal cx(mCleanGlobal);
+
+ GetAndClearHistogram(cx.GetJSContext(), mTelemetry,
+ "TELEMETRY_TEST_KEYED_COUNT"_ns, true);
+
+ // Accumulate data in the provided key within the histogram
+ Telemetry::Accumulate(Telemetry::TELEMETRY_TEST_KEYED_COUNT, "sample"_ns,
+ kExpectedValue);
+
+ // Get a snapshot for all the histograms
+ JS::Rooted<JS::Value> snapshot(cx.GetJSContext());
+ GetSnapshots(cx.GetJSContext(), mTelemetry, "TELEMETRY_TEST_KEYED_COUNT",
+ &snapshot, true);
+
+ // Get the histogram from the snapshot
+ JS::Rooted<JS::Value> histogram(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "TELEMETRY_TEST_KEYED_COUNT", snapshot,
+ &histogram);
+
+ // Get "sample" property from histogram
+ JS::Rooted<JS::Value> expectedKeyData(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "sample", histogram, &expectedKeyData);
+
+ // Get "sum" property from keyed data
+ JS::Rooted<JS::Value> sum(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "sum", expectedKeyData, &sum);
+
+ // Check that the sum stored in the histogram matches with |kExpectedValue|
+ uint32_t uSum = 0;
+ JS::ToUint32(cx.GetJSContext(), sum, &uSum);
+ ASSERT_EQ(uSum, kExpectedValue)
+ << "The histogram is not returning expected sum";
+}
+
+TEST_F(TelemetryTestFixture, TestKeyedKeysHistogram) {
+ AutoJSContextWithGlobal cx(mCleanGlobal);
+
+ JS::Rooted<JS::Value> testHistogram(cx.GetJSContext());
+ JS::Rooted<JS::Value> rval(cx.GetJSContext());
+
+ GetAndClearHistogram(cx.GetJSContext(), mTelemetry,
+ "TELEMETRY_TEST_KEYED_KEYS"_ns, true);
+
+ // Test the accumulation on both the allowed and unallowed keys, using
+ // the API that accepts histogram IDs.
+ Telemetry::Accumulate(Telemetry::TELEMETRY_TEST_KEYED_KEYS, "not-allowed"_ns,
+ 1);
+ Telemetry::Accumulate(Telemetry::TELEMETRY_TEST_KEYED_KEYS, "testkey"_ns, 0);
+ // Do the same, using the API that accepts the histogram name as a string.
+ Telemetry::Accumulate("TELEMETRY_TEST_KEYED_KEYS", "not-allowed"_ns, 1);
+ Telemetry::Accumulate("TELEMETRY_TEST_KEYED_KEYS", "CommonKey"_ns, 1);
+
+ // Get a snapshot for all the histograms
+ JS::Rooted<JS::Value> snapshot(cx.GetJSContext());
+ GetSnapshots(cx.GetJSContext(), mTelemetry, "TELEMETRY_TEST_KEYED_KEYS",
+ &snapshot, true);
+
+ // Get the histogram from the snapshot
+ JS::Rooted<JS::Value> histogram(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "TELEMETRY_TEST_KEYED_KEYS", snapshot,
+ &histogram);
+
+ // Get "testkey" property from histogram and check that it stores the correct
+ // data.
+ JS::Rooted<JS::Value> expectedKeyData(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "testkey", histogram, &expectedKeyData);
+ ASSERT_TRUE(!expectedKeyData.isUndefined())
+ << "Cannot find the expected key in the histogram data";
+ JS::Rooted<JS::Value> sum(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "sum", expectedKeyData, &sum);
+ uint32_t uSum = 0;
+ JS::ToUint32(cx.GetJSContext(), sum, &uSum);
+ ASSERT_EQ(uSum, 0U)
+ << "The histogram is not returning expected sum for 'testkey'";
+
+ // Do the same for the "CommonKey" property.
+ GetProperty(cx.GetJSContext(), "CommonKey", histogram, &expectedKeyData);
+ ASSERT_TRUE(!expectedKeyData.isUndefined())
+ << "Cannot find the expected key in the histogram data";
+ GetProperty(cx.GetJSContext(), "sum", expectedKeyData, &sum);
+ JS::ToUint32(cx.GetJSContext(), sum, &uSum);
+ ASSERT_EQ(uSum, 1U)
+ << "The histogram is not returning expected sum for 'CommonKey'";
+
+ GetProperty(cx.GetJSContext(), "not-allowed", histogram, &expectedKeyData);
+ ASSERT_TRUE(expectedKeyData.isUndefined())
+ << "Unallowed keys must not be recorded in the histogram data";
+
+ // The 'not-allowed' key accumulation for 'TELEMETRY_TESTED_KEYED_KEYS' was
+ // attemtped twice, so we expect the count of
+ // 'telemetry.accumulate_unknown_histogram_keys' to be 2
+ const uint32_t expectedAccumulateUnknownCount = 2;
+ JS::Rooted<JS::Value> scalarsSnapshot(cx.GetJSContext());
+ GetScalarsSnapshot(true, cx.GetJSContext(), &scalarsSnapshot);
+ CheckKeyedUintScalar("telemetry.accumulate_unknown_histogram_keys",
+ "TELEMETRY_TEST_KEYED_KEYS", cx.GetJSContext(),
+ scalarsSnapshot, expectedAccumulateUnknownCount);
+}
+
+TEST_F(TelemetryTestFixture, AccumulateCategoricalHistogram) {
+ const uint32_t kExpectedValue = 2;
+
+ AutoJSContextWithGlobal cx(mCleanGlobal);
+
+ GetAndClearHistogram(cx.GetJSContext(), mTelemetry,
+ "TELEMETRY_TEST_CATEGORICAL"_ns, false);
+
+ // Accumulate one unit into the categorical histogram with label
+ // Telemetry::LABELS_TELEMETRY_TEST_CATEGORICAL::CommonLabel
+ Telemetry::AccumulateCategorical(
+ Telemetry::LABELS_TELEMETRY_TEST_CATEGORICAL::CommonLabel);
+
+ // Accumulate another unit into the same categorical histogram using a string
+ // label
+ Telemetry::AccumulateCategorical(Telemetry::TELEMETRY_TEST_CATEGORICAL,
+ "CommonLabel"_ns);
+
+ // Get a snapshot for all the histograms
+ JS::Rooted<JS::Value> snapshot(cx.GetJSContext());
+ GetSnapshots(cx.GetJSContext(), mTelemetry, "TELEMETRY_TEST_CATEGORICAL",
+ &snapshot, false);
+
+ // Get our histogram from the snapshot
+ JS::Rooted<JS::Value> histogram(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "TELEMETRY_TEST_CATEGORICAL", snapshot,
+ &histogram);
+
+ // Get values object from histogram. Each entry in the object maps to a label
+ // in the histogram.
+ JS::Rooted<JS::Value> values(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "values", histogram, &values);
+
+ // Get the value for the label we care about
+ JS::Rooted<JS::Value> value(cx.GetJSContext());
+ GetElement(cx.GetJSContext(),
+ static_cast<uint32_t>(
+ Telemetry::LABELS_TELEMETRY_TEST_CATEGORICAL::CommonLabel),
+ values, &value);
+
+ // Check that the value stored in the histogram matches with |kExpectedValue|
+ uint32_t uValue = 0;
+ JS::ToUint32(cx.GetJSContext(), value, &uValue);
+ ASSERT_EQ(uValue, kExpectedValue)
+ << "The histogram is not returning expected value";
+}
+
+TEST_F(TelemetryTestFixture, AccumulateKeyedCategoricalHistogram) {
+ const uint32_t kSampleExpectedValue = 2;
+ const uint32_t kOtherSampleExpectedValue = 1;
+
+ AutoJSContextWithGlobal cx(mCleanGlobal);
+
+ GetAndClearHistogram(cx.GetJSContext(), mTelemetry,
+ "TELEMETRY_TEST_KEYED_CATEGORICAL"_ns, true);
+
+ // Accumulate one unit into the categorical histogram with label
+ // Telemetry::LABELS_TELEMETRY_TEST_KEYED_CATEGORICAL::CommonLabel
+ Telemetry::AccumulateCategoricalKeyed(
+ "sample"_ns,
+ Telemetry::LABELS_TELEMETRY_TEST_KEYED_CATEGORICAL::CommonLabel);
+ // Accumulate another unit into the same categorical histogram
+ Telemetry::AccumulateCategoricalKeyed(
+ "sample"_ns,
+ Telemetry::LABELS_TELEMETRY_TEST_KEYED_CATEGORICAL::CommonLabel);
+ // Accumulate another unit into a different categorical histogram
+ Telemetry::AccumulateCategoricalKeyed(
+ "other-sample"_ns,
+ Telemetry::LABELS_TELEMETRY_TEST_KEYED_CATEGORICAL::CommonLabel);
+
+ // Get a snapshot for all the histograms
+ JS::Rooted<JS::Value> snapshot(cx.GetJSContext());
+ GetSnapshots(cx.GetJSContext(), mTelemetry,
+ "TELEMETRY_TEST_KEYED_CATEGORICAL", &snapshot, true);
+ // Get the histogram from the snapshot
+ JS::Rooted<JS::Value> histogram(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "TELEMETRY_TEST_KEYED_CATEGORICAL", snapshot,
+ &histogram);
+
+ // Check that the sample histogram contains the values we expect
+ JS::Rooted<JS::Value> sample(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "sample", histogram, &sample);
+ // Get values object from sample. Each entry in the object maps to a label in
+ // the histogram.
+ JS::Rooted<JS::Value> sampleValues(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "values", sample, &sampleValues);
+ // Get the value for the label we care about
+ JS::Rooted<JS::Value> sampleValue(cx.GetJSContext());
+ GetElement(
+ cx.GetJSContext(),
+ static_cast<uint32_t>(
+ Telemetry::LABELS_TELEMETRY_TEST_KEYED_CATEGORICAL::CommonLabel),
+ sampleValues, &sampleValue);
+ // Check that the value stored in the histogram matches with
+ // |kSampleExpectedValue|
+ uint32_t uSampleValue = 0;
+ JS::ToUint32(cx.GetJSContext(), sampleValue, &uSampleValue);
+ ASSERT_EQ(uSampleValue, kSampleExpectedValue)
+ << "The sample histogram is not returning expected value";
+
+ // Check that the other-sample histogram contains the values we expect
+ JS::Rooted<JS::Value> otherSample(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "other-sample", histogram, &otherSample);
+ // Get values object from the other-sample. Each entry in the object maps to a
+ // label in the histogram.
+ JS::Rooted<JS::Value> otherValues(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "values", otherSample, &otherValues);
+ // Get the value for the label we care about
+ JS::Rooted<JS::Value> otherValue(cx.GetJSContext());
+ GetElement(
+ cx.GetJSContext(),
+ static_cast<uint32_t>(
+ Telemetry::LABELS_TELEMETRY_TEST_KEYED_CATEGORICAL::CommonLabel),
+ otherValues, &otherValue);
+ // Check that the value stored in the histogram matches with
+ // |kOtherSampleExpectedValue|
+ uint32_t uOtherValue = 0;
+ JS::ToUint32(cx.GetJSContext(), otherValue, &uOtherValue);
+ ASSERT_EQ(uOtherValue, kOtherSampleExpectedValue)
+ << "The other-sample histogram is not returning expected value";
+}
+
+TEST_F(TelemetryTestFixture, AccumulateCountHistogram_MultipleSamples) {
+ nsTArray<uint32_t> samples({4, 4, 4});
+ const uint32_t kExpectedSum = 12;
+
+ AutoJSContextWithGlobal cx(mCleanGlobal);
+
+ GetAndClearHistogram(cx.GetJSContext(), mTelemetry, "TELEMETRY_TEST_COUNT"_ns,
+ false);
+
+ // Accumulate in histogram
+ Telemetry::Accumulate(Telemetry::TELEMETRY_TEST_COUNT, samples);
+
+ // Get a snapshot of all the histograms
+ JS::Rooted<JS::Value> snapshot(cx.GetJSContext());
+ GetSnapshots(cx.GetJSContext(), mTelemetry, "TELEMETRY_TEST_COUNT", &snapshot,
+ false);
+
+ // Get histogram from snapshot
+ JS::Rooted<JS::Value> histogram(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "TELEMETRY_TEST_COUNT", snapshot, &histogram);
+
+ // Get "sum" from histogram
+ JS::Rooted<JS::Value> sum(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "sum", histogram, &sum);
+
+ // Check that sum matches with aValue
+ uint32_t uSum = 0;
+ JS::ToUint32(cx.GetJSContext(), sum, &uSum);
+ ASSERT_EQ(uSum, kExpectedSum)
+ << "This histogram is not returning expected value";
+}
+
+TEST_F(TelemetryTestFixture, AccumulateLinearHistogram_MultipleSamples) {
+ nsTArray<uint32_t> samples({4, 4, 4});
+ const uint32_t kExpectedCount = 3;
+
+ AutoJSContextWithGlobal cx(mCleanGlobal);
+
+ GetAndClearHistogram(cx.GetJSContext(), mTelemetry,
+ "TELEMETRY_TEST_LINEAR"_ns, false);
+
+ // Accumulate in the histogram
+ Telemetry::Accumulate(Telemetry::TELEMETRY_TEST_LINEAR, samples);
+
+ // Get a snapshot of all the histograms
+ JS::Rooted<JS::Value> snapshot(cx.GetJSContext());
+ GetSnapshots(cx.GetJSContext(), mTelemetry, "TELEMETRY_TEST_LINEAR",
+ &snapshot, false);
+
+ // Get histogram from snapshot
+ JS::Rooted<JS::Value> histogram(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "TELEMETRY_TEST_LINEAR", snapshot, &histogram);
+
+ // Get "values" object from histogram
+ JS::Rooted<JS::Value> values(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "values", histogram, &values);
+
+ // Index 0 is only for values less than 'low'. Values within range start at
+ // index 1
+ JS::Rooted<JS::Value> count(cx.GetJSContext());
+ const uint32_t index = 1;
+ GetElement(cx.GetJSContext(), index, values, &count);
+
+ // Check that this count matches with nSamples
+ uint32_t uCount = 0;
+ JS::ToUint32(cx.GetJSContext(), count, &uCount);
+ ASSERT_EQ(uCount, kExpectedCount)
+ << "The histogram did not accumulate the correct number of values";
+}
+
+TEST_F(TelemetryTestFixture, AccumulateLinearHistogram_DifferentSamples) {
+ nsTArray<uint32_t> samples(
+ {4, 8, 2147483646, uint32_t(INT_MAX) + 1, UINT32_MAX});
+
+ AutoJSContextWithGlobal cx(mCleanGlobal);
+
+ mTelemetry->ClearScalars();
+ GetAndClearHistogram(cx.GetJSContext(), mTelemetry,
+ "TELEMETRY_TEST_LINEAR"_ns, false);
+
+ // Accumulate in histogram
+ Telemetry::Accumulate(Telemetry::TELEMETRY_TEST_LINEAR, samples);
+
+ // Get a snapshot of all histograms
+ JS::Rooted<JS::Value> snapshot(cx.GetJSContext());
+ GetSnapshots(cx.GetJSContext(), mTelemetry, "TELEMETRY_TEST_LINEAR",
+ &snapshot, false);
+
+ // Get histogram from snapshot
+ JS::Rooted<JS::Value> histogram(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "TELEMETRY_TEST_LINEAR", snapshot, &histogram);
+
+ // Get values object from histogram
+ JS::Rooted<JS::Value> values(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "values", histogram, &values);
+
+ // Get values in first and last buckets
+ JS::Rooted<JS::Value> countFirst(cx.GetJSContext());
+ JS::Rooted<JS::Value> countLast(cx.GetJSContext());
+ const uint32_t firstIndex = 1;
+ // Buckets are indexed by their start value
+ const uint32_t lastIndex = INT32_MAX - 1;
+ GetElement(cx.GetJSContext(), firstIndex, values, &countFirst);
+ GetElement(cx.GetJSContext(), lastIndex, values, &countLast);
+
+ // Check that the values match
+ uint32_t uCountFirst = 0;
+ uint32_t uCountLast = 0;
+ JS::ToUint32(cx.GetJSContext(), countFirst, &uCountFirst);
+ JS::ToUint32(cx.GetJSContext(), countLast, &uCountLast);
+
+ const uint32_t kExpectedCountFirst = 2;
+ // We expect 2147483646 to be in the last bucket, as well the two samples
+ // above 2^31 (prior to bug 1438335, values between INT_MAX and UINT32_MAX
+ // would end up as 0s)
+ const uint32_t kExpectedCountLast = 3;
+ ASSERT_EQ(uCountFirst, kExpectedCountFirst)
+ << "The first bucket did not accumulate the correct number of values";
+ ASSERT_EQ(uCountLast, kExpectedCountLast)
+ << "The last bucket did not accumulate the correct number of values";
+
+ // We accumulated two values that had to be clamped. We expect the count in
+ // 'telemetry.accumulate_clamped_values' to be 2 (only one storage).
+ const uint32_t expectedAccumulateClampedCount = 2;
+ JS::Rooted<JS::Value> scalarsSnapshot(cx.GetJSContext());
+ GetScalarsSnapshot(true, cx.GetJSContext(), &scalarsSnapshot);
+ CheckKeyedUintScalar("telemetry.accumulate_clamped_values",
+ "TELEMETRY_TEST_LINEAR", cx.GetJSContext(),
+ scalarsSnapshot, expectedAccumulateClampedCount);
+}
+
+TEST_F(TelemetryTestFixture, AccumulateKeyedCountHistogram_MultipleSamples) {
+ const nsTArray<uint32_t> samples({5, 10, 15});
+ const uint32_t kExpectedSum = 5 + 10 + 15;
+
+ AutoJSContextWithGlobal cx(mCleanGlobal);
+
+ GetAndClearHistogram(cx.GetJSContext(), mTelemetry,
+ "TELEMETRY_TEST_KEYED_COUNT"_ns, true);
+
+ // Accumulate data in the provided key within the histogram
+ Telemetry::Accumulate(Telemetry::TELEMETRY_TEST_KEYED_COUNT, "sample"_ns,
+ samples);
+
+ // Get a snapshot for all the histograms
+ JS::Rooted<JS::Value> snapshot(cx.GetJSContext());
+ GetSnapshots(cx.GetJSContext(), mTelemetry, "TELEMETRY_TEST_KEYED_COUNT",
+ &snapshot, true);
+
+ // Get the histogram from the snapshot
+ JS::Rooted<JS::Value> histogram(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "TELEMETRY_TEST_KEYED_COUNT", snapshot,
+ &histogram);
+
+ // Get "sample" property from histogram
+ JS::Rooted<JS::Value> expectedKeyData(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "sample", histogram, &expectedKeyData);
+
+ // Get "sum" property from keyed data
+ JS::Rooted<JS::Value> sum(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "sum", expectedKeyData, &sum);
+
+ // Check that the sum stored in the histogram matches with |kExpectedSum|
+ uint32_t uSum = 0;
+ JS::ToUint32(cx.GetJSContext(), sum, &uSum);
+ ASSERT_EQ(uSum, kExpectedSum)
+ << "The histogram is not returning expected sum";
+}
+
+TEST_F(TelemetryTestFixture, TestKeyedLinearHistogram_MultipleSamples) {
+ AutoJSContextWithGlobal cx(mCleanGlobal);
+
+ mTelemetry->ClearScalars();
+ GetAndClearHistogram(cx.GetJSContext(), mTelemetry,
+ "TELEMETRY_TEST_KEYED_LINEAR"_ns, true);
+
+ const nsTArray<uint32_t> samples({1, 5, 250000, UINT_MAX});
+ // Test the accumulation on the key 'testkey', using
+ // the API that accepts histogram IDs.
+ Telemetry::Accumulate(Telemetry::TELEMETRY_TEST_KEYED_LINEAR, "testkey"_ns,
+ samples);
+
+ // Get a snapshot for all the histograms
+ JS::Rooted<JS::Value> snapshot(cx.GetJSContext());
+ GetSnapshots(cx.GetJSContext(), mTelemetry, "TELEMETRY_TEST_KEYED_LINEAR",
+ &snapshot, true);
+
+ // Get the histogram from the snapshot
+ JS::Rooted<JS::Value> histogram(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "TELEMETRY_TEST_KEYED_LINEAR", snapshot,
+ &histogram);
+
+ // Get "testkey" property from histogram.
+ JS::Rooted<JS::Value> expectedKeyData(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "testkey", histogram, &expectedKeyData);
+ ASSERT_TRUE(!expectedKeyData.isUndefined())
+ << "Cannot find the expected key in the histogram data";
+
+ // Get values object from 'testkey' histogram.
+ JS::Rooted<JS::Value> values(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "values", expectedKeyData, &values);
+
+ // Get values in first and last buckets.
+ JS::Rooted<JS::Value> countFirst(cx.GetJSContext());
+ JS::Rooted<JS::Value> countLast(cx.GetJSContext());
+ const uint32_t firstIndex = 1;
+ // Buckets are indexed by their start value
+ const uint32_t lastIndex = 250000;
+ GetElement(cx.GetJSContext(), firstIndex, values, &countFirst);
+ GetElement(cx.GetJSContext(), lastIndex, values, &countLast);
+
+ // Check that the values match.
+ uint32_t uCountFirst = 0;
+ uint32_t uCountLast = 0;
+ JS::ToUint32(cx.GetJSContext(), countFirst, &uCountFirst);
+ JS::ToUint32(cx.GetJSContext(), countLast, &uCountLast);
+
+ const uint32_t kExpectedCountFirst = 2;
+ const uint32_t kExpectedCountLast = 2;
+ ASSERT_EQ(uCountFirst, kExpectedCountFirst)
+ << "The first bucket did not accumulate the correct number of values for "
+ "key 'testkey'";
+ ASSERT_EQ(uCountLast, kExpectedCountLast)
+ << "The last bucket did not accumulate the correct number of values for "
+ "key 'testkey'";
+
+ // We accumulated one keyed values that had to be clamped. We expect the
+ // count in 'telemetry.accumulate_clamped_values' to be 1
+ const uint32_t expectedAccumulateClampedCount = 1;
+ JS::Rooted<JS::Value> scalarsSnapshot(cx.GetJSContext());
+ GetScalarsSnapshot(true, cx.GetJSContext(), &scalarsSnapshot);
+ CheckKeyedUintScalar("telemetry.accumulate_clamped_values",
+ "TELEMETRY_TEST_KEYED_LINEAR", cx.GetJSContext(),
+ scalarsSnapshot, expectedAccumulateClampedCount);
+}
+
+TEST_F(TelemetryTestFixture, TestKeyedKeysHistogram_MultipleSamples) {
+ AutoJSContextWithGlobal cx(mCleanGlobal);
+ mTelemetry->ClearScalars();
+ const nsTArray<uint32_t> samples({false, false, true, 32, true});
+
+ GetAndClearHistogram(cx.GetJSContext(), mTelemetry,
+ "TELEMETRY_TEST_KEYED_KEYS"_ns, true);
+
+ // Test the accumulation on both the allowed and unallowed keys, using
+ // the API that accepts histogram IDs.
+ Telemetry::Accumulate(Telemetry::TELEMETRY_TEST_KEYED_KEYS, "not-allowed"_ns,
+ samples);
+ Telemetry::Accumulate(Telemetry::TELEMETRY_TEST_KEYED_KEYS, "testkey"_ns,
+ samples);
+
+ // Get a snapshot for all the histograms
+ JS::Rooted<JS::Value> snapshot(cx.GetJSContext());
+ GetSnapshots(cx.GetJSContext(), mTelemetry, "TELEMETRY_TEST_KEYED_KEYS",
+ &snapshot, true);
+
+ // Get the histogram from the snapshot
+ JS::Rooted<JS::Value> histogram(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "TELEMETRY_TEST_KEYED_KEYS", snapshot,
+ &histogram);
+
+ // Get "testkey" property from histogram and check that it stores the correct
+ // data.
+ JS::Rooted<JS::Value> testKeyData(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "testkey", histogram, &testKeyData);
+ ASSERT_TRUE(!testKeyData.isUndefined())
+ << "Cannot find the key 'testkey' in the histogram data";
+
+ JS::Rooted<JS::Value> values(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "values", testKeyData, &values);
+
+ // Get values in buckets 0,1,2
+ const uint32_t falseIndex = 0;
+ const uint32_t trueIndex = 1;
+ const uint32_t otherIndex = 2;
+
+ JS::Rooted<JS::Value> countFalse(cx.GetJSContext());
+ JS::Rooted<JS::Value> countTrue(cx.GetJSContext());
+ JS::Rooted<JS::Value> countOther(cx.GetJSContext());
+
+ GetElement(cx.GetJSContext(), falseIndex, values, &countFalse);
+ GetElement(cx.GetJSContext(), trueIndex, values, &countTrue);
+ GetElement(cx.GetJSContext(), otherIndex, values, &countOther);
+
+ uint32_t uCountFalse = 0;
+ uint32_t uCountTrue = 0;
+ uint32_t uCountOther = 0;
+ JS::ToUint32(cx.GetJSContext(), countFalse, &uCountFalse);
+ JS::ToUint32(cx.GetJSContext(), countTrue, &uCountTrue);
+ JS::ToUint32(cx.GetJSContext(), countOther, &uCountOther);
+
+ const uint32_t kExpectedCountFalse = 2;
+ const uint32_t kExpectedCountTrue = 3;
+ const uint32_t kExpectedCountOther = 0;
+
+ ASSERT_EQ(uCountFalse, kExpectedCountFalse)
+ << "The histogram did not accumulate the correct number of 'false' "
+ "booleans for key 'testkey'";
+ ASSERT_EQ(uCountTrue, kExpectedCountTrue)
+ << "The histogram did not accumulate the correct number of 'true' "
+ "booleans for key 'testkey'";
+ ASSERT_EQ(uCountOther, kExpectedCountOther)
+ << "The histogram did not accumulate the correct number of undefined "
+ "values for key 'testkey'";
+
+ // Here we check that we are not accumulating to a different (but still
+ // 'allowed') key. Get "CommonKey" property from histogram and check that it
+ // has no data. Since we accumulated no data to it, commonKeyData should be
+ // undefined.
+ JS::Rooted<JS::Value> commonKeyData(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "CommonKey", histogram, &commonKeyData);
+ ASSERT_TRUE(commonKeyData.isUndefined())
+ << "Found data in key 'CommonKey' even though we accumulated no data to "
+ "it";
+
+ // Here we check that our function does not allow accumulation into unallowed
+ // keys. Get 'not-allowed' property from histogram and check that this also
+ // has no data. This should contain no data because this key is not allowed.
+ JS::Rooted<JS::Value> notAllowedKeyData(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "not-allowed", histogram, &notAllowedKeyData);
+ ASSERT_TRUE(notAllowedKeyData.isUndefined())
+ << "Found data in key 'not-allowed' even though accumuling data to it is "
+ "not allowed";
+
+ // The 'not-allowed' key accumulation for 'TELEMETRY_TESTED_KEYED_KEYS' was
+ // attemtped once, so we expect the count of
+ // 'telemetry.accumulate_unknown_histogram_keys' to be 1
+ const uint32_t expectedAccumulateUnknownCount = 1;
+ JS::Rooted<JS::Value> scalarsSnapshot(cx.GetJSContext());
+ GetScalarsSnapshot(true, cx.GetJSContext(), &scalarsSnapshot);
+ CheckKeyedUintScalar("telemetry.accumulate_unknown_histogram_keys",
+ "TELEMETRY_TEST_KEYED_KEYS", cx.GetJSContext(),
+ scalarsSnapshot, expectedAccumulateUnknownCount);
+}
+
+TEST_F(TelemetryTestFixture,
+ AccumulateCategoricalHistogram_MultipleStringLabels) {
+ const uint32_t kExpectedValue = 2;
+ const nsTArray<nsCString> labels({"CommonLabel"_ns, "CommonLabel"_ns});
+ AutoJSContextWithGlobal cx(mCleanGlobal);
+
+ GetAndClearHistogram(cx.GetJSContext(), mTelemetry,
+ "TELEMETRY_TEST_CATEGORICAL"_ns, false);
+
+ // Accumulate the units into a categorical histogram using a string label
+ Telemetry::AccumulateCategorical(Telemetry::TELEMETRY_TEST_CATEGORICAL,
+ labels);
+
+ // Get a snapshot for all the histograms
+ JS::Rooted<JS::Value> snapshot(cx.GetJSContext());
+ GetSnapshots(cx.GetJSContext(), mTelemetry, "TELEMETRY_TEST_CATEGORICAL",
+ &snapshot, false);
+
+ // Get our histogram from the snapshot
+ JS::Rooted<JS::Value> histogram(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "TELEMETRY_TEST_CATEGORICAL", snapshot,
+ &histogram);
+
+ // Get values object from histogram. Each entry in the object maps to a label
+ // in the histogram.
+ JS::Rooted<JS::Value> values(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "values", histogram, &values);
+
+ // Get the value for the label we care about
+ JS::Rooted<JS::Value> value(cx.GetJSContext());
+ GetElement(cx.GetJSContext(),
+ static_cast<uint32_t>(
+ Telemetry::LABELS_TELEMETRY_TEST_CATEGORICAL::CommonLabel),
+ values, &value);
+
+ // Check that the value stored in the histogram matches with |kExpectedValue|
+ uint32_t uValue = 0;
+ JS::ToUint32(cx.GetJSContext(), value, &uValue);
+ ASSERT_EQ(uValue, kExpectedValue)
+ << "The histogram is not returning expected value";
+
+ // Now we check for no accumulation when a bad label is present in the array.
+ //
+ // The 'values' property is not initialized unless data is accumulated so
+ // keeping another test to check for this case alone is wasteful as we will
+ // have to accumulate some data anyway.
+
+ const nsTArray<nsCString> badLabelArray({"CommonLabel"_ns, "BadLabel"_ns});
+
+ // Try to accumulate the array into the histogram.
+ Telemetry::AccumulateCategorical(Telemetry::TELEMETRY_TEST_CATEGORICAL,
+ badLabelArray);
+
+ // Get snapshot of all the histograms
+ GetSnapshots(cx.GetJSContext(), mTelemetry, "TELEMETRY_TEST_CATEGORICAL",
+ &snapshot, false);
+
+ // Get our histogram from the snapshot
+ GetProperty(cx.GetJSContext(), "TELEMETRY_TEST_CATEGORICAL", snapshot,
+ &histogram);
+
+ // Get values array from histogram
+ GetProperty(cx.GetJSContext(), "values", histogram, &values);
+
+ // Get the value for the label we care about
+ GetElement(cx.GetJSContext(),
+ static_cast<uint32_t>(
+ Telemetry::LABELS_TELEMETRY_TEST_CATEGORICAL::CommonLabel),
+ values, &value);
+
+ // Check that the value stored in the histogram matches with |kExpectedValue|
+ uValue = 0;
+ JS::ToUint32(cx.GetJSContext(), value, &uValue);
+ ASSERT_EQ(uValue, kExpectedValue)
+ << "The histogram accumulated data when it should not have";
+}
+
+TEST_F(TelemetryTestFixture,
+ AccumulateCategoricalHistogram_MultipleEnumValues) {
+ const uint32_t kExpectedValue = 2;
+ const nsTArray<Telemetry::LABELS_TELEMETRY_TEST_CATEGORICAL> enumLabels(
+ {Telemetry::LABELS_TELEMETRY_TEST_CATEGORICAL::CommonLabel,
+ Telemetry::LABELS_TELEMETRY_TEST_CATEGORICAL::CommonLabel});
+
+ AutoJSContextWithGlobal cx(mCleanGlobal);
+
+ GetAndClearHistogram(cx.GetJSContext(), mTelemetry,
+ "TELEMETRY_TEST_CATEGORICAL"_ns, false);
+
+ // Accumulate the units into a categorical histogram using the enumLabels
+ // array
+ Telemetry::AccumulateCategorical<
+ Telemetry::LABELS_TELEMETRY_TEST_CATEGORICAL>(enumLabels);
+
+ // Get a snapshot for all the histograms
+ JS::Rooted<JS::Value> snapshot(cx.GetJSContext());
+ GetSnapshots(cx.GetJSContext(), mTelemetry, "TELEMETRY_TEST_CATEGORICAL",
+ &snapshot, false);
+
+ // Get our histogram from the snapshot
+ JS::Rooted<JS::Value> histogram(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "TELEMETRY_TEST_CATEGORICAL", snapshot,
+ &histogram);
+
+ // Get values object from histogram. Each entry in the object maps to a label
+ // in the histogram.
+ JS::Rooted<JS::Value> values(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "values", histogram, &values);
+
+ // Get the value for the label we care about
+ JS::Rooted<JS::Value> value(cx.GetJSContext());
+ GetElement(cx.GetJSContext(),
+ static_cast<uint32_t>(
+ Telemetry::LABELS_TELEMETRY_TEST_CATEGORICAL::CommonLabel),
+ values, &value);
+
+ // Check that the value stored in the histogram matches with |kExpectedValue|
+ uint32_t uValue = 0;
+ JS::ToUint32(cx.GetJSContext(), value, &uValue);
+ ASSERT_EQ(uValue, kExpectedValue)
+ << "The histogram is not returning expected value";
+}
+
+TEST_F(TelemetryTestFixture,
+ AccumulateKeyedCategoricalHistogram_MultipleEnumValues) {
+ const uint32_t kExpectedCommonLabel = 2;
+ const uint32_t kExpectedLabel2 = 1;
+ const nsTArray<Telemetry::LABELS_TELEMETRY_TEST_KEYED_CATEGORICAL> enumLabels(
+ {Telemetry::LABELS_TELEMETRY_TEST_KEYED_CATEGORICAL::CommonLabel,
+ Telemetry::LABELS_TELEMETRY_TEST_KEYED_CATEGORICAL::CommonLabel,
+ Telemetry::LABELS_TELEMETRY_TEST_KEYED_CATEGORICAL::Label2});
+
+ AutoJSContextWithGlobal cx(mCleanGlobal);
+
+ GetAndClearHistogram(cx.GetJSContext(), mTelemetry,
+ "TELEMETRY_TEST_KEYED_CATEGORICAL"_ns, true);
+
+ // Accumulate the array into the categorical keyed histogram
+ Telemetry::AccumulateCategoricalKeyed("sampleKey"_ns, enumLabels);
+
+ // Get a snapshot for all the histograms
+ JS::Rooted<JS::Value> snapshot(cx.GetJSContext());
+ GetSnapshots(cx.GetJSContext(), mTelemetry,
+ "TELEMETRY_TEST_KEYED_CATEGORICAL", &snapshot, true);
+
+ // Get the histogram from the snapshot
+ JS::Rooted<JS::Value> histogram(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "TELEMETRY_TEST_KEYED_CATEGORICAL", snapshot,
+ &histogram);
+
+ // Check that the sampleKey histogram contains correct number of CommonLabel
+ // samples
+ JS::Rooted<JS::Value> sample(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "sampleKey", histogram, &sample);
+
+ // Get values object from the sample. Each entry in the object maps to a label
+ // in the histogram.
+ JS::Rooted<JS::Value> sampleKeyValues(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "values", sample, &sampleKeyValues);
+
+ // Get the count of CommonLabel
+ JS::Rooted<JS::Value> commonLabelValue(cx.GetJSContext());
+ GetElement(
+ cx.GetJSContext(),
+ static_cast<uint32_t>(
+ Telemetry::LABELS_TELEMETRY_TEST_KEYED_CATEGORICAL::CommonLabel),
+ sampleKeyValues, &commonLabelValue);
+
+ // Check that the value stored in the histogram matches with
+ // |kExpectedCommonLabel|
+ uint32_t uCommonLabelValue = 0;
+ JS::ToUint32(cx.GetJSContext(), commonLabelValue, &uCommonLabelValue);
+ ASSERT_EQ(uCommonLabelValue, kExpectedCommonLabel)
+ << "The sampleKey histogram did not accumulate the correct number of "
+ "CommonLabel samples";
+
+ // Check that the sampleKey histogram contains the correct number of Label2
+ // values Get the count of Label2
+ JS::Rooted<JS::Value> label2Value(cx.GetJSContext());
+ GetElement(cx.GetJSContext(),
+ static_cast<uint32_t>(
+ Telemetry::LABELS_TELEMETRY_TEST_KEYED_CATEGORICAL::Label2),
+ sampleKeyValues, &label2Value);
+
+ // Check that the value stored in the histogram matches with |kExpectedLabel2|
+ uint32_t uLabel2Value = 0;
+ JS::ToUint32(cx.GetJSContext(), label2Value, &uLabel2Value);
+ ASSERT_EQ(uLabel2Value, kExpectedLabel2)
+ << "The sampleKey histogram did not accumulate the correct number of "
+ "Label2 samples";
+}
+
+TEST_F(TelemetryTestFixture, AccumulateTimeDelta) {
+ const uint32_t kExpectedValue = 100;
+ const TimeStamp start = TimeStamp::Now();
+ const TimeDuration delta = TimeDuration::FromMilliseconds(50);
+
+ AutoJSContextWithGlobal cx(mCleanGlobal);
+
+ GetAndClearHistogram(cx.GetJSContext(), mTelemetry, "TELEMETRY_TEST_COUNT"_ns,
+ false);
+
+ // Accumulate in the histogram
+ Telemetry::AccumulateTimeDelta(Telemetry::TELEMETRY_TEST_COUNT, start - delta,
+ start);
+
+ Telemetry::AccumulateTimeDelta(Telemetry::TELEMETRY_TEST_COUNT, start - delta,
+ start);
+
+ Telemetry::AccumulateTimeDelta(Telemetry::TELEMETRY_TEST_COUNT, start, start);
+
+ // end > start timestamp gives zero contribution
+ Telemetry::AccumulateTimeDelta(Telemetry::TELEMETRY_TEST_COUNT, start + delta,
+ start);
+
+ // Get a snapshot for all the histograms
+ JS::Rooted<JS::Value> snapshot(cx.GetJSContext());
+ GetSnapshots(cx.GetJSContext(), mTelemetry, "TELEMETRY_TEST_COUNT", &snapshot,
+ false);
+
+ // Get the histogram from the snapshot
+ JS::Rooted<JS::Value> histogram(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "TELEMETRY_TEST_COUNT", snapshot, &histogram);
+
+ // Get "sum" property from histogram
+ JS::Rooted<JS::Value> sum(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "sum", histogram, &sum);
+
+ // Check that the "sum" stored in the histogram matches with |kExpectedValue|
+ uint32_t uSum = 0;
+ JS::ToUint32(cx.GetJSContext(), sum, &uSum);
+ ASSERT_EQ(uSum, kExpectedValue)
+ << "The histogram is not returning expected value";
+}
+
+TEST_F(TelemetryTestFixture, AccumulateKeyedTimeDelta) {
+ const uint32_t kExpectedValue = 100;
+ const TimeStamp start = TimeStamp::Now();
+ const TimeDuration delta = TimeDuration::FromMilliseconds(50);
+
+ AutoJSContextWithGlobal cx(mCleanGlobal);
+
+ GetAndClearHistogram(cx.GetJSContext(), mTelemetry,
+ "TELEMETRY_TEST_KEYED_COUNT"_ns, true);
+
+ // Accumulate time delta in the provided key within the histogram
+ Telemetry::AccumulateTimeDelta(Telemetry::TELEMETRY_TEST_KEYED_COUNT,
+ "sample"_ns, start - delta, start);
+
+ Telemetry::AccumulateTimeDelta(Telemetry::TELEMETRY_TEST_KEYED_COUNT,
+ "sample"_ns, start - delta, start);
+
+ // end > start timestamp gives zero contribution
+ Telemetry::AccumulateTimeDelta(Telemetry::TELEMETRY_TEST_KEYED_COUNT,
+ "sample"_ns, start + delta, start);
+
+ Telemetry::AccumulateTimeDelta(Telemetry::TELEMETRY_TEST_KEYED_COUNT,
+ "sample"_ns, start, start);
+
+ // Get a snapshot for all the histograms
+ JS::Rooted<JS::Value> snapshot(cx.GetJSContext());
+ GetSnapshots(cx.GetJSContext(), mTelemetry, "TELEMETRY_TEST_KEYED_COUNT",
+ &snapshot, true);
+
+ // Get the histogram from the snapshot
+ JS::Rooted<JS::Value> histogram(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "TELEMETRY_TEST_KEYED_COUNT", snapshot,
+ &histogram);
+
+ // Get "sample" property from histogram
+ JS::Rooted<JS::Value> expectedKeyData(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "sample", histogram, &expectedKeyData);
+
+ // Get "sum" property from keyed data
+ JS::Rooted<JS::Value> sum(cx.GetJSContext());
+ GetProperty(cx.GetJSContext(), "sum", expectedKeyData, &sum);
+
+ // Check that the sum stored in the histogram matches with |kExpectedValue|
+ uint32_t uSum = 0;
+ JS::ToUint32(cx.GetJSContext(), sum, &uSum);
+ ASSERT_EQ(uSum, kExpectedValue)
+ << "The histogram is not returning expected sum";
+}