from unittest.mock import MagicMock from CommonServerPython import * import pytest from Packs.CommonScripts.Scripts.SearchIssues import SearchIssues from SearchIssues import * def test_create_sha_search_field_query_single_value(): result = create_sha_search_field_query("actor_process_image_sha256", EQ, ["abc123"]) expected = {"AND": [{"OR": [{"SEARCH_FIELD": "actor_process_image_sha256", "SEARCH_TYPE": "EQ", "SEARCH_VALUE": "abc123"}]}]} assert result == expected def test_create_sha_search_field_query_multiple_values(): result = create_sha_search_field_query("actor_process_image_sha256", EQ, ["abc123", "def456"]) expected = { "AND": [ { "OR": [ {"SEARCH_FIELD": "actor_process_image_sha256", "SEARCH_TYPE": "EQ", "SEARCH_VALUE": "abc123"}, {"SEARCH_FIELD": "actor_process_image_sha256", "SEARCH_TYPE": "EQ", "SEARCH_VALUE": "def456"}, ] } ] } assert result == expected def test_create_sha_search_field_query_empty_list(): result = create_sha_search_field_query("actor_process_image_sha256", EQ, []) assert result is None def test_prepare_sha256_custom_field_empty_input(): args = {"sha256": None} result = prepare_sha256_custom_field(args) assert result is None @pytest.mark.parametrize("sha_values", [["abc123", "xyz456"]]) def test_main_with_sha256_filter(monkeypatch, sha_values): expected_custom_filter = """{ "OR": [ { "AND": [ { "OR": [ { "SEARCH_FIELD": "actor_process_image_sha256", "SEARCH_TYPE": "EQ", "SEARCH_VALUE": "abc123" }, { "SEARCH_FIELD": "actor_process_image_sha256", "SEARCH_TYPE": "EQ", "SEARCH_VALUE": "xyz456" } ] } ] }, { "AND": [ { "OR": [ { "SEARCH_FIELD": "causality_actor_process_image_sha256", "SEARCH_TYPE": "EQ", "SEARCH_VALUE": "abc123" }, { "SEARCH_FIELD": "causality_actor_process_image_sha256", "SEARCH_TYPE": "EQ", "SEARCH_VALUE": "xyz456" } ] } ] }, { "AND": [ { "OR": [ { "SEARCH_FIELD": "action_process_image_sha256", "SEARCH_TYPE": "EQ", "SEARCH_VALUE": "abc123" }, { "SEARCH_FIELD": "action_process_image_sha256", "SEARCH_TYPE": "EQ", "SEARCH_VALUE": "xyz456" } ] } ] }, { "AND": [ { "OR": [ { "SEARCH_FIELD": "os_actor_process_image_sha256", "SEARCH_TYPE": "EQ", "SEARCH_VALUE": "abc123" }, { "SEARCH_FIELD": "os_actor_process_image_sha256", "SEARCH_TYPE": "EQ", "SEARCH_VALUE": "xyz456" } ] } ] }, { "AND": [ { "OR": [ { "SEARCH_FIELD": "action_file_macro_sha256", "SEARCH_TYPE": "EQ", "SEARCH_VALUE": "abc123" }, { "SEARCH_FIELD": "action_file_macro_sha256", "SEARCH_TYPE": "EQ", "SEARCH_VALUE": "xyz456" } ] } ] } ] }""" # Mock demisto.args() monkeypatch.setattr( SearchIssues.demisto, "args", lambda: {"sha256": ",".join(sha_values), "start_time": "2024-01-01", "end_time": "2024-01-02"}, ) # Mock demisto.executeCommand() fake_response = { "EntryContext": { "Core.Issue(val.internal_id && val.internal_id == obj.internal_id)": [{"internal_id": "test123", "severity": "high"}] }, "HumanReadable": "Sample Issue Result", "Type": 1, } execute_command_mock = MagicMock(return_value=[fake_response]) monkeypatch.setattr(SearchIssues.demisto, "executeCommand", execute_command_mock) # Mock demisto.debug and return_results monkeypatch.setattr(SearchIssues, "return_results", lambda x: x) monkeypatch.setattr(SearchIssues.demisto, "debug", lambda x: None) SearchIssues.main() # Ensure core-get-issues was called assert execute_command_mock.called, "core-get-issues was not called" # Get the actual args passed to core-get-issues called_args = execute_command_mock.call_args[0][1] # [0] is args tuple, [1] is the args dict assert "custom_filter" in called_args, "custom_filter not found in args" expected_dict = json.loads(expected_custom_filter) actual_dict = json.loads(called_args["custom_filter"]) assert actual_dict == expected_dict, "custom_filter structure does not match expected" @pytest.mark.parametrize( "args, expected", [ # empty string values are dropped ({"status": "", "severity": "high"}, {"severity": "high"}), # all empty → empty result ({"status": "", "page": ""}, {}), # empty input dict ({}, {}), # non-empty regular args are kept as-is ({"status": "active", "severity": "low"}, {"status": "active", "severity": "low"}), ], ) def test_remove_empty_string_values_general(args, expected): assert remove_empty_string_values(args) == expected @pytest.mark.parametrize( "key, value, should_keep", [ ("page", "1", True), ("page", "0", True), ("page_size", "100", True), ("page", " 3 ", True), ("page_size", " 10 ", True), ("page", "n/a", False), ("page", "invalid_offset", False), ("page", "1.5", False), ("page", "-1", False), ("page", "abc", False), ("page_size", "bad", False), ("page", "", False), ("page_size", "", False), ], ) def test_remove_empty_string_values_numeric_args(key, value, should_keep): result = remove_empty_string_values({key: value}) if should_keep: assert result == {key: value} else: assert result == {} @pytest.mark.parametrize( "value, should_keep", [ ("42", True), ("1,2,3", True), (["10", "20"], True), ("n/a", False), ("abc", False), ("1,abc,3", False), (["10", "n/a"], False), ("", False), ], ) def test_remove_empty_string_values_numeric_list_args(value, should_keep): result = remove_empty_string_values({"issue_id": value}) if should_keep: assert result == {"issue_id": value} else: assert result == {} @pytest.mark.parametrize( "args, expected", [ ( # valid regular + valid numeric + valid list {"status": "active", "page": "2", "issue_id": "7,8"}, {"status": "active", "page": "2", "issue_id": "7,8"}, ), ( # empty string dropped, invalid numeric dropped, valid list kept {"severity": "", "page_size": "bad", "issue_id": "1,2"}, {"issue_id": "1,2"}, ), ( # all three categories invalid → empty result {"severity": "", "page": "n/a", "issue_id": "abc"}, {}, ), ( # numeric arg valid, list arg invalid, regular arg kept {"page": "5", "issue_id": "x,y", "status": "closed"}, {"page": "5", "status": "closed"}, ), ], ) def test_remove_empty_string_values_mixed(args, expected): assert remove_empty_string_values(args) == expected