testit-python-commons 5.2.0__tar.gz → 5.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/PKG-INFO +1 -1
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/setup.py +1 -1
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/client/api_client.py +10 -3
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/client/converter.py +12 -2
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/client/helpers/bulk_autotest_helper.py +3 -3
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/models/test_result.py +15 -1
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/services/adapter_manager.py +54 -19
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/utils/html_escape_utils.py +75 -51
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons.egg-info/PKG-INFO +1 -1
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons.egg-info/SOURCES.txt +2 -1
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/tests/test_html_escape_utils.py +56 -0
- testit_python_commons-5.2.2/tests/test_xss_parameters_escape.py +72 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/README.md +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/setup.cfg +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/__init__.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/api/__init__.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/api/attachments_api.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/api/auto_tests_api.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/api/configurations_api.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/api/custom_attributes_api.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/api/parameters_api.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/api/project_attributes_api.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/api/project_sections_api.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/api/project_work_items_api.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/api/projects_api.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/api/sections_api.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/api/test_results_api.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/api/test_runs_api.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/api/work_items_api.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/api/workflows_api.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/api_client.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/apis/__init__.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/configuration.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/exceptions.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/__init__.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/adapters_auto_tests_id_work_items_post_request.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/adapters_auto_tests_post_request.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/adapters_auto_tests_put_request.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/adapters_auto_tests_search_post_request.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/adapters_configurations_search_post_request.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/adapters_custom_attributes_global_id_put_request.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/adapters_custom_attributes_global_post_request.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/adapters_custom_attributes_search_post_request.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/adapters_parameters_post_request.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/adapters_parameters_search_post_request.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/adapters_projects_post_request.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/adapters_projects_project_id_attributes_put_request.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/adapters_projects_project_id_attributes_search_post_request.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/adapters_projects_project_id_work_items_search_post_request.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/adapters_projects_search_post_request.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/adapters_sections_post_request.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/adapters_test_results_id_put_request.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/adapters_test_results_search_post_request.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/adapters_test_runs_id_reruns_post_request.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/adapters_test_runs_post_request.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/adapters_test_runs_put_request.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/adapters_work_items_post_request.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/assign_attachment_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/assign_auto_test_case_id_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/assign_iteration_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/attachment_api_result.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/attachment_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/attachment_put_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/attachment_put_model_auto_test_step_results_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/attachment_update_request.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/auto_test.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/auto_test_api_result.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/auto_test_api_result_layer.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/auto_test_case_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/auto_test_create_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/auto_test_create_api_model_layer.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/auto_test_filter_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/auto_test_id_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/auto_test_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/auto_test_model_last_test_result_configuration.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/auto_test_model_last_test_result_status.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/auto_test_result_reason_short.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/auto_test_results_for_test_run_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/auto_test_search_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/auto_test_search_api_model_filter.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/auto_test_search_api_model_includes.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/auto_test_search_include_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/auto_test_step.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/auto_test_step_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/auto_test_step_api_result.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/auto_test_step_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/auto_test_step_result.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/auto_test_step_result_update_request.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/auto_test_update_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/auto_test_work_item_identifier_api_result.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/available_test_result_outcome.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/configuration_filter_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/configuration_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/configuration_short_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/create_empty_test_run_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/create_link_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/create_parameter_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/create_project_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/create_step_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/create_work_item_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/custom_attribute_api_result.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/custom_attribute_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/custom_attribute_option_api_result.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/custom_attribute_option_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/custom_attribute_option_post_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/custom_attribute_option_update_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/custom_attribute_put_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/custom_attribute_search_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/custom_attribute_search_api_result.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/custom_attribute_type.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/custom_attribute_types_enum.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/date_time_range_selector_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/deletion_state.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/detailed_project_api_result.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/detailed_project_api_result_workflow.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/failure_category_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/global_custom_attribute_post_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/global_custom_attribute_update_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/guid_extraction_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/image_resize_type.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/int32_range_selector_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/int64_range_selector_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/iteration_api_result.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/iteration_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/label_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/label_api_result.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/label_short_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/layer_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/layer_api_result.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/layer_source.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/link_api_result.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/link_create_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/link_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/link_post_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/link_put_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/link_short_api_result.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/link_type.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/link_update_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/manual_rerun_api_result.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/manual_rerun_select_test_results_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/manual_rerun_select_test_results_api_model_extraction_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/manual_rerun_select_test_results_api_model_filter.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/manual_rerun_test_result_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/manual_rerun_test_result_api_model_test_result_ids.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/operation.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/parameter_api_result.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/parameter_iteration_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/parameter_short_api_result.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/parameter_short_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/parameters_filter_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/problem_details.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/project_api_result.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/project_attributes_filter_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/project_shortest_api_result.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/project_type_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/projects_filter_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/projects_filter_model_autotests_count.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/projects_filter_model_checklists_count.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/projects_filter_model_created_date.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/projects_filter_model_shared_steps_count.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/projects_filter_model_test_cases_count.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/section_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/section_post_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/section_shared_step.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/section_with_steps_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/shared_step_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/shared_step_result_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/step_comment_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/step_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/step_post_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/step_result_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/tag_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/test_result_link_api_result.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/test_result_outcome.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/test_result_response.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/test_result_short_response.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/test_result_short_response_status.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/test_result_step_comment_update_request.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/test_result_update_request.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/test_results_filter_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/test_results_filter_api_model_duration.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/test_run_api_result.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/test_run_api_result_status.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/test_run_state.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/test_status_api_result.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/test_status_api_type.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/test_status_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/test_status_type.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/update_empty_test_run_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/update_link_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/validation_problem_details.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/work_item_api_result.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/work_item_entity_type_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/work_item_filter_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/work_item_filter_api_model_duration.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/work_item_id_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/work_item_parameter_key_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/work_item_parameter_key_api_result.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/work_item_priority_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/work_item_priority_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/work_item_select_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/work_item_select_api_model_filter.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/work_item_short_api_result.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/work_item_source_type_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/work_item_state_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/work_item_states.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/work_item_type_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/workflow_api_result.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model/workflow_status_api_result.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/model_utils.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/models/__init__.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/rest.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/api_client_syncstorage/__init__.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/api_client_syncstorage/api/__init__.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/api_client_syncstorage/api/completion_api.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/api_client_syncstorage/api/health_api.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/api_client_syncstorage/api/system_api.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/api_client_syncstorage/api/test_results_api.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/api_client_syncstorage/api/workers_api.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/api_client_syncstorage/api_client.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/api_client_syncstorage/apis/__init__.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/api_client_syncstorage/configuration.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/api_client_syncstorage/exceptions.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/api_client_syncstorage/model/__init__.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/api_client_syncstorage/model/completion_response.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/api_client_syncstorage/model/health_status_response.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/api_client_syncstorage/model/register_request.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/api_client_syncstorage/model/register_response.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/api_client_syncstorage/model/set_worker_status_request.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/api_client_syncstorage/model/set_worker_status_response.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/api_client_syncstorage/model/shutdown_response.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/api_client_syncstorage/model/test_result_cut_api_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/api_client_syncstorage/model/test_result_save_response.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/api_client_syncstorage/model_utils.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/api_client_syncstorage/models/__init__.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/api_client_syncstorage/rest.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/__init__.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/app_properties.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/client/__init__.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/client/client_configuration.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/client/helpers/__init__.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/client/helpers/test_result_matching.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/client/helpers/threads_manager.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/client/models/__init__.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/client/models/threads_for_create_and_result.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/client/models/threads_for_update_and_result.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/configurations/__init__.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/configurations/properties_names.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/decorators.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/dynamic_methods.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/models/__init__.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/models/adapter_mode.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/models/fixture.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/models/link.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/models/link_type.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/models/outcome_type.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/models/status_type.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/models/step_result.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/models/test_layers.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/models/test_result_with_all_fixture_step_results_model.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/services/__init__.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/services/adapter_manager_configuration.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/services/fixture_manager.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/services/fixture_storage.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/services/logger.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/services/plugin_manager.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/services/retry.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/services/step_manager.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/services/step_result_storage.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/services/sync_storage/__init__.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/services/sync_storage/sync_storage_runner.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/services/test_run_metadata.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/services/utils.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/step.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons/utils/__init__.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons.egg-info/dependency_links.txt +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons.egg-info/requires.txt +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/testit_python_commons.egg-info/top_level.txt +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/tests/test_app_properties.py +0 -0
- {testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/tests/test_dynamic_methods.py +0 -0
|
@@ -41,6 +41,7 @@ from testit_python_commons.services.retry import (
|
|
|
41
41
|
retry,
|
|
42
42
|
retry_on_connection_error,
|
|
43
43
|
)
|
|
44
|
+
from testit_python_commons.utils.html_escape_utils import HtmlEscapeUtils
|
|
44
45
|
|
|
45
46
|
|
|
46
47
|
class ApiClientWorker:
|
|
@@ -265,9 +266,9 @@ class ApiClientWorker:
|
|
|
265
266
|
self,
|
|
266
267
|
test_results: List[TestResult],
|
|
267
268
|
fixture_containers: dict,
|
|
268
|
-
|
|
269
|
+
finalized_result_keys: set = None) -> None:
|
|
269
270
|
logging.debug("call __write_tests")
|
|
270
|
-
|
|
271
|
+
finalized_result_keys = finalized_result_keys or set()
|
|
271
272
|
bulk_autotest_helper = BulkAutotestHelper(self.__autotest_api, self.__test_run_api, self.__config)
|
|
272
273
|
create_count = 0
|
|
273
274
|
update_count = 0
|
|
@@ -277,8 +278,11 @@ class ApiClientWorker:
|
|
|
277
278
|
for test_result in test_results:
|
|
278
279
|
test_result = self.__add_fixtures_to_test_result(test_result, fixture_containers)
|
|
279
280
|
external_id = test_result.get_external_id()
|
|
281
|
+
finalize_key = test_result.get_finalize_key()
|
|
280
282
|
|
|
281
|
-
|
|
283
|
+
# Skip only the same invocation (Java: by UUID). Bare externalId would
|
|
284
|
+
# drop other parametrize iterations that share one autotest id.
|
|
285
|
+
if finalize_key in finalized_result_keys:
|
|
282
286
|
skip_count += 1
|
|
283
287
|
logging.info(
|
|
284
288
|
'Bulk import: skip sendTestResults for %s (already finalized at test finish)',
|
|
@@ -469,6 +473,7 @@ class ApiClientWorker:
|
|
|
469
473
|
test_result,
|
|
470
474
|
self.__config.get_project_id())
|
|
471
475
|
|
|
476
|
+
HtmlEscapeUtils.escape_html_in_object(model)
|
|
472
477
|
autotest_response = self.__autotest_api.adapters_auto_tests_post(
|
|
473
478
|
adapters_auto_tests_post_request=model)
|
|
474
479
|
|
|
@@ -496,6 +501,7 @@ class ApiClientWorker:
|
|
|
496
501
|
model = Converter.prepare_to_update_autotest(test_result, autotest, self.__config.get_project_id())
|
|
497
502
|
|
|
498
503
|
try:
|
|
504
|
+
HtmlEscapeUtils.escape_html_in_object(model)
|
|
499
505
|
self.__autotest_api.adapters_auto_tests_put(adapters_auto_tests_put_request=model)
|
|
500
506
|
except Exception as exc:
|
|
501
507
|
if is_retriable_connection_error(exc):
|
|
@@ -562,6 +568,7 @@ class ApiClientWorker:
|
|
|
562
568
|
self.__config.get_configuration_id(),
|
|
563
569
|
self.__status_codes)
|
|
564
570
|
|
|
571
|
+
HtmlEscapeUtils.escape_html_in_object(model)
|
|
565
572
|
response = self.__test_run_api.adapters_test_runs_id_test_results_post(
|
|
566
573
|
id=self.__config.get_test_run_id(),
|
|
567
574
|
auto_test_results_for_test_run_model=[model])
|
|
@@ -45,9 +45,19 @@ from testit_python_commons.models.step_result import StepResult
|
|
|
45
45
|
from testit_python_commons.models.test_result import TestResult
|
|
46
46
|
from testit_python_commons.models.test_result_with_all_fixture_step_results_model import TestResultWithAllFixtureStepResults
|
|
47
47
|
from testit_python_commons.services.logger import adapter_logger
|
|
48
|
+
from testit_python_commons.utils.html_escape_utils import HtmlEscapeUtils
|
|
48
49
|
|
|
49
50
|
|
|
50
51
|
class Converter:
|
|
52
|
+
@staticmethod
|
|
53
|
+
def _escape_string_map(values: Optional[dict]) -> Optional[dict]:
|
|
54
|
+
if not values:
|
|
55
|
+
return values
|
|
56
|
+
return {
|
|
57
|
+
str(key): HtmlEscapeUtils.escape_html_tags(str(value)) if value is not None else value
|
|
58
|
+
for key, value in values.items()
|
|
59
|
+
}
|
|
60
|
+
|
|
51
61
|
@staticmethod
|
|
52
62
|
@adapter_logger
|
|
53
63
|
def test_run_to_test_run_short_model(
|
|
@@ -402,8 +412,8 @@ class Converter:
|
|
|
402
412
|
test_result.get_teardown_results()),
|
|
403
413
|
traces=test_result.get_traces(),
|
|
404
414
|
attachments=test_result.get_attachments(),
|
|
405
|
-
parameters=test_result.get_parameters(),
|
|
406
|
-
properties=test_result.get_properties(),
|
|
415
|
+
parameters=cls._escape_string_map(test_result.get_parameters()),
|
|
416
|
+
properties=cls._escape_string_map(test_result.get_properties()),
|
|
407
417
|
links=cls.links_to_links_post_model(
|
|
408
418
|
test_result.get_result_links()),
|
|
409
419
|
duration=round(test_result.get_duration()),
|
|
@@ -156,7 +156,7 @@ class BulkAutotestHelper:
|
|
|
156
156
|
def __create_tests(self, autotests_for_create: List[AutoTestCreateApiModel]):
|
|
157
157
|
# logging.debug(f'Creating autotests: "{autotests_for_create}')
|
|
158
158
|
|
|
159
|
-
autotests_for_create = HtmlEscapeUtils.
|
|
159
|
+
autotests_for_create = HtmlEscapeUtils.escape_html_in_object_list(autotests_for_create)
|
|
160
160
|
self.__autotests_api.adapters_auto_tests_bulk_post(auto_test_create_api_model=autotests_for_create)
|
|
161
161
|
|
|
162
162
|
logging.debug(f'Autotests were created')
|
|
@@ -165,7 +165,7 @@ class BulkAutotestHelper:
|
|
|
165
165
|
def __update_tests(self, autotests_for_update: List[AutoTestUpdateApiModel]):
|
|
166
166
|
# logging.debug(f'Updating autotests: {autotests_for_update}')
|
|
167
167
|
|
|
168
|
-
autotests_for_update = HtmlEscapeUtils.
|
|
168
|
+
autotests_for_update = HtmlEscapeUtils.escape_html_in_object_list(autotests_for_update)
|
|
169
169
|
self.__autotests_api.adapters_auto_tests_bulk_put(auto_test_update_api_model=autotests_for_update)
|
|
170
170
|
|
|
171
171
|
logging.debug(f'Autotests were updated')
|
|
@@ -174,7 +174,7 @@ class BulkAutotestHelper:
|
|
|
174
174
|
def __load_test_results(self, test_results: List[AutoTestResultsForTestRunModel]):
|
|
175
175
|
# logging.debug(f'Loading test results: {test_results}')
|
|
176
176
|
|
|
177
|
-
test_results = HtmlEscapeUtils.
|
|
177
|
+
test_results = HtmlEscapeUtils.escape_html_in_object_list(test_results)
|
|
178
178
|
self.__test_runs_api.adapters_test_runs_id_test_results_post(
|
|
179
179
|
id=self.__test_run_id,
|
|
180
180
|
auto_test_results_for_test_run_model=test_results)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import json
|
|
1
2
|
from typing import List
|
|
2
3
|
|
|
3
4
|
from testit_python_commons.models.link import Link
|
|
@@ -289,7 +290,7 @@ class TestResult:
|
|
|
289
290
|
|
|
290
291
|
@adapter_logger
|
|
291
292
|
def set_external_key(self, external_key: str):
|
|
292
|
-
self.__external_key = external_key
|
|
293
|
+
self.__external_key = HtmlEscapeUtils.escape_html_tags(external_key)
|
|
293
294
|
|
|
294
295
|
return self
|
|
295
296
|
|
|
@@ -297,6 +298,19 @@ class TestResult:
|
|
|
297
298
|
def get_external_key(self) -> str:
|
|
298
299
|
return self.__external_key
|
|
299
300
|
|
|
301
|
+
def get_finalize_key(self) -> str:
|
|
302
|
+
"""
|
|
303
|
+
Identity of one test invocation for bulk dedupe (parametrize-safe).
|
|
304
|
+
Prefer externalKey (e.g. pytest node id); else externalId + parameters.
|
|
305
|
+
"""
|
|
306
|
+
if self.__external_key:
|
|
307
|
+
return self.__external_key
|
|
308
|
+
params = self.__parameters or {}
|
|
309
|
+
return '{0}\n{1}'.format(
|
|
310
|
+
self.__external_id,
|
|
311
|
+
json.dumps(params, sort_keys=True, default=str, ensure_ascii=False),
|
|
312
|
+
)
|
|
313
|
+
|
|
300
314
|
@adapter_logger
|
|
301
315
|
def set_layer(self, layer: str):
|
|
302
316
|
self.__layer = HtmlEscapeUtils.escape_html_tags(layer) if layer else None
|
|
@@ -5,6 +5,7 @@ import uuid
|
|
|
5
5
|
from testit_python_commons.client.api_client import ApiClientWorker
|
|
6
6
|
from testit_python_commons.client.client_configuration import ClientConfiguration
|
|
7
7
|
from testit_python_commons.models.adapter_mode import AdapterMode
|
|
8
|
+
from testit_python_commons.models.status_type import StatusType
|
|
8
9
|
from testit_python_commons.models.test_result import TestResult
|
|
9
10
|
from testit_python_commons.services.adapter_manager_configuration import (
|
|
10
11
|
AdapterManagerConfiguration,
|
|
@@ -18,6 +19,7 @@ from testit_python_commons.services.sync_storage.sync_storage_runner import (
|
|
|
18
19
|
)
|
|
19
20
|
|
|
20
21
|
SYNC_STORAGE_AVAILABLE = True
|
|
22
|
+
IN_PROGRESS_LITERAL = "InProgress"
|
|
21
23
|
|
|
22
24
|
|
|
23
25
|
class AdapterManager:
|
|
@@ -33,6 +35,9 @@ class AdapterManager:
|
|
|
33
35
|
self.__api_client = ApiClientWorker(client_configuration)
|
|
34
36
|
self.__fixture_manager = fixture_manager
|
|
35
37
|
self.__test_result_map = {}
|
|
38
|
+
# Keys of results already sent at test finish (externalKey or externalId+params).
|
|
39
|
+
# Must not be bare externalId — parametrize shares one externalId.
|
|
40
|
+
self.__finalized_result_keys = set()
|
|
36
41
|
self.__test_results = []
|
|
37
42
|
self.__test_run_metadata_applied = False
|
|
38
43
|
|
|
@@ -146,23 +151,32 @@ class AdapterManager:
|
|
|
146
151
|
|
|
147
152
|
@adapter_logger
|
|
148
153
|
def write_test(self, test_result: TestResult) -> None:
|
|
149
|
-
|
|
150
|
-
self.
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
# for realtime false
|
|
154
|
-
# if
|
|
155
|
-
logging.debug("Is already in progress: " + str(self.__is_already_in_progress()))
|
|
156
|
-
# Handle Sync Storage integration if available
|
|
157
|
-
# Check if current worker is master and no test is in progress
|
|
158
|
-
if self.__is_active_syncstorage_instance() and self.__is_master_and_no_in_progress():
|
|
159
|
-
logging.debug(f"Outcome: {test_result.get_outcome()}")
|
|
160
|
-
is_ok = self.on_master_no_already_in_progress(test_result)
|
|
161
|
-
if is_ok:
|
|
154
|
+
try:
|
|
155
|
+
if self.__config.should_import_realtime():
|
|
156
|
+
self.__write_test_realtime(test_result)
|
|
162
157
|
return
|
|
163
|
-
# else continue normal processing
|
|
164
158
|
|
|
165
|
-
|
|
159
|
+
# for realtime false
|
|
160
|
+
# if
|
|
161
|
+
logging.debug("Is already in progress: " + str(self.__is_already_in_progress()))
|
|
162
|
+
# Handle Sync Storage integration if available
|
|
163
|
+
# Check if current worker is master and no test is in progress
|
|
164
|
+
if self.__is_active_syncstorage_instance() and self.__is_master_and_no_in_progress():
|
|
165
|
+
logging.debug(f"Outcome: {test_result.get_outcome()}")
|
|
166
|
+
is_ok = self.on_master_no_already_in_progress(test_result)
|
|
167
|
+
if is_ok:
|
|
168
|
+
return
|
|
169
|
+
# else continue normal processing
|
|
170
|
+
|
|
171
|
+
self.__test_results.append(test_result)
|
|
172
|
+
except Exception as exc:
|
|
173
|
+
# Do not abort the pytest/session run if TMS rejects one result (e.g. XSS validation)
|
|
174
|
+
logging.error(
|
|
175
|
+
'Failed to write test result for external_id="%s", parameters=%s: %s',
|
|
176
|
+
test_result.get_external_id(),
|
|
177
|
+
test_result.get_parameters(),
|
|
178
|
+
exc,
|
|
179
|
+
)
|
|
166
180
|
|
|
167
181
|
|
|
168
182
|
@adapter_logger
|
|
@@ -189,12 +203,31 @@ class AdapterManager:
|
|
|
189
203
|
self.__sync_storage_runner.set_is_already_in_progress(True)
|
|
190
204
|
|
|
191
205
|
try:
|
|
192
|
-
#
|
|
206
|
+
# Mode 0: finalize in TMS now (TP-bound InProgress / orphan fix).
|
|
207
|
+
# Modes 1/2: post InProgress to TMS; Work X finalizes from the cut.
|
|
208
|
+
if self.__config.get_mode() == AdapterMode.USE_FILTER:
|
|
209
|
+
logging.debug(
|
|
210
|
+
"SyncStorage accepted %s; sendTestResults with final status (mode 0)",
|
|
211
|
+
test_result.get_external_id(),
|
|
212
|
+
)
|
|
213
|
+
self._write_test_realtime_internal(test_result)
|
|
214
|
+
return True
|
|
215
|
+
|
|
216
|
+
final_outcome = test_result.get_outcome()
|
|
217
|
+
final_status_type = test_result.get_status_type()
|
|
193
218
|
logging.debug(
|
|
194
|
-
"SyncStorage accepted %s; sendTestResults
|
|
219
|
+
"SyncStorage accepted %s; sendTestResults InProgress (Work X will finalize)",
|
|
195
220
|
test_result.get_external_id(),
|
|
196
221
|
)
|
|
197
|
-
|
|
222
|
+
try:
|
|
223
|
+
test_result.set_outcome(IN_PROGRESS_LITERAL)
|
|
224
|
+
test_result.set_status_type(StatusType.INPROGRESS)
|
|
225
|
+
self._write_test_realtime_internal(test_result)
|
|
226
|
+
finally:
|
|
227
|
+
if final_outcome is not None:
|
|
228
|
+
test_result.set_outcome(final_outcome)
|
|
229
|
+
if final_status_type is not None:
|
|
230
|
+
test_result.set_status_type(final_status_type)
|
|
198
231
|
return True
|
|
199
232
|
except Exception as e:
|
|
200
233
|
logging.warning(
|
|
@@ -233,7 +266,9 @@ class AdapterManager:
|
|
|
233
266
|
logging.warning(test_result)
|
|
234
267
|
return
|
|
235
268
|
|
|
269
|
+
# Fixture attach (realtime) still indexes by externalId.
|
|
236
270
|
self.__test_result_map[ext_id] = test_result_id
|
|
271
|
+
self.__finalized_result_keys.add(test_result.get_finalize_key())
|
|
237
272
|
|
|
238
273
|
@adapter_logger
|
|
239
274
|
def write_tests(self) -> None:
|
|
@@ -265,7 +300,7 @@ class AdapterManager:
|
|
|
265
300
|
self.__api_client.write_tests(
|
|
266
301
|
self.__test_results,
|
|
267
302
|
fixtures,
|
|
268
|
-
|
|
303
|
+
finalized_result_keys=set(self.__finalized_result_keys),
|
|
269
304
|
)
|
|
270
305
|
|
|
271
306
|
@adapter_logger
|
|
@@ -15,23 +15,18 @@ class HtmlEscapeUtils:
|
|
|
15
15
|
|
|
16
16
|
NO_ESCAPE_HTML_ENV_VAR = "NO_ESCAPE_HTML"
|
|
17
17
|
|
|
18
|
-
#
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
# Using negative lookbehind to avoid double escaping
|
|
24
|
-
_LESS_THAN_PATTERN = re.compile('<')
|
|
25
|
-
_GREATER_THAN_PATTERN = re.compile('>')
|
|
26
|
-
|
|
18
|
+
# Align with Java adapters: tag must start with letter, '!' or '/'
|
|
19
|
+
_HTML_TAG_PATTERN = re.compile(
|
|
20
|
+
r'''<[a-zA-Z!/][^<>"']*(?:"[^"]*"[^<>"']*|'[^']*'[^<>"']*)*>'''
|
|
21
|
+
)
|
|
22
|
+
|
|
27
23
|
@staticmethod
|
|
28
24
|
def escape_html_tags(text: Optional[str]) -> Optional[str]:
|
|
29
25
|
"""
|
|
30
26
|
Escapes HTML tags to prevent XSS attacks.
|
|
31
27
|
First checks if the string contains HTML tags using regex pattern.
|
|
32
28
|
Only performs escaping if HTML tags are detected.
|
|
33
|
-
Escapes
|
|
34
|
-
Uses regex with negative lookbehind to avoid double escaping.
|
|
29
|
+
Escapes < as < and > as > (idempotent for already-escaped text).
|
|
35
30
|
|
|
36
31
|
Args:
|
|
37
32
|
text: The text to escape
|
|
@@ -51,11 +46,7 @@ class HtmlEscapeUtils:
|
|
|
51
46
|
if not HtmlEscapeUtils._HTML_TAG_PATTERN.search(text):
|
|
52
47
|
return text # No HTML tags found, return original string
|
|
53
48
|
|
|
54
|
-
|
|
55
|
-
result = HtmlEscapeUtils._LESS_THAN_PATTERN.sub('<', text)
|
|
56
|
-
result = HtmlEscapeUtils._GREATER_THAN_PATTERN.sub('>', result)
|
|
57
|
-
|
|
58
|
-
return result
|
|
49
|
+
return text.replace('<', '<').replace('>', '>')
|
|
59
50
|
|
|
60
51
|
@staticmethod
|
|
61
52
|
def escape_html_in_object(obj: Any) -> Any:
|
|
@@ -80,7 +71,12 @@ class HtmlEscapeUtils:
|
|
|
80
71
|
return obj
|
|
81
72
|
|
|
82
73
|
try:
|
|
83
|
-
|
|
74
|
+
if isinstance(obj, list):
|
|
75
|
+
HtmlEscapeUtils._process_list(obj)
|
|
76
|
+
elif isinstance(obj, dict):
|
|
77
|
+
HtmlEscapeUtils._process_dict(obj)
|
|
78
|
+
else:
|
|
79
|
+
HtmlEscapeUtils._process_object_attributes(obj)
|
|
84
80
|
except Exception as e:
|
|
85
81
|
# Silently ignore reflection errors
|
|
86
82
|
logging.debug(f"Error processing object attributes: {e}")
|
|
@@ -90,7 +86,7 @@ class HtmlEscapeUtils:
|
|
|
90
86
|
@staticmethod
|
|
91
87
|
def escape_html_in_object_list(obj_list: Optional[List[Any]]) -> Optional[List[Any]]:
|
|
92
88
|
"""
|
|
93
|
-
Escapes HTML tags in
|
|
89
|
+
Escapes HTML tags in list items: strings in-place, objects via reflection.
|
|
94
90
|
Can be disabled by setting NO_ESCAPE_HTML environment variable to "true".
|
|
95
91
|
|
|
96
92
|
Args:
|
|
@@ -106,47 +102,68 @@ class HtmlEscapeUtils:
|
|
|
106
102
|
no_escape_html = os.environ.get(HtmlEscapeUtils.NO_ESCAPE_HTML_ENV_VAR, "").lower()
|
|
107
103
|
if no_escape_html == "true":
|
|
108
104
|
return obj_list
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
HtmlEscapeUtils.escape_html_in_object(obj)
|
|
112
|
-
|
|
105
|
+
|
|
106
|
+
HtmlEscapeUtils._process_list(obj_list)
|
|
113
107
|
return obj_list
|
|
114
108
|
|
|
109
|
+
@staticmethod
|
|
110
|
+
def _process_dict(obj: dict) -> None:
|
|
111
|
+
for key, value in obj.items():
|
|
112
|
+
if isinstance(value, str):
|
|
113
|
+
obj[key] = HtmlEscapeUtils.escape_html_tags(value)
|
|
114
|
+
elif isinstance(value, list):
|
|
115
|
+
HtmlEscapeUtils._process_list(value)
|
|
116
|
+
elif isinstance(value, dict):
|
|
117
|
+
HtmlEscapeUtils._process_dict(value)
|
|
118
|
+
elif value is not None and not HtmlEscapeUtils._is_simple_type(type(value)):
|
|
119
|
+
HtmlEscapeUtils.escape_html_in_object(value)
|
|
120
|
+
|
|
121
|
+
@staticmethod
|
|
122
|
+
def _iter_object_attr_names(obj: Any):
|
|
123
|
+
"""
|
|
124
|
+
OpenAPI models store fields in attribute_map/_data_store; they are not listed by dir().
|
|
125
|
+
Prefer those maps, fall back to public dir() attributes for plain objects.
|
|
126
|
+
"""
|
|
127
|
+
attribute_map = getattr(obj, 'attribute_map', None)
|
|
128
|
+
if isinstance(attribute_map, dict) and attribute_map:
|
|
129
|
+
return attribute_map.keys()
|
|
130
|
+
|
|
131
|
+
data_store = getattr(obj, '_data_store', None)
|
|
132
|
+
if isinstance(data_store, dict) and data_store:
|
|
133
|
+
return data_store.keys()
|
|
134
|
+
|
|
135
|
+
return (
|
|
136
|
+
attr_name for attr_name in dir(obj)
|
|
137
|
+
if not attr_name.startswith('_') and not callable(getattr(obj, attr_name, None))
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
@staticmethod
|
|
141
|
+
def _should_skip_attr(attr_name: str) -> bool:
|
|
142
|
+
return (
|
|
143
|
+
attr_name.startswith('_')
|
|
144
|
+
or attr_name.startswith("external_id")
|
|
145
|
+
or attr_name.startswith("externalId")
|
|
146
|
+
or attr_name.startswith("auto_test_external_id")
|
|
147
|
+
or attr_name.startswith("autoTestExternalId")
|
|
148
|
+
)
|
|
149
|
+
|
|
115
150
|
@staticmethod
|
|
116
151
|
def _process_object_attributes(obj: Any) -> None:
|
|
117
152
|
"""
|
|
118
153
|
Process all attributes of an object for HTML escaping.
|
|
119
154
|
"""
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
if (
|
|
127
|
-
attr_name.startswith("external_id")
|
|
128
|
-
or attr_name.startswith("externalId")
|
|
129
|
-
or attr_name.startswith("auto_test_external_id")
|
|
130
|
-
or attr_name.startswith("autoTestExternalId")
|
|
131
|
-
):
|
|
155
|
+
for attr_name in HtmlEscapeUtils._iter_object_attr_names(obj):
|
|
156
|
+
if HtmlEscapeUtils._should_skip_attr(attr_name):
|
|
157
|
+
continue
|
|
158
|
+
|
|
159
|
+
try:
|
|
160
|
+
value = getattr(obj, attr_name, None)
|
|
161
|
+
if callable(value):
|
|
132
162
|
continue
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
except Exception as e:
|
|
138
|
-
# Silently ignore attribute errors
|
|
139
|
-
logging.debug(f"Error processing attribute {attr_name}: {e}")
|
|
140
|
-
|
|
141
|
-
# Handle dictionary objects
|
|
142
|
-
elif isinstance(obj, dict):
|
|
143
|
-
for key, value in obj.items():
|
|
144
|
-
if isinstance(value, str):
|
|
145
|
-
obj[key] = HtmlEscapeUtils.escape_html_tags(value)
|
|
146
|
-
elif isinstance(value, list):
|
|
147
|
-
HtmlEscapeUtils._process_list(value)
|
|
148
|
-
elif not HtmlEscapeUtils._is_simple_type(type(value)):
|
|
149
|
-
HtmlEscapeUtils.escape_html_in_object(value)
|
|
163
|
+
HtmlEscapeUtils._process_attribute_value(obj, attr_name, value)
|
|
164
|
+
except Exception as e:
|
|
165
|
+
# Silently ignore attribute errors
|
|
166
|
+
logging.debug(f"Error processing attribute {attr_name}: {e}")
|
|
150
167
|
|
|
151
168
|
@staticmethod
|
|
152
169
|
def _process_attribute_value(obj: Any, attr_name: str, value: Any) -> None:
|
|
@@ -162,6 +179,13 @@ class HtmlEscapeUtils:
|
|
|
162
179
|
pass
|
|
163
180
|
elif isinstance(value, list):
|
|
164
181
|
HtmlEscapeUtils._process_list(value)
|
|
182
|
+
elif isinstance(value, dict):
|
|
183
|
+
HtmlEscapeUtils._process_dict(value)
|
|
184
|
+
try:
|
|
185
|
+
# Write back so OpenAPI models that return dict copies keep escaped values
|
|
186
|
+
setattr(obj, attr_name, value)
|
|
187
|
+
except AttributeError:
|
|
188
|
+
pass
|
|
165
189
|
elif value is not None and not HtmlEscapeUtils._is_simple_type(type(value)):
|
|
166
190
|
# Process nested objects (but not simple types)
|
|
167
191
|
HtmlEscapeUtils.escape_html_in_object(value)
|
|
@@ -275,4 +275,5 @@ src/testit_python_commons/utils/__init__.py
|
|
|
275
275
|
src/testit_python_commons/utils/html_escape_utils.py
|
|
276
276
|
tests/test_app_properties.py
|
|
277
277
|
tests/test_dynamic_methods.py
|
|
278
|
-
tests/test_html_escape_utils.py
|
|
278
|
+
tests/test_html_escape_utils.py
|
|
279
|
+
tests/test_xss_parameters_escape.py
|
|
@@ -101,6 +101,32 @@ class TestHtmlEscapeUtils(unittest.TestCase):
|
|
|
101
101
|
self.assertEqual(result[0].description, "<div>content</div>")
|
|
102
102
|
self.assertEqual(result[1].description, "<span>more</span>")
|
|
103
103
|
|
|
104
|
+
def test_escape_html_in_object_accepts_list(self):
|
|
105
|
+
"""Bulk send path passes a list — must escape each item, not no-op."""
|
|
106
|
+
test_list = [
|
|
107
|
+
SampleData("First", "<script>alert(1)</script>"),
|
|
108
|
+
SampleData("Second", "<img src=x onerror=alert(1)>"),
|
|
109
|
+
]
|
|
110
|
+
result = HtmlEscapeUtils.escape_html_in_object(test_list)
|
|
111
|
+
|
|
112
|
+
self.assertEqual(result[0].description, "<script>alert(1)</script>")
|
|
113
|
+
self.assertEqual(result[1].description, "<img src=x onerror=alert(1)>")
|
|
114
|
+
|
|
115
|
+
def test_escape_html_in_list_of_strings(self):
|
|
116
|
+
tags = ["<script>alert(1)</script>", "safe", "<b>x</b>"]
|
|
117
|
+
result = HtmlEscapeUtils.escape_html_in_object(tags)
|
|
118
|
+
|
|
119
|
+
self.assertEqual(result[0], "<script>alert(1)</script>")
|
|
120
|
+
self.assertEqual(result[1], "safe")
|
|
121
|
+
self.assertEqual(result[2], "<b>x</b>")
|
|
122
|
+
|
|
123
|
+
def test_escape_html_in_list_of_dicts(self):
|
|
124
|
+
labels = [{"name": "<script>alert(1)</script>"}, {"name": "ok"}]
|
|
125
|
+
result = HtmlEscapeUtils.escape_html_in_object(labels)
|
|
126
|
+
|
|
127
|
+
self.assertEqual(result[0]["name"], "<script>alert(1)</script>")
|
|
128
|
+
self.assertEqual(result[1]["name"], "ok")
|
|
129
|
+
|
|
104
130
|
def test_escape_disabled_by_env_var(self):
|
|
105
131
|
"""Test that escaping can be disabled via environment variable"""
|
|
106
132
|
os.environ[HtmlEscapeUtils.NO_ESCAPE_HTML_ENV_VAR] = "true"
|
|
@@ -131,6 +157,36 @@ class TestHtmlEscapeUtils(unittest.TestCase):
|
|
|
131
157
|
self.assertEqual(result["tags"][0], "<tag>")
|
|
132
158
|
self.assertEqual(result["tags"][1], "normal_tag")
|
|
133
159
|
|
|
160
|
+
def test_escape_openapi_model_parameters(self):
|
|
161
|
+
"""OpenAPI models hide fields from dir(); parameters must still be escaped."""
|
|
162
|
+
from adapters_api.models import AutoTestResultsForTestRunModel, TestStatusType
|
|
163
|
+
|
|
164
|
+
model = AutoTestResultsForTestRunModel(
|
|
165
|
+
configuration_id="cfg",
|
|
166
|
+
auto_test_external_id="ext",
|
|
167
|
+
status_type=TestStatusType("Succeeded"),
|
|
168
|
+
parameters={"description": '<script>alert("1")</script>'},
|
|
169
|
+
message='<img src=x onerror=alert(1)>',
|
|
170
|
+
)
|
|
171
|
+
HtmlEscapeUtils.escape_html_in_object(model)
|
|
172
|
+
|
|
173
|
+
self.assertEqual(
|
|
174
|
+
model.parameters["description"],
|
|
175
|
+
'<script>alert("1")</script>',
|
|
176
|
+
)
|
|
177
|
+
self.assertEqual(model.message, "<img src=x onerror=alert(1)>")
|
|
178
|
+
|
|
179
|
+
def test_client_s_tag_param_and_legacy_entities(self):
|
|
180
|
+
"""Plain <s>/<script> params escape to entities; already-escaped text stays stable."""
|
|
181
|
+
self.assertEqual(
|
|
182
|
+
HtmlEscapeUtils.escape_html_tags('<s>alert("1")</s>'),
|
|
183
|
+
'<s>alert("1")</s>',
|
|
184
|
+
)
|
|
185
|
+
self.assertEqual(
|
|
186
|
+
HtmlEscapeUtils.escape_html_tags('<script>alert("1")</script>'),
|
|
187
|
+
'<script>alert("1")</script>',
|
|
188
|
+
)
|
|
189
|
+
|
|
134
190
|
|
|
135
191
|
if __name__ == '__main__':
|
|
136
192
|
unittest.main()
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""Regression: XSS in pytest params must be escaped before TMS API payloads."""
|
|
2
|
+
|
|
3
|
+
import importlib.util
|
|
4
|
+
import unittest
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from adapters_api import ApiClient
|
|
8
|
+
from testit_python_commons.client.converter import Converter
|
|
9
|
+
from testit_python_commons.models.test_result import TestResult
|
|
10
|
+
from testit_python_commons.utils.html_escape_utils import HtmlEscapeUtils
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _load_xss_payloads():
|
|
14
|
+
path = Path(__file__).resolve().parents[2] / "test_files" / "test_xss_parametrize.py"
|
|
15
|
+
spec = importlib.util.spec_from_file_location("test_xss_parametrize", path)
|
|
16
|
+
module = importlib.util.module_from_spec(spec)
|
|
17
|
+
spec.loader.exec_module(module)
|
|
18
|
+
return module.XSS_PAYLOADS
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class TestXssParametersEscape(unittest.TestCase):
|
|
22
|
+
@classmethod
|
|
23
|
+
def setUpClass(cls):
|
|
24
|
+
cls.payloads = _load_xss_payloads()
|
|
25
|
+
|
|
26
|
+
def test_test_result_parameters_escaped_for_all_payloads(self):
|
|
27
|
+
for payload in self.payloads:
|
|
28
|
+
with self.subTest(payload=payload):
|
|
29
|
+
result = TestResult().set_parameters({"description": payload})
|
|
30
|
+
value = result.get_parameters()["description"]
|
|
31
|
+
if HtmlEscapeUtils._HTML_TAG_PATTERN.search(payload):
|
|
32
|
+
self.assertNotIn("<script", value.lower().replace("<", ""))
|
|
33
|
+
self.assertIn("<", value)
|
|
34
|
+
self.assertNotEqual(value, payload)
|
|
35
|
+
# API model must keep escaped value
|
|
36
|
+
model = Converter.test_result_to_testrun_result_post_model(
|
|
37
|
+
result.set_external_id("ext").set_outcome("Passed").set_status_type("Succeeded").set_duration(1),
|
|
38
|
+
"cfg",
|
|
39
|
+
["PASSED"],
|
|
40
|
+
)
|
|
41
|
+
self.assertEqual(model.parameters["description"], value)
|
|
42
|
+
serialized = ApiClient.sanitize_for_serialization(model)
|
|
43
|
+
self.assertEqual(serialized["parameters"]["description"], value)
|
|
44
|
+
|
|
45
|
+
def test_external_key_with_nodeid_xss_is_escaped(self):
|
|
46
|
+
payload = '<script>alert("1")</script>'
|
|
47
|
+
node_key = f"tests and test_xss_parametrize.py and test_05_with_chg_xss[{payload}]"
|
|
48
|
+
result = TestResult().set_external_key(node_key)
|
|
49
|
+
escaped = result.get_external_key()
|
|
50
|
+
self.assertIn("<script>", escaped)
|
|
51
|
+
self.assertNotIn("<script>", escaped)
|
|
52
|
+
|
|
53
|
+
def test_bulk_list_escape_mutates_result_models(self):
|
|
54
|
+
payload = '<script>alert("1")</script>'
|
|
55
|
+
# Simulate model built WITHOUT going through TestResult setters (raw params)
|
|
56
|
+
class FakeResult:
|
|
57
|
+
def __init__(self):
|
|
58
|
+
self.parameters = {"description": payload}
|
|
59
|
+
self.message = payload
|
|
60
|
+
|
|
61
|
+
models = [FakeResult(), FakeResult()]
|
|
62
|
+
HtmlEscapeUtils.escape_html_in_object(models)
|
|
63
|
+
for model in models:
|
|
64
|
+
self.assertEqual(
|
|
65
|
+
model.parameters["description"],
|
|
66
|
+
'<script>alert("1")</script>',
|
|
67
|
+
)
|
|
68
|
+
self.assertEqual(model.message, '<script>alert("1")</script>')
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
if __name__ == "__main__":
|
|
72
|
+
unittest.main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/api/__init__.py
RENAMED
|
File without changes
|
{testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/api/attachments_api.py
RENAMED
|
File without changes
|
{testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/api/auto_tests_api.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{testit_python_commons-5.2.0 → testit_python_commons-5.2.2}/src/adapters_api/api/parameters_api.py
RENAMED
|
File without changes
|
|
File without changes
|