blob: 33095f6834c1b95f5d64809f5933cc5e879c1818 [file] [log] [blame]
// Copyright 2020 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 <fuchsia/logger/cpp/fidl_test_base.h>
#include <lib/sys/cpp/component_context.h>
#include <lib/syslog/wire_format.h>
#include <zircon/errors.h>
#include <zircon/status.h>
#include <map>
#include <string>
#include <vector>
#include "src/lib/testing/loop_fixture/test_loop_fixture.h"
#include "src/sys/tools/log/log.h"
namespace {
class FakeLogSink : public fuchsia::logger::testing::LogSink_TestBase {
public:
explicit FakeLogSink(fidl::InterfaceRequest<fuchsia::logger::LogSink> request)
: binding_(this, std::move(request)) {}
void NotImplemented_(const std::string& name) override {
ADD_FAILURE() << "unexpected call to " << name;
}
void Connect(zx::socket socket) override { socket_ = std::move(socket); }
fpromise::result<std::tuple<zx_time_t, std::string, std::string>, zx_status_t> ReadPacket() {
static_assert(FX_LOG_MAX_DATAGRAM_LEN == sizeof(fx_log_packet_t));
std::vector<char> packet(FX_LOG_MAX_DATAGRAM_LEN);
size_t actual = 0;
zx_status_t status = socket_.read(0, packet.data(), packet.size(), &actual);
if (status != ZX_OK) {
return fpromise::error(status);
}
if (actual != packet.size()) {
// Packet should be exactly one log packet.
return fpromise::error(ZX_ERR_BAD_STATE);
}
if (*packet.rbegin() != 0) {
// Non-zero final byte indicates an improperly terminated message string.
return fpromise::error(ZX_ERR_BAD_STATE);
}
auto log_packet = reinterpret_cast<const fx_log_packet_t*>(packet.data());
if (log_packet->data[0] == 0 || log_packet->data[1 + log_packet->data[0]] != 0) {
// This fake assumes messages have exactly one tag.
return fpromise::error(ZX_ERR_NOT_SUPPORTED);
}
std::string tag(&log_packet->data[1]);
std::string msg(&log_packet->data[1 + tag.length() + 1]);
return fpromise::ok(std::make_tuple(log_packet->metadata.time, tag, msg));
}
void WaitForInterestChange(WaitForInterestChangeCallback callback) override {}
private:
fidl::Binding<fuchsia::logger::LogSink> binding_;
zx::socket socket_;
};
class LogTest : public gtest::TestLoopFixture {
protected:
LogTest() = default;
};
TEST_F(LogTest, InvalidArgc) {
EXPECT_EQ(log::ParseAndWriteLog(nullptr, zx::time::infinite(), 0, nullptr), ZX_ERR_INVALID_ARGS);
EXPECT_EQ(log::ParseAndWriteLog(nullptr, zx::time::infinite(), 1, nullptr), ZX_ERR_INVALID_ARGS);
EXPECT_EQ(log::ParseAndWriteLog(nullptr, zx::time::infinite(), 2, nullptr), ZX_ERR_INVALID_ARGS);
EXPECT_EQ(log::ParseAndWriteLog(nullptr, zx::time::infinite(), 4, nullptr), ZX_ERR_INVALID_ARGS);
EXPECT_EQ(log::ParseAndWriteLog(nullptr, zx::time::infinite(), 5, nullptr), ZX_ERR_INVALID_ARGS);
}
TEST_F(LogTest, TagTooLong) {
std::string tag(64, 'x');
const char* argv[]{"log", tag.c_str(), ""};
EXPECT_EQ(log::ParseAndWriteLog(nullptr, zx::time::infinite(), 3, const_cast<char**>(argv)),
ZX_ERR_OUT_OF_RANGE);
}
TEST_F(LogTest, CombinedTooLong) {
std::string tag(32, 'x');
std::string msg(32716, 'x');
const char* argv[]{"log", tag.c_str(), msg.c_str()};
EXPECT_EQ(log::ParseAndWriteLog(nullptr, zx::time::infinite(), 3, const_cast<char**>(argv)),
ZX_ERR_OUT_OF_RANGE);
}
TEST_F(LogTest, SimpleLog) {
fuchsia::logger::LogSinkHandle log_sink;
FakeLogSink fake(log_sink.NewRequest());
const char* argv[]{"log", "hello", "world"};
auto time = zx::clock::get_monotonic();
EXPECT_EQ(log::ParseAndWriteLog(std::move(log_sink), time, 3, const_cast<char**>(argv)), ZX_OK);
RunLoopUntilIdle();
auto result = fake.ReadPacket();
ASSERT_TRUE(result.is_ok()) << zx_status_get_string(result.error());
auto [time_out, tag, msg] = result.take_value();
EXPECT_EQ(tag, "hello");
EXPECT_EQ(msg, "world");
EXPECT_EQ(time_out, time.get());
}
} // namespace