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