sapling/eden/integration/debug_getpath_test.py
Andres Suarez fbdb46f5cb Tidy up license headers
Reviewed By: chadaustin

Differential Revision: D17872966

fbshipit-source-id: cd60a364a2146f0dadbeca693b1d4a5d7c97ff63
2019-10-11 05:28:23 -07:00

134 lines
4.9 KiB
Python

#!/usr/bin/env python3
# Copyright (c) Facebook, Inc. and its affiliates.
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2.
import os
import stat
import time
from facebook.eden.ttypes import TimeSpec
from .lib import edenclient, testcase
@testcase.eden_repo_test
class DebugGetPathTest(testcase.EdenRepoTest):
def populate_repo(self) -> None:
self.repo.write_file("hello", "hola\n")
self.repo.commit("Initial commit.")
def test_getpath_root_inode(self) -> None:
"""
Test that calling `eden debug getpath 1` returns the path to the eden
mount, and indicates that the inode is loaded.
"""
output = self.eden.run_cmd("debug", "getpath", "1", cwd=self.mount)
self.assertEqual("loaded " + self.mount + "\n", output)
def test_getpath_dot_eden_inode(self) -> None:
"""
Test that calling `eden debug getpath ${ino}` returns the path to the
.eden directory, and indicates that the inode is loaded.
"""
st = os.lstat(os.path.join(self.mount, ".eden"))
self.assertTrue(stat.S_ISDIR(st.st_mode))
ino = st.st_ino
output = self.eden.run_cmd("debug", "getpath", str(ino), cwd=self.mount)
self.assertEqual("loaded " + os.path.join(self.mount, ".eden") + "\n", output)
def test_getpath_invalid_inode(self) -> None:
"""
Test that calling `eden debug getpath 1234` raises an error since
1234 is not a valid inode number
"""
with self.assertRaises(edenclient.EdenCommandError) as context:
self.eden.run_cmd("debug", "getpath", "1234", cwd=self.mount)
self.assertIn(
"unknown inode number 1234", context.exception.stderr.decode()
)
def test_getpath_unloaded_inode(self) -> None:
"""
Test that calling `eden debug getpath` on an unloaded inode returns the
correct path and indicates that it is unloaded
"""
dirpath = os.path.join(self.mount, "dir")
filepath = os.path.join(dirpath, "file")
# Create the file
self.write_file(os.path.join("dir", "file"), "blah")
# Get the inodeNumber
stat = os.stat(filepath)
self.unload_one_inode_under("dir")
# Get the path for dir/file from its inodeNumber
output = self.eden.run_cmd("debug", "getpath", str(stat.st_ino), cwd=self.mount)
self.assertEqual(f"unloaded {filepath}\n", output)
def test_getpath_unloaded_inode_rename_parent(self) -> None:
"""
Test that when an unloaded inode has one of its parents renamed,
`eden debug getpath` returns the new path
"""
# Create the file
self.write_file(os.path.join("foo", "bar", "test.txt"), "blah")
dirpath = os.path.join(self.mount, "foo", "bar")
# Get the inodeNumber
stat = os.stat(os.path.join(dirpath, "test.txt"))
self.unload_one_inode_under(os.path.join("foo", "bar"))
# Rename the foo directory
os.rename(os.path.join(self.mount, "foo"), os.path.join(self.mount, "newname"))
# Get the new path for the file from its inodeNumber
output = self.eden.run_cmd("debug", "getpath", str(stat.st_ino), cwd=self.mount)
self.assertEqual(
"unloaded " + os.path.join(self.mount, "newname", "bar", "test.txt") + "\n",
output,
)
def unload_one_inode_under(self, path: str) -> None:
# TODO: To support unloading more than one inode, sum the return value
# until count is reached our the attempt limit has been reached.
remaining_attempts = 5
while True:
age = TimeSpec() # zero
with self.eden.get_thrift_client() as client:
count = client.unloadInodeForPath(
os.fsencode(self.mount), os.fsencode(path), age
)
if remaining_attempts == 1:
self.assertEqual(1, count)
elif count == 1:
break
else:
remaining_attempts -= 1
time.sleep(1)
continue
def test_getpath_unlinked_inode(self) -> None:
"""
Test that when an inode is unlinked, `eden debug getpath` indicates
that it is unlinked
"""
# Create the file
self.write_file(os.path.join("foo", "bar", "test.txt"), "blah")
# Keep an open file handle so that the inode doesn't become invalid
f = open(os.path.join(self.mount, "foo", "bar", "test.txt"))
# Get the inodeNumber
stat = os.stat(os.path.join(self.mount, "foo", "bar", "test.txt"))
# Unlink the file
os.unlink(os.path.join(self.mount, "foo", "bar", "test.txt"))
output = self.eden.run_cmd("debug", "getpath", str(stat.st_ino), cwd=self.mount)
# Close the file handle
f.close()
self.assertEqual("loaded [unlinked]\n", output)