|
7 | 7 |
|
8 | 8 |
|
9 | 9 | class TestRetry: |
10 | | - @pytest.fixture() |
11 | | - def retry_policy(self) -> DatabricksRetryPolicy: |
12 | | - return DatabricksRetryPolicy( |
| 10 | + def _make_retry_policy(self, **overrides) -> DatabricksRetryPolicy: |
| 11 | + defaults = dict( |
13 | 12 | delay_min=1, |
14 | 13 | delay_max=30, |
15 | 14 | stop_after_attempts_count=3, |
16 | 15 | stop_after_attempts_duration=900, |
17 | 16 | delay_default=2, |
18 | 17 | force_dangerous_codes=[], |
19 | 18 | ) |
| 19 | + defaults.update(overrides) |
| 20 | + return DatabricksRetryPolicy(**defaults) |
| 21 | + |
| 22 | + @pytest.fixture() |
| 23 | + def retry_policy(self) -> DatabricksRetryPolicy: |
| 24 | + return self._make_retry_policy() |
20 | 25 |
|
21 | 26 | @pytest.fixture() |
22 | 27 | def error_history(self) -> RequestHistory: |
@@ -84,112 +89,82 @@ def test_excessive_retry_attempts_error(self, t_mock, retry_policy): |
84 | 89 | # Internally urllib3 calls the increment function generating a new instance for every retry |
85 | 90 | retry_policy = retry_policy.increment() |
86 | 91 |
|
87 | | - @pytest.fixture() |
88 | | - def server_directed_retry_policy(self) -> DatabricksRetryPolicy: |
89 | | - return DatabricksRetryPolicy( |
90 | | - delay_min=1, |
91 | | - delay_max=30, |
92 | | - stop_after_attempts_count=3, |
93 | | - stop_after_attempts_duration=900, |
94 | | - delay_default=2, |
95 | | - force_dangerous_codes=[], |
96 | | - server_directed_only=True, |
97 | | - ) |
98 | | - |
99 | | - def test_server_directed_only__retries_with_retry_after( |
100 | | - self, server_directed_retry_policy |
101 | | - ): |
| 92 | + def test_respect_server_retry_after__retries_with_retry_after(self): |
102 | 93 | """429 + Retry-After header → should retry""" |
103 | | - server_directed_retry_policy._retry_start_time = time.time() |
104 | | - server_directed_retry_policy.command_type = CommandType.OTHER |
105 | | - should_retry, msg = server_directed_retry_policy.should_retry( |
106 | | - "POST", 429, has_retry_after=True |
107 | | - ) |
| 94 | + policy = self._make_retry_policy(respect_server_retry_after_header=True) |
| 95 | + policy._retry_start_time = time.time() |
| 96 | + policy.command_type = CommandType.OTHER |
| 97 | + should_retry, msg = policy.should_retry("POST", 429, has_retry_after=True) |
108 | 98 | assert should_retry is True |
109 | 99 |
|
110 | | - def test_server_directed_only__no_retry_without_retry_after( |
111 | | - self, server_directed_retry_policy |
112 | | - ): |
| 100 | + def test_respect_server_retry_after__no_retry_without_retry_after(self): |
113 | 101 | """429 without Retry-After header → no retry""" |
114 | | - server_directed_retry_policy._retry_start_time = time.time() |
115 | | - server_directed_retry_policy.command_type = CommandType.OTHER |
116 | | - should_retry, msg = server_directed_retry_policy.should_retry( |
117 | | - "POST", 429, has_retry_after=False |
118 | | - ) |
| 102 | + policy = self._make_retry_policy(respect_server_retry_after_header=True) |
| 103 | + policy._retry_start_time = time.time() |
| 104 | + policy.command_type = CommandType.OTHER |
| 105 | + should_retry, msg = policy.should_retry("POST", 429, has_retry_after=False) |
119 | 106 | assert should_retry is False |
120 | | - assert "server_directed_only" in msg |
| 107 | + assert "respect_server_retry_after_header" in msg |
121 | 108 |
|
122 | | - def test_server_directed_only__no_retry_503_without_header( |
123 | | - self, server_directed_retry_policy |
124 | | - ): |
| 109 | + def test_respect_server_retry_after__no_retry_503_without_header(self): |
125 | 110 | """503 without Retry-After header → no retry""" |
126 | | - server_directed_retry_policy._retry_start_time = time.time() |
127 | | - server_directed_retry_policy.command_type = CommandType.OTHER |
128 | | - should_retry, msg = server_directed_retry_policy.should_retry( |
129 | | - "POST", 503, has_retry_after=False |
130 | | - ) |
| 111 | + policy = self._make_retry_policy(respect_server_retry_after_header=True) |
| 112 | + policy._retry_start_time = time.time() |
| 113 | + policy.command_type = CommandType.OTHER |
| 114 | + should_retry, msg = policy.should_retry("POST", 503, has_retry_after=False) |
131 | 115 | assert should_retry is False |
132 | | - assert "server_directed_only" in msg |
| 116 | + assert "respect_server_retry_after_header" in msg |
133 | 117 |
|
134 | | - def test_server_directed_only__overrides_dangerous_codes(self): |
135 | | - """force_dangerous_codes=[500] + no Retry-After → no retry in server_directed_only mode""" |
136 | | - policy = DatabricksRetryPolicy( |
137 | | - delay_min=1, |
138 | | - delay_max=30, |
139 | | - stop_after_attempts_count=3, |
140 | | - stop_after_attempts_duration=900, |
141 | | - delay_default=2, |
142 | | - force_dangerous_codes=[500], |
143 | | - server_directed_only=True, |
| 118 | + def test_respect_server_retry_after__overrides_dangerous_codes(self): |
| 119 | + """force_dangerous_codes=[500] + no Retry-After → no retry in respect_server_retry_after_header mode""" |
| 120 | + policy = self._make_retry_policy( |
| 121 | + force_dangerous_codes=[500], respect_server_retry_after_header=True |
144 | 122 | ) |
145 | 123 | policy._retry_start_time = time.time() |
146 | 124 | policy.command_type = CommandType.EXECUTE_STATEMENT |
147 | 125 | should_retry, msg = policy.should_retry("POST", 500, has_retry_after=False) |
148 | 126 | assert should_retry is False |
149 | | - assert "server_directed_only" in msg |
| 127 | + assert "respect_server_retry_after_header" in msg |
150 | 128 |
|
151 | | - def test_server_directed_only__non_retryable_codes_unaffected( |
152 | | - self, server_directed_retry_policy |
153 | | - ): |
| 129 | + def test_respect_server_retry_after__non_retryable_codes_unaffected(self): |
154 | 130 | """401/403/501 still don't retry even with Retry-After header""" |
155 | | - server_directed_retry_policy._retry_start_time = time.time() |
156 | | - server_directed_retry_policy.command_type = CommandType.OTHER |
| 131 | + policy = self._make_retry_policy(respect_server_retry_after_header=True) |
| 132 | + policy._retry_start_time = time.time() |
| 133 | + policy.command_type = CommandType.OTHER |
157 | 134 | for code in [401, 403, 501]: |
158 | | - should_retry, msg = server_directed_retry_policy.should_retry( |
| 135 | + should_retry, msg = policy.should_retry( |
159 | 136 | "POST", code, has_retry_after=True |
160 | 137 | ) |
161 | 138 | assert should_retry is False, f"Code {code} should never retry" |
162 | 139 |
|
163 | 140 | def test_default_mode_unchanged(self, retry_policy): |
164 | | - """server_directed_only=False preserves existing behavior — 429 retries without header""" |
| 141 | + """respect_server_retry_after_header=False preserves existing behavior — 429 retries without header""" |
165 | 142 | retry_policy._retry_start_time = time.time() |
166 | 143 | retry_policy.command_type = CommandType.OTHER |
167 | 144 | should_retry, msg = retry_policy.should_retry( |
168 | 145 | "POST", 429, has_retry_after=False |
169 | 146 | ) |
170 | 147 | assert should_retry is True |
171 | 148 |
|
172 | | - def test_server_directed_only__survives_new(self, server_directed_retry_policy): |
| 149 | + def test_respect_server_retry_after__survives_new(self): |
173 | 150 | """urllib3 calls .new() between retries to create a fresh policy instance. |
174 | | - Verify that server_directed_only is carried over and still enforced.""" |
175 | | - server_directed_retry_policy._retry_start_time = time.time() |
176 | | - server_directed_retry_policy.command_type = CommandType.OTHER |
177 | | - new_policy = server_directed_retry_policy.new() |
178 | | - assert new_policy.server_directed_only is True |
| 151 | + Verify that respect_server_retry_after_header is carried over and still enforced.""" |
| 152 | + policy = self._make_retry_policy(respect_server_retry_after_header=True) |
| 153 | + policy._retry_start_time = time.time() |
| 154 | + policy.command_type = CommandType.OTHER |
| 155 | + new_policy = policy.new() |
| 156 | + assert new_policy.respect_server_retry_after_header is True |
179 | 157 | # The new instance should still block retries without Retry-After |
180 | 158 | should_retry, msg = new_policy.should_retry("POST", 429, has_retry_after=False) |
181 | 159 | assert should_retry is False |
182 | | - assert "server_directed_only" in msg |
| 160 | + assert "respect_server_retry_after_header" in msg |
183 | 161 |
|
184 | | - def test_server_directed_only__execute_statement_with_retry_after( |
185 | | - self, server_directed_retry_policy |
186 | | - ): |
| 162 | + def test_respect_server_retry_after__execute_statement_with_retry_after(self): |
187 | 163 | """EXECUTE_STATEMENT + 429 + Retry-After header → retry""" |
188 | | - server_directed_retry_policy._retry_start_time = time.time() |
189 | | - server_directed_retry_policy.command_type = CommandType.EXECUTE_STATEMENT |
190 | | - should_retry, msg = server_directed_retry_policy.should_retry( |
191 | | - "POST", 429, has_retry_after=True |
192 | | - ) |
| 164 | + policy = self._make_retry_policy(respect_server_retry_after_header=True) |
| 165 | + policy._retry_start_time = time.time() |
| 166 | + policy.command_type = CommandType.EXECUTE_STATEMENT |
| 167 | + should_retry, msg = policy.should_retry("POST", 429, has_retry_after=True) |
193 | 168 | assert should_retry is True |
194 | 169 |
|
195 | 170 | def test_404_does_not_retry_for_any_command_type(self, retry_policy): |
|
0 commit comments