{"id":15276,"date":"2022-02-23T03:52:39","date_gmt":"2022-02-23T08:52:39","guid":{"rendered":"https:\/\/qxf2.com\/blog\/?p=15276"},"modified":"2022-02-23T03:52:39","modified_gmt":"2022-02-23T08:52:39","slug":"jira-xray","status":"publish","type":"post","link":"https:\/\/qxf2.com\/blog\/jira-xray\/","title":{"rendered":"XRAY server version Integration with Jira for behave BDD"},"content":{"rendered":"<h4>Why this post<\/h4>\n<p>XRAY is a Test management plugin for Jira. This plugin helps you automate your complete testing process. Also, it has easy integration with BDD which is something we have implemented at our client.<\/p>\n<p>There are server and cloud versions of XRAY. This article talks about simple methods which we implemented to get XRAY Server integration done with behave BDD.<\/p>\n<p>Few terms you will see used in the post:<br \/>\n<strong>Test ExecutionID<\/strong> &#8211; The XRAY ID of type Test Execution. There can be many test executions based on your test cycles.<br \/>\n<strong>Test PlanID <\/strong>&#8211; This will map to the test plan in Jira. Test execution are mapped to test plans.<br \/>\n<strong>TestcaseID<\/strong> &#8211; These are actual test cases in Jira. TestcaseID is mapped to Test ExecutionID and is part of many test executions. <\/p>\n<h4>Current flow <\/h4>\n<p>The client generates a TestPlanID for the new cycle, and based on the environments, a TestExecutionID is created under this TestplanID. When the tests are run with the ExecutionID(s) the TestcaseID is automatically aligned with them.<\/p>\n<p>One thing to remember, XRAY always aligns tests to execution. So if you don&#8217;t want to create TestExecutionID initially and want teams to create their own, teams feel it&#8217;s an overhead to go to Jira and create TestExectionID and then use that while running test. Phew!!!<br \/>\nXRAY, on the other hand, allows you to pass TestPlanID while running the test, and it will generate the TestExecutionID and align your tests to it. That&#8217;s cool right?<\/p>\n<p>In the example, I am passing TestPlanID. And call methods to create TestExectionID and link them, finally upload results to Jira.<\/p>\n<p>When TestPlanID is passed, first check if the planID is valid using XRAY API. If it&#8217;s valid then call API to create ExecutionID and link them.<\/p>\n<h4>Verify if the TestPlanID and TestExecutionID are valid<\/h4>\n<pre lang=\"Python\">\r\n \r\ndef find_if_valid_plan_id(test_plan_id):\r\n    \"\"\"    \r\n    Function calls the xray api for checking test plan id.\r\n    Returns the response status code to callee function.\r\n    :param test_plan_id: xray test plan id\r\n    :returns statuscode_plan : api response status code\r\n    \"\"\"\r\n    \r\n    print \"running find_if_valid_planid with plan id with plan id:\", test_plan_id\r\n    try:\r\n        url = \"{}rest\/raven\/1.0\/api\/testplan\/{}\/test?limit=10\".format(JIRA_BASE_URL, test_plan_id)\r\n        headers = header()\r\n        response = requests.request(\"GET\", url, headers=headers, data=None)\r\n        statuscode_plan = response.status_code\r\n        print \"status code returned for plan id and url used are\", statuscode_plan, url\r\n        return statuscode_plan\r\n    except Exception as e:\r\n        print \"Unable to execute find_if_valid_plan_id\", e\r\n        raise\r\n\r\ndef find_if_valid_exec_id(xray_execution_id):\r\n    \"\"\"\r\n    Function calls the xray api for checking test execution id.\r\n    Returns the response status code to callee function.\r\n    :param xray_execution_id : xray test execution id\r\n    :returns statuscode_exec : api response status code\r\n    \"\"\"\r\n    \r\n    print \"running find_if_valid_exec_id with execution id : \", xray_execution_id\r\n    try:\r\n        url = \"{}rest\/raven\/1.0\/api\/testexec\/{}\/test?limit=10\".format(JIRA_BASE_URL, xray_execution_id)\r\n        headers = header()\r\n        response = requests.request(\"GET\", url, headers=headers, data=None)\r\n        statuscode_exec = response.status_code\r\n        print \"status code returned for exececution id and url used are\", statuscode_exec, url\r\n        return statuscode_exec\r\n    except Exception as e:\r\n        print \"Unable to execute find_if_valid_exec_id\", e\r\n        raise\r\n\r\n<\/pre>\n<h4>\nCreate TestExecutionID<\/h4>\n<p>When TestplanID is passed, we need to call the API to create a new TestExecutionID and then call another API to link them.<\/p>\n<pre lang=\"Python\">\r\ndef create_xray_test_execution_id_and_link_with_test_plan(test_plan_id):\r\n    \"\"\"\r\n    This function using xray api call creates new test execution id with the details \r\n    mentioned in the Payload parameter.\r\n    Newly created execution id is then passed to another xray api call which links it with the passed plan id.\r\n    The execution id is returned by this function.\r\n    :param test_pan_id : xray test plan id\r\n    :returns xray_test_execution_id : newly created execution id\r\n    :returns execution_creation_resp_status_code : response status for execution id created\r\n    \"\"\"\r\n    \r\n    print \"creating new execution id\"\r\n    try:\r\n        xray_test_execution_id =\"\"\r\n        url = \"{}rest\/api\/2\/issue\/\".format(JIRA_BASE_URL)\r\n        payload = {\r\n            \"fields\": {\r\n                \"project\":{\r\n                    \"id\": \"xxxx\" #pass the actual id\r\n                },\r\n                \"summary\": \"Creating a Test Execution issue\",\r\n                \"description\": \"Creating of a test execution issue using IDs for projects and issue types using the REST API\",\r\n                \"issuetype\": {\r\n                    \"id\": \"xxx\" #pass the actual id\r\n                }\r\n            }\r\n        }\r\n        payloadJson = json.dumps(payload)\r\n        headers = header()\r\n        response_execution_creation = requests.request(\"POST\", url, headers=headers, data=payloadJson)\r\n        execution_creation_resp_status_code = response_execution_creation.status_code\r\n        if execution_creation_resp_status_code != 404:\r\n            result = json.loads(response_execution_creation.text)\r\n            if execution_creation_resp_status_code != 400:\r\n                xray_test_execution_id = result['key']\r\n                print(result['key'])\r\n                #Link Test Plan to Test Execution ID\r\n                print \"Linking newly created execution id to plan id\"\r\n                link_execution_id(xray_test_execution_id, test_plan_id) \r\n        return xray_test_execution_id\r\n    except Exception as e:\r\n        print \"Unable to execute create_xray_test_execution_id_and_link_with_test_plan\", e\r\n        raise\r\n<\/pre>\n<h4>\nLink the newly created TestExecutionID to the passed TestPlanID<\/h4>\n<pre lang=\"Python\">\r\ndef link_execution_id(xray_test_execution_id, test_plan_id):\r\n    \"\"\"\r\n    This function will link the newly created execution id with the plan id\r\n    :param xray_test_execution_id : newly created execution id\r\n    :param test_plan_id : test plan id\r\n    :returns response_plan_linking_status : returns the status code of linking execution with plan\r\n    \"\"\"\r\n    try:\r\n        print \"Linking newly created execution id to plan id\"\r\n        url = \"{}rest\/raven\/1.0\/api\/testplan\/{}\/testexecution\".format(JIRA_BASE_URL, test_plan_id)\r\n        print(url)\r\n        payload_plan = {\r\n            \"add\": [\r\n                xray_test_execution_id\r\n            ]\r\n        }\r\n        payloadJson_plan = json.dumps(payload_plan)\r\n        response_plan_linking = requests.request(\"POST\", url, headers=headers, data=payloadJson_plan)\r\n        response_plan_linking_status = response_plan_linking.status_code\r\n        print \"This is response for test plan link to newly created test execution id\", response_plan_linking\r\n        if response_plan_linking.status_code != 200:\r\n            print \"plan id to execution id linking has failed\"\r\n            xray_test_execution_id = None\r\n        return response_plan_linking_status\r\n    except Exception as e:\r\n        print \"Unable to execute link_execution_id\", e\r\n        raise\r\n<\/pre>\n<h4>\nNow, you can upload the results to XRAY<\/h4>\n<pre lang=\"Python\">\r\ndef update_xray_results(xray_execution_id, feature_files, config_json_files):\r\n    \"\"\"    \r\n    This is the main function for xray result update which calls various functions in sequence\r\n    and updates xray results to jira.\r\n    :param xray_execution_id : xray test execution id\r\n    :returns : None\r\n    \"\"\"\r\n    try:\r\n        print \"inside update_xray_results\"\r\n        final_json_files = \"c:\/behave_json_files\"\r\n        update_xray_execution_results_using_behave_api(final_json_files)\r\n    except Exception as e:\r\n        print \"Unable to execute update_xray_results\", e\r\n        raise\r\n\r\ndef update_xray_execution_results_using_behave_api(final_json_files):\r\n    \"\"\"\r\n    This function makes the XRAY api call to upload the final results from the json files.\r\n    :param  final_json_files : folder where final json files are stored after cleaning and updating\r\n    :returns : None\r\n    \"\"\"\r\n    try:\r\n        url = \"{}rest\/raven\/1.0\/import\/execution\/behave\".format(JIRA_BASE_URL)\r\n        headers = header()\r\n        response_status = None\r\n        for file in final_json_files:\r\n            if file.endswith(\".json\"):\r\n                print \"Found json for api call. JSON file name is \", file\r\n                with open(XRAY_JSON_DIR_FINAL + file, 'r+') as json_file:\r\n                    json_data = json.load(json_file)\r\n                    data = json.dumps(json_data)\r\n                    response = requests.request(\"POST\", url, headers=headers, data=data)\r\n                    response_status = response.status_code\r\n                    if response.status_code == 500:\r\n                        print \"Something has gone wrong, check the json file for more details\", file\r\n                    else:\r\n                        continue\r\n        return response_status\r\n    except Exception as e:\r\n        print \"behave api call failing\", e\r\n        raise\r\n\r\n<\/pre>\n<h3>All the code put together<\/h3>\n<pre lang=\"Python\">\r\nimport requests\r\nimport json\r\n\r\nJIRA_AUTH = ('authid authpassword')\r\nJIRA_BASE_URL = \"http:\/\/abc\/\" \r\nXRAY_JSON_DIR_FINAL = \"<mention the path where final json files are created>\"\r\n\r\ndef header():\r\n    \"\"\"\r\n    This function holds all the headers required for xray behave api.\r\n    The Jira Authorization details are passed here.\r\n    This function is called in methods which make jira xray api calls.\r\n    \r\n    :returns headers : headers required for xray api call\r\n    \"\"\"\r\n\r\n    headers = {'Accept' : 'application\/json', 'Content-Type': 'application\/json', 'Authorization': JIRA_AUTH}\r\n    return headers\r\n\r\ndef check_and_update_xray_results(xray_execution_id, test_plan_id, feature_files, config_json_files):\r\n    \"\"\"    \r\n    This function checks if from CLI test plan id or execution id is passed.\r\n    \r\n    :param xray_execution_id : xray test execution id\r\n    :param test_plan_id : xray test plan id\r\n    :returns : None\r\n    \"\"\"\r\n    try:\r\n        if test_plan_id is not None:\r\n            print \"Test Plan ID is passed\"\r\n            check_update_plan_id(test_plan_id, feature_files, config_json_files)\r\n        if xray_execution_id is not None:\r\n            check_update_execution_id(xray_execution_id, feature_files, config_json_files)\r\n    except Exception as e:\r\n        print \"Unable to execute check_and_update_xray_results\", e\r\n        raise\r\n\r\ndef check_update_plan_id(test_plan_id, feature_files, config_json_files):\r\n    \"\"\"    \r\n    This functions calls method to verify passed plan id is valid or not.\r\n    If passed plan id is valid then function to create and link test execution id is called.\r\n    With newly created execution id the xray test results upload is proceeded.\r\n    :param test_plan_id : xray test plan id\r\n    :returns : None\r\n    \"\"\"\r\n    try:\r\n        statuscode_plan = find_if_valid_plan_id(test_plan_id)\r\n        xray_test_execution_id = None\r\n        if statuscode_plan == 200:\r\n            print \"going to create execution id and link it to plan id\"\r\n            execution_creation_resp_status_code, xray_test_execution_id = create_xray_test_execution_id_and_link_with_test_plan(test_plan_id)\r\n            print \"new execution id is \", xray_test_execution_id\r\n            if xray_test_execution_id is not None:\r\n                xray_execution_id = xray_test_execution_id\r\n                update_xray_results(xray_execution_id, feature_files, config_json_files)\r\n        else:\r\n            print \"status code returned for plan id being valid\", statuscode_plan\r\n    except Exception as e:\r\n        print \"Unable to execute check_update_plan_id\", e\r\n        raise\r\n\r\ndef check_update_execution_id(xray_execution_id, feature_files, config_json_files):\r\n    \"\"\"    \r\n    This function will be called when execution id is passed directly from CLI or commander.\r\n    First function will check if the passed id is valid. \r\n    If excution id is valid then xray test result upload function is invoked.\r\n    :param xray_execution_id : xray test execution id\r\n    :returns : None\r\n    \"\"\"\r\n    try:\r\n        statuscode_exec = find_if_valid_exec_id(xray_execution_id)\r\n        if statuscode_exec == 200:\r\n            print \"Execution ID is passed directly\"\r\n            update_xray_results(xray_execution_id, feature_files, config_json_files)\r\n        else:\r\n            print \"status code returned for execution id being valid\", statuscode_exec\r\n    except Exception as e:\r\n        print \"Unable to execute check_update_execution_id\", e\r\n        raise\r\n\r\ndef find_if_valid_plan_id(test_plan_id):\r\n    \"\"\"    \r\n    Function calls the xray api for checking test plan id.\r\n    Returns the response status code to callee function.\r\n    :param test_plan_id: xray test plan id\r\n    :returns statuscode_plan : api response status code\r\n    \"\"\"\r\n    \r\n    print \"running find_if_valid_planid with plan id with plan id:\", test_plan_id\r\n    try:\r\n        url = \"{}rest\/raven\/1.0\/api\/testplan\/{}\/test?limit=10\".format(JIRA_BASE_URL, test_plan_id)\r\n        headers = header()\r\n        response = requests.request(\"GET\", url, headers=headers, data=None)\r\n        statuscode_plan = response.status_code\r\n        print \"status code returned for plan id and url used are\", statuscode_plan, url\r\n        return statuscode_plan\r\n    except Exception as e:\r\n        print \"Unable to execute find_if_valid_plan_id\", e\r\n        raise\r\n\r\ndef find_if_valid_exec_id(xray_execution_id):\r\n    \"\"\"\r\n    Function calls the xray api for checking test execution id.\r\n    Returns the response status code to callee function.\r\n    :param xray_execution_id : xray test execution id\r\n    :returns statuscode_exec : api response status code\r\n    \"\"\"\r\n    \r\n    print \"running find_if_valid_exec_id with execution id : \", xray_execution_id\r\n    try:\r\n        url = \"{}rest\/raven\/1.0\/api\/testexec\/{}\/test?limit=10\".format(JIRA_BASE_URL, xray_execution_id)\r\n        headers = header()\r\n        response = requests.request(\"GET\", url, headers=headers, data=None)\r\n        statuscode_exec = response.status_code\r\n        print \"status code returned for exececution id and url used are\", statuscode_exec, url\r\n        return statuscode_exec\r\n    except Exception as e:\r\n        print \"Unable to execute find_if_valid_exec_id\", e\r\n        raise\r\n\r\ndef create_xray_test_execution_id_and_link_with_test_plan(test_plan_id):\r\n    \"\"\"\r\n    This function using xray api call creates new test execution id with the details \r\n    mentioned in the Payload parameter.\r\n    Newly created execution id is then passed to another xray api call which links it with the passed plan id.\r\n    The execution id is returned by this function.\r\n    :param test_pan_id : xray test plan id\r\n    :returns xray_test_execution_id : newly created execution id\r\n    :returns execution_creation_resp_status_code : response status for execution id created\r\n    \"\"\"\r\n    \r\n    print \"creating new execution id\"\r\n    try:\r\n        xray_test_execution_id =\"\"\r\n        url = \"{}rest\/api\/2\/issue\/\".format(JIRA_BASE_URL)\r\n        payload = {\r\n            \"fields\": {\r\n                \"project\":{\r\n                    \"id\": \"xxxx\" #pass the actual id\r\n                },\r\n                \"summary\": \"Creating a Test Execution issue\",\r\n                \"description\": \"Creating of a test execution issue using IDs for projects and issue types using the REST API\",\r\n                \"issuetype\": {\r\n                    \"id\": \"xxx\" #pass the actual id\r\n                }\r\n            }\r\n        }\r\n        payloadJson = json.dumps(payload)\r\n        headers = header()\r\n        response_execution_creation = requests.request(\"POST\", url, headers=headers, data=payloadJson)\r\n        execution_creation_resp_status_code = response_execution_creation.status_code\r\n        if execution_creation_resp_status_code != 404:\r\n            result = json.loads(response_execution_creation.text)\r\n            if execution_creation_resp_status_code != 400:\r\n                xray_test_execution_id = result['key']\r\n                print(result['key'])\r\n                #Link Test Plan to Test Execution ID\r\n                print \"Linking newly created execution id to plan id\"\r\n                link_execution_id(xray_test_execution_id, test_plan_id) \r\n        return xray_test_execution_id\r\n    except Exception as e:\r\n        print \"Unable to execute create_xray_test_execution_id_and_link_with_test_plan\", e\r\n        raise\r\n\r\ndef link_execution_id(xray_test_execution_id, test_plan_id):\r\n    \"\"\"\r\n    This function will link the newly created execution id with the plan id\r\n    :param xray_test_execution_id : newly created execution id\r\n    :param test_plan_id : test plan id\r\n    :returns response_plan_linking_status : returns the status code of linking execution with plan\r\n    \"\"\"\r\n    try:\r\n        print \"Linking newly created execution id to plan id\"\r\n        url = \"{}rest\/raven\/1.0\/api\/testplan\/{}\/testexecution\".format(JIRA_BASE_URL, test_plan_id)\r\n        print(url)\r\n        payload_plan = {\r\n            \"add\": [\r\n                xray_test_execution_id\r\n            ]\r\n        }\r\n        payloadJson_plan = json.dumps(payload_plan)\r\n        response_plan_linking = requests.request(\"POST\", url, headers=headers, data=payloadJson_plan)\r\n        response_plan_linking_status = response_plan_linking.status_code\r\n        print \"This is response for test plan link to newly created test execution id\", response_plan_linking\r\n        if response_plan_linking.status_code != 200:\r\n            print \"plan id to execution id linking has failed\"\r\n            xray_test_execution_id = None\r\n        return response_plan_linking_status\r\n    except Exception as e:\r\n        print \"Unable to execute link_execution_id\", e\r\n        raise\r\n\r\ndef upload_xray_test_report(xray_execution_id, test_plan_id, files, config_json_files):\r\n    \"\"\"\r\n    The function checks if either of the xray ids(execution id or plan id) are passed.\r\n    If none of the ids are found then further execution is stopped.\r\n    :param xray_execution_id : xray test execution id\r\n    :test_plan_id : xray test plan id\r\n    :returns : None\r\n    \"\"\"\r\n    print \"Test Execution ID is \", xray_execution_id, \"Test Plan ID is \", test_plan_id\r\n    try:\r\n        if xray_execution_id and test_plan_id:\r\n            print \"Pass only one of the IDs, cannot upload results\"\r\n        elif xray_execution_id or test_plan_id:\r\n            print \"Found XRAY id\"\r\n            check_and_update_xray_results(xray_execution_id, test_plan_id, feature_files, config_json_files)\r\n        else:\r\n            print \"Test execution ID or Test plan ID not passed, not uploading results to XRAY\"\r\n    except Exception as e:\r\n        print \"Unable to update xray with test results\", e\r\n        raise\r\n\r\ndef update_xray_results(xray_execution_id, feature_files, config_json_files):\r\n    \"\"\"    \r\n    This is the main function for xray result update which calls various functions in sequence\r\n    and updates xray results to jira.\r\n    :param xray_execution_id : xray test execution id\r\n    :returns : None\r\n    \"\"\"\r\n    try:\r\n        print \"inside update_xray_results\"\r\n        final_json_files = \"c:\/behave_json_files\"\r\n        update_xray_execution_results_using_behave_api(final_json_files)\r\n    except Exception as e:\r\n        print \"Unable to execute update_xray_results\", e\r\n        raise\r\n\r\ndef update_xray_execution_results_using_behave_api(final_json_files):\r\n    \"\"\"\r\n    This function makes the XRAY api call to upload the final results from the json files.\r\n    :param  final_json_files : folder where final json files are stored after cleaning and updating\r\n    :returns : None\r\n    \"\"\"\r\n    try:\r\n        url = \"{}rest\/raven\/1.0\/import\/execution\/behave\".format(JIRA_BASE_URL)\r\n        headers = header()\r\n        response_status = None\r\n        for file in final_json_files:\r\n            if file.endswith(\".json\"):\r\n                print \"Found json for api call. JSON file name is \", file\r\n                with open(XRAY_JSON_DIR_FINAL + file, 'r+') as json_file:\r\n                    json_data = json.load(json_file)\r\n                    data = json.dumps(json_data)\r\n                    response = requests.request(\"POST\", url, headers=headers, data=data)\r\n                    response_status = response.status_code\r\n                    if response.status_code == 500:\r\n                        print \"Something has gone wrong, check the json file for more details\", file\r\n                    else:\r\n                        continue\r\n        return response_status\r\n    except Exception as e:\r\n        print \"behave api call failing\", e\r\n        raise\r\n\r\nif __name__ == '__main__':\r\n\r\n    test_plan_id = \"XRAY-123\"\r\n    feature_files = \"some_feature.feature\"\r\n    config_json_files = \"file_name.json\"\r\n    xray_execution_id = create_xray_test_execution_id_and_link_with_test_plan(test_plan_id)\r\n    print xray_execution_id\r\n    upload_xray_test_report(xray_execution_id, test_plan_id, feature_files, config_json_files)\r\n    update_xray_results(xray_execution_id, feature_files, config_json_files)\r\n<\/pre>\n<p>I hope this post gets you started with the XRAY integration quickly.<br \/>\nNote- code example is compatible with python2 only.<\/p>\n<p>Reference &#8211; https:\/\/docs.getxray.app\/display\/XRAY\/About+Xray<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Why this post XRAY is a Test management plugin for Jira. This plugin helps you automate your complete testing process. Also, it has easy integration with BDD which is something we have implemented at our client. There are server and cloud versions of XRAY. This article talks about simple methods which we implemented to get XRAY Server integration done with [&hellip;]<\/p>\n","protected":false},"author":26,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[102,18,298],"tags":[],"class_list":["post-15276","post","type-post","status-publish","format-standard","hentry","category-behave","category-python","category-xray"],"_links":{"self":[{"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/posts\/15276","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/users\/26"}],"replies":[{"embeddable":true,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/comments?post=15276"}],"version-history":[{"count":40,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/posts\/15276\/revisions"}],"predecessor-version":[{"id":16544,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/posts\/15276\/revisions\/16544"}],"wp:attachment":[{"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/media?parent=15276"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/categories?post=15276"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/tags?post=15276"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}