1 /*
2 * Copyright (C) 2023, 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
18 #include "socket/StatsSocketListener.h"
19 #include "tests/statsd_test_util.h"
20
21 #ifdef __ANDROID__
22
23 namespace android {
24 namespace os {
25 namespace statsd {
26
27 namespace {
28
29 constexpr uint32_t kTestUid = 1001;
30 constexpr uint32_t kTestPid = 1002;
31 constexpr int kEventCount = 1000;
32 constexpr int kEventFilteredCount = 500;
33 constexpr int kAtomId = 1000;
34
35 class AStatsEventWrapper final {
36 AStatsEvent* statsEvent = nullptr;
37
38 public:
AStatsEventWrapper(int atomId)39 AStatsEventWrapper(int atomId) {
40 statsEvent = AStatsEvent_obtain();
41 createStatsEvent(statsEvent, INT64_TYPE, /*atomId=*/atomId);
42 AStatsEvent_build(statsEvent);
43 }
44
getBuffer() const45 std::pair<const uint8_t*, size_t> getBuffer() const {
46 size_t size;
47 const uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
48 return std::make_pair(buf, size);
49 }
50
~AStatsEventWrapper()51 ~AStatsEventWrapper() {
52 AStatsEvent_release(statsEvent);
53 }
54 };
55
56 } // namespace
57
generateAtomLogging(const std::shared_ptr<LogEventQueue> & queue,const std::shared_ptr<LogEventFilter> & filter,int eventCount,int startAtomId)58 void generateAtomLogging(const std::shared_ptr<LogEventQueue>& queue,
59 const std::shared_ptr<LogEventFilter>& filter, int eventCount,
60 int startAtomId) {
61 // create number of AStatsEvent
62 for (int i = 0; i < eventCount; i++) {
63 AStatsEventWrapper event(startAtomId + i);
64 auto [buf, size] = event.getBuffer();
65 StatsSocketListener::processMessage(buf, size, kTestUid, kTestPid, queue, filter);
66 }
67 }
68
69 class SocketParseMessageTestNoFiltering : public testing::TestWithParam<bool> {
70 protected:
71 std::shared_ptr<LogEventQueue> mEventQueue;
72 std::shared_ptr<LogEventFilter> mLogEventFilter;
73
74 public:
SocketParseMessageTestNoFiltering()75 SocketParseMessageTestNoFiltering()
76 : mEventQueue(std::make_shared<LogEventQueue>(kEventCount /*buffer limit*/)),
77 mLogEventFilter(GetParam() ? std::make_shared<LogEventFilter>() : nullptr) {
78 }
79
ToString(testing::TestParamInfo<bool> info)80 static std::string ToString(testing::TestParamInfo<bool> info) {
81 return info.param ? "WithEventFilter" : "NoEventFilter";
82 }
83 };
84
85 INSTANTIATE_TEST_SUITE_P(SocketParseMessageTestNoFiltering, SocketParseMessageTestNoFiltering,
86 testing::Bool(), SocketParseMessageTestNoFiltering::ToString);
87
TEST_P(SocketParseMessageTestNoFiltering,TestProcessMessageNoFiltering)88 TEST_P(SocketParseMessageTestNoFiltering, TestProcessMessageNoFiltering) {
89 if (GetParam()) {
90 mLogEventFilter->setFilteringEnabled(false);
91 }
92
93 generateAtomLogging(mEventQueue, mLogEventFilter, kEventCount, kAtomId);
94
95 // check content of the queue
96 EXPECT_EQ(kEventCount, mEventQueue->mQueue.size());
97 for (int i = 0; i < kEventCount; i++) {
98 auto logEvent = mEventQueue->waitPop();
99 EXPECT_TRUE(logEvent->isValid());
100 EXPECT_EQ(kAtomId + i, logEvent->GetTagId());
101 EXPECT_FALSE(logEvent->isParsedHeaderOnly());
102 }
103 }
104
TEST_P(SocketParseMessageTestNoFiltering,TestProcessMessageNoFilteringWithEmptySetExplicitSet)105 TEST_P(SocketParseMessageTestNoFiltering, TestProcessMessageNoFilteringWithEmptySetExplicitSet) {
106 if (GetParam()) {
107 mLogEventFilter->setFilteringEnabled(false);
108 LogEventFilter::AtomIdSet idsList;
109 mLogEventFilter->setAtomIds(idsList, nullptr);
110 }
111
112 generateAtomLogging(mEventQueue, mLogEventFilter, kEventCount, kAtomId);
113
114 // check content of the queue
115 EXPECT_EQ(kEventCount, mEventQueue->mQueue.size());
116 for (int i = 0; i < kEventCount; i++) {
117 auto logEvent = mEventQueue->waitPop();
118 EXPECT_TRUE(logEvent->isValid());
119 EXPECT_EQ(kAtomId + i, logEvent->GetTagId());
120 EXPECT_FALSE(logEvent->isParsedHeaderOnly());
121 }
122 }
123
TEST(SocketParseMessageTest,TestProcessMessageFilterEmptySet)124 TEST(SocketParseMessageTest, TestProcessMessageFilterEmptySet) {
125 std::shared_ptr<LogEventQueue> eventQueue =
126 std::make_shared<LogEventQueue>(kEventCount /*buffer limit*/);
127
128 std::shared_ptr<LogEventFilter> logEventFilter = std::make_shared<LogEventFilter>();
129
130 generateAtomLogging(eventQueue, logEventFilter, kEventCount, kAtomId);
131
132 // check content of the queue
133 for (int i = 0; i < kEventCount; i++) {
134 auto logEvent = eventQueue->waitPop();
135 EXPECT_TRUE(logEvent->isValid());
136 EXPECT_EQ(kAtomId + i, logEvent->GetTagId());
137 EXPECT_TRUE(logEvent->isParsedHeaderOnly());
138 }
139 }
140
TEST(SocketParseMessageTest,TestProcessMessageFilterEmptySetExplicitSet)141 TEST(SocketParseMessageTest, TestProcessMessageFilterEmptySetExplicitSet) {
142 std::shared_ptr<LogEventQueue> eventQueue =
143 std::make_shared<LogEventQueue>(kEventCount /*buffer limit*/);
144
145 std::shared_ptr<LogEventFilter> logEventFilter = std::make_shared<LogEventFilter>();
146
147 LogEventFilter::AtomIdSet idsList;
148 logEventFilter->setAtomIds(idsList, nullptr);
149
150 generateAtomLogging(eventQueue, logEventFilter, kEventCount, kAtomId);
151
152 // check content of the queue
153 for (int i = 0; i < kEventCount; i++) {
154 auto logEvent = eventQueue->waitPop();
155 EXPECT_TRUE(logEvent->isValid());
156 EXPECT_EQ(kAtomId + i, logEvent->GetTagId());
157 EXPECT_TRUE(logEvent->isParsedHeaderOnly());
158 }
159 }
160
TEST(SocketParseMessageTest,TestProcessMessageFilterCompleteSet)161 TEST(SocketParseMessageTest, TestProcessMessageFilterCompleteSet) {
162 std::shared_ptr<LogEventQueue> eventQueue =
163 std::make_shared<LogEventQueue>(kEventCount /*buffer limit*/);
164
165 std::shared_ptr<LogEventFilter> logEventFilter = std::make_shared<LogEventFilter>();
166
167 LogEventFilter::AtomIdSet idsList;
168 for (int i = 0; i < kEventCount; i++) {
169 idsList.insert(kAtomId + i);
170 }
171 logEventFilter->setAtomIds(idsList, nullptr);
172
173 generateAtomLogging(eventQueue, logEventFilter, kEventCount, kAtomId);
174
175 // check content of the queue
176 EXPECT_EQ(kEventCount, eventQueue->mQueue.size());
177 for (int i = 0; i < kEventCount; i++) {
178 auto logEvent = eventQueue->waitPop();
179 EXPECT_TRUE(logEvent->isValid());
180 EXPECT_EQ(kAtomId + i, logEvent->GetTagId());
181 EXPECT_FALSE(logEvent->isParsedHeaderOnly());
182 }
183 }
184
TEST(SocketParseMessageTest,TestProcessMessageFilterPartialSet)185 TEST(SocketParseMessageTest, TestProcessMessageFilterPartialSet) {
186 std::shared_ptr<LogEventQueue> eventQueue =
187 std::make_shared<LogEventQueue>(kEventCount /*buffer limit*/);
188
189 std::shared_ptr<LogEventFilter> logEventFilter = std::make_shared<LogEventFilter>();
190
191 LogEventFilter::AtomIdSet idsList;
192 for (int i = 0; i < kEventFilteredCount; i++) {
193 idsList.insert(kAtomId + i);
194 }
195 logEventFilter->setAtomIds(idsList, nullptr);
196
197 generateAtomLogging(eventQueue, logEventFilter, kEventCount, kAtomId);
198
199 // check content of the queue
200 EXPECT_EQ(kEventCount, eventQueue->mQueue.size());
201 for (int i = 0; i < kEventFilteredCount; i++) {
202 auto logEvent = eventQueue->waitPop();
203 EXPECT_TRUE(logEvent->isValid());
204 EXPECT_EQ(kAtomId + i, logEvent->GetTagId());
205 EXPECT_FALSE(logEvent->isParsedHeaderOnly());
206 }
207
208 for (int i = kEventFilteredCount; i < kEventCount; i++) {
209 auto logEvent = eventQueue->waitPop();
210 EXPECT_TRUE(logEvent->isValid());
211 EXPECT_EQ(kAtomId + i, logEvent->GetTagId());
212 EXPECT_TRUE(logEvent->isParsedHeaderOnly());
213 }
214 }
215
TEST(SocketParseMessageTest,TestProcessMessageFilterToggle)216 TEST(SocketParseMessageTest, TestProcessMessageFilterToggle) {
217 std::shared_ptr<LogEventQueue> eventQueue =
218 std::make_shared<LogEventQueue>(kEventCount * 3 /*buffer limit*/);
219
220 std::shared_ptr<LogEventFilter> logEventFilter = std::make_shared<LogEventFilter>();
221
222 LogEventFilter::AtomIdSet idsList;
223 for (int i = 0; i < kEventFilteredCount; i++) {
224 idsList.insert(kAtomId + i);
225 }
226 // events with ids from kAtomId to kAtomId + kEventFilteredCount should not be skipped
227 logEventFilter->setAtomIds(idsList, nullptr);
228
229 generateAtomLogging(eventQueue, logEventFilter, kEventCount, kAtomId);
230
231 logEventFilter->setFilteringEnabled(false);
232 // since filtering is disabled - events with any ids should not be skipped
233 // will generate events with ids [kAtomId + kEventCount, kAtomId + kEventCount * 2]
234 generateAtomLogging(eventQueue, logEventFilter, kEventCount, kAtomId + kEventCount);
235
236 logEventFilter->setFilteringEnabled(true);
237 LogEventFilter::AtomIdSet idsList2;
238 for (int i = kEventFilteredCount; i < kEventCount; i++) {
239 idsList2.insert(kAtomId + kEventCount * 2 + i);
240 }
241 // events with idsList2 ids should not be skipped
242 logEventFilter->setAtomIds(idsList2, nullptr);
243
244 // will generate events with ids [kAtomId + kEventCount * 2, kAtomId + kEventCount * 3]
245 generateAtomLogging(eventQueue, logEventFilter, kEventCount, kAtomId + kEventCount * 2);
246
247 // check content of the queue
248 EXPECT_EQ(kEventCount * 3, eventQueue->mQueue.size());
249 // events with ids from kAtomId to kAtomId + kEventFilteredCount should not be skipped
250 for (int i = 0; i < kEventFilteredCount; i++) {
251 auto logEvent = eventQueue->waitPop();
252 EXPECT_TRUE(logEvent->isValid());
253 EXPECT_EQ(kAtomId + i, logEvent->GetTagId());
254 EXPECT_FALSE(logEvent->isParsedHeaderOnly());
255 }
256
257 // all events above kAtomId + kEventFilteredCount to kAtomId + kEventCount should be skipped
258 for (int i = kEventFilteredCount; i < kEventCount; i++) {
259 auto logEvent = eventQueue->waitPop();
260 EXPECT_TRUE(logEvent->isValid());
261 EXPECT_EQ(kAtomId + i, logEvent->GetTagId());
262 EXPECT_TRUE(logEvent->isParsedHeaderOnly());
263 }
264
265 // events with ids [kAtomId + kEventCount, kAtomId + kEventCount * 2] should not be skipped
266 // since wiltering was disabled at that time
267 for (int i = 0; i < kEventCount; i++) {
268 auto logEvent = eventQueue->waitPop();
269 EXPECT_TRUE(logEvent->isValid());
270 EXPECT_EQ(kAtomId + kEventCount + i, logEvent->GetTagId());
271 EXPECT_FALSE(logEvent->isParsedHeaderOnly());
272 }
273
274 // first half events with ids [kAtomId + kEventCount * 2, kAtomId + kEventCount * 3]
275 // should be skipped
276 for (int i = 0; i < kEventFilteredCount; i++) {
277 auto logEvent = eventQueue->waitPop();
278 EXPECT_TRUE(logEvent->isValid());
279 EXPECT_EQ(kAtomId + kEventCount * 2 + i, logEvent->GetTagId());
280 EXPECT_TRUE(logEvent->isParsedHeaderOnly());
281 }
282
283 // second half events with ids [kAtomId + kEventCount * 2, kAtomId + kEventCount * 3]
284 // should be processed
285 for (int i = kEventFilteredCount; i < kEventCount; i++) {
286 auto logEvent = eventQueue->waitPop();
287 EXPECT_TRUE(logEvent->isValid());
288 EXPECT_EQ(kAtomId + kEventCount * 2 + i, logEvent->GetTagId());
289 EXPECT_FALSE(logEvent->isParsedHeaderOnly());
290 }
291 }
292
293 // TODO: tests for setAtomIds() with multiple consumers
294 // TODO: use MockLogEventFilter to test different sets from different consumers
295
296 } // namespace statsd
297 } // namespace os
298 } // namespace android
299 #else
300 GTEST_LOG_(INFO) << "This test does nothing.\n";
301 #endif
302