// 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 "build_info.h"

#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/fdio/fdio.h>
#include <lib/fdio/namespace.h>
#include <lib/fidl/cpp/binding.h>
#include <lib/sys/cpp/testing/component_context_provider.h>
#include <lib/syslog/cpp/macros.h>
#include <lib/vfs/cpp/pseudo_dir.h>
#include <lib/vfs/cpp/pseudo_file.h>
#include <zircon/status.h>

#include "src/lib/testing/loop_fixture/test_loop_fixture.h"

namespace {
const char kFuchsiaBuildInfoDirectoryPath[] = "/config/build-info";

const char kProductFileName[] = "product";
const char kBoardFileName[] = "board";
const char kVersionFileName[] = "version";
const char kPlatformVersionFileName[] = "platform_version";
const char kProductVersionFileName[] = "product_version";
const char kLastCommitDateFileName[] = "latest-commit-date";
}  // namespace

class BuildInfoServiceInstance {
 public:
  explicit BuildInfoServiceInstance(std::unique_ptr<sys::ComponentContext> context) {
    context_ = std::move(context);
    binding_ = std::make_unique<fidl::Binding<fuchsia::buildinfo::Provider>>(&impl_);
    fidl::InterfaceRequestHandler<fuchsia::buildinfo::Provider> handler =
        [&](fidl::InterfaceRequest<fuchsia::buildinfo::Provider> request) {
          binding_->Bind(std::move(request));
        };
    context_->outgoing()->AddPublicService(std::move(handler));
  }

 private:
  ProviderImpl impl_;
  std::unique_ptr<fidl::Binding<fuchsia::buildinfo::Provider>> binding_;
  std::unique_ptr<sys::ComponentContext> context_;
};

class BuildInfoServiceTestFixture : public gtest::TestLoopFixture {
 public:
  BuildInfoServiceTestFixture() : loop_(&kAsyncLoopConfigNoAttachToCurrentThread) {}

  void SetUp() override {
    TestLoopFixture::SetUp();
    build_info_service_instance_.reset(new BuildInfoServiceInstance(provider_.TakeContext()));

    loop_.StartThread();

    // Get the process's namespace.
    fdio_ns_t *ns;
    zx_status_t status = fdio_ns_get_installed(&ns);
    ZX_ASSERT_MSG(status == ZX_OK, "Cannot get namespace: %s\n", zx_status_get_string(status));

    // Create the /config/build-info path in the namespace.
    auto [build_info_client, build_info_server] = fidl::Endpoints<fuchsia_io::Directory>::Create();
    std::string build_info_directory_path(kFuchsiaBuildInfoDirectoryPath);
    status = fdio_ns_bind(ns, build_info_directory_path.c_str(),
                          build_info_client.TakeChannel().release());
    ZX_ASSERT_MSG(status == ZX_OK, "Cannot bind %s to namespace: %s\n",
                  build_info_directory_path.c_str(), zx_status_get_string(status));

    // Connect the build-info PseudoDir to the /config/build-info path.
    build_info_directory_.Serve(fuchsia_io::wire::kPermReadable | fuchsia_io::wire::kPermWritable,
                                std::move(build_info_server), loop_.dispatcher());
  }

  // Creates a PsuedoDir named |build_info_filename| in the PsuedoDir "/config/build-info" in
  // the component's namespace. The file contains |build_info_filename| followed optionally by
  // a trailing newline.
  void CreateBuildInfoFile(std::string build_info_filename, bool with_trailing_newline = true) {
    std::string file_contents(build_info_filename);

    // Some build info files contain a trailing newline which the build info service strips.
    // Optionally add a trailing newline to test the trailing whitespace stripping.
    if (with_trailing_newline) {
      file_contents.append("\n");
    }

    vfs::PseudoFile::ReadHandler versionFileReadFn = [file_contents](std::vector<uint8_t> *output,
                                                                     size_t max_file_size) {
      output->resize(file_contents.length());
      std::copy(file_contents.begin(), file_contents.end(), output->begin());
      return ZX_OK;
    };
    vfs::PseudoFile::WriteHandler versionFileWriteFn;

    // Create a PseudoFile.
    std::unique_ptr<vfs::PseudoFile> pseudo_file = std::make_unique<vfs::PseudoFile>(
        file_contents.length(), std::move(versionFileReadFn), std::move(versionFileWriteFn));

    // Add the file to the build-info PseudoDir.
    build_info_directory_.AddEntry(std::move(build_info_filename), std::move(pseudo_file));
  }

  void TearDown() override {
    TestLoopFixture::TearDown();
    build_info_service_instance_.reset();
    DestroyBuildInfoFile();
  }

 protected:
  fuchsia::buildinfo::ProviderPtr GetProxy() {
    fuchsia::buildinfo::ProviderPtr provider;
    provider_.ConnectToPublicService(provider.NewRequest());
    return provider;
  }

 private:
  void DestroyBuildInfoFile() {
    fdio_ns_t *ns;
    zx_status_t status = fdio_ns_get_installed(&ns);
    ZX_ASSERT_MSG(status == ZX_OK, "Cannot retrieve the namespace: %s\n",
                  zx_status_get_string(status));

    std::string build_info_directory_path(kFuchsiaBuildInfoDirectoryPath);
    status = fdio_ns_unbind(ns, build_info_directory_path.c_str());
    ZX_ASSERT_MSG(status == ZX_OK, "Cannot unbind from a namespace: %s\n",
                  zx_status_get_string(status));

    loop_.Quit();
    loop_.JoinThreads();
  }

  std::unique_ptr<BuildInfoServiceInstance> build_info_service_instance_;
  sys::testing::ComponentContextProvider provider_;
  vfs::PseudoDir build_info_directory_;
  async::Loop loop_;
};

TEST_F(BuildInfoServiceTestFixture, BuildInfo) {
  CreateBuildInfoFile(kProductFileName);
  CreateBuildInfoFile(kBoardFileName);
  CreateBuildInfoFile(kVersionFileName);
  CreateBuildInfoFile(kPlatformVersionFileName);
  CreateBuildInfoFile(kProductVersionFileName);
  CreateBuildInfoFile(kLastCommitDateFileName);

  fuchsia::buildinfo::ProviderPtr proxy = GetProxy();
  proxy->GetBuildInfo([&](const fuchsia::buildinfo::BuildInfo &response) {
    EXPECT_TRUE(response.has_product_config());
    EXPECT_EQ(response.product_config(), kProductFileName);
    EXPECT_TRUE(response.has_board_config());
    EXPECT_EQ(response.board_config(), kBoardFileName);
    EXPECT_TRUE(response.has_version());
    EXPECT_EQ(response.version(), kVersionFileName);
    EXPECT_TRUE(response.has_platform_version());
    EXPECT_EQ(response.platform_version(), kPlatformVersionFileName);
    EXPECT_TRUE(response.has_product_version());
    EXPECT_EQ(response.product_version(), kProductVersionFileName);
    EXPECT_TRUE(response.has_latest_commit_date());
    EXPECT_EQ(response.latest_commit_date(), kLastCommitDateFileName);
  });

  RunLoopUntilIdle();
}

TEST_F(BuildInfoServiceTestFixture, EmptyBuildInfo) {
  CreateBuildInfoFile("");
  CreateBuildInfoFile("");
  CreateBuildInfoFile("");
  CreateBuildInfoFile("");

  fuchsia::buildinfo::ProviderPtr proxy = GetProxy();
  proxy->GetBuildInfo([&](const fuchsia::buildinfo::BuildInfo &response) {
    EXPECT_FALSE(response.has_product_config());
    EXPECT_FALSE(response.has_board_config());
    EXPECT_FALSE(response.has_version());
    EXPECT_FALSE(response.has_platform_version());
    EXPECT_FALSE(response.has_product_version());
    EXPECT_FALSE(response.has_latest_commit_date());
  });

  RunLoopUntilIdle();
}

TEST_F(BuildInfoServiceTestFixture, NonPresentBuildInfo) {
  fuchsia::buildinfo::ProviderPtr proxy = GetProxy();
  proxy->GetBuildInfo([&](const fuchsia::buildinfo::BuildInfo &response) {
    EXPECT_FALSE(response.has_product_config());
    EXPECT_FALSE(response.has_board_config());
    EXPECT_FALSE(response.has_version());
    EXPECT_FALSE(response.has_platform_version());
    EXPECT_FALSE(response.has_product_version());
    EXPECT_FALSE(response.has_latest_commit_date());
  });

  RunLoopUntilIdle();
}
