# HG changeset patch
# User Georges Racinet <georges.racinet@octobus.net>
# Date 1587406653 -7200
#      Mon Apr 20 20:17:33 2020 +0200
# Node ID 53fdbb7ab32802b108552f0e6016d2c6b928838a
# Parent  8cca59bd3923510228a5f53741e90593f36e2a5c
GitLab hooks: handling connection errors

The returned message is very generic, but the exact cause will
be ovious in the logs. Most immediate case is misconfiguration.

diff --git a/heptapod/gitlab/__init__.py b/heptapod/gitlab/__init__.py
--- a/heptapod/gitlab/__init__.py
+++ b/heptapod/gitlab/__init__.py
@@ -8,6 +8,7 @@
 import os
 import re
 import requests
+from requests.exceptions import RequestException
 import requests_unixsocket
 
 logger = logging.getLogger(__name__)
@@ -220,9 +221,14 @@
     def post_receive(self, changes, env=None):
         """Call GitLab internal API post-receive endpoint."""
         params = self.post_receive_params(changes, env=env)
-        resp = self.gitlab_internal_api_request('POST',
-                                                subpath='post_receive',
-                                                params=params)
+        try:
+            resp = self.gitlab_internal_api_request('POST',
+                                                    subpath='post_receive',
+                                                    params=params)
+        except RequestException:
+            logger.exception("GitLab internal API is unreachable")
+            return False, '', "GitLab is unreachable"
+
         ok = resp.status_code == 200
         as_json = resp.json()
         logger.debug("post_receive for changes %r, response: %r",
@@ -263,9 +269,14 @@
         """Call GitLab internal API 'allowed' endpoint used for pre-receive
         """
         params = self.pre_receive_params(changes, env=env)
-        resp = self.gitlab_internal_api_request('POST',
-                                                subpath='allowed',
-                                                params=params)
+        try:
+            resp = self.gitlab_internal_api_request('POST',
+                                                    subpath='allowed',
+                                                    params=params)
+        except RequestException:
+            logger.exception("GitLab internal API is unreachable")
+            return False, '', "GitLab is unreachable"
+
         if resp.status_code not in ALLOWED_API_KNOWN_STATUS_CODES:
             return False, '', "API is not accessible"
 
diff --git a/heptapod/gitlab/tests/test_hooks.py b/heptapod/gitlab/tests/test_hooks.py
--- a/heptapod/gitlab/tests/test_hooks.py
+++ b/heptapod/gitlab/tests/test_hooks.py
@@ -150,7 +150,10 @@
 def request_recorder(records, responses):
     def request(hook, meth, subpath, params, **kwargs):
         records.append((meth, subpath, params, kwargs))
-        return responses.pop(0)
+        resp = responses.pop(0)
+        if isinstance(resp, Exception):
+            raise resp
+        return resp
 
     return request
 
@@ -262,7 +265,7 @@
 
 def test_integration_post_receive(tmpdir, monkeypatch):
     records = []
-    resp = make_json_response(
+    responses = [make_json_response(
         {u'broadcast_message': None,
          u'reference_counter_decreased': True,
          u'merge_request_urls': [
@@ -270,8 +273,10 @@
               'test_project_1583330760_9216309/merge_requests/1',
               u'branch_name': u'topic/default/antelope',
               u'new_merge_request': False}
-         ]})
-    responses = [resp]
+         ]}),
+                 requests.exceptions.Timeout("1 ns is too much ;-)"),
+                 ]
+
     monkeypatch.setattr(Hook, 'gitlab_internal_api_request',
                         request_recorder(records, responses))
 
@@ -297,6 +302,10 @@
         'http://localhost:3000/root/test_project_1583330760_9216309/'
         'merge_requests/1']
 
+    return_code, out, err = hook(changes)
+    assert return_code == 1
+    assert err == 'GitLab is unreachable'
+
 
 def test_integration_pre_receive(tmpdir, monkeypatch):
     records = []
@@ -311,6 +320,7 @@
                                      },
                                     status_code=401),
                  make_response(504, b"Bad gateway :-("),
+                 requests.exceptions.ConnectionError("Failed"),
                  ]
     monkeypatch.setattr(Hook, 'gitlab_internal_api_request',
                         request_recorder(records, responses))
@@ -345,6 +355,10 @@
     assert return_code == 1
     assert err == 'API is not accessible'
 
+    return_code, out, err = hook(changes)
+    assert return_code == 1
+    assert err == 'GitLab is unreachable'
+
 
 def test_empty_changes(tmpdir):
     hook = Hook('post-receive', make_repo(tmpdir, 'repo.hg').repo)