blob: 78987e6214e1563703138af88739a21661ff0a65 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "managed_logger.h"
#include <lib/gtest/real_loop_fixture.h>
#include "log_listener.h"
#include "log_listener_test_helpers.h"
#include "src/lib/fxl/strings/join_strings.h"
#include "src/lib/testing/predicates/status.h"
namespace netemul {
namespace testing {
constexpr const char* kLoggerName = "my_logger";
class ManagedLoggerTest : public gtest::RealLoopFixture {
public:
using LogLevel = fuchsia::logger::LogLevelFilter;
ManagedLoggerTest() : gtest::RealLoopFixture(), listener_(new TestListener()) {}
protected:
void Startup(std::string name, bool is_err) {
logger_ = std::make_unique<ManagedLogger>(std::move(name), is_err, listener_);
sock_.reset(logger_->CreateHandle().release());
logger_->Start([](ManagedLogger* logger) { FAIL() << "Managed logger shouldn't close"; });
}
void Write(const std::string& msg) {
size_t actual = 0;
EXPECT_OK(sock_.write(0, msg.c_str(), msg.length(), &actual));
EXPECT_EQ(actual, msg.length());
}
std::vector<fuchsia::logger::LogMessage>& messages() { return listener_->messages(); }
void WaitForMessageCount(size_t len) {
RunLoopUntil([this, len]() { return messages().size() >= len; });
}
void CheckMessage(const fuchsia::logger::LogMessage& msg, LogLevel severity,
const std::string& str, const std::vector<std::string>& tags) {
EXPECT_EQ(msg.dropped_logs, 0u);
EXPECT_EQ(msg.pid, 0u);
EXPECT_EQ(msg.tid, 0u);
EXPECT_NE(msg.time, 0u);
EXPECT_EQ(msg.severity, static_cast<int32_t>(severity));
EXPECT_EQ(msg.msg, str);
EXPECT_EQ(msg.tags.size(), tags.size());
for (const auto& t : tags) {
EXPECT_NE(std::find(msg.tags.begin(), msg.tags.end(), t), msg.tags.end())
<< "Tag " << t << " in message, but got tags " << fxl::JoinStrings(msg.tags, ",");
}
}
void DestroyLogger() { logger_ = nullptr; }
zx::socket& socket() { return sock_; }
private:
zx::socket sock_;
std::shared_ptr<TestListener> listener_;
std::unique_ptr<ManagedLogger> logger_;
};
TEST_F(ManagedLoggerTest, BreaksNewLines) {
Startup(kLoggerName, false);
Write("Hello\nWorld\nExtra");
WaitForMessageCount(2);
// no more than two messages should have been logged:
EXPECT_EQ(messages().size(), 2u);
CheckMessage(messages()[0], LogLevel::INFO, "Hello", {kLoggerName});
CheckMessage(messages()[1], LogLevel::INFO, "World", {kLoggerName});
// when we append the rest of the line it'll get logged:
Write(" Data\n");
WaitForMessageCount(3);
CheckMessage(messages()[2], LogLevel::INFO, "Extra Data", {kLoggerName});
}
TEST_F(ManagedLoggerTest, LogLevelError) {
Startup(kLoggerName, true);
Write("Hello\n");
WaitForMessageCount(1);
CheckMessage(messages()[0], LogLevel::ERROR, "Hello", {kLoggerName});
}
TEST_F(ManagedLoggerTest, LargeMessageGetsBroken) {
Startup(kLoggerName, false);
std::string msg = "a";
std::stringstream big_message;
for (int i = 0; i < ManagedLogger::BufferSize - 1; i++) {
msg[0] = 'a' + (i % 26);
Write(msg);
big_message << msg;
if (i % 10 == 0) {
// Make the listener consume the message bit by bit
RunLoopUntilIdle();
}
}
Write("More\n");
WaitForMessageCount(2);
CheckMessage(messages()[0], LogLevel::INFO, big_message.str(), {kLoggerName});
CheckMessage(messages()[1], LogLevel::INFO, "More", {kLoggerName});
}
TEST_F(ManagedLoggerTest, DrainsSocketOnExit) {
Startup(kLoggerName, false);
constexpr char kMsg[] = "Hello World";
constexpr char kShortMsg[] = "Hello";
constexpr size_t kMessages = 25;
for (size_t i = 0; i < kMessages; i++) {
Write(std::string(kMsg) + "\n");
}
// Write one last incomplete message, missing a newline.
Write(kShortMsg);
DestroyLogger();
ASSERT_EQ(messages().size(), kMessages + 1);
for (auto i = messages().begin(); i != messages().end() - 1; i++) {
CheckMessage(*i, LogLevel::INFO, kMsg, {kLoggerName});
}
CheckMessage(messages().back(), LogLevel::INFO, kShortMsg, {kLoggerName});
}
} // namespace testing
} // namespace netemul