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