do not add optional survey fields with empty strings that are not backed by extra_vars

This commit is contained in:
Peter Braun
2026-02-17 10:13:33 +01:00
parent 08f1507f70
commit d2e51c4124
2 changed files with 40 additions and 14 deletions

View File

@@ -188,6 +188,10 @@ class SurveyJobTemplateMixin(models.Model):
runtime_extra_vars.pop(variable_key)
if default is not None:
# do not add variables that contain an empty string, are not required and are nor present in extra_vars
if default == '' and not survey_element.get('required') and variable_key not in runtime_extra_vars:
continue
decrypted_default = default
if survey_element['type'] == "password" and isinstance(decrypted_default, str) and decrypted_default.startswith('$encrypted$'):
decrypted_default = decrypt_value(get_encryption_key('value', pk=None), decrypted_default)

View File

@@ -176,22 +176,22 @@ def test_display_survey_spec_encrypts_default(survey_spec_factory):
@pytest.mark.survey
@pytest.mark.parametrize(
"question_type,default,min,max,expect_use,expect_value",
"question_type,default,min,max,expect_valid,expect_use,expect_value",
[
("text", "", 0, 0, True, ''), # default used
("text", "", 1, 0, False, 'N/A'), # value less than min length
("password", "", 1, 0, False, 'N/A'), # passwords behave the same as text
("multiplechoice", "", 0, 0, False, 'N/A'), # historical bug
("multiplechoice", "zeb", 0, 0, False, 'N/A'), # zeb not in choices
("multiplechoice", "coffee", 0, 0, True, 'coffee'),
("multiselect", None, 0, 0, False, 'N/A'), # NOTE: Behavior is arguable, value of [] may be prefered
("multiselect", "", 0, 0, False, 'N/A'),
("multiselect", ["zeb"], 0, 0, False, 'N/A'),
("multiselect", ["milk"], 0, 0, True, ["milk"]),
("multiselect", ["orange\nmilk"], 0, 0, False, 'N/A'), # historical bug
("text", "", 0, 0, True, False, 'N/A'), # valid but empty default not sent for optional question
("text", "", 1, 0, False, False, 'N/A'), # value less than min length
("password", "", 1, 0, False, False, 'N/A'), # passwords behave the same as text
("multiplechoice", "", 0, 0, False, False, 'N/A'), # historical bug
("multiplechoice", "zeb", 0, 0, False, False, 'N/A'), # zeb not in choices
("multiplechoice", "coffee", 0, 0, True, True, 'coffee'),
("multiselect", None, 0, 0, False, False, 'N/A'), # NOTE: Behavior is arguable, value of [] may be prefered
("multiselect", "", 0, 0, False, False, 'N/A'),
("multiselect", ["zeb"], 0, 0, False, False, 'N/A'),
("multiselect", ["milk"], 0, 0, True, True, ["milk"]),
("multiselect", ["orange\nmilk"], 0, 0, False, False, 'N/A'), # historical bug
],
)
def test_optional_survey_question_defaults(survey_spec_factory, question_type, default, min, max, expect_use, expect_value):
def test_optional_survey_question_defaults(survey_spec_factory, question_type, default, min, max, expect_valid, expect_use, expect_value):
spec = survey_spec_factory(
[
{
@@ -208,7 +208,7 @@ def test_optional_survey_question_defaults(survey_spec_factory, question_type, d
jt = JobTemplate(name="test-jt", survey_spec=spec, survey_enabled=True)
defaulted_extra_vars = jt._update_unified_job_kwargs({}, {})
element = spec['spec'][0]
if expect_use:
if expect_valid:
assert jt._survey_element_validation(element, {element['variable']: element['default']}) == []
else:
assert jt._survey_element_validation(element, {element['variable']: element['default']})
@@ -218,6 +218,28 @@ def test_optional_survey_question_defaults(survey_spec_factory, question_type, d
assert 'c' not in defaulted_extra_vars['extra_vars']
@pytest.mark.survey
def test_optional_survey_empty_default_with_runtime_extra_var(survey_spec_factory):
"""When a user explicitly provides an empty string at runtime for an optional
survey question, the variable should still be included in extra_vars."""
spec = survey_spec_factory(
[
{
"required": False,
"default": "",
"choices": "",
"variable": "c",
"min": 0,
"max": 0,
"type": "text",
},
]
)
jt = JobTemplate(name="test-jt", survey_spec=spec, survey_enabled=True)
defaulted_extra_vars = jt._update_unified_job_kwargs({}, {'extra_vars': json.dumps({'c': ''})})
assert json.loads(defaulted_extra_vars['extra_vars'])['c'] == ''
@pytest.mark.survey
@pytest.mark.parametrize(
"question_type,default,maxlen,kwargs,expected",