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 "socket/LogEventFilter.h"
17
18 #include <gtest/gtest.h>
19
20 #include <algorithm>
21
22 #ifdef __ANDROID__
23
24 namespace android {
25 namespace os {
26 namespace statsd {
27
28 namespace {
29
30 constexpr int kAtomIdsCount = 100; // Filter size setup
31
generateAtomIds(int rangeStart,int rangeEndInclusive)32 LogEventFilter::AtomIdSet generateAtomIds(int rangeStart, int rangeEndInclusive) {
33 LogEventFilter::AtomIdSet atomIds;
34 for (int i = rangeStart; i <= rangeEndInclusive; ++i) {
35 atomIds.insert(i);
36 }
37 return atomIds;
38 }
39
testGuaranteedUnusedAtomsNotInUse(const LogEventFilter & filter)40 bool testGuaranteedUnusedAtomsNotInUse(const LogEventFilter& filter) {
41 const auto sampleIds = generateAtomIds(10000, 11000);
42 bool atLeastOneInUse = false;
43 for (const auto& atomId : sampleIds) {
44 atLeastOneInUse |= filter.isAtomInUse(atomId);
45 }
46 return !atLeastOneInUse;
47 }
48
49 class LogEventFilterTest : public ::testing::Test {
50 public:
SetUp()51 void SetUp() override {
52 filter.setFilteringEnabled(true);
53 }
54 LogEventFilter filter;
55 };
56
57 } // namespace
58
TEST_F(LogEventFilterTest,TestEmptyFilter)59 TEST_F(LogEventFilterTest, TestEmptyFilter) {
60 const auto sampleIds = generateAtomIds(1, kAtomIdsCount);
61 for (const auto& atomId : sampleIds) {
62 EXPECT_FALSE(filter.isAtomInUse(atomId));
63 }
64 }
65
TEST_F(LogEventFilterTest,TestRemoveNonExistingEmptyFilter)66 TEST_F(LogEventFilterTest, TestRemoveNonExistingEmptyFilter) {
67 EXPECT_FALSE(filter.isAtomInUse(1));
68 LogEventFilter::AtomIdSet emptyAtomIdsSet;
69 EXPECT_EQ(0, filter.mTagIdsPerConsumer.size());
70 EXPECT_EQ(0, filter.mLocalTagIds.size());
71 filter.setAtomIds(std::move(emptyAtomIdsSet), reinterpret_cast<LogEventFilter::ConsumerId>(0));
72 EXPECT_FALSE(filter.isAtomInUse(1));
73 EXPECT_EQ(0, filter.mLocalTagIds.size());
74 EXPECT_EQ(0, filter.mTagIdsPerConsumer.size());
75 }
76
TEST_F(LogEventFilterTest,TestEmptyFilterDisabled)77 TEST_F(LogEventFilterTest, TestEmptyFilterDisabled) {
78 filter.setFilteringEnabled(false);
79 const auto sampleIds = generateAtomIds(1, kAtomIdsCount);
80 for (const auto& atomId : sampleIds) {
81 EXPECT_TRUE(filter.isAtomInUse(atomId));
82 }
83 }
84
TEST_F(LogEventFilterTest,TestNonEmptyFilterFullOverlap)85 TEST_F(LogEventFilterTest, TestNonEmptyFilterFullOverlap) {
86 auto filterIds = generateAtomIds(1, kAtomIdsCount);
87 filter.setAtomIds(std::move(filterIds), reinterpret_cast<LogEventFilter::ConsumerId>(0));
88 EXPECT_EQ(1, filter.mTagIdsPerConsumer.size());
89
90 // inner copy updated only during fetch if required
91 EXPECT_EQ(0, filter.mLocalTagIds.size());
92 const auto sampleIds = generateAtomIds(1, kAtomIdsCount);
93 for (const auto& atomId : sampleIds) {
94 EXPECT_TRUE(filter.isAtomInUse(atomId));
95 }
96 EXPECT_EQ(kAtomIdsCount, filter.mLocalTagIds.size());
97 }
98
TEST_F(LogEventFilterTest,TestNonEmptyFilterPartialOverlap)99 TEST_F(LogEventFilterTest, TestNonEmptyFilterPartialOverlap) {
100 auto filterIds = generateAtomIds(1, kAtomIdsCount);
101 filter.setAtomIds(std::move(filterIds), reinterpret_cast<LogEventFilter::ConsumerId>(0));
102 // extra 100 atom ids should be filtered out
103 const auto sampleIds = generateAtomIds(1, kAtomIdsCount + 100);
104 for (const auto& atomId : sampleIds) {
105 bool const atomInUse = atomId <= kAtomIdsCount;
106 EXPECT_EQ(atomInUse, filter.isAtomInUse(atomId));
107 }
108 }
109
TEST_F(LogEventFilterTest,TestNonEmptyFilterDisabledPartialOverlap)110 TEST_F(LogEventFilterTest, TestNonEmptyFilterDisabledPartialOverlap) {
111 auto filterIds = generateAtomIds(1, kAtomIdsCount);
112 filter.setAtomIds(std::move(filterIds), reinterpret_cast<LogEventFilter::ConsumerId>(0));
113 filter.setFilteringEnabled(false);
114 // extra 100 atom ids should be in use due to filter is disabled
115 const auto sampleIds = generateAtomIds(1, kAtomIdsCount + 100);
116 for (const auto& atomId : sampleIds) {
117 EXPECT_TRUE(filter.isAtomInUse(atomId));
118 }
119 }
120
TEST_F(LogEventFilterTest,TestMultipleConsumerOverlapIdsRemoved)121 TEST_F(LogEventFilterTest, TestMultipleConsumerOverlapIdsRemoved) {
122 auto filterIds1 = generateAtomIds(1, kAtomIdsCount);
123 // half of filterIds1 atom ids overlaps with filterIds2
124 auto filterIds2 = generateAtomIds(kAtomIdsCount / 2, kAtomIdsCount * 2);
125 filter.setAtomIds(std::move(filterIds1), reinterpret_cast<LogEventFilter::ConsumerId>(0));
126 filter.setAtomIds(std::move(filterIds2), reinterpret_cast<LogEventFilter::ConsumerId>(1));
127 // inner copy updated only during fetch if required
128 EXPECT_EQ(0, filter.mLocalTagIds.size());
129 const auto sampleIds = generateAtomIds(1, kAtomIdsCount * 2);
130 for (const auto& atomId : sampleIds) {
131 EXPECT_TRUE(filter.isAtomInUse(atomId));
132 }
133 EXPECT_EQ(kAtomIdsCount * 2, filter.mLocalTagIds.size());
134 EXPECT_TRUE(testGuaranteedUnusedAtomsNotInUse(filter));
135
136 // set empty filter for second consumer
137 LogEventFilter::AtomIdSet emptyAtomIdsSet;
138 filter.setAtomIds(std::move(emptyAtomIdsSet), reinterpret_cast<LogEventFilter::ConsumerId>(1));
139 EXPECT_EQ(kAtomIdsCount * 2, filter.mLocalTagIds.size());
140 for (const auto& atomId : sampleIds) {
141 bool const atomInUse = atomId <= kAtomIdsCount;
142 EXPECT_EQ(atomInUse, filter.isAtomInUse(atomId));
143 }
144 EXPECT_EQ(kAtomIdsCount, filter.mLocalTagIds.size());
145 EXPECT_TRUE(testGuaranteedUnusedAtomsNotInUse(filter));
146 }
147
TEST_F(LogEventFilterTest,TestMultipleConsumerEmptyFilter)148 TEST_F(LogEventFilterTest, TestMultipleConsumerEmptyFilter) {
149 auto filterIds1 = generateAtomIds(1, kAtomIdsCount);
150 auto filterIds2 = generateAtomIds(kAtomIdsCount + 1, kAtomIdsCount * 2);
151 filter.setAtomIds(std::move(filterIds1), reinterpret_cast<LogEventFilter::ConsumerId>(0));
152 filter.setAtomIds(std::move(filterIds2), reinterpret_cast<LogEventFilter::ConsumerId>(1));
153 EXPECT_EQ(2, filter.mTagIdsPerConsumer.size());
154 // inner copy updated only during fetch if required
155 EXPECT_EQ(0, filter.mLocalTagIds.size());
156 const auto sampleIds = generateAtomIds(1, kAtomIdsCount * 2);
157 for (const auto& atomId : sampleIds) {
158 EXPECT_TRUE(filter.isAtomInUse(atomId));
159 }
160 EXPECT_EQ(kAtomIdsCount * 2, filter.mLocalTagIds.size());
161 EXPECT_TRUE(testGuaranteedUnusedAtomsNotInUse(filter));
162
163 // set empty filter for first consumer
164 LogEventFilter::AtomIdSet emptyAtomIdsSet;
165 filter.setAtomIds(emptyAtomIdsSet, reinterpret_cast<LogEventFilter::ConsumerId>(0));
166 EXPECT_EQ(1, filter.mTagIdsPerConsumer.size());
167 EXPECT_EQ(kAtomIdsCount * 2, filter.mLocalTagIds.size());
168 for (const auto& atomId : sampleIds) {
169 bool const atomInUse = atomId > kAtomIdsCount;
170 EXPECT_EQ(atomInUse, filter.isAtomInUse(atomId));
171 }
172 EXPECT_EQ(kAtomIdsCount, filter.mLocalTagIds.size());
173 EXPECT_TRUE(testGuaranteedUnusedAtomsNotInUse(filter));
174
175 // set empty filter for second consumer
176 filter.setAtomIds(emptyAtomIdsSet, reinterpret_cast<LogEventFilter::ConsumerId>(1));
177 EXPECT_EQ(0, filter.mTagIdsPerConsumer.size());
178 EXPECT_EQ(kAtomIdsCount, filter.mLocalTagIds.size());
179 for (const auto& atomId : sampleIds) {
180 EXPECT_FALSE(filter.isAtomInUse(atomId));
181 }
182 EXPECT_EQ(0, filter.mLocalTagIds.size());
183 EXPECT_TRUE(testGuaranteedUnusedAtomsNotInUse(filter));
184 }
185
186 } // namespace statsd
187 } // namespace os
188 } // namespace android
189 #else
190 GTEST_LOG_(INFO) << "This test does nothing.\n";
191 #endif
192