summaryrefslogtreecommitdiff
path: root/tests/unit
diff options
context:
space:
mode:
authorKarun Japhet <karun@japhet.in>2021-08-28 11:41:59 +0530
committerKarun Japhet <karun@japhet.in>2021-08-29 15:01:18 +0530
commit3b1d3a41da7e7228f3a465d06902db8af564153e (patch)
treee16d5e53efb182475c96a32ac1f2686a43ee9c19 /tests/unit
parenta00ec87bdbadccaf3e3700a48cbb797fd2750107 (diff)
downloadgitlab-3b1d3a41da7e7228f3a465d06902db8af564153e.tar.gz
feat: allow global retry_transient_errors setup
`retry_transient_errors` can now be set through the Gitlab instance and global configuration Documentation for API usage has been updated and missing tests have been added.
Diffstat (limited to 'tests/unit')
-rw-r--r--tests/unit/conftest.py15
-rw-r--r--tests/unit/test_config.py70
-rw-r--r--tests/unit/test_gitlab_http_methods.py95
3 files changed, 173 insertions, 7 deletions
diff --git a/tests/unit/conftest.py b/tests/unit/conftest.py
index 64df051..f58c77a 100644
--- a/tests/unit/conftest.py
+++ b/tests/unit/conftest.py
@@ -9,7 +9,18 @@ def gl():
"http://localhost",
private_token="private_token",
ssl_verify=True,
- api_version=4,
+ api_version="4",
+ )
+
+
+@pytest.fixture
+def gl_retry():
+ return gitlab.Gitlab(
+ "http://localhost",
+ private_token="private_token",
+ ssl_verify=True,
+ api_version="4",
+ retry_transient_errors=True,
)
@@ -17,7 +28,7 @@ def gl():
@pytest.fixture
def gl_trailing():
return gitlab.Gitlab(
- "http://localhost/", private_token="private_token", api_version=4
+ "http://localhost/", private_token="private_token", api_version="4"
)
diff --git a/tests/unit/test_config.py b/tests/unit/test_config.py
index cd61b8d..a62106b 100644
--- a/tests/unit/test_config.py
+++ b/tests/unit/test_config.py
@@ -86,6 +86,31 @@ per_page = 200
"""
+def global_retry_transient_errors(value: bool) -> str:
+ return u"""[global]
+default = one
+retry_transient_errors={}
+[one]
+url = http://one.url
+private_token = ABCDEF""".format(
+ value
+ )
+
+
+def global_and_gitlab_retry_transient_errors(
+ global_value: bool, gitlab_value: bool
+) -> str:
+ return u"""[global]
+ default = one
+ retry_transient_errors={global_value}
+ [one]
+ url = http://one.url
+ private_token = ABCDEF
+ retry_transient_errors={gitlab_value}""".format(
+ global_value=global_value, gitlab_value=gitlab_value
+ )
+
+
@mock.patch.dict(os.environ, {"PYTHON_GITLAB_CFG": "/some/path"})
def test_env_config_present():
assert ["/some/path"] == config._env_config()
@@ -245,3 +270,48 @@ def test_config_user_agent(m_open, path_exists, config_string, expected_agent):
cp = config.GitlabConfigParser()
assert cp.user_agent == expected_agent
+
+
+@mock.patch("os.path.exists")
+@mock.patch("builtins.open")
+@pytest.mark.parametrize(
+ "config_string,expected",
+ [
+ pytest.param(valid_config, False, id="default_value"),
+ pytest.param(
+ global_retry_transient_errors(True), True, id="global_config_true"
+ ),
+ pytest.param(
+ global_retry_transient_errors(False), False, id="global_config_false"
+ ),
+ pytest.param(
+ global_and_gitlab_retry_transient_errors(False, True),
+ True,
+ id="gitlab_overrides_global_true",
+ ),
+ pytest.param(
+ global_and_gitlab_retry_transient_errors(True, False),
+ False,
+ id="gitlab_overrides_global_false",
+ ),
+ pytest.param(
+ global_and_gitlab_retry_transient_errors(True, True),
+ True,
+ id="gitlab_equals_global_true",
+ ),
+ pytest.param(
+ global_and_gitlab_retry_transient_errors(False, False),
+ False,
+ id="gitlab_equals_global_false",
+ ),
+ ],
+)
+def test_config_retry_transient_errors_when_global_config_is_set(
+ m_open, path_exists, config_string, expected
+):
+ fd = io.StringIO(config_string)
+ fd.close = mock.Mock(return_value=None)
+ m_open.return_value = fd
+
+ cp = config.GitlabConfigParser()
+ assert cp.retry_transient_errors == expected
diff --git a/tests/unit/test_gitlab_http_methods.py b/tests/unit/test_gitlab_http_methods.py
index f1bc9cd..5a3584e 100644
--- a/tests/unit/test_gitlab_http_methods.py
+++ b/tests/unit/test_gitlab_http_methods.py
@@ -30,7 +30,7 @@ def test_http_request(gl):
def test_http_request_404(gl):
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/not_there", method="get")
def resp_cont(url, request):
- content = {"Here is wh it failed"}
+ content = {"Here is why it failed"}
return response(404, content, {}, None, 5, request)
with HTTMock(resp_cont):
@@ -38,6 +38,91 @@ def test_http_request_404(gl):
gl.http_request("get", "/not_there")
+@pytest.mark.parametrize("status_code", [500, 502, 503, 504])
+def test_http_request_with_only_failures(gl, status_code):
+ call_count = 0
+
+ @urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects", method="get")
+ def resp_cont(url, request):
+ nonlocal call_count
+ call_count += 1
+ return response(status_code, {"Here is why it failed"}, {}, None, 5, request)
+
+ with HTTMock(resp_cont):
+ with pytest.raises(GitlabHttpError):
+ gl.http_request("get", "/projects")
+
+ assert call_count == 1
+
+
+def test_http_request_with_retry_on_method_for_transient_failures(gl):
+ call_count = 0
+ calls_before_success = 3
+
+ @urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects", method="get")
+ def resp_cont(url, request):
+ nonlocal call_count
+ call_count += 1
+ status_code = 200 if call_count == calls_before_success else 500
+ return response(
+ status_code,
+ {"Failure is the stepping stone to success"},
+ {},
+ None,
+ 5,
+ request,
+ )
+
+ with HTTMock(resp_cont):
+ http_r = gl.http_request("get", "/projects", retry_transient_errors=True)
+
+ assert http_r.status_code == 200
+ assert call_count == calls_before_success
+
+
+def test_http_request_with_retry_on_class_for_transient_failures(gl_retry):
+ call_count = 0
+ calls_before_success = 3
+
+ @urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects", method="get")
+ def resp_cont(url, request):
+ nonlocal call_count
+ call_count += 1
+ status_code = 200 if call_count == calls_before_success else 500
+ return response(
+ status_code,
+ {"Failure is the stepping stone to success"},
+ {},
+ None,
+ 5,
+ request,
+ )
+
+ with HTTMock(resp_cont):
+ http_r = gl_retry.http_request("get", "/projects")
+
+ assert http_r.status_code == 200
+ assert call_count == calls_before_success
+
+
+def test_http_request_with_retry_on_class_and_method_for_transient_failures(gl_retry):
+ call_count = 0
+ calls_before_success = 3
+
+ @urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects", method="get")
+ def resp_cont(url, request):
+ nonlocal call_count
+ call_count += 1
+ status_code = 200 if call_count == calls_before_success else 500
+ return response(status_code, {"Here is why it failed"}, {}, None, 5, request)
+
+ with HTTMock(resp_cont):
+ with pytest.raises(GitlabHttpError):
+ gl_retry.http_request("get", "/projects", retry_transient_errors=False)
+
+ assert call_count == 1
+
+
def test_get_request(gl):
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects", method="get")
def resp_cont(url, request):
@@ -66,7 +151,7 @@ def test_get_request_raw(gl):
def test_get_request_404(gl):
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/not_there", method="get")
def resp_cont(url, request):
- content = {"Here is wh it failed"}
+ content = {"Here is why it failed"}
return response(404, content, {}, None, 5, request)
with HTTMock(resp_cont):
@@ -150,7 +235,7 @@ def test_post_request_404(gl):
scheme="http", netloc="localhost", path="/api/v4/not_there", method="post"
)
def resp_cont(url, request):
- content = {"Here is wh it failed"}
+ content = {"Here is why it failed"}
return response(404, content, {}, None, 5, request)
with HTTMock(resp_cont):
@@ -186,7 +271,7 @@ def test_put_request(gl):
def test_put_request_404(gl):
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/not_there", method="put")
def resp_cont(url, request):
- content = {"Here is wh it failed"}
+ content = {"Here is why it failed"}
return response(404, content, {}, None, 5, request)
with HTTMock(resp_cont):
@@ -226,7 +311,7 @@ def test_delete_request_404(gl):
scheme="http", netloc="localhost", path="/api/v4/not_there", method="delete"
)
def resp_cont(url, request):
- content = {"Here is wh it failed"}
+ content = {"Here is why it failed"}
return response(404, content, {}, None, 5, request)
with HTTMock(resp_cont):