/* 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 snapshot(cx.GetJSContext()); GetSnapshots(cx.GetJSContext(), mTelemetry, telemetryTestCountName, &snapshot, false); // Get the histogram from the snapshot JS::Rooted histogram(cx.GetJSContext()); GetProperty(cx.GetJSContext(), telemetryTestCountName, snapshot, &histogram); // Get "sum" property from histogram JS::Rooted 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 snapshot(cx.GetJSContext()); GetSnapshots(cx.GetJSContext(), mTelemetry, "TELEMETRY_TEST_KEYED_COUNT", &snapshot, true); // Get the histogram from the snapshot JS::Rooted histogram(cx.GetJSContext()); GetProperty(cx.GetJSContext(), "TELEMETRY_TEST_KEYED_COUNT", snapshot, &histogram); // Get "sample" property from histogram JS::Rooted expectedKeyData(cx.GetJSContext()); GetProperty(cx.GetJSContext(), "sample", histogram, &expectedKeyData); // Get "sum" property from keyed data JS::Rooted 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 testHistogram(cx.GetJSContext()); JS::Rooted 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 snapshot(cx.GetJSContext()); GetSnapshots(cx.GetJSContext(), mTelemetry, "TELEMETRY_TEST_KEYED_KEYS", &snapshot, true); // Get the histogram from the snapshot JS::Rooted 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 expectedKeyData(cx.GetJSContext()); GetProperty(cx.GetJSContext(), "testkey", histogram, &expectedKeyData); ASSERT_TRUE(!expectedKeyData.isUndefined()) << "Cannot find the expected key in the histogram data"; JS::Rooted 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 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 snapshot(cx.GetJSContext()); GetSnapshots(cx.GetJSContext(), mTelemetry, "TELEMETRY_TEST_CATEGORICAL", &snapshot, false); // Get our histogram from the snapshot JS::Rooted 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 values(cx.GetJSContext()); GetProperty(cx.GetJSContext(), "values", histogram, &values); // Get the value for the label we care about JS::Rooted value(cx.GetJSContext()); GetElement(cx.GetJSContext(), static_cast( 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 snapshot(cx.GetJSContext()); GetSnapshots(cx.GetJSContext(), mTelemetry, "TELEMETRY_TEST_KEYED_CATEGORICAL", &snapshot, true); // Get the histogram from the snapshot JS::Rooted histogram(cx.GetJSContext()); GetProperty(cx.GetJSContext(), "TELEMETRY_TEST_KEYED_CATEGORICAL", snapshot, &histogram); // Check that the sample histogram contains the values we expect JS::Rooted 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 sampleValues(cx.GetJSContext()); GetProperty(cx.GetJSContext(), "values", sample, &sampleValues); // Get the value for the label we care about JS::Rooted sampleValue(cx.GetJSContext()); GetElement( cx.GetJSContext(), static_cast( 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 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 otherValues(cx.GetJSContext()); GetProperty(cx.GetJSContext(), "values", otherSample, &otherValues); // Get the value for the label we care about JS::Rooted otherValue(cx.GetJSContext()); GetElement( cx.GetJSContext(), static_cast( 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 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 snapshot(cx.GetJSContext()); GetSnapshots(cx.GetJSContext(), mTelemetry, "TELEMETRY_TEST_COUNT", &snapshot, false); // Get histogram from snapshot JS::Rooted histogram(cx.GetJSContext()); GetProperty(cx.GetJSContext(), "TELEMETRY_TEST_COUNT", snapshot, &histogram); // Get "sum" from histogram JS::Rooted 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 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 snapshot(cx.GetJSContext()); GetSnapshots(cx.GetJSContext(), mTelemetry, "TELEMETRY_TEST_LINEAR", &snapshot, false); // Get histogram from snapshot JS::Rooted histogram(cx.GetJSContext()); GetProperty(cx.GetJSContext(), "TELEMETRY_TEST_LINEAR", snapshot, &histogram); // Get "values" object from histogram JS::Rooted 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 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 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 snapshot(cx.GetJSContext()); GetSnapshots(cx.GetJSContext(), mTelemetry, "TELEMETRY_TEST_LINEAR", &snapshot, false); // Get histogram from snapshot JS::Rooted histogram(cx.GetJSContext()); GetProperty(cx.GetJSContext(), "TELEMETRY_TEST_LINEAR", snapshot, &histogram); // Get values object from histogram JS::Rooted values(cx.GetJSContext()); GetProperty(cx.GetJSContext(), "values", histogram, &values); // Get values in first and last buckets JS::Rooted countFirst(cx.GetJSContext()); JS::Rooted 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 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 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 snapshot(cx.GetJSContext()); GetSnapshots(cx.GetJSContext(), mTelemetry, "TELEMETRY_TEST_KEYED_COUNT", &snapshot, true); // Get the histogram from the snapshot JS::Rooted histogram(cx.GetJSContext()); GetProperty(cx.GetJSContext(), "TELEMETRY_TEST_KEYED_COUNT", snapshot, &histogram); // Get "sample" property from histogram JS::Rooted expectedKeyData(cx.GetJSContext()); GetProperty(cx.GetJSContext(), "sample", histogram, &expectedKeyData); // Get "sum" property from keyed data JS::Rooted 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 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 snapshot(cx.GetJSContext()); GetSnapshots(cx.GetJSContext(), mTelemetry, "TELEMETRY_TEST_KEYED_LINEAR", &snapshot, true); // Get the histogram from the snapshot JS::Rooted histogram(cx.GetJSContext()); GetProperty(cx.GetJSContext(), "TELEMETRY_TEST_KEYED_LINEAR", snapshot, &histogram); // Get "testkey" property from histogram. JS::Rooted 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 values(cx.GetJSContext()); GetProperty(cx.GetJSContext(), "values", expectedKeyData, &values); // Get values in first and last buckets. JS::Rooted countFirst(cx.GetJSContext()); JS::Rooted 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 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 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 snapshot(cx.GetJSContext()); GetSnapshots(cx.GetJSContext(), mTelemetry, "TELEMETRY_TEST_KEYED_KEYS", &snapshot, true); // Get the histogram from the snapshot JS::Rooted 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 testKeyData(cx.GetJSContext()); GetProperty(cx.GetJSContext(), "testkey", histogram, &testKeyData); ASSERT_TRUE(!testKeyData.isUndefined()) << "Cannot find the key 'testkey' in the histogram data"; JS::Rooted 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 countFalse(cx.GetJSContext()); JS::Rooted countTrue(cx.GetJSContext()); JS::Rooted 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 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 notAllowedKeyData(cx.GetJSContext()); GetProperty(cx.GetJSContext(), "not-allowed", histogram, ¬AllowedKeyData); 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 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 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 snapshot(cx.GetJSContext()); GetSnapshots(cx.GetJSContext(), mTelemetry, "TELEMETRY_TEST_CATEGORICAL", &snapshot, false); // Get our histogram from the snapshot JS::Rooted 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 values(cx.GetJSContext()); GetProperty(cx.GetJSContext(), "values", histogram, &values); // Get the value for the label we care about JS::Rooted value(cx.GetJSContext()); GetElement(cx.GetJSContext(), static_cast( 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 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( 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 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 snapshot(cx.GetJSContext()); GetSnapshots(cx.GetJSContext(), mTelemetry, "TELEMETRY_TEST_CATEGORICAL", &snapshot, false); // Get our histogram from the snapshot JS::Rooted 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 values(cx.GetJSContext()); GetProperty(cx.GetJSContext(), "values", histogram, &values); // Get the value for the label we care about JS::Rooted value(cx.GetJSContext()); GetElement(cx.GetJSContext(), static_cast( 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 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 snapshot(cx.GetJSContext()); GetSnapshots(cx.GetJSContext(), mTelemetry, "TELEMETRY_TEST_KEYED_CATEGORICAL", &snapshot, true); // Get the histogram from the snapshot JS::Rooted 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 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 sampleKeyValues(cx.GetJSContext()); GetProperty(cx.GetJSContext(), "values", sample, &sampleKeyValues); // Get the count of CommonLabel JS::Rooted commonLabelValue(cx.GetJSContext()); GetElement( cx.GetJSContext(), static_cast( 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 label2Value(cx.GetJSContext()); GetElement(cx.GetJSContext(), static_cast( 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 snapshot(cx.GetJSContext()); GetSnapshots(cx.GetJSContext(), mTelemetry, "TELEMETRY_TEST_COUNT", &snapshot, false); // Get the histogram from the snapshot JS::Rooted histogram(cx.GetJSContext()); GetProperty(cx.GetJSContext(), "TELEMETRY_TEST_COUNT", snapshot, &histogram); // Get "sum" property from histogram JS::Rooted 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 snapshot(cx.GetJSContext()); GetSnapshots(cx.GetJSContext(), mTelemetry, "TELEMETRY_TEST_KEYED_COUNT", &snapshot, true); // Get the histogram from the snapshot JS::Rooted histogram(cx.GetJSContext()); GetProperty(cx.GetJSContext(), "TELEMETRY_TEST_KEYED_COUNT", snapshot, &histogram); // Get "sample" property from histogram JS::Rooted expectedKeyData(cx.GetJSContext()); GetProperty(cx.GetJSContext(), "sample", histogram, &expectedKeyData); // Get "sum" property from keyed data JS::Rooted 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"; }