168 lines
6.6 KiB
C++
168 lines
6.6 KiB
C++
// Copyright 2022 The Pigweed Authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
// use this file except in compliance with the License. You may obtain a copy of
|
|
// the License at
|
|
//
|
|
// https://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
// License for the specific language governing permissions and limitations under
|
|
// the License.
|
|
|
|
#include "pw_log_rpc_private/test_utils.h"
|
|
|
|
#include <cstdint>
|
|
|
|
#include "gtest/gtest.h"
|
|
#include "pw_bytes/span.h"
|
|
#include "pw_containers/vector.h"
|
|
#include "pw_log/log.h"
|
|
#include "pw_log/proto/log.pwpb.h"
|
|
#include "pw_log_tokenized/metadata.h"
|
|
#include "pw_protobuf/bytes_utils.h"
|
|
#include "pw_protobuf/decoder.h"
|
|
|
|
namespace pw::log_rpc {
|
|
namespace {
|
|
void VerifyOptionallyTokenizedField(protobuf::Decoder& entry_decoder,
|
|
log::LogEntry::Fields field_number,
|
|
ConstByteSpan expected_data) {
|
|
if (expected_data.empty()) {
|
|
return;
|
|
}
|
|
ConstByteSpan tokenized_data;
|
|
ASSERT_EQ(entry_decoder.Next(), OkStatus());
|
|
ASSERT_EQ(entry_decoder.FieldNumber(), static_cast<uint32_t>(field_number));
|
|
ASSERT_EQ(entry_decoder.ReadBytes(&tokenized_data), OkStatus());
|
|
std::string_view data_as_string(
|
|
reinterpret_cast<const char*>(tokenized_data.begin()),
|
|
tokenized_data.size());
|
|
std::string_view expected_data_as_string(
|
|
reinterpret_cast<const char*>(expected_data.begin()),
|
|
expected_data.size());
|
|
EXPECT_EQ(data_as_string, expected_data_as_string);
|
|
}
|
|
} // namespace
|
|
|
|
// Unpacks a `LogEntry` proto buffer to compare it with the expected data and
|
|
// updates the total drop count found.
|
|
void VerifyLogEntry(protobuf::Decoder& entry_decoder,
|
|
const TestLogEntry& expected_entry,
|
|
uint32_t& drop_count_out) {
|
|
VerifyOptionallyTokenizedField(entry_decoder,
|
|
log::LogEntry::Fields::MESSAGE,
|
|
expected_entry.tokenized_data);
|
|
if (expected_entry.metadata.level()) {
|
|
ASSERT_EQ(entry_decoder.Next(), OkStatus());
|
|
ASSERT_EQ(entry_decoder.FieldNumber(),
|
|
static_cast<uint32_t>(log::LogEntry::Fields::LINE_LEVEL));
|
|
uint32_t line_level;
|
|
ASSERT_TRUE(entry_decoder.ReadUint32(&line_level).ok());
|
|
EXPECT_EQ(expected_entry.metadata.level(),
|
|
line_level & PW_LOG_LEVEL_BITMASK);
|
|
EXPECT_EQ(expected_entry.metadata.line_number(),
|
|
(line_level & ~PW_LOG_LEVEL_BITMASK) >> PW_LOG_LEVEL_BITS);
|
|
}
|
|
if (expected_entry.metadata.flags()) {
|
|
ASSERT_EQ(entry_decoder.Next(), OkStatus());
|
|
ASSERT_EQ(entry_decoder.FieldNumber(),
|
|
static_cast<uint32_t>(log::LogEntry::Fields::FLAGS));
|
|
uint32_t flags;
|
|
ASSERT_TRUE(entry_decoder.ReadUint32(&flags).ok());
|
|
EXPECT_EQ(expected_entry.metadata.flags(), flags);
|
|
}
|
|
if (expected_entry.timestamp) {
|
|
ASSERT_EQ(entry_decoder.Next(), OkStatus());
|
|
ASSERT_TRUE(entry_decoder.FieldNumber() ==
|
|
static_cast<uint32_t>(log::LogEntry::Fields::TIMESTAMP) ||
|
|
entry_decoder.FieldNumber() ==
|
|
static_cast<uint32_t>(
|
|
log::LogEntry::Fields::TIME_SINCE_LAST_ENTRY));
|
|
int64_t timestamp;
|
|
ASSERT_TRUE(entry_decoder.ReadInt64(×tamp).ok());
|
|
EXPECT_EQ(expected_entry.timestamp, timestamp);
|
|
}
|
|
if (expected_entry.dropped) {
|
|
ASSERT_EQ(entry_decoder.Next(), OkStatus());
|
|
ASSERT_EQ(entry_decoder.FieldNumber(),
|
|
static_cast<uint32_t>(log::LogEntry::Fields::DROPPED));
|
|
uint32_t dropped = 0;
|
|
ASSERT_TRUE(entry_decoder.ReadUint32(&dropped).ok());
|
|
EXPECT_EQ(expected_entry.dropped, dropped);
|
|
drop_count_out += dropped;
|
|
}
|
|
if (expected_entry.metadata.module()) {
|
|
ASSERT_EQ(entry_decoder.Next(), OkStatus());
|
|
ASSERT_EQ(entry_decoder.FieldNumber(),
|
|
static_cast<uint32_t>(log::LogEntry::Fields::MODULE));
|
|
const Result<uint32_t> module =
|
|
protobuf::DecodeBytesToUint32(entry_decoder);
|
|
ASSERT_EQ(module.status(), OkStatus());
|
|
EXPECT_EQ(expected_entry.metadata.module(), module.value());
|
|
}
|
|
VerifyOptionallyTokenizedField(
|
|
entry_decoder, log::LogEntry::Fields::FILE, expected_entry.file);
|
|
VerifyOptionallyTokenizedField(
|
|
entry_decoder, log::LogEntry::Fields::THREAD, expected_entry.thread);
|
|
}
|
|
|
|
// Compares an encoded LogEntry's fields against the expected sequence ID and
|
|
// LogEntries, and updates the total entry and drop counts. Starts comparing at
|
|
// `expected_entries[entries_count_out]`. `expected_entries` must be in the same
|
|
// order that messages were added to the MultiSink.
|
|
void 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) {
|
|
size_t entry_index = entries_count_out;
|
|
while (entries_decoder.Next().ok()) {
|
|
if (static_cast<pw::log::LogEntries::Fields>(
|
|
entries_decoder.FieldNumber()) ==
|
|
log::LogEntries::Fields::ENTRIES) {
|
|
ConstByteSpan entry;
|
|
EXPECT_EQ(entries_decoder.ReadBytes(&entry), OkStatus());
|
|
protobuf::Decoder entry_decoder(entry);
|
|
if (expected_entries.empty()) {
|
|
break;
|
|
}
|
|
|
|
ASSERT_LT(entry_index, expected_entries.size());
|
|
|
|
// Keep track of entries and drops respective counts.
|
|
uint32_t current_drop_count = 0;
|
|
VerifyLogEntry(
|
|
entry_decoder, expected_entries[entry_index], current_drop_count);
|
|
++entry_index;
|
|
drop_count_out += current_drop_count;
|
|
if (current_drop_count == 0) {
|
|
++entries_count_out;
|
|
}
|
|
} else if (static_cast<pw::log::LogEntries::Fields>(
|
|
entries_decoder.FieldNumber()) ==
|
|
log::LogEntries::Fields::FIRST_ENTRY_SEQUENCE_ID) {
|
|
uint32_t first_entry_sequence_id = 0;
|
|
EXPECT_EQ(entries_decoder.ReadUint32(&first_entry_sequence_id),
|
|
OkStatus());
|
|
EXPECT_EQ(expected_first_entry_sequence_id, first_entry_sequence_id);
|
|
}
|
|
}
|
|
}
|
|
|
|
size_t CountLogEntries(protobuf::Decoder& entries_decoder) {
|
|
size_t entries_found = 0;
|
|
while (entries_decoder.Next().ok()) {
|
|
if (static_cast<pw::log::LogEntries::Fields>(
|
|
entries_decoder.FieldNumber()) ==
|
|
log::LogEntries::Fields::ENTRIES) {
|
|
++entries_found;
|
|
}
|
|
}
|
|
return entries_found;
|
|
}
|
|
|
|
} // namespace pw::log_rpc
|