blob: 75ceafb489b3ec7b6537098c206876926987dde0 [file] [log] [blame]
Yangster13fb7e42018-03-07 17:30:49 -08001// Copyright (C) 2017 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 "src/stats_log_util.h"
19#include "tests/statsd_test_util.h"
20
21#include <vector>
22
23namespace android {
24namespace os {
25namespace statsd {
26
27#ifdef __ANDROID__
28
29namespace {
30
31StatsdConfig CreateDurationMetricConfig_NoLink_SimpleCondition(
32 DurationMetric::AggregationType aggregationType, bool addExtraDimensionInCondition) {
33 StatsdConfig config;
34 *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher();
35 *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher();
36 *config.add_atom_matcher() = CreateSyncStartAtomMatcher();
37 *config.add_atom_matcher() = CreateSyncEndAtomMatcher();
38
39 auto scheduledJobPredicate = CreateScheduledJobPredicate();
40 auto dimensions = scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions();
41 dimensions->set_field(android::util::SCHEDULED_JOB_STATE_CHANGED);
42 dimensions->add_child()->set_field(2); // job name field.
43
44 auto isSyncingPredicate = CreateIsSyncingPredicate();
45 auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
46 *syncDimension = CreateAttributionUidAndTagDimensions(android::util::SYNC_STATE_CHANGED,
47 {Position::FIRST});
48 if (addExtraDimensionInCondition) {
49 syncDimension->add_child()->set_field(2 /* name field*/);
50 }
51
52 *config.add_predicate() = scheduledJobPredicate;
53 *config.add_predicate() = isSyncingPredicate;
54
55 auto metric = config.add_duration_metric();
56 metric->set_bucket(FIVE_MINUTES);
57 metric->set_id(StringToId("scheduledJob"));
58 metric->set_what(scheduledJobPredicate.id());
59 metric->set_condition(isSyncingPredicate.id());
60 metric->set_aggregation_type(aggregationType);
61 auto dimensionWhat = metric->mutable_dimensions_in_what();
62 dimensionWhat->set_field(android::util::SCHEDULED_JOB_STATE_CHANGED);
63 dimensionWhat->add_child()->set_field(2); // job name field.
64 *metric->mutable_dimensions_in_condition() = CreateAttributionUidAndTagDimensions(
65 android::util::SYNC_STATE_CHANGED, {Position::FIRST});
66 return config;
67}
68
69} // namespace
70
71TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_SimpleCondition) {
72 for (bool isDimensionInConditionSubSetOfConditionTrackerDimension : {true, false}) {
73 for (auto aggregationType : {DurationMetric::SUM, DurationMetric::MAX_SPARSE}) {
74 ConfigKey cfgKey;
75 auto config = CreateDurationMetricConfig_NoLink_SimpleCondition(
76 aggregationType, isDimensionInConditionSubSetOfConditionTrackerDimension);
77 int64_t bucketStartTimeNs = 10000000000;
78 int64_t bucketSizeNs =
79 TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
80
81 auto processor = CreateStatsLogProcessor(
82 bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
83 EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
84 EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
85
86 std::vector<AttributionNodeInternal> attributions1 = {
87 CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
88 CreateAttribution(222, "GMSCoreModule2")};
89
90 std::vector<AttributionNodeInternal> attributions2 = {
91 CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
92 CreateAttribution(555, "GMSCoreModule2")};
93
94 std::vector<std::unique_ptr<LogEvent>> events;
95
96 events.push_back(CreateStartScheduledJobEvent(
97 {CreateAttribution(9999, "")}, "job0", bucketStartTimeNs + 1));
98 events.push_back(CreateFinishScheduledJobEvent(
99 {CreateAttribution(9999, "")}, "job0",bucketStartTimeNs + 101));
100
101 events.push_back(CreateStartScheduledJobEvent(
102 {CreateAttribution(9999, "")}, "job2", bucketStartTimeNs + 201));
103 events.push_back(CreateFinishScheduledJobEvent(
104 {CreateAttribution(9999, "")}, "job2",bucketStartTimeNs + 500));
105
106 events.push_back(CreateStartScheduledJobEvent(
107 {CreateAttribution(8888, "")}, "job2", bucketStartTimeNs + 600));
108 events.push_back(CreateFinishScheduledJobEvent(
109 {CreateAttribution(8888, "")}, "job2",bucketStartTimeNs + bucketSizeNs + 850));
110
111 events.push_back(CreateStartScheduledJobEvent(
112 {CreateAttribution(8888, "")}, "job1", bucketStartTimeNs + bucketSizeNs + 600));
113 events.push_back(CreateFinishScheduledJobEvent(
114 {CreateAttribution(8888, "")}, "job1", bucketStartTimeNs + bucketSizeNs + 900));
115
116 events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
117 bucketStartTimeNs + 10));
118 events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
119 bucketStartTimeNs + 50));
120
121 events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
122 bucketStartTimeNs + 200));
123 events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
124 bucketStartTimeNs + bucketSizeNs + 300));
125
126 events.push_back(CreateSyncStartEvent(attributions1, "ReadDoc",
127 bucketStartTimeNs + 400));
128 events.push_back(CreateSyncEndEvent(attributions1, "ReadDoc",
129 bucketStartTimeNs + bucketSizeNs - 1));
130
131 events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
132 bucketStartTimeNs + 401));
133 events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
134 bucketStartTimeNs + bucketSizeNs + 700));
135
136 sortLogEventsByTimestamp(&events);
137
138 for (const auto& event : events) {
139 processor->OnLogEvent(event.get());
140 }
141
142 ConfigMetricsReportList reports;
143 vector<uint8_t> buffer;
144 processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &buffer);
145 EXPECT_TRUE(buffer.size() > 0);
146 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
147
148 EXPECT_EQ(reports.reports_size(), 1);
149 EXPECT_EQ(reports.reports(0).metrics_size(), 1);
150 StatsLogReport::DurationMetricDataWrapper metrics;
151 sortMetricDataByDimensionsValue(
152 reports.reports(0).metrics(0).duration_metrics(), &metrics);
153 if (aggregationType == DurationMetric::SUM) {
154 EXPECT_EQ(metrics.data_size(), 4);
155 auto data = metrics.data(0);
156 EXPECT_EQ(data.dimensions_in_what().field(),
157 android::util::SCHEDULED_JOB_STATE_CHANGED);
158 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
159 2); // job name field
160 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
161 "job0"); // job name
162 ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
163 android::util::SYNC_STATE_CHANGED, 111, "App1");
164 EXPECT_EQ(data.bucket_info_size(), 1);
165 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 40);
166 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
167 bucketStartTimeNs);
168 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
169 bucketStartTimeNs + bucketSizeNs);
170
171 data = metrics.data(1);
172 EXPECT_EQ(data.dimensions_in_what().field(),
173 android::util::SCHEDULED_JOB_STATE_CHANGED);
174 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
175 2); // job name field
176 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
177 "job1"); // job name
178 ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
179 android::util::SYNC_STATE_CHANGED, 333, "App2");
180 EXPECT_EQ(data.bucket_info_size(), 1);
181 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 100);
182 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
183 bucketStartTimeNs + bucketSizeNs);
184 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
185 bucketStartTimeNs + 2 * bucketSizeNs);
186
187 data = metrics.data(2);
188 EXPECT_EQ(data.dimensions_in_what().field(),
189 android::util::SCHEDULED_JOB_STATE_CHANGED);
190 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
191 2); // job name field
192 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
193 "job2"); // job name
194 ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
195 android::util::SYNC_STATE_CHANGED, 111, "App1");
196 EXPECT_EQ(data.bucket_info_size(), 2);
197 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
198 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
199 bucketStartTimeNs + bucketSizeNs);
200 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 201 + bucketSizeNs - 600);
201 EXPECT_EQ(data.bucket_info(1).duration_nanos(), 300);
202 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
203 bucketStartTimeNs + bucketSizeNs);
204 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
205 bucketStartTimeNs + 2 * bucketSizeNs);
206
207 data = metrics.data(3);
208 EXPECT_EQ(data.dimensions_in_what().field(),
209 android::util::SCHEDULED_JOB_STATE_CHANGED);
210 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
211 2); // job name field
212 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
213 "job2"); // job name
214 ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
215 android::util::SYNC_STATE_CHANGED, 333, "App2");
216 EXPECT_EQ(data.bucket_info_size(), 2);
217 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 401 + bucketSizeNs - 600);
218 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
219 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
220 bucketStartTimeNs + bucketSizeNs);
221 EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
222 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
223 bucketStartTimeNs + bucketSizeNs);
224 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
225 bucketStartTimeNs + 2 * bucketSizeNs);
226 } else {
227 EXPECT_EQ(metrics.data_size(), 4);
228 auto data = metrics.data(0);
229 EXPECT_EQ(data.dimensions_in_what().field(),
230 android::util::SCHEDULED_JOB_STATE_CHANGED);
231 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
232 2); // job name field
233 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
234 "job0"); // job name
235 ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
236 android::util::SYNC_STATE_CHANGED, 111, "App1");
237 EXPECT_EQ(data.bucket_info_size(), 1);
238 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 40);
239 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
240 bucketStartTimeNs);
241 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
242 bucketStartTimeNs + bucketSizeNs);
243
244 data = metrics.data(1);
245 EXPECT_EQ(data.dimensions_in_what().field(),
246 android::util::SCHEDULED_JOB_STATE_CHANGED);
247 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
248 2); // job name field
249 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
250 "job1"); // job name
251 ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
252 android::util::SYNC_STATE_CHANGED, 333, "App2");
253 EXPECT_EQ(data.bucket_info_size(), 1);
254 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 100);
255 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
256 bucketStartTimeNs + bucketSizeNs);
257 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
258 bucketStartTimeNs + 2 * bucketSizeNs);
259
260 data = metrics.data(2);
261 EXPECT_EQ(data.dimensions_in_what().field(),
262 android::util::SCHEDULED_JOB_STATE_CHANGED);
263 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
264 2); // job name field
265 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
266 "job2"); // job name
267 ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
268 android::util::SYNC_STATE_CHANGED, 111, "App1");
269 EXPECT_EQ(data.bucket_info_size(), 2);
270 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
271 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
272 bucketStartTimeNs + bucketSizeNs);
273 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 201);
274 EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 300);
275 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
276 bucketStartTimeNs + bucketSizeNs);
277 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
278 bucketStartTimeNs + 2 * bucketSizeNs);
279
280 data = metrics.data(3);
281 EXPECT_EQ(data.dimensions_in_what().field(),
282 android::util::SCHEDULED_JOB_STATE_CHANGED);
283 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
284 2); // job name field
285 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
286 "job2"); // job name
287 ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
288 android::util::SYNC_STATE_CHANGED, 333, "App2");
289 EXPECT_EQ(data.bucket_info_size(), 2);
290 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 401 );
291 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
292 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
293 bucketStartTimeNs + bucketSizeNs);
294 EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 700);
295 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
296 bucketStartTimeNs + bucketSizeNs);
297 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
298 bucketStartTimeNs + 2 * bucketSizeNs);
299 }
300 }
301 }
302}
303
304namespace {
305
306StatsdConfig createDurationMetric_Link_SimpleConditionConfig(
307 DurationMetric::AggregationType aggregationType, bool addExtraDimensionInCondition) {
308 StatsdConfig config;
309 *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher();
310 *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher();
311 *config.add_atom_matcher() = CreateSyncStartAtomMatcher();
312 *config.add_atom_matcher() = CreateSyncEndAtomMatcher();
313
314 auto scheduledJobPredicate = CreateScheduledJobPredicate();
315 auto dimensions = scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions();
316 *dimensions = CreateAttributionUidDimensions(
317 android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
318 dimensions->add_child()->set_field(2); // job name field.
319
320 auto isSyncingPredicate = CreateIsSyncingPredicate();
321 auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
322 *syncDimension = CreateAttributionUidDimensions(
323 android::util::SYNC_STATE_CHANGED, {Position::FIRST});
324 if (addExtraDimensionInCondition) {
325 syncDimension->add_child()->set_field(2 /* name field*/);
326 }
327
328 *config.add_predicate() = scheduledJobPredicate;
329 *config.add_predicate() = isSyncingPredicate;
330
331 auto metric = config.add_duration_metric();
332 metric->set_bucket(FIVE_MINUTES);
333 metric->set_id(StringToId("scheduledJob"));
334 metric->set_what(scheduledJobPredicate.id());
335 metric->set_condition(isSyncingPredicate.id());
336 metric->set_aggregation_type(aggregationType);
337 *metric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
338 android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
339
340 auto links = metric->add_links();
341 links->set_condition(isSyncingPredicate.id());
342 *links->mutable_fields_in_what() =
343 CreateAttributionUidDimensions(
344 android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
345 *links->mutable_fields_in_condition() =
346 CreateAttributionUidDimensions(android::util::SYNC_STATE_CHANGED, {Position::FIRST});
347 return config;
348}
349
350} // namespace
351
352TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_SimpleCondition) {
353 for (bool isFullLink : {true, false}) {
354 for (auto aggregationType : {DurationMetric::SUM, DurationMetric::MAX_SPARSE}) {
355 ConfigKey cfgKey;
356 auto config = createDurationMetric_Link_SimpleConditionConfig(
357 aggregationType, !isFullLink);
358 int64_t bucketStartTimeNs = 10000000000;
359 int64_t bucketSizeNs =
360 TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
361
362 auto processor = CreateStatsLogProcessor(
363 bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
364 EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
365 EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
366
367 std::vector<AttributionNodeInternal> attributions1 = {
368 CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
369 CreateAttribution(222, "GMSCoreModule2")};
370
371 std::vector<AttributionNodeInternal> attributions2 = {
372 CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
373 CreateAttribution(555, "GMSCoreModule2")};
374
375 std::vector<AttributionNodeInternal> attributions3 = {
376 CreateAttribution(444, "App3"), CreateAttribution(222, "GMSCoreModule1"),
377 CreateAttribution(555, "GMSCoreModule2")};
378
379 std::vector<std::unique_ptr<LogEvent>> events;
380
381 events.push_back(CreateStartScheduledJobEvent(
382 {CreateAttribution(111, "App1")}, "job1", bucketStartTimeNs + 1));
383 events.push_back(CreateFinishScheduledJobEvent(
384 {CreateAttribution(111, "App1")}, "job1",bucketStartTimeNs + 101));
385
386 events.push_back(CreateStartScheduledJobEvent(
387 {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 201));
388 events.push_back(CreateFinishScheduledJobEvent(
389 {CreateAttribution(333, "App2")}, "job2",bucketStartTimeNs + 500));
390 events.push_back(CreateStartScheduledJobEvent(
391 {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 600));
392 events.push_back(
393 CreateFinishScheduledJobEvent({CreateAttribution(333, "App2")}, "job2",
394 bucketStartTimeNs + bucketSizeNs + 850));
395
396 events.push_back(
397 CreateStartScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
398 bucketStartTimeNs + bucketSizeNs - 2));
399 events.push_back(
400 CreateFinishScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
401 bucketStartTimeNs + bucketSizeNs + 900));
402
403 events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
404 bucketStartTimeNs + 50));
405 events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
406 bucketStartTimeNs + 110));
407
408 events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
409 bucketStartTimeNs + 300));
410 events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
411 bucketStartTimeNs + bucketSizeNs + 700));
412 events.push_back(CreateSyncStartEvent(attributions2, "ReadDoc",
413 bucketStartTimeNs + 400));
414 events.push_back(CreateSyncEndEvent(attributions2, "ReadDoc",
415 bucketStartTimeNs + bucketSizeNs - 1));
416
417 events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
418 bucketStartTimeNs + 550));
419 events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
420 bucketStartTimeNs + 800));
421 events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
422 bucketStartTimeNs + bucketSizeNs - 1));
423 events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
424 bucketStartTimeNs + bucketSizeNs + 700));
425
426 sortLogEventsByTimestamp(&events);
427
428 for (const auto& event : events) {
429 processor->OnLogEvent(event.get());
430 }
431
432 ConfigMetricsReportList reports;
433 vector<uint8_t> buffer;
434 processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &buffer);
435 EXPECT_TRUE(buffer.size() > 0);
436 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
437
438 EXPECT_EQ(reports.reports_size(), 1);
439 EXPECT_EQ(reports.reports(0).metrics_size(), 1);
440 StatsLogReport::DurationMetricDataWrapper metrics;
441 sortMetricDataByDimensionsValue(
442 reports.reports(0).metrics(0).duration_metrics(), &metrics);
443
444 if (aggregationType == DurationMetric::SUM) {
445 EXPECT_EQ(metrics.data_size(), 3);
446 auto data = metrics.data(0);
447 ValidateAttributionUidDimension(
448 data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
449 EXPECT_EQ(data.bucket_info_size(), 1);
450 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 50);
451 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
452 bucketStartTimeNs);
453 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
454 bucketStartTimeNs + bucketSizeNs);
455
456 data = metrics.data(1);
457 ValidateAttributionUidDimension(
458 data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
459 EXPECT_EQ(data.bucket_info_size(), 2);
460 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
461 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
462 bucketStartTimeNs + bucketSizeNs);
463 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 300 + bucketSizeNs - 600);
464 EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
465 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
466 bucketStartTimeNs + bucketSizeNs);
467 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
468 bucketStartTimeNs + 2 * bucketSizeNs);
469
470 data = metrics.data(2);
471 ValidateAttributionUidDimension(
472 data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
473 EXPECT_EQ(data.bucket_info_size(), 2);
474 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 1);
475 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
476 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
477 bucketStartTimeNs + bucketSizeNs);
478 EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
479 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
480 bucketStartTimeNs + bucketSizeNs);
481 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
482 bucketStartTimeNs + 2 * bucketSizeNs);
483 } else {
484 EXPECT_EQ(metrics.data_size(), 3);
485 auto data = metrics.data(0);
486 ValidateAttributionUidDimension(
487 data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
488 EXPECT_EQ(data.bucket_info_size(), 1);
489 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 50);
490 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
491 bucketStartTimeNs);
492 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
493 bucketStartTimeNs + bucketSizeNs);
494
495 data = metrics.data(1);
496 ValidateAttributionUidDimension(
497 data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
498 EXPECT_EQ(data.bucket_info_size(), 2);
499 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
500 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
501 bucketStartTimeNs + bucketSizeNs);
502 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 300);
503 EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 700);
504 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
505 bucketStartTimeNs + bucketSizeNs);
506 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
507 bucketStartTimeNs + 2 * bucketSizeNs);
508
509 data = metrics.data(2);
510 ValidateAttributionUidDimension(
511 data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
512 EXPECT_EQ(data.bucket_info_size(), 1);
513 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 701);
514 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
515 bucketStartTimeNs + bucketSizeNs);
516 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
517 bucketStartTimeNs + 2 * bucketSizeNs);
518 }
519 }
520 }
521}
522
523namespace {
524
525StatsdConfig createDurationMetric_PartialLink_SimpleConditionConfig(
526 DurationMetric::AggregationType aggregationType) {
527 StatsdConfig config;
528 *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher();
529 *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher();
530 *config.add_atom_matcher() = CreateSyncStartAtomMatcher();
531 *config.add_atom_matcher() = CreateSyncEndAtomMatcher();
532
533 auto scheduledJobPredicate = CreateScheduledJobPredicate();
534 auto dimensions = scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions();
535 *dimensions = CreateAttributionUidDimensions(
536 android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
537 dimensions->add_child()->set_field(2); // job name field.
538
539 auto isSyncingPredicate = CreateIsSyncingPredicate();
540 auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
541 *syncDimension = CreateAttributionUidDimensions(
542 android::util::SYNC_STATE_CHANGED, {Position::FIRST});
543 syncDimension->add_child()->set_field(2 /* name field*/);
544
545 *config.add_predicate() = scheduledJobPredicate;
546 *config.add_predicate() = isSyncingPredicate;
547
548 auto metric = config.add_duration_metric();
549 metric->set_bucket(FIVE_MINUTES);
550 metric->set_id(StringToId("scheduledJob"));
551 metric->set_what(scheduledJobPredicate.id());
552 metric->set_condition(isSyncingPredicate.id());
553 metric->set_aggregation_type(aggregationType);
554 *metric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
555 android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
556 *metric->mutable_dimensions_in_condition() = *syncDimension;
557
558 auto links = metric->add_links();
559 links->set_condition(isSyncingPredicate.id());
560 *links->mutable_fields_in_what() =
561 CreateAttributionUidDimensions(
562 android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
563 *links->mutable_fields_in_condition() =
564 CreateAttributionUidDimensions(android::util::SYNC_STATE_CHANGED, {Position::FIRST});
565 return config;
566}
567
568} // namespace
569
570TEST(DimensionInConditionE2eTest, TestDurationMetric_PartialLink_SimpleCondition) {
571 for (auto aggregationType : {DurationMetric::SUM, DurationMetric::MAX_SPARSE}) {
572 ConfigKey cfgKey;
573 auto config = createDurationMetric_PartialLink_SimpleConditionConfig(
574 aggregationType);
575 int64_t bucketStartTimeNs = 10000000000;
576 int64_t bucketSizeNs =
577 TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
578
579 auto processor = CreateStatsLogProcessor(
580 bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
581 EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
582 EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
583
584 std::vector<AttributionNodeInternal> attributions1 = {
585 CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
586 CreateAttribution(222, "GMSCoreModule2")};
587
588 std::vector<AttributionNodeInternal> attributions2 = {
589 CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
590 CreateAttribution(555, "GMSCoreModule2")};
591
592 std::vector<AttributionNodeInternal> attributions3 = {
593 CreateAttribution(444, "App3"), CreateAttribution(222, "GMSCoreModule1"),
594 CreateAttribution(555, "GMSCoreModule2")};
595
596 std::vector<std::unique_ptr<LogEvent>> events;
597
598 events.push_back(CreateStartScheduledJobEvent(
599 {CreateAttribution(111, "App1")}, "job1", bucketStartTimeNs + 1));
600 events.push_back(CreateFinishScheduledJobEvent(
601 {CreateAttribution(111, "App1")}, "job1",bucketStartTimeNs + 101));
602
603 events.push_back(CreateStartScheduledJobEvent(
604 {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 201));
605 events.push_back(CreateFinishScheduledJobEvent(
606 {CreateAttribution(333, "App2")}, "job2",bucketStartTimeNs + 500));
607 events.push_back(CreateStartScheduledJobEvent(
608 {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 600));
609 events.push_back(CreateFinishScheduledJobEvent(
610 {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + bucketSizeNs + 850));
611
612 events.push_back(
613 CreateStartScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
614 bucketStartTimeNs + bucketSizeNs - 2));
615 events.push_back(
616 CreateFinishScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
617 bucketStartTimeNs + bucketSizeNs + 900));
618
619 events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
620 bucketStartTimeNs + 50));
621 events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
622 bucketStartTimeNs + 110));
623
624 events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
625 bucketStartTimeNs + 300));
626 events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
627 bucketStartTimeNs + bucketSizeNs + 700));
628 events.push_back(CreateSyncStartEvent(attributions2, "ReadDoc",
629 bucketStartTimeNs + 400));
630 events.push_back(CreateSyncEndEvent(attributions2, "ReadDoc",
631 bucketStartTimeNs + bucketSizeNs - 1));
632
633 events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
634 bucketStartTimeNs + 550));
635 events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
636 bucketStartTimeNs + 800));
637 events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
638 bucketStartTimeNs + bucketSizeNs - 1));
639 events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
640 bucketStartTimeNs + bucketSizeNs + 700));
641
642 sortLogEventsByTimestamp(&events);
643
644 for (const auto& event : events) {
645 processor->OnLogEvent(event.get());
646 }
647
648 ConfigMetricsReportList reports;
649 vector<uint8_t> buffer;
650 processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &buffer);
651 EXPECT_TRUE(buffer.size() > 0);
652 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
653
654 EXPECT_EQ(reports.reports_size(), 1);
655 EXPECT_EQ(reports.reports(0).metrics_size(), 1);
656 StatsLogReport::DurationMetricDataWrapper metrics;
657 sortMetricDataByDimensionsValue(
658 reports.reports(0).metrics(0).duration_metrics(), &metrics);
659
660 if (aggregationType == DurationMetric::SUM) {
661 EXPECT_EQ(4, metrics.data_size());
662 auto data = metrics.data(0);
663 ValidateAttributionUidDimension(
664 data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
665 ValidateAttributionUidDimension(
666 data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 111);
667 EXPECT_EQ("ReadEmail",
668 data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
669 EXPECT_EQ(data.bucket_info_size(), 1);
670 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 50);
671 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
672 bucketStartTimeNs);
673 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
674 bucketStartTimeNs + bucketSizeNs);
675
676 data = metrics.data(1);
677 ValidateAttributionUidDimension(
678 data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
679 ValidateAttributionUidDimension(
680 data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
681 EXPECT_EQ("ReadDoc",
682 data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
683 EXPECT_EQ(data.bucket_info_size(), 1);
684 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
685 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
686 bucketStartTimeNs + bucketSizeNs);
687 EXPECT_EQ(data.bucket_info(0).duration_nanos(), bucketSizeNs - 1 - 400 - 100);
688
689 data = metrics.data(2);
690 ValidateAttributionUidDimension(
691 data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
692 ValidateAttributionUidDimension(
693 data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
694 EXPECT_EQ("ReadEmail",
695 data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
696 EXPECT_EQ(data.bucket_info_size(), 2);
697 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
698 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
699 bucketStartTimeNs + bucketSizeNs);
700 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 300 + bucketSizeNs - 600);
701 EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
702 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
703 bucketStartTimeNs + bucketSizeNs);
704 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
705 bucketStartTimeNs + 2 * bucketSizeNs);
706
707 data = metrics.data(3);
708 ValidateAttributionUidDimension(
709 data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
710 ValidateAttributionUidDimension(
711 data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 444);
712 EXPECT_EQ("ReadDoc",
713 data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
714 EXPECT_EQ(data.bucket_info_size(), 2);
715 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 1);
716 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
717 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
718 bucketStartTimeNs + bucketSizeNs);
719 EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
720 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
721 bucketStartTimeNs + bucketSizeNs);
722 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
723 bucketStartTimeNs + 2 * bucketSizeNs);
724 } else {
725 EXPECT_EQ(metrics.data_size(), 4);
726 auto data = metrics.data(0);
727 ValidateAttributionUidDimension(
728 data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
729 ValidateAttributionUidDimension(
730 data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 111);
731 EXPECT_EQ("ReadEmail",
732 data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
733 EXPECT_EQ(data.bucket_info_size(), 1);
734 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 50);
735 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
736 bucketStartTimeNs);
737 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
738 bucketStartTimeNs + bucketSizeNs);
739
740 data = metrics.data(1);
741 ValidateAttributionUidDimension(
742 data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
743 ValidateAttributionUidDimension(
744 data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
745 EXPECT_EQ("ReadDoc",
746 data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
747 EXPECT_EQ(data.bucket_info_size(), 2);
748 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
749 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
750 bucketStartTimeNs + bucketSizeNs);
751 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 100);
752 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
753 bucketStartTimeNs + bucketSizeNs);
754 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
755 bucketStartTimeNs + 2 * bucketSizeNs);
756 EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 1 - 600);
757
758 data = metrics.data(2);
759 ValidateAttributionUidDimension(
760 data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
761 ValidateAttributionUidDimension(
762 data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
763 EXPECT_EQ("ReadEmail",
764 data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
765 EXPECT_EQ(data.bucket_info_size(), 2);
766 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
767 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
768 bucketStartTimeNs + bucketSizeNs);
769 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 300);
770 EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 700);
771 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
772 bucketStartTimeNs + bucketSizeNs);
773 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
774 bucketStartTimeNs + 2 * bucketSizeNs);
775
776 data = metrics.data(3);
777 ValidateAttributionUidDimension(
778 data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
779 ValidateAttributionUidDimension(
780 data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 444);
781 EXPECT_EQ("ReadDoc",
782 data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
783 EXPECT_EQ(data.bucket_info_size(), 1);
784 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 701);
785 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
786 bucketStartTimeNs + bucketSizeNs);
787 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
788 bucketStartTimeNs + 2 * bucketSizeNs);
789 }
790 }
791}
792
793#else
794GTEST_LOG_(INFO) << "This test does nothing.\n";
795#endif
796
797} // namespace statsd
798} // namespace os
799} // namespace android