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=filesystem.LinuxFsUtil(), process_finder=self.make_process_finder(), out=out, ) return out
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(), process_finder=self.make_process_finder(), 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)
def test_unconfigured_mounts_dont_crash(self, mock_get_roots_for_nuclide): # If Eden 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( instance, dry_run, instance.mount_table, fs_util=FakeFsUtil(), process_finder=self.make_process_finder(), 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 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)
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().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(), process_finder=self.make_process_finder(), out=out, ) return exit_code, out.getvalue(), mounts
def test_not_much_to_do_when_eden_is_not_running(self, mock_watchman): edenfs_path = '/path/to/eden-mount' side_effects: List[Dict[str, Any]] = [] calls = [] calls.append(call(['watch-list'])) side_effects.append({'roots': [edenfs_path]}) mock_watchman.side_effect = side_effects out = io.StringIO() dry_run = False mount_paths = { edenfs_path: { 'bind-mounts': {}, 'mount': edenfs_path, 'scm_type': 'hg', 'snapshot': 'abcd' * 10, 'client-dir': '/I_DO_NOT_EXIST' } } config = FakeConfig(mount_paths, is_healthy=False) exit_code = doctor.cure_what_ails_you(config, dry_run, out) self.assertEqual( 'Eden is not running: cannot perform all checks.\n' 'Performing 3 checks for /path/to/eden-mount.\n' 'All is well.\n', out.getvalue() ) mock_watchman.assert_has_calls(calls) self.assertEqual(0, exit_code)
def test_edenfs_starting(self, mock_get_roots_for_nuclide, mock_watchman): instance = FakeEdenInstance( self.make_temporary_directory(), status=fb_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=filesystem.LinuxFsUtil(), process_finder=self.make_process_finder(), 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)
def test_edenfs_stopping(self, mock_get_roots_for_nuclide, mock_watchman): instance = FakeEdenInstance( self.make_temporary_directory(), status=fb_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=filesystem.LinuxFsUtil(), process_finder=self.make_process_finder(), 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)
def test_edenfs_not_running(self, mock_get_roots_for_nuclide, mock_watchman): instance = FakeEdenInstance(self.make_temporary_directory(), status=fb_status.DEAD) instance.create_test_mount("eden-mount") out = TestOutput() dry_run = False exit_code = doctor.cure_what_ails_you( instance, dry_run, FakeMountTable(), fs_util=filesystem.LinuxFsUtil(), process_finder=self.make_process_finder(), out=out, ) self.assertEqual( """\ <yellow>- Found problem:<reset> Eden is not running. To start Eden, run: eden start <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)
def test_nfs_mounted(self, mock_is_nfs_mounted): 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( instance, dry_run, instance.mount_table, fs_util=filesystem.LinuxFsUtil(), process_finder=self.make_process_finder(), 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)
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().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=filesystem.LinuxFsUtil(), process_finder=self.make_process_finder(), out=out, ) return exit_code, out.getvalue(), mounts
def test_unconfigured_mounts_dont_crash(self, mock_get_roots_for_nuclide): # If Eden 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( instance, dry_run, instance.mount_table, fs_util=filesystem.LinuxFsUtil(), process_finder=self.make_process_finder(), 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 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)
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(), process_finder=self.make_process_finder(), 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)
def test_fails_if_no_mount_points(self): out = io.StringIO() dry_run = False mount_paths = {} config = FakeConfig(mount_paths, is_healthy=False) exit_code = doctor.cure_what_ails_you(config, dry_run, out) self.assertEqual('No mounts points to assess.\n', out.getvalue()) self.assertEqual(1, exit_code)
def test_unconfigured_mounts_dont_crash(self): # If Eden advertises that a mount is active, but it is not in the # configuration, then at least don't throw an exception. tmp_dir = tempfile.mkdtemp(prefix='eden_test.') try: edenfs_path1 = os.path.join(tmp_dir, 'path1') edenfs_path2 = os.path.join(tmp_dir, 'path2') mount_paths = OrderedDict() mount_paths[edenfs_path1] = { 'bind-mounts': {}, 'mount': edenfs_path1, 'scm_type': 'hg', 'snapshot': 'abcd' * 10, 'client-dir': '/I_DO_NOT_EXIST1' } # path2 is not configured in the config... config = FakeConfig(mount_paths, is_healthy=True) # ... but is advertised by the daemon... config.get_thrift_client()._mounts = [ eden_ttypes.MountInfo(mountPoint=edenfs_path1), eden_ttypes.MountInfo(mountPoint=edenfs_path2), ] # ... and is in the system mount table. mount_table = FakeMountTable() mount_table.stats[edenfs_path1] = mtab.MTStat(st_uid=os.getuid(), st_dev=11) mount_table.stats[edenfs_path2] = mtab.MTStat(st_uid=os.getuid(), st_dev=12) os.mkdir(edenfs_path1) hg_dir = os.path.join(edenfs_path1, '.hg') os.mkdir(hg_dir) dirstate = os.path.join(hg_dir, 'dirstate') dirstate_hash = b'\xab\xcd' * 10 parents = (dirstate_hash, b'\x00' * 20) with open(dirstate, 'wb') as f: eden.dirstate.write(f, parents, tuples_dict={}, copymap={}) dry_run = False out = io.StringIO() exit_code = doctor.cure_what_ails_you(config, dry_run, out, mount_table) finally: shutil.rmtree(tmp_dir) self.assertEqual( f'''\ Performing 3 checks for {edenfs_path1}. All is well. ''', out.getvalue()) self.assertEqual(0, exit_code)
def test_not_all_mounts_have_watchman_watcher(self, mock_watchman): edenfs_path = '/path/to/eden-mount' edenfs_path_not_watched = '/path/to/eden-mount-not-watched' 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'}) calls.append(call(['debug-get-subscriptions', edenfs_path])) side_effects.append({}) mock_watchman.side_effect = side_effects out = io.StringIO() dry_run = False mount_paths = OrderedDict() mount_paths[edenfs_path] = { 'bind-mounts': {}, 'mount': edenfs_path, 'scm_type': 'git', 'snapshot': 'abcd' * 10, 'client-dir': '/I_DO_NOT_EXIST' } mount_paths[edenfs_path_not_watched] = { 'bind-mounts': {}, 'mount': edenfs_path_not_watched, 'scm_type': 'git', 'snapshot': 'abcd' * 10, 'client-dir': '/I_DO_NOT_EXIST' } config = FakeConfig(mount_paths, is_healthy=True) config.get_thrift_client()._mounts = [ eden_ttypes.MountInfo(mountPoint=edenfs_path), eden_ttypes.MountInfo(mountPoint=edenfs_path_not_watched), ] mount_table = FakeMountTable() mount_table.stats['/path/to/eden-mount'] = mtab.MTStat( st_uid=os.getuid(), st_dev=10) mount_table.stats['/path/to/eden-mount-not-watched'] = mtab.MTStat( st_uid=os.getuid(), st_dev=11) exit_code = doctor.cure_what_ails_you(config, dry_run, out, mount_table=mount_table) self.assertEqual( 'Performing 2 checks for /path/to/eden-mount.\n' 'Performing 2 checks for /path/to/eden-mount-not-watched.\n' 'All is well.\n', out.getvalue()) mock_watchman.assert_has_calls(calls) self.assertEqual(0, exit_code)
def test_eden_not_in_use(self, mock_get_roots_for_nuclide, mock_watchman): instance = FakeEdenInstance(self.make_temporary_directory(), status=fb_status.DEAD) out = TestOutput() dry_run = False exit_code = doctor.cure_what_ails_you( instance, dry_run, FakeMountTable(), fs_util=filesystem.LinuxFsUtil(), process_finder=self.make_process_finder(), out=out, ) self.assertEqual("Eden is not in use.\n", out.getvalue()) self.assertEqual(0, exit_code)
def test_eden_not_in_use(self, mock_get_roots_for_nuclide, mock_watchman): instance = FakeEdenInstance( self.make_temporary_directory(), status=fb_status.DEAD ) out = TestOutput() dry_run = False exit_code = doctor.cure_what_ails_you( instance, dry_run, FakeMountTable(), fs_util=filesystem.LinuxFsUtil(), process_finder=self.make_process_finder(), out=out, ) self.assertEqual("Eden is not in use.\n", out.getvalue()) self.assertEqual(0, exit_code)
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=filesystem.LinuxFsUtil(), process_finder=self.make_process_finder(), out=out, ) v.stdout = out.getvalue() return v
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=filesystem.LinuxFsUtil(), process_finder=self.make_process_finder(), out=out, ) v.stdout = out.getvalue() return v
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=filesystem.LinuxFsUtil(), process_finder=self.make_process_finder(), out=out, ) return exit_code, out.getvalue() finally: if old_pwd is not None: os.environ["PWD"] = old_pwd
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=filesystem.LinuxFsUtil(), process_finder=self.make_process_finder(), out=out, ) return exit_code, out.getvalue() finally: if old_pwd is not None: os.environ["PWD"] = old_pwd
def test_not_all_mounts_have_watchman_watcher(self, mock_get_roots_for_nuclide, mock_watchman): 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( instance, dry_run, mount_table=instance.mount_table, fs_util=filesystem.LinuxFsUtil(), process_finder=self.make_process_finder(), 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)
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(), process_finder=self.make_process_finder(), 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)
def test_not_all_mounts_have_watchman_watcher( self, mock_get_roots_for_nuclide, mock_watchman ): 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( instance, dry_run, mount_table=instance.mount_table, fs_util=filesystem.LinuxFsUtil(), process_finder=self.make_process_finder(), 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)
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=filesystem.LinuxFsUtil(), process_finder=self.make_process_finder(), 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)
def test_end_to_end_test_with_various_scenarios(self, mock_watchman): side_effects: List[Dict[str, Any]] = [] calls = [] tmp_dir = tempfile.mkdtemp(prefix='eden_test.') try: # In edenfs_path1, we will break the snapshot check. edenfs_path1 = os.path.join(tmp_dir, 'path1') # In edenfs_path2, we will break the inotify check and the Nuclide # subscriptions check. edenfs_path2 = os.path.join(tmp_dir, 'path2') calls.append(call(['watch-list'])) side_effects.append({'roots': [edenfs_path1, edenfs_path2]}) 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_subscription=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_subscription=None) ) mock_watchman.side_effect = side_effects out = io.StringIO() dry_run = False mount_paths = OrderedDict() edenfs_path1_snapshot_hex = 'abcd' * 10 mount_paths[edenfs_path1] = { 'bind-mounts': {}, 'mount': edenfs_path1, 'scm_type': 'hg', 'snapshot': edenfs_path1_snapshot_hex, 'client-dir': '/I_DO_NOT_EXIST1' } mount_paths[edenfs_path2] = { 'bind-mounts': {}, 'mount': edenfs_path2, 'scm_type': 'git', 'snapshot': 'dcba' * 10, 'client-dir': '/I_DO_NOT_EXIST2' } config = FakeConfig(mount_paths, is_healthy=True) os.mkdir(edenfs_path1) hg_dir = os.path.join(edenfs_path1, '.hg') os.mkdir(hg_dir) dirstate = os.path.join(hg_dir, 'dirstate') dirstate_hash = b'\x12\x34\x56\x78' * 5 parents = (dirstate_hash, b'\x00' * 20) with open(dirstate, 'wb') as f: eden.dirstate.write(f, parents, tuples_dict={}, copymap={}) exit_code = doctor.cure_what_ails_you(config, dry_run, out) finally: shutil.rmtree(tmp_dir) self.assertEqual( f'''\ Performing 3 checks for {edenfs_path1}. p1 for {edenfs_path1} is {'12345678' * 5}, but Eden's internal hash in its SNAPSHOT file is {edenfs_path1_snapshot_hex}. Performing 2 checks for {edenfs_path2}. Previous Watchman watcher for {edenfs_path2} was "inotify" but is now "eden". Nuclide appears to be used to edit {edenfs_path2}, but a key Watchman subscription appears to be missing. This can cause file changes to fail to show up in Nuclide. Currently, the only workaround this is to run "Nuclide Remote Projects: Kill And Restart" from the command palette in Atom. Number of fixes made: 1. Number of issues that could not be fixed: 2. ''', out.getvalue() ) mock_watchman.assert_has_calls(calls) self.assertEqual(1, exit_code)
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(), process_finder=self.make_process_finder(), 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)
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=filesystem.LinuxFsUtil(), process_finder=self.make_process_finder(), 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)