sapling/eden/integration/fsck_test.py
Adam Simpkins ef04ccf546 replace a bunch of pyre-fixme comments with pyre-ignoree
Summary:
D17135557 added a bunch of `pyre-fixme` comments to the EdenFS integration
tests for cases where Pyre cannot detect that some attributes are initialized
by the test case `setUp()` method.

It looks like Pyre's handling of `setUp()` is somewhat incorrect: it looks
like if a class has a `setUp()` method this currently suppresses all
uninitialized attribute errors (even if some attributes really are never
initialized).  However, Pyre does not detect `setUp()` methods inherited from
parent classes, and always warns about uninitialized attributes in this case
even they are initialized.

Lets change these comments from `pyre-fixme` to `pyre-ignore` since this
appears to be an issue with Pyre rather than with this code.  T62487924 is
open to track adding support for annotating custom constructor methods, which
might help here.  I've also posted in Pyre Q&A about incorrect handling of
`setUp()` in derived classes.

Reviewed By: grievejia

Differential Revision: D19963118

fbshipit-source-id: 9fd13fc8665367e0780f871a5a0d9a8fe50cc687
2020-02-24 18:55:19 -08:00

168 lines
6.6 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 pathlib
import subprocess
import unittest
from pathlib import Path
from typing import Tuple
from eden.test_support.temporary_directory import TemporaryDirectoryMixin
from .lib import edenclient, overlay as overlay_mod, repobase, testcase
FSCK_RETCODE_OK = 0
FSCK_RETCODE_SKIPPED = 1
FSCK_RETCODE_WARNINGS = 2
FSCK_RETCODE_ERRORS = 3
# pyre-ignore[13]: T62487924
class FsckTest(testcase.EdenRepoTest):
overlay: overlay_mod.OverlayStore
def populate_repo(self) -> None:
self.repo.write_file("README.md", "tbd\n")
self.repo.write_file("proj/src/main.c", "int main() { return 0; }\n")
self.repo.write_file("proj/src/lib.c", "void foo() {}\n")
self.repo.write_file("proj/src/include/lib.h", "#pragma once\nvoid foo();\n")
self.repo.write_file(
"proj/test/test.sh", "#!/bin/bash\necho test\n", mode=0o755
)
self.repo.write_file("doc/foo.txt", "foo\n")
self.repo.write_file("doc/bar.txt", "bar\n")
self.repo.symlink("proj/doc", "../doc")
self.repo.commit("Initial commit.")
def create_repo(self, name: str) -> repobase.Repository:
return self.create_hg_repo("main")
def setup_eden_test(self) -> None:
super().setup_eden_test()
self.overlay = overlay_mod.OverlayStore(self.eden, self.mount_path)
def run_fsck(self, *args: str) -> Tuple[int, str]:
"""Run `eden fsck [args]` and return a tuple of the return code and
the combined stdout and stderr.
The command output will be decoded as UTF-8 and returned as a string.
"""
cmd_result = self.eden.run_unchecked(
"fsck", *args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT
)
fsck_out = cmd_result.stdout.decode("utf-8", errors="replace")
return (cmd_result.returncode, fsck_out)
def test_fsck_force_and_check_only(self) -> None:
"""Test the behavior of the --force and --check-only fsck flags."""
foo_overlay_path = self.overlay.materialize_file(pathlib.Path("doc/foo.txt"))
# Running fsck with the mount still mounted should fail
returncode, fsck_out = self.run_fsck(self.mount)
self.assertIn(f"Not checking {self.mount}", fsck_out)
self.assertEqual(FSCK_RETCODE_SKIPPED, returncode)
# Running fsck with --force should override that
returncode, fsck_out = self.run_fsck(self.mount, "--force")
self.assertIn(f"warning: could not obtain lock", fsck_out)
self.assertIn(f"scanning anyway due to --force", fsck_out)
self.assertIn(f"Checking {self.mount}", fsck_out)
self.assertEqual(FSCK_RETCODE_OK, returncode)
# fsck should perform the check normally without --force
# if the mount is not mounted
self.eden.run_cmd("unmount", self.mount)
returncode, fsck_out = self.run_fsck(self.mount)
self.assertIn(f"Checking {self.mount}", fsck_out)
self.assertIn("No issues found", fsck_out)
self.assertEqual(FSCK_RETCODE_OK, returncode)
# Truncate the overlay file for doc/foo.txt to 0 length
with foo_overlay_path.open("wb"):
pass
# Running fsck with --check-only should report the error but not try to fix it.
returncode, fsck_out = self.run_fsck("--check-only")
self.assertIn(f"Checking {self.mount}", fsck_out)
self.assertRegex(
fsck_out,
r"invalid overlay file for materialized file .* \(doc/foo.txt\).*: "
r"zero-sized overlay file",
)
self.assertRegex(fsck_out, r"\b1 errors")
self.assertRegex(fsck_out, "Not fixing errors: --check-only was specified")
self.assertEqual(FSCK_RETCODE_ERRORS, returncode)
# Running fsck with no arguments should attempt to fix the errors
returncode, fsck_out = self.run_fsck()
self.assertRegex(
fsck_out,
r"invalid overlay file for materialized file .* \(doc/foo.txt\).*: "
r"zero-sized overlay file",
)
self.assertRegex(fsck_out, r"\b1 errors")
self.assertRegex(fsck_out, "Beginning repairs")
self.assertRegex(
fsck_out, "replacing corrupt file inode 'doc/foo.txt' with an empty file"
)
self.assertRegex(fsck_out, "Fixed 1 of 1 issues")
self.assertEqual(FSCK_RETCODE_ERRORS, returncode)
# There should be no more errors if we run fsck again
returncode, fsck_out = self.run_fsck()
self.assertIn(f"Checking {self.mount}", fsck_out)
self.assertIn("No issues found", fsck_out)
self.assertEqual(FSCK_RETCODE_OK, returncode)
def test_fsck_multiple_mounts(self) -> None:
mount2 = Path(self.mounts_dir) / "second_mount"
mount3 = Path(self.mounts_dir) / "third_mount"
mount4 = Path(self.mounts_dir) / "fourth_mount"
self.eden.clone(self.repo_name, mount2)
self.eden.clone(self.repo_name, mount3)
self.eden.clone(self.repo_name, mount4)
# Unmount all but mount3
self.eden.unmount(Path(self.mount))
self.eden.unmount(mount2)
self.eden.unmount(mount4)
# Running fsck should check all but mount3
returncode, fsck_out = self.run_fsck()
self.assertIn(f"Checking {self.mount}", fsck_out)
self.assertIn(f"Checking {mount2}", fsck_out)
self.assertIn(f"Not checking {mount3}", fsck_out)
self.assertIn(f"Checking {mount4}", fsck_out)
self.assertEqual(FSCK_RETCODE_SKIPPED, returncode)
# Running fsck with --force should check everything
returncode, fsck_out = self.run_fsck("--force")
self.assertIn(f"Checking {self.mount}", fsck_out)
self.assertIn(f"Checking {mount2}", fsck_out)
self.assertIn(f"Checking {mount3}", fsck_out)
self.assertIn(f"Checking {mount4}", fsck_out)
self.assertEqual(FSCK_RETCODE_OK, returncode)
class FsckTestNoEdenfs(unittest.TestCase, TemporaryDirectoryMixin):
def test_fsck_no_checkouts(self) -> None:
tmp_dir = self.make_temporary_directory()
eden = edenclient.EdenFS(Path(tmp_dir))
cmd_result = eden.run_unchecked(
"fsck",
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
encoding="utf-8",
errors="replace",
)
self.assertIn(
"No Eden checkouts are configured. Nothing to check.", cmd_result.stderr
)
self.assertEqual("", cmd_result.stdout)
self.assertEqual(0, cmd_result.returncode)