blob: 2fb2982a2d50ad4bbd3b315a0b25ecea520ad7b3 [file] [log] [blame]
// Copyright 2021 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_sink/log_sink.h"
#include <string>
#include "gtest/gtest.h"
#include "pw_log/levels.h"
#include "pw_log/proto/log.pwpb.h"
#include "pw_log_sink/multisink_adapter.h"
#include "pw_multisink/multisink.h"
#include "pw_protobuf/decoder.h"
namespace pw::log_sink {
namespace {
constexpr size_t kMaxTokenizedMessageSize = 512;
constexpr char kTokenizedMessage[] = "Test Message";
std::string LogMessageToString(ConstByteSpan message) {
pw::protobuf::Decoder log_decoder(message);
std::string_view log_entry_message;
EXPECT_TRUE(log_decoder.Next().ok()); // line_level - 2
EXPECT_TRUE(log_decoder.Next().ok()); // flags - 3
EXPECT_TRUE(log_decoder.Next().ok()); // timestamp - 5
EXPECT_TRUE(log_decoder.Next().ok()); // message - 1
EXPECT_EQ(1u, log_decoder.FieldNumber());
EXPECT_TRUE(log_decoder.ReadString(&log_entry_message).ok());
return std::string(log_entry_message);
}
void LogMessageForTest(const char* message) {
pw_LogSink_Log(0, 0, nullptr, nullptr, 0, nullptr, "%s", message);
}
void LogInvalidMessageForTest() {
char long_message[kMaxTokenizedMessageSize + 1];
memset(long_message, 'A', sizeof(long_message));
long_message[kMaxTokenizedMessageSize] = '\0';
pw_LogSink_Log(0, 0, nullptr, nullptr, 0, nullptr, "%s", long_message);
}
class TestSink final : public Sink {
public:
void HandleEntry(ConstByteSpan message) final {
last_message_string_ = LogMessageToString(message);
message_count_++;
}
void HandleDropped(uint32_t count) final { drop_count_ += count; }
void VerifyMessage(std::string tokenized_message) {
EXPECT_EQ(tokenized_message, last_message_string_);
}
uint32_t GetMessageCount() { return message_count_; }
uint32_t GetDropCount() { return drop_count_; }
private:
std::string last_message_string_;
uint32_t message_count_ = 0;
uint32_t drop_count_ = 0;
};
} // namespace
TEST(LogSink, NoSink) {
// Confirm that the log function does not crash when no sink is present.
LogMessageForTest(kTokenizedMessage);
}
TEST(LogSink, SingleSink) {
TestSink test_sink;
AddSink(test_sink);
LogMessageForTest(kTokenizedMessage);
test_sink.VerifyMessage(kTokenizedMessage);
RemoveSink(test_sink);
}
TEST(LogSink, MultipleSink) {
TestSink test_sink_io;
TestSink test_sink_bt;
AddSink(test_sink_io);
AddSink(test_sink_bt);
LogMessageForTest(kTokenizedMessage);
test_sink_io.VerifyMessage(kTokenizedMessage);
test_sink_bt.VerifyMessage(kTokenizedMessage);
RemoveSink(test_sink_io);
LogMessageForTest(kTokenizedMessage);
test_sink_io.VerifyMessage(kTokenizedMessage);
EXPECT_EQ(test_sink_io.GetMessageCount(), 1U);
EXPECT_EQ(test_sink_bt.GetMessageCount(), 2U);
RemoveSink(test_sink_bt);
}
TEST(LogSink, DroppedEntries) {
TestSink test_sink;
LogMessageForTest(kTokenizedMessage);
AddSink(test_sink);
LogMessageForTest(kTokenizedMessage);
EXPECT_EQ(test_sink.GetMessageCount(), 1U);
EXPECT_EQ(test_sink.GetDropCount(), 1U);
LogInvalidMessageForTest();
EXPECT_EQ(test_sink.GetMessageCount(), 1U);
EXPECT_EQ(test_sink.GetDropCount(), 2U);
LogMessageForTest(kTokenizedMessage);
EXPECT_EQ(test_sink.GetMessageCount(), 2U);
EXPECT_EQ(test_sink.GetDropCount(), 2U);
RemoveSink(test_sink);
}
TEST(LogSink, MultiSinkAdapter) {
constexpr size_t kMultiSinkBufferSize = 1024;
std::byte buffer[kMultiSinkBufferSize];
std::byte entry_buffer[kMultiSinkBufferSize];
pw::multisink::MultiSink multisink(buffer);
pw::multisink::MultiSink::Drain drain;
MultiSinkAdapter multisink_adapter(multisink);
multisink.AttachDrain(drain);
LogMessageForTest(kTokenizedMessage);
AddSink(multisink_adapter);
LogMessageForTest(kTokenizedMessage);
uint32_t drop_count = 0;
Result<ConstByteSpan> entry = drain.GetEntry(entry_buffer, drop_count);
ASSERT_TRUE(entry.ok());
EXPECT_EQ(LogMessageToString(entry.value()), kTokenizedMessage);
EXPECT_EQ(drop_count, 1U);
}
} // namespace pw::log_sink