blob: 2576cf5b1339a796a0f1624f35aabebd36bf6af1 [file] [log] [blame]
Tej Singh89817632019-12-09 16:58:08 -08001// Copyright (C) 2019 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 "src/external/StatsCallbackPuller.h"
16
17#include <android/os/BnPullAtomCallback.h>
18#include <android/os/IPullAtomResultReceiver.h>
19#include <gmock/gmock.h>
20#include <gtest/gtest.h>
21#include <stdio.h>
22
23#include <chrono>
24#include <thread>
25#include <vector>
26
27#include "../metrics/metrics_test_helper.h"
28#include "src/stats_log_util.h"
29#include "tests/statsd_test_util.h"
30
31#ifdef __ANDROID__
32
33namespace android {
34namespace os {
35namespace statsd {
36
37using namespace testing;
38using std::make_shared;
39using std::shared_ptr;
40using std::vector;
41using std::this_thread::sleep_for;
42using testing::Contains;
43
44namespace {
45int pullTagId = -12;
46bool pullSuccess;
47vector<int64_t> values;
48int64_t pullDelayNs;
49int64_t pullTimeoutNs;
50int64_t pullCoolDownNs;
51std::thread pullThread;
52
53stats_event* createSimpleEvent(int64_t value) {
54 stats_event* event = stats_event_obtain();
55 stats_event_set_atom_id(event, pullTagId);
56 stats_event_write_int64(event, value);
57 stats_event_build(event);
58 return event;
59}
60
61void executePull(const sp<IPullAtomResultReceiver>& resultReceiver) {
62 // Convert stats_events into StatsEventParcels.
63 std::vector<android::util::StatsEventParcel> parcels;
64 for (int i = 0; i < values.size(); i++) {
65 stats_event* event = createSimpleEvent(values[i]);
66 size_t size;
67 uint8_t* buffer = stats_event_get_buffer(event, &size);
68
69 android::util::StatsEventParcel p;
70 // vector.assign() creates a copy, but this is inevitable unless
71 // stats_event.h/c uses a vector as opposed to a buffer.
72 p.buffer.assign(buffer, buffer + size);
73 parcels.push_back(std::move(p));
74 stats_event_release(event);
75 }
76
77 sleep_for(std::chrono::nanoseconds(pullDelayNs));
78 resultReceiver->pullFinished(pullTagId, pullSuccess, parcels);
79}
80
81class FakePullAtomCallback : public BnPullAtomCallback {
82public:
83 binder::Status onPullAtom(int atomTag,
84 const sp<IPullAtomResultReceiver>& resultReceiver) override {
85 // Force pull to happen in separate thread to simulate binder.
86 pullThread = std::thread(executePull, resultReceiver);
87 return binder::Status::ok();
88 }
89};
90
91class StatsCallbackPullerTest : public ::testing::Test {
92public:
93 StatsCallbackPullerTest() {
94 }
95
96 void SetUp() override {
97 pullSuccess = false;
98 pullDelayNs = 0;
99 values.clear();
100 pullTimeoutNs = 10000000000LL; // 10 seconds.
101 pullCoolDownNs = 1000000000; // 1 second.
102 }
103
104 void TearDown() override {
105 if (pullThread.joinable()) {
106 pullThread.join();
107 }
108 values.clear();
109 }
110};
111} // Anonymous namespace.
112
113TEST_F(StatsCallbackPullerTest, PullSuccess) {
114 sp<FakePullAtomCallback> cb = new FakePullAtomCallback();
115 int64_t value = 43;
116 pullSuccess = true;
117 values.push_back(value);
118
Tej Singh5b4951b2020-01-24 13:23:56 -0800119 StatsCallbackPuller puller(pullTagId, cb, pullCoolDownNs, pullTimeoutNs, {});
Tej Singh89817632019-12-09 16:58:08 -0800120
121 vector<std::shared_ptr<LogEvent>> dataHolder;
122 int64_t startTimeNs = getElapsedRealtimeNs();
123 EXPECT_TRUE(puller.PullInternal(&dataHolder));
124 int64_t endTimeNs = getElapsedRealtimeNs();
125
126 EXPECT_EQ(1, dataHolder.size());
127 EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
128 EXPECT_LT(startTimeNs, dataHolder[0]->GetElapsedTimestampNs());
129 EXPECT_GT(endTimeNs, dataHolder[0]->GetElapsedTimestampNs());
130 EXPECT_EQ(1, dataHolder[0]->size());
131 EXPECT_EQ(value, dataHolder[0]->getValues()[0].mValue.int_value);
132}
133
134TEST_F(StatsCallbackPullerTest, PullFail) {
135 sp<FakePullAtomCallback> cb = new FakePullAtomCallback();
136 pullSuccess = false;
137 int64_t value = 1234;
138 values.push_back(value);
139
Tej Singh5b4951b2020-01-24 13:23:56 -0800140 StatsCallbackPuller puller(pullTagId, cb, pullCoolDownNs, pullTimeoutNs, {});
Tej Singh89817632019-12-09 16:58:08 -0800141
142 vector<std::shared_ptr<LogEvent>> dataHolder;
143 EXPECT_FALSE(puller.PullInternal(&dataHolder));
144 EXPECT_EQ(0, dataHolder.size());
145}
146
147TEST_F(StatsCallbackPullerTest, PullTimeout) {
148 sp<FakePullAtomCallback> cb = new FakePullAtomCallback();
149 pullSuccess = true;
150 pullDelayNs = 500000000; // 500ms.
151 pullTimeoutNs = 10000; // 10 microseconds.
152 int64_t value = 4321;
153 values.push_back(value);
154
Tej Singh5b4951b2020-01-24 13:23:56 -0800155 StatsCallbackPuller puller(pullTagId, cb, pullCoolDownNs, pullTimeoutNs, {});
Tej Singh89817632019-12-09 16:58:08 -0800156
157 vector<std::shared_ptr<LogEvent>> dataHolder;
158 int64_t startTimeNs = getElapsedRealtimeNs();
159 // Returns true to let StatsPuller code evaluate the timeout.
160 EXPECT_TRUE(puller.PullInternal(&dataHolder));
161 int64_t endTimeNs = getElapsedRealtimeNs();
162 int64_t actualPullDurationNs = endTimeNs - startTimeNs;
163
164 // Pull should take at least the timeout amount of time, but should stop early because the delay
165 // is bigger.
166 EXPECT_LT(pullTimeoutNs, actualPullDurationNs);
167 EXPECT_GT(pullDelayNs, actualPullDurationNs);
168 EXPECT_EQ(0, dataHolder.size());
169
170 // Let the pull return and make sure that the dataHolder is not modified.
171 pullThread.join();
172 EXPECT_EQ(0, dataHolder.size());
173}
174
175// Register a puller and ensure that the timeout logic works.
176TEST_F(StatsCallbackPullerTest, RegisterAndTimeout) {
177 sp<FakePullAtomCallback> cb = new FakePullAtomCallback();
178 pullSuccess = true;
179 pullDelayNs = 500000000; // 500 ms.
180 pullTimeoutNs = 10000; // 10 microsseconds.
181 int64_t value = 4321;
182 values.push_back(value);
183
184 StatsPullerManager pullerManager;
185 pullerManager.RegisterPullAtomCallback(/*uid=*/-1, pullTagId, pullCoolDownNs, pullTimeoutNs,
186 vector<int32_t>(), cb);
187 vector<std::shared_ptr<LogEvent>> dataHolder;
188 int64_t startTimeNs = getElapsedRealtimeNs();
189 // Returns false, since StatsPuller code will evaluate the timeout.
190 EXPECT_FALSE(pullerManager.Pull(pullTagId, &dataHolder));
191 int64_t endTimeNs = getElapsedRealtimeNs();
192 int64_t actualPullDurationNs = endTimeNs - startTimeNs;
193
194 // Pull should take at least the timeout amount of time, but should stop early because the delay
195 // is bigger.
196 EXPECT_LT(pullTimeoutNs, actualPullDurationNs);
197 EXPECT_GT(pullDelayNs, actualPullDurationNs);
198 EXPECT_EQ(0, dataHolder.size());
199
200 // Let the pull return and make sure that the dataHolder is not modified.
201 pullThread.join();
202 EXPECT_EQ(0, dataHolder.size());
203}
204
205} // namespace statsd
206} // namespace os
207} // namespace android
208#else
209GTEST_LOG_(INFO) << "This test does nothing.\n";
210#endif