diff --git a/docs/generated_files.md b/docs/generated_files.md index 582f41de5..aab74c463 100644 --- a/docs/generated_files.md +++ b/docs/generated_files.md @@ -16,10 +16,10 @@ The following table describes the files generated by UCC framework. | tags.conf | output/<YOUR_ADDON_NAME>/default | Generates `tags.conf` file based on the `eventtypes.conf` created for custom alert actions. | | _account.conf | output/<YOUR_ADDON_NAME>/README | Generates `_account.conf.spec` file for the configuration mentioned in globalConfig | | _settings.conf | output/<YOUR_ADDON_NAME>/README | Generates `_settings.conf.spec` file for the Proxy, Logging or Custom Tab mentioned in globalConfig | -| configuration.xml | output/<YOUR_ADDON_NAME>/default/data/ui/views | Generates configuration.xml file in `default/data/ui/views/` folder if globalConfig is present. | -| dashboard.xml | output/<YOUR_ADDON_NAME>/default/data/ui/views | Generates dashboard.xml file based on dashboard configuration present in globalConfig in `default/data/ui/views` folder. | -| default.xml | output/<YOUR_ADDON_NAME>/default/data/ui/nav | Generates default.xml file based on configs present in globalConfigin in `default/data/ui/nav` folder. | +| configuration.xml | output/<YOUR_ADDON_NAME>/default/data/ui/views | Generates configuration.xml file in `default/data/ui/views/` folder if configuration is defined in globalConfig. | +| dashboard.xml | output/<YOUR_ADDON_NAME>/default/data/ui/views | Generates dashboard.xml file based on dashboard configuration present in globalConfig, in `default/data/ui/views` folder. | +| default.xml | output/<YOUR_ADDON_NAME>/default/data/ui/nav | Generates default.xml file based on configs present in globalConfig, in `default/data/ui/nav` folder. | | inputs.xml | output/<YOUR_ADDON_NAME>/default/data/ui/views | Generates inputs.xml based on inputs configuration present in globalConfig, in `default/data/ui/views/inputs.xml` folder | -| _redirect.xml | output/<YOUR_ADDON_NAME>/default/data/ui/views | Generates ta_name_redirect.xml file, if oauth is mentioned in globalConfig,in `default/data/ui/views/` folder. | -| _.html | output/<YOUR_ADDON_NAME>/default/data/ui/alerts | Generates `alert_name.html` file based on alerts configuration present in globalConfig in `default/data/ui/alerts` folder. | +| _redirect.xml | output/<YOUR_ADDON_NAME>/default/data/ui/views | Generates ta_name_redirect.xml file, if oauth is mentioned in globalConfig, in `default/data/ui/views/` folder. | +| _.html | output/<YOUR_ADDON_NAME>/default/data/ui/alerts | Generates `alert_name.html` file based on alerts configuration present in globalConfig, in `default/data/ui/alerts` folder. | diff --git a/splunk_add_on_ucc_framework/commands/openapi_generator/ucc_to_oas.py b/splunk_add_on_ucc_framework/commands/openapi_generator/ucc_to_oas.py index b030ce547..44db362b1 100644 --- a/splunk_add_on_ucc_framework/commands/openapi_generator/ucc_to_oas.py +++ b/splunk_add_on_ucc_framework/commands/openapi_generator/ucc_to_oas.py @@ -158,15 +158,17 @@ def __add_schemas_object( ) -> OpenAPIObject: if open_api_object.components is not None: open_api_object.components.schemas = {} - for tab in global_config.pages.configuration.tabs: # type: ignore[attr-defined] - schema_name, schema_object = __get_schema_object( - name=tab.name, entities=tab.entity - ) - open_api_object.components.schemas[schema_name] = schema_object - schema_name, schema_object = __get_schema_object( - name=tab.name, entities=tab.entity, without=["name"] - ) - open_api_object.components.schemas[schema_name] = schema_object + pages = getattr(global_config, "pages", None) + if hasattr(pages, "configuration"): + for tab in global_config.pages.configuration.tabs: # type: ignore[attr-defined] + schema_name, schema_object = __get_schema_object( + name=tab.name, entities=tab.entity + ) + open_api_object.components.schemas[schema_name] = schema_object + schema_name, schema_object = __get_schema_object( + name=tab.name, entities=tab.entity, without=["name"] + ) + open_api_object.components.schemas[schema_name] = schema_object if hasattr(global_config.pages, "inputs") and hasattr( # type: ignore[attr-defined] global_config.pages.inputs, "services" # type: ignore[attr-defined] ): @@ -378,18 +380,20 @@ def __assign_ta_paths( def __add_paths( open_api_object: OpenAPIObject, global_config: DataClasses ) -> OpenAPIObject: - for tab in global_config.pages.configuration.tabs: # type: ignore[attr-defined] - open_api_object = __assign_ta_paths( - open_api_object=open_api_object, - path=f"/{global_config.meta.restRoot}_{tab.name}" # type: ignore[attr-defined] - if hasattr(tab, "table") - else f"/{global_config.meta.restRoot}_settings/{tab.name}", # type: ignore[attr-defined] - path_name=tab.name, - actions=tab.table.actions - if hasattr(tab, "table") and hasattr(tab.table, "actions") - else None, - page=GloblaConfigPages.CONFIGURATION, - ) + pages = getattr(global_config, "pages", None) + if hasattr(pages, "configuration"): + for tab in global_config.pages.configuration.tabs: # type: ignore[attr-defined] + open_api_object = __assign_ta_paths( + open_api_object=open_api_object, + path=f"/{global_config.meta.restRoot}_{tab.name}" # type: ignore[attr-defined] + if hasattr(tab, "table") + else f"/{global_config.meta.restRoot}_settings/{tab.name}", # type: ignore[attr-defined] + path_name=tab.name, + actions=tab.table.actions + if hasattr(tab, "table") and hasattr(tab.table, "actions") + else None, + page=GloblaConfigPages.CONFIGURATION, + ) if hasattr(global_config.pages, "inputs") and hasattr( # type: ignore[attr-defined] global_config.pages.inputs, "services" # type: ignore[attr-defined] ): diff --git a/splunk_add_on_ucc_framework/data_ui_generator.py b/splunk_add_on_ucc_framework/data_ui_generator.py index 315c88fa6..3456a3734 100644 --- a/splunk_add_on_ucc_framework/data_ui_generator.py +++ b/splunk_add_on_ucc_framework/data_ui_generator.py @@ -19,8 +19,7 @@ # nosemgrep: splunk.use-defused-xml from xml.etree import ElementTree as ET from defusedxml import minidom - -DEFAULT_VIEW = "configuration" +from typing import Optional def _pretty_print_xml(string: str) -> str: @@ -31,7 +30,10 @@ def _pretty_print_xml(string: str) -> str: def generate_nav_default_xml( - include_inputs: bool, include_dashboard: bool, default_view: str + include_inputs: bool, + include_dashboard: bool, + include_configuration: bool, + default_view: Optional[str], ) -> str: """ Generates `default/data/ui/nav/default.xml` file. @@ -39,15 +41,30 @@ def generate_nav_default_xml( The validation is being done in `_validate_meta_default_view` function from `global_config_validator.py` file. """ nav = ET.Element("nav") + if default_view is None: + # we do this calculation as all the below properties are now optional + if include_configuration: + default_view = "configuration" + elif include_inputs: + default_view = "inputs" + elif include_dashboard: + default_view = "dashboard" + else: + default_view = "search" + if include_inputs: if default_view == "inputs": ET.SubElement(nav, "view", attrib={"name": "inputs", "default": "true"}) else: ET.SubElement(nav, "view", attrib={"name": "inputs"}) - if default_view == "configuration": - ET.SubElement(nav, "view", attrib={"name": "configuration", "default": "true"}) - else: - ET.SubElement(nav, "view", attrib={"name": "configuration"}) + + if include_configuration: + if default_view == "configuration": + ET.SubElement( + nav, "view", attrib={"name": "configuration", "default": "true"} + ) + else: + ET.SubElement(nav, "view", attrib={"name": "configuration"}) if include_dashboard: if default_view == "dashboard": ET.SubElement(nav, "view", attrib={"name": "dashboard", "default": "true"}) @@ -57,6 +74,7 @@ def generate_nav_default_xml( ET.SubElement(nav, "view", attrib={"name": "search", "default": "true"}) else: ET.SubElement(nav, "view", attrib={"name": "search"}) + nav_as_string = ET.tostring(nav, encoding="unicode") return _pretty_print_xml(nav_as_string) diff --git a/splunk_add_on_ucc_framework/generators/html_files/create_alert_actions_html.py b/splunk_add_on_ucc_framework/generators/html_files/create_alert_actions_html.py index 78cafbbd7..2d23c029f 100644 --- a/splunk_add_on_ucc_framework/generators/html_files/create_alert_actions_html.py +++ b/splunk_add_on_ucc_framework/generators/html_files/create_alert_actions_html.py @@ -25,7 +25,7 @@ class AlertActionsHtml(HTMLGenerator): __description__ = ( - "Generates `alert_name.html` file based on alerts configuration present in globalConfig" + "Generates `alert_name.html` file based on alerts configuration present in globalConfig," " in `default/data/ui/alerts` folder." ) diff --git a/splunk_add_on_ucc_framework/generators/xml_files/create_configuration_xml.py b/splunk_add_on_ucc_framework/generators/xml_files/create_configuration_xml.py index 41dc4c86f..507eeb8d1 100644 --- a/splunk_add_on_ucc_framework/generators/xml_files/create_configuration_xml.py +++ b/splunk_add_on_ucc_framework/generators/xml_files/create_configuration_xml.py @@ -14,21 +14,27 @@ # limitations under the License. # from splunk_add_on_ucc_framework.generators.xml_files import XMLGenerator -from typing import Any, Dict +from typing import Any, Dict, Union from splunk_add_on_ucc_framework import data_ui_generator class ConfigurationXml(XMLGenerator): - __description__ = "Generates configuration.xml file in `default/data/ui/views/` folder if globalConfig is present." + __description__ = ( + "Generates configuration.xml file in `default/data/ui/views/` folder if " + "configuration is defined in globalConfig." + ) def _set_attributes(self, **kwargs: Any) -> None: - self.configuration_xml_content = ( - data_ui_generator.generate_views_configuration_xml( - self._addon_name, + if self._global_config and self._global_config.has_configuration(): + self.configuration_xml_content = ( + data_ui_generator.generate_views_configuration_xml( + self._addon_name, + ) ) - ) - def generate_xml(self) -> Dict[str, str]: + def generate_xml(self) -> Union[Dict[str, str], None]: + if self._global_config and not self._global_config.has_configuration(): + return None file_path = self.get_file_output_path( ["default", "data", "ui", "views", "configuration.xml"] ) diff --git a/splunk_add_on_ucc_framework/generators/xml_files/create_dashboard_xml.py b/splunk_add_on_ucc_framework/generators/xml_files/create_dashboard_xml.py index 14381523c..79256e01f 100644 --- a/splunk_add_on_ucc_framework/generators/xml_files/create_dashboard_xml.py +++ b/splunk_add_on_ucc_framework/generators/xml_files/create_dashboard_xml.py @@ -20,7 +20,7 @@ class DashboardXml(XMLGenerator): __description__ = ( - "Generates dashboard.xml file based on dashboard configuration present in globalConfig" + "Generates dashboard.xml file based on dashboard configuration present in globalConfig," " in `default/data/ui/views` folder." ) diff --git a/splunk_add_on_ucc_framework/generators/xml_files/create_default_xml.py b/splunk_add_on_ucc_framework/generators/xml_files/create_default_xml.py index a9e9b57d5..800560b7e 100644 --- a/splunk_add_on_ucc_framework/generators/xml_files/create_default_xml.py +++ b/splunk_add_on_ucc_framework/generators/xml_files/create_default_xml.py @@ -24,8 +24,8 @@ class DefaultXml(XMLGenerator): __description__ = ( - "Generates default.xml file based on configs present in globalConfig" - "in in `default/data/ui/nav` folder." + "Generates default.xml file based on configs present in globalConfig," + " in `default/data/ui/nav` folder." ) def _set_attributes(self, **kwargs: Any) -> None: @@ -45,9 +45,8 @@ def _set_attributes(self, **kwargs: Any) -> None: self.default_xml_content = data_ui_generator.generate_nav_default_xml( include_inputs=self._global_config.has_inputs(), include_dashboard=self._global_config.has_dashboard(), - default_view=self._global_config.meta.get( - "default_view", data_ui_generator.DEFAULT_VIEW - ), + include_configuration=self._global_config.has_configuration(), + default_view=self._global_config.meta.get("default_view"), ) def generate_xml(self) -> Dict[str, str]: diff --git a/splunk_add_on_ucc_framework/generators/xml_files/create_redirect_xml.py b/splunk_add_on_ucc_framework/generators/xml_files/create_redirect_xml.py index dd27640c8..7c668f1eb 100644 --- a/splunk_add_on_ucc_framework/generators/xml_files/create_redirect_xml.py +++ b/splunk_add_on_ucc_framework/generators/xml_files/create_redirect_xml.py @@ -21,7 +21,7 @@ class RedirectXml(XMLGenerator): __description__ = ( "Generates ta_name_redirect.xml file, if oauth is mentioned in globalConfig," - "in `default/data/ui/views/` folder." + " in `default/data/ui/views/` folder." ) def _set_attributes(self, **kwargs: Any) -> None: diff --git a/splunk_add_on_ucc_framework/global_config.py b/splunk_add_on_ucc_framework/global_config.py index 09716b0d1..91852e3da 100644 --- a/splunk_add_on_ucc_framework/global_config.py +++ b/splunk_add_on_ucc_framework/global_config.py @@ -88,11 +88,14 @@ def expand(self) -> None: self.expand_entities() def expand_tabs(self) -> None: - for i, tab in enumerate(self._content["pages"]["configuration"]["tabs"]): - self._content["pages"]["configuration"]["tabs"][i] = resolve_tab(tab) + if self.has_configuration(): + for i, tab in enumerate(self._content["pages"]["configuration"]["tabs"]): + self._content["pages"]["configuration"]["tabs"][i] = resolve_tab(tab) def expand_entities(self) -> None: - self._expand_entities(self._content["pages"]["configuration"]["tabs"]) + self._expand_entities( + self._content["pages"].get("configuration", {}).get("tabs") + ) self._expand_entities(self._content["pages"].get("inputs", {}).get("services")) self._expand_entities(self._content.get("alerts")) @@ -117,7 +120,9 @@ def inputs(self) -> List[Any]: @property def tabs(self) -> List[Any]: - return self._content["pages"]["configuration"]["tabs"] + if "configuration" in self._content["pages"]: + return self._content["pages"]["configuration"]["tabs"] + return [] @property def dashboard(self) -> Dict[str, Any]: @@ -207,6 +212,9 @@ def add_ucc_version(self, version: str) -> None: def has_inputs(self) -> bool: return bool(self.inputs) + def has_configuration(self) -> bool: + return bool(self.tabs) + def has_alerts(self) -> bool: return bool(self.alerts) diff --git a/splunk_add_on_ucc_framework/global_config_update.py b/splunk_add_on_ucc_framework/global_config_update.py index 47128e1b4..246ba78a8 100644 --- a/splunk_add_on_ucc_framework/global_config_update.py +++ b/splunk_add_on_ucc_framework/global_config_update.py @@ -276,7 +276,7 @@ def _dump_with_migrated_entities( global_config.content["pages"].get("inputs", {}).get("services"), entity_type ) _collapse_entities( - global_config.content["pages"]["configuration"].get("tabs"), entity_type + global_config.content["pages"].get("configuration", {}).get("tabs"), entity_type ) _collapse_entities(global_config.content.get("alerts"), entity_type) diff --git a/splunk_add_on_ucc_framework/global_config_validator.py b/splunk_add_on_ucc_framework/global_config_validator.py index f6d2fa3d4..702af4935 100644 --- a/splunk_add_on_ucc_framework/global_config_validator.py +++ b/splunk_add_on_ucc_framework/global_config_validator.py @@ -25,7 +25,6 @@ from splunk_add_on_ucc_framework import dashboard as dashboard_lib from splunk_add_on_ucc_framework import global_config as global_config_lib -from splunk_add_on_ucc_framework import data_ui_generator from splunk_add_on_ucc_framework.tabs import resolve_tab, Tab from splunk_add_on_ucc_framework.exceptions import GlobalConfigValidatorException @@ -54,10 +53,13 @@ def __init__(self, source_dir: str, global_config: global_config_lib.GlobalConfi self._config = global_config.content @property - def config_tabs(self) -> List[Tab]: - return [ - resolve_tab(tab) for tab in self._config["pages"]["configuration"]["tabs"] - ] + def config_tabs(self) -> List[Any]: + if self._global_config.has_configuration(): + return [ + resolve_tab(tab) + for tab in self._config["pages"]["configuration"]["tabs"] + ] + return [] def _validate_config_against_schema(self) -> None: """ @@ -430,7 +432,6 @@ def _validate_duplicates(self) -> None: not required in schema, so this checks if globalConfig has inputs """ pages = self._config["pages"] - self._validate_tabs_duplicates(self.config_tabs) inputs = pages.get("inputs") @@ -700,9 +701,14 @@ def _validate_field_modifications(self) -> None: ) def _validate_meta_default_view(self) -> None: - default_view = self._global_config.meta.get( - "defaultView", data_ui_generator.DEFAULT_VIEW - ) + default_view = self._global_config.meta.get("defaultView") + if ( + default_view == "configuration" + and not self._global_config.has_configuration() + ): + raise GlobalConfigValidatorException( + 'meta.defaultView == "configuration" but there is no configuration defined in globalConfig' + ) if default_view == "inputs" and not self._global_config.has_inputs(): raise GlobalConfigValidatorException( 'meta.defaultView == "inputs" but there is no inputs defined in globalConfig' @@ -715,8 +721,8 @@ def _validate_meta_default_view(self) -> None: def validate(self) -> None: self._validate_config_against_schema() self._validate_configuration_tab_table_has_name_field() - self._validate_custom_rest_handlers() self._validate_file_type_entity() + self._validate_custom_rest_handlers() self._validate_validators() self._validate_multilevel_menu() self._validate_duplicates() diff --git a/splunk_add_on_ucc_framework/schema/schema.json b/splunk_add_on_ucc_framework/schema/schema.json index f5f5e7a8b..2d02a0391 100644 --- a/splunk_add_on_ucc_framework/schema/schema.json +++ b/splunk_add_on_ucc_framework/schema/schema.json @@ -2677,9 +2677,6 @@ "$ref": "#/definitions/DashboardPage" } }, - "required": [ - "configuration" - ], "additionalProperties": false }, "RegexValidator": { diff --git a/tests/smoke/test_ucc_build.py b/tests/smoke/test_ucc_build.py index 1566a4108..597f32cab 100644 --- a/tests/smoke/test_ucc_build.py +++ b/tests/smoke/test_ucc_build.py @@ -307,6 +307,75 @@ def test_ucc_generate_with_configuration(): assert path.exists(actual_file_path) +def test_ucc_generate_with_no_configuration(): + with tempfile.TemporaryDirectory() as temp_dir: + package_folder = path.join( + path.dirname(path.realpath(__file__)), + "..", + "testdata", + "test_addons", + "package_global_config_no_configuration", + "package", + ) + build.generate( + source=package_folder, output_directory=temp_dir, addon_version="1.1.1" + ) + + expected_folder = path.join( + path.dirname(__file__), + "..", + "testdata", + "expected_addons", + "expected_addon_no_configuration", + "Splunk_TA_UCCExample", + ) + actual_folder = path.join(temp_dir, "Splunk_TA_UCCExample") + + # app.manifest and appserver/static/js/build/globalConfig.json + # should be included too, but they may introduce flaky tests as + # their content depends on the git commit. + _compare_app_conf(expected_folder, actual_folder) + # Expected add-on package folder does not have "lib" in it. + files_to_be_equal = [ + ("README.txt",), + ("default", "restmap.conf"), + ("default", "inputs.conf"), + ("default", "web.conf"), + ("default", "data", "ui", "nav", "default.xml"), + ("default", "data", "ui", "views", "inputs.xml"), + ("bin", "example_input_one.py"), + ("bin", "example_input_two.py"), + ("bin", "import_declare_test.py"), + ("bin", "splunk_ta_uccexample_rh_example_input_one.py"), + ("bin", "splunk_ta_uccexample_rh_example_input_two.py"), + ("README", "inputs.conf.spec"), + ("metadata", "default.meta"), + ] + helpers.compare_file_content( + files_to_be_equal, + expected_folder, + actual_folder, + ) + files_to_exist = [ + ("static", "appIcon.png"), + ("static", "appIcon_2x.png"), + ("static", "appIconAlt.png"), + ("static", "appIconAlt_2x.png"), + ] + for f in files_to_exist: + actual_file_path = path.join(actual_folder, *f) + assert path.exists(actual_file_path) + + files_should_be_absent = [ + ("default", "data", "ui", "views", "configuration.xml"), + ("README", "splunk_ta_uccexample_account.conf.spec"), + ("README", "splunk_ta_uccexample_settings.conf.spec"), + ] + for af in files_should_be_absent: + actual_file_path = path.join(actual_folder, *af) + assert not path.exists(actual_file_path) + + def test_ucc_generate_with_configuration_files_only(): with tempfile.TemporaryDirectory() as temp_dir: package_folder = path.join( diff --git a/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/README.txt b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/README.txt new file mode 100644 index 000000000..530a9e548 --- /dev/null +++ b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/README.txt @@ -0,0 +1 @@ +Just a readme \ No newline at end of file diff --git a/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/README/inputs.conf.spec b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/README/inputs.conf.spec new file mode 100644 index 000000000..9e02e25ab --- /dev/null +++ b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/README/inputs.conf.spec @@ -0,0 +1,5 @@ +[example_input_one://] +interval = Time interval of the data input, in seconds. + +[example_input_two://] +interval = Time interval of the data input, in seconds. diff --git a/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/VERSION b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/VERSION new file mode 100644 index 000000000..380654aa1 --- /dev/null +++ b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/VERSION @@ -0,0 +1,2 @@ +5.55.0+2b3a9e8d9 +5.55.0+2b3a9e8d9 \ No newline at end of file diff --git a/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/app.manifest b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/app.manifest new file mode 100644 index 000000000..c14ffb4ed --- /dev/null +++ b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/app.manifest @@ -0,0 +1,54 @@ +{ + "dependencies": null, + "incompatibleApps": null, + "info": { + "author": [ + { + "company": null, + "email": "addonfactory@splunk.com", + "name": "Splunk" + } + ], + "classification": { + "categories": [], + "developmentStatus": null, + "intendedAudience": null + }, + "commonInformationModels": null, + "description": "Description of Splunk Add-on for UCC Example", + "id": { + "group": null, + "name": "Splunk_TA_UCCExample", + "version": "5.55.0+2b3a9e8d9" + }, + "license": { + "name": "Apache-2.0", + "text": "LICENSES/Apache-2.0.txt", + "uri": "https://www.apache.org/licenses/LICENSE-2.0" + }, + "privacyPolicy": { + "name": null, + "text": null, + "uri": null + }, + "releaseDate": null, + "releaseNotes": { + "name": null, + "text": "./README.txt", + "uri": null + }, + "title": "Splunk Add-on for UCC Example" + }, + "inputGroups": null, + "platformRequirements": null, + "schemaVersion": "2.0.0", + "supportedDeployments": [ + "_standalone", + "_distributed" + ], + "targetWorkloads": [ + "_search_heads", + "_indexers" + ], + "tasks": null +} \ No newline at end of file diff --git a/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/appserver/static/js/build/globalConfig.json b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/appserver/static/js/build/globalConfig.json new file mode 100644 index 000000000..57cf3224e --- /dev/null +++ b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/appserver/static/js/build/globalConfig.json @@ -0,0 +1,191 @@ +{ + "pages": { + "inputs": { + "title": "Inputs", + "services": [ + { + "name": "example_input_one", + "description": "This is a description for Input One", + "title": "Example Input One", + "entity": [ + { + "type": "text", + "label": "Name", + "validators": [ + { + "type": "regex", + "errorMsg": "Input Name must begin with a letter and consist exclusively of alphanumeric characters and underscores.", + "pattern": "^[a-zA-Z]\\w*$" + }, + { + "type": "string", + "errorMsg": "Length of input name should be between 1 and 100", + "minLength": 1, + "maxLength": 100 + } + ], + "field": "name", + "help": "A unique name for the data input.", + "required": true + }, + { + "type": "text", + "field": "interval", + "label": "Interval", + "validators": [ + { + "type": "regex", + "errorMsg": "Interval must be either a non-negative number, CRON interval or -1.", + "pattern": "^((?:-1|\\d+(?:\\.\\d+)?)|(([\\*\\d{1,2}\\,\\-\\/]+\\s){4}[\\*\\d{1,2}\\,\\-\\/]+))$" + } + ], + "help": "Time interval of the data input, in seconds.", + "required": true + } + ], + "table": { + "actions": [ + "edit", + "delete", + "clone" + ], + "header": [ + { + "label": "Name", + "field": "name" + }, + { + "label": "Interval", + "field": "interval" + }, + { + "label": "Status", + "field": "disabled" + } + ], + "moreInfo": [ + { + "label": "Name", + "field": "name" + }, + { + "label": "Interval", + "field": "interval" + }, + { + "label": "Status", + "field": "disabled" + } + ] + }, + "warning": { + "create": { + "message": "Warning text for create mode" + }, + "edit": { + "message": "Warning text for edit mode" + }, + "clone": { + "message": "Warning text for clone mode" + }, + "config": { + "message": "Warning text for config mode" + } + } + }, + { + "name": "example_input_two", + "description": "This is a description for Input Two", + "title": "Example Input Two", + "entity": [ + { + "type": "text", + "label": "Name", + "validators": [ + { + "type": "regex", + "errorMsg": "Input Name must begin with a letter and consist exclusively of alphanumeric characters and underscores.", + "pattern": "^[a-zA-Z]\\w*$" + }, + { + "type": "string", + "errorMsg": "Length of input name should be between 1 and 100", + "minLength": 1, + "maxLength": 100 + } + ], + "field": "name", + "help": "A unique name for the data input.", + "required": true + }, + { + "type": "text", + "field": "interval", + "label": "Interval", + "validators": [ + { + "type": "regex", + "errorMsg": "Interval must be either a non-negative number, CRON interval or -1.", + "pattern": "^((?:-1|\\d+(?:\\.\\d+)?)|(([\\*\\d{1,2}\\,\\-\\/]+\\s){4}[\\*\\d{1,2}\\,\\-\\/]+))$" + } + ], + "help": "Time interval of the data input, in seconds.", + "required": true + } + ], + "table": { + "actions": [ + "edit", + "delete", + "clone" + ], + "header": [ + { + "label": "Name", + "field": "name" + }, + { + "label": "Interval", + "field": "interval" + }, + { + "label": "Status", + "field": "disabled" + } + ], + "moreInfo": [ + { + "label": "Name", + "field": "name" + }, + { + "label": "Interval", + "field": "interval" + }, + { + "label": "Status", + "field": "disabled" + } + ] + }, + "useInputToggleConfirmation": true + } + ] + }, + "dashboard": { + "panels": [ + { + "name": "default" + } + ] + } + }, + "meta": { + "name": "Splunk_TA_UCCExample", + "restRoot": "splunk_ta_uccexample", + "version": "5.55.0+2b3a9e8d9", + "displayName": "Splunk UCC test Add-on", + "schemaVersion": "0.0.9", + "_uccVersion": "5.55.0" + } +} diff --git a/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/appserver/static/js/build/splunk_ta_uccexample_redirect_page.5.5.8R5fd76615.js b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/appserver/static/js/build/splunk_ta_uccexample_redirect_page.5.5.8R5fd76615.js new file mode 100644 index 000000000..a1adc936c --- /dev/null +++ b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/appserver/static/js/build/splunk_ta_uccexample_redirect_page.5.5.8R5fd76615.js @@ -0,0 +1,30 @@ +(() => { + // This method takes param name and searches it from windows url, if found returns it + // eslint-disable-next-line consistent-return + const getUrlParam = (param) => { + let params = window.location.search.substring(1); + params = params.split('&'); + for (let i = 0; i < params.length; i += 1) { + const kv = params[i].split('='); + if (kv[0] === param) { + return kv[1]; + } + } + }; + // Check if we get any error param in url + const error = getUrlParam('error'); + let message = {}; + // If we get error param return the error param + if (error !== undefined) { + message = { error }; + } else { + // Else return the code and state param + const code = getUrlParam('code'); + const state = getUrlParam('state'); + message = { code, state }; + } + // Call the parent windows' getMessage method + window.opener.getMessage(message); + // Close the window + window.close(); +})(); diff --git a/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/appserver/static/openapi.json b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/appserver/static/openapi.json new file mode 100644 index 000000000..9ff181415 --- /dev/null +++ b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/appserver/static/openapi.json @@ -0,0 +1,581 @@ +{ + "openapi": "3.0.0", + "info": { + "title": "Splunk_TA_UCCExample", + "version": "5.55.0+2b3a9e8d9", + "description": "Splunk UCC test Add-on", + "contact": { + "name": "Splunk", + "email": "addonfactory@splunk.com" + }, + "license": { + "name": "Apache-2.0", + "url": "https://www.apache.org/licenses/LICENSE-2.0" + } + }, + "servers": [ + { + "url": "https://{domain}:{port}/servicesNS/-/Splunk_TA_UCCExample", + "variables": { + "domain": { + "default": "localhost" + }, + "port": { + "default": "8089" + } + }, + "description": "Access via management interface" + } + ], + "components": { + "schemas": { + "example_input_one": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "interval": { + "type": "string" + }, + "disabled": { + "type": "string", + "enum": [ + "False", + "True" + ] + } + } + }, + "example_input_one_without_name": { + "type": "object", + "properties": { + "interval": { + "type": "string" + }, + "disabled": { + "type": "string", + "enum": [ + "False", + "True" + ] + } + } + }, + "example_input_one_without_disabled": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "interval": { + "type": "string" + } + } + }, + "example_input_two": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "interval": { + "type": "string" + }, + "disabled": { + "type": "string", + "enum": [ + "False", + "True" + ] + } + } + }, + "example_input_two_without_name": { + "type": "object", + "properties": { + "interval": { + "type": "string" + }, + "disabled": { + "type": "string", + "enum": [ + "False", + "True" + ] + } + } + }, + "example_input_two_without_disabled": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "interval": { + "type": "string" + } + } + } + }, + "securitySchemes": { + "BasicAuth": { + "type": "http", + "scheme": "basic" + } + } + }, + "paths": { + "/splunk_ta_uccexample_example_input_one": { + "get": { + "responses": { + "200": { + "description": "Get list of items for example_input_one", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "entry": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "content": { + "$ref": "#/components/schemas/example_input_one_without_name" + } + } + } + } + } + } + } + } + } + }, + "description": "Get list of items for example_input_one", + "deprecated": false + }, + "post": { + "responses": { + "200": { + "description": "Create item in example_input_one", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "entry": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "content": { + "$ref": "#/components/schemas/example_input_one_without_name" + } + } + } + } + } + } + } + } + } + }, + "description": "Create item in example_input_one", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/example_input_one_without_disabled" + } + } + }, + "required": false + }, + "deprecated": false + }, + "parameters": [ + { + "name": "output_mode", + "in": "query", + "required": true, + "description": "Output mode", + "schema": { + "type": "string", + "enum": [ + "json" + ], + "default": "json" + } + } + ] + }, + "/splunk_ta_uccexample_example_input_one/{name}": { + "get": { + "responses": { + "200": { + "description": "Get example_input_one item details", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "entry": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "content": { + "$ref": "#/components/schemas/example_input_one_without_name" + } + } + } + } + } + } + } + } + } + }, + "description": "Get example_input_one item details", + "deprecated": false + }, + "post": { + "responses": { + "200": { + "description": "Update example_input_one item", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "entry": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "content": { + "$ref": "#/components/schemas/example_input_one_without_name" + } + } + } + } + } + } + } + } + } + }, + "description": "Update example_input_one item", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/example_input_one_without_name" + } + } + }, + "required": false + }, + "deprecated": false + }, + "delete": { + "responses": { + "200": { + "description": "Delete example_input_one item", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "entry": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "content": { + "$ref": "#/components/schemas/example_input_one_without_name" + } + } + } + } + } + } + } + } + } + }, + "description": "Delete example_input_one item", + "deprecated": false + }, + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "description": "The name of the item to operate on", + "schema": { + "type": "string" + } + }, + { + "name": "output_mode", + "in": "query", + "required": true, + "description": "Output mode", + "schema": { + "type": "string", + "enum": [ + "json" + ], + "default": "json" + } + } + ] + }, + "/splunk_ta_uccexample_example_input_two": { + "get": { + "responses": { + "200": { + "description": "Get list of items for example_input_two", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "entry": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "content": { + "$ref": "#/components/schemas/example_input_two_without_name" + } + } + } + } + } + } + } + } + } + }, + "description": "Get list of items for example_input_two", + "deprecated": false + }, + "post": { + "responses": { + "200": { + "description": "Create item in example_input_two", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "entry": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "content": { + "$ref": "#/components/schemas/example_input_two_without_name" + } + } + } + } + } + } + } + } + } + }, + "description": "Create item in example_input_two", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/example_input_two_without_disabled" + } + } + }, + "required": false + }, + "deprecated": false + }, + "parameters": [ + { + "name": "output_mode", + "in": "query", + "required": true, + "description": "Output mode", + "schema": { + "type": "string", + "enum": [ + "json" + ], + "default": "json" + } + } + ] + }, + "/splunk_ta_uccexample_example_input_two/{name}": { + "get": { + "responses": { + "200": { + "description": "Get example_input_two item details", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "entry": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "content": { + "$ref": "#/components/schemas/example_input_two_without_name" + } + } + } + } + } + } + } + } + } + }, + "description": "Get example_input_two item details", + "deprecated": false + }, + "post": { + "responses": { + "200": { + "description": "Update example_input_two item", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "entry": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "content": { + "$ref": "#/components/schemas/example_input_two_without_name" + } + } + } + } + } + } + } + } + } + }, + "description": "Update example_input_two item", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/example_input_two_without_name" + } + } + }, + "required": false + }, + "deprecated": false + }, + "delete": { + "responses": { + "200": { + "description": "Delete example_input_two item", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "entry": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "content": { + "$ref": "#/components/schemas/example_input_two_without_name" + } + } + } + } + } + } + } + } + } + }, + "description": "Delete example_input_two item", + "deprecated": false + }, + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "description": "The name of the item to operate on", + "schema": { + "type": "string" + } + }, + { + "name": "output_mode", + "in": "query", + "required": true, + "description": "Output mode", + "schema": { + "type": "string", + "enum": [ + "json" + ], + "default": "json" + } + } + ] + } + }, + "security": [ + { + "BasicAuth": [] + } + ] +} \ No newline at end of file diff --git a/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/appserver/templates/base.html b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/appserver/templates/base.html new file mode 100644 index 000000000..4110436fd --- /dev/null +++ b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/appserver/templates/base.html @@ -0,0 +1,40 @@ + +<%! app_name = cherrypy.request.path_info.split('/')[3] %>\ + + + + + + ${_('Loading')} + + + + + + + + + + + <% page_path = "/static/app/" + app_name + "/js/build/entry_page.js" %> + + + + diff --git a/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/bin/example_input_one.py b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/bin/example_input_one.py new file mode 100644 index 000000000..3c6317bc2 --- /dev/null +++ b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/bin/example_input_one.py @@ -0,0 +1,47 @@ +import import_declare_test + +import json +import sys + +from splunklib import modularinput as smi + + +class EXAMPLE_INPUT_ONE(smi.Script): + def __init__(self): + super(EXAMPLE_INPUT_ONE, self).__init__() + + def get_scheme(self): + scheme = smi.Scheme('example_input_one') + scheme.description = 'Example Input One' + scheme.use_external_validation = True + scheme.streaming_mode_xml = True + scheme.use_single_instance = False + + scheme.add_argument( + smi.Argument( + 'name', + title='Name', + description='Name', + required_on_create=True + ) + ) + return scheme + + def validate_input(self, definition: smi.ValidationDefinition): + return + + def stream_events(self, inputs: smi.InputDefinition, ew: smi.EventWriter): + input_items = [{'count': len(inputs.inputs)}] + for input_name, input_item in inputs.inputs.items(): + input_item['name'] = input_name + input_items.append(input_item) + event = smi.Event( + data=json.dumps(input_items), + sourcetype='example_input_one', + ) + ew.write_event(event) + + +if __name__ == '__main__': + exit_code = EXAMPLE_INPUT_ONE().run(sys.argv) + sys.exit(exit_code) \ No newline at end of file diff --git a/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/bin/example_input_two.py b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/bin/example_input_two.py new file mode 100644 index 000000000..8b702d393 --- /dev/null +++ b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/bin/example_input_two.py @@ -0,0 +1,47 @@ +import import_declare_test + +import json +import sys + +from splunklib import modularinput as smi + + +class EXAMPLE_INPUT_TWO(smi.Script): + def __init__(self): + super(EXAMPLE_INPUT_TWO, self).__init__() + + def get_scheme(self): + scheme = smi.Scheme('example_input_two') + scheme.description = 'Example Input Two' + scheme.use_external_validation = True + scheme.streaming_mode_xml = True + scheme.use_single_instance = False + + scheme.add_argument( + smi.Argument( + 'name', + title='Name', + description='Name', + required_on_create=True + ) + ) + return scheme + + def validate_input(self, definition: smi.ValidationDefinition): + return + + def stream_events(self, inputs: smi.InputDefinition, ew: smi.EventWriter): + input_items = [{'count': len(inputs.inputs)}] + for input_name, input_item in inputs.inputs.items(): + input_item['name'] = input_name + input_items.append(input_item) + event = smi.Event( + data=json.dumps(input_items), + sourcetype='example_input_two', + ) + ew.write_event(event) + + +if __name__ == '__main__': + exit_code = EXAMPLE_INPUT_TWO().run(sys.argv) + sys.exit(exit_code) \ No newline at end of file diff --git a/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/bin/import_declare_test.py b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/bin/import_declare_test.py new file mode 100644 index 000000000..677be6665 --- /dev/null +++ b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/bin/import_declare_test.py @@ -0,0 +1,12 @@ + +import os +import sys +import re +from os.path import dirname + +ta_name = 'Splunk_TA_UCCExample' +pattern = re.compile(r'[\\/]etc[\\/]apps[\\/][^\\/]+[\\/]bin[\\/]?$') +new_paths = [path for path in sys.path if not pattern.search(path) or ta_name in path] +new_paths.insert(0, os.path.join(dirname(dirname(__file__)), "lib")) +new_paths.insert(0, os.path.sep.join([os.path.dirname(__file__), ta_name])) +sys.path = new_paths diff --git a/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_example_input_one.py b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_example_input_one.py new file mode 100644 index 000000000..d79c549c2 --- /dev/null +++ b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_example_input_one.py @@ -0,0 +1,68 @@ + +import import_declare_test + +from splunktaucclib.rest_handler.endpoint import ( + field, + validator, + RestModel, + DataInputModel, +) +from splunktaucclib.rest_handler import admin_external, util +from splunktaucclib.rest_handler.admin_external import AdminExternalHandler +import logging + +util.remove_http_proxy_env_vars() + + +special_fields = [ + field.RestField( + 'name', + required=True, + encrypted=False, + default=None, + validator=validator.AllOf( + validator.Pattern( + regex=r"""^[a-zA-Z]\w*$""", + ), + validator.String( + max_len=100, + min_len=1, + ) + ) + ) +] + +fields = [ + field.RestField( + 'interval', + required=True, + encrypted=False, + default=None, + validator=validator.Pattern( + regex=r"""^((?:-1|\d+(?:\.\d+)?)|(([\*\d{1,2}\,\-\/]+\s){4}[\*\d{1,2}\,\-\/]+))$""", + ) + ), + + field.RestField( + 'disabled', + required=False, + validator=None + ) + +] +model = RestModel(fields, name=None, special_fields=special_fields) + + + +endpoint = DataInputModel( + 'example_input_one', + model, +) + + +if __name__ == '__main__': + logging.getLogger().addHandler(logging.NullHandler()) + admin_external.handle( + endpoint, + handler=AdminExternalHandler, + ) diff --git a/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_example_input_two.py b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_example_input_two.py new file mode 100644 index 000000000..72c810b8b --- /dev/null +++ b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_example_input_two.py @@ -0,0 +1,68 @@ + +import import_declare_test + +from splunktaucclib.rest_handler.endpoint import ( + field, + validator, + RestModel, + DataInputModel, +) +from splunktaucclib.rest_handler import admin_external, util +from splunktaucclib.rest_handler.admin_external import AdminExternalHandler +import logging + +util.remove_http_proxy_env_vars() + + +special_fields = [ + field.RestField( + 'name', + required=True, + encrypted=False, + default=None, + validator=validator.AllOf( + validator.Pattern( + regex=r"""^[a-zA-Z]\w*$""", + ), + validator.String( + max_len=100, + min_len=1, + ) + ) + ) +] + +fields = [ + field.RestField( + 'interval', + required=True, + encrypted=False, + default=None, + validator=validator.Pattern( + regex=r"""^((?:-1|\d+(?:\.\d+)?)|(([\*\d{1,2}\,\-\/]+\s){4}[\*\d{1,2}\,\-\/]+))$""", + ) + ), + + field.RestField( + 'disabled', + required=False, + validator=None + ) + +] +model = RestModel(fields, name=None, special_fields=special_fields) + + + +endpoint = DataInputModel( + 'example_input_two', + model, +) + + +if __name__ == '__main__': + logging.getLogger().addHandler(logging.NullHandler()) + admin_external.handle( + endpoint, + handler=AdminExternalHandler, + ) diff --git a/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/default/app.conf b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/default/app.conf new file mode 100644 index 000000000..11cdab12a --- /dev/null +++ b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/default/app.conf @@ -0,0 +1,21 @@ +[launcher] +version = 5.55.0+2b3a9e8d9 +description = Description of Splunk Add-on for UCC Example +author = Splunk + +[id] +version = 5.55.0+2b3a9e8d9 +name = Splunk_TA_UCCExample + +[install] +build = 1736241728 +is_configured = false +state = enabled + +[package] +id = Splunk_TA_UCCExample +check_for_updates = true + +[ui] +label = Splunk Add-on for UCC Example +is_visible = true diff --git a/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/default/data/ui/nav/default.xml b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/default/data/ui/nav/default.xml new file mode 100644 index 000000000..6a33c539f --- /dev/null +++ b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/default/data/ui/nav/default.xml @@ -0,0 +1,6 @@ + + diff --git a/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/default/data/ui/views/dashboard.xml b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/default/data/ui/views/dashboard.xml new file mode 100644 index 000000000..3f7765605 --- /dev/null +++ b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/default/data/ui/views/dashboard.xml @@ -0,0 +1,4 @@ + + + + diff --git a/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/default/data/ui/views/inputs.xml b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/default/data/ui/views/inputs.xml new file mode 100644 index 000000000..e9246677b --- /dev/null +++ b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/default/data/ui/views/inputs.xml @@ -0,0 +1,4 @@ + + + + diff --git a/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/default/inputs.conf b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/default/inputs.conf new file mode 100644 index 000000000..8f983c07c --- /dev/null +++ b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/default/inputs.conf @@ -0,0 +1,5 @@ +[example_input_one] +python.version = python3 + +[example_input_two] +python.version = python3 diff --git a/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/default/restmap.conf b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/default/restmap.conf new file mode 100644 index 000000000..9923431f1 --- /dev/null +++ b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/default/restmap.conf @@ -0,0 +1,17 @@ +[admin:splunk_ta_uccexample] +match = / +members = splunk_ta_uccexample_example_input_one, splunk_ta_uccexample_example_input_two + +[admin_external:splunk_ta_uccexample_example_input_one] +handlertype = python +python.version = python3 +handlerfile = splunk_ta_uccexample_rh_example_input_one.py +handleractions = edit, list, remove, create +handlerpersistentmode = true + +[admin_external:splunk_ta_uccexample_example_input_two] +handlertype = python +python.version = python3 +handlerfile = splunk_ta_uccexample_rh_example_input_two.py +handleractions = edit, list, remove, create +handlerpersistentmode = true diff --git a/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/default/web.conf b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/default/web.conf new file mode 100644 index 000000000..200298670 --- /dev/null +++ b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/default/web.conf @@ -0,0 +1,15 @@ +[expose:splunk_ta_uccexample_example_input_one] +pattern = splunk_ta_uccexample_example_input_one +methods = POST, GET + +[expose:splunk_ta_uccexample_example_input_one_specified] +pattern = splunk_ta_uccexample_example_input_one/* +methods = POST, GET, DELETE + +[expose:splunk_ta_uccexample_example_input_two] +pattern = splunk_ta_uccexample_example_input_two +methods = POST, GET + +[expose:splunk_ta_uccexample_example_input_two_specified] +pattern = splunk_ta_uccexample_example_input_two/* +methods = POST, GET, DELETE diff --git a/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/metadata/default.meta b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/metadata/default.meta new file mode 100644 index 000000000..1231cfad5 --- /dev/null +++ b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/metadata/default.meta @@ -0,0 +1,7 @@ + +# Application-level permissions + +[] +owner = admin +access = read : [ * ], write : [ admin, sc_admin ] +export = system diff --git a/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/static/appIcon.png b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/static/appIcon.png new file mode 100644 index 000000000..88f67e725 Binary files /dev/null and b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/static/appIcon.png differ diff --git a/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/static/appIconAlt.png b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/static/appIconAlt.png new file mode 100644 index 000000000..88f67e725 Binary files /dev/null and b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/static/appIconAlt.png differ diff --git a/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/static/appIconAlt_2x.png b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/static/appIconAlt_2x.png new file mode 100644 index 000000000..c638b3f15 Binary files /dev/null and b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/static/appIconAlt_2x.png differ diff --git a/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/static/appIcon_2x.png b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/static/appIcon_2x.png new file mode 100644 index 000000000..c638b3f15 Binary files /dev/null and b/tests/testdata/expected_addons/expected_addon_no_configuration/Splunk_TA_UCCExample/static/appIcon_2x.png differ diff --git a/tests/testdata/test_addons/package_global_config_no_configuration/globalConfig.json b/tests/testdata/test_addons/package_global_config_no_configuration/globalConfig.json new file mode 100644 index 000000000..1846052e4 --- /dev/null +++ b/tests/testdata/test_addons/package_global_config_no_configuration/globalConfig.json @@ -0,0 +1,176 @@ +{ + "pages": { + "inputs": { + "title": "Inputs", + "services": [ + { + "name": "example_input_one", + "description": "This is a description for Input One", + "title": "Example Input One", + "entity": [ + { + "type": "text", + "label": "Name", + "validators": [ + { + "type": "regex", + "errorMsg": "Input Name must begin with a letter and consist exclusively of alphanumeric characters and underscores.", + "pattern": "^[a-zA-Z]\\w*$" + }, + { + "type": "string", + "errorMsg": "Length of input name should be between 1 and 100", + "minLength": 1, + "maxLength": 100 + } + ], + "field": "name", + "help": "A unique name for the data input.", + "required": true + }, + { + "type": "interval", + "field": "interval", + "label": "Interval", + "help": "Time interval of the data input, in seconds.", + "required": true + } + ], + "table": { + "actions": [ + "edit", + "delete", + "clone" + ], + "header": [ + { + "label": "Name", + "field": "name" + }, + { + "label": "Interval", + "field": "interval" + }, + { + "label": "Status", + "field": "disabled" + } + ], + "moreInfo": [ + { + "label": "Name", + "field": "name" + }, + { + "label": "Interval", + "field": "interval" + }, + { + "label": "Status", + "field": "disabled" + } + ] + }, + "warning": { + "create": { + "message": "Warning text for create mode" + }, + "edit": { + "message": "Warning text for edit mode" + }, + "clone": { + "message": "Warning text for clone mode" + }, + "config": { + "message": "Warning text for config mode" + } + } + }, + { + "name": "example_input_two", + "description": "This is a description for Input Two", + "title": "Example Input Two", + "entity": [ + { + "type": "text", + "label": "Name", + "validators": [ + { + "type": "regex", + "errorMsg": "Input Name must begin with a letter and consist exclusively of alphanumeric characters and underscores.", + "pattern": "^[a-zA-Z]\\w*$" + }, + { + "type": "string", + "errorMsg": "Length of input name should be between 1 and 100", + "minLength": 1, + "maxLength": 100 + } + ], + "field": "name", + "help": "A unique name for the data input.", + "required": true + }, + { + "type": "interval", + "field": "interval", + "label": "Interval", + "help": "Time interval of the data input, in seconds.", + "required": true + } + ], + "table": { + "actions": [ + "edit", + "delete", + "clone" + ], + "header": [ + { + "label": "Name", + "field": "name" + }, + { + "label": "Interval", + "field": "interval" + }, + { + "label": "Status", + "field": "disabled" + } + ], + "moreInfo": [ + { + "label": "Name", + "field": "name" + }, + { + "label": "Interval", + "field": "interval" + }, + { + "label": "Status", + "field": "disabled" + } + ] + }, + "useInputToggleConfirmation": true + } + ] + }, + "dashboard": { + "panels": [ + { + "name": "default" + } + ] + } + }, + "meta": { + "name": "Splunk_TA_UCCExample", + "restRoot": "splunk_ta_uccexample", + "version": "5.55.0+1bb56cc1", + "displayName": "Splunk UCC test Add-on", + "schemaVersion": "0.0.9" + } +} diff --git a/tests/testdata/test_addons/package_global_config_no_configuration/package/README.txt b/tests/testdata/test_addons/package_global_config_no_configuration/package/README.txt new file mode 100644 index 000000000..530a9e548 --- /dev/null +++ b/tests/testdata/test_addons/package_global_config_no_configuration/package/README.txt @@ -0,0 +1 @@ +Just a readme \ No newline at end of file diff --git a/tests/testdata/test_addons/package_global_config_no_configuration/package/app.manifest b/tests/testdata/test_addons/package_global_config_no_configuration/package/app.manifest new file mode 100644 index 000000000..bc6cb1459 --- /dev/null +++ b/tests/testdata/test_addons/package_global_config_no_configuration/package/app.manifest @@ -0,0 +1,54 @@ +{ + "schemaVersion": "2.0.0", + "info": { + "title": "Splunk Add-on for UCC Example", + "id": { + "group": null, + "name": "Splunk_TA_UCCExample", + "version": "7.0.1" + }, + "author": [ + { + "name": "Splunk", + "email": "addonfactory@splunk.com", + "company": null + } + ], + "releaseDate": null, + "description": "Description of Splunk Add-on for UCC Example", + "classification": { + "intendedAudience": null, + "categories": [], + "developmentStatus": null + }, + "commonInformationModels": null, + "license": { + "name": "Apache-2.0", + "text": "LICENSES/Apache-2.0.txt", + "uri": "https://www.apache.org/licenses/LICENSE-2.0" + }, + "privacyPolicy": { + "name": null, + "text": null, + "uri": null + }, + "releaseNotes": { + "name": null, + "text": "./README.txt", + "uri": null + } + }, + "dependencies": null, + "tasks": null, + "inputGroups": null, + "incompatibleApps": null, + "platformRequirements": null, + "supportedDeployments": [ + "_standalone", + "_distributed" + ], + "targetWorkloads": [ + "_search_heads", + "_indexers" + ] +} \ No newline at end of file diff --git a/tests/testdata/test_addons/package_global_config_no_configuration/package/lib/requirements.txt b/tests/testdata/test_addons/package_global_config_no_configuration/package/lib/requirements.txt new file mode 100644 index 000000000..4e63a1a57 --- /dev/null +++ b/tests/testdata/test_addons/package_global_config_no_configuration/package/lib/requirements.txt @@ -0,0 +1 @@ +splunktaucclib diff --git a/tests/testdata/test_addons/package_global_config_no_configuration/package/static/appIcon.png b/tests/testdata/test_addons/package_global_config_no_configuration/package/static/appIcon.png new file mode 100644 index 000000000..88f67e725 Binary files /dev/null and b/tests/testdata/test_addons/package_global_config_no_configuration/package/static/appIcon.png differ diff --git a/tests/testdata/test_addons/package_global_config_no_configuration/package/static/appIconAlt.png b/tests/testdata/test_addons/package_global_config_no_configuration/package/static/appIconAlt.png new file mode 100644 index 000000000..88f67e725 Binary files /dev/null and b/tests/testdata/test_addons/package_global_config_no_configuration/package/static/appIconAlt.png differ diff --git a/tests/testdata/test_addons/package_global_config_no_configuration/package/static/appIconAlt_2x.png b/tests/testdata/test_addons/package_global_config_no_configuration/package/static/appIconAlt_2x.png new file mode 100644 index 000000000..c638b3f15 Binary files /dev/null and b/tests/testdata/test_addons/package_global_config_no_configuration/package/static/appIconAlt_2x.png differ diff --git a/tests/testdata/test_addons/package_global_config_no_configuration/package/static/appIcon_2x.png b/tests/testdata/test_addons/package_global_config_no_configuration/package/static/appIcon_2x.png new file mode 100644 index 000000000..c638b3f15 Binary files /dev/null and b/tests/testdata/test_addons/package_global_config_no_configuration/package/static/appIcon_2x.png differ diff --git a/tests/unit/commands/openapi_generator/test_ucc_to_oas.py b/tests/unit/commands/openapi_generator/test_ucc_to_oas.py index 15099822f..3d72f2335 100644 --- a/tests/unit/commands/openapi_generator/test_ucc_to_oas.py +++ b/tests/unit/commands/openapi_generator/test_ucc_to_oas.py @@ -12,6 +12,17 @@ def test_transform_config_all(global_config_all_json, app_manifest_correct): assert json.loads(expected_open_api_json) == openapi_object.json +def test_transform_no_configuration( + global_config_no_configuration, app_manifest_correct +): + openapi_object = ucc_to_oas.transform( + global_config_no_configuration, app_manifest_correct + ) + + expected_open_api_json = get_testdata_file("openapi.json.no_config.generated") + assert json.loads(expected_open_api_json) == openapi_object.json + + def test_transform_multiple_account( global_config_multiple_account, app_manifest_correct ): diff --git a/tests/unit/conftest.py b/tests/unit/conftest.py index 99ade67a7..025e1d6c6 100644 --- a/tests/unit/conftest.py +++ b/tests/unit/conftest.py @@ -31,6 +31,15 @@ def global_config_all_json() -> global_config_lib.GlobalConfig: return global_config +@pytest.fixture +def global_config_no_configuration() -> global_config_lib.GlobalConfig: + global_config_path = helpers.get_testdata_file_path( + "global_config_no_configuration.json" + ) + global_config = global_config_lib.GlobalConfig(global_config_path) + return global_config + + @pytest.fixture def global_config_all_yaml() -> global_config_lib.GlobalConfig: global_config_path = helpers.get_testdata_file_path("valid_config.yaml") diff --git a/tests/unit/generators/xml_files/test_create_configuration_xml.py b/tests/unit/generators/xml_files/test_create_configuration_xml.py index 271ef1a7e..e5b7d86ec 100644 --- a/tests/unit/generators/xml_files/test_create_configuration_xml.py +++ b/tests/unit/generators/xml_files/test_create_configuration_xml.py @@ -2,12 +2,17 @@ from unittest.mock import patch, MagicMock from splunk_add_on_ucc_framework.generators.xml_files import ConfigurationXml from splunk_add_on_ucc_framework.global_config import GlobalConfig -import tests.unit.helpers as helpers +from tests.unit.helpers import get_testdata_file_path @fixture def global_config(): - return GlobalConfig(helpers.get_testdata_file_path("valid_config.json")) + return GlobalConfig(get_testdata_file_path("valid_config.json")) + + +@fixture +def global_config_without_configuration(): + return GlobalConfig(get_testdata_file_path("valid_config_no_configuration.json")) @fixture @@ -47,6 +52,51 @@ def test_set_attributes( assert hasattr(config_xml, "configuration_xml_content") +def test_set_attributes_without_configuration( + global_config_without_configuration, + input_dir, + output_dir, + ucc_dir, + ta_name, +): + config_xml = ConfigurationXml( + global_config=global_config_without_configuration, + input_dir=input_dir, + output_dir=output_dir, + ucc_dir=ucc_dir, + addon_name=ta_name, + ) + assert not hasattr(config_xml, "configuration_xml_content") + + +@patch( + "splunk_add_on_ucc_framework.generators.xml_files.ConfigurationXml._set_attributes", + return_value=MagicMock(), +) +def test_generate_xml_without_configuration( + mock_set_attributes, + global_config_without_configuration, + input_dir, + output_dir, + ucc_dir, + ta_name, +): + configuration_xml = ConfigurationXml( + global_config=global_config_without_configuration, + input_dir=input_dir, + output_dir=output_dir, + ucc_dir=ucc_dir, + addon_name=ta_name, + ) + + mock_writer = MagicMock() + with patch.object(configuration_xml, "writer", mock_writer): + file_paths = configuration_xml.generate_xml() + + # Assert that no files are returned since no dashboard is configured + assert file_paths is None + + @patch( "splunk_add_on_ucc_framework.generators.xml_files.ConfigurationXml._set_attributes", return_value=MagicMock(), diff --git a/tests/unit/test_data_ui_generator.py b/tests/unit/test_data_ui_generator.py index 0ca2c14a6..e65337075 100644 --- a/tests/unit/test_data_ui_generator.py +++ b/tests/unit/test_data_ui_generator.py @@ -7,6 +7,7 @@ def test_generate_nav_default_xml(): result = data_ui_generator.generate_nav_default_xml( include_inputs=True, include_dashboard=True, + include_configuration=True, default_view="configuration", ) @@ -27,6 +28,7 @@ def test_generate_nav_default_xml_only_configuration(): result = data_ui_generator.generate_nav_default_xml( include_inputs=False, include_dashboard=False, + include_configuration=True, default_view="configuration", ) @@ -45,6 +47,7 @@ def test_generate_nav_default_xml_with_default_inputs_page(): result = data_ui_generator.generate_nav_default_xml( include_inputs=True, include_dashboard=False, + include_configuration=True, default_view="inputs", ) @@ -64,6 +67,7 @@ def test_generate_nav_default_xml_with_default_dashboard_page(): result = data_ui_generator.generate_nav_default_xml( include_inputs=True, include_dashboard=True, + include_configuration=True, default_view="dashboard", ) @@ -84,6 +88,7 @@ def test_generate_nav_default_xml_with_search_view_default(): result = data_ui_generator.generate_nav_default_xml( include_inputs=False, include_dashboard=False, + include_configuration=True, default_view="search", ) @@ -98,6 +103,25 @@ def test_generate_nav_default_xml_with_search_view_default(): assert " ".join([str(item) for item in diff]) == "" +def test_generate_nav_default_xml_with_no_configuration(): + result = data_ui_generator.generate_nav_default_xml( + include_inputs=True, + include_dashboard=False, + include_configuration=False, + default_view="search", + ) + + expected_result = """ + +""" + diff = xmldiff.main.diff_texts(result, expected_result) + + assert " ".join([str(item) for item in diff]) == "" + + def test_generate_views_inputs_xml(): result = data_ui_generator.generate_views_inputs_xml("Splunk_TA_UCCExample") diff --git a/tests/unit/test_global_config.py b/tests/unit/test_global_config.py index 6759bffa8..fd34f90cb 100644 --- a/tests/unit/test_global_config.py +++ b/tests/unit/test_global_config.py @@ -28,6 +28,7 @@ def test_global_config_parse(filename): assert global_config.original_path == global_config_path assert global_config.schema_version == "0.0.3" assert global_config.version == "1.0.0" + assert global_config.has_configuration() is True assert global_config.has_inputs() is True assert global_config.has_alerts() is True assert global_config.has_oauth() is True @@ -67,12 +68,21 @@ def test_global_config_configs(global_config_only_configuration): def test_global_config_only_configuration(global_config_only_configuration): + assert global_config_only_configuration.has_configuration() is True assert global_config_only_configuration.has_inputs() is False assert global_config_only_configuration.has_alerts() is False assert global_config_only_configuration.has_oauth() is False assert global_config_only_configuration.has_dashboard() is False +def test_global_config_no_configuration(global_config_no_configuration): + assert global_config_no_configuration.has_configuration() is False + assert global_config_no_configuration.has_inputs() is True + assert global_config_no_configuration.has_alerts() is False + assert global_config_no_configuration.has_oauth() is False + assert global_config_no_configuration.has_dashboard() is True + + def test_global_config_only_logging(global_config_only_logging): assert global_config_only_logging.has_alerts() is False diff --git a/tests/unit/test_global_config_validator.py b/tests/unit/test_global_config_validator.py index 38493d406..929c4fae9 100644 --- a/tests/unit/test_global_config_validator.py +++ b/tests/unit/test_global_config_validator.py @@ -318,6 +318,12 @@ def test_autocompletefields_children_support_integer_values(): 'meta.defaultView == "inputs" but there is no inputs defined in globalConfig' ), ), + ( + "invalid_config_meta_default_configuration_page_but_no_configuration_defined.json", + ( + 'meta.defaultView == "configuration" but there is no configuration defined in globalConfig' + ), + ), ( "invalid_config_meta_default_dashboard_page_but_no_dashboard_defined.json", ( diff --git a/tests/unit/testdata/global_config_no_configuration.json b/tests/unit/testdata/global_config_no_configuration.json new file mode 100644 index 000000000..684ccab6b --- /dev/null +++ b/tests/unit/testdata/global_config_no_configuration.json @@ -0,0 +1,181 @@ +{ + "pages": { + "inputs": { + "title": "Inputs", + "services": [ + { + "name": "example_input_one", + "description": "This is a description for Input One", + "title": "Example Input", + "entity": [ + { + "type": "text", + "label": "Name", + "validators": [ + { + "type": "regex", + "errorMsg": "Input Name must begin with a letter and consist exclusively of alphanumeric characters and underscores.", + "pattern": "^[a-zA-Z]\\w*$" + }, + { + "type": "string", + "errorMsg": "Length of input name should be between 1 and 100", + "minLength": 1, + "maxLength": 100 + } + ], + "field": "name", + "help": "A unique name for the data input.", + "required": true + }, + { + "type": "interval", + "field": "interval", + "label": "Interval", + "help": "Time interval of the data input, in seconds.", + "required": true + } + ], + "table": { + "actions": [ + "edit", + "delete", + "clone" + ], + "header": [ + { + "label": "Name", + "field": "name" + }, + { + "label": "Interval", + "field": "interval" + }, + { + "label": "Status", + "field": "disabled" + } + ], + "moreInfo": [ + { + "label": "Name", + "field": "name" + }, + { + "label": "Interval", + "field": "interval" + }, + { + "label": "Status", + "field": "disabled" + } + ] + }, + "warning": { + "create": { + "message": "Warning text for create mode" + }, + "edit": { + "message": "Warning text for edit mode" + }, + "clone": { + "message": "Warning text for clone mode" + }, + "config": { + "message": "Warning text for config mode" + } + } + }, + { + "name": "example_input_two", + "description": "This is a description for Input Two", + "title": "Example Input Two", + "entity": [ + { + "type": "text", + "label": "Name", + "validators": [ + { + "type": "regex", + "errorMsg": "Input Name must begin with a letter and consist exclusively of alphanumeric characters and underscores.", + "pattern": "^[a-zA-Z]\\w*$" + }, + { + "type": "string", + "errorMsg": "Length of input name should be between 1 and 100", + "minLength": 1, + "maxLength": 100 + } + ], + "field": "name", + "help": "A unique name for the data input.", + "required": true + }, + { + "type": "interval", + "field": "interval", + "label": "Interval", + "help": "Time interval of the data input, in seconds.", + "required": true + } + ], + "table": { + "actions": [ + "edit", + "delete", + "clone" + ], + "header": [ + { + "label": "Name", + "field": "name" + }, + { + "label": "Interval", + "field": "interval" + }, + { + "label": "Status", + "field": "disabled" + } + ], + "moreInfo": [ + { + "label": "Name", + "field": "name" + }, + { + "label": "Interval", + "field": "interval" + }, + { + "label": "Status", + "field": "disabled" + } + ], + "customRow": { + "type": "external", + "src": "custom_row" + } + }, + "useInputToggleConfirmation": true + } + ] + }, + "dashboard": { + "panels": [ + { + "name": "default" + } + ] + } + }, + "meta": { + "name": "Splunk_TA_UCCExample", + "restRoot": "splunk_ta_uccexample", + "version": "5.55.0+1bb56cc1", + "displayName": "Splunk UCC test Add-on", + "schemaVersion": "0.0.9", + "_uccVersion": "5.55.0" + } +} diff --git a/tests/unit/testdata/invalid_config_meta_default_configuration_page_but_no_configuration_defined.json b/tests/unit/testdata/invalid_config_meta_default_configuration_page_but_no_configuration_defined.json new file mode 100644 index 000000000..8f15fb428 --- /dev/null +++ b/tests/unit/testdata/invalid_config_meta_default_configuration_page_but_no_configuration_defined.json @@ -0,0 +1,181 @@ +{ + "pages": { + "inputs": { + "title": "Inputs", + "services": [ + { + "name": "example_input_one", + "description": "This is a description for Input One", + "title": "Example Input", + "entity": [ + { + "type": "text", + "label": "Name", + "validators": [ + { + "type": "regex", + "errorMsg": "Input Name must begin with a letter and consist exclusively of alphanumeric characters and underscores.", + "pattern": "^[a-zA-Z]\\w*$" + }, + { + "type": "string", + "errorMsg": "Length of input name should be between 1 and 100", + "minLength": 1, + "maxLength": 100 + } + ], + "field": "name", + "help": "A unique name for the data input.", + "required": true + }, + { + "type": "interval", + "field": "interval", + "label": "Interval", + "help": "Time interval of the data input, in seconds.", + "required": true + } + ], + "table": { + "actions": [ + "edit", + "delete", + "clone" + ], + "header": [ + { + "label": "Name", + "field": "name" + }, + { + "label": "Interval", + "field": "interval" + }, + { + "label": "Status", + "field": "disabled" + } + ], + "moreInfo": [ + { + "label": "Name", + "field": "name" + }, + { + "label": "Interval", + "field": "interval" + }, + { + "label": "Status", + "field": "disabled" + } + ] + }, + "warning": { + "create": { + "message": "Warning text for create mode" + }, + "edit": { + "message": "Warning text for edit mode" + }, + "clone": { + "message": "Warning text for clone mode" + }, + "config": { + "message": "Warning text for config mode" + } + } + }, + { + "name": "example_input_two", + "description": "This is a description for Input Two", + "title": "Example Input Two", + "entity": [ + { + "type": "text", + "label": "Name", + "validators": [ + { + "type": "regex", + "errorMsg": "Input Name must begin with a letter and consist exclusively of alphanumeric characters and underscores.", + "pattern": "^[a-zA-Z]\\w*$" + }, + { + "type": "string", + "errorMsg": "Length of input name should be between 1 and 100", + "minLength": 1, + "maxLength": 100 + } + ], + "field": "name", + "help": "A unique name for the data input.", + "required": true + }, + { + "type": "interval", + "field": "interval", + "label": "Interval", + "help": "Time interval of the data input, in seconds.", + "required": true + } + ], + "table": { + "actions": [ + "edit", + "delete", + "clone" + ], + "header": [ + { + "label": "Name", + "field": "name" + }, + { + "label": "Interval", + "field": "interval" + }, + { + "label": "Status", + "field": "disabled" + } + ], + "moreInfo": [ + { + "label": "Name", + "field": "name" + }, + { + "label": "Interval", + "field": "interval" + }, + { + "label": "Status", + "field": "disabled" + } + ], + "customRow": { + "type": "external", + "src": "custom_row" + } + }, + "useInputToggleConfirmation": true + } + ] + }, + "dashboard": { + "panels": [ + { + "name": "default" + } + ] + } + }, + "meta": { + "name": "Splunk_TA_UCCExample", + "restRoot": "splunk_ta_uccexample", + "version": "5.55.0+1bb56cc1", + "displayName": "Splunk UCC test Add-on", + "schemaVersion": "0.0.9", + "defaultView": "configuration" + } +} diff --git a/tests/unit/testdata/openapi.json.no_config.generated b/tests/unit/testdata/openapi.json.no_config.generated new file mode 100644 index 000000000..7bb80d7f9 --- /dev/null +++ b/tests/unit/testdata/openapi.json.no_config.generated @@ -0,0 +1,581 @@ +{ + "openapi": "3.0.0", + "info": { + "title": "Splunk_TA_UCCExample", + "version": "5.55.0+1bb56cc1", + "description": "Splunk UCC test Add-on", + "contact": { + "name": "Splunk", + "email": "addonfactory@splunk.com" + }, + "license": { + "name": "Apache-2.0", + "url": "https://www.apache.org/licenses/LICENSE-2.0" + } + }, + "servers": [ + { + "url": "https://{domain}:{port}/servicesNS/-/Splunk_TA_UCCExample", + "variables": { + "domain": { + "default": "localhost" + }, + "port": { + "default": "8089" + } + }, + "description": "Access via management interface" + } + ], + "components": { + "schemas": { + "example_input_one": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "interval": { + "type": "string" + }, + "disabled": { + "type": "string", + "enum": [ + "False", + "True" + ] + } + } + }, + "example_input_one_without_name": { + "type": "object", + "properties": { + "interval": { + "type": "string" + }, + "disabled": { + "type": "string", + "enum": [ + "False", + "True" + ] + } + } + }, + "example_input_one_without_disabled": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "interval": { + "type": "string" + } + } + }, + "example_input_two": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "interval": { + "type": "string" + }, + "disabled": { + "type": "string", + "enum": [ + "False", + "True" + ] + } + } + }, + "example_input_two_without_name": { + "type": "object", + "properties": { + "interval": { + "type": "string" + }, + "disabled": { + "type": "string", + "enum": [ + "False", + "True" + ] + } + } + }, + "example_input_two_without_disabled": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "interval": { + "type": "string" + } + } + } + }, + "securitySchemes": { + "BasicAuth": { + "type": "http", + "scheme": "basic" + } + } + }, + "paths": { + "/splunk_ta_uccexample_example_input_one": { + "get": { + "responses": { + "200": { + "description": "Get list of items for example_input_one", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "entry": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "content": { + "$ref": "#/components/schemas/example_input_one_without_name" + } + } + } + } + } + } + } + } + } + }, + "description": "Get list of items for example_input_one", + "deprecated": false + }, + "post": { + "responses": { + "200": { + "description": "Create item in example_input_one", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "entry": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "content": { + "$ref": "#/components/schemas/example_input_one_without_name" + } + } + } + } + } + } + } + } + } + }, + "description": "Create item in example_input_one", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/example_input_one_without_disabled" + } + } + }, + "required": false + }, + "deprecated": false + }, + "parameters": [ + { + "name": "output_mode", + "in": "query", + "required": true, + "description": "Output mode", + "schema": { + "type": "string", + "enum": [ + "json" + ], + "default": "json" + } + } + ] + }, + "/splunk_ta_uccexample_example_input_one/{name}": { + "get": { + "responses": { + "200": { + "description": "Get example_input_one item details", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "entry": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "content": { + "$ref": "#/components/schemas/example_input_one_without_name" + } + } + } + } + } + } + } + } + } + }, + "description": "Get example_input_one item details", + "deprecated": false + }, + "post": { + "responses": { + "200": { + "description": "Update example_input_one item", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "entry": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "content": { + "$ref": "#/components/schemas/example_input_one_without_name" + } + } + } + } + } + } + } + } + } + }, + "description": "Update example_input_one item", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/example_input_one_without_name" + } + } + }, + "required": false + }, + "deprecated": false + }, + "delete": { + "responses": { + "200": { + "description": "Delete example_input_one item", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "entry": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "content": { + "$ref": "#/components/schemas/example_input_one_without_name" + } + } + } + } + } + } + } + } + } + }, + "description": "Delete example_input_one item", + "deprecated": false + }, + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "description": "The name of the item to operate on", + "schema": { + "type": "string" + } + }, + { + "name": "output_mode", + "in": "query", + "required": true, + "description": "Output mode", + "schema": { + "type": "string", + "enum": [ + "json" + ], + "default": "json" + } + } + ] + }, + "/splunk_ta_uccexample_example_input_two": { + "get": { + "responses": { + "200": { + "description": "Get list of items for example_input_two", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "entry": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "content": { + "$ref": "#/components/schemas/example_input_two_without_name" + } + } + } + } + } + } + } + } + } + }, + "description": "Get list of items for example_input_two", + "deprecated": false + }, + "post": { + "responses": { + "200": { + "description": "Create item in example_input_two", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "entry": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "content": { + "$ref": "#/components/schemas/example_input_two_without_name" + } + } + } + } + } + } + } + } + } + }, + "description": "Create item in example_input_two", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/example_input_two_without_disabled" + } + } + }, + "required": false + }, + "deprecated": false + }, + "parameters": [ + { + "name": "output_mode", + "in": "query", + "required": true, + "description": "Output mode", + "schema": { + "type": "string", + "enum": [ + "json" + ], + "default": "json" + } + } + ] + }, + "/splunk_ta_uccexample_example_input_two/{name}": { + "get": { + "responses": { + "200": { + "description": "Get example_input_two item details", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "entry": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "content": { + "$ref": "#/components/schemas/example_input_two_without_name" + } + } + } + } + } + } + } + } + } + }, + "description": "Get example_input_two item details", + "deprecated": false + }, + "post": { + "responses": { + "200": { + "description": "Update example_input_two item", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "entry": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "content": { + "$ref": "#/components/schemas/example_input_two_without_name" + } + } + } + } + } + } + } + } + } + }, + "description": "Update example_input_two item", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/example_input_two_without_name" + } + } + }, + "required": false + }, + "deprecated": false + }, + "delete": { + "responses": { + "200": { + "description": "Delete example_input_two item", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "entry": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "content": { + "$ref": "#/components/schemas/example_input_two_without_name" + } + } + } + } + } + } + } + } + } + }, + "description": "Delete example_input_two item", + "deprecated": false + }, + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "description": "The name of the item to operate on", + "schema": { + "type": "string" + } + }, + { + "name": "output_mode", + "in": "query", + "required": true, + "description": "Output mode", + "schema": { + "type": "string", + "enum": [ + "json" + ], + "default": "json" + } + } + ] + } + }, + "security": [ + { + "BasicAuth": [] + } + ] +} \ No newline at end of file diff --git a/tests/unit/testdata/valid_config_no_configuration.json b/tests/unit/testdata/valid_config_no_configuration.json new file mode 100644 index 000000000..e0e74a186 --- /dev/null +++ b/tests/unit/testdata/valid_config_no_configuration.json @@ -0,0 +1,754 @@ +{ + "pages": { + "inputs": { + "services": [ + { + "hook": { + "src": "Hook" + }, + "name": "example_input_one", + "entity": [ + { + "type": "text", + "label": "Name", + "validators": [ + { + "type": "regex", + "errorMsg": "Input Name must begin with a letter and consist exclusively of alphanumeric characters and underscores.", + "pattern": "^[a-zA-Z]\\w*$" + }, + { + "type": "string", + "errorMsg": "Length of input name should be between 1 and 100", + "minLength": 1, + "maxLength": 100 + } + ], + "field": "name", + "help": "A unique name for the data input.", + "required": true + }, + { + "type": "checkbox", + "label": "Example Checkbox", + "field": "input_one_checkbox", + "help": "This is an example checkbox for the input one entity" + }, + { + "type": "radio", + "label": "Example Radio", + "field": "input_one_radio", + "defaultValue": "yes", + "help": "This is an example radio button for the input one entity", + "required": false, + "options": { + "items": [ + { + "value": "yes", + "label": "Yes" + }, + { + "value": "no", + "label": "No" + } + ], + "display": true + } + }, + { + "field": "singleSelectTest", + "label": "Single Select Group Test", + "type": "singleSelect", + "options": { + "createSearchChoice": true, + "autoCompleteFields": [ + { + "label": "Group1", + "children": [ + { + "value": "one", + "label": "One" + }, + { + "value": "two", + "label": "Two" + } + ] + }, + { + "label": "Group2", + "children": [ + { + "value": "three", + "label": "Three" + }, + { + "value": "four", + "label": "Four" + } + ] + } + ] + } + }, + { + "field": "multipleSelectTest", + "label": "Multiple Select Test", + "type": "multipleSelect", + "options": { + "delimiter": "|", + "items": [ + { + "value": "a", + "label": "A" + }, + { + "value": "b", + "label": "B" + } + ] + } + }, + { + "type": "text", + "label": "Interval", + "validators": [ + { + "type": "regex", + "errorMsg": "Interval must be an integer.", + "pattern": "^\\-[1-9]\\d*$|^\\d*$" + } + ], + "field": "interval", + "help": "Time interval of the data input, in seconds.", + "required": true + }, + { + "type": "singleSelect", + "label": "Index", + "validators": [ + { + "type": "string", + "errorMsg": "Length of index name should be between 1 and 80.", + "minLength": 1, + "maxLength": 80 + } + ], + "defaultValue": "default", + "options": { + "endpointUrl": "data/indexes", + "denyList": "^_.*$", + "createSearchChoice": true + }, + "field": "index", + "required": true + }, + { + "type": "singleSelect", + "label": "Example Account", + "options": { + "referenceName": "account" + }, + "help": "", + "field": "account", + "required": true + }, + { + "type": "text", + "label": "Object", + "validators": [ + { + "type": "string", + "errorMsg": "Max length of text input is 8192", + "minLength": 0, + "maxLength": 8192 + } + ], + "field": "object", + "help": "The name of the object to query for.", + "required": true + }, + { + "type": "text", + "label": "Object Fields", + "validators": [ + { + "type": "string", + "errorMsg": "Max length of text input is 8192", + "minLength": 0, + "maxLength": 8192 + } + ], + "field": "object_fields", + "help": "Object fields from which to collect data. Delimit multiple fields using a comma.", + "required": true + }, + { + "type": "text", + "label": "Order By", + "validators": [ + { + "type": "string", + "errorMsg": "Max length of text input is 8192", + "minLength": 0, + "maxLength": 8192 + } + ], + "defaultValue": "LastModifiedDate", + "field": "order_by", + "help": "The datetime field by which to query results in ascending order for indexing.", + "required": true + }, + { + "type": "radio", + "label": "Use existing data input?", + "field": "use_existing_checkpoint", + "defaultValue": "yes", + "help": "Data input already exists. Select `No` if you want to reset the data collection.", + "required": false, + "options": { + "items": [ + { + "value": "yes", + "label": "Yes" + }, + { + "value": "no", + "label": "No" + } + ], + "display": false + } + }, + { + "type": "text", + "label": "Query Start Date", + "validators": [ + { + "type": "regex", + "errorMsg": "Invalid date and time format", + "pattern": "^(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}.\\d{3}z)?$" + } + ], + "field": "start_date", + "help": "The datetime after which to query and index records, in this format: \"YYYY-MM-DDThh:mm:ss.000z\".\nDefaults to 90 days earlier from now.", + "tooltip": "Changing this parameter may result in gaps or duplication in data collection.", + "required": false + }, + { + "type": "text", + "label": "Limit", + "validators": [ + { + "type": "string", + "errorMsg": "Max length of text input is 8192", + "minLength": 0, + "maxLength": 8192 + } + ], + "defaultValue": "1000", + "field": "limit", + "help": "The maximum number of results returned by the query.", + "required": false + }, + { + "field": "example_help_link", + "label": "", + "type": "helpLink", + "options": { + "text": "Help Link", + "link": "https://docs.splunk.com/Documentation" + } + } + ], + "title": "Example Input One" + }, + { + "name": "example_input_two", + "entity": [ + { + "type": "text", + "label": "Name", + "validators": [ + { + "type": "regex", + "errorMsg": "Input Name must begin with a letter and consist exclusively of alphanumeric characters and underscores.", + "pattern": "^[a-zA-Z]\\w*$" + }, + { + "type": "string", + "errorMsg": "Length of input name should be between 1 and 100", + "minLength": 1, + "maxLength": 100 + } + ], + "field": "name", + "help": "A unique name for the data input.", + "required": true + }, + { + "type": "text", + "label": "Interval", + "validators": [ + { + "type": "regex", + "errorMsg": "Interval must be an integer.", + "pattern": "^\\-[1-9]\\d*$|^\\d*$" + } + ], + "field": "interval", + "help": "Time interval of the data input, in seconds .", + "required": true + }, + { + "type": "singleSelect", + "label": "Index", + "validators": [ + { + "type": "string", + "errorMsg": "Length of index name should be between 1 and 80.", + "minLength": 1, + "maxLength": 80 + } + ], + "defaultValue": "default", + "options": { + "endpointUrl": "data/indexes", + "denyList": "^_.*$", + "createSearchChoice": true + }, + "field": "index", + "required": true + }, + { + "type": "singleSelect", + "label": "Example Account", + "options": { + "referenceName": "account" + }, + "help": "", + "field": "account", + "required": true + }, + { + "type": "multipleSelect", + "label": "Example Multiple Select", + "field": "input_two_multiple_select", + "help": "This is an example multipleSelect for input two entity", + "required": true, + "options": { + "items": [ + { + "value": "one", + "label": "Option One" + }, + { + "value": "two", + "label": "Option Two" + } + ] + } + }, + { + "type": "checkbox", + "label": "Example Checkbox", + "field": "input_two_checkbox", + "help": "This is an example checkbox for the input two entity" + }, + { + "type": "radio", + "label": "Example Radio", + "field": "input_two_radio", + "defaultValue": "yes", + "help": "This is an example radio button for the input two entity", + "required": false, + "options": { + "items": [ + { + "value": "yes", + "label": "Yes" + }, + { + "value": "no", + "label": "No" + } + ], + "display": true + } + }, + { + "type": "radio", + "label": "Use existing data input?", + "field": "use_existing_checkpoint", + "defaultValue": "yes", + "help": "Data input already exists. Select `No` if you want to reset the data collection.", + "required": false, + "options": { + "items": [ + { + "value": "yes", + "label": "Yes" + }, + { + "value": "no", + "label": "No" + } + ], + "display": false + } + }, + { + "type": "text", + "label": "Query Start Date", + "validators": [ + { + "type": "regex", + "errorMsg": "Invalid date and time format", + "pattern": "^(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}.\\d{3}z)?$" + } + ], + "field": "start_date", + "help": "The date and time, in \"YYYY-MM-DDThh:mm:ss.000z\" format, after which to query and index records. \nThe default is 90 days before today.", + "tooltip": "Changing this parameter may result in gaps or duplication in data collection.", + "required": false + }, + { + "field": "example_help_link", + "label": "", + "type": "helpLink", + "options": { + "text": "Help Link", + "link": "https://docs.splunk.com/Documentation" + } + }, + { + "type": "checkboxGroup", + "label": "Two groups", + "field": "api1", + "options": { + "groups": [ + { + "label": "Collect", + "fields": [ + "collectFolderCollaboration", + "collectFileMetadata", + "collectTasksAndComments" + ] + }, + { + "label": "Collect2", + "options": { + "isExpandable": true + }, + "fields": ["collectFolderMetadata"] + } + ], + "rows": [ + { + "field": "collectFolderCollaboration", + "input": { + "defaultValue": 1200, + "required": false, + "validators": [ + { + "type": "number", + "range": [1, 1200] + } + ] + } + }, + { + "field": "collectFileMetadata", + "checkbox": { + "label": "Collect file metadata" + }, + "input": { + "defaultValue": 1, + "required": true + } + }, + { + "field": "collectTasksAndComments", + "checkbox": { + "label": "This is a very very long line" + }, + "input": { + "defaultValue": 1, + "required": true + } + }, + { + "field": "collectFolderMetadata", + "checkbox": { + "label": "Collect folder metadata" + }, + "input": { + "defaultValue": 3600, + "required": true + } + } + ] + } + }, + { + "type": "checkboxGroup", + "label": "No groups", + "field": "api2", + "options": { + "rows": [ + { + "field": "collectFolderMetadata", + "checkbox": { + "label": "Collect folder metadata", + "defaultValue": true + }, + "input": { + "defaultValue": 3600, + "required": true + } + }, + { + "field": "collectFolderCollaboration", + "checkbox": { + "label": "Collect folder collaboration" + }, + "input": { + "defaultValue": 1200, + "required": false, + "validators": [ + { + "type": "number", + "range": [1, 1200] + } + ] + } + }, + { + "field": "collectFileMetadata", + "checkbox": { + "label": "Collect file metadata" + }, + "input": { + "defaultValue": 1, + "required": true + } + }, + { + "field": "collectTasksAndComments", + "checkbox": { + "label": "Collect tasks and comments" + }, + "input": { + "defaultValue": 1, + "required": true + } + } + ] + } + }, + { + "type": "checkboxGroup", + "label": "Mixed", + "field": "api3", + "required": true, + "options": { + "groups": [ + { + "label": "Group 1", + "options": { + "isExpandable": true, + "expand": true + }, + "fields": ["collectFolderCollaboration"] + }, + { + "label": "Group 3", + "options": { + "isExpandable": true, + "expand": true + }, + "fields": ["collectFolderMetadata"] + } + ], + "rows": [ + { + "field": "collectFolderCollaboration", + "checkbox": { + "label": "Collect folder collaboration", + "defaultValue": true + }, + "input": { + "defaultValue": 1200, + "required": false + } + }, + { + "field": "collectFileMetadata", + "checkbox": { + "label": "Collect file metadata", + "defaultValue": false + }, + "input": { + "defaultValue": 1, + "required": true + } + }, + { + "field": "collectTasksAndComments", + "checkbox": { + "label": "Collect tasks and comments" + }, + "input": { + "defaultValue": 1, + "required": true + } + }, + { + "field": "collectFolderMetadata", + "checkbox": { + "label": "Collect folder metadata" + }, + "input": { + "defaultValue": 3600, + "required": true + } + }, + { + "field": "field223", + "checkbox": { + "label": "Required field" + }, + "input": { + "required": true + } + }, + { + "field": "field23", + "checkbox": { + "label": "No more 2 characters" + }, + "input": { + "defaultValue": 123 + } + }, + { + "field": "160validation", + "checkbox": { + "label": "from 1 to 60 validation" + }, + "input": { + "validators": [ + { + "type": "number", + "range": [1, 60] + } + ] + } + } + ] + } + } + ], + "title": "Example Input Two" + } + ], + "title": "Inputs", + "description": "Manage your data inputs", + "table": { + "actions": [ + "edit", + "delete", + "clone" + ], + "header": [ + { + "label": "Name", + "field": "name" + }, + { + "label": "Account Name", + "field": "account" + }, + { + "label": "Interval", + "field": "interval" + }, + { + "label": "Index", + "field": "index" + }, + { + "label": "Status", + "field": "disabled" + } + ], + "moreInfo": [ + { + "label": "Name", + "field": "name" + }, + { + "label": "Interval", + "field": "interval" + }, + { + "label": "Index", + "field": "index" + }, + { + "label": "Status", + "field": "disabled", + "mapping": { + "true": "Disabled", + "false": "Enabled" + } + }, + { + "label": "Example Account", + "field": "account" + }, + { + "label": "Object", + "field": "object" + }, + { + "label": "Object Fields", + "field": "object_fields" + }, + { + "label": "Order By", + "field": "order_by" + }, + { + "label": "Query Start Date", + "field": "start_date" + }, + { + "label": "Limit", + "field": "limit" + } + ] + } + }, + "dashboard": { + "panels": [ + { + "name": "default" + } + ], + "settings": { + "error_panel_log_lvl": [ + "ERROR", + "CRITICAL" + ] + } + } + }, + "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 diff --git a/ui/src/components/BaseFormView/BaseFormView.tsx b/ui/src/components/BaseFormView/BaseFormView.tsx index 9adc26495..08623018d 100644 --- a/ui/src/components/BaseFormView/BaseFormView.tsx +++ b/ui/src/components/BaseFormView/BaseFormView.tsx @@ -190,7 +190,7 @@ class BaseFormView extends PureComponent { } }); } else { - globalConfig.pages.configuration.tabs.forEach((tab) => { + (globalConfig.pages.configuration?.tabs ?? []).forEach((tab) => { const flag = tab.table ? tab.name === props.serviceName : tab.name === props.stanzaName && props.serviceName === 'settings'; diff --git a/ui/src/components/EntityModal/TestConfig.ts b/ui/src/components/EntityModal/TestConfig.ts index 6a5a85070..35a120482 100644 --- a/ui/src/components/EntityModal/TestConfig.ts +++ b/ui/src/components/EntityModal/TestConfig.ts @@ -94,6 +94,7 @@ export const getConfigBasicOauthDisableonEdit = () => { ...globalConfig.pages, configuration: { ...globalConfig.pages.configuration, + title: globalConfig.pages.configuration?.title ?? '', tabs: [{ entity: entityBasicOauthDisableonEdit, ...defaultTableProps }], }, }, @@ -109,6 +110,7 @@ export const getConfigOauthOauthDisableonEdit = () => { ...globalConfig.pages, configuration: { ...globalConfig.pages.configuration, + title: globalConfig.pages.configuration?.title ?? '', tabs: [{ entity: entityOauthOauthDisableonEdit, ...defaultTableProps }], }, }, @@ -168,6 +170,7 @@ export const getConfigAccessTokenMock = () => { ...globalConfig.pages, configuration: { ...globalConfig.pages.configuration, + title: globalConfig.pages.configuration?.title ?? '', tabs: [{ entity: accessTokenMock, ...defaultTableProps }], }, }, @@ -215,6 +218,7 @@ export const getConfigEnableFalseForOauth = () => { ...globalConfig.pages, configuration: { ...globalConfig.pages.configuration, + title: globalConfig.pages.configuration?.title ?? '', tabs: [{ entity: entityEnableFalseForOauthField, ...defaultTableProps }], }, }, @@ -244,6 +248,7 @@ export const getConfigWarningMessage = () => { ...globalConfig.pages, configuration: { ...globalConfig.pages.configuration, + title: globalConfig.pages.configuration?.title ?? '', tabs: [ { entity: accessTokenMock, ...defaultTableProps, warning: WARNING_MESSAGES }, ], @@ -261,6 +266,7 @@ export const getConfigWarningMessageAlwaysDisplay = () => { ...globalConfig.pages, configuration: { ...globalConfig.pages.configuration, + title: globalConfig.pages.configuration?.title ?? '', tabs: [ { entity: accessTokenMock, @@ -314,6 +320,7 @@ export const getConfigFullyEnabledField = () => { ...globalConfig.pages, configuration: { ...globalConfig.pages.configuration, + title: globalConfig.pages.configuration?.title ?? '', tabs: [{ entity: entityBasicOauthFullyEnabledField, ...defaultTableProps }], }, }, @@ -364,6 +371,7 @@ export const getConfigWithOauthDefaultValue = () => { ...globalConfig.pages, configuration: { ...globalConfig.pages.configuration, + title: globalConfig.pages.configuration?.title ?? '', tabs: [{ entity: entityBasicOauthDefaultValue, ...defaultTableProps }], }, }, @@ -435,6 +443,7 @@ export const getConfigWithSeparatedEndpointsOAuth = () => { ...globalConfig.pages, configuration: { ...globalConfig.pages.configuration, + title: globalConfig.pages.configuration?.title ?? '', tabs: [{ entity: entityOauthOauthSeparatedEndpoints, ...defaultTableProps }], }, }, diff --git a/ui/src/components/FormModifications/TestConfig.ts b/ui/src/components/FormModifications/TestConfig.ts index 0825e24c4..fd0f83ad0 100644 --- a/ui/src/components/FormModifications/TestConfig.ts +++ b/ui/src/components/FormModifications/TestConfig.ts @@ -146,6 +146,7 @@ export const getConfigWithModifications = () => { ...standardConfig.pages, configuration: { ...standardConfig.pages.configuration, + title: standardConfig.pages.configuration?.title ?? '', tabs: [ { entity: [ diff --git a/ui/src/components/table/CustomTable.tsx b/ui/src/components/table/CustomTable.tsx index 233461fbf..5902e2b37 100644 --- a/ui/src/components/table/CustomTable.tsx +++ b/ui/src/components/table/CustomTable.tsx @@ -18,6 +18,7 @@ import { SortDirection } from './useTableSort'; import { GlobalConfig } from '../../types/globalConfig/globalConfig'; import { ITableConfig } from '../../types/globalConfig/pages'; import { StandardPages } from '../../types/components/shareableTypes'; +import { invariant } from '../../util/invariant'; interface CustomTableProps { page: StandardPages; @@ -47,7 +48,7 @@ const getServiceToStyleMap = (page: StandardPages, unifiedConfigs: GlobalConfig) serviceToStyleMap[x.name] = x.style === STYLE_PAGE ? STYLE_PAGE : STYLE_MODAL; }); } else { - unifiedConfigs.pages.configuration.tabs.forEach((x) => { + unifiedConfigs.pages.configuration?.tabs.forEach((x) => { serviceToStyleMap[x.name] = x.style === STYLE_PAGE ? STYLE_PAGE : STYLE_MODAL; }); } @@ -179,6 +180,10 @@ const CustomTable: React.FC = ({ const services = inputsPage?.services; label = services?.find((x) => x.name === entityModal.serviceName)?.title; } else if (page === PAGE_CONF) { + invariant( + unifiedConfigs.pages.configuration, + 'Configuration page not found in global config' + ); const { tabs } = unifiedConfigs.pages.configuration; label = tabs.find((x) => x.name === entityModal.serviceName)?.title; } diff --git a/ui/src/components/table/TableWrapper.tsx b/ui/src/components/table/TableWrapper.tsx index 4abb0f880..8595089f8 100644 --- a/ui/src/components/table/TableWrapper.tsx +++ b/ui/src/components/table/TableWrapper.tsx @@ -41,7 +41,7 @@ const getTableConfigAndServices = ( const services = page === PAGE_INPUT ? unifiedConfigs.pages.inputs?.services - : unifiedConfigs.pages.configuration.tabs.filter((x) => x.name === serviceName); + : unifiedConfigs.pages.configuration?.tabs.filter((x) => x.name === serviceName); if (page === PAGE_INPUT) { if (unifiedConfigs.pages.inputs && 'table' in unifiedConfigs.pages.inputs) { return { @@ -69,7 +69,7 @@ const getTableConfigAndServices = ( }; } - const tableConfig = unifiedConfigs.pages.configuration.tabs.find( + const tableConfig = unifiedConfigs.pages.configuration?.tabs.find( (x) => x.name === serviceName )?.table; diff --git a/ui/src/hooks/usePlatform.ts b/ui/src/hooks/usePlatform.ts index 16fa55c9f..e24328f60 100644 --- a/ui/src/hooks/usePlatform.ts +++ b/ui/src/hooks/usePlatform.ts @@ -18,7 +18,7 @@ const checkIfHideInAnyEntity = (entities: AnyEntity[]): boolean => { const checkIfHideForPlatformUsed = (globalConfig: GlobalConfig, page?: StandardPages): boolean => { if (!page || page === 'configuration') { - const isHideUsedInConfig = globalConfig.pages.configuration.tabs.find( + const isHideUsedInConfig = globalConfig.pages.configuration?.tabs.find( (tab) => tab.hideForPlatform || checkIfHideInAnyEntity(tab.entity || []) || false ); if (isHideUsedInConfig) { diff --git a/ui/src/pages/Configuration/ConfigurationPage.tsx b/ui/src/pages/Configuration/ConfigurationPage.tsx index 33016a6c8..1f5734230 100644 --- a/ui/src/pages/Configuration/ConfigurationPage.tsx +++ b/ui/src/pages/Configuration/ConfigurationPage.tsx @@ -20,6 +20,7 @@ import { TabSchema } from '../../types/globalConfig/pages'; import { PageContextProvider } from '../../context/PageContext'; import { shouldHideForPlatform } from '../../util/pageContext'; import { usePlatform } from '../../hooks/usePlatform'; +import { invariant } from '../../util/invariant'; const StyledHeaderControls = styled.div` display: inline-flex; @@ -46,6 +47,7 @@ type Tab = z.infer; function ConfigurationPage() { const unifiedConfigs = getUnifiedConfigs(); + invariant(unifiedConfigs.pages.configuration, 'Configuration page not found in global config'); const { title, description, subDescription, tabs } = unifiedConfigs.pages.configuration; const platform = usePlatform(unifiedConfigs, 'configuration'); diff --git a/ui/src/types/globalConfig/pages.ts b/ui/src/types/globalConfig/pages.ts index aed9c7704..cc43316cf 100644 --- a/ui/src/types/globalConfig/pages.ts +++ b/ui/src/types/globalConfig/pages.ts @@ -161,12 +161,14 @@ const InputsPageSchema = z.union([InputsPageRegular, InputsPageTableSchema]).opt const ServiceTableSchema = z.union([TableFullServiceSchema, TableLessServiceSchema]); export const pages = z.object({ - configuration: z.object({ - title: z.string(), - description: z.string().optional(), - subDescription: SubDescriptionSchema, - tabs: z.array(TabSchema).min(1), - }), + configuration: z + .object({ + title: z.string(), + description: z.string().optional(), + subDescription: SubDescriptionSchema, + tabs: z.array(TabSchema).min(1), + }) + .optional(), inputs: InputsPageSchema, dashboard: z .object({