1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include <gtest/gtest.h>
17 #include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
18 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
19 #include "matchers/matcher_util.h"
20 #include "src/logd/LogEvent.h"
21 #include "stats_log_util.h"
22 #include "stats_util.h"
23 #include "subscriber/SubscriberReporter.h"
24
25 #ifdef __ANDROID__
26
27 using android::util::ProtoReader;
28
29 namespace android {
30 namespace os {
31 namespace statsd {
32
TEST(AtomMatcherTest,TestFieldTranslation)33 TEST(AtomMatcherTest, TestFieldTranslation) {
34 FieldMatcher matcher1;
35 matcher1.set_field(10);
36 FieldMatcher* child = matcher1.add_child();
37 child->set_field(1);
38 child->set_position(Position::ANY);
39
40 child = child->add_child();
41 child->set_field(1);
42
43 vector<Matcher> output;
44 translateFieldMatcher(matcher1, &output);
45
46 EXPECT_EQ((size_t)1, output.size());
47
48 const auto& matcher12 = output[0];
49 EXPECT_EQ((int32_t)10, matcher12.mMatcher.getTag());
50 EXPECT_EQ((int32_t)0x02010001, matcher12.mMatcher.getField());
51 EXPECT_EQ((int32_t)0xff7f007f, matcher12.mMask);
52 }
53
TEST(AtomMatcherTest,TestFieldTranslation_ALL)54 TEST(AtomMatcherTest, TestFieldTranslation_ALL) {
55 FieldMatcher matcher1;
56 matcher1.set_field(10);
57 FieldMatcher* child = matcher1.add_child();
58 child->set_field(1);
59 child->set_position(Position::ALL);
60
61 child = child->add_child();
62 child->set_field(1);
63
64 vector<Matcher> output;
65 translateFieldMatcher(matcher1, &output);
66
67 EXPECT_EQ((size_t)1, output.size());
68
69 const auto& matcher12 = output[0];
70 EXPECT_EQ((int32_t)10, matcher12.mMatcher.getTag());
71 EXPECT_EQ((int32_t)0x02010001, matcher12.mMatcher.getField());
72 EXPECT_EQ((int32_t)0xff7f7f7f, matcher12.mMask);
73 }
74
TEST(AtomMatcherTest,TestFilter_ALL)75 TEST(AtomMatcherTest, TestFilter_ALL) {
76 FieldMatcher matcher1;
77 matcher1.set_field(10);
78 FieldMatcher* child = matcher1.add_child();
79 child->set_field(1);
80 child->set_position(Position::ALL);
81
82 child->add_child()->set_field(1);
83 child->add_child()->set_field(2);
84
85 child = matcher1.add_child();
86 child->set_field(2);
87
88 vector<Matcher> matchers;
89 translateFieldMatcher(matcher1, &matchers);
90
91 AttributionNodeInternal attribution_node1;
92 attribution_node1.set_uid(1111);
93 attribution_node1.set_tag("location1");
94
95 AttributionNodeInternal attribution_node2;
96 attribution_node2.set_uid(2222);
97 attribution_node2.set_tag("location2");
98
99 AttributionNodeInternal attribution_node3;
100 attribution_node3.set_uid(3333);
101 attribution_node3.set_tag("location3");
102 std::vector<AttributionNodeInternal> attribution_nodes = {attribution_node1, attribution_node2,
103 attribution_node3};
104
105 // Set up the event
106 LogEvent event(10, 12345);
107 event.write(attribution_nodes);
108 event.write("some value");
109 // Convert to a LogEvent
110 event.init();
111 HashableDimensionKey output;
112
113 filterValues(matchers, event.getValues(), &output);
114
115 EXPECT_EQ((size_t)7, output.getValues().size());
116 EXPECT_EQ((int32_t)0x02010101, output.getValues()[0].mField.getField());
117 EXPECT_EQ((int32_t)1111, output.getValues()[0].mValue.int_value);
118 EXPECT_EQ((int32_t)0x02010102, output.getValues()[1].mField.getField());
119 EXPECT_EQ("location1", output.getValues()[1].mValue.str_value);
120
121 EXPECT_EQ((int32_t)0x02010201, output.getValues()[2].mField.getField());
122 EXPECT_EQ((int32_t)2222, output.getValues()[2].mValue.int_value);
123 EXPECT_EQ((int32_t)0x02010202, output.getValues()[3].mField.getField());
124 EXPECT_EQ("location2", output.getValues()[3].mValue.str_value);
125
126 EXPECT_EQ((int32_t)0x02010301, output.getValues()[4].mField.getField());
127 EXPECT_EQ((int32_t)3333, output.getValues()[4].mValue.int_value);
128 EXPECT_EQ((int32_t)0x02010302, output.getValues()[5].mField.getField());
129 EXPECT_EQ("location3", output.getValues()[5].mValue.str_value);
130
131 EXPECT_EQ((int32_t)0x00020000, output.getValues()[6].mField.getField());
132 EXPECT_EQ("some value", output.getValues()[6].mValue.str_value);
133 }
134
TEST(AtomMatcherTest,TestSubDimension)135 TEST(AtomMatcherTest, TestSubDimension) {
136 HashableDimensionKey dim;
137
138 int pos1[] = {1, 1, 1};
139 int pos2[] = {1, 1, 2};
140 int pos3[] = {1, 1, 3};
141 int pos4[] = {2, 0, 0};
142 Field field1(10, pos1, 2);
143 Field field2(10, pos2, 2);
144
145 Field field3(10, pos3, 2);
146 Field field4(10, pos4, 0);
147
148 Value value1((int32_t)10025);
149 Value value2("tag");
150
151 Value value11((int32_t)10026);
152 Value value22("tag2");
153
154 dim.addValue(FieldValue(field1, value1));
155 dim.addValue(FieldValue(field2, value2));
156
157 HashableDimensionKey subDim1;
158 subDim1.addValue(FieldValue(field1, value1));
159
160 HashableDimensionKey subDim2;
161 subDim1.addValue(FieldValue(field2, value2));
162
163 EXPECT_TRUE(dim.contains(dim));
164 EXPECT_TRUE(dim.contains(subDim1));
165 EXPECT_TRUE(dim.contains(subDim2));
166
167 HashableDimensionKey subDim3;
168 subDim3.addValue(FieldValue(field1, value11));
169 EXPECT_FALSE(dim.contains(subDim3));
170
171 HashableDimensionKey subDim4;
172 // Empty dimension is always a sub dimension of other dimensions
173 EXPECT_TRUE(dim.contains(subDim4));
174 }
175
TEST(AtomMatcherTest,TestMetric2ConditionLink)176 TEST(AtomMatcherTest, TestMetric2ConditionLink) {
177 AttributionNodeInternal attribution_node1;
178 attribution_node1.set_uid(1111);
179 attribution_node1.set_tag("location1");
180
181 AttributionNodeInternal attribution_node2;
182 attribution_node2.set_uid(2222);
183 attribution_node2.set_tag("location2");
184
185 AttributionNodeInternal attribution_node3;
186 attribution_node3.set_uid(3333);
187 attribution_node3.set_tag("location3");
188 std::vector<AttributionNodeInternal> attribution_nodes = {attribution_node1, attribution_node2,
189 attribution_node3};
190
191 // Set up the event
192 LogEvent event(10, 12345);
193 event.write(attribution_nodes);
194 event.write("some value");
195 // Convert to a LogEvent
196 event.init();
197
198 FieldMatcher whatMatcher;
199 whatMatcher.set_field(10);
200 FieldMatcher* child11 = whatMatcher.add_child();
201 child11->set_field(1);
202 child11->set_position(Position::ANY);
203 child11 = child11->add_child();
204 child11->set_field(1);
205
206 FieldMatcher conditionMatcher;
207 conditionMatcher.set_field(27);
208 FieldMatcher* child2 = conditionMatcher.add_child();
209 child2->set_field(2);
210 child2->set_position(Position::LAST);
211
212 child2 = child2->add_child();
213 child2->set_field(2);
214
215 Metric2Condition link;
216
217 translateFieldMatcher(whatMatcher, &link.metricFields);
218 translateFieldMatcher(conditionMatcher, &link.conditionFields);
219
220 EXPECT_EQ((size_t)1, link.metricFields.size());
221 EXPECT_EQ((int32_t)0x02010001, link.metricFields[0].mMatcher.getField());
222 EXPECT_EQ((int32_t)0xff7f007f, link.metricFields[0].mMask);
223 EXPECT_EQ((int32_t)10, link.metricFields[0].mMatcher.getTag());
224
225 EXPECT_EQ((size_t)1, link.conditionFields.size());
226 EXPECT_EQ((int32_t)0x02028002, link.conditionFields[0].mMatcher.getField());
227 EXPECT_EQ((int32_t)0xff7f807f, link.conditionFields[0].mMask);
228 EXPECT_EQ((int32_t)27, link.conditionFields[0].mMatcher.getTag());
229 }
230
TEST(AtomMatcherTest,TestWriteDimensionPath)231 TEST(AtomMatcherTest, TestWriteDimensionPath) {
232 for (auto position : {Position::ANY, Position::ALL, Position::FIRST, Position::LAST}) {
233 FieldMatcher matcher1;
234 matcher1.set_field(10);
235 FieldMatcher* child = matcher1.add_child();
236 child->set_field(2);
237 child->set_position(position);
238 child->add_child()->set_field(1);
239 child->add_child()->set_field(3);
240
241 child = matcher1.add_child();
242 child->set_field(4);
243
244 child = matcher1.add_child();
245 child->set_field(6);
246 child->add_child()->set_field(2);
247
248 vector<Matcher> matchers;
249 translateFieldMatcher(matcher1, &matchers);
250
251 android::util::ProtoOutputStream protoOut;
252 writeDimensionPathToProto(matchers, &protoOut);
253
254 vector<uint8_t> outData;
255 outData.resize(protoOut.size());
256 size_t pos = 0;
257 sp<ProtoReader> reader = protoOut.data();
258 while (reader->readBuffer() != NULL) {
259 size_t toRead = reader->currentToRead();
260 std::memcpy(&(outData[pos]), reader->readBuffer(), toRead);
261 pos += toRead;
262 reader->move(toRead);
263 }
264
265 DimensionsValue result;
266 EXPECT_EQ(true, result.ParseFromArray(&outData[0], outData.size()));
267
268 EXPECT_EQ(10, result.field());
269 EXPECT_EQ(DimensionsValue::ValueCase::kValueTuple, result.value_case());
270 EXPECT_EQ(3, result.value_tuple().dimensions_value_size());
271
272 const auto& dim1 = result.value_tuple().dimensions_value(0);
273 EXPECT_EQ(2, dim1.field());
274 EXPECT_EQ(2, dim1.value_tuple().dimensions_value_size());
275
276 const auto& dim11 = dim1.value_tuple().dimensions_value(0);
277 EXPECT_EQ(1, dim11.field());
278
279 const auto& dim12 = dim1.value_tuple().dimensions_value(1);
280 EXPECT_EQ(3, dim12.field());
281
282 const auto& dim2 = result.value_tuple().dimensions_value(1);
283 EXPECT_EQ(4, dim2.field());
284
285 const auto& dim3 = result.value_tuple().dimensions_value(2);
286 EXPECT_EQ(6, dim3.field());
287 EXPECT_EQ(1, dim3.value_tuple().dimensions_value_size());
288 const auto& dim31 = dim3.value_tuple().dimensions_value(0);
289 EXPECT_EQ(2, dim31.field());
290 }
291 }
292
TEST(AtomMatcherTest,TestSubscriberDimensionWrite)293 TEST(AtomMatcherTest, TestSubscriberDimensionWrite) {
294 HashableDimensionKey dim;
295
296 int pos1[] = {1, 1, 1};
297 int pos2[] = {1, 1, 2};
298 int pos3[] = {1, 1, 3};
299 int pos4[] = {2, 0, 0};
300
301 Field field1(10, pos1, 2);
302 Field field2(10, pos2, 2);
303 Field field3(10, pos3, 2);
304 Field field4(10, pos4, 0);
305
306 Value value1((int32_t)10025);
307 Value value2("tag");
308 Value value3((int32_t)987654);
309 Value value4((int32_t)99999);
310
311 dim.addValue(FieldValue(field1, value1));
312 dim.addValue(FieldValue(field2, value2));
313 dim.addValue(FieldValue(field3, value3));
314 dim.addValue(FieldValue(field4, value4));
315
316 SubscriberReporter::getStatsDimensionsValue(dim);
317 // TODO(b/110562792): can't test anything here because StatsDimensionsValue class doesn't
318 // have any read api.
319 }
320
TEST(AtomMatcherTest,TestWriteDimensionToProto)321 TEST(AtomMatcherTest, TestWriteDimensionToProto) {
322 HashableDimensionKey dim;
323 int pos1[] = {1, 1, 1};
324 int pos2[] = {1, 1, 2};
325 int pos3[] = {1, 1, 3};
326 int pos4[] = {2, 0, 0};
327 Field field1(10, pos1, 2);
328 Field field2(10, pos2, 2);
329 Field field3(10, pos3, 2);
330 Field field4(10, pos4, 0);
331
332 Value value1((int32_t)10025);
333 Value value2("tag");
334 Value value3((int32_t)987654);
335 Value value4((int32_t)99999);
336
337 dim.addValue(FieldValue(field1, value1));
338 dim.addValue(FieldValue(field2, value2));
339 dim.addValue(FieldValue(field3, value3));
340 dim.addValue(FieldValue(field4, value4));
341
342 android::util::ProtoOutputStream protoOut;
343 writeDimensionToProto(dim, nullptr /* include strings */, &protoOut);
344
345 vector<uint8_t> outData;
346 outData.resize(protoOut.size());
347 size_t pos = 0;
348 sp<ProtoReader> reader = protoOut.data();
349 while (reader->readBuffer() != NULL) {
350 size_t toRead = reader->currentToRead();
351 std::memcpy(&(outData[pos]), reader->readBuffer(), toRead);
352 pos += toRead;
353 reader->move(toRead);
354 }
355
356 DimensionsValue result;
357 EXPECT_EQ(true, result.ParseFromArray(&outData[0], outData.size()));
358 EXPECT_EQ(10, result.field());
359 EXPECT_EQ(DimensionsValue::ValueCase::kValueTuple, result.value_case());
360 EXPECT_EQ(2, result.value_tuple().dimensions_value_size());
361
362 const auto& dim1 = result.value_tuple().dimensions_value(0);
363 EXPECT_EQ(DimensionsValue::ValueCase::kValueTuple, dim1.value_case());
364 EXPECT_EQ(3, dim1.value_tuple().dimensions_value_size());
365
366 const auto& dim11 = dim1.value_tuple().dimensions_value(0);
367 EXPECT_EQ(DimensionsValue::ValueCase::kValueInt, dim11.value_case());
368 EXPECT_EQ(10025, dim11.value_int());
369
370 const auto& dim12 = dim1.value_tuple().dimensions_value(1);
371 EXPECT_EQ(DimensionsValue::ValueCase::kValueStr, dim12.value_case());
372 EXPECT_EQ("tag", dim12.value_str());
373
374 const auto& dim13 = dim1.value_tuple().dimensions_value(2);
375 EXPECT_EQ(DimensionsValue::ValueCase::kValueInt, dim13.value_case());
376 EXPECT_EQ(987654, dim13.value_int());
377
378 const auto& dim2 = result.value_tuple().dimensions_value(1);
379 EXPECT_EQ(DimensionsValue::ValueCase::kValueInt, dim2.value_case());
380 EXPECT_EQ(99999, dim2.value_int());
381 }
382
TEST(AtomMatcherTest,TestWriteDimensionLeafNodesToProto)383 TEST(AtomMatcherTest, TestWriteDimensionLeafNodesToProto) {
384 HashableDimensionKey dim;
385 int pos1[] = {1, 1, 1};
386 int pos2[] = {1, 1, 2};
387 int pos3[] = {1, 1, 3};
388 int pos4[] = {2, 0, 0};
389 Field field1(10, pos1, 2);
390 Field field2(10, pos2, 2);
391 Field field3(10, pos3, 2);
392 Field field4(10, pos4, 0);
393
394 Value value1((int32_t)10025);
395 Value value2("tag");
396 Value value3((int32_t)987654);
397 Value value4((int64_t)99999);
398
399 dim.addValue(FieldValue(field1, value1));
400 dim.addValue(FieldValue(field2, value2));
401 dim.addValue(FieldValue(field3, value3));
402 dim.addValue(FieldValue(field4, value4));
403
404 android::util::ProtoOutputStream protoOut;
405 writeDimensionLeafNodesToProto(dim, 1, nullptr /* include strings */, &protoOut);
406
407 vector<uint8_t> outData;
408 outData.resize(protoOut.size());
409 size_t pos = 0;
410 sp<ProtoReader> reader = protoOut.data();
411 while (reader->readBuffer() != NULL) {
412 size_t toRead = reader->currentToRead();
413 std::memcpy(&(outData[pos]), reader->readBuffer(), toRead);
414 pos += toRead;
415 reader->move(toRead);
416 }
417
418 DimensionsValueTuple result;
419 EXPECT_EQ(true, result.ParseFromArray(&outData[0], outData.size()));
420 EXPECT_EQ(4, result.dimensions_value_size());
421
422 const auto& dim1 = result.dimensions_value(0);
423 EXPECT_EQ(DimensionsValue::ValueCase::kValueInt, dim1.value_case());
424 EXPECT_EQ(10025, dim1.value_int());
425
426 const auto& dim2 = result.dimensions_value(1);
427 EXPECT_EQ(DimensionsValue::ValueCase::kValueStr, dim2.value_case());
428 EXPECT_EQ("tag", dim2.value_str());
429
430 const auto& dim3 = result.dimensions_value(2);
431 EXPECT_EQ(DimensionsValue::ValueCase::kValueInt, dim3.value_case());
432 EXPECT_EQ(987654, dim3.value_int());
433
434 const auto& dim4 = result.dimensions_value(3);
435 EXPECT_EQ(DimensionsValue::ValueCase::kValueLong, dim4.value_case());
436 EXPECT_EQ(99999, dim4.value_long());
437 }
438
TEST(AtomMatcherTest,TestWriteAtomToProto)439 TEST(AtomMatcherTest, TestWriteAtomToProto) {
440 AttributionNodeInternal attribution_node1;
441 attribution_node1.set_uid(1111);
442 attribution_node1.set_tag("location1");
443
444 AttributionNodeInternal attribution_node2;
445 attribution_node2.set_uid(2222);
446 attribution_node2.set_tag("location2");
447
448 std::vector<AttributionNodeInternal> attribution_nodes = {attribution_node1, attribution_node2};
449
450 // Set up the event
451 LogEvent event(4, 12345);
452 event.write(attribution_nodes);
453 event.write((int32_t)999);
454 // Convert to a LogEvent
455 event.init();
456
457 android::util::ProtoOutputStream protoOutput;
458 writeFieldValueTreeToStream(event.GetTagId(), event.getValues(), &protoOutput);
459
460 vector<uint8_t> outData;
461 outData.resize(protoOutput.size());
462 size_t pos = 0;
463 sp<ProtoReader> reader = protoOutput.data();
464 while (reader->readBuffer() != NULL) {
465 size_t toRead = reader->currentToRead();
466 std::memcpy(&(outData[pos]), reader->readBuffer(), toRead);
467 pos += toRead;
468 reader->move(toRead);
469 }
470
471 Atom result;
472 EXPECT_EQ(true, result.ParseFromArray(&outData[0], outData.size()));
473 EXPECT_EQ(Atom::PushedCase::kBleScanResultReceived, result.pushed_case());
474 const auto& atom = result.ble_scan_result_received();
475 EXPECT_EQ(2, atom.attribution_node_size());
476 EXPECT_EQ(1111, atom.attribution_node(0).uid());
477 EXPECT_EQ("location1", atom.attribution_node(0).tag());
478 EXPECT_EQ(2222, atom.attribution_node(1).uid());
479 EXPECT_EQ("location2", atom.attribution_node(1).tag());
480 EXPECT_EQ(999, atom.num_results());
481 }
482
483
484 } // namespace statsd
485 } // namespace os
486 } // namespace android
487 #else
488 GTEST_LOG_(INFO) << "This test does nothing.\n";
489 #endif
490