UnitTest
Provides for automated testing of automations, playbooks, and sub-playbooks.
python · Content Testing
Source
import io import uuid import demistomock as demisto # noqa: F401 from CommonServerPython import * # noqa: F401 def GetAutomationId(name): autoId = execute_command("core-api-post", {"uri": f"/automation/load/{name}"})["response"]["id"] return autoId def GetPlaybookId(name): playbook = execute_command("core-api-post", {"uri": "/playbook/search", "body": {"query": "name:" + f'"{name}"'}})[ "response"]["playbooks"] if playbook is None: return "-1" pbid = playbook[0]["id"] return pbid def RunUTResults(args): try: # Set up the task arguments addafter = args["addafter"] incid = args["incid"] gridfld = args["gridfield"] scriptid = GetAutomationId("UnitTestResults") newargs = { "cmds": {"simple": ",".join(args["cmds"])}, "tasks": {"simple": ",".join(args["tasks"])}, "gridfield": {"simple": gridfld}, "status": {"simple": str(args["status"]).replace("[", "").replace("]", "")}, } task = { "name": "DisplayUnitTestResults", "description": "", "loop": {}, "tags": [], # ID for "UnitTestResults" automation "automationScript": scriptid, "type": "regular", "neighborInvPBTaskId": addafter, "addAfter": True, "playbookId": "", "ignoreWorker": True, "scriptArguments": newargs, "separateContext": None, "pageSize": 50, "version": -1, } # Add the task to display unit test results attempts = 0 while attempts < 5: results = execute_command("core-api-post", {"uri": f"/inv-playbook/task/add/{incid}", "body": task}) if "response" in results: results = results["response"] if "tasks" in results: tasks = results["tasks"] break attempts = attempts + 1 # Find the task ID of the last "DisplayUnitTestResults" task that was just added to the playbook new_id = "0" task_id = "0" if attempts < 5: for _key, val in tasks.items(): if ( "scriptId" in val["task"] and val["task"]["scriptId"] == scriptid and val["task"]["name"] == "DisplayUnitTestResults" ): new_id = val["id"] if int(new_id) > int(task_id): task_id = new_id else: raise DemistoException("unable to add DisplayUnitTestResults task to playbook") # Execute the task inside a demisto lock to prevent concurrent updates to the unit test status grid field attempts = 0 contents = execute_command("demisto-lock-get", {"name": gridfld, "timeout": 60}) if "Lock acquired successfully" in contents: while attempts < 5: start_response = execute_command( "core-api-post", { "uri": "/inv-playbook/task/execute", "body": { "taskinfo": {"invId": incid, "inTaskID": task_id, "version": -1, "args": newargs, "loopArgs": {}}, "playbooksdebuginfo": {}, "pageSize": 50, }, }, ) if "response" not in start_response: attempts = attempts + 1 else: break execute_command("demisto-lock-release", {"name": gridfld}) else: raise DemistoException(f"unable to acquire lock name: {gridfld}") except Exception as ex: execute_command("demisto-lock-release", {"name": gridfld}) demisto.error(traceback.format_exc()) return_error(f"RunUTResults: Exception failed to execute. Error: {ex!s}") def RunAdhocPlaybook(playbookname, taskname, addafter, incid): try: pbid = GetPlaybookId(playbookname) if pbid == "-1": raise DemistoException(f"Playbook '{playbookname}' not found") task = { "name": taskname, "loop": {}, "type": "playbook", "neighborInvPBTaskId": addafter, "addAfter": True, "playbookId": pbid, "scriptArguments": {}, "separateContext": True, "pageSize": 50, "version": -1, } # Add the playbook as a task tasks = execute_command("core-api-post", {"uri": f"/inv-playbook/task/add/{incid}", "body": task})[ "response" ]["tasks"] # Find the new task ID in the updated playbook and execute the task for key, task in tasks.items(): if "name" in task["task"] and task["task"]["name"] == taskname: execute_command( "core-api-post", { "uri": "/inv-playbook/task/execute", "body": { "taskinfo": {"invId": incid, "inTaskID": key, "version": -1, "args": {}, "loopArgs": {}}, "playbooksdebuginfo": {}, "pageSize": 50, }, }, ) except Exception as ex: demisto.error(traceback.format_exc()) return_error(f"RunAdhocPlaybook: Exception failed to execute. Error: {ex!s}") def RunAutomations(buf): cmds = [] tasks = [] status = [] line = buf.readline() while line != "": words = line.split(",", 1) command = words[0].strip() params = json.loads(words[1]) name = words[1].replace(",", " ").replace("{", "(").replace("}", ")").replace('"', "") cmds.append(command) tasks.append(f"UT_{name}") demisto.executeCommand(command, params) status.append(True) line = buf.readline() return cmds, tasks, status def RunSubplaybooks(buf, addAfter, incId): playbooks = [] line = buf.readline() while line != "": words = line.split(",", 1) playbooks.append(words[0].strip()) line = buf.readline() cmds, tasks, status = RunPlaybooks(playbooks, addAfter, incId) return cmds, tasks, status def RunPlaybooks(playbooks, addAfter, incId): cmds = [] tasks = [] status = [] for p in playbooks: p = p.strip() if p == "": continue taskName = f"UT_{p}_{uuid.uuid4().hex}" cmds.append(p) tasks.append(taskName) RunAdhocPlaybook(p, taskName, addAfter, incId) status.append(True) return cmds, tasks, status def main(): try: cmds = [] tasks = [] status = [] incId = demisto.incident()["id"] args = demisto.args() playbooks = args.get("playbook", "").split(",") addAfter = args.get("addAfter", "") testType = args.get("testType", "") listName = args.get("listName", "") if listName != "": listlines = execute_command("getList", {"listName": listName}) buf = io.StringIO(listlines) else: buf = None demisto.debug(f"{listName=} -> {buf=}") # Add the tasks to the playbook and execute it if testType == "Automation": cmds, tasks, status = RunAutomations(buf) elif testType == "Subplaybook": cmds, tasks, status = RunSubplaybooks(buf, addAfter, incId) elif testType == "Playbook": cmds, tasks, status = RunPlaybooks(playbooks, addAfter, incId) elif testType == "Multiselect": # demisto.incident()['id'] does not work from field change trigger script incId = demisto.executeCommand("getIncidents", {})[0]["Metadata"]["investigationId"] cmds, tasks, status = RunPlaybooks(playbooks, addAfter, incId) else: return # Add a task to display the results. Does this inside demisto locks to ensure # serial updates to the unit test status grid field when test butten selection add tasks quickly if len(cmds) > 0: newargs = { "playbookname": "UnitTestResults", "addafter": addAfter, "incid": incId, "cmds": cmds, "tasks": tasks, "gridfield": "contenttestingunittestresults", "status": status, } RunUTResults(newargs) except Exception as ex: demisto.error(traceback.format_exc()) status.append(False) newargs = { "playbookname": "UnitTestResults", "taskname": "main: exception occured", "addafter": addAfter, "incid": incId, "cmds": cmds, "tasks": tasks, "gridfield": "contenttestingunittestresults", "status": status, } RunUTResults(newargs) return_error(f"UnitTest: Exception failed to execute. Error: {ex!s}") if __name__ in ("__main__", "__builtin__", "builtins"): main()
README
Provides for automated testing of automations, playbooks, and sub-playbooks.
Script Data
| Name | Description |
|---|---|
| Script Type | python3 |
Inputs
| Argument Name | Description |
|---|---|
| playbook | Playbook to Execute. |
| addAfter | Playbook Task to Add This Task After. |
| testType | Type of Test to Run. |
| listName | List to Read Subplaybooks or Automations From. |
Outputs
There are no outputs for this script.