|
| 1 | +from unittest.mock import patch |
| 2 | + |
1 | 3 | import pytest |
| 4 | +import requests |
2 | 5 | from django.test.utils import override_settings |
3 | 6 |
|
4 | 7 | from ansible_base.lib.utils.response import get_relative_url |
5 | | -from ansible_base.rbac.models import RoleDefinition |
| 8 | +from ansible_base.rbac.models import RoleDefinition, RoleUserAssignment |
6 | 9 |
|
7 | 10 |
|
8 | 11 | @pytest.mark.django_db |
@@ -192,3 +195,67 @@ def test_role_definitions_post_disabled_by_settings(admin_api_client): |
192 | 195 | assert response.status_code == 200, response.data |
193 | 196 | print(response.data) |
194 | 197 | assert 'POST' not in response.data.get('actions', {}) |
| 198 | + |
| 199 | + |
| 200 | +@pytest.mark.parametrize( |
| 201 | + "sync_error_status, expected_status", |
| 202 | + [ |
| 203 | + (400, 400), # ValidationError |
| 204 | + (401, 403), # PermissionDenied |
| 205 | + (403, 403), # PermissionDenied |
| 206 | + (500, 500), # Re-raised HTTPError → Internal Server Error |
| 207 | + (None, 500), # HTTPError with no response → Internal Server Error |
| 208 | + ], |
| 209 | +) |
| 210 | +@pytest.mark.django_db |
| 211 | +def test_user_assignment_remote_sync_error_handling(admin_api_client, inv_rd, rando, inventory, sync_error_status, expected_status): |
| 212 | + """Test that remote sync HTTP errors are handled correctly for user assignments""" |
| 213 | + url = get_relative_url('roleuserassignment-list') |
| 214 | + data = dict(role_definition=inv_rd.id, user=rando.id, object_id=inventory.id) |
| 215 | + |
| 216 | + # Track initial count to verify transaction rollback |
| 217 | + initial_count = RoleUserAssignment.objects.count() |
| 218 | + |
| 219 | + # Mock the remote sync to raise HTTPError with specified status |
| 220 | + if sync_error_status is not None: |
| 221 | + mock_response = requests.Response() |
| 222 | + mock_response.status_code = sync_error_status |
| 223 | + http_error = requests.exceptions.HTTPError(response=mock_response) |
| 224 | + else: |
| 225 | + # Simulate HTTPError with no response (e.g., connection failed) |
| 226 | + http_error = requests.exceptions.HTTPError(response=None) |
| 227 | + |
| 228 | + with patch('ansible_base.rbac.api.views.BaseAssignmentViewSet.remote_sync_assignment') as mock_sync: |
| 229 | + mock_sync.side_effect = http_error |
| 230 | + |
| 231 | + response = admin_api_client.post(url, data=data, format="json") |
| 232 | + assert response.status_code == expected_status |
| 233 | + assert 'detail' in response.data |
| 234 | + |
| 235 | + # Verify that no assignment was created due to transaction rollback |
| 236 | + assert RoleUserAssignment.objects.count() == initial_count |
| 237 | + |
| 238 | + |
| 239 | +@pytest.mark.django_db |
| 240 | +def test_user_assignment_remote_sync_connection_error(admin_api_client, inv_rd, rando, inventory): |
| 241 | + """Test that connection errors during remote sync cause unhandled exceptions""" |
| 242 | + url = get_relative_url('roleuserassignment-list') |
| 243 | + data = dict(role_definition=inv_rd.id, user=rando.id, object_id=inventory.id) |
| 244 | + |
| 245 | + # Track initial count to verify transaction rollback |
| 246 | + initial_count = RoleUserAssignment.objects.count() |
| 247 | + |
| 248 | + # Mock the remote sync to raise ConnectionError (no HTTP response) |
| 249 | + connection_error = requests.exceptions.ConnectionError("Connection failed") |
| 250 | + |
| 251 | + with patch('ansible_base.rbac.api.views.BaseAssignmentViewSet.remote_sync_assignment') as mock_sync: |
| 252 | + mock_sync.side_effect = connection_error |
| 253 | + |
| 254 | + response = admin_api_client.post(url, data=data, format="json") |
| 255 | + |
| 256 | + # NOTE: ConnectionError is not currently caught, so it should result in 500 |
| 257 | + # This test documents the current behavior - ConnectionError escapes the handler |
| 258 | + assert response.status_code == 500 |
| 259 | + |
| 260 | + # Verify that no assignment was created due to transaction rollback |
| 261 | + assert RoleUserAssignment.objects.count() == initial_count |
0 commit comments