|
3 | 3 | import responses
|
4 | 4 |
|
5 | 5 | from gitlab import GitlabHttpError, GitlabList, GitlabParsingError, RedirectError
|
| 6 | +from gitlab.client import RETRYABLE_TRANSIENT_ERROR_CODES |
6 | 7 | from tests.unit import helpers
|
7 | 8 |
|
8 | 9 | MATCH_EMPTY_QUERY_PARAMS = [responses.matchers.query_param_matcher({})]
|
@@ -51,7 +52,7 @@ def test_http_request_404(gl):
|
51 | 52 |
|
52 | 53 |
|
53 | 54 | @responses.activate
|
54 |
| -@pytest.mark.parametrize("status_code", [500, 502, 503, 504]) |
| 55 | +@pytest.mark.parametrize("status_code", RETRYABLE_TRANSIENT_ERROR_CODES) |
55 | 56 | def test_http_request_with_only_failures(gl, status_code):
|
56 | 57 | url = "http://localhost/api/v4/projects"
|
57 | 58 | responses.add(
|
@@ -97,6 +98,37 @@ def request_callback(request):
|
97 | 98 | assert len(responses.calls) == calls_before_success
|
98 | 99 |
|
99 | 100 |
|
| 101 | +@responses.activate |
| 102 | +def test_http_request_with_retry_on_method_for_transient_network_failures(gl): |
| 103 | + call_count = 0 |
| 104 | + calls_before_success = 3 |
| 105 | + |
| 106 | + url = "http://localhost/api/v4/projects" |
| 107 | + |
| 108 | + def request_callback(request): |
| 109 | + nonlocal call_count |
| 110 | + call_count += 1 |
| 111 | + status_code = 200 |
| 112 | + headers = {} |
| 113 | + body = "[]" |
| 114 | + |
| 115 | + if call_count >= calls_before_success: |
| 116 | + return (status_code, headers, body) |
| 117 | + raise requests.ConnectionError("Connection aborted.") |
| 118 | + |
| 119 | + responses.add_callback( |
| 120 | + method=responses.GET, |
| 121 | + url=url, |
| 122 | + callback=request_callback, |
| 123 | + content_type="application/json", |
| 124 | + ) |
| 125 | + |
| 126 | + http_r = gl.http_request("get", "/projects", retry_transient_errors=True) |
| 127 | + |
| 128 | + assert http_r.status_code == 200 |
| 129 | + assert len(responses.calls) == calls_before_success |
| 130 | + |
| 131 | + |
100 | 132 | @responses.activate
|
101 | 133 | def test_http_request_with_retry_on_class_for_transient_failures(gl_retry):
|
102 | 134 | call_count = 0
|
@@ -126,6 +158,37 @@ def request_callback(request: requests.models.PreparedRequest):
|
126 | 158 | assert len(responses.calls) == calls_before_success
|
127 | 159 |
|
128 | 160 |
|
| 161 | +@responses.activate |
| 162 | +def test_http_request_with_retry_on_class_for_transient_network_failures(gl_retry): |
| 163 | + call_count = 0 |
| 164 | + calls_before_success = 3 |
| 165 | + |
| 166 | + url = "http://localhost/api/v4/projects" |
| 167 | + |
| 168 | + def request_callback(request: requests.models.PreparedRequest): |
| 169 | + nonlocal call_count |
| 170 | + call_count += 1 |
| 171 | + status_code = 200 |
| 172 | + headers = {} |
| 173 | + body = "[]" |
| 174 | + |
| 175 | + if call_count >= calls_before_success: |
| 176 | + return (status_code, headers, body) |
| 177 | + raise requests.ConnectionError("Connection aborted.") |
| 178 | + |
| 179 | + responses.add_callback( |
| 180 | + method=responses.GET, |
| 181 | + url=url, |
| 182 | + callback=request_callback, |
| 183 | + content_type="application/json", |
| 184 | + ) |
| 185 | + |
| 186 | + http_r = gl_retry.http_request("get", "/projects", retry_transient_errors=True) |
| 187 | + |
| 188 | + assert http_r.status_code == 200 |
| 189 | + assert len(responses.calls) == calls_before_success |
| 190 | + |
| 191 | + |
129 | 192 | @responses.activate
|
130 | 193 | def test_http_request_with_retry_on_class_and_method_for_transient_failures(gl_retry):
|
131 | 194 | call_count = 0
|
@@ -155,6 +218,39 @@ def request_callback(request):
|
155 | 218 | assert len(responses.calls) == 1
|
156 | 219 |
|
157 | 220 |
|
| 221 | +@responses.activate |
| 222 | +def test_http_request_with_retry_on_class_and_method_for_transient_network_failures( |
| 223 | + gl_retry, |
| 224 | +): |
| 225 | + call_count = 0 |
| 226 | + calls_before_success = 3 |
| 227 | + |
| 228 | + url = "http://localhost/api/v4/projects" |
| 229 | + |
| 230 | + def request_callback(request): |
| 231 | + nonlocal call_count |
| 232 | + call_count += 1 |
| 233 | + status_code = 200 |
| 234 | + headers = {} |
| 235 | + body = "[]" |
| 236 | + |
| 237 | + if call_count >= calls_before_success: |
| 238 | + return (status_code, headers, body) |
| 239 | + raise requests.ConnectionError("Connection aborted.") |
| 240 | + |
| 241 | + responses.add_callback( |
| 242 | + method=responses.GET, |
| 243 | + url=url, |
| 244 | + callback=request_callback, |
| 245 | + content_type="application/json", |
| 246 | + ) |
| 247 | + |
| 248 | + with pytest.raises(requests.ConnectionError): |
| 249 | + gl_retry.http_request("get", "/projects", retry_transient_errors=False) |
| 250 | + |
| 251 | + assert len(responses.calls) == 1 |
| 252 | + |
| 253 | + |
158 | 254 | def create_redirect_response(
|
159 | 255 | *, response: requests.models.Response, http_method: str, api_path: str
|
160 | 256 | ) -> requests.models.Response:
|
|
0 commit comments