xref: /aosp_15_r20/external/pigweed/pw_log_rpc/test_utils.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2022 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_private/test_utils.h"
16 
17 #include <cstdint>
18 
19 #include "pw_bytes/span.h"
20 #include "pw_containers/vector.h"
21 #include "pw_log/log.h"
22 #include "pw_log/proto/log.pwpb.h"
23 #include "pw_log_tokenized/metadata.h"
24 #include "pw_protobuf/bytes_utils.h"
25 #include "pw_protobuf/decoder.h"
26 #include "pw_unit_test/framework.h"
27 
28 namespace pw::log_rpc {
29 namespace {
VerifyOptionallyTokenizedField(protobuf::Decoder & entry_decoder,log::pwpb::LogEntry::Fields field_number,ConstByteSpan expected_data)30 void VerifyOptionallyTokenizedField(protobuf::Decoder& entry_decoder,
31                                     log::pwpb::LogEntry::Fields field_number,
32                                     ConstByteSpan expected_data) {
33   if (expected_data.empty()) {
34     return;
35   }
36   ConstByteSpan tokenized_data;
37   ASSERT_EQ(entry_decoder.Next(), OkStatus());
38   ASSERT_EQ(entry_decoder.FieldNumber(), static_cast<uint32_t>(field_number));
39   ASSERT_EQ(entry_decoder.ReadBytes(&tokenized_data), OkStatus());
40   std::string_view data_as_string(
41       reinterpret_cast<const char*>(tokenized_data.data()),
42       tokenized_data.size());
43   std::string_view expected_data_as_string(
44       reinterpret_cast<const char*>(expected_data.data()),
45       expected_data.size());
46   EXPECT_EQ(data_as_string, expected_data_as_string);
47 }
48 }  // namespace
49 
50 // Unpacks a `LogEntry` proto buffer to compare it with the expected data and
51 // updates the total drop count found.
VerifyLogEntry(protobuf::Decoder & entry_decoder,const TestLogEntry & expected_entry,uint32_t & drop_count_out)52 void VerifyLogEntry(protobuf::Decoder& entry_decoder,
53                     const TestLogEntry& expected_entry,
54                     uint32_t& drop_count_out) {
55   VerifyOptionallyTokenizedField(entry_decoder,
56                                  log::pwpb::LogEntry::Fields::kMessage,
57                                  expected_entry.tokenized_data);
58   if (expected_entry.metadata.level()) {
59     ASSERT_EQ(entry_decoder.Next(), OkStatus());
60     ASSERT_EQ(entry_decoder.FieldNumber(),
61               static_cast<uint32_t>(log::pwpb::LogEntry::Fields::kLineLevel));
62     uint32_t line_level;
63     ASSERT_TRUE(entry_decoder.ReadUint32(&line_level).ok());
64     EXPECT_EQ(expected_entry.metadata.level(),
65               line_level & PW_LOG_LEVEL_BITMASK);
66     EXPECT_EQ(expected_entry.metadata.line_number(),
67               (line_level & ~PW_LOG_LEVEL_BITMASK) >> PW_LOG_LEVEL_BITS);
68   }
69   if (expected_entry.metadata.flags()) {
70     ASSERT_EQ(entry_decoder.Next(), OkStatus());
71     ASSERT_EQ(entry_decoder.FieldNumber(),
72               static_cast<uint32_t>(log::pwpb::LogEntry::Fields::kFlags));
73     uint32_t flags;
74     ASSERT_TRUE(entry_decoder.ReadUint32(&flags).ok());
75     EXPECT_EQ(expected_entry.metadata.flags(), flags);
76   }
77   if (expected_entry.timestamp) {
78     ASSERT_EQ(entry_decoder.Next(), OkStatus());
79     ASSERT_TRUE(
80         entry_decoder.FieldNumber() ==
81             static_cast<uint32_t>(log::pwpb::LogEntry::Fields::kTimestamp) ||
82         entry_decoder.FieldNumber() ==
83             static_cast<uint32_t>(
84                 log::pwpb::LogEntry::Fields::kTimeSinceLastEntry));
85     int64_t timestamp;
86     ASSERT_TRUE(entry_decoder.ReadInt64(&timestamp).ok());
87     EXPECT_EQ(expected_entry.timestamp, timestamp);
88   }
89   if (expected_entry.dropped) {
90     ASSERT_EQ(entry_decoder.Next(), OkStatus());
91     ASSERT_EQ(entry_decoder.FieldNumber(),
92               static_cast<uint32_t>(log::pwpb::LogEntry::Fields::kDropped));
93     uint32_t dropped = 0;
94     ASSERT_TRUE(entry_decoder.ReadUint32(&dropped).ok());
95     EXPECT_EQ(expected_entry.dropped, dropped);
96     drop_count_out += dropped;
97   }
98   if (expected_entry.metadata.module()) {
99     ASSERT_EQ(entry_decoder.Next(), OkStatus());
100     ASSERT_EQ(entry_decoder.FieldNumber(),
101               static_cast<uint32_t>(log::pwpb::LogEntry::Fields::kModule));
102     const Result<uint32_t> module =
103         protobuf::DecodeBytesToUint32(entry_decoder);
104     ASSERT_EQ(module.status(), OkStatus());
105     EXPECT_EQ(expected_entry.metadata.module(), module.value());
106   }
107   VerifyOptionallyTokenizedField(
108       entry_decoder, log::pwpb::LogEntry::Fields::kFile, expected_entry.file);
109   VerifyOptionallyTokenizedField(entry_decoder,
110                                  log::pwpb::LogEntry::Fields::kThread,
111                                  expected_entry.thread);
112 }
113 
114 // Compares an encoded LogEntry's fields against the expected sequence ID and
115 // LogEntries, and updates the total entry and drop counts. Starts comparing at
116 // `expected_entries[entries_count_out]`. `expected_entries` must be in the same
117 // order that messages were added to the MultiSink.
VerifyLogEntries(protobuf::Decoder & entries_decoder,const Vector<TestLogEntry> & expected_entries,uint32_t expected_first_entry_sequence_id,size_t & entries_count_out,uint32_t & drop_count_out)118 void VerifyLogEntries(protobuf::Decoder& entries_decoder,
119                       const Vector<TestLogEntry>& expected_entries,
120                       uint32_t expected_first_entry_sequence_id,
121                       size_t& entries_count_out,
122                       uint32_t& drop_count_out) {
123   size_t entry_index = entries_count_out;
124   while (entries_decoder.Next().ok()) {
125     if (static_cast<log::pwpb::LogEntries::Fields>(
126             entries_decoder.FieldNumber()) ==
127         log::pwpb::LogEntries::Fields::kEntries) {
128       ConstByteSpan entry;
129       EXPECT_EQ(entries_decoder.ReadBytes(&entry), OkStatus());
130       protobuf::Decoder entry_decoder(entry);
131       if (expected_entries.empty()) {
132         break;
133       }
134 
135       ASSERT_LT(entry_index, expected_entries.size());
136 
137       // Keep track of entries and drops respective counts.
138       uint32_t current_drop_count = 0;
139       VerifyLogEntry(
140           entry_decoder, expected_entries[entry_index], current_drop_count);
141       ++entry_index;
142       drop_count_out += current_drop_count;
143       if (current_drop_count == 0) {
144         ++entries_count_out;
145       }
146     } else if (static_cast<log::pwpb::LogEntries::Fields>(
147                    entries_decoder.FieldNumber()) ==
148                log::pwpb::LogEntries::Fields::kFirstEntrySequenceId) {
149       uint32_t first_entry_sequence_id = 0;
150       EXPECT_EQ(entries_decoder.ReadUint32(&first_entry_sequence_id),
151                 OkStatus());
152       EXPECT_EQ(expected_first_entry_sequence_id, first_entry_sequence_id);
153     }
154   }
155 }
156 
CountLogEntries(protobuf::Decoder & entries_decoder)157 size_t CountLogEntries(protobuf::Decoder& entries_decoder) {
158   size_t entries_found = 0;
159   while (entries_decoder.Next().ok()) {
160     if (static_cast<log::pwpb::LogEntries::Fields>(
161             entries_decoder.FieldNumber()) ==
162         log::pwpb::LogEntries::Fields::kEntries) {
163       ++entries_found;
164     }
165   }
166   return entries_found;
167 }
168 
169 }  // namespace pw::log_rpc
170