From 1ebb641c1e0cd08bc2c3e55543974c363163cb30 Mon Sep 17 00:00:00 2001 From: Ryan Petrello Date: Mon, 13 Feb 2017 12:43:13 -0500 Subject: [PATCH] work around a DRF issue that causes CharField to cast `None` to `"None"` see: #5322 --- awx/conf/fields.py | 12 ++++++++++++ awx/conf/tests/unit/test_settings.py | 28 ++++++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/awx/conf/fields.py b/awx/conf/fields.py index 13d80ae937..f8d012a3aa 100644 --- a/awx/conf/fields.py +++ b/awx/conf/fields.py @@ -19,6 +19,18 @@ logger = logging.getLogger('awx.conf.fields') # appropriate Python type to be used in settings. +class CharField(CharField): + + def to_representation(self, value): + # django_rest_frameworks' default CharField implementation casts `None` + # to a string `"None"`: + # + # https://github.com/tomchristie/django-rest-framework/blob/cbad236f6d817d992873cd4df6527d46ab243ed1/rest_framework/fields.py#L761 + if value is None: + return None + return super(CharField, self).to_representation(value) + + class StringListField(ListField): child = CharField() diff --git a/awx/conf/tests/unit/test_settings.py b/awx/conf/tests/unit/test_settings.py index 5cd5d0e012..3fc78c452d 100644 --- a/awx/conf/tests/unit/test_settings.py +++ b/awx/conf/tests/unit/test_settings.py @@ -9,10 +9,9 @@ from django.conf import LazySettings from django.core.cache.backends.locmem import LocMemCache from django.core.exceptions import ImproperlyConfigured from django.utils.translation import ugettext_lazy as _ -from rest_framework import fields import pytest -from awx.conf import models +from awx.conf import models, fields from awx.conf.settings import SettingsWrapper, EncryptedCacheProxy, SETTING_CACHE_NOTSET from awx.conf.registry import SettingsRegistry @@ -330,6 +329,31 @@ def test_read_only_setting_deletion(settings): assert settings.AWX_SOME_SETTING == 'DEFAULT' +def test_charfield_properly_sets_none(settings, mocker): + "see: https://github.com/ansible/ansible-tower/issues/5322" + settings.registry.register( + 'AWX_SOME_SETTING', + field_class=fields.CharField, + category=_('System'), + category_slug='system', + allow_null=True + ) + + setting_list = mocker.Mock(**{'order_by.return_value.first.return_value': None}) + with apply_patches([ + mocker.patch('awx.conf.models.Setting.objects.filter', + return_value=setting_list), + mocker.patch('awx.conf.models.Setting.objects.create', mocker.Mock()) + ]): + settings.AWX_SOME_SETTING = None + + models.Setting.objects.create.assert_called_with( + key='AWX_SOME_SETTING', + user=None, + value=None + ) + + def test_settings_use_an_encrypted_cache(settings): settings.registry.register( 'AWX_ENCRYPTED',