blob: a34aaf059ce539dd770594b55c44138845361371 [file] [log] [blame]
David Chenbd125272018-04-04 19:02:50 -07001// 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
David Chen81245fd2018-04-12 14:33:37 -070017#include <binder/IPCThreadState.h>
David Chenbd125272018-04-04 19:02:50 -070018#include "src/StatsLogProcessor.h"
19#include "src/StatsService.h"
20#include "src/stats_log_util.h"
21#include "tests/statsd_test_util.h"
22
23#include <vector>
24
25namespace android {
26namespace os {
27namespace statsd {
28
29#ifdef __ANDROID__
30
Jeff Sharkey6b649252018-04-16 09:50:22 -060031const string kAndroid = "android";
David Chenbd125272018-04-04 19:02:50 -070032const string kApp1 = "app1.sharing.1";
33const int kConfigKey = 789130123; // Randomly chosen to avoid collisions with existing configs.
34
35void SendConfig(StatsService& service, const StatsdConfig& config) {
36 string str;
37 config.SerializeToString(&str);
38 std::vector<uint8_t> configAsVec(str.begin(), str.end());
39 bool success;
Jeff Sharkey6b649252018-04-16 09:50:22 -060040 service.addConfiguration(kConfigKey, configAsVec, String16(kAndroid.c_str()));
David Chenbd125272018-04-04 19:02:50 -070041}
42
David Chen81245fd2018-04-12 14:33:37 -070043ConfigMetricsReport GetReports(sp<StatsLogProcessor> processor, int64_t timestamp,
44 bool include_current = false) {
David Chenbd125272018-04-04 19:02:50 -070045 vector<uint8_t> output;
David Chen81245fd2018-04-12 14:33:37 -070046 IPCThreadState* ipc = IPCThreadState::self();
47 ConfigKey configKey(ipc->getCallingUid(), kConfigKey);
48 processor->onDumpReport(configKey, timestamp, include_current /* include_current_bucket*/,
49 &output);
David Chenbd125272018-04-04 19:02:50 -070050 ConfigMetricsReportList reports;
51 reports.ParseFromArray(output.data(), output.size());
52 EXPECT_EQ(1, reports.reports_size());
53 return reports.reports(0);
54}
55
56StatsdConfig MakeConfig() {
57 StatsdConfig config;
58 config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
59
60 auto appCrashMatcher = CreateProcessCrashAtomMatcher();
61 *config.add_atom_matcher() = appCrashMatcher;
62 auto countMetric = config.add_count_metric();
63 countMetric->set_id(StringToId("AppCrashes"));
64 countMetric->set_what(appCrashMatcher.id());
65 countMetric->set_bucket(FIVE_MINUTES);
66 return config;
67}
68
David Chen81245fd2018-04-12 14:33:37 -070069StatsdConfig MakeValueMetricConfig(int64_t minTime) {
70 StatsdConfig config;
71 config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
72
73 auto temperatureAtomMatcher = CreateTemperatureAtomMatcher();
74 *config.add_atom_matcher() = temperatureAtomMatcher;
75 *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
76 *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
77
78 auto valueMetric = config.add_value_metric();
79 valueMetric->set_id(123456);
80 valueMetric->set_what(temperatureAtomMatcher.id());
81 *valueMetric->mutable_value_field() =
82 CreateDimensions(android::util::TEMPERATURE, {3 /* temperature degree field */});
83 *valueMetric->mutable_dimensions_in_what() =
84 CreateDimensions(android::util::TEMPERATURE, {2 /* sensor name field */});
85 valueMetric->set_bucket(FIVE_MINUTES);
86 valueMetric->set_min_bucket_size_nanos(minTime);
87 return config;
88}
89
90StatsdConfig MakeGaugeMetricConfig(int64_t minTime) {
91 StatsdConfig config;
92 config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
93
94 auto temperatureAtomMatcher = CreateTemperatureAtomMatcher();
95 *config.add_atom_matcher() = temperatureAtomMatcher;
96 *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
97 *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
98
99 auto gaugeMetric = config.add_gauge_metric();
100 gaugeMetric->set_id(123456);
101 gaugeMetric->set_what(temperatureAtomMatcher.id());
102 gaugeMetric->mutable_gauge_fields_filter()->set_include_all(true);
103 *gaugeMetric->mutable_dimensions_in_what() =
104 CreateDimensions(android::util::TEMPERATURE, {2 /* sensor name field */});
105 gaugeMetric->set_bucket(FIVE_MINUTES);
106 gaugeMetric->set_min_bucket_size_nanos(minTime);
107 return config;
108}
109
David Chenbd125272018-04-04 19:02:50 -0700110TEST(PartialBucketE2eTest, TestCountMetricWithoutSplit) {
111 StatsService service(nullptr);
112 SendConfig(service, MakeConfig());
113 const long start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
114 // initialized with.
115
116 service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
117 service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 2).get());
118
David Chen81245fd2018-04-12 14:33:37 -0700119 ConfigMetricsReport report = GetReports(service.mProcessor, start + 3);
David Chenbd125272018-04-04 19:02:50 -0700120 // Expect no metrics since the bucket has not finished yet.
121 EXPECT_EQ(0, report.metrics_size());
122}
123
124TEST(PartialBucketE2eTest, TestCountMetricNoSplitOnNewApp) {
125 StatsService service(nullptr);
126 SendConfig(service, MakeConfig());
127 const long start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
128 // initialized with.
129
130 // Force the uidmap to update at timestamp 2.
131 service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
132 // This is a new installation, so there shouldn't be a split (should be same as the without
133 // split case).
134 service.mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2);
135 // Goes into the second bucket.
136 service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get());
137
David Chen81245fd2018-04-12 14:33:37 -0700138 ConfigMetricsReport report = GetReports(service.mProcessor, start + 4);
David Chenbd125272018-04-04 19:02:50 -0700139 EXPECT_EQ(0, report.metrics_size());
140}
141
142TEST(PartialBucketE2eTest, TestCountMetricSplitOnUpgrade) {
143 StatsService service(nullptr);
144 SendConfig(service, MakeConfig());
145 const long start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
146 // initialized with.
147 service.mUidMap->updateMap(start, {1}, {1}, {String16(kApp1.c_str())});
148
149 // Force the uidmap to update at timestamp 2.
150 service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
151 service.mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2);
152 // Goes into the second bucket.
153 service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get());
154
David Chen81245fd2018-04-12 14:33:37 -0700155 ConfigMetricsReport report = GetReports(service.mProcessor, start + 4);
David Chenbd125272018-04-04 19:02:50 -0700156 EXPECT_EQ(1, report.metrics_size());
157 EXPECT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info(0).count());
158}
159
160TEST(PartialBucketE2eTest, TestCountMetricSplitOnRemoval) {
161 StatsService service(nullptr);
162 SendConfig(service, MakeConfig());
163 const long start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
164 // initialized with.
165 service.mUidMap->updateMap(start, {1}, {1}, {String16(kApp1.c_str())});
166
167 // Force the uidmap to update at timestamp 2.
168 service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
169 service.mUidMap->removeApp(start + 2, String16(kApp1.c_str()), 1);
170 // Goes into the second bucket.
171 service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get());
172
David Chen81245fd2018-04-12 14:33:37 -0700173 ConfigMetricsReport report = GetReports(service.mProcessor, start + 4);
David Chenbd125272018-04-04 19:02:50 -0700174 EXPECT_EQ(1, report.metrics_size());
175 EXPECT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info(0).count());
176}
177
David Chen81245fd2018-04-12 14:33:37 -0700178TEST(PartialBucketE2eTest, TestValueMetricWithoutMinPartialBucket) {
179 StatsService service(nullptr);
180 // Partial buckets don't occur when app is first installed.
181 service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1);
182 SendConfig(service, MakeValueMetricConfig(0));
183 const long start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
184 // initialized with.
185
186 service.mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
187 service.mUidMap->updateApp(5 * 60 * NS_PER_SEC + start + 2, String16(kApp1.c_str()), 1, 2);
188
189 ConfigMetricsReport report =
190 GetReports(service.mProcessor, 5 * 60 * NS_PER_SEC + start + 100, true);
191 EXPECT_EQ(1, report.metrics_size());
192 EXPECT_EQ(0, report.metrics(0).value_metrics().skipped_size());
193}
194
195TEST(PartialBucketE2eTest, TestValueMetricWithMinPartialBucket) {
196 StatsService service(nullptr);
197 // Partial buckets don't occur when app is first installed.
198 service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1);
199 SendConfig(service, MakeValueMetricConfig(60 * NS_PER_SEC /* One minute */));
200 const long start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
201 // initialized with.
202
203 const int64_t endSkipped = 5 * 60 * NS_PER_SEC + start + 2;
204 service.mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
205 service.mUidMap->updateApp(endSkipped, String16(kApp1.c_str()), 1, 2);
206
207 ConfigMetricsReport report =
208 GetReports(service.mProcessor, 5 * 60 * NS_PER_SEC + start + 100 * NS_PER_SEC, true);
209 EXPECT_EQ(1, report.metrics_size());
210 EXPECT_EQ(1, report.metrics(0).value_metrics().skipped_size());
211 // Can't test the start time since it will be based on the actual time when the pulling occurs.
212 EXPECT_EQ(endSkipped, report.metrics(0).value_metrics().skipped(0).end_elapsed_nanos());
213}
214
215TEST(PartialBucketE2eTest, TestGaugeMetricWithoutMinPartialBucket) {
216 StatsService service(nullptr);
217 // Partial buckets don't occur when app is first installed.
218 service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1);
219 SendConfig(service, MakeGaugeMetricConfig(0));
220 const long start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
221 // initialized with.
222
223 service.mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
224 service.mUidMap->updateApp(5 * 60 * NS_PER_SEC + start + 2, String16(kApp1.c_str()), 1, 2);
225
226 ConfigMetricsReport report =
227 GetReports(service.mProcessor, 5 * 60 * NS_PER_SEC + start + 100, true);
228 EXPECT_EQ(1, report.metrics_size());
229 EXPECT_EQ(0, report.metrics(0).gauge_metrics().skipped_size());
230}
231
232TEST(PartialBucketE2eTest, TestGaugeMetricWithMinPartialBucket) {
233 StatsService service(nullptr);
234 // Partial buckets don't occur when app is first installed.
235 service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1);
236 SendConfig(service, MakeGaugeMetricConfig(60 * NS_PER_SEC /* One minute */));
237 const long start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
238 // initialized with.
239
240 const int64_t endSkipped = 5 * 60 * NS_PER_SEC + start + 2;
241 service.mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
242 service.mUidMap->updateApp(endSkipped, String16(kApp1.c_str()), 1, 2);
243
244 ConfigMetricsReport report =
245 GetReports(service.mProcessor, 5 * 60 * NS_PER_SEC + start + 100 * NS_PER_SEC, true);
246 EXPECT_EQ(1, report.metrics_size());
247 EXPECT_EQ(1, report.metrics(0).gauge_metrics().skipped_size());
248 // Can't test the start time since it will be based on the actual time when the pulling occurs.
249 EXPECT_EQ(endSkipped, report.metrics(0).gauge_metrics().skipped(0).end_elapsed_nanos());
250}
251
David Chenbd125272018-04-04 19:02:50 -0700252#else
253GTEST_LOG_(INFO) << "This test does nothing.\n";
254#endif
255
256} // namespace statsd
257} // namespace os
Jeff Sharkey6b649252018-04-16 09:50:22 -0600258} // namespace android