def test_symlinks_are_by_default_an_error(tmp_dir_path): """By default symlinks should be treated as an error""" file_path = tmp_dir_path / "file" file_path.touch() link_path = tmp_dir_path / "link" link_path.symlink_to(file_path) result, errors = mtimes.find_mtimes(tmp_dir_path) assert result == {file_path: tests.IsA(int)} assert errors == {link_path: tests.IsA(mtimes.FindError)}
def test_nonexistent_dir_is_an_error(tmp_dir_path): missing_path = tmp_dir_path / "does-not-exist" result, errors = mtimes.find_mtimes(missing_path) assert result == {} assert errors == {missing_path: tests.IsA(mtimes.FindError)}
def test_missing_permission_to_directory(self): """Missing permissions to a directory is an error""" directory = self.mkdir('no-permission') os.chmod(directory, 0) result, errors = path.find_mtimes(self.tmpdir) self.assertEqual({}, result) self.assertEqual({directory: tests.IsA(exceptions.FindError)}, errors)
def test_symlink_pointing_at_itself_fails(self): """Symlink pointing at itself should give as an OS error""" link = os.path.join(self.tmpdir, 'link') os.symlink(link, link) result, errors = path.find_mtimes(link, follow=True) self.assertEqual({}, result) self.assertEqual({link: tests.IsA(exceptions.FindError)}, errors)
def test_symlink_pointing_at_parent_fails(self): """We should detect a loop via the parent and give up on the branch""" os.symlink(self.tmpdir, os.path.join(self.tmpdir, 'link')) result, errors = path.find_mtimes(self.tmpdir, follow=True) self.assertEqual({}, result) self.assertEqual(1, len(errors)) self.assertEqual(tests.IsA(Exception), errors.values()[0])
def test_symlink_pointing_at_itself_fails(tmp_dir_path): link_path = tmp_dir_path / "link" link_path.symlink_to(link_path) result, errors = mtimes.find_mtimes(tmp_dir_path, follow=True) assert result == {} assert errors == {link_path: tests.IsA(mtimes.FindError)}
def test_file_as_the_root_just_returns_the_file(tmp_dir_path): file_path = tmp_dir_path / "single" file_path.touch() result, errors = mtimes.find_mtimes(file_path) assert result == {file_path: tests.IsA(int)} assert errors == {}
def test_symlink_branches_are_not_excluded(tmp_dir_path): """Using symlinks to make a file show up multiple times should work""" file_path = tmp_dir_path / "dir" / "file" file_path.parent.mkdir() file_path.touch() link1_path = tmp_dir_path / "link1" link1_path.symlink_to(file_path) link2_path = tmp_dir_path / "link2" link2_path.symlink_to(file_path) result, errors = mtimes.find_mtimes(tmp_dir_path, follow=True) assert result == { file_path: tests.IsA(int), link1_path: tests.IsA(int), link2_path: tests.IsA(int), } assert errors == {}
def test_symlinks_are_ignored(self): """By default symlinks should be treated as an error""" target = self.touch('target') link = os.path.join(self.tmpdir, 'link') os.symlink(target, link) result, errors = path.find_mtimes(self.tmpdir) self.assertEqual(result, {target: tests.any_int}) self.assertEqual(errors, {link: tests.IsA(exceptions.FindError)})
def test_missing_permission_to_directory_is_an_error(tmp_dir_path): dir_path = tmp_dir_path / "dir" dir_path.mkdir(mode=0o000) result, errors = mtimes.find_mtimes(tmp_dir_path) assert result == {} assert errors == {dir_path: tests.IsA(mtimes.FindError)} dir_path.chmod(0o755)
def test_symlink_pointing_at_parent_fails(tmp_dir_path): """We should detect a loop via the parent and give up on the branch""" link_path = tmp_dir_path / "link" link_path.symlink_to(tmp_dir_path, target_is_directory=True) result, errors = mtimes.find_mtimes(tmp_dir_path, follow=True) assert result == {} assert errors == {link_path: tests.IsA(Exception)}
def test_with_follow_symlink_to_file_as_root_is_followed(tmp_dir_path): file_path = tmp_dir_path / "file" file_path.touch() link_path = tmp_dir_path / "link" link_path.symlink_to(file_path) result, errors = mtimes.find_mtimes(link_path, follow=True) assert result == {file_path: tests.IsA(int)} assert errors == {}
def test_missing_permission_to_file_is_not_an_error(tmp_dir_path): """Missing permissions to a file is not a search error""" file_path = tmp_dir_path / "file" file_path.touch(mode=0o000) result, errors = mtimes.find_mtimes(tmp_dir_path) assert result == {file_path: tests.IsA(int)} assert errors == {} file_path.chmod(0o644)
def test_nested_directories(tmp_dir_path): # Setup foo/bar and baz directories foo_path = tmp_dir_path / "foo" / "file" foo_path.parent.mkdir() foo_path.touch() foo_bar_path = tmp_dir_path / "foo" / "bar" / "filee" foo_bar_path.parent.mkdir() foo_bar_path.touch() baz_path = tmp_dir_path / "baz" / "file" baz_path.parent.mkdir() baz_path.touch() result, errors = mtimes.find_mtimes(tmp_dir_path) assert result == { foo_path: tests.IsA(int), foo_bar_path: tests.IsA(int), baz_path: tests.IsA(int), } assert errors == {}
def test_indirect_symlink_loop(tmp_dir_path): """More indirect loops should also be detected""" # Setup tmpdir/directory/loop where loop points to tmpdir link_path = tmp_dir_path / "dir" / "link" link_path.parent.mkdir() link_path.symlink_to(tmp_dir_path, target_is_directory=True) result, errors = mtimes.find_mtimes(tmp_dir_path, follow=True) assert result == {} assert errors == {link_path: tests.IsA(Exception)}
def test_symlink_to_directory_is_followed(tmp_dir_path): file_path = tmp_dir_path / "dir" / "file" file_path.parent.mkdir() file_path.touch() link_path = tmp_dir_path / "link" link_path.symlink_to(file_path.parent, target_is_directory=True) result, errors = mtimes.find_mtimes(link_path, follow=True) assert result == {file_path: tests.IsA(int)} assert errors == {}
def test_indirect_symlink_loop(self): """More indirect loops should also be detected""" # Setup tmpdir/directory/loop where loop points to tmpdir directory = os.path.join(self.tmpdir, b'directory') loop = os.path.join(directory, b'loop') os.mkdir(directory) os.symlink(self.tmpdir, loop) result, errors = path.find_mtimes(self.tmpdir, follow=True) self.assertEqual({}, result) self.assertEqual({loop: tests.IsA(Exception)}, errors)
def test_missing_permission_to_directory_is_an_error(tmp_dir_path): dir_path = tmp_dir_path / "dir" dir_path.mkdir(mode=0o000) result, errors = mtimes.find_mtimes(tmp_dir_path) if os.getuid() == 0: # Test is run as root, nothing is off limits. assert errors == {} else: assert result == {} assert errors == {dir_path: tests.IsA(mtimes.FindError)} dir_path.chmod(0o755)
def test_names_are_bytestrings(self): """We shouldn't be mixing in unicode for paths.""" result, errors = path.find_mtimes(tests.path_to_data_dir('')) for name in result.keys() + errors.keys(): self.assertEqual(name, tests.IsA(bytes))
def test_nonexistent_dir(self): """Non existent search roots are an error""" missing = os.path.join(self.tmpdir, 'does-not-exist') result, errors = path.find_mtimes(missing) self.assertEqual(result, {}) self.assertEqual(errors, {missing: tests.IsA(exceptions.FindError)})