sapling/eden/integration/remount_test.py
Pyre Bot Jr bb5656edfc Add annotations to eden
Reviewed By: shannonzhu

Differential Revision: D34217873

fbshipit-source-id: 93794c9e7e63d12b709fca1d636e71916ef0eb5c
2022-02-14 12:17:43 -08:00

210 lines
6.9 KiB
Python

#!/usr/bin/env python3
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2.
import json
import os
from .lib import edenclient, testcase
NOT_MOUNTED_DIR_LIST = ["README_EDEN.txt"]
@testcase.eden_repo_test
class RemountTest(testcase.EdenRepoTest):
def populate_repo(self) -> None:
self.repo.write_file("hello", "hola\n")
self.repo.write_file("adir/file", "foo!\n")
self.repo.symlink("slink", "hello")
self.repo.commit("Initial commit.")
def _assert_mounted(self, mount_path: str) -> None:
expected_entries = {".eden", "adir", "hello", "slink"}
self.assert_checkout_root_entries(expected_entries, path=mount_path)
def select_storage_engine(self) -> str:
"""we need to persist data across restarts"""
return "sqlite"
def test_remount_basic(self) -> None:
# Mount multiple clients
self._clone_checkouts(5)
self.eden.shutdown()
self.eden.start()
# Verify that clients are remounted on startup
for i in range(5):
self._assert_mounted(f"{self.mount}-{i}")
# Verify that default repo created by EdenRepoTestBase is remounted
self._assert_mounted(self.mount)
def test_git_and_hg(self) -> None:
# Create git and hg repositories for mounting
repo_names = {"git": "git_repo", "hg": "hg_repo"}
git_repo = self.create_git_repo(repo_names["git"])
hg_repo = self.create_hg_repo(repo_names["hg"])
repos = {"git_repo": git_repo, "hg_repo": hg_repo}
git_repo.write_file("hello", "hola\n")
git_repo.commit("Initial commit.")
hg_repo.write_file("hello", "hola\n")
hg_repo.commit("Initial commit.")
# Mount git and hg clients
for name, repo in repos.items():
for i in range(3):
self.eden.clone(repo.path, os.path.join(self.mounts_dir, f"{name}-{i}"))
self.eden.shutdown()
self.eden.start()
# Verify that clients are remounted on startup
for name, repo in repos.items():
scm_type = repo.get_type()
for i in range(3):
mount_path = os.path.join(self.mounts_dir, f"{name}-{i}")
self.assert_checkout_root_entries(
{".eden", "hello"}, mount_path, scm_type=scm_type
)
hello = os.path.join(mount_path, "hello")
with open(hello, "r") as f:
self.assertEqual("hola\n", f.read())
def test_partial_unmount(self) -> None:
self._clone_checkouts(5)
# Remove the main checkout
self.eden.remove(self.mount)
self.assertFalse(os.path.exists(self.mount))
self.eden.shutdown()
self.eden.start()
# Verify that clients that were still mounted at shutdown are remounted
for i in range(5):
self._assert_mounted(f"{self.mount}-{i}")
# Verify that unmounted client is not remounted
self.assertFalse(os.path.exists(self.mount))
def test_restart_twice(self) -> None:
self.maxDiff = None
self._clone_checkouts(5)
self.eden.shutdown()
self.eden.start()
# Remove some checkouts
self.eden.remove(self.mount)
self.eden.remove(self.mount + "-3")
self.eden.shutdown()
self.eden.start()
# Verify that clients that were still mounted at shutdown are remounted
checkouts = self.eden.list_cmd_simple()
expected_checkouts = {
f"{self.mount}-{i}": "RUNNING" for i in range(5) if i != 3
}
self.assertEqual(expected_checkouts, checkouts)
for i in range(5):
if i == 3:
continue
self._assert_mounted(f"{self.mount}-{i}")
# Verify that unmounted clients are not remounted
self.assertFalse(os.path.exists(self.mount))
self.assertFalse(os.path.exists(self.mount + "3"))
def test_try_remount_existing_mount(self) -> None:
"""Verify trying to mount an existing mount prints a sensible error."""
mount_destination = self.mount + "-0"
self.eden.clone(self.repo.path, mount_destination)
with self.assertRaises(edenclient.EdenCommandError) as context:
self.eden.run_cmd("mount", mount_destination)
self.assertIn(
(
"ERROR: Mount point in use! %s is already mounted by EdenFS.\n"
% mount_destination
),
context.exception.stderr,
)
self.assertEqual(1, context.exception.returncode)
def test_empty_config_json(self) -> None:
self._clone_checkouts(5)
# Clear the contents of config.json file
open(os.path.join(self.eden_dir, "config.json"), "w").close()
self.eden.shutdown()
self.eden.start()
self._verify_not_mounted(5)
def test_deleted_config_json(self) -> None:
self._clone_checkouts(5)
# Delete the config.json file
os.remove(os.path.join(self.eden_dir, "config.json"))
self.eden.shutdown()
self.eden.start()
self._verify_not_mounted(5)
def test_incorrect_config_json(self) -> None:
self._clone_checkouts(5)
# Reload config.json file with incorrect data
config_data = {
self.mounts_dir + "/incorrectdir1": "jskdnbailreylbflhv",
self.mounts_dir + "/incorrectdir2": "ndjnhaleruybfialus",
}
with open(os.path.join(self.eden_dir, "config.json"), "w") as f:
json.dump(config_data, f, indent=2, sort_keys=True)
f.write("\n")
self.eden.shutdown()
self.eden.start()
self._verify_not_mounted(5)
# Incorrect mount paths from config.json should not have been created
for incorrect_mount in config_data:
self.assertFalse(os.path.isdir(incorrect_mount))
def test_bad_config_json(self) -> None:
self._clone_checkouts(5)
# Reload config.json file with random data
with open(os.path.join(self.eden_dir, "config.json"), "w") as f:
f.write("njfaeriurbvailuwrawikc\n")
self.eden.shutdown()
self.eden.start()
self._verify_not_mounted(5)
def _clone_checkouts(self, num_mounts) -> None:
for i in range(num_mounts):
self.eden.clone(self.repo.path, self.mount + "-" + str(i))
def _verify_not_mounted(self, num_mounts, main_mounted: bool = False) -> None:
# Verify that no clients are remounted. No errors should be thrown here
for i in range(num_mounts):
entries = sorted(os.listdir(self.mount + "-" + str(i)))
self.assertEqual(NOT_MOUNTED_DIR_LIST, entries)
if not main_mounted:
entries = sorted(os.listdir(self.mount))
self.assertEqual(NOT_MOUNTED_DIR_LIST, entries)