1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
|
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
#include "TelemetryTestHelpers.h"
#include "gtest/gtest.h"
#include "mozilla/CycleCollectedJSContext.h"
#include "mozilla/Unused.h"
using namespace mozilla;
// Helper methods provided to simplify writing tests and meant to be used in C++
// Gtests.
namespace TelemetryTestHelpers {
void CheckUintScalar(const char* aName, JSContext* aCx,
JS::HandleValue aSnapshot, uint32_t expectedValue) {
// Validate the value of the test scalar.
JS::RootedValue value(aCx);
JS::RootedObject scalarObj(aCx, &aSnapshot.toObject());
ASSERT_TRUE(JS_GetProperty(aCx, scalarObj, aName, &value))
<< "The test scalar must be reported.";
JS_GetProperty(aCx, scalarObj, aName, &value);
ASSERT_TRUE(value.isInt32())
<< "The scalar value must be of the correct type.";
ASSERT_TRUE(value.toInt32() >= 0)
<< "The uint scalar type must contain a value >= 0.";
ASSERT_EQ(static_cast<uint32_t>(value.toInt32()), expectedValue)
<< "The scalar value must match the expected value.";
}
void CheckBoolScalar(const char* aName, JSContext* aCx,
JS::HandleValue aSnapshot, bool expectedValue) {
// Validate the value of the test scalar.
JS::RootedValue value(aCx);
JS::RootedObject scalarObj(aCx, &aSnapshot.toObject());
ASSERT_TRUE(JS_GetProperty(aCx, scalarObj, aName, &value))
<< "The test scalar must be reported.";
ASSERT_TRUE(value.isBoolean())
<< "The scalar value must be of the correct type.";
ASSERT_EQ(static_cast<bool>(value.toBoolean()), expectedValue)
<< "The scalar value must match the expected value.";
}
void CheckStringScalar(const char* aName, JSContext* aCx,
JS::HandleValue aSnapshot, const char* expectedValue) {
// Validate the value of the test scalar.
JS::RootedValue value(aCx);
JS::RootedObject scalarObj(aCx, &aSnapshot.toObject());
ASSERT_TRUE(JS_GetProperty(aCx, scalarObj, aName, &value))
<< "The test scalar must be reported.";
ASSERT_TRUE(value.isString())
<< "The scalar value must be of the correct type.";
bool sameString;
ASSERT_TRUE(
JS_StringEqualsAscii(aCx, value.toString(), expectedValue, &sameString))
<< "JS String comparison failed";
ASSERT_TRUE(sameString) << "The scalar value must match the expected string";
}
void CheckKeyedUintScalar(const char* aName, const char* aKey, JSContext* aCx,
JS::HandleValue aSnapshot, uint32_t expectedValue) {
JS::RootedValue keyedScalar(aCx);
JS::RootedObject scalarObj(aCx, &aSnapshot.toObject());
// Get the aName keyed scalar object from the scalars snapshot.
ASSERT_TRUE(JS_GetProperty(aCx, scalarObj, aName, &keyedScalar))
<< "The keyed scalar must be reported.";
CheckUintScalar(aKey, aCx, keyedScalar, expectedValue);
}
void CheckKeyedBoolScalar(const char* aName, const char* aKey, JSContext* aCx,
JS::HandleValue aSnapshot, bool expectedValue) {
JS::RootedValue keyedScalar(aCx);
JS::RootedObject scalarObj(aCx, &aSnapshot.toObject());
// Get the aName keyed scalar object from the scalars snapshot.
ASSERT_TRUE(JS_GetProperty(aCx, scalarObj, aName, &keyedScalar))
<< "The keyed scalar must be reported.";
CheckBoolScalar(aKey, aCx, keyedScalar, expectedValue);
}
void CheckNumberOfProperties(const char* aName, JSContext* aCx,
JS::HandleValue aSnapshot,
uint32_t expectedNumProperties) {
JS::RootedValue keyedScalar(aCx);
JS::RootedObject scalarObj(aCx, &aSnapshot.toObject());
// Get the aName keyed scalar object from the scalars snapshot.
ASSERT_TRUE(JS_GetProperty(aCx, scalarObj, aName, &keyedScalar))
<< "The keyed scalar must be reported.";
JS::RootedObject keyedScalarObj(aCx, &keyedScalar.toObject());
JS::Rooted<JS::IdVector> ids(aCx, JS::IdVector(aCx));
ASSERT_TRUE(JS_Enumerate(aCx, keyedScalarObj, &ids))
<< "We must be able to get keyed scalar members.";
ASSERT_EQ(expectedNumProperties, ids.length())
<< "The scalar must report the expected number of properties.";
}
void GetScalarsSnapshot(bool aKeyed, JSContext* aCx,
JS::MutableHandle<JS::Value> aResult) {
nsCOMPtr<nsITelemetry> telemetry =
do_GetService("@mozilla.org/base/telemetry;1");
// Get a snapshot of the scalars.
JS::RootedValue scalarsSnapshot(aCx);
nsresult rv;
if (aKeyed) {
rv = telemetry->SnapshotKeyedScalars(
nsITelemetry::DATASET_RELEASE_CHANNEL_OPTIN, false, aCx, 0,
&scalarsSnapshot);
} else {
rv = telemetry->SnapshotScalars(nsITelemetry::DATASET_RELEASE_CHANNEL_OPTIN,
false, aCx, 0, &scalarsSnapshot);
}
// Validate the snapshot.
ASSERT_EQ(rv, NS_OK) << "Creating a snapshot of the data must not fail.";
ASSERT_TRUE(scalarsSnapshot.isObject()) << "The snapshot must be an object.";
// We currently only support scalars from the parent process in the gtests.
JS::RootedValue parentScalars(aCx);
JS::RootedObject scalarObj(aCx, &scalarsSnapshot.toObject());
// Don't complain if no scalars for the parent process can be found. Just
// return an empty object.
Unused << JS_GetProperty(aCx, scalarObj, "parent", &parentScalars);
aResult.set(parentScalars);
}
void GetAndClearHistogram(JSContext* cx, nsCOMPtr<nsITelemetry> mTelemetry,
const nsACString& name, bool is_keyed) {
JS::RootedValue testHistogram(cx);
nsresult rv =
is_keyed ? mTelemetry->GetKeyedHistogramById(name, cx, &testHistogram)
: mTelemetry->GetHistogramById(name, cx, &testHistogram);
ASSERT_EQ(rv, NS_OK) << "Cannot fetch histogram";
// Clear the stored value
JS::RootedObject testHistogramObj(cx, &testHistogram.toObject());
JS::RootedValue rval(cx);
ASSERT_TRUE(JS_CallFunctionName(cx, testHistogramObj, "clear",
JS::HandleValueArray::empty(), &rval))
<< "Cannot clear histogram";
}
void GetProperty(JSContext* cx, const char* name, JS::HandleValue valueIn,
JS::MutableHandleValue valueOut) {
JS::RootedValue property(cx);
JS::RootedObject valueInObj(cx, &valueIn.toObject());
ASSERT_TRUE(JS_GetProperty(cx, valueInObj, name, &property))
<< "Cannot get property '" << name << "'";
valueOut.set(property);
}
void GetElement(JSContext* cx, uint32_t index, JS::HandleValue valueIn,
JS::MutableHandleValue valueOut) {
JS::RootedValue element(cx);
JS::RootedObject valueInObj(cx, &valueIn.toObject());
ASSERT_TRUE(JS_GetElement(cx, valueInObj, index, &element))
<< "Cannot get element at index '" << index << "'";
valueOut.set(element);
}
void GetSnapshots(JSContext* cx, nsCOMPtr<nsITelemetry> mTelemetry,
const char* name, JS::MutableHandleValue valueOut,
bool is_keyed) {
JS::RootedValue snapshots(cx);
nsresult rv = is_keyed ? mTelemetry->SnapshotKeyedHistograms(
nsITelemetry::DATASET_RELEASE_CHANNEL_OPTIN,
false, false, cx, &snapshots)
: mTelemetry->SnapshotHistograms(
nsITelemetry::DATASET_RELEASE_CHANNEL_OPTIN,
false, false, cx, &snapshots);
JS::RootedValue snapshot(cx);
GetProperty(cx, "parent", snapshots, &snapshot);
ASSERT_EQ(rv, NS_OK) << "Cannot call histogram snapshots";
valueOut.set(snapshot);
}
} // namespace TelemetryTestHelpers
|