|
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