// 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())) {}

  bool ShouldRemount() const { 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<fuchsia_io::Directory>(caller.channel())->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.push_back(ParamType{options, false});
      if (!options.filesystem->GetTraits().in_memory) {
        test_combinations.push_back(ParamType{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.push_back(ParamType{options, false});
      if (!options.filesystem->GetTraits().in_memory) {
        test_combinations.push_back(ParamType{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)
