Example #1
0
    def test_nfs_mounted(self, mock_is_nfs_mounted) -> None:
        mock_is_nfs_mounted.return_value = True
        instance = FakeEdenInstance(self.make_temporary_directory())
        checkout = instance.create_test_mount("mount_dir")

        dry_run = True
        out = TestOutput()
        exit_code = doctor.cure_what_ails_you(
            typing.cast(EdenInstance, instance),
            dry_run,
            instance.mount_table,
            fs_util=FakeFsUtil(),
            proc_utils=self.make_proc_utils(),
            kerberos_checker=FakeKerberosChecker(),
            out=out,
        )
        expected = f"""<yellow>- Found problem:<reset>
Eden's state directory is on an NFS file system: {instance.state_dir}
  This will likely cause performance problems and/or other errors.
The most common cause for this is if your ~/local symlink does not point to local disk.  Make sure that ~/local is a symlink pointing to local disk and then restart Eden.

Checking {checkout.path}
<yellow>- Found problem:<reset>
The Mercurial data directory for {checkout.path}/.hg/sharedpath is at {instance.default_backing_repo}/.hg which is on a NFS filesystem. Accessing files and directories in this repository will be slow.
<yellow>Discovered 2 problems during --dry-run<reset>
"""
        self.assertEqual(expected, out.getvalue())
        self.assertEqual(1, exit_code)
Example #2
0
    def test_edenfs_starting(self, mock_get_roots_for_nuclide, mock_watchman):
        instance = FakeEdenInstance(self.make_temporary_directory(),
                                    status=fb303_status.STARTING)
        instance.create_test_mount("eden-mount")

        out = TestOutput()
        dry_run = False
        exit_code = doctor.cure_what_ails_you(
            instance,
            dry_run,
            FakeMountTable(),
            fs_util=FakeFsUtil(),
            proc_utils=self.make_proc_utils(),
            kerberos_checker=FakeKerberosChecker(),
            out=out,
        )

        self.assertEqual(
            """\
<yellow>- Found problem:<reset>
Eden is currently still starting.
Please wait for edenfs to finish starting.
If Eden seems to be taking too long to start you can try restarting it
with "eden restart"

<yellow>1 issue requires manual attention.<reset>
Ask in the Eden Users group if you need help fixing issues with Eden:
https://fb.facebook.com/groups/eden.users/
""",
            out.getvalue(),
        )
        self.assertEqual(1, exit_code)
Example #3
0
    def _test_remount_checkouts(
        self,
        mock_get_roots_for_nuclide,
        mock_watchman,
        dry_run: bool,
        old_edenfs: bool = False,
    ) -> Tuple[int, str, List[Path]]:
        """Test that `eden doctor` remounts configured mount points that are not
        currently mounted.
        """
        tmp_dir = self.make_temporary_directory()
        instance = FakeEdenInstance(tmp_dir)

        mounts = []
        mount1 = instance.create_test_mount("path1")
        mounts.append(mount1.path)
        mounts.append(instance.create_test_mount("path2", active=False).path)
        if old_edenfs:
            # Mimic older versions of edenfs, and do not return mount state data.
            instance.get_thrift_client_legacy().change_mount_state(
                mount1.path, None)

        out = TestOutput()
        exit_code = doctor.cure_what_ails_you(
            typing.cast(EdenInstance, instance),
            dry_run,
            instance.mount_table,
            fs_util=FakeFsUtil(),
            proc_utils=self.make_proc_utils(),
            kerberos_checker=FakeKerberosChecker(),
            out=out,
        )
        return exit_code, out.getvalue(), mounts
Example #4
0
    def test_edenfs_stopping(self, mock_get_roots_for_nuclide, mock_watchman):
        instance = FakeEdenInstance(self.make_temporary_directory(),
                                    status=fb303_status.STOPPING)
        instance.create_test_mount("eden-mount")

        out = TestOutput()
        dry_run = False
        exit_code = doctor.cure_what_ails_you(
            instance,
            dry_run,
            FakeMountTable(),
            fs_util=FakeFsUtil(),
            proc_utils=self.make_proc_utils(),
            kerberos_checker=FakeKerberosChecker(),
            out=out,
        )

        self.assertEqual(
            """\
<yellow>- Found problem:<reset>
Eden is currently shutting down.
Either wait for edenfs to exit, or to forcibly kill Eden, run:

    eden stop --kill

<yellow>1 issue requires manual attention.<reset>
Ask in the Eden Users group if you need help fixing issues with Eden:
https://fb.facebook.com/groups/eden.users/
""",
            out.getvalue(),
        )
        self.assertEqual(1, exit_code)
Example #5
0
    def test_edenfs_not_running(self, mock_get_roots_for_nuclide,
                                mock_watchman) -> None:
        instance = FakeEdenInstance(self.make_temporary_directory(),
                                    status=fb303_status.DEAD)
        instance.create_test_mount("eden-mount")

        out = TestOutput()
        dry_run = False
        exit_code = doctor.cure_what_ails_you(
            # pyre-fixme[6]: For 1st param expected `EdenInstance` but got
            #  `FakeEdenInstance`.
            instance,
            dry_run,
            FakeMountTable(),
            fs_util=FakeFsUtil(),
            proc_utils=self.make_proc_utils(),
            kerberos_checker=FakeKerberosChecker(),
            out=out,
        )

        self.assertEqual(
            """\
<yellow>- Found problem:<reset>
EdenFS is not running.
To start EdenFS, run:

    eden start

<yellow>1 issue requires manual attention.<reset>
Ask in the EdenFS Users group if you need help fixing issues with EdenFS:
https://fb.facebook.com/groups/eden.users/
""",
            out.getvalue(),
        )
        self.assertEqual(1, exit_code)
Example #6
0
    def test_privhelper_check_not_accessible(self,
                                             mock_check_privhelper_connection):
        instance = FakeEdenInstance(self.make_temporary_directory())
        mount = instance.create_test_mount("path1").path
        dry_run = False
        out = TestOutput()
        exit_code = doctor.cure_what_ails_you(
            instance,
            dry_run,
            instance.mount_table,
            fs_util=FakeFsUtil(),
            proc_utils=self.make_proc_utils(),
            kerberos_checker=FakeKerberosChecker(),
            out=out,
        )

        self.assertEqual(
            f"""\
<yellow>- Found problem:<reset>
The PrivHelper process is not accessible.
To restore the connection to the PrivHelper, run `eden restart`

Checking {mount}
<yellow>1 issue requires manual attention.<reset>
Ask in the Eden Users group if you need help fixing issues with Eden:
https://fb.facebook.com/groups/eden.users/
""",
            out.getvalue(),
        )
        self.assertEqual(1, exit_code)
Example #7
0
    def test_privhelper_check_accessible(
            self, mock_check_privhelper_connection) -> None:
        instance = FakeEdenInstance(self.make_temporary_directory())
        mount = instance.create_test_mount("path1").path
        dry_run = False
        out = TestOutput()
        exit_code = doctor.cure_what_ails_you(
            # pyre-fixme[6]: For 1st param expected `EdenInstance` but got
            #  `FakeEdenInstance`.
            instance,
            dry_run,
            instance.mount_table,
            fs_util=FakeFsUtil(),
            proc_utils=self.make_proc_utils(),
            kerberos_checker=FakeKerberosChecker(),
            out=out,
        )

        self.assertEqual(
            f"""\
Checking {mount}
<green>No issues detected.<reset>
""",
            out.getvalue(),
        )
        self.assertEqual(0, exit_code)
Example #8
0
 def cure_what_ails_you(self, dry_run: bool) -> TestOutput:
     out = TestOutput()
     doctor.cure_what_ails_you(
         typing.cast(EdenInstance, self.instance),
         dry_run,
         self.instance.mount_table,
         fs_util=FakeFsUtil(),
         proc_utils=self.make_proc_utils(),
         kerberos_checker=FakeKerberosChecker(),
         out=out,
     )
     return out
Example #9
0
    def test_eden_not_in_use(self, mock_get_roots_for_nuclide, mock_watchman):
        instance = FakeEdenInstance(self.make_temporary_directory(),
                                    status=fb303_status.DEAD)

        out = TestOutput()
        dry_run = False
        exit_code = doctor.cure_what_ails_you(
            instance,
            dry_run,
            FakeMountTable(),
            fs_util=FakeFsUtil(),
            proc_utils=self.make_proc_utils(),
            kerberos_checker=FakeKerberosChecker(),
            out=out,
        )

        self.assertEqual("EdenFS is not in use.\n", out.getvalue())
        self.assertEqual(0, exit_code)
Example #10
0
    def run_varying_nfs(self, mock_path_read_text) -> NfsDoctorResult:
        instance = FakeEdenInstance(self.make_temporary_directory())
        shared_path = "shared_path"
        mount_dir = "mount_dir"
        mock_path_read_text.return_value = shared_path
        client_path = str(instance.create_test_mount(mount_dir).path)

        dry_run = True
        out = TestOutput()
        exit_code = doctor.cure_what_ails_you(
            typing.cast(EdenInstance, instance),
            dry_run,
            instance.mount_table,
            fs_util=FakeFsUtil(),
            proc_utils=self.make_proc_utils(),
            kerberos_checker=FakeKerberosChecker(),
            out=out,
        )
        return NfsDoctorResult(
            mount_dir, shared_path, client_path, instance, exit_code, out.getvalue()
        )
Example #11
0
    def run_varying_nfs(self, mock_path_read_text):
        instance = FakeEdenInstance(self.make_temporary_directory())
        v = SimpleNamespace(
            mount_dir="mount_dir", shared_path="shared_path", instance=instance
        )
        mock_path_read_text.return_value = v.shared_path
        v.client_path = str(instance.create_test_mount(v.mount_dir).path)

        dry_run = True
        out = TestOutput()
        v.exit_code = doctor.cure_what_ails_you(
            instance,
            dry_run,
            instance.mount_table,
            fs_util=FakeFsUtil(),
            proc_utils=self.make_proc_utils(),
            kerberos_checker=FakeKerberosChecker(),
            out=out,
        )
        v.stdout = out.getvalue()
        return v
Example #12
0
    def test_not_all_mounts_have_watchman_watcher(self,
                                                  mock_get_roots_for_nuclide,
                                                  mock_watchman) -> None:
        instance = FakeEdenInstance(self.make_temporary_directory())
        edenfs_path = str(
            instance.create_test_mount("eden-mount", scm_type="git").path)
        edenfs_path_not_watched = str(
            instance.create_test_mount("eden-mount-not-watched",
                                       scm_type="git").path)
        side_effects: List[Dict[str, Any]] = []
        calls = []

        calls.append(call(["watch-list"]))
        side_effects.append({"roots": [edenfs_path]})
        calls.append(call(["watch-project", edenfs_path]))
        side_effects.append({"watcher": "eden"})
        mock_watchman.side_effect = side_effects

        out = TestOutput()
        dry_run = False
        exit_code = doctor.cure_what_ails_you(
            # pyre-fixme[6]: For 1st param expected `EdenInstance` but got
            #  `FakeEdenInstance`.
            instance,
            dry_run,
            mount_table=instance.mount_table,
            fs_util=FakeFsUtil(),
            proc_utils=self.make_proc_utils(),
            kerberos_checker=FakeKerberosChecker(),
            out=out,
        )

        self.assertEqual(
            f"Checking {edenfs_path}\n"
            f"Checking {edenfs_path_not_watched}\n"
            "<green>No issues detected.<reset>\n",
            out.getvalue(),
        )
        mock_watchman.assert_has_calls(calls)
        self.assertEqual(0, exit_code)
Example #13
0
 def _test_with_pwd(self, instance: "FakeEdenInstance",
                    pwd: Optional[str]) -> Tuple[int, str]:
     if pwd is None:
         old_pwd = os.environ.pop("PWD", None)
     else:
         old_pwd = os.environ.get("PWD")
         os.environ["PWD"] = pwd
     try:
         out = TestOutput()
         exit_code = doctor.cure_what_ails_you(
             typing.cast(EdenInstance, instance),
             dry_run=False,
             mount_table=instance.mount_table,
             fs_util=FakeFsUtil(),
             proc_utils=self.make_proc_utils(),
             kerberos_checker=FakeKerberosChecker(),
             out=out,
         )
         return exit_code, out.getvalue()
     finally:
         if old_pwd is not None:
             os.environ["PWD"] = old_pwd
Example #14
0
    def test_unconfigured_mounts_dont_crash(
            self, mock_get_roots_for_nuclide) -> None:
        # If EdenFS advertises that a mount is active, but it is not in the
        # configuration, then at least don't throw an exception.
        instance = FakeEdenInstance(self.make_temporary_directory())
        edenfs_path1 = instance.create_test_mount("path1").path
        edenfs_path2 = instance.create_test_mount("path2").path
        # Remove path2 from the list of mounts in the instance
        instance.remove_checkout_configuration(str(edenfs_path2))

        dry_run = False
        out = TestOutput()
        exit_code = doctor.cure_what_ails_you(
            # pyre-fixme[6]: For 1st param expected `EdenInstance` but got
            #  `FakeEdenInstance`.
            instance,
            dry_run,
            instance.mount_table,
            fs_util=FakeFsUtil(),
            proc_utils=self.make_proc_utils(),
            kerberos_checker=FakeKerberosChecker(),
            out=out,
        )

        self.assertEqual(
            f"""\
Checking {edenfs_path1}
Checking {edenfs_path2}
<yellow>- Found problem:<reset>
Checkout {edenfs_path2} is running but not listed in Eden's configuration file.
Running "eden unmount {edenfs_path2}" will unmount this checkout.

<yellow>1 issue requires manual attention.<reset>
Ask in the EdenFS Users group if you need help fixing issues with EdenFS:
https://fb.facebook.com/groups/eden.users/
""",
            out.getvalue(),
        )
        self.assertEqual(1, exit_code)
Example #15
0
    def test_watchman_fails(self, mock_watchman):
        tmp_dir = self.make_temporary_directory()
        instance = FakeEdenInstance(tmp_dir)

        mount = instance.create_test_mount("path1", active=False).path

        # Make calls to watchman fail rather than returning expected output
        side_effects = [{"error": "watchman failed"}]
        mock_watchman.side_effect = side_effects

        out = TestOutput()
        exit_code = doctor.cure_what_ails_you(
            typing.cast(EdenInstance, instance),
            dry_run=False,
            mount_table=instance.mount_table,
            fs_util=FakeFsUtil(),
            proc_utils=self.make_proc_utils(),
            kerberos_checker=FakeKerberosChecker(),
            out=out,
        )

        # "watchman watch-list" should have been called by the doctor code
        calls = [call(["watch-list"])]
        mock_watchman.assert_has_calls(calls)

        self.assertEqual(
            out.getvalue(),
            f"""\
Checking {mount}
<yellow>- Found problem:<reset>
{mount} is not currently mounted
Remounting {mount}...<green>fixed<reset>

<yellow>Successfully fixed 1 problem.<reset>
""",
        )
        self.assertEqual(exit_code, 0)
Example #16
0
    def test_end_to_end_test_with_various_scenarios(self,
                                                    mock_get_roots_for_nuclide,
                                                    mock_watchman):
        side_effects: List[Dict[str, Any]] = []
        calls = []
        instance = FakeEdenInstance(self.make_temporary_directory())

        # In edenfs_path1, we will break the snapshot check.
        edenfs_path1_snapshot = "abcd" * 10
        edenfs_path1_dirstate_parent = "12345678" * 5
        edenfs_path1 = str(
            instance.create_test_mount(
                "path1",
                snapshot=edenfs_path1_snapshot,
                dirstate_parent=edenfs_path1_dirstate_parent,
            ).path)

        # In edenfs_path2, we will break the inotify check and the Nuclide
        # subscriptions check.
        edenfs_path2 = str(
            instance.create_test_mount("path2",
                                       scm_type="git",
                                       setup_path=False).path)

        # In edenfs_path3, we do not create the .hg directory
        edenfs_path3 = str(
            instance.create_test_mount("path3", setup_path=False).path)
        os.makedirs(edenfs_path3)

        # Assume all paths are used as root folders in a connected Nuclide.
        mock_get_roots_for_nuclide.return_value = {
            edenfs_path1,
            edenfs_path2,
            edenfs_path3,
        }

        calls.append(call(["watch-list"]))
        side_effects.append(
            {"roots": [edenfs_path1, edenfs_path2, edenfs_path3]})

        calls.append(call(["watch-project", edenfs_path1]))
        side_effects.append({"watcher": "eden"})

        calls.append(call(["debug-get-subscriptions", edenfs_path1]))
        side_effects.append(
            _create_watchman_subscription(
                filewatcher_subscriptions=[f"filewatcher-{edenfs_path1}"]))

        calls.append(call(["watch-project", edenfs_path2]))
        side_effects.append({"watcher": "inotify"})
        calls.append(call(["watch-del", edenfs_path2]))
        side_effects.append({"watch-del": True, "root": edenfs_path2})
        calls.append(call(["watch-project", edenfs_path2]))
        side_effects.append({"watcher": "eden"})

        calls.append(call(["debug-get-subscriptions", edenfs_path2]))
        side_effects.append(
            _create_watchman_subscription(filewatcher_subscriptions=[]))

        calls.append(call(["watch-project", edenfs_path3]))
        side_effects.append({"watcher": "eden"})
        calls.append(call(["debug-get-subscriptions", edenfs_path3]))
        side_effects.append(
            _create_watchman_subscription(
                filewatcher_subscriptions=[f"filewatcher-{edenfs_path3}"]))

        mock_watchman.side_effect = side_effects

        out = TestOutput()
        dry_run = False

        exit_code = doctor.cure_what_ails_you(
            instance,
            dry_run,
            instance.mount_table,
            fs_util=FakeFsUtil(),
            proc_utils=self.make_proc_utils(),
            kerberos_checker=FakeKerberosChecker(),
            out=out,
        )

        self.assertEqual(
            f"""\
Checking {edenfs_path1}
<yellow>- Found problem:<reset>
Found inconsistent/missing data in {edenfs_path1}/.hg:
  mercurial's parent commit is {edenfs_path1_dirstate_parent}, \
but Eden's internal parent commit is {edenfs_path1_snapshot}
Repairing hg directory contents for {edenfs_path1}...<green>fixed<reset>

Checking {edenfs_path2}
<yellow>- Found problem:<reset>
Watchman is watching {edenfs_path2} with the wrong watcher type: \
"inotify" instead of "eden"
Fixing watchman watch for {edenfs_path2}...<green>fixed<reset>

<yellow>- Found problem:<reset>
Nuclide appears to be used to edit the following directories
under {edenfs_path2}:

  {edenfs_path2}

but the following Watchman subscriptions appear to be missing:

  filewatcher-{edenfs_path2}

This can cause file changes to fail to show up in Nuclide.
Currently, the only workaround for this is to run
"Nuclide Remote Projects: Kill And Restart" from the
command palette in Atom.

Checking {edenfs_path3}
<yellow>- Found problem:<reset>
Missing hg directory: {edenfs_path3}/.hg
Repairing hg directory contents for {edenfs_path3}...<green>fixed<reset>

<yellow>Successfully fixed 3 problems.<reset>
<yellow>1 issue requires manual attention.<reset>
Ask in the Eden Users group if you need help fixing issues with Eden:
https://fb.facebook.com/groups/eden.users/
""",
            out.getvalue(),
        )
        mock_watchman.assert_has_calls(calls)
        self.assertEqual(1, exit_code)