Skip to content

Commit

Permalink
Validation checks & Unit test cases added
Browse files Browse the repository at this point in the history
  • Loading branch information
namrata-metron committed Feb 9, 2024
1 parent 679e056 commit 0a3e7bc
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 15 deletions.
38 changes: 25 additions & 13 deletions Packs/Devo/Integrations/Devo_v2/Devo_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -825,15 +825,16 @@ def multi_table_query_command(offset, items):


def convert_to_str(value):
warnings = []
if isinstance(value, list) and len(value) == 0:
print("Warning: Empty list encountered.")
return '[]'
warnings.append("Empty list encountered.")
return '[]', warnings
elif isinstance(value, dict) and not value:
print("Warning: Empty dictionary encountered.")
return '{}'
elif isinstance(value, (list, dict)):
return json.dumps(value)
return str(value)
warnings.append("Empty dictionary encountered.")
return '{}', warnings
elif isinstance(value, list | dict):
return json.dumps(value), warnings
return str(value), warnings


def write_to_table_command():
Expand Down Expand Up @@ -878,15 +879,15 @@ def write_to_table_command():
formatted_record = convert_to_str(r)

# If the record is empty, skip sending it
if not formatted_record.strip():
if not len(formatted_record):
continue

# Send each record to Devo with the specified tag
sender.send(tag=final_tag, msg=formatted_record)

# Update totals
total_events += 1
total_bytes_sent += len(formatted_record.encode("utf-8"))
total_bytes_sent += len(formatted_record)

current_ts = int(time.time())
start_ts = (current_ts - 30) * 1000
Expand Down Expand Up @@ -957,14 +958,25 @@ def write_to_lookup_table_command():
total_events = 0
total_bytes = 0

# Validate headers
if not isinstance(headers, dict) or "headers" not in headers or not isinstance(headers["headers"], list):
raise ValueError("Invalid headers format. 'headers' must be a list.")

columns = headers["headers"]

# Validate key_index
key_index = int(headers.get("key_index", 0)) # Ensure it's casted to integer
if key_index < 0:
raise ValueError("key_index must be a non-negative integer value.")

# Validate action
action = headers.get("action", "")
if action not in {"INC", "FULL"}:
raise ValueError("action must be either 'INC' or 'FULL'.")
try:
con = Sender(config=engine_config, timeout=60)
lookup = Lookup(name=lookup_table_name, con=con)

# Prepare headers for sending
columns = headers.get("headers", [])
key_index = headers.get("key_index", 0)
action = headers.get("action", "")
lookup.send_headers(headers=columns, key_index=key_index, event="START", action=action)

# Send data lines
Expand Down
96 changes: 94 additions & 2 deletions Packs/Devo/Integrations/Devo_v2/Devo_v2_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@
}
MOCK_WRITER_ARGS = {
"tableName": "whatever.table",
"records": [{"foo": "hello"}, {"foo": "world"}, {"foo": "demisto"}],
"records": '[{"foo": "hello"}, {"foo": "world"}, {"foo": "demisto"}]',
}
MOCK_WRITE_TO_TABLE_RECORDS = {
"tableName": "whatever.table",
Expand All @@ -163,6 +163,20 @@
'{"fields": ["foo2", "bar2", "baz2"]}, '
'{"fields": ["foo3", "bar3", "baz3"]}]')
}
MOCK_LOOKUP_WRITER_ARGS_key = {
"lookupTableName": "hello.world.lookup",
"headers": '{"headers": ["foo", "bar", "baz"], "key_index": 0, "action": "FULL"}',
"records": ('[{"fields": ["foo1", "bar1", "baz1"], "delete": false}, '
'{"fields": ["foo2", "bar2", "baz2"]}, '
'{"fields": ["foo3", "bar3", "baz3"]}]')
}
MOCK_LOOKUP_WRITER_ARGS_action = {
"lookupTableName": "hello.world.lookup",
"headers": '{"headers": ["foo", "bar", "baz"], "key_index": 0, "action": "INC"}',
"records": ('[{"fields": ["foo1", "bar1", "baz1"], "delete": false}, '
'{"fields": ["foo2", "bar2", "baz2"]}, '
'{"fields": ["foo3", "bar3", "baz3"]}]')
}
MOCK_KEYS = {"foo": "bar", "baz": "bug"}
OFFSET = 0
ITEMS_PER_PAGE = 10
Expand Down Expand Up @@ -502,13 +516,37 @@ def test_write_devo(mock_load_results, mock_write_args):
assert len(results) == 2 # We expect two entries in the results list
found = False
for result in results:
if "HumanReadable" in result and result["HumanReadable"] == "Total Records Sent: 3.\nTotal Bytes Sent: 48.":
if "HumanReadable" in result and result["HumanReadable"] == "Total Records Sent: 3.\nTotal Bytes Sent: 6.":
found = True
break
assert found, "Expected string not found in 'HumanReadable' field of results"
assert results[0]["EntryContext"]["Devo.LinqQuery"] == "from whatever.table"


@patch("Devo_v2.WRITER_RELAY", MOCK_WRITER_RELAY, create=True)
@patch("Devo_v2.WRITER_CREDENTIALS", MOCK_WRITER_CREDENTIALS, create=True)
@patch("Devo_v2.demisto.args")
@patch("Devo_v2.Sender")
def test_write_devo_data(mock_load_results, mock_write_args):
mock_load_results.return_value.load.return_value = MOCK_LINQ_RETURN
mock_write_args.return_value = MOCK_WRITER_ARGS
try:
write_to_table_command()
except ValueError as exc:
error_msg = str(exc)
assert "Error decoding JSON. Please ensure the records are valid JSON." in error_msg
try:
write_to_table_command()
except ValueError as exc:
error_msg = str(exc)
assert "The 'records' parameter must be a list." in error_msg
try:
write_to_table_command()
except ValueError as exc:
error_msg = str(exc)
assert "All records are empty." in error_msg


@patch("Devo_v2.WRITER_RELAY", MOCK_WRITER_RELAY, create=True)
@patch("Devo_v2.WRITER_CREDENTIALS", MOCK_WRITER_CREDENTIALS, create=True)
@patch("Devo_v2.demisto.args")
Expand All @@ -527,6 +565,60 @@ def test_write_lookup_devo(
assert "Total Bytes Sent: 125." in results


@patch("Devo_v2.WRITER_RELAY", MOCK_WRITER_RELAY, create=True)
@patch("Devo_v2.WRITER_CREDENTIALS", MOCK_WRITER_CREDENTIALS, create=True)
@patch("Devo_v2.demisto.args")
@patch("Devo_v2.Sender")
@patch("Devo_v2.Lookup")
def test_write_lookup_devo_header(
mock_lookup_writer_lookup, mock_lookup_writer_sender, mock_lookup_write_args
):
mock_lookup_write_args.return_value = MOCK_LOOKUP_WRITER_ARGS
mock_lookup_writer_sender.return_value = MOCK_SENDER()
mock_lookup_writer_lookup.return_value = MOCK_LOOKUP()
try:
write_to_lookup_table_command()
except ValueError as exc:
error_msg = str(exc)
assert "Invalid headers format. 'headers' must be a list." in error_msg


@patch("Devo_v2.WRITER_RELAY", MOCK_WRITER_RELAY, create=True)
@patch("Devo_v2.WRITER_CREDENTIALS", MOCK_WRITER_CREDENTIALS, create=True)
@patch("Devo_v2.demisto.args")
@patch("Devo_v2.Sender")
@patch("Devo_v2.Lookup")
def test_write_lookup_devo_invalid(
mock_lookup_writer_lookup, mock_lookup_writer_sender, mock_lookup_write_args
):
mock_lookup_write_args.return_value = MOCK_LOOKUP_WRITER_ARGS_key
mock_lookup_writer_sender.return_value = MOCK_SENDER()
mock_lookup_writer_lookup.return_value = MOCK_LOOKUP()
try:
write_to_lookup_table_command()
except ValueError as exc:
error_msg = str(exc)
assert "key_index must be a non-negative integer value." in error_msg


@patch("Devo_v2.WRITER_RELAY", MOCK_WRITER_RELAY, create=True)
@patch("Devo_v2.WRITER_CREDENTIALS", MOCK_WRITER_CREDENTIALS, create=True)
@patch("Devo_v2.demisto.args")
@patch("Devo_v2.Sender")
@patch("Devo_v2.Lookup")
def test_write_lookup_devo_invalid_action(
mock_lookup_writer_lookup, mock_lookup_writer_sender, mock_lookup_write_args
):
mock_lookup_write_args.return_value = MOCK_LOOKUP_WRITER_ARGS_action
mock_lookup_writer_sender.return_value = MOCK_SENDER()
mock_lookup_writer_lookup.return_value = MOCK_LOOKUP()
try:
write_to_lookup_table_command()
except ValueError as err:
error = str(err)
assert "action must be either 'INC' or 'FULL'." in error


@patch("Devo_v2.demisto_ISO", return_value="2022-03-15T15:01:23.456Z")
def test_alert_to_incident_all_data(mock_demisto_ISO):
incident = alert_to_incident(ALERT, USER_PREFIX)
Expand Down

0 comments on commit 0a3e7bc

Please sign in to comment.