diff --git a/Packs/Base/ReleaseNotes/1_41_24.md b/Packs/Base/ReleaseNotes/1_41_24.md new file mode 100644 index 000000000000..688f401c0ea0 --- /dev/null +++ b/Packs/Base/ReleaseNotes/1_41_24.md @@ -0,0 +1,6 @@ + +#### Scripts + +##### CommonServerPython + +- Fixed an issue where duplicate events were fetched. diff --git a/Packs/Base/Scripts/CommonServerPython/CommonServerPython.py b/Packs/Base/Scripts/CommonServerPython/CommonServerPython.py index afc1360c5187..1b76aeb0e994 100644 --- a/Packs/Base/Scripts/CommonServerPython/CommonServerPython.py +++ b/Packs/Base/Scripts/CommonServerPython/CommonServerPython.py @@ -11697,9 +11697,15 @@ def remove_old_incidents_ids(found_incidents_ids, current_time, look_back): deletion_threshold_in_seconds = look_back_in_seconds * 2 new_found_incidents_ids = {} + latest_incident_time = max(found_incidents_ids.values() or [current_time]) + demisto.debug('lb: latest_incident_time is {}'.format(latest_incident_time)) + for inc_id, addition_time in found_incidents_ids.items(): - if current_time - addition_time <= deletion_threshold_in_seconds: + if ( + current_time - addition_time <= deletion_threshold_in_seconds + or addition_time == latest_incident_time # The latest IDs must be kept to avoid duplicate incidents + ): new_found_incidents_ids[inc_id] = addition_time demisto.debug('lb: Adding incident id: {}, its addition time: {}, deletion_threshold_in_seconds: {}'.format( inc_id, addition_time, deletion_threshold_in_seconds)) @@ -11708,6 +11714,7 @@ def remove_old_incidents_ids(found_incidents_ids, current_time, look_back): inc_id, addition_time, deletion_threshold_in_seconds)) demisto.debug('lb: Number of new found ids: {}, their ids: {}'.format( len(new_found_incidents_ids), new_found_incidents_ids.keys())) + return new_found_incidents_ids @@ -12891,7 +12898,7 @@ def __exit__(self, exc_type, exc_val, exc_tb): demisto.debug("Resetting timed signal") signal.alarm(0) # Cancel SIGALRM if it's scheduled return exc_type is SignalTimeoutError # True if a timeout is reacched, False otherwise - + @classmethod def limit_time(cls, seconds, default_return_value=None): """ diff --git a/Packs/Base/Scripts/CommonServerPython/CommonServerPython_test.py b/Packs/Base/Scripts/CommonServerPython/CommonServerPython_test.py index ff6b6fb3b1b4..fe3c873099ad 100644 --- a/Packs/Base/Scripts/CommonServerPython/CommonServerPython_test.py +++ b/Packs/Base/Scripts/CommonServerPython/CommonServerPython_test.py @@ -1020,7 +1020,7 @@ def test_list_integers(): Then: Validate that the script ran successfully. """ - data = {'key': 'value', 'listtest': [1, 2, 3, 4]} + data = {'key': 'value', 'listtest': [1, 2, 3, 4]} table = tableToMarkdown("tableToMarkdown test", data, sort_headers=False, is_auto_json_transform=True) assert table @@ -3787,7 +3787,7 @@ def test_return_outputs_text_raw_response(self, mocker): pytest.param('on', True, id='string_on_lowercase'), pytest.param('ON', True, id='string_on_uppercase'), pytest.param('1', True, id='string_one'), - + # False values pytest.param('false', False, id='string_false_lowercase'), pytest.param('no', False, id='string_no_lowercase'), @@ -8694,6 +8694,23 @@ def test_calculate_new_offset(self): assert calculate_new_offset(1, 2, 3) == 0 assert calculate_new_offset(1, 2, None) == 3 + def test_remove_old_incidents_ids(self): + """ + Test that the remove_old_incidents_ids function removes old incident IDs from the last run object. + Given: + A last run object with incident IDs and their addition times. + When: + Calling remove_old_incidents_ids with the last run object and a look back period. + Then: + Make sure that the old incident IDs are removed from the last run object and the latest incident IDs is returned. + """ + from CommonServerPython import remove_old_incidents_ids + + assert remove_old_incidents_ids( + {"inc1": 1, "inc2": 2, "inc3": 3}, 1000, 1) == {"inc3": 3} + assert remove_old_incidents_ids( + {"inc1": 1, "inc2": 2, "inc3": 2}, 1000, 1) == {"inc2": 2, "inc3": 2} + class TestTracebackLineNumberAdgustment: @staticmethod @@ -9773,12 +9790,12 @@ def test_censor_request_logs(request_log, expected_output): case 3: A request log with a sensitive data under the 'Authorization' header, but with no 'Bearer' prefix. case 4: A request log with a sensitive data under the 'Authorization' header, but with no 'send b' prefix at the beginning. case 5: A request log with no sensitive data. - case 6: A request log with a sensitive data under the 'Authorization' header, with a "LOG" prefix (which used in cases + case 6: A request log with a sensitive data under the 'Authorization' header, with a "LOG" prefix (which used in cases like HMAC signature authentication). When: Running censor_request_logs function. Then: - Assert the function returns the exactly same log with the sensitive data masked. + Assert the function returns the exactly same log with the sensitive data masked. """ assert censor_request_logs(request_log) == expected_output @@ -9953,18 +9970,18 @@ def test_get_server_config_fail(mocker): "Test-instanec-without-xsoar-engine-configures" ]) def test_is_integration_instance_running_on_engine(mocker, instance_name, expected_result): - """ Tests the 'is_integration_instance_running_on_engine' function's logic. + """ Tests the 'is_integration_instance_running_on_engine' function's logic. - Given: + Given: 1. A name of an instance that has an engine configured (and relevant mocked responses). 2. A name of an instance that doesn't have an engine configured (and relevant mocked responses). - When: - - Running the 'is_integration_instance_running_on_engine' funcution. + When: + - Running the 'is_integration_instance_running_on_engine' funcution. Then: - - Verify that: - 1. The result is the engine's id. + - Verify that: + 1. The result is the engine's id. 2. The result is an empty string. """ mock_response = { @@ -9980,14 +9997,14 @@ def test_is_integration_instance_running_on_engine(mocker, instance_name, expect def test_get_engine_base_url(mocker): - """ Tests the 'get_engine_base_url' function's logic. + """ Tests the 'get_engine_base_url' function's logic. - Given: + Given: - Mocked response of the internalHttpRequest call for the '/engines' endpoint, including 2 engines. - - An id of an engine. + - An id of an engine. - When: - - Running the 'is_integration_instance_running_on_engine' funcution. + When: + - Running the 'is_integration_instance_running_on_engine' funcution. Then: - Verify that base url of the given engine id was returened. @@ -10659,5 +10676,5 @@ def test_execution_timeout_decorator(sleep_time, expected_return_value): def do_logic(): time.sleep(sleep_time) return "I AM DONE" - + assert do_logic() == expected_return_value diff --git a/Packs/Base/pack_metadata.json b/Packs/Base/pack_metadata.json index 03fe61d9af3a..8685a0454d29 100644 --- a/Packs/Base/pack_metadata.json +++ b/Packs/Base/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Base", "description": "The base pack for Cortex XSOAR.", "support": "xsoar", - "currentVersion": "1.41.23", + "currentVersion": "1.41.24", "author": "Cortex XSOAR", "serverMinVersion": "6.0.0", "url": "https://www.paloaltonetworks.com/cortex",