• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2021 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <gtest/gtest.h>
16 
17 #include "src/StatsLogProcessor.h"
18 #include "tests/statsd_test_util.h"
19 
20 namespace android {
21 namespace os {
22 namespace statsd {
23 
24 #ifdef __ANDROID__
25 
26 using namespace std;
27 
28 namespace {
29 
CreateTestAtomReportedEvent(const uint64_t timestampNs,const long longField,const string & stringField)30 unique_ptr<LogEvent> CreateTestAtomReportedEvent(const uint64_t timestampNs, const long longField,
31                                                  const string& stringField) {
32     return CreateTestAtomReportedEvent(
33             timestampNs, /* attributionUids */ {1001},
34             /* attributionTags */ {"app1"}, /* intField */ 0, longField, /* floatField */ 0.0f,
35             stringField, /* boolField */ false, TestAtomReported::OFF, /* bytesField */ {},
36             /* repeatedIntField */ {}, /* repeatedLongField */ {}, /* repeatedFloatField */ {},
37             /* repeatedStringField */ {}, /* repeatedBoolField */ {},
38             /* repeatedBoolFieldLength */ 0, /* repeatedEnumField */ {});
39 }
40 
41 }  // anonymous namespace.
42 
43 class KllMetricE2eTest : public ::testing::Test {
44 protected:
SetUp()45     void SetUp() override {
46         key = ConfigKey(123, 987);
47         bucketStartTimeNs = getElapsedRealtimeNs();
48         bucketSizeNs = TimeUnitToBucketSizeInMillis(TEN_MINUTES) * 1000000LL;
49         whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
50         metric = createKllMetric("ScreenBrightness", whatMatcher, /*valueField=*/1,
51                                  /*condition=*/nullopt);
52 
53         config.add_allowed_log_source("AID_ROOT");
54 
55         *config.add_atom_matcher() = whatMatcher;
56         *config.add_kll_metric() = metric;
57 
58         events.push_back(CreateScreenBrightnessChangedEvent(bucketStartTimeNs + 5 * NS_PER_SEC, 5));
59         events.push_back(
60                 CreateScreenBrightnessChangedEvent(bucketStartTimeNs + 15 * NS_PER_SEC, 15));
61         events.push_back(
62                 CreateScreenBrightnessChangedEvent(bucketStartTimeNs + 25 * NS_PER_SEC, 40));
63     }
64 
65     ConfigKey key;
66     uint64_t bucketStartTimeNs;
67     uint64_t bucketSizeNs;
68     AtomMatcher whatMatcher;
69     KllMetric metric;
70     StatsdConfig config;
71     vector<unique_ptr<LogEvent>> events;
72 };
73 
TEST_F(KllMetricE2eTest,TestSimpleMetric)74 TEST_F(KllMetricE2eTest, TestSimpleMetric) {
75     const sp<StatsLogProcessor> processor =
76             CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, key);
77 
78     for (auto& event : events) {
79         processor->OnLogEvent(event.get());
80     }
81 
82     uint64_t dumpTimeNs = bucketStartTimeNs + bucketSizeNs;
83     ConfigMetricsReportList reports;
84     vector<uint8_t> buffer;
85     processor->onDumpReport(key, dumpTimeNs, /*include_current_bucket*/ false, true, ADB_DUMP, FAST,
86                             &buffer);
87     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
88     backfillDimensionPath(&reports);
89     backfillStringInReport(&reports);
90     backfillStartEndTimestamp(&reports);
91     ASSERT_EQ(reports.reports_size(), 1);
92 
93     ConfigMetricsReport report = reports.reports(0);
94     ASSERT_EQ(report.metrics_size(), 1);
95     StatsLogReport metricReport = report.metrics(0);
96     EXPECT_EQ(metricReport.metric_id(), metric.id());
97     EXPECT_TRUE(metricReport.has_kll_metrics());
98     ASSERT_EQ(metricReport.kll_metrics().data_size(), 1);
99     KllMetricData data = metricReport.kll_metrics().data(0);
100     ASSERT_EQ(data.bucket_info_size(), 1);
101     KllBucketInfo bucket = data.bucket_info(0);
102     EXPECT_EQ(bucket.start_bucket_elapsed_nanos(), bucketStartTimeNs);
103     EXPECT_EQ(bucket.end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
104     EXPECT_EQ(bucket.sketches_size(), 1);
105     EXPECT_EQ(metricReport.kll_metrics().skipped_size(), 0);
106 }
107 
TEST_F(KllMetricE2eTest,TestMetricWithDimensions)108 TEST_F(KllMetricE2eTest, TestMetricWithDimensions) {
109     whatMatcher = CreateSimpleAtomMatcher("TestAtomReported", util::TEST_ATOM_REPORTED);
110     metric = createKllMetric("TestAtomMetric", whatMatcher, /* kllField */ 3,
111                              /* condition */ nullopt);
112 
113     *metric.mutable_dimensions_in_what() =
114             CreateDimensions(util::TEST_ATOM_REPORTED, {5 /* string_field */});
115 
116     config.clear_atom_matcher();
117     *config.add_atom_matcher() = whatMatcher;
118 
119     config.clear_kll_metric();
120     *config.add_kll_metric() = metric;
121 
122     events.clear();
123     events.push_back(CreateTestAtomReportedEvent(bucketStartTimeNs + 5 * NS_PER_SEC, 5l, "dim_1"));
124     events.push_back(CreateTestAtomReportedEvent(bucketStartTimeNs + 15 * NS_PER_SEC, 6l, "dim_2"));
125     events.push_back(CreateTestAtomReportedEvent(bucketStartTimeNs + 25 * NS_PER_SEC, 7l, "dim_1"));
126 
127     const sp<StatsLogProcessor> processor =
128             CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, key);
129 
130     for (auto& event : events) {
131         processor->OnLogEvent(event.get());
132     }
133 
134     uint64_t dumpTimeNs = bucketStartTimeNs + bucketSizeNs;
135     ConfigMetricsReportList reports;
136     vector<uint8_t> buffer;
137     processor->onDumpReport(key, dumpTimeNs, /*include_current_bucket*/ false, true, ADB_DUMP, FAST,
138                             &buffer);
139     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
140     backfillDimensionPath(&reports);
141     backfillStringInReport(&reports);
142     backfillStartEndTimestamp(&reports);
143     ASSERT_EQ(reports.reports_size(), 1);
144 
145     ConfigMetricsReport report = reports.reports(0);
146     ASSERT_EQ(report.metrics_size(), 1);
147     StatsLogReport metricReport = report.metrics(0);
148     EXPECT_EQ(metricReport.metric_id(), metric.id());
149     EXPECT_TRUE(metricReport.has_kll_metrics());
150     ASSERT_EQ(metricReport.kll_metrics().data_size(), 2);
151 
152     KllMetricData data = metricReport.kll_metrics().data(0);
153     ASSERT_EQ(data.bucket_info_size(), 1);
154     KllBucketInfo bucket = data.bucket_info(0);
155     EXPECT_EQ(bucket.start_bucket_elapsed_nanos(), bucketStartTimeNs);
156     EXPECT_EQ(bucket.end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
157     EXPECT_EQ(bucket.sketches_size(), 1);
158     EXPECT_EQ(metricReport.kll_metrics().skipped_size(), 0);
159     EXPECT_EQ(data.dimensions_in_what().field(), util::TEST_ATOM_REPORTED);
160     ASSERT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
161     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 5);
162     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(), "dim_1");
163 
164     data = metricReport.kll_metrics().data(1);
165     ASSERT_EQ(data.bucket_info_size(), 1);
166     bucket = data.bucket_info(0);
167     EXPECT_EQ(bucket.start_bucket_elapsed_nanos(), bucketStartTimeNs);
168     EXPECT_EQ(bucket.end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
169     EXPECT_EQ(bucket.sketches_size(), 1);
170     EXPECT_EQ(metricReport.kll_metrics().skipped_size(), 0);
171     EXPECT_EQ(data.dimensions_in_what().field(), util::TEST_ATOM_REPORTED);
172     ASSERT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
173     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 5);
174     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(), "dim_2");
175 }
176 
TEST_F(KllMetricE2eTest,TestInitWithKllFieldPositionALL)177 TEST_F(KllMetricE2eTest, TestInitWithKllFieldPositionALL) {
178     // Create config.
179     StatsdConfig config;
180     config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
181 
182     AtomMatcher testAtomReportedMatcher =
183             CreateSimpleAtomMatcher("TestAtomReportedMatcher", util::TEST_ATOM_REPORTED);
184     *config.add_atom_matcher() = testAtomReportedMatcher;
185 
186     // Create kll metric.
187     int64_t metricId = 123456;
188     KllMetric* kllMetric = config.add_kll_metric();
189     kllMetric->set_id(metricId);
190     kllMetric->set_bucket(TimeUnit::FIVE_MINUTES);
191     kllMetric->set_what(testAtomReportedMatcher.id());
192     *kllMetric->mutable_kll_field() = CreateRepeatedDimensions(
193             util::TEST_ATOM_REPORTED, {9 /*repeated_int_field*/}, {Position::ALL});
194 
195     // Initialize StatsLogProcessor.
196     const uint64_t bucketStartTimeNs = 10000000000;  // 0:10
197     int uid = 12345;
198     int64_t cfgId = 98765;
199     ConfigKey cfgKey(uid, cfgId);
200     sp<StatsLogProcessor> processor =
201             CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
202 
203     // Config initialization fails.
204     ASSERT_EQ(0, processor->mMetricsManagers.size());
205 }
206 
TEST_F(KllMetricE2eTest,TestDimensionalSampling)207 TEST_F(KllMetricE2eTest, TestDimensionalSampling) {
208     ShardOffsetProvider::getInstance().setShardOffset(5);
209 
210     // Create config.
211     StatsdConfig config;
212     config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
213 
214     AtomMatcher bleScanResultReceivedMatcher = CreateSimpleAtomMatcher(
215             "BleScanResultReceivedAtomMatcher", util::BLE_SCAN_RESULT_RECEIVED);
216     *config.add_atom_matcher() = bleScanResultReceivedMatcher;
217 
218     // Create kll metric.
219     KllMetric sampledKllMetric =
220             createKllMetric("KllSampledBleScanResultsPerUid", bleScanResultReceivedMatcher,
221                             /*num_results=*/2, nullopt);
222     *sampledKllMetric.mutable_dimensions_in_what() =
223             CreateAttributionUidDimensions(util::BLE_SCAN_RESULT_RECEIVED, {Position::FIRST});
224     *sampledKllMetric.mutable_dimensional_sampling_info()->mutable_sampled_what_field() =
225             CreateAttributionUidDimensions(util::BLE_SCAN_RESULT_RECEIVED, {Position::FIRST});
226     sampledKllMetric.mutable_dimensional_sampling_info()->set_shard_count(2);
227     *config.add_kll_metric() = sampledKllMetric;
228 
229     // Initialize StatsLogProcessor.
230     const uint64_t bucketStartTimeNs = 10000000000;  // 0:10
231     int uid = 12345;
232     int64_t cfgId = 98765;
233     ConfigKey cfgKey(uid, cfgId);
234 
235     sp<StatsLogProcessor> processor = CreateStatsLogProcessor(
236             bucketStartTimeNs, bucketStartTimeNs, config, cfgKey, nullptr, 0, new UidMap());
237 
238     int appUid1 = 1001;  // odd hash value
239     int appUid2 = 1002;  // even hash value
240     int appUid3 = 1003;  // odd hash value
241     std::vector<std::unique_ptr<LogEvent>> events;
242 
243     events.push_back(CreateBleScanResultReceivedEvent(bucketStartTimeNs + 20 * NS_PER_SEC,
244                                                       {appUid1}, {"tag1"}, 10));
245     events.push_back(CreateBleScanResultReceivedEvent(bucketStartTimeNs + 40 * NS_PER_SEC,
246                                                       {appUid2}, {"tag2"}, 10));
247     events.push_back(CreateBleScanResultReceivedEvent(bucketStartTimeNs + 60 * NS_PER_SEC,
248                                                       {appUid3}, {"tag3"}, 10));
249 
250     events.push_back(CreateBleScanResultReceivedEvent(bucketStartTimeNs + 120 * NS_PER_SEC,
251                                                       {appUid1}, {"tag1"}, 11));
252     events.push_back(CreateBleScanResultReceivedEvent(bucketStartTimeNs + 140 * NS_PER_SEC,
253                                                       {appUid2}, {"tag2"}, 12));
254     events.push_back(CreateBleScanResultReceivedEvent(bucketStartTimeNs + 160 * NS_PER_SEC,
255                                                       {appUid3}, {"tag3"}, 13));
256 
257     // Send log events to StatsLogProcessor.
258     for (auto& event : events) {
259         processor->OnLogEvent(event.get());
260     }
261 
262     // Check dump report.
263     vector<uint8_t> buffer;
264     ConfigMetricsReportList reports;
265     processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true, ADB_DUMP,
266                             FAST, &buffer);
267     ASSERT_GT(buffer.size(), 0);
268     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
269     backfillDimensionPath(&reports);
270     backfillStringInReport(&reports);
271     backfillStartEndTimestamp(&reports);
272     backfillAggregatedAtoms(&reports);
273 
274     ConfigMetricsReport report = reports.reports(0);
275     ASSERT_EQ(report.metrics_size(), 1);
276     StatsLogReport metricReport = report.metrics(0);
277     EXPECT_EQ(metricReport.metric_id(), sampledKllMetric.id());
278     EXPECT_TRUE(metricReport.has_kll_metrics());
279     StatsLogReport::KllMetricDataWrapper kllMetrics;
280     sortMetricDataByDimensionsValue(metricReport.kll_metrics(), &kllMetrics);
281     ASSERT_EQ(kllMetrics.data_size(), 2);
282     EXPECT_EQ(kllMetrics.skipped_size(), 0);
283 
284     // Only Uid 1 and 3 are logged. (odd hash value) + (offset of 5) % (shard count of 2) = 0
285     KllMetricData data = kllMetrics.data(0);
286     ValidateAttributionUidDimension(data.dimensions_in_what(), util::BLE_SCAN_RESULT_RECEIVED,
287                                     appUid1);
288     ValidateKllBucket(data.bucket_info(0), bucketStartTimeNs, bucketStartTimeNs + bucketSizeNs, {2},
289                       0);
290 
291     data = kllMetrics.data(1);
292     ValidateAttributionUidDimension(data.dimensions_in_what(), util::BLE_SCAN_RESULT_RECEIVED,
293                                     appUid3);
294     ValidateKllBucket(data.bucket_info(0), bucketStartTimeNs, bucketStartTimeNs + bucketSizeNs, {2},
295                       0);
296 }
297 
298 #else
299 GTEST_LOG_(INFO) << "This test does nothing.\n";
300 #endif
301 
302 }  // namespace statsd
303 }  // namespace os
304 }  // namespace android
305