diff options
| author | Karun Japhet <karun@japhet.in> | 2021-08-28 11:41:59 +0530 |
|---|---|---|
| committer | Karun Japhet <karun@japhet.in> | 2021-08-29 15:01:18 +0530 |
| commit | 3b1d3a41da7e7228f3a465d06902db8af564153e (patch) | |
| tree | e16d5e53efb182475c96a32ac1f2686a43ee9c19 /tests/unit | |
| parent | a00ec87bdbadccaf3e3700a48cbb797fd2750107 (diff) | |
| download | gitlab-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.py | 15 | ||||
| -rw-r--r-- | tests/unit/test_config.py | 70 | ||||
| -rw-r--r-- | tests/unit/test_gitlab_http_methods.py | 95 |
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): |
