// 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 <fidl/fuchsia.logger/cpp/wire.h>
#include <fuchsia/io/cpp/fidl.h>
#include <fuchsia/logger/cpp/fidl_test_base.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/driver2/logger.h>
#include <lib/driver2/test_base.h>
#include <lib/fidl/cpp/binding.h>
#include <lib/syslog/wire_format.h>

#include <gtest/gtest.h>
#include <rapidjson/document.h>

#include "src/diagnostics/lib/cpp-log-decoder/log_decoder.h"
#include "src/lib/diagnostics/accessor2logger/log_message.h"
#include "src/lib/fsl/vmo/sized_vmo.h"
#include "src/lib/fsl/vmo/strings.h"

namespace fio = fuchsia::io;
namespace flogger = fuchsia::logger;
namespace frunner = fuchsia_component_runner;

constexpr char kName[] = "my-name";
constexpr char kMessage[] = "my-message";

class TestLogSink : public flogger::testing::LogSink_TestBase {
 public:
  using ConnectHandler = fit::function<void(zx::socket socket)>;

  void SetConnectHandler(ConnectHandler connect_handler) {
    connect_handler_ = std::move(connect_handler);
  }

 private:
  void ConnectStructured(::zx::socket socket) override { connect_handler_(std::move(socket)); }

  void NotImplemented_(const std::string& name) override {
    printf("Not implemented: LogSink::%s\n", name.data());
  }

  ConnectHandler connect_handler_;
};

void CheckLogUnreadable(zx::socket& log_socket) {
  zx_signals_t pending = ZX_SIGNAL_NONE;
  EXPECT_EQ(ZX_ERR_TIMED_OUT,
            log_socket.wait_one(ZX_SOCKET_READABLE, zx::time::infinite_past(), &pending));
  EXPECT_EQ(ZX_SOCKET_WRITABLE, pending);
}

std::string rust_decode_message_to_string(uint8_t* data, size_t len) {
  auto raw_message = fuchsia_decode_log_message_to_json(data, len);
  std::string ret = raw_message;
  fuchsia_free_decoded_log_message(raw_message);
  return ret;
}

struct DecodedLogMessage {
  fuchsia::logger::LogMessage message;
  rapidjson::Document document;
};

DecodedLogMessage decode_log_message_to_struct(uint8_t* data, size_t len) {
  fsl::SizedVmo vmo;
  auto msg = rust_decode_message_to_string(data, len);
  fsl::VmoFromString(msg, &vmo);
  fuchsia::diagnostics::FormattedContent content;
  fuchsia::mem::Buffer buffer;
  buffer.vmo = std::move(vmo.vmo());
  buffer.size = msg.size();
  content.set_json(std::move(buffer));
  DecodedLogMessage ret;
  ret.message =
      diagnostics::accessor2logger::ConvertFormattedContentToHostLogMessages(std::move(content))
          .take_value()[0]
          .take_value();
  ret.document.Parse(msg);
  return ret;
}

void CheckLogReadable(zx::socket& log_socket, fx_log_severity_t severity) {
  // Check state of logger after writing info log.
  zx_signals_t pending = ZX_SIGNAL_NONE;
  EXPECT_EQ(ZX_OK, log_socket.wait_one(ZX_SOCKET_READABLE, zx::time::infinite_past(), &pending));
  EXPECT_EQ(ZX_SOCKET_READABLE | ZX_SOCKET_WRITABLE, pending);

  // Read from the log socket.
  uint8_t packet[ZX_CHANNEL_MAX_MSG_BYTES];
  size_t actual = 0;
  ASSERT_EQ(ZX_OK, log_socket.read(0, &packet, sizeof(packet), &actual));
  EXPECT_LT(actual, sizeof(packet));
  auto msg = decode_log_message_to_struct(packet, actual);
  EXPECT_EQ(severity, msg.message.severity);
  EXPECT_EQ(msg.message.tags[0], kName);
  EXPECT_EQ(std::string(msg.document[0]["payload"]["root"]["message"]["value"].GetString()),
            kMessage);
}

TEST(LoggerTest, CreateAndLog) {
  async::Loop loop{&kAsyncLoopConfigNoAttachToCurrentThread};

  // Setup namespace.
  auto svc = fidl::CreateEndpoints<fuchsia_io::Directory>();
  EXPECT_EQ(ZX_OK, svc.status_value());
  auto ns = driver::testing::CreateNamespace(std::move(svc->client));
  ASSERT_TRUE(ns.is_ok());

  // Setup logger.
  zx::socket log_socket;
  TestLogSink log_sink;
  log_sink.SetConnectHandler([&log_socket](zx::socket socket) { log_socket = std::move(socket); });
  fidl::Binding<flogger::LogSink> log_binding(&log_sink);

  driver::testing::Directory svc_directory;
  svc_directory.SetOpenHandler([&loop, &log_binding](std::string path, auto object) {
    EXPECT_EQ(fidl::DiscoverableProtocolName<fuchsia_logger::LogSink>, path);
    log_binding.Bind(object.TakeChannel(), loop.dispatcher());
  });
  fidl::Binding<fio::Directory> svc_binding(&svc_directory);
  svc_binding.Bind(svc->server.TakeChannel(), loop.dispatcher());

  auto logger = driver::Logger::Create(*ns, loop.dispatcher(), kName);
  ASSERT_TRUE(logger.is_ok());
  loop.RunUntilIdle();

  // Check initial state of logger.
  ASSERT_TRUE(log_socket.is_valid());
  CheckLogUnreadable(log_socket);

  // Check state of logger after writing logs that were below |min_severity|.
  FDF_LOGL(TRACE, logger.value(), kMessage);
  CheckLogUnreadable(log_socket);
  FDF_LOGL(DEBUG, logger.value(), kMessage);
  CheckLogUnreadable(log_socket);

  // Check state of logger after writing logs.
  FDF_LOGL(INFO, logger.value(), kMessage);
  CheckLogReadable(log_socket, FX_LOG_INFO);
  FDF_LOGL(WARNING, logger.value(), kMessage);
  CheckLogReadable(log_socket, FX_LOG_WARNING);
  FDF_LOGL(ERROR, logger.value(), kMessage);
  CheckLogReadable(log_socket, FX_LOG_ERROR);
}

TEST(LoggerTest, Create_NoLogSink) {
  async::Loop loop{&kAsyncLoopConfigNoAttachToCurrentThread};

  // Setup namespace.
  auto pkg = fidl::CreateEndpoints<fuchsia_io::Directory>();
  EXPECT_EQ(ZX_OK, pkg.status_value());
  fidl::Arena arena;
  fidl::VectorView<frunner::wire::ComponentNamespaceEntry> ns_entries(arena, 1);
  ns_entries[0].Allocate(arena);
  ns_entries[0].set_path(arena, "/pkg").set_directory(std::move(pkg->client));
  auto ns = driver::Namespace::Create(ns_entries);
  ASSERT_TRUE(ns.is_ok());

  // Setup logger.
  auto logger = driver::Logger::Create(*ns, loop.dispatcher(), kName);
  ASSERT_TRUE(logger.is_error());
}

TEST(LoggerTest, SetSeverity) {
  async::Loop loop{&kAsyncLoopConfigNoAttachToCurrentThread};

  // Setup namespace.
  auto svc = fidl::CreateEndpoints<fuchsia_io::Directory>();
  EXPECT_EQ(ZX_OK, svc.status_value());
  auto ns = driver::testing::CreateNamespace(std::move(svc->client));
  ASSERT_TRUE(ns.is_ok());

  // Setup logger.
  zx::socket log_socket;
  TestLogSink log_sink;
  log_sink.SetConnectHandler([&log_socket](zx::socket socket) { log_socket = std::move(socket); });
  fidl::Binding<flogger::LogSink> log_binding(&log_sink);

  driver::testing::Directory svc_directory;
  svc_directory.SetOpenHandler([&loop, &log_binding](std::string path, auto object) {
    EXPECT_EQ(fidl::DiscoverableProtocolName<fuchsia_logger::LogSink>, path);
    log_binding.Bind(object.TakeChannel(), loop.dispatcher());
  });
  fidl::Binding<fio::Directory> svc_binding(&svc_directory);
  svc_binding.Bind(svc->server.TakeChannel(), loop.dispatcher());

  auto logger = driver::Logger::Create(*ns, loop.dispatcher(), kName);
  ASSERT_TRUE(logger.is_ok());
  loop.RunUntilIdle();

  // Check initial state of logger.
  ASSERT_TRUE(log_socket.is_valid());
  CheckLogUnreadable(log_socket);

  // Check severity after setting it.
  logger.value().SetSeverity(FUCHSIA_LOG_INFO);
  ASSERT_EQ(FUCHSIA_LOG_INFO, logger.value().GetSeverity());

  // Check state of logger after writing logs that were above or equal to min
  // severity.
  FDF_LOGL(INFO, logger.value(), kMessage);
  CheckLogReadable(log_socket, FX_LOG_INFO);
  FDF_LOGL(WARNING, logger.value(), kMessage);
  CheckLogReadable(log_socket, FX_LOG_WARNING);

  // Check severity after setting it.
  logger.value().SetSeverity(FUCHSIA_LOG_WARNING);
  ASSERT_EQ(FUCHSIA_LOG_WARNING, logger.value().GetSeverity());

  // Check state of logger after writing logs that were below min severity.
  FDF_LOGL(INFO, logger.value(), kMessage);
  CheckLogUnreadable(log_socket);
  FDF_LOGL(WARNING, logger.value(), kMessage);
  CheckLogReadable(log_socket, FX_LOG_WARNING);
}
