// 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.

// TODO(fxb/44924): We should come up with a better way of testing client libraries,
// rather than testing every client against every server. See issue for details.

#include <fcntl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/fdio/directory.h>
#include <lib/fdio/fdio.h>
#include <lib/fdio/namespace.h>
#include <lib/sys/cpp/component_context.h>
#include <lib/sys/service/cpp/service.h>
#include <unistd.h>
#include <zircon/syscalls.h>

#include <iostream>

#include <fbl/unique_fd.h>

#include "fuchsia/io/cpp/fidl.h"
#include "fuchsia/io/test/cpp/fidl.h"
#include "fuchsia/sys/cpp/fidl.h"
#include "gtest/gtest.h"

fidl::InterfaceHandle<fuchsia::io::Directory> StartTestHarness(
    sys::ComponentContext* context,
    std::string harness_name,
    fidl::InterfaceRequest<fuchsia::sys::ComponentController> controller) {
  fidl::InterfaceHandle<fuchsia::io::Directory> svc;
  fuchsia::sys::LaunchInfo info{
      .url = "fuchsia-pkg://fuchsia.com/" + harness_name + "#meta/" + harness_name + ".cmx",
      .directory_request = svc.NewRequest().TakeChannel(),
  };

  auto launcher = context->svc()->Connect<fuchsia::sys::Launcher>();
  launcher->CreateComponent(std::move(info), std::move(controller));
  return svc;
}

class FdioTest : public testing::Test {
 public:
  // This will be initialized by |main|.
  static sys::ComponentContext* component_context;

  // This will be set by |main| multiple times.
  static const char* harness_name;

  static void SetUpTestSuite() {
    auto svc = StartTestHarness(component_context, harness_name, controller.NewRequest());
    auto default_service = sys::OpenServiceAt<fuchsia::io::test::Harness>(svc);
    // TODO(fxb/33880): Add io2 tests when ready.
    v1_test_cases = default_service.v1().Connect().Bind();
  }

  static void TearDownTestSuite() {
    // This will also terminate the test harness component.
    auto _ = controller.Unbind();
  }

 protected:
  FdioTest() {
    EXPECT_EQ(ZX_OK, zx::channel::create(0, &client_end_, &server_end_));
    EXPECT_EQ(ZX_OK, fdio_ns_get_installed(&ns_));
    if (!ns_) {
      return;
    }
    EXPECT_EQ(ZX_OK, fdio_ns_bind(ns_, kTestPath, client_end_.release()));
  }

  ~FdioTest() override {
    EXPECT_EQ(ZX_OK, fdio_ns_unbind(ns_, kTestPath));
  }

  static void FillBuffer(std::vector<char>* buf) {
    buf->resize(kTestVmoSize);
    for (size_t i = 0; i < kTestVmoSize; i++) {
      // Mod 256 by truncating.
      (*buf)[i] = static_cast<char>(i);
    }
  }

  static zx::vmo MakeTestVmo(const std::vector<char>& buffer) {
    zx::vmo ret;
    EXPECT_EQ(ZX_OK, zx::vmo::create(kTestVmoSize, 0, &ret));
    EXPECT_EQ(ZX_OK, ret.write(&buffer[0], 0, kTestVmoSize));
    return ret;
  }

  zx::channel&& TakeServerEnd() { return std::move(server_end_); }

  // To test fdio, the root server directory will be bound to this path
  // in the namespace.
  constexpr static const char* kTestPath = "/fdio_test";

  constexpr static const char* kVmoFileName = "vmo_file";

  constexpr static size_t kTestVmoSize = 4096;

  static fuchsia::sys::ComponentControllerPtr controller;

  static fidl::InterfacePtr<fuchsia::io::test::TestCases> v1_test_cases;

 private:
  zx::channel client_end_;
  zx::channel server_end_;
  fdio_ns_t* ns_;
  std::vector<char> golden_buffer_;
};

sys::ComponentContext* FdioTest::component_context = {};
const char* FdioTest::harness_name = nullptr;
fuchsia::sys::ComponentControllerPtr FdioTest::controller = {};
fidl::InterfacePtr<fuchsia::io::test::TestCases> FdioTest::v1_test_cases = {};

TEST_F(FdioTest, OpenEmptyDirectory) {
  v1_test_cases->GetEmptyDirectory(TakeServerEnd());
  fbl::unique_fd dir_fd(open(kTestPath, O_RDONLY));
  ASSERT_TRUE(dir_fd.is_valid()) << "errno is " << errno;

  struct stat statbuf;
  EXPECT_EQ(0, fstat(dir_fd.get(), &statbuf)) << "errno is" << errno;
  EXPECT_EQ(1ul, statbuf.st_nlink);
  EXPECT_EQ(0, statbuf.st_size);
}

TEST_F(FdioTest, ReadFromVmoFile) {
  std::vector<char> golden_buffer;
  FillBuffer(&golden_buffer);
  auto buffer = fuchsia::mem::Range{
      .vmo = MakeTestVmo(golden_buffer), .offset = 0, .size = golden_buffer.size()};
  v1_test_cases->GetDirectoryWithVmoFile(std::move(buffer), TakeServerEnd());

  std::string vmo_path = std::string(kTestPath) + "/" + kVmoFileName;
  fbl::unique_fd vmo_fd(open(vmo_path.c_str(), O_RDONLY));
  ASSERT_TRUE(vmo_fd.is_valid()) << "errno is " << errno;

  // Reading works.
  std::vector<char> read_buffer(kTestVmoSize);
  EXPECT_EQ(static_cast<ssize_t>(kTestVmoSize),
            read(vmo_fd.get(), read_buffer.data(), kTestVmoSize));
  EXPECT_EQ(golden_buffer, read_buffer);
}

TEST_F(FdioTest, GetAttrVmoFile) {
  std::vector<char> golden_buffer;
  FillBuffer(&golden_buffer);
  auto buffer = fuchsia::mem::Range{
      .vmo = MakeTestVmo(golden_buffer), .offset = 0, .size = golden_buffer.size()};
  v1_test_cases->GetDirectoryWithVmoFile(std::move(buffer), TakeServerEnd());

  std::string vmo_path = std::string(kTestPath) + "/" + kVmoFileName;
  fbl::unique_fd vmo_fd(open(vmo_path.c_str(), O_RDONLY));
  ASSERT_TRUE(vmo_fd.is_valid()) << "errno is " << errno;

  struct stat statbuf;
  EXPECT_EQ(0, fstat(vmo_fd.get(), &statbuf)) << "errno is" << errno;
  EXPECT_EQ(kTestVmoSize, static_cast<size_t>(statbuf.st_size));
}

int main(int argc, char** argv) {
  async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);
  auto context = sys::ComponentContext::Create();
  FdioTest::component_context = context.get();

  testing::InitGoogleTest(&argc, argv);

  int exit_code = 0;
  for (const auto& harness_name : {
    "io_conformance_harness_sdkcpp",
    "io_conformance_harness_ulibfs",
    "io_conformance_harness_rust_pseudo_fs_mt",
  }) {
    FdioTest::harness_name = harness_name;
    std::cout << "----" << std::endl;
    std::cout << "---- Selecting testing harness: " << harness_name << std::endl;
    std::cout << "----" << std::endl;
    int result = RUN_ALL_TESTS();
    if (result != 0) {
      exit_code = result;
    }
  }
  return exit_code;
}
