// Copyright 2017 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 <errno.h>
#include <fcntl.h>
#include <fidl/fuchsia.io/cpp/wire.h>
#include <lib/fdio/cpp/caller.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <zircon/errors.h>

#include <iostream>
#include <string>
#include <tuple>
#include <vector>

#include <fbl/unique_fd.h>

#include "src/storage/fs_test/fs_test_fixture.h"
#include "src/storage/fvm/format.h"
#include "src/storage/minfs/format.h"

// TODO(fxbug.dev/84697) Re-enable once FIDL wire format migration is complete.
#if !__has_feature(address_sanitizer)

namespace fs_test {
namespace {

namespace fio = fuchsia_io;

using ParamType = std::tuple<TestFilesystemOptions, /*remount=*/bool>;

class ResizeTest : public BaseFilesystemTest, public testing::WithParamInterface<ParamType> {
 public:
  ResizeTest() : BaseFilesystemTest(std::get<0>(GetParam())) {}

  static bool ShouldRemount() { return std::get<1>(GetParam()); }

 protected:
  void QueryInfo(uint64_t* out_free_pool_size) {
    fbl::unique_fd fd(open(fs().mount_path().c_str(), O_RDONLY | O_DIRECTORY));
    ASSERT_TRUE(fd);
    fdio_cpp::FdioCaller caller(std::move(fd));
    auto query_result = fidl::WireCall(caller.borrow_as<fio::Directory>())->QueryFilesystem();
    ASSERT_EQ(query_result.status(), ZX_OK);
    ASSERT_NE(query_result->info, nullptr);
    fuchsia_io::wire::FilesystemInfo* info = query_result->info.get();
    // This should always be true, for all filesystems.
    ASSERT_GT(info->total_bytes, info->used_bytes);
    *out_free_pool_size = info->free_shared_pool_bytes;
  }

  void EnsureCanGrow() {
    uint64_t free_pool_size;
    ASSERT_NO_FATAL_FAILURE(QueryInfo(&free_pool_size));
    // This tests expects to run with free FVM space.
    ASSERT_GT(free_pool_size, 0ul);
  }

  void EnsureCannotGrow() {
    uint64_t free_pool_size;
    ASSERT_NO_FATAL_FAILURE(QueryInfo(&free_pool_size));
    ASSERT_EQ(free_pool_size, 0ul);
  }
};

using MaxInodeTest = ResizeTest;

TEST_P(MaxInodeTest, UseAllInodes) {
  ASSERT_NO_FATAL_FAILURE(EnsureCanGrow());

  // Create 100,000 inodes.
  // We expect that this will force enough inodes to cause the
  // filesystem structures to resize partway through.
  constexpr size_t kFilesPerDirectory = 100;
  size_t d = 0;
  while (true) {
    if (d % 100 == 0) {
      std::cout << "Creating directory (containing 100 files): " << d << std::endl;
    }
    const std::string dname = GetPath(std::to_string(d));
    if (mkdir(dname.c_str(), 0666) < 0) {
      ASSERT_EQ(errno, ENOSPC);
      break;
    }
    bool stop = false;
    for (size_t f = 0; f < kFilesPerDirectory; f++) {
      const std::string fname = dname + "/" + std::to_string(f);
      fbl::unique_fd fd(open(fname.c_str(), O_CREAT | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR));
      if (!fd) {
        ASSERT_EQ(errno, ENOSPC);
        stop = true;
        break;
      }
    }
    if (stop) {
      break;
    }
    d++;
  }

  ASSERT_NO_FATAL_FAILURE(EnsureCannotGrow());

  if (ShouldRemount()) {
    std::cout << "Unmounting, Verifying, Re-mounting..." << std::endl;
    EXPECT_EQ(fs().Unmount().status_value(), ZX_OK);
    EXPECT_EQ(fs().Fsck().status_value(), ZX_OK);
    EXPECT_EQ(fs().Mount().status_value(), ZX_OK);
  }

  size_t directory_count = d;
  for (size_t d = 0; d < directory_count; d++) {
    if (d % 100 == 0) {
      std::cout << "Deleting directory (containing 100 files): " << d << std::endl;
    }
    const std::string dname = GetPath(std::to_string(d));
    for (size_t f = 0; f < kFilesPerDirectory; f++) {
      const std::string fname = dname + "/" + std::to_string(f);
      ASSERT_EQ(unlink(fname.c_str()), 0);
    }
    ASSERT_EQ(rmdir(dname.c_str()), 0);
  }
}

using MaxDataTest = ResizeTest;

TEST_P(MaxDataTest, UseAllData) {
  constexpr size_t kBufSize = 1 << 20;
  constexpr size_t kFileSize = 20 * kBufSize;
  ASSERT_NO_FATAL_FAILURE(EnsureCanGrow());

  uint64_t disk_size = fs().options().device_block_count * fs().options().device_block_size;
  // Counts both copies of the metadata.
  // TODO(jfsulliv) change to use MetadataBuffer::BytesNeeded() when that's landed.
  size_t metadata_size =
      fvm::Header::FromDiskSize(fvm::kMaxUsablePartitions, disk_size, fs().options().fvm_slice_size)
          .GetDataStartOffset();

  ASSERT_GT(disk_size, metadata_size);
  disk_size -= metadata_size;

  ASSERT_GT(disk_size, minfs::kMinfsMinimumSlices * fs().options().fvm_slice_size);
  disk_size -= minfs::kMinfsMinimumSlices * fs().options().fvm_slice_size;

  std::vector<uint8_t> buf(kBufSize);

  size_t f = 0;
  while (true) {
    std::cout << "Creating 20 MB file " << f << std::endl;
    const std::string fname = GetPath(std::to_string(f));
    fbl::unique_fd fd(open(fname.c_str(), O_CREAT | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR));
    if (!fd) {
      ASSERT_EQ(errno, ENOSPC);
      break;
    }
    f++;
    bool stop = false;
    ASSERT_EQ(ftruncate(fd.get(), kFileSize), 0);
    for (size_t done = 0; done < kFileSize;) {
      ssize_t r = write(fd.get(), buf.data(), std::min(kBufSize, kFileSize - done));
      if (r < 0) {
        ASSERT_EQ(errno, ENOSPC);
        stop = true;
        break;
      }
      done += r;
    }
    if (stop) {
      break;
    }
  }

  ASSERT_NO_FATAL_FAILURE(EnsureCannotGrow());

  if (ShouldRemount()) {
    std::cout << "Unmounting, Verifying, Re-mounting..." << std::endl;
    EXPECT_EQ(fs().Unmount().status_value(), ZX_OK);
    EXPECT_EQ(fs().Fsck().status_value(), ZX_OK);
    EXPECT_EQ(fs().Mount().status_value(), ZX_OK);
  }

  size_t file_count = f;
  for (size_t f = 0; f < file_count; f++) {
    const std::string fname = GetPath(std::to_string(f));
    ASSERT_EQ(unlink(fname.c_str()), 0);
  }
}

std::string GetParamDescription(const testing::TestParamInfo<ParamType>& param) {
  std::stringstream s;
  s << std::get<0>(param.param) << (std::get<1>(param.param) ? "WithRemount" : "WithoutRemount");
  return s.str();
}

std::vector<ParamType> GetTestCombinationsForMaxInodeTest() {
  std::vector<ParamType> test_combinations;
  for (TestFilesystemOptions options : AllTestFilesystems()) {
    if (options.use_fvm && options.filesystem->GetTraits().supports_resize) {
      options.device_block_count = 1LLU << 15;
      options.device_block_size = 1LLU << 9;
      options.fvm_slice_size = 1LLU << 20;
      test_combinations.emplace_back(options, false);
      if (!options.filesystem->GetTraits().in_memory) {
        test_combinations.emplace_back(options, true);
      }
    }
  }
  return test_combinations;
}

std::vector<ParamType> GetTestCombinationsForMaxDataTest() {
  std::vector<ParamType> test_combinations;
  for (TestFilesystemOptions options : AllTestFilesystems()) {
    if (options.use_fvm && options.filesystem->GetTraits().supports_resize) {
      options.device_block_count = 1LLU << 17;
      options.device_block_size = 1LLU << 9;
      options.fvm_slice_size = 1LLU << 20;
      test_combinations.emplace_back(options, false);
      if (!options.filesystem->GetTraits().in_memory) {
        test_combinations.emplace_back(options, true);
      }
    }
  }
  return test_combinations;
}

INSTANTIATE_TEST_SUITE_P(/*no prefix*/, MaxInodeTest,
                         testing::ValuesIn(GetTestCombinationsForMaxInodeTest()),
                         GetParamDescription);

GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MaxInodeTest);

INSTANTIATE_TEST_SUITE_P(/*no prefix*/, MaxDataTest,
                         testing::ValuesIn(GetTestCombinationsForMaxDataTest()),
                         GetParamDescription);

GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MaxDataTest);

}  // namespace
}  // namespace fs_test

#endif  // !__has_feature(address_sanitizer)
