• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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