mirror of
https://github.com/ansible/awx.git
synced 2026-05-14 21:07:39 -02:30
Fix server error from PATCH to inventory source (#16274)
Fix server error from PATCH to inventory source, co-authored with Claude opus 4.6
This commit is contained in:
@@ -89,7 +89,7 @@ class DeprecatedCredentialField(serializers.IntegerField):
|
|||||||
def to_internal_value(self, pk):
|
def to_internal_value(self, pk):
|
||||||
try:
|
try:
|
||||||
pk = int(pk)
|
pk = int(pk)
|
||||||
except ValueError:
|
except (ValueError, TypeError):
|
||||||
self.fail('invalid')
|
self.fail('invalid')
|
||||||
try:
|
try:
|
||||||
Credential.objects.get(pk=pk)
|
Credential.objects.get(pk=pk)
|
||||||
|
|||||||
@@ -463,6 +463,26 @@ class TestInventorySourceCredential:
|
|||||||
assert 'Cloud-based inventory sources (such as ec2)' in r.data['credential'][0]
|
assert 'Cloud-based inventory sources (such as ec2)' in r.data['credential'][0]
|
||||||
assert 'require credentials for the matching cloud service' in r.data['credential'][0]
|
assert 'require credentials for the matching cloud service' in r.data['credential'][0]
|
||||||
|
|
||||||
|
def test_credential_dict_value_returns_400(self, inventory, admin_user, put):
|
||||||
|
"""Passing a dict for the credential field should return 400, not 500.
|
||||||
|
|
||||||
|
Reproduces a bug where int() raises TypeError on non-scalar types
|
||||||
|
(dict, list) which was uncaught, resulting in a 500 Internal Server Error.
|
||||||
|
"""
|
||||||
|
inv_src = InventorySource.objects.create(name='test-src', inventory=inventory, source='ec2')
|
||||||
|
r = put(
|
||||||
|
url=reverse('api:inventory_source_detail', kwargs={'pk': inv_src.pk}),
|
||||||
|
data={
|
||||||
|
'name': 'test-src',
|
||||||
|
'inventory': inventory.pk,
|
||||||
|
'source': 'ec2',
|
||||||
|
'credential': {'username': 'admin', 'password': 'secret'},
|
||||||
|
},
|
||||||
|
user=admin_user,
|
||||||
|
expect=400,
|
||||||
|
)
|
||||||
|
assert r.status_code == 400
|
||||||
|
|
||||||
def test_vault_credential_not_allowed(self, project, inventory, vault_credential, admin_user, post):
|
def test_vault_credential_not_allowed(self, project, inventory, vault_credential, admin_user, post):
|
||||||
"""Vault credentials cannot be associated via the deprecated field"""
|
"""Vault credentials cannot be associated via the deprecated field"""
|
||||||
# TODO: when feature is added, add tests to use the related credentials
|
# TODO: when feature is added, add tests to use the related credentials
|
||||||
|
|||||||
49
awx/main/tests/unit/api/test_fields.py
Normal file
49
awx/main/tests/unit/api/test_fields.py
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import pytest
|
||||||
|
from collections import OrderedDict
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
|
from rest_framework.exceptions import ValidationError
|
||||||
|
|
||||||
|
from awx.api.fields import DeprecatedCredentialField
|
||||||
|
|
||||||
|
|
||||||
|
class TestDeprecatedCredentialField:
|
||||||
|
"""Test that DeprecatedCredentialField handles unexpected input types gracefully."""
|
||||||
|
|
||||||
|
def test_dict_value_raises_validation_error(self):
|
||||||
|
"""Passing a dict instead of an integer should return a 400 validation error, not a 500 TypeError."""
|
||||||
|
field = DeprecatedCredentialField()
|
||||||
|
with pytest.raises(ValidationError):
|
||||||
|
field.to_internal_value({"username": "admin", "password": "secret"})
|
||||||
|
|
||||||
|
def test_ordered_dict_value_raises_validation_error(self):
|
||||||
|
"""Passing an OrderedDict should return a 400 validation error, not a 500 TypeError."""
|
||||||
|
field = DeprecatedCredentialField()
|
||||||
|
with pytest.raises(ValidationError):
|
||||||
|
field.to_internal_value(OrderedDict([("username", "admin")]))
|
||||||
|
|
||||||
|
def test_list_value_raises_validation_error(self):
|
||||||
|
"""Passing a list should return a 400 validation error, not a 500 TypeError."""
|
||||||
|
field = DeprecatedCredentialField()
|
||||||
|
with pytest.raises(ValidationError):
|
||||||
|
field.to_internal_value([1, 2, 3])
|
||||||
|
|
||||||
|
def test_string_value_raises_validation_error(self):
|
||||||
|
"""Passing a non-numeric string should return a 400 validation error."""
|
||||||
|
field = DeprecatedCredentialField()
|
||||||
|
with pytest.raises(ValidationError):
|
||||||
|
field.to_internal_value("not_a_number")
|
||||||
|
|
||||||
|
@mock.patch('awx.api.fields.Credential.objects')
|
||||||
|
def test_valid_integer_value_works(self, mock_cred_objects):
|
||||||
|
"""Passing a valid integer PK should work when the credential exists."""
|
||||||
|
mock_cred_objects.get.return_value = mock.MagicMock()
|
||||||
|
field = DeprecatedCredentialField()
|
||||||
|
assert field.to_internal_value(42) == 42
|
||||||
|
|
||||||
|
@mock.patch('awx.api.fields.Credential.objects')
|
||||||
|
def test_valid_string_integer_value_works(self, mock_cred_objects):
|
||||||
|
"""Passing a numeric string PK should work when the credential exists."""
|
||||||
|
mock_cred_objects.get.return_value = mock.MagicMock()
|
||||||
|
field = DeprecatedCredentialField()
|
||||||
|
assert field.to_internal_value("42") == 42
|
||||||
Reference in New Issue
Block a user