|
21 | 21 | from django_declarative_apis.machinery import errors, filtering, tasks |
22 | 22 | from django_declarative_apis.machinery.tasks import future_task_runner |
23 | 23 | from django_declarative_apis.resources.utils import HttpStatusCode |
24 | | -from tests import testutils |
| 24 | +from tests import testutils, models |
25 | 25 |
|
26 | 26 | _TEST_RESOURCE = {"foo": "bar"} |
27 | 27 |
|
@@ -147,70 +147,96 @@ def resource(self): |
147 | 147 | mock_logging.error.assert_called_with("('something bad happened',)\nNone") |
148 | 148 |
|
149 | 149 | def test_get_response_with_dirty_resource(self): |
150 | | - class _TestResource: |
151 | | - def is_dirty(self, check_relationship=False): |
152 | | - return True |
| 150 | + class _TestEndpoint1(machinery.EndpointDefinition): |
| 151 | + @machinery.endpoint_resource(type=models.DirtyFieldsModel) |
| 152 | + def resource(self): |
| 153 | + result = models.DirtyFieldsModel(field="abcde") |
| 154 | + result.fk_field = models.TestModel.objects.create(int_field=1) |
| 155 | + return result |
| 156 | + |
| 157 | + class _TestEndpoint2(machinery.EndpointDefinition): |
| 158 | + @machinery.endpoint_resource(type=models.DirtyFieldsModel) |
| 159 | + def resource(self): |
| 160 | + result = models.DirtyFieldsModel(field="abcde") |
| 161 | + result.fk_field = models.TestModel.objects.create(int_field=1) |
| 162 | + return result |
153 | 163 |
|
154 | | - def save(self): |
| 164 | + @machinery.task |
| 165 | + def null_task(self): |
155 | 166 | pass |
156 | 167 |
|
157 | | - class _TestEndpoint(machinery.EndpointDefinition): |
158 | | - @machinery.endpoint_resource(type=_TestResource) |
| 168 | + class _TestEndpoint3(machinery.EndpointDefinition): |
| 169 | + @machinery.endpoint_resource(type=models.DirtyFieldsModel) |
159 | 170 | def resource(self): |
160 | | - return _TestResource() |
| 171 | + result = models.DirtyFieldsModel(field="abcde") |
| 172 | + result.fk_field = models.TestModel.objects.create(int_field=1) |
| 173 | + return result |
161 | 174 |
|
162 | | - endpoint = _TestEndpoint() |
163 | | - manager = machinery.EndpointBinder.BoundEndpointManager( |
164 | | - machinery._EndpointRequestLifecycleManager(endpoint), endpoint |
165 | | - ) |
| 175 | + @machinery.task |
| 176 | + def task(self): |
| 177 | + self.resource.field = "zyxwv" |
| 178 | + |
| 179 | + for test_name, endpoint_cls, expected_call_count in ( |
| 180 | + ("No Task", _TestEndpoint1, 1), |
| 181 | + ("No-op Task", _TestEndpoint2, 1), |
| 182 | + ("With Task", _TestEndpoint3, 2), |
| 183 | + ): |
| 184 | + with self.subTest(test_name): |
| 185 | + endpoint = endpoint_cls() |
| 186 | + manager = machinery.EndpointBinder.BoundEndpointManager( |
| 187 | + machinery._EndpointRequestLifecycleManager(endpoint), endpoint |
| 188 | + ) |
166 | 189 |
|
167 | | - class _FakeRequest: |
168 | | - META = {} |
| 190 | + class _FakeRequest: |
| 191 | + META = {} |
169 | 192 |
|
170 | | - manager.bound_endpoint.request = _FakeRequest() |
| 193 | + manager.bound_endpoint.request = _FakeRequest() |
171 | 194 |
|
172 | | - with mock.patch.object(_TestResource, "save", return_value=None) as mock_save: |
173 | | - manager.get_response() |
174 | | - # save is called before and after tasks. since we've hardcoded _TestResource.is_dirty to return True, |
175 | | - # both of them should fire |
176 | | - self.assertEqual(mock_save.call_count, 2) |
| 195 | + with mock.patch.object( |
| 196 | + models.DirtyFieldsModel.objects, |
| 197 | + "update_or_create", |
| 198 | + wraps=models.DirtyFieldsModel.objects.update_or_create, |
| 199 | + ) as mock_uoc: |
| 200 | + manager.get_response() |
| 201 | + self.assertEqual(mock_uoc.call_count, expected_call_count) |
177 | 202 |
|
178 | 203 | def test_get_response_with_client_error_while_executing_tasks(self): |
179 | | - class _TestResource: |
180 | | - def is_dirty(self, check_relationship=False): |
181 | | - return True |
182 | | - |
183 | | - def save(self): |
184 | | - pass |
185 | | - |
186 | 204 | class _TestEndpoint(machinery.EndpointDefinition): |
187 | | - @machinery.endpoint_resource(type=_TestResource) |
| 205 | + @machinery.endpoint_resource(type=models.DirtyFieldsModel) |
188 | 206 | def resource(self): |
189 | | - return _TestResource() |
| 207 | + result = models.DirtyFieldsModel(id=1, field="abcde") |
| 208 | + result.fk_field = models.TestModel.objects.create(int_field=1) |
| 209 | + return result |
190 | 210 |
|
191 | 211 | @machinery.task |
192 | 212 | def raise_an_exception(self): |
| 213 | + self.resource.field = "zyxwv" |
193 | 214 | raise errors.ClientError( |
194 | 215 | code=http.HTTPStatus.BAD_REQUEST, |
195 | 216 | message="something bad happened", |
196 | 217 | save_changes=error_should_save_changes, |
197 | 218 | ) |
198 | 219 |
|
199 | 220 | for error_should_save_changes in (True, False): |
200 | | - with mock.patch.object(_TestResource, "save") as mock_save: |
201 | | - endpoint = _TestEndpoint() |
202 | | - manager = machinery.EndpointBinder.BoundEndpointManager( |
203 | | - machinery._EndpointRequestLifecycleManager(endpoint), endpoint |
204 | | - ) |
205 | | - try: |
206 | | - manager.get_response() |
207 | | - self.fail("This should have failed") |
208 | | - except errors.ClientError: |
209 | | - # save should be called twice if the exception says the resource should be saved: once before |
210 | | - # tasks are executed and once during exception handling. |
211 | | - self.assertEqual( |
212 | | - mock_save.call_count, 2 if error_should_save_changes else 1 |
| 221 | + with self.subTest(f"error_should_save_changes={error_should_save_changes}"): |
| 222 | + with mock.patch.object( |
| 223 | + models.DirtyFieldsModel.objects, |
| 224 | + "update_or_create", |
| 225 | + wraps=models.DirtyFieldsModel.objects.update_or_create, |
| 226 | + ) as mock_uoc: |
| 227 | + endpoint = _TestEndpoint() |
| 228 | + manager = machinery.EndpointBinder.BoundEndpointManager( |
| 229 | + machinery._EndpointRequestLifecycleManager(endpoint), endpoint |
213 | 230 | ) |
| 231 | + try: |
| 232 | + manager.get_response() |
| 233 | + self.fail("This should have failed") |
| 234 | + except errors.ClientError: |
| 235 | + # save should be called twice if the exception says the resource should be saved: once before |
| 236 | + # tasks are executed and once during exception handling. |
| 237 | + self.assertEqual( |
| 238 | + mock_uoc.call_count, 2 if error_should_save_changes else 1 |
| 239 | + ) |
214 | 240 |
|
215 | 241 | def test_get_response_custom_http_response(self): |
216 | 242 | expected_data = {"foo": "bar"} |
@@ -280,7 +306,11 @@ class _QuerySet(list): |
280 | 306 | data = _QuerySet([_TestResource("foo", "bar"), _TestResource("bar", "baz")]) |
281 | 307 |
|
282 | 308 | filter_def = { |
283 | | - _TestResource: {"name": filtering.ALWAYS, "secret": filtering.NEVER} |
| 309 | + _TestResource: { |
| 310 | + "name": filtering.ALWAYS, |
| 311 | + "secret": filtering.NEVER, |
| 312 | + "foo": filtering.ALWAYS, |
| 313 | + } |
284 | 314 | } |
285 | 315 |
|
286 | 316 | class _TestEndpoint(machinery.EndpointDefinition): |
|
0 commit comments