// Copyright 2018 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 <gmock/gmock.h>
#include <gtest/gtest.h>
#include <string.h>
#include <future>

#include "guest_test.h"

template <class T>
T* GuestTest<T>::enclosed_guest_ = nullptr;

class ZirconVsockGuestTest : public ZirconEnclosedGuest,
                             public fuchsia::guest::HostVsockAcceptor {
 public:
  struct IncomingRequest {
    uint32_t src_cid;
    uint32_t src_port;
    uint32_t port;
    fuchsia::guest::HostVsockAcceptor::AcceptCallback callback;
  };

  std::vector<IncomingRequest> requests;

  void Accept(uint32_t src_cid, uint32_t src_port, uint32_t port,
              AcceptCallback callback) override {
    requests.push_back({src_cid, src_port, port, std::move(callback)});
  }

  void Read(zx::socket& socket, size_t amount) {
    size_t total_read = 0;
    while (total_read != amount) {
      size_t read;
      char buf[1000];
      zx_signals_t pending;
      socket.wait_one(ZX_SOCKET_READABLE, zx::time::infinite(), &pending);
      ASSERT_TRUE((pending & ZX_SOCKET_READABLE) != 0);
      size_t read_amount = std::min(amount - total_read, sizeof(buf));
      ASSERT_EQ(socket.read(0, &buf, read_amount, &read), ZX_OK);
      total_read += read;
    }
  }

  void TestReadWrite(zx::socket& socket) {
    Read(socket, 60000 * 4);
    uint8_t value = 42;
    size_t actual;
    ASSERT_EQ(socket.write(0, &value, 1, &actual), ZX_OK);
    EXPECT_EQ(static_cast<int>(actual), 1);
  }

  void TestThread() {
    async::Loop loop(&kAsyncLoopConfigAttachToThread);

    fuchsia::guest::HostVsockEndpointSyncPtr vsock_endpoint;
    GetHostVsockEndpoint(vsock_endpoint.NewRequest());

    fidl::Binding<fuchsia::guest::HostVsockAcceptor> binding{this};
    zx_status_t out_status;
    ASSERT_EQ(vsock_endpoint->Listen(8000, binding.NewBinding(), &out_status),
              ZX_OK);
    ASSERT_EQ(out_status, ZX_OK);

    ASSERT_EQ(binding.WaitForMessage(), ZX_OK);
    ASSERT_TRUE(requests.size() == 1);
    ASSERT_EQ(requests[0].src_cid, GetGuestCid());
    ASSERT_EQ(requests[0].src_port, 49152u);
    ASSERT_EQ(requests[0].port, 8000u);

    zx::socket socket1, socket2;
    ASSERT_EQ(zx::socket::create(ZX_SOCKET_STREAM, &socket1, &socket2), ZX_OK);
    requests.back().callback(ZX_OK, std::move(socket2));
    requests.pop_back();
    TestReadWrite(socket1);

    zx_signals_t pending;
    // Read the read/write completes we expect the util to close the connection.
    socket1.wait_one(ZX_SOCKET_PEER_CLOSED, zx::time::infinite(), &pending);
    ASSERT_TRUE((pending & ZX_SOCKET_PEER_CLOSED) != 0);

    socket1.reset();

    // Attempt to connect into the guest
    EXPECT_EQ(zx::socket::create(ZX_SOCKET_STREAM, &socket1, &socket2), ZX_OK);
    ASSERT_EQ(vsock_endpoint->Connect(GetGuestCid(), 8001, std::move(socket2),
                                      &out_status),
              ZX_OK);
    ASSERT_EQ(out_status, ZX_OK);

    // Wait for all the data
    TestReadWrite(socket1);
    // Close the connection by dropping the socket.
    socket1.reset();

    // Open another connection.
    EXPECT_EQ(zx::socket::create(ZX_SOCKET_STREAM, &socket1, &socket2), ZX_OK);
    ASSERT_EQ(vsock_endpoint->Connect(GetGuestCid(), 8001, std::move(socket2),
                                      &out_status),
              ZX_OK);
    ASSERT_EQ(out_status, ZX_OK);
    // Read some data then close the connection
    Read(socket1, 10);
    socket1.reset();

    // Wait for another connection to get accepted
    EXPECT_EQ(zx::socket::create(ZX_SOCKET_STREAM, &socket1, &socket2), ZX_OK);
    ASSERT_EQ(vsock_endpoint->Connect(GetGuestCid(), 8001, std::move(socket2),
                                      &out_status),
              ZX_OK);
    ASSERT_EQ(out_status, ZX_OK);
    // Keep writing until we get peer closed
    zx_status_t status;
    do {
      socket1.wait_one(ZX_SOCKET_PEER_CLOSED | ZX_SOCKET_WRITABLE, zx::time::infinite(), &pending);
      if((pending & ZX_SOCKET_WRITABLE) != 0) {
        uint8_t buf[1000];
        size_t actual = 0;
        status = socket1.write(0, buf, sizeof(buf), &actual);
      }
    } while (status != ZX_ERR_PEER_CLOSED && (pending & ZX_SOCKET_PEER_CLOSED) == 0);
  }
};

using VsockGuestTest = GuestTest<ZirconVsockGuestTest>;

// Disabled due to flake: MAC-237
TEST_F(VsockGuestTest, DISABLED_ConnectDisconnect) {
  auto handle = std::async(std::launch::async,
                           [this] { this->GetEnclosedGuest()->TestThread(); });

  std::string result;
  EXPECT_EQ(RunUtil("virtio_vsock_test_util", "", &result), ZX_OK);

  handle.wait();

  EXPECT_THAT(result, ::testing::HasSubstr("PASS"));
}
