diff --git a/hgitaly/service/repository.py b/hgitaly/service/repository.py index 49074aa6e1f7be9d31af1e314da1c585a64a76ea_aGdpdGFseS9zZXJ2aWNlL3JlcG9zaXRvcnkucHk=..b95ba87a8464d59b4d80df72b35ff7c2abd60ac7_aGdpdGFseS9zZXJ2aWNlL3JlcG9zaXRvcnkucHk= 100644 --- a/hgitaly/service/repository.py +++ b/hgitaly/service/repository.py @@ -94,6 +94,8 @@ FullPathResponse, GetRawChangesRequest, GetRawChangesResponse, + GetCustomHooksRequest, + GetCustomHooksResponse, RepositoryExistsRequest, RepositoryExistsResponse, GetArchiveRequest, @@ -108,6 +110,8 @@ SearchFilesByContentResponse, SearchFilesByNameRequest, SearchFilesByNameResponse, + SetCustomHooksRequest, + SetCustomHooksResponse, SetFullPathRequest, SetFullPathResponse, WriteRefRequest, @@ -378,8 +382,7 @@ context) -> SearchFilesByContentResponse: not_implemented(context, issue=80) # pragma no cover - def RestoreCustomHooks(self, request: RestoreCustomHooksRequest, - context) -> RestoreCustomHooksResponse: + def set_custom_hooks(self, request, context): def load_repo(req, context): return self.load_repo(req.repository, context) @@ -383,4 +386,18 @@ def load_repo(req, context): return self.load_repo(req.repository, context) + with streaming_request_tempfile_extract( + request, context, + first_request_handler=load_repo + ) as (repo, tmpf): + tmpf.flush() + try: + restore_additional(repo.ui, repo, + tmpf.name.encode('ascii')) + except Exception as exc: + context.abort(StatusCode.INTERNAL, + "Error in tarball application: %r" % exc) + + def RestoreCustomHooks(self, request: RestoreCustomHooksRequest, + context) -> RestoreCustomHooksResponse: try: @@ -386,15 +403,5 @@ try: - with streaming_request_tempfile_extract( - request, context, - first_request_handler=load_repo - ) as (repo, tmpf): - tmpf.flush() - try: - restore_additional(repo.ui, repo, - tmpf.name.encode('ascii')) - except Exception as exc: - context.abort(StatusCode.INTERNAL, - "Error in tarball application: %r" % exc) + self.set_custom_hooks(request, context) finally: return RestoreCustomHooksResponse() @@ -398,8 +405,14 @@ finally: return RestoreCustomHooksResponse() - def BackupCustomHooks(self, request: BackupCustomHooksRequest, - context) -> BackupCustomHooksResponse: + def SetCustomHooks(self, request: SetCustomHooksRequest, + context) -> SetCustomHooksResponse: + try: + self.set_custom_hooks(request, context) + finally: + return SetCustomHooksResponse() + + def get_custom_hooks(self, request, context, resp_cls): repo = self.load_repo(request.repository, context) with tempfile.NamedTemporaryFile( mode='wb+', @@ -414,7 +427,17 @@ data = tmpf.read(WRITE_BUFFER_SIZE) if not data: break - yield BackupCustomHooksResponse(data=data) + yield resp_cls(data=data) + + def BackupCustomHooks(self, request: BackupCustomHooksRequest, + context) -> BackupCustomHooksResponse: + yield from self.get_custom_hooks( + request, context, BackupCustomHooksResponse) + + def GetCustomHooks(self, request: GetCustomHooksRequest, + context) -> GetCustomHooksResponse: + yield from self.get_custom_hooks( + request, context, GetCustomHooksResponse) def RemoveRepository(self, request: RemoveRepositoryRequest, context) -> RemoveRepositoryResponse: diff --git a/hgitaly/service/tests/test_repository_service.py b/hgitaly/service/tests/test_repository_service.py index 49074aa6e1f7be9d31af1e314da1c585a64a76ea_aGdpdGFseS9zZXJ2aWNlL3Rlc3RzL3Rlc3RfcmVwb3NpdG9yeV9zZXJ2aWNlLnB5..b95ba87a8464d59b4d80df72b35ff7c2abd60ac7_aGdpdGFseS9zZXJ2aWNlL3Rlc3RzL3Rlc3RfcmVwb3NpdG9yeV9zZXJ2aWNlLnB5 100644 --- a/hgitaly/service/tests/test_repository_service.py +++ b/hgitaly/service/tests/test_repository_service.py @@ -45,9 +45,10 @@ FindMergeBaseRequest, FullPathRequest, GetArchiveRequest, + GetCustomHooksRequest, HasLocalBranchesRequest, RemoveRepositoryRequest, RepositoryExistsRequest, RestoreCustomHooksRequest, SearchFilesByNameRequest, SetFullPathRequest, @@ -48,9 +49,10 @@ HasLocalBranchesRequest, RemoveRepositoryRequest, RepositoryExistsRequest, RestoreCustomHooksRequest, SearchFilesByNameRequest, SetFullPathRequest, + SetCustomHooksRequest, WriteRefRequest, ) from hgitaly.stub.repository_pb2_grpc import RepositoryServiceStub @@ -61,6 +63,8 @@ ) from .fixture import ServiceFixture +parametrize = pytest.mark.parametrize + @attr.s class RepositoryFixture(ServiceFixture): @@ -137,9 +141,21 @@ for chunk in stream.slice_binary_file(tarball_path, nb_chunks) ) + def set_custom_hooks(self, tarball_path, + grpc_repo=None, + nb_chunks=2, + **kw): + if grpc_repo is None: + grpc_repo = self.grpc_repo + + return self.stub.SetCustomHooks( + SetCustomHooksRequest(repository=grpc_repo, data=chunk) + for chunk in stream.slice_binary_file(tarball_path, nb_chunks) + ) + def backup_custom_hooks(self, save_path): with open(save_path, 'wb') as fobj: for chunk in self.stub.BackupCustomHooks(BackupCustomHooksRequest( repository=self.grpc_repo)): fobj.write(chunk.data) @@ -140,9 +156,15 @@ def backup_custom_hooks(self, save_path): with open(save_path, 'wb') as fobj: for chunk in self.stub.BackupCustomHooks(BackupCustomHooksRequest( repository=self.grpc_repo)): fobj.write(chunk.data) + def get_custom_hooks(self, save_path): + with open(save_path, 'wb') as fobj: + for chunk in self.stub.GetCustomHooks(GetCustomHooksRequest( + repository=self.grpc_repo)): + fobj.write(chunk.data) + def remove_repository(self, grpc_repo=None): if grpc_repo is None: grpc_repo = self.grpc_repo @@ -581,7 +603,8 @@ assert search(ref=b'unknown', query='.') == [] -def test_restore_custom_hooks(fixture_with_repo, tmpdir): +@parametrize('rpc_name', ['restore', 'set']) +def test_set_custom_hooks(fixture_with_repo, tmpdir, rpc_name): fixture = fixture_with_repo wrapper = fixture.repo_wrapper @@ -585,6 +608,11 @@ fixture = fixture_with_repo wrapper = fixture.repo_wrapper + if rpc_name == 'restore': + meth = fixture.restore_custom_hooks + else: + meth = fixture.set_custom_hooks + # this is a valid tar file with the minimal `hgrc` used in these tests # the underlying restoration function from py-heptapod is itself tested, # and Heptapod backup tests will further exercise this. @@ -593,7 +621,7 @@ hgrc_path = wrapper.path / '.hg/hgrc' os.unlink(hgrc_path) - fixture.restore_custom_hooks(tarball_path) + meth(tarball_path) assert hgrc_path.read_text() # TODO test unknown storage and repo @@ -603,7 +631,7 @@ invalid_tarball_path = tmpdir / 'invalid.tgz' invalid_tarball_path.write("something else") with pytest.raises(grpc.RpcError) as exc_info: - fixture.restore_custom_hooks(invalid_tarball_path) + meth(invalid_tarball_path) assert exc_info.value.code() == grpc.StatusCode.INTERNAL @@ -607,5 +635,6 @@ assert exc_info.value.code() == grpc.StatusCode.INTERNAL -def test_backup_custom_hooks(fixture_with_repo, tmpdir): +@parametrize('rpc_name', ['backup', 'get']) +def test_backup_custom_hooks(fixture_with_repo, tmpdir, rpc_name): fixture = fixture_with_repo @@ -611,3 +640,7 @@ fixture = fixture_with_repo + if rpc_name == 'restore': + meth = fixture.backup_custom_hooks + else: + meth = fixture.get_custom_hooks tarball_path = tmpdir / 'hg_aditional.tgz' @@ -612,6 +645,7 @@ tarball_path = tmpdir / 'hg_aditional.tgz' - fixture.backup_custom_hooks(tarball_path) + meth(tarball_path) + assert tarball_path.exists() def test_remove_repository(fixture_with_repo):