From 29c1251400b80d72e4349f1281df5d8d8ffb5f5d Mon Sep 17 00:00:00 2001 From: Artem Rys Date: Mon, 23 Oct 2023 16:49:55 +0200 Subject: [PATCH] feat: additional validations for the groups feature (#926) This PR adds one more additional validation for the "Groups Feature" (https://splunk.github.io/addonfactory-ucc-generator/advanced/groups_feature/): there can not be a group field which is not defined in the entity. --- .../global_config_validator.py | 15 +- tests/unit/test_global_config_validator.py | 8 + ...oup_uses_fields_not_defined_in_entity.json | 163 ++++++++++++++++++ 3 files changed, 184 insertions(+), 2 deletions(-) create mode 100644 tests/unit/testdata/invalid_config_group_uses_fields_not_defined_in_entity.json diff --git a/splunk_add_on_ucc_framework/global_config_validator.py b/splunk_add_on_ucc_framework/global_config_validator.py index 463c75fb0..ffbd184bb 100644 --- a/splunk_add_on_ucc_framework/global_config_validator.py +++ b/splunk_add_on_ucc_framework/global_config_validator.py @@ -521,7 +521,7 @@ def _validate_checkbox_group(self) -> None: ) group_used_field_names.append(group_field_name) - def _validate_group_labels(self) -> None: + def _validate_groups(self) -> None: pages = self._config["pages"] inputs = pages.get("inputs") if inputs is None: @@ -531,6 +531,10 @@ def _validate_group_labels(self) -> None: groups = service.get("groups") if groups is None: continue + entities = service["entity"] + entity_fields = [] + for entity in entities: + entity_fields.append(entity["field"]) service_group_labels = [] for group in groups: group_label = group["label"] @@ -539,6 +543,13 @@ def _validate_group_labels(self) -> None: f"Service {service['name']} has duplicate labels in groups" ) service_group_labels.append(group_label) + for group in groups: + group_fields = group["fields"] + for group_field in group_fields: + if group_field not in entity_fields: + raise GlobalConfigValidatorException( + f"Service {service['name']} uses group field {group_field} which is not defined in entity" + ) def validate(self) -> None: self._validate_config_against_schema() @@ -552,4 +563,4 @@ def validate(self) -> None: self._validate_panels() self._warn_on_placeholder_usage() self._validate_checkbox_group() - self._validate_group_labels() + self._validate_groups() diff --git a/tests/unit/test_global_config_validator.py b/tests/unit/test_global_config_validator.py index d61683758..949a7a445 100644 --- a/tests/unit/test_global_config_validator.py +++ b/tests/unit/test_global_config_validator.py @@ -295,6 +295,14 @@ def test_config_validation_when_deprecated_placeholder_is_used(caplog): "Service input_with_duplicate_group_labels has duplicate labels in groups" ), ), + ( + "invalid_config_group_uses_fields_not_defined_in_entity.json", + False, + ( + "Service input_with_undefined_group_field uses group field " + "undefined_entity_field_name which is not defined in entity" + ), + ), ], ) def test_config_validation_when_error(filename, is_yaml, exception_message): diff --git a/tests/unit/testdata/invalid_config_group_uses_fields_not_defined_in_entity.json b/tests/unit/testdata/invalid_config_group_uses_fields_not_defined_in_entity.json new file mode 100644 index 000000000..ab252daf9 --- /dev/null +++ b/tests/unit/testdata/invalid_config_group_uses_fields_not_defined_in_entity.json @@ -0,0 +1,163 @@ +{ + "pages": { + "configuration": { + "tabs": [ + { + "name": "logging", + "entity": [ + { + "type": "singleSelect", + "label": "Log level", + "options": { + "disableSearch": true, + "autoCompleteFields": [ + { + "value": "DEBUG", + "label": "DEBUG" + }, + { + "value": "INFO", + "label": "INFO" + }, + { + "value": "WARNING", + "label": "WARNING" + }, + { + "value": "ERROR", + "label": "ERROR" + }, + { + "value": "CRITICAL", + "label": "CRITICAL" + } + ] + }, + "defaultValue": "INFO", + "field": "loglevel" + } + ], + "title": "Logging" + } + ], + "title": "Configuration", + "description": "Set up your add-on" + }, + "inputs": { + "title": "Inputs", + "description": "Create data inputs", + "table": { + "header": [ + { + "field": "name", + "label": "Input Name" + } + ], + "moreInfo": [ + { + "field": "name", + "label": "Name" + } + ], + "actions": [ + "edit", + "delete", + "clone" + ] + }, + "services": [ + { + "name": "input_with_undefined_group_field", + "title": "Input with undefined group field", + "groups": [ + { + "label": "Label 1", + "options": { + "isExpandable": false + }, + "fields": [ + "name" + ] + }, + { + "label": "Label 2", + "options": { + "isExpandable": false + }, + "fields": [ + "sourcetype", + "index", + "undefined_entity_field_name" + ] + }, + { + "label": "Label 3", + "options": { + "expand": false, + "isExpandable": true + }, + "fields": [ + "interval" + ] + } + ], + "entity": [ + { + "field": "name", + "label": "Name", + "type": "text", + "required": true, + "validators": [ + { + "type": "regex", + "pattern": "^[^%<>/\\^$]+$", + "errorMsg": "Please enter name without special characters ^%<>/\\^$" + } + ] + }, + { + "field": "interval", + "label": "Interval (in seconds)", + "type": "text", + "defaultValue": 3600, + "validators": [ + { + "type": "number", + "range": [ + 0, + 31536000 + ] + } + ] + }, + { + "field": "sourcetype", + "label": "Source Type", + "type": "text", + "defaultValue": "default:sourcetype" + }, + { + "field": "index", + "label": "Index", + "type": "singleSelect", + "required": true, + "defaultValue": "default", + "options": { + "createSearchChoice": true, + "endpointUrl": "data/indexes", + "denyList": "^_.*$" + } + } + ] + } + ] + } + }, + "meta": { + "name": "Splunk_TA_UCCExample", + "restRoot": "splunk_ta_uccexample", + "version": "1.0.0", + "displayName": "Splunk UCC test Add-on", + "schemaVersion": "0.0.3" + } +} \ No newline at end of file