Skip to content

Commit

Permalink
CR fixes #3
Browse files Browse the repository at this point in the history
  • Loading branch information
liorblob committed Jun 22, 2020
1 parent 2831035 commit 5afcab9
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 33 deletions.
42 changes: 23 additions & 19 deletions Packs/Base/Scripts/CommonServerPython/CommonServerPython.py
Original file line number Diff line number Diff line change
Expand Up @@ -3823,6 +3823,11 @@ def dict_safe_get(dict_object, keys, default_return_value = None):
def merge_lists(original_list, updated_list, key):
"""
Replace values in a list with those in an updated list.
Example:
>>> original = [{'id': '1', 'updated': 'n'}, {'id': '2', 'updated': 'n'}, {'id': '11', 'updated': 'n'}]
>>> updated = [{'id': '1', 'updated': 'y'}, {'id': '3', 'updated': 'y'}, {'id': '11', 'updated': 'n',
>>> 'remove': True}]
>>> result = [{'id': '1', 'updated': 'y'}, {'id': '2', 'updated': 'n'}, {'id': '3', 'updated': 'y'}]
:type original_list: ``list``
:param original_list: The original list.
Expand All @@ -3836,12 +3841,6 @@ def merge_lists(original_list, updated_list, key):
:rtype: ``list``
:return: The merged list.
Example:
>>> original = [{'id': '1', 'updated': 'n'}, {'id': '2', 'updated': 'n'}, {'id': '11', 'updated': 'n'}]
>>> updated = [{'id': '1', 'updated': 'y'}, {'id': '3', 'updated': 'y'}, {'id': '11', 'updated': 'n',
>>> 'remove': True}]
>>> result = [{'id': '1', 'updated': 'y'}, {'id': '2', 'updated': 'n'}, {'id': '3', 'updated': 'y'}]
"""

original_dict = {element[key]: element for element in original_list}
Expand Down Expand Up @@ -3916,11 +3915,13 @@ def is_versioned_context_available():
return is_demisto_version_ge(MIN_VERSION_FOR_VERSIONED_CONTEXT)


def set_to_integration_context_with_retries(context, object_keys=None, sync=True):
def set_to_integration_context_with_retries(context, object_keys=None, sync=True,
max_retry_times = CONTEXT_UPDATE_RETRY_TIMES):
"""
Update the integration context with a dictionary of keys and values with multiple attempts.
The function supports merging the context keys using the provided object_keys parameter.
If the version is too old by the time the context is set, another attempt will be made until the limit.
If the version is too old by the time the context is set,
another attempt will be made until the limit after a random sleep.
:type context: ``dict``
:param context: A dictionary of keys and values to set.
Expand All @@ -3929,7 +3930,10 @@ def set_to_integration_context_with_retries(context, object_keys=None, sync=True
:param object_keys: A dictionary to map between context keys and their unique ID for merging them.
:type sync: ``bool``
:param sync: Whether to make a versioned request.
:param sync: Whether to save the context directly to the DB.
:type max_retry_times: ``int``
:param max_retry_times: The maximum number of attempts to try.
:rtype: ``None``
:return: None
Expand All @@ -3938,31 +3942,31 @@ def set_to_integration_context_with_retries(context, object_keys=None, sync=True

# do while...
while True:
if attempt == CONTEXT_UPDATE_RETRY_TIMES:
if attempt == max_retry_times:
raise Exception('Failed updating integration context. Max retry attempts exceeded.')

# Update the latest context and get the new version
integration_context, version = update_context(context, object_keys, sync)
integration_context, version = update_integration_context(context, object_keys, sync)

demisto.info('Attempting to update the integration context with version {}.'.format(version))
demisto.debug('Attempting to update the integration context with version {}.'.format(version))

# Attempt to update integration context with a version.
# If we get a ValueError (DB Version), the version is too old. Then we need to try again.
attempt = attempt + 1
# If we get a ValueError (DB Version), then the version was not updated and we need to try again.
attempt += 1
try:
set_integration_context(integration_context, sync, version)
demisto.info('Successfully updated integration context. New version is {}.'
demisto.debug('Successfully updated integration context. New version is {}.'
.format(version + 1 if version != -1 else version))
break
except ValueError as ve:
demisto.info('Failed updating integration context with version {}: {} Attempts left - {}'
demisto.debug('Failed updating integration context with version {}: {} Attempts left - {}'
.format(version, str(ve), CONTEXT_UPDATE_RETRY_TIMES - attempt))
# Sleep for a random time
time_to_sleep = randint(1, 100) / 1000
time.sleep(time_to_sleep)


def get_integration_context_with_version(sync):
def get_integration_context_with_version(sync=True):
"""
Get the latest integration context with version, if available.
Expand All @@ -3984,7 +3988,7 @@ def get_integration_context_with_version(sync):
return integration_context, version


def update_context(context, object_keys=None, sync=True):
def update_integration_context(context, object_keys=None, sync=True):
"""
Update the integration context with a given dictionary after merging it with the latest integration context.
Expand All @@ -4006,7 +4010,7 @@ def update_context(context, object_keys=None, sync=True):
if not object_keys:
object_keys = {}

for key, value in context.items():
for key, _ in context.items():
latest_object = json.loads(integration_context.get(key, '[]'))
updated_object = context[key]
if key in object_keys:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2121,7 +2121,7 @@ def test_update_context_merge(mocker):
mirrors.extend([new_mirror])

# Arrange
context, version = CommonServerPython.update_context({'mirrors': [new_mirror]}, OBJECTS_TO_KEYS, True)
context, version = CommonServerPython.update_integration_context({'mirrors': [new_mirror]}, OBJECTS_TO_KEYS, True)
new_mirrors = json.loads(context['mirrors'])

# Assert
Expand Down Expand Up @@ -2151,7 +2151,7 @@ def test_update_context_no_merge(mocker):
conversations.extend([new_conversation])

# Arrange
context, version = CommonServerPython.update_context({'conversations': conversations}, OBJECTS_TO_KEYS, True)
context, version = CommonServerPython.update_integration_context({'conversations': conversations}, OBJECTS_TO_KEYS, True)
new_conversations = json.loads(context['conversations'])

# Assert
Expand Down Expand Up @@ -2195,7 +2195,7 @@ def test_set_latest_integration_context(mocker):
mocker.patch.object(demisto, 'getIntegrationContextVersioned', return_value=get_integration_context_versioned())
mocker.patch.object(demisto, 'setIntegrationContextVersioned', side_effecet=set_integration_context_versioned)
int_context = get_integration_context_versioned()
mocker.patch.object(CommonServerPython, 'update_context',
mocker.patch.object(CommonServerPython, 'update_integration_context',
side_effect=[(int_context['context'], int_context['version']),
(int_context['context'], int_context['version'] + 1)])
mocker.patch.object(CommonServerPython, 'set_integration_context', side_effect=[ValueError, int_context['context']])
Expand Down Expand Up @@ -2224,7 +2224,7 @@ def test_set_latest_integration_context_fail(mocker):
mocker.patch.object(demisto, 'getIntegrationContextVersioned', return_value=get_integration_context_versioned())
mocker.patch.object(demisto, 'setIntegrationContextVersioned', side_effecet=set_integration_context_versioned)
int_context = get_integration_context_versioned()
mocker.patch.object(CommonServerPython, 'update_context', return_value=(int_context['context'],
mocker.patch.object(CommonServerPython, 'update_integration_context', return_value=(int_context['context'],
int_context['version']))
mocker.patch.object(CommonServerPython, 'set_integration_context', side_effect=ValueError)

Expand Down
12 changes: 6 additions & 6 deletions Packs/Slack/Integrations/Slack/Slack.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
from slack.web.slack_response import SlackResponse

from distutils.util import strtobool
from random import randint
from typing import Tuple, Dict, List, Optional
import asyncio
import concurrent
Expand Down Expand Up @@ -54,6 +53,7 @@
'questions': 'entitlement',
'users': 'id'
}
SYNC_CONTEXT = True

''' GLOBALS '''

Expand Down Expand Up @@ -224,7 +224,8 @@ def find_mirror_by_investigation() -> dict:

return mirror

def set_name_and_icon(body, method):

def set_name_and_icon(body: dict, method: str):
"""
If provided, sets a name and an icon for the bot if a message is sent.
Args:
Expand Down Expand Up @@ -1060,7 +1061,7 @@ async def create_incidents(incidents: list, user_name: str, user_email: str, use


@slack.RTMClient.run_on(event='message')
async def listen(**payload):
async def listen(**payload: dict):
"""
Listens to Slack RTM messages
Expand Down Expand Up @@ -1141,7 +1142,7 @@ async def listen(**payload):
await handle_listen_error(f'Error occurred while listening to Slack: {str(e)}')


async def get_user_by_id_async(client, user_id):
async def get_user_by_id_async(client: slack.WebClient, user_id: str) -> dict:
"""
Get the details of a slack user by id asynchronously.
Args:
Expand Down Expand Up @@ -1886,7 +1887,7 @@ def init_globals(command_name: str = ''):
"""
global BOT_TOKEN, ACCESS_TOKEN, PROXY_URL, PROXIES, DEDICATED_CHANNEL, CLIENT, CHANNEL_CLIENT
global SEVERITY_THRESHOLD, ALLOW_INCIDENTS, NOTIFY_INCIDENTS, INCIDENT_TYPE, VERIFY_CERT
global BOT_NAME, BOT_ICON_URL, MAX_LIMIT_TIME, PAGINATED_COUNT, SSL_CONTEXT, SYNC_CONTEXT
global BOT_NAME, BOT_ICON_URL, MAX_LIMIT_TIME, PAGINATED_COUNT, SSL_CONTEXT

VERIFY_CERT = not demisto.params().get('unsecure', False)
if not VERIFY_CERT:
Expand Down Expand Up @@ -1919,7 +1920,6 @@ def init_globals(command_name: str = ''):
BOT_ICON_URL = demisto.params().get('bot_icon') # Bot default icon url defined by the slack plugin (3-rd party)
MAX_LIMIT_TIME = int(demisto.params().get('max_limit_time', '60'))
PAGINATED_COUNT = int(demisto.params().get('paginated_count', '200'))
SYNC_CONTEXT = True


def print_thread_dump():
Expand Down
7 changes: 3 additions & 4 deletions Tests/demistomock/demistomock.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import uuid

integrationContext = {}
integrationContextVersioned = {}
is_debug = False # type: bool

exampleIncidents = [
Expand Down Expand Up @@ -505,8 +504,8 @@ def setIntegrationContextVersioned(context, version=-1, sync=False):
the context will be saved at the end of the command.
"""
global integrationContextVersioned
integrationContextVersioned = context
global integrationContext
integrationContext = context


def getIntegrationContextVersioned(refresh=False):
Expand All @@ -518,7 +517,7 @@ def getIntegrationContextVersioned(refresh=False):
Returns:
Dict with a key of context and a key of version.
"""
return integrationContextVersioned
return integrationContext

def incidents(incidents=None):
"""
Expand Down

0 comments on commit 5afcab9

Please sign in to comment.