1 // Copyright 2020 The Pigweed Authors
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
7 // https://www.apache.org/licenses/LICENSE-2.0
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
15 #include "pw_log_rpc/log_queue.h"
17 #include "gtest/gtest.h"
18 #include "pw_log/levels.h"
19 #include "pw_log_rpc_proto/log.pwpb.h"
20 #include "pw_protobuf/decoder.h"
22 namespace pw::log_rpc {
25 constexpr size_t kEncodeBufferSize = 512;
27 constexpr const char kTokenizedMessage[] = "msg_token";
28 constexpr uint32_t kFlags = 0xF;
29 constexpr uint32_t kLevel = 0b010;
30 constexpr uint32_t kLine = 0b101011000;
31 constexpr uint32_t kTokenizedThread = 0xF;
32 constexpr int64_t kTimestamp = 0;
34 constexpr size_t kLogBufferSize = kEncodeBufferSize * 3;
36 void VerifyLogEntry(pw::protobuf::Decoder& log_decoder,
37 const char* expected_tokenized_message,
38 const uint32_t expected_flags,
39 const uint32_t expected_level,
40 const uint32_t expected_line,
41 const uint32_t expected_tokenized_thread,
42 const int64_t expected_timestamp) {
43 ConstByteSpan log_entry_message;
44 EXPECT_TRUE(log_decoder.Next().ok()); // preamble
45 EXPECT_EQ(1U, log_decoder.FieldNumber());
46 EXPECT_TRUE(log_decoder.ReadBytes(&log_entry_message).ok());
48 pw::protobuf::Decoder entry_decoder(log_entry_message);
49 ConstByteSpan tokenized_message;
50 EXPECT_TRUE(entry_decoder.Next().ok()); // tokenized_message
51 EXPECT_EQ(1U, entry_decoder.FieldNumber());
52 EXPECT_TRUE(entry_decoder.ReadBytes(&tokenized_message).ok());
53 EXPECT_TRUE(std::memcmp(tokenized_message.begin(),
54 (const void*)expected_tokenized_message,
55 tokenized_message.size()) == 0);
58 EXPECT_TRUE(entry_decoder.Next().ok()); // line_level
59 EXPECT_EQ(2U, entry_decoder.FieldNumber());
60 EXPECT_TRUE(entry_decoder.ReadUint32(&line_level).ok());
61 EXPECT_EQ(expected_level, line_level & PW_LOG_LEVEL_BITMASK);
62 EXPECT_EQ(expected_line,
63 (line_level & ~PW_LOG_LEVEL_BITMASK) >> PW_LOG_LEVEL_BITWIDTH);
66 EXPECT_TRUE(entry_decoder.Next().ok()); // flags
67 EXPECT_EQ(3U, entry_decoder.FieldNumber());
68 EXPECT_TRUE(entry_decoder.ReadUint32(&flags).ok());
69 EXPECT_EQ(expected_flags, flags);
71 uint32_t tokenized_thread;
72 EXPECT_TRUE(entry_decoder.Next().ok()); // tokenized_thread
73 EXPECT_EQ(4U, entry_decoder.FieldNumber());
74 EXPECT_TRUE(entry_decoder.ReadUint32(&tokenized_thread).ok());
75 EXPECT_EQ(expected_tokenized_thread, tokenized_thread);
78 EXPECT_TRUE(entry_decoder.Next().ok()); // timestamp
79 EXPECT_EQ(5U, entry_decoder.FieldNumber());
80 EXPECT_TRUE(entry_decoder.ReadInt64(×tamp).ok());
81 EXPECT_EQ(expected_timestamp, timestamp);
86 TEST(LogQueue, SinglePushPopTokenizedMessage) {
87 std::byte log_buffer[kLogBufferSize];
88 LogQueueWithEncodeBuffer<kEncodeBufferSize> log_queue(log_buffer);
91 log_queue.PushTokenizedMessage(
92 std::as_bytes(std::span(kTokenizedMessage)),
99 std::byte log_entry[kEncodeBufferSize];
100 Result<ConstByteSpan> pop_result = log_queue.Pop(std::span(log_entry));
101 EXPECT_TRUE(pop_result.ok());
103 pw::protobuf::Decoder log_decoder(pop_result.value());
104 VerifyLogEntry(log_decoder,
113 TEST(LogQueue, MultiplePushPopTokenizedMessage) {
114 constexpr int kEntryCount = 3;
116 std::byte log_buffer[1024];
117 LogQueueWithEncodeBuffer<kEncodeBufferSize> log_queue(log_buffer);
119 for (int i = 0; i < kEntryCount; i++) {
120 EXPECT_EQ(Status::OK,
121 log_queue.PushTokenizedMessage(
122 std::as_bytes(std::span(kTokenizedMessage)),
130 std::byte log_entry[kEncodeBufferSize];
131 for (int i = 0; i < kEntryCount; i++) {
132 Result<ConstByteSpan> pop_result = log_queue.Pop(std::span(log_entry));
133 EXPECT_TRUE(pop_result.ok());
135 pw::protobuf::Decoder log_decoder(pop_result.value());
136 VerifyLogEntry(log_decoder,
146 TEST(LogQueue, PopMultiple) {
147 constexpr int kEntryCount = 3;
149 std::byte log_buffer[kLogBufferSize];
150 LogQueueWithEncodeBuffer<kEncodeBufferSize> log_queue(log_buffer);
152 for (int i = 0; i < kEntryCount; i++) {
153 EXPECT_EQ(Status::OK,
154 log_queue.PushTokenizedMessage(
155 std::as_bytes(std::span(kTokenizedMessage)),
163 std::byte log_entries[kLogBufferSize];
164 Result<ConstByteSpan> pop_result = log_queue.PopMultiple(log_entries);
165 EXPECT_TRUE(pop_result.ok());
167 pw::protobuf::Decoder log_decoder(pop_result.value());
168 for (int i = 0; i < kEntryCount; i++) {
169 VerifyLogEntry(log_decoder,
179 TEST(LogQueue, TooSmallEncodeBuffer) {
180 constexpr size_t kSmallBuffer = 1;
182 std::byte log_buffer[kLogBufferSize];
183 LogQueueWithEncodeBuffer<kSmallBuffer> log_queue(log_buffer);
184 EXPECT_EQ(Status::INTERNAL,
185 log_queue.PushTokenizedMessage(
186 std::as_bytes(std::span(kTokenizedMessage)),
194 TEST(LogQueue, TooSmallLogBuffer) {
195 constexpr size_t kSmallerThanPreamble = 1;
196 constexpr size_t kEntryCount = 100;
198 // Expect OUT_OF_RANGE when the buffer is smaller than a preamble.
199 std::byte log_buffer[kLogBufferSize];
200 LogQueueWithEncodeBuffer<kEncodeBufferSize> log_queue_small(
201 std::span(log_buffer, kSmallerThanPreamble));
202 EXPECT_EQ(Status::OUT_OF_RANGE,
203 log_queue_small.PushTokenizedMessage(
204 std::as_bytes(std::span(kTokenizedMessage)),
211 // Expect RESOURCE_EXHAUSTED when there's not enough space for the chunk.
212 LogQueueWithEncodeBuffer<kEncodeBufferSize> log_queue_medium(log_buffer);
213 for (size_t i = 0; i < kEntryCount; i++) {
214 log_queue_medium.PushTokenizedMessage(
215 std::as_bytes(std::span(kTokenizedMessage)),
222 EXPECT_EQ(Status::RESOURCE_EXHAUSTED,
223 log_queue_medium.PushTokenizedMessage(
224 std::as_bytes(std::span(kTokenizedMessage)),
232 } // namespace pw::log_rpc