# HG changeset patch
# User Georges Racinet <georges.racinet@octobus.net>
# Date 1602261857 -7200
#      Fri Oct 09 18:44:17 2020 +0200
# Node ID 96517c9560f90b1413d7113de5e9aaa6b7417962
# Parent  5622b6e121d90ff5f27c5a5955b0daabe4d36b04
RepositoryService: proper error responses

This standard way to return errors to the client is by means
of `context.set_code()` and `set_details()`. Some Python
exceptions are automatically converted into errors, but
with potential loss of information.

The new test brings the coverage of repository_service to 100%

diff --git a/hgitaly/service/repository_service.py b/hgitaly/service/repository_service.py
--- a/hgitaly/service/repository_service.py
+++ b/hgitaly/service/repository_service.py
@@ -4,6 +4,7 @@
 # GNU General Public License version 2 or any later version.
 #
 # SPDX-License-Identifier: GPL-2.0-or-later
+from grpc import StatusCode
 import logging
 from mercurial import (
     error,
@@ -59,14 +60,19 @@
             request: WriteRefRequest,
             context) -> WriteRefResponse:
         if request.ref != b'HEAD':
-            raise NotImplementedError(
+            context.set_code(StatusCode.INVALID_ARGUMENT)
+            context.set_details(
                 "Moving a GitLab branch is not implemented in Mercurial "
                 "and would at most make sense for bookmarks.")
+            return WriteRefResponse()
 
         target = git_branch_from_ref(request.revision)
         if target is None:
-            raise ValueError("The default GitLab branch can only be set "
-                             "to a branch ref, got %r" % request.revision)
+            context.set_code(StatusCode.INVALID_ARGUMENT)
+            context.set_details(
+                "The default GitLab branch can only be set "
+                "to a branch ref, got %r" % request.revision)
+            return WriteRefResponse()
 
         repo = self.load_repo(request.repository)
         # TODO that part and the constant should go to hgext3rd.heptapod, since
diff --git a/hgitaly/service/tests/test_repository_service.py b/hgitaly/service/tests/test_repository_service.py
--- a/hgitaly/service/tests/test_repository_service.py
+++ b/hgitaly/service/tests/test_repository_service.py
@@ -4,13 +4,16 @@
 # GNU General Public License version 2 or any later version.
 #
 # SPDX-License-Identifier: GPL-2.0-or-later
+import grpc
 import shutil
+import pytest
 
 from hgitaly.tests.common import make_empty_repo
 
 from hgitaly.stub.repository_service_pb2 import (
     HasLocalBranchesRequest,
     RepositoryExistsRequest,
+    WriteRefRequest,
 )
 from hgitaly.stub.repository_service_pb2_grpc import RepositoryServiceStub
 
@@ -50,3 +53,22 @@
                     close_branch=True)
 
     assert not has_local_branches()
+
+
+def test_write_ref(grpc_channel, server_repos_root):
+    repo_stub = RepositoryServiceStub(grpc_channel)
+    wrapper, grpc_repo = make_empty_repo(server_repos_root)
+
+    with pytest.raises(grpc.RpcError) as exc_info:
+        repo_stub.WriteRef(WriteRefRequest(
+            repository=grpc_repo,
+            ref=b'refs/heads/something',
+            revision=b'dead01234cafe'))
+    assert exc_info.value.code() == grpc.StatusCode.INVALID_ARGUMENT
+
+    with pytest.raises(grpc.RpcError) as exc_info:
+        repo_stub.WriteRef(WriteRefRequest(
+            repository=grpc_repo,
+            ref=b'HEAD',
+            revision=b'topic/default/wont-last'))
+    assert exc_info.value.code() == grpc.StatusCode.INVALID_ARGUMENT