// 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 <fcntl.h>
#include <fuchsia/device/lifecycle/test/llcpp/fidl.h>
#include <fuchsia/device/llcpp/fidl.h>
#include <fuchsia/hardware/serial/llcpp/fidl.h>
#include <fuchsia/io/llcpp/fidl.h>
#include <lib/driver-integration-test/fixture.h>
#include <lib/fdio/directory.h>
#include <zircon/processargs.h>
#include <zircon/syscalls.h>

#include <vector>

#include <ddk/platform-defs.h>
#include <zxtest/zxtest.h>

using driver_integration_test::IsolatedDevmgr;
using llcpp::fuchsia::device::Controller;
using llcpp::fuchsia::device::lifecycle::test::Lifecycle;
using llcpp::fuchsia::device::lifecycle::test::TestDevice;
using llcpp::fuchsia::hardware::serial::Device;
using llcpp::fuchsia::io::Directory;
using llcpp::fuchsia::io::File;

class LifecycleTest : public zxtest::Test {
 public:
  ~LifecycleTest() override = default;
  void SetUp() override {
    IsolatedDevmgr::Args args;
    args.load_drivers.push_back("/boot/driver/ddk-lifecycle-test.so");

    board_test::DeviceEntry dev = {};
    dev.vid = PDEV_VID_TEST;
    dev.pid = PDEV_PID_LIFECYCLE_TEST;
    dev.did = 0;
    args.device_list.push_back(dev);

    zx_status_t status = IsolatedDevmgr::Create(&args, &devmgr_);
    ASSERT_OK(status);
    fbl::unique_fd fd;
    ASSERT_OK(devmgr_integration_test::RecursiveWaitForFile(
        devmgr_.devfs_root(), "sys/platform/11:10:0/ddk-lifecycle-test", &fd));
    ASSERT_GT(fd.get(), 0);
    ASSERT_OK(fdio_get_service_handle(fd.release(), chan_.reset_and_get_address()));
    ASSERT_NE(chan_.get(), ZX_HANDLE_INVALID);

    // Subscribe to the device lifecycle events.
    zx::channel local, remote;
    ASSERT_OK(zx::channel::create(0, &local, &remote));

    auto result = TestDevice::Call::SubscribeToLifecycle(zx::unowned(chan_), std::move(remote));
    ASSERT_OK(result.status());
    ASSERT_FALSE(result->result.is_err());
    lifecycle_chan_ = std::move(local);
  }

 protected:
  void WaitPreRelease(uint64_t child_id);

  zx::channel chan_;
  IsolatedDevmgr devmgr_;

  zx::channel lifecycle_chan_;
};

void LifecycleTest::WaitPreRelease(uint64_t child_id) {
  bool removed = false;
  uint64_t device_id = 0;
  while (!removed) {
    Lifecycle::EventHandlers event_handlers;
    event_handlers.on_child_pre_release = [&](uint64_t id) -> zx_status_t {
      device_id = id;
      removed = true;
      return ZX_OK;
    };
    ASSERT_OK(Lifecycle::Call::HandleEvents(zx::unowned_channel(lifecycle_chan_),
                                            std::move(event_handlers)));
  }
  ASSERT_EQ(device_id, child_id);
}

TEST_F(LifecycleTest, ChildPreRelease) {
  // Add some child devices and store the returned ids.
  std::vector<uint64_t> child_ids;
  const uint32_t num_children = 10;
  for (unsigned int i = 0; i < num_children; i++) {
    auto result = TestDevice::Call::AddChild(zx::unowned(chan_), true /* complete_init */,
                                             ZX_OK /* init_status */);
    ASSERT_OK(result.status());
    ASSERT_FALSE(result->result.is_err());
    child_ids.push_back(result->result.response().child_id);
  }

  // Remove the child devices and check the test device received the pre-release notifications.
  for (auto child_id : child_ids) {
    auto result = TestDevice::Call::RemoveChild(zx::unowned(chan_), child_id);
    ASSERT_OK(result.status());
    ASSERT_FALSE(result->result.is_err());

    // Wait for the child pre-release notification.
    ASSERT_NO_FATAL_FAILURES(WaitPreRelease(child_id));
  }
}

TEST_F(LifecycleTest, Init) {
  // Add a child device that does not complete its init hook yet.
  uint64_t child_id;
  auto result = TestDevice::Call::AddChild(zx::unowned(chan_), false /* complete_init */,
                                           ZX_OK /* init_status */);
  ASSERT_OK(result.status());
  ASSERT_FALSE(result->result.is_err());
  child_id = result->result.response().child_id;

  auto remove_result = TestDevice::Call::RemoveChild(zx::unowned(chan_), child_id);
  ASSERT_OK(remove_result.status());
  ASSERT_FALSE(remove_result->result.is_err());

  auto init_result = TestDevice::Call::CompleteChildInit(zx::unowned(chan_), child_id);
  ASSERT_OK(init_result.status());
  ASSERT_FALSE(init_result->result.is_err());

  // Wait for the child pre-release notification.
  ASSERT_NO_FATAL_FAILURES(WaitPreRelease(child_id));
}

TEST_F(LifecycleTest, CloseAllConnectionsOnInstanceUnbind) {
  auto result = TestDevice::Call::AddChild(zx::unowned(chan_), true /* complete_init */,
                                           ZX_OK /* init_status */);
  ASSERT_OK(result.status());
  ASSERT_FALSE(result->result.is_err());
  auto child_id = result->result.response().child_id;
  fbl::unique_fd fd;
  ASSERT_OK(devmgr_integration_test::RecursiveWaitForFile(
      devmgr_.devfs_root(), "sys/platform/11:10:0/ddk-lifecycle-test/ddk-lifecycle-test-child",
      &fd));
  ASSERT_TRUE(fd.get() > 0);
  zx::channel chan;
  fdio_get_service_handle(fd.get(), chan.reset_and_get_address());
  ASSERT_TRUE(TestDevice::Call::RemoveChild(zx::unowned(chan_), child_id).ok());
  zx_signals_t closed;
  ASSERT_OK(chan.wait_one(ZX_CHANNEL_PEER_CLOSED, zx::time::infinite(), &closed));
  ASSERT_TRUE(closed & ZX_CHANNEL_PEER_CLOSED);
  // Wait for the child pre-release notification.
  ASSERT_NO_FATAL_FAILURES(WaitPreRelease(child_id));
}

TEST_F(LifecycleTest, ReadCallFailsDuringUnbind) {
  auto result = TestDevice::Call::AddChild(zx::unowned(chan_), true /* complete_init */,
                                           ZX_OK /* init_status */);
  ASSERT_OK(result.status());
  ASSERT_FALSE(result->result.is_err());
  auto child_id = result->result.response().child_id;
  fbl::unique_fd fd;

  ASSERT_OK(devmgr_integration_test::RecursiveWaitForFile(
      devmgr_.devfs_root(), "sys/platform/11:10:0/ddk-lifecycle-test/ddk-lifecycle-test-child",
      &fd));
  ASSERT_TRUE(fd.get() > 0);
  zx::channel chan;
  fdio_get_service_handle(fd.get(), chan.reset_and_get_address());

  ASSERT_TRUE(TestDevice::Call::AsyncRemoveChild(zx::unowned(chan_), child_id).ok());
  ASSERT_EQ(File::Call::Read(zx::unowned(chan), 10).value().s, ZX_ERR_IO_NOT_PRESENT);
  fidl::Array<uint8_t, 5> array;
  ASSERT_EQ(File::Call::Write(zx::unowned(chan), fidl::unowned_vec(array)).value().s,
            ZX_ERR_IO_NOT_PRESENT);
  int fd2 = open("sys/platform/11:10:0/ddk-lifecycle-test/ddk-lifecycle-test-child", O_RDWR);
  ASSERT_EQ(fd2, -1);
  ASSERT_EQ(Device::Call::GetClass(zx::unowned(chan)).status(), ZX_ERR_PEER_CLOSED);
  struct Epitaph {
    zx_txid_t txid;
    uint8_t flags[3];
    uint8_t magic_number;
    uint64_t ordinal;
    zx_status_t error;
  } epitaph;
  constexpr auto kEpitaph = 0xFFFFFFFFFFFFFFFF;
  uint32_t actual_bytes = 0;
  uint32_t actual_handles = 0;
  ASSERT_OK(chan.read(0, &epitaph, nullptr, sizeof(epitaph), 0, &actual_bytes, &actual_handles));
  ASSERT_EQ(actual_bytes, sizeof(epitaph));
  ASSERT_EQ(epitaph.ordinal, kEpitaph);
  ASSERT_EQ(epitaph.error, ZX_ERR_IO_NOT_PRESENT);
}

TEST_F(LifecycleTest, CloseAllConnectionsOnUnbind) {
  Controller::Call::ScheduleUnbind(zx::unowned(chan_));
  zx_signals_t closed;
  ASSERT_OK(chan_.wait_one(ZX_CHANNEL_PEER_CLOSED, zx::time::infinite(), &closed));
  ASSERT_TRUE(closed & ZX_CHANNEL_PEER_CLOSED);
}

// Tests that the child device is removed if init fails.
TEST_F(LifecycleTest, FailedInit) {
  uint64_t child_id;
  auto result = TestDevice::Call::AddChild(zx::unowned(chan_), true /* complete_init */,
                                           ZX_ERR_BAD_STATE /* init_status */);
  ASSERT_OK(result.status());
  ASSERT_FALSE(result->result.is_err());
  child_id = result->result.response().child_id;

  // Wait for the child pre-release notification.
  ASSERT_NO_FATAL_FAILURES(WaitPreRelease(child_id));
}
