mirror of
https://github.com/ansible/awx.git
synced 2026-04-28 13:15:27 -02:30
* Pass plugin_description through to CredentialType.description Propagate the plugin_description field from credential plugins into the CredentialType description when loading and creating managed credential types, including updates to existing records. Assisted-by: Claude * Add unit tests for plugin_description passthrough to CredentialType Tests cover load_plugin, get_creation_params, and _setup_tower_managed_defaults handling of the description field. Assisted-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: PabloHiro <palonso@redhat.com>
135 lines
4.8 KiB
Python
135 lines
4.8 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
import pytest
|
|
|
|
from types import SimpleNamespace
|
|
from unittest import mock
|
|
|
|
from awx.main.models import Credential, CredentialType
|
|
from awx.main.models.credential import CredentialTypeHelper, ManagedCredentialType
|
|
|
|
from django.apps import apps
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_unique_hash_with_unicode():
|
|
ct = CredentialType.objects.create(name='Väult', kind='vault')
|
|
cred = Credential.objects.create(name='Iñtërnâtiônàlizætiøn', credential_type=ct, inputs={'vault_id': '🐉🐉🐉'})
|
|
assert cred.unique_hash(display=True) == 'Väult (id=🐉🐉🐉)'
|
|
|
|
|
|
def test_custom_cred_with_empty_encrypted_field():
|
|
ct = CredentialType(name='My Custom Cred', kind='custom', inputs={'fields': [{'id': 'some_field', 'label': 'My Field', 'secret': True}]})
|
|
cred = Credential(id=4, name='Testing 1 2 3', credential_type=ct, inputs={})
|
|
assert cred.encrypt_field('some_field', None) is None
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
(
|
|
'apps',
|
|
'app_config',
|
|
),
|
|
[
|
|
(
|
|
apps,
|
|
None,
|
|
),
|
|
(
|
|
None,
|
|
apps.get_app_config('main'),
|
|
),
|
|
],
|
|
)
|
|
def test__get_credential_type_class(apps, app_config):
|
|
ct = CredentialType._get_credential_type_class(apps=apps, app_config=app_config)
|
|
assert ct.__name__ == 'CredentialType'
|
|
|
|
|
|
def test__get_credential_type_class_invalid_params():
|
|
with pytest.raises(ValueError) as e:
|
|
CredentialType._get_credential_type_class(apps=apps, app_config=apps.get_app_config('main'))
|
|
|
|
assert type(e.value) is ValueError
|
|
assert str(e.value) == 'Expected only apps or app_config to be defined, not both'
|
|
|
|
|
|
def test_credential_context_property():
|
|
"""Test that credential context property initializes empty dict and persists across accesses."""
|
|
ct = CredentialType(name='Test Cred', kind='vault')
|
|
cred = Credential(id=1, name='Test Credential', credential_type=ct, inputs={})
|
|
|
|
# First access should return empty dict
|
|
context = cred.context
|
|
assert context == {}
|
|
|
|
# Modify the context
|
|
context['test_key'] = 'test_value'
|
|
|
|
# Second access should return the same dict with modifications
|
|
assert cred.context == {'test_key': 'test_value'}
|
|
assert cred.context is context # Same object reference
|
|
|
|
|
|
def test_credential_context_property_independent_instances():
|
|
"""Test that context property is independent between credential instances."""
|
|
ct = CredentialType(name='Test Cred', kind='vault')
|
|
cred1 = Credential(id=1, name='Cred 1', credential_type=ct, inputs={})
|
|
cred2 = Credential(id=2, name='Cred 2', credential_type=ct, inputs={})
|
|
|
|
cred1.context['key1'] = 'value1'
|
|
cred2.context['key2'] = 'value2'
|
|
|
|
assert cred1.context == {'key1': 'value1'}
|
|
assert cred2.context == {'key2': 'value2'}
|
|
assert cred1.context is not cred2.context
|
|
|
|
|
|
def test_load_plugin_passes_description():
|
|
plugin = SimpleNamespace(name='test_plugin', inputs={'fields': []}, backend=None, plugin_description='A test plugin')
|
|
CredentialType.load_plugin('test_ns', plugin)
|
|
entry = ManagedCredentialType.registry['test_ns']
|
|
assert entry.description == 'A test plugin'
|
|
del ManagedCredentialType.registry['test_ns']
|
|
|
|
|
|
def test_load_plugin_missing_description():
|
|
plugin = SimpleNamespace(name='test_plugin', inputs={'fields': []}, backend=None)
|
|
CredentialType.load_plugin('test_ns', plugin)
|
|
entry = ManagedCredentialType.registry['test_ns']
|
|
assert entry.description == ''
|
|
del ManagedCredentialType.registry['test_ns']
|
|
|
|
|
|
def test_get_creation_params_external_includes_description():
|
|
cred_type = SimpleNamespace(namespace='test_ns', kind='external', name='Test', description='My description')
|
|
params = CredentialTypeHelper.get_creation_params(cred_type)
|
|
assert params['description'] == 'My description'
|
|
|
|
|
|
def test_get_creation_params_external_missing_description():
|
|
cred_type = SimpleNamespace(namespace='test_ns', kind='external', name='Test')
|
|
params = CredentialTypeHelper.get_creation_params(cred_type)
|
|
assert params['description'] == ''
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_setup_tower_managed_defaults_updates_description():
|
|
registry_entry = SimpleNamespace(
|
|
namespace='test_ns',
|
|
kind='external',
|
|
name='Test Plugin',
|
|
inputs={'fields': []},
|
|
backend=None,
|
|
description='Updated description',
|
|
)
|
|
# Create an existing credential type with no description
|
|
ct = CredentialType.objects.create(name='Test Plugin', kind='external', namespace='old_ns')
|
|
assert ct.description == ''
|
|
|
|
with mock.patch.dict(ManagedCredentialType.registry, {'test_ns': registry_entry}, clear=True):
|
|
CredentialType._setup_tower_managed_defaults()
|
|
|
|
ct.refresh_from_db()
|
|
assert ct.description == 'Updated description'
|
|
assert ct.namespace == 'test_ns'
|