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