Skip to content
Snippets Groups Projects
Commit f7c06a89 authored by Georges Racinet's avatar Georges Racinet
Browse files

RepositoryService.CreateRepository: error if path already taken

In version 14.6, Gitaly makes it an error to attempt to create
a repository if anything already exists at the target path
(even broken symlinks).

This is worth a minor version change.

This deprives us of the way we were triggering actual
repository creation errors in tests.
To maintain coverage, we're now using the broken symlink
trick one step higher in the file hierarchy: on the storage itself.
Playing with permissions would not work in CI.
parent 46369243
No related branches found
No related tags found
1 merge request!93Matching Gitaly 14.6
0.20.1dev0
0.21.1dev0
......@@ -90,8 +90,7 @@
return response_cls()
def already_exists(context, response_cls, message,
log_level=logging.WARN): # pragma no cover
def already_exists(context, response_cls, message, log_level=logging.WARN):
"""Return grpc UNKNOWN code with message.
Similar to :func:`not_found`, except for the default ``log_level``
......
......@@ -13,7 +13,6 @@
archival,
scmutil,
hg,
vfs as vfsmod,
)
from heptapod.gitlab.branch import gitlab_branch_from_ref
......@@ -25,6 +24,7 @@
)
from ..errors import (
already_exists,
internal_error,
invalid_argument,
not_found,
......@@ -276,4 +276,8 @@
)
return invalid_argument(context, CreateRepositoryResponse,
message=msg)
if os.path.lexists(repo_path):
return already_exists(context, CreateRepositoryResponse,
message="A file or directory "
"exists already at %r" % repo_path)
try:
......@@ -279,12 +283,4 @@
try:
# check if already an Hg repository (logic similar to upstream Hg)
wdir_vfs = vfsmod.vfs(repo_path, expandpath=True, realpath=True)
hgvfs = vfsmod.vfs(wdir_vfs.join(b'.hg'))
if hgvfs.exists():
# To match with Gitaly/Git behavior, if repository already
# initialized we should not return any error
# (although `hg init` would throw an error)
return CreateRepositoryResponse()
hg.peer(self.ui, opts={}, path=repo_path, create=True)
except Exception as exc:
msg = (
......
......@@ -334,9 +334,12 @@
wrapper = LocalRepoWrapper(hg.repository(ui, pathb), path)
assert wrapper.repo.path.endswith(b'default/sample_repo/.hg')
# To follow along with Gitaly, attempt to create existing repo
# shouldn't respond with any error
do_rpc(rel_path)
# As of Gitaly 14.6, attempt to create existing repo is an error.
with pytest.raises(grpc.RpcError) as exc_info:
do_rpc(rel_path)
assert exc_info.value.code() == grpc.StatusCode.ALREADY_EXISTS
assert 'exists already' in exc_info.value.details()
# when storage name doesn't exists
with pytest.raises(grpc.RpcError) as exc_info:
......@@ -345,8 +348,10 @@
assert 'no such storage' in exc_info.value.details()
# test with a broken symlink (which points to itself)
# This used to be a way to test failure in `hg init`, now should be
# refused as already existing path (see Gitaly Comparison tests)
brepo_name = "myrepo_a_broken_symlink"
path = (server_repos_root / default_storage / brepo_name)
path.symlink_to(path)
with pytest.raises(grpc.RpcError) as exc_info:
do_rpc(brepo_name)
......@@ -348,10 +353,24 @@
brepo_name = "myrepo_a_broken_symlink"
path = (server_repos_root / default_storage / brepo_name)
path.symlink_to(path)
with pytest.raises(grpc.RpcError) as exc_info:
do_rpc(brepo_name)
assert exc_info.value.code() == grpc.StatusCode.INTERNAL
assert 'Too many levels of symbolic links' in exc_info.value.details()
assert exc_info.value.code() == grpc.StatusCode.ALREADY_EXISTS
assert 'exists already' in exc_info.value.details()
# using a broken symlink for the whole storage directory
# to pass the check for existing repo and still fail in `hg init`
rel_path = 'creation_error'
storage_path = server_repos_root / default_storage
try:
shutil.rmtree(storage_path)
storage_path.symlink_to(storage_path)
with pytest.raises(grpc.RpcError) as exc_info:
do_rpc(rel_path)
assert exc_info.value.code() == grpc.StatusCode.INTERNAL
finally:
storage_path.unlink()
storage_path.mkdir(exist_ok=True)
def test_set_full_path(grpc_channel, server_repos_root):
......
......@@ -116,4 +116,6 @@
response = repo_stubs[vcs].CreateRepository(request)
return response
hg_rel_path = rel_path + '.hg'
git_rel_path = rel_path + '.git'
# actual test
......@@ -119,5 +121,12 @@
# actual test
assert do_rpc('hg', rel_path) == do_rpc('git', rel_path)
assert do_rpc('hg', hg_rel_path) == do_rpc('git', git_rel_path)
# when repo already exists (actually its directory)
with pytest.raises(grpc.RpcError) as exc_info_git:
do_rpc('git', git_rel_path)
with pytest.raises(grpc.RpcError) as exc_info_hg:
do_rpc('hg', hg_rel_path)
assert exc_info_hg.value.code() == exc_info_git.value.code()
# when storage name is invalid
with pytest.raises(grpc.RpcError) as exc_info_hg:
......@@ -129,6 +138,12 @@
assert 'no such storage' in exc_info_git.value.details()
# test with a broken symlink (which points to itself)
# it used to be an error for both, with Gitaly complaining
# that the file exists (but would not raise an error for
# an existing proper Git repo). As of 14.6, Gitaly refuses
# all existing files, including broken symlinks
# As a consequence of the added early check, we don't have
# any case of `hg init` itself failing on hand.
repo_name = "myrepo_a_broken_symlink"
path = (server_repos_root / default_storage / repo_name)
path.symlink_to(path)
......@@ -136,9 +151,10 @@
do_rpc('hg', repo_name)
with pytest.raises(grpc.RpcError) as exc_info_git:
do_rpc('git', repo_name)
assert exc_info_hg.value.code() == exc_info_git.value.code()
assert 'Too many levels of symbolic links' in exc_info_hg.value.details()
assert 'file exists' in exc_info_git.value.details()
exc_hg, exc_git = exc_info_hg.value, exc_info_git.value
assert exc_hg.code() == exc_git.code()
for exc in (exc_hg, exc_git):
assert 'exists already' in exc.details()
def test_set_full_path(gitaly_comparison, server_repos_root):
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment