• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://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, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #include "pw_log_rpc/log_filter_service.h"
16 
17 #include <array>
18 #include <cstdint>
19 #include <limits>
20 
21 #include "gtest/gtest.h"
22 #include "pw_bytes/endian.h"
23 #include "pw_log/proto/log.pwpb.h"
24 #include "pw_log_rpc/log_filter.h"
25 #include "pw_log_rpc/log_filter_map.h"
26 #include "pw_protobuf/bytes_utils.h"
27 #include "pw_protobuf/decoder.h"
28 #include "pw_result/result.h"
29 #include "pw_rpc/channel.h"
30 #include "pw_rpc/raw/test_method_context.h"
31 
32 namespace pw::log_rpc {
33 namespace {
34 
35 class FilterServiceTest : public ::testing::Test {
36  public:
FilterServiceTest()37   FilterServiceTest() : filter_map_(filters_) {}
38 
39  protected:
40   FilterMap filter_map_;
41   static constexpr size_t kMaxFilterRules = 3;
42   std::array<Filter::Rule, kMaxFilterRules> rules1_;
43   std::array<Filter::Rule, kMaxFilterRules> rules2_;
44   std::array<Filter::Rule, kMaxFilterRules> rules3_;
45   static constexpr std::array<std::byte, cfg::kMaxFilterIdBytes> filter_id1_{
46       std::byte(65), std::byte(66), std::byte(67), std::byte(0)};
47   static constexpr std::array<std::byte, cfg::kMaxFilterIdBytes> filter_id2_{
48       std::byte(68), std::byte(69), std::byte(70), std::byte(0)};
49   static constexpr std::array<std::byte, cfg::kMaxFilterIdBytes> filter_id3_{
50       std::byte(71), std::byte(72), std::byte(73), std::byte(0)};
51   static constexpr size_t kMaxFilters = 3;
52   std::array<Filter, kMaxFilters> filters_ = {
53       Filter(filter_id1_, rules1_),
54       Filter(filter_id2_, rules2_),
55       Filter(filter_id3_, rules3_),
56   };
57 };
58 
TEST_F(FilterServiceTest,GetFilterIds)59 TEST_F(FilterServiceTest, GetFilterIds) {
60   PW_RAW_TEST_METHOD_CONTEXT(FilterService, ListFilterIds, 1)
61   context(filter_map_);
62   context.call({});
63   ASSERT_EQ(OkStatus(), context.status());
64   ASSERT_TRUE(context.done());
65   ASSERT_EQ(context.responses().size(), 1u);
66   protobuf::Decoder decoder(context.responses()[0]);
67 
68   for (const auto& filter : filter_map_.filters()) {
69     ASSERT_EQ(decoder.Next(), OkStatus());
70     ASSERT_EQ(decoder.FieldNumber(), 1u);  // filter_id
71     ConstByteSpan filter_id;
72     ASSERT_EQ(decoder.ReadBytes(&filter_id), OkStatus());
73     ASSERT_EQ(filter_id.size(), filter.id().size());
74     EXPECT_EQ(
75         std::memcmp(filter_id.data(), filter.id().data(), filter_id.size()), 0);
76   }
77   EXPECT_FALSE(decoder.Next().ok());
78 
79   // No IDs reported when the filter map is empty.
80   FilterMap empty_filter_map({});
81   PW_RAW_TEST_METHOD_CONTEXT(FilterService, ListFilterIds, 1)
82   no_filter_context(empty_filter_map);
83   no_filter_context.call({});
84   ASSERT_EQ(OkStatus(), no_filter_context.status());
85   ASSERT_TRUE(no_filter_context.done());
86   ASSERT_EQ(no_filter_context.responses().size(), 1u);
87   protobuf::Decoder no_filter_decoder(no_filter_context.responses()[0]);
88   uint32_t filter_count = 0;
89   while (no_filter_decoder.Next().ok()) {
90     EXPECT_EQ(no_filter_decoder.FieldNumber(), 1u);  // filter_id
91     ++filter_count;
92   }
93   EXPECT_EQ(filter_count, 0u);
94 }
95 
EncodeFilterRule(const Filter::Rule & rule,log::FilterRule::StreamEncoder & encoder)96 Status EncodeFilterRule(const Filter::Rule& rule,
97                         log::FilterRule::StreamEncoder& encoder) {
98   PW_TRY(
99       encoder.WriteLevelGreaterThanOrEqual(rule.level_greater_than_or_equal));
100   PW_TRY(encoder.WriteModuleEquals(rule.module_equals));
101   PW_TRY(encoder.WriteAnyFlagsSet(rule.any_flags_set));
102   return encoder.WriteAction(static_cast<log::FilterRule::Action>(rule.action));
103 }
104 
EncodeFilter(const Filter & filter,log::Filter::StreamEncoder & encoder)105 Status EncodeFilter(const Filter& filter, log::Filter::StreamEncoder& encoder) {
106   for (auto& rule : filter.rules()) {
107     log::FilterRule::StreamEncoder rule_encoder = encoder.GetRuleEncoder();
108     PW_TRY(EncodeFilterRule(rule, rule_encoder));
109   }
110   return OkStatus();
111 }
112 
EncodeFilterRequest(const Filter & filter,ByteSpan buffer)113 Result<ConstByteSpan> EncodeFilterRequest(const Filter& filter,
114                                           ByteSpan buffer) {
115   stream::MemoryWriter writer(buffer);
116   std::byte encode_buffer[256];
117   protobuf::StreamEncoder encoder(writer, encode_buffer);
118   PW_TRY(encoder.WriteBytes(
119       static_cast<uint32_t>(log::SetFilterRequest::Fields::FILTER_ID),
120       filter.id()));
121   {
122     log::Filter::StreamEncoder filter_encoder = encoder.GetNestedEncoder(
123         static_cast<uint32_t>(log::SetFilterRequest::Fields::FILTER));
124     PW_TRY(EncodeFilter(filter, filter_encoder));
125   }  // Let the StreamEncoder destructor finalize the data.
126   return ConstByteSpan(writer.data(), writer.bytes_written());
127 }
128 
VerifyRule(const Filter::Rule & rule,const Filter::Rule & expected_rule)129 void VerifyRule(const Filter::Rule& rule, const Filter::Rule& expected_rule) {
130   EXPECT_EQ(rule.level_greater_than_or_equal,
131             expected_rule.level_greater_than_or_equal);
132   EXPECT_EQ(rule.module_equals, expected_rule.module_equals);
133   EXPECT_EQ(rule.any_flags_set, expected_rule.any_flags_set);
134   EXPECT_EQ(rule.action, expected_rule.action);
135 }
136 
TEST_F(FilterServiceTest,SetFilterRules)137 TEST_F(FilterServiceTest, SetFilterRules) {
138   const std::array<Filter::Rule, 4> new_rules{{
139       {
140           .action = Filter::Rule::Action::kKeep,
141           .level_greater_than_or_equal = log::FilterRule::Level::DEBUG_LEVEL,
142           .any_flags_set = 0x0f,
143           .module_equals{std::byte(123)},
144       },
145       {
146           .action = Filter::Rule::Action::kInactive,
147           .level_greater_than_or_equal = log::FilterRule::Level::ANY_LEVEL,
148           .any_flags_set = 0xef,
149           .module_equals{},
150       },
151       {
152           .action = Filter::Rule::Action::kKeep,
153           .level_greater_than_or_equal = log::FilterRule::Level::INFO_LEVEL,
154           .any_flags_set = 0x1234,
155           .module_equals{std::byte(99)},
156       },
157       {
158           .action = Filter::Rule::Action::kDrop,
159           .level_greater_than_or_equal = log::FilterRule::Level::ANY_LEVEL,
160           .any_flags_set = 0,
161           .module_equals{std::byte(4)},
162       },
163   }};
164   const Filter new_filter(filters_[0].id(),
165                           const_cast<std::array<Filter::Rule, 4>&>(new_rules));
166 
167   std::byte request_buffer[512];
168   const auto request = EncodeFilterRequest(new_filter, request_buffer);
169   ASSERT_EQ(request.status(), OkStatus());
170 
171   PW_RAW_TEST_METHOD_CONTEXT(FilterService, SetFilter, 1)
172   context(filter_map_);
173   context.call(request.value());
174   ASSERT_EQ(OkStatus(), context.status());
175 
176   size_t i = 0;
177   for (const auto& rule : filters_[0].rules()) {
178     VerifyRule(rule, new_rules[i++]);
179   }
180 }
181 
TEST_F(FilterServiceTest,SetFilterRulesWhenUsedByDrain)182 TEST_F(FilterServiceTest, SetFilterRulesWhenUsedByDrain) {
183   const std::array<Filter::Rule, 4> new_filter_rules{{
184       {
185           .action = Filter::Rule::Action::kKeep,
186           .level_greater_than_or_equal = log::FilterRule::Level::CRITICAL_LEVEL,
187           .any_flags_set = 0xfd,
188           .module_equals{std::byte(543)},
189       },
190       {
191           .action = Filter::Rule::Action::kInactive,
192           .level_greater_than_or_equal = log::FilterRule::Level::ANY_LEVEL,
193           .any_flags_set = 0xca,
194           .module_equals{},
195       },
196       {
197           .action = Filter::Rule::Action::kKeep,
198           .level_greater_than_or_equal = log::FilterRule::Level::INFO_LEVEL,
199           .any_flags_set = 0xabcd,
200           .module_equals{std::byte(9000)},
201       },
202       {
203           .action = Filter::Rule::Action::kDrop,
204           .level_greater_than_or_equal = log::FilterRule::Level::ANY_LEVEL,
205           .any_flags_set = 0,
206           .module_equals{std::byte(123)},
207       },
208   }};
209   Filter& filter = filters_[0];
210   const Filter new_filter(
211       filter.id(), const_cast<std::array<Filter::Rule, 4>&>(new_filter_rules));
212 
213   std::byte request_buffer[256];
214   const auto request = EncodeFilterRequest(new_filter, request_buffer);
215   ASSERT_EQ(request.status(), OkStatus());
216 
217   PW_RAW_TEST_METHOD_CONTEXT(FilterService, SetFilter, 1)
218   context(filter_map_);
219   context.call(request.value());
220   ASSERT_EQ(OkStatus(), context.status());
221 
222   size_t i = 0;
223   for (const auto& rule : filter.rules()) {
224     VerifyRule(rule, new_filter_rules[i++]);
225   }
226 
227   // An empty request should not modify the filter.
228   PW_RAW_TEST_METHOD_CONTEXT(FilterService, SetFilter, 1)
229   context_no_filter(filter_map_);
230   context_no_filter.call({});
231   EXPECT_EQ(Status::OutOfRange(), context_no_filter.status());
232 
233   i = 0;
234   for (const auto& rule : filter.rules()) {
235     VerifyRule(rule, new_filter_rules[i++]);
236   }
237 
238   // A new request for logs with a new filter updates filter.
239   const std::array<Filter::Rule, 4> second_filter_rules{{
240       {
241           .action = Filter::Rule::Action::kKeep,
242           .level_greater_than_or_equal = log::FilterRule::Level::DEBUG_LEVEL,
243           .any_flags_set = 0xab,
244           .module_equals{},
245       },
246       {
247           .action = Filter::Rule::Action::kDrop,
248           .level_greater_than_or_equal = log::FilterRule::Level::ANY_LEVEL,
249           .any_flags_set = 0x11,
250           .module_equals{std::byte(34)},
251       },
252       {
253           .action = Filter::Rule::Action::kKeep,
254           .level_greater_than_or_equal = log::FilterRule::Level::ANY_LEVEL,
255           .any_flags_set = 0xef,
256           .module_equals{std::byte(23)},
257       },
258       {
259           .action = Filter::Rule::Action::kDrop,
260           .level_greater_than_or_equal = log::FilterRule::Level::ANY_LEVEL,
261           .any_flags_set = 0x0f,
262           .module_equals{},
263       },
264   }};
265   const Filter second_filter(
266       filter.id(),
267       const_cast<std::array<Filter::Rule, 4>&>(second_filter_rules));
268 
269   std::memset(request_buffer, 0, sizeof(request_buffer));
270   const auto second_filter_request =
271       EncodeFilterRequest(second_filter, request_buffer);
272   ASSERT_EQ(second_filter_request.status(), OkStatus());
273   PW_RAW_TEST_METHOD_CONTEXT(FilterService, SetFilter, 1)
274   context_new_filter(filter_map_);
275   context_new_filter.call(second_filter_request.value());
276   ASSERT_EQ(OkStatus(), context.status());
277 
278   i = 0;
279   for (const auto& rule : filter.rules()) {
280     VerifyRule(rule, second_filter_rules[i++]);
281   }
282 }
283 
VerifyFilterRule(protobuf::Decoder & decoder,const Filter::Rule & expected_rule)284 void VerifyFilterRule(protobuf::Decoder& decoder,
285                       const Filter::Rule& expected_rule) {
286   ASSERT_TRUE(decoder.Next().ok());
287   ASSERT_EQ(decoder.FieldNumber(), 1u);  // level_greater_than_or_equal
288   log::FilterRule::Level level_greater_than_or_equal;
289   ASSERT_EQ(decoder.ReadUint32(
290                 reinterpret_cast<uint32_t*>(&level_greater_than_or_equal)),
291             OkStatus());
292   EXPECT_EQ(level_greater_than_or_equal,
293             expected_rule.level_greater_than_or_equal);
294 
295   ASSERT_TRUE(decoder.Next().ok());
296   ASSERT_EQ(decoder.FieldNumber(), 2u);  // module_equals
297   ConstByteSpan module_equals;
298   ASSERT_EQ(decoder.ReadBytes(&module_equals), OkStatus());
299   ASSERT_EQ(module_equals.size(), expected_rule.module_equals.size());
300   EXPECT_EQ(std::memcmp(module_equals.data(),
301                         expected_rule.module_equals.data(),
302                         module_equals.size()),
303             0);
304 
305   ASSERT_TRUE(decoder.Next().ok());
306   ASSERT_EQ(decoder.FieldNumber(), 3u);  // any_flags_set
307   uint32_t any_flags_set;
308   ASSERT_EQ(decoder.ReadUint32(&any_flags_set), OkStatus());
309   EXPECT_EQ(any_flags_set, expected_rule.any_flags_set);
310 
311   ASSERT_TRUE(decoder.Next().ok());
312   ASSERT_EQ(decoder.FieldNumber(), 4u);  // action
313   Filter::Rule::Action action;
314   ASSERT_EQ(decoder.ReadUint32(reinterpret_cast<uint32_t*>(&action)),
315             OkStatus());
316   EXPECT_EQ(action, expected_rule.action);
317 }
318 
VerifyFilterRules(protobuf::Decoder & decoder,std::span<const Filter::Rule> expected_rules)319 void VerifyFilterRules(protobuf::Decoder& decoder,
320                        std::span<const Filter::Rule> expected_rules) {
321   size_t rules_found = 0;
322   while (decoder.Next().ok()) {
323     ConstByteSpan rule;
324     EXPECT_TRUE(decoder.ReadBytes(&rule).ok());
325     protobuf::Decoder rule_decoder(rule);
326     if (rules_found >= expected_rules.size()) {
327       break;
328     }
329     VerifyFilterRule(rule_decoder, expected_rules[rules_found]);
330     ++rules_found;
331   }
332   EXPECT_EQ(rules_found, expected_rules.size());
333 }
334 
TEST_F(FilterServiceTest,GetFilterRules)335 TEST_F(FilterServiceTest, GetFilterRules) {
336   PW_RAW_TEST_METHOD_CONTEXT(FilterService, GetFilter, 1)
337   context(filter_map_);
338 
339   std::byte request_buffer[64];
340   log::GetFilterRequest::MemoryEncoder encoder(request_buffer);
341   ASSERT_EQ(OkStatus(), encoder.WriteFilterId(filter_id1_));
342   const auto request = ConstByteSpan(encoder);
343   context.call(request);
344   ASSERT_EQ(OkStatus(), context.status());
345   ASSERT_TRUE(context.done());
346   ASSERT_EQ(context.responses().size(), 1u);
347 
348   // Verify against empty rules.
349   protobuf::Decoder decoder(context.responses()[0]);
350   VerifyFilterRules(decoder, rules1_);
351 
352   // Partially populate rules.
353   rules1_[0].action = Filter::Rule::Action::kKeep;
354   rules1_[0].level_greater_than_or_equal = log::FilterRule::Level::DEBUG_LEVEL;
355   rules1_[0].any_flags_set = 0xab;
356   const std::array<std::byte, 2> module1{std::byte(123), std::byte(0xab)};
357   rules1_[0].module_equals.assign(module1.begin(), module1.end());
358   rules1_[1].action = Filter::Rule::Action::kDrop;
359   rules1_[1].level_greater_than_or_equal = log::FilterRule::Level::ERROR_LEVEL;
360   rules1_[1].any_flags_set = 0;
361 
362   PW_RAW_TEST_METHOD_CONTEXT(FilterService, GetFilter, 1)
363   context2(filter_map_);
364   context2.call(request);
365   ASSERT_EQ(OkStatus(), context2.status());
366   ASSERT_EQ(context2.responses().size(), 1u);
367   protobuf::Decoder decoder2(context2.responses()[0]);
368   VerifyFilterRules(decoder2, rules1_);
369 
370   // Modify the rest of the filter rules.
371   rules1_[2].action = Filter::Rule::Action::kKeep;
372   rules1_[2].level_greater_than_or_equal = log::FilterRule::Level::FATAL_LEVEL;
373   rules1_[2].any_flags_set = 0xcd;
374   const std::array<std::byte, 2> module2{std::byte(1), std::byte(2)};
375   rules1_[2].module_equals.assign(module2.begin(), module2.end());
376   rules1_[3].action = Filter::Rule::Action::kInactive;
377 
378   PW_RAW_TEST_METHOD_CONTEXT(FilterService, GetFilter, 1)
379   context3(filter_map_);
380   context3.call(request);
381   ASSERT_EQ(OkStatus(), context3.status());
382   ASSERT_EQ(context3.responses().size(), 1u);
383   protobuf::Decoder decoder3(context3.responses()[0]);
384   VerifyFilterRules(decoder3, rules1_);
385 }
386 
387 }  // namespace
388 }  // namespace pw::log_rpc
389