Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
1 lines (1 sloc) 19.3 KB
{"events":[{"eventName":"SlackEvent","_id":"event-1"},{"eventName":"TriggerJenkins","_id":"event-2"},{"eventName":"UploadJavaCucumberResults","_id":"event-3"},{"eventName":"UpdateQTestWithFormattedResultsEvent","_id":"event-4"},{"eventName":"JiraStoryUpdated","_id":"event-5"},{"eventName":"UploadPythonJUnitResults","_id":"event-6"},{"eventName":"UploadPostmanJsonResults","_id":"event-7"},{"eventName":"LinkScenarioRequirements","_id":"event-8"}],"actions":[{"name":"SlackAction","description":"Sends whatever is sent to in the body to slack in the channel provided constant \"SlackWebHook\". The webhook must be set up within the slack integrations in the slack application.","pFunction":"var str = body;\n\nvar request = require('request');\nvar slack_webhook = constants.SlackWebHook;\n\nconsole.log('About to request slack webhook: ', slack_webhook);\n\nrequest({uri: slack_webhook,\n method: 'POST',\n json: {\"text\": JSON.stringify(str)}\n }, function(error, response, body) { }\n);","_id":"action-1"},{"name":"TriggerJenkinsJob","description":"Triggers a remote Jenkins job. The job must be configured to allow remote triggers. This assumes a crumb is required as part of the application security settings. All Jenkins constants must be filled out and setup within Jenkins for this to work properly.","pFunction":"var url = \"http://\" + constants.JenkinsUserName + \":\" + constants.JenkinsAPIToken + \"@\" + \n constants.JenkinsURL + '/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,\":\",//crumb)';\n\nrequest.get({url:url, insecure: true}, function(err, response, body) {\n if(!err) {\n var crumb = body.split(\":\")[1];\n\n var joburl = \"http://\" + constants.JenkinsUserName + \":\" + constants.JenkinsAPIToken + \"@\" + \n constants.JenkinsURL + \"/job/\" + constants.JenkinsJobName + \"/build?token=\" + constants.JenkinsJobToken\n var opts = {\n url: joburl,\n insecure: true,\n contentType: \"application/x-www-form-urlencoded; charset=UTF-8\",\n headers: {\n \"Jenkins-Crumb\": crumb\n }\n }\n\n request.post(opts, function(err, res, bd) {\n emitEvent('SlackEvent', { JenkinsCallSuccess: \"Jenkins Build just kicked off for project \" + constants.JenkinsJobName }); \n })\n }\n})","_id":"action-2"},{"name":"FormatJavaCucumber","description":"Accepts raw, standard surefire reports from Java's Cucumber framework. Attachments may be included in the 'embeddings' field for each step. ","pFunction":"// Payload to be passed in: json style cucumber for java test results\n\n/////// Pulse version\nvar payload = body;\nvar testResults = payload.result; \nvar projectId = payload.projectId;\nvar cycleId = payload[\"test-cycle\"];\n\n//////// Commandline version\n//var fs = require('fs');\n//var testResults = JSON.parse(fs.readFileSync('path/to/your/results/cucumber-report.json', 'utf8'));\n//var projectId = $YOUR_PROJECT_ID; // Pulse Automation Project\n//var cycleId = $YOUR_TEST_CYCLE_ID; // Pulse Automation Project\n/// TODO: Remove above\n\nvar testLogs = [];\n\ntestResults.forEach(function(feature) {\n var featureName = feature.name;\n feature.elements.forEach(function(testCase) {\n \n if(!testCase.name)\n testCase.name = \"Unnamed\";\n \n TCStatus = \"passed\"; // NOTE: that the automation settings must be mapped with passed vs the default PASS\n \n var reportingLog = {\n exe_start_date: new Date(), // TODO These could be passed in\n exe_end_date: new Date(),\n module_names: [\n 'Features'\n ],\n name: testCase.name,\n automation_content: feature.uri + \"#\" + testCase.name\n };\n\n var testStepLogs = [];\n order = 0;\n stepNames = [];\n attachments = [];\n \n testCase.steps.forEach(function(step) {\n stepNames.push(step.name);\n\n var status = step.result.status;\n var actual = step.name;\n\n if(TCStatus == \"passed\" && status == \"skipped\") {\n TCStatus = \"skipped\";\n }\n if(status == \"failed\") {\n TCStatus = \"failed\";\n actual = step.result.error_message;\n }\n if(status == \"undefined\") {\n TCStatus = \"failed\";\n status = \"failed\";\n }\n\n // Are there an attachment for this step?\n if(\"embeddings\" in step) {\n console.log(\"Has attachment\");\n \n attCount = 0;\n step.embeddings.forEach(function(att) {\n attCount++;\n var attachment = {\n name: step.name + \" Attachment \" + attCount,\n \"content_type\": att.mime_type,\n data: att.data\n };\n console.log(\"Attachment: \" + attachment.name)\n \n attachments.push(attachment);\n });\n }\n \n var expected = step.keyword + \" \" + step.name;\n \n if(\"location\" in step.match) {\n expected = step.match.location;\n }\n\n var stepLog = {\n order: order,\n description: step.name,\n expected_result: step.keyword,\n actual_result: actual,\n status: status\n };\n \n testStepLogs.push(stepLog);\n order++;\n });\n\n reportingLog.attachments = attachments;\n reportingLog.description = stepNames.join(\"<br/>\");\n reportingLog.status = TCStatus;\n reportingLog.test_step_logs = testStepLogs;\n reportingLog.featureName = featureName;\n testLogs.push(reportingLog);\n });\n});\n\nvar formattedResults = {\n \"projectId\" : projectId,\n \"test-cycle\" : cycleId,\n \"logs\" : testLogs\n};\n\n// Pulse Version\n// Emit next fxn to upload results/parse\nemitEvent('UpdateQTestWithFormattedResultsEvent', formattedResults );\n\n/// Command line version\n// Write new file\n//var payload = fs.writeFile('formattedResults.json', JSON.stringify(formattedResults, null, \" \" ), 'utf8', function() {\n// console.log(\"File written: formattedResults.json\");\n//});\n\n\n\n","_id":"action-3"},{"name":"UpdateQTestWithFormattedResults","description":"Uses the auto-test-logs bulk uploader API call to qTest Manager to upload formatted test results.","pFunction":"// Specific to pulse actions\nvar payload = body;\n\nvar testLogs = payload.logs;\nvar cycleId = payload[\"test-cycle\"];\nvar projectId = payload.projectId;\n\nvar standardHeaders = {\n 'Content-Type': 'application/json',\n 'Authorization': constants.qTestAPIToken\n} \n\nvar opts = {\n url: \"https://\" + constants.ManagerURL + \"/api/v3/projects/\" + projectId + \"/auto-test-logs?type=automation\",\n json: true,\n headers: standardHeaders,\n body: {\n test_cycle: cycleId,\n test_logs: testLogs\n }\n};\n\nrequest.post(opts, function(err, response, resbody) {\n if(err) {\n emitEvent('SlackEvent', { createLogsAndTCsErr: err });\n }\n else {\n emitEvent('SlackEvent', { AutomationLogUploaded: resbody });\n \n if(response.body.type == \"AUTOMATION_TEST_LOG\") {\n // Try to link requirements\n emitEvent('LinkScenarioRequirements', payload);\n }\n else {\n emitEvent('SlackEvent', { Error: \"Wrong type\"});\n }\n }\n});\n\n\n\n","_id":"action-4"},{"name":"scenarioColors","description":"Updates qTest Scenario colors based on the pass/fail of the test case step","pFunction":"var payload = body;\nvar testLogs = payload.logs;\n\nfor (var res of testLogs) {\n for (var step of res[\"test_step_logs\"]) {\n var stepName = step.description;\n var stepStatus = step.status;\n \n // Undefined means no step definition existed and it should fail\n if(stepStatus == \"undefined\") {\n stepStatus = \"failed\";\n }\n \n // one of PASSED (green), FAILED (red), or SKIPPED (yellow)\n var stepStatus = _.upperCase(stepStatus);\n \n // Call the pulse API to update step results\n Steps.updateStepResults(constants.SCENARIO_ACCOUNT_ID, constants.SCENARIO_PROJECT_ID, stepName, stepStatus);\n } \n}","_id":"action-5"},{"name":"FormatPythonPyTestJUnit","description":"Formats raw python pytest junit results to a format that the bulk uploader pulse rule can read.","pFunction":"/////// Pulse version\nvar payload = body;\nvar testResults = payload.result; \nvar projectId = payload.projectId;\nvar cycleId = payload[\"test-cycle\"];\n\nxml2js = require('xml2js');\n\n//////// Commandline version\n// var fs = require('fs');\n// \n// var projectId = 12345; \n// var cycleId = 12341234; \n/// TODO: Remove above\n\nvar testLogs = [];\nfunction FormatLogs(tr) {\n \n var testResults = JSON.parse(tr);\n testResults.testsuite.testcase.forEach(function(tc) {\n var tcResult = tc[\"$\"];\n var tcName = \"\";\n\n // Format the name\n var note = \"\";\n if(!tcResult.name) \n tcName = \"Unnamed\";\n else \n tcName = tcResult.name.substring(0, tcResult.name.indexOf('['));\n note = tcResult.name;\n\n TCStatus = \"PASS\";\n \n if(tc.failure) {\n TCStatus = \"FAIL\";\n if(note)\n note = \"\\n\" + JSON.stringify(tc.failure);\n else\n note = JSON.stringify(tc.failure);\n }\n\n // The automation content is what we're going to use to run this later so it's important to get that format for Python pytest\n //$file :: $classname (after the last .) :: $name (before the [)\n var tcShortClassName = tcResult.classname.substring(tcResult.classname.lastIndexOf('.') + 1)\n var auto = tcResult.file + \"::\" + tcShortClassName + \"::\" + tcName;\n\n var reportingLog = {\n exe_start_date: new Date(), // TODO this could use the time to complete to be more precise\n exe_end_date: new Date(),\n module_names: [\n 'JUnitTests'\n ],\n name: tcName,\n automation_content: auto,\n note: note\n };\n\n // There are no steps here, so we'll add one step entry\n var testStepLogs = [{\n order: 0,\n description: tcName,\n expected_result: tcName,\n status: TCStatus\n }];\n\n reportingLog.description = \"Test case imported from Python Test\"\n reportingLog.status = TCStatus;\n reportingLog.test_step_logs = testStepLogs;\n testLogs.push(reportingLog);\n });\n\n var formattedResults = {\n \"projectId\" : projectId,\n \"test-cycle\" : cycleId,\n \"logs\" : testLogs\n };\n\n return formattedResults;\n}\n\n // Pulse Version\nvar parser = new xml2js.Parser();\nparser.parseString(testResults, function (err, result) {\n var formattedResults = FormatLogs(JSON.stringify(result));\n emitEvent('UpdateQTestWithFormattedResultsEvent', formattedResults );\n});\n\n/// Command line version\n// fs.readFile('results.xml', function(err, data) {\n// parser.parseString(data, function (err, result) {\n// var formattedResults = FormatLogs(JSON.stringify(result));\n// Write new file\n// var payload = fs.writeFile('formattedResults.json', JSON.stringify(formattedResults, null, \" \" ), 'utf8', function() {\n// console.log(\"File written: formattedResults.json\");\n// });\n// });\n// });\n\n\n\n","_id":"action-6"},{"name":"FormatPostmanJson","description":"Formats raw postman json results to a format that the Pulse Rule to upload results to qTest Manager can read.","pFunction":"// Payload to be passed in: json style cucumber for java test results\n\n/////// Pulse version\nvar payload = body;\nvar testResults = payload.result; \nvar projectId = payload.projectId;\nvar cycleId = payload[\"test-cycle\"];\n\nvar collectionName = testResults.collection.info.name;\nvar testLogs = [];\n\ntestResults.run.executions.forEach(function(testCase) {\n\n var featureName = testCase.item.name;\n \n TCStatus = \"passed\";\n var reportingLog = {\n exe_start_date: new Date(), // TODO These could be passed in\n exe_end_date: new Date(),\n module_names: [\n 'Postman'\n ],\n name: testCase.item.name,\n automation_content: collectionName + \"#\" + testCase.item.name // TODO See if ID is static or when that changes\n };\n\n var testStepLogs = [];\n order = 0;\n stepNames = [];\n\n if(!(\"assertions\" in testCase)) {\n return;\n }\n \n testCase.assertions.forEach(function(step) {\n stepNames.push(step.assertion);\n stepErrorVal = \"passed\";\n \n var actual = step.assertion;\n \n if(\"error\" in step) {\n stepErrorVal = \"failed\";\n TCStatus = \"failed\";\n actual = step.error.message;\n }\n\n var stepLog = {\n order: order,\n description: step.assertion,\n expected_result: step.assertion,\n status: stepErrorVal,\n actual_result: actual\n };\n \n testStepLogs.push(stepLog);\n order++;\n });\n\n reportingLog.description = \"Created by Pulse\"; // testCase.request;\n reportingLog.status = TCStatus;\n reportingLog.test_step_logs = testStepLogs;\n reportingLog.featureName = featureName;\n testLogs.push(reportingLog);\n \n});\n\nvar formattedResults = {\n \"projectId\" : projectId,\n \"test-cycle\" : cycleId,\n \"logs\" : testLogs\n};\n\n\n// Pulse Version\nemitEvent('UpdateQTestWithFormattedResultsEvent', formattedResults );\n\n\n\n","_id":"action-7"},{"name":"LinkScenarioRequirements","description":"Attempts to Link Requirements to Test Cases in qTest Manager if you are using qTest Scenario.","pFunction":"// Specific to pulse actions\nvar payload = body;\n\nvar testLogs = payload.logs;\nvar projectId = payload.projectId;\n\nvar standardHeaders = {\n 'Content-Type': 'application/json',\n 'Authorization': constants.qTestAPIToken\n} \n\n// This makes a best effort to link if test cases exist. Not if you just uploaded via the auto-test-logs endpoint, the job is batched and may not be completed yet\n// This is an expensive call with all the posts - we may not want to make it each time there is an update, perhaps we just use this in an Action Trigger.\ntestLogs.forEach(function(testcase) {\n \n var feat = Features.getIssueLinkByFeatureName(constants.SCENARIO_ACCOUNT_ID, constants.SCENARIO_PROJECT_ID, testcase.featureName);\n \n if(feat.length === 0) // No corresponding feature exists in scenario\n return;\n \n feat.forEach(function(matchingFeature) {\n \n var reqopts = getReqBody(matchingFeature.issueKey);\n request.post(reqopts, function(err, response, featureResBody) {\n \n if(err) {\n emitEvent('SlackEvent', { Error: \"Problem getting requirement: \" + err });\n }\n else {\n if(featureResBody.items.length === 0) // No corresponding feature exists in scenario\n return;\n \n var reqid = featureResBody.items[0].id;\n var tcopts = getTCBody(testcase.name);\n \n request.post(tcopts, function(tcerr, tcresponse, testCaseResBody) {\n \n if(tcerr) {\n emitEvent('SlackEvent', { Error: \"Problem getting test case: \" + err });\n }\n else {\n var tcid = testCaseResBody.items[0].id;\n var linkopts = getLinkBody(reqid, tcid);\n \n request.post(linkopts, function(optserr, optsresponse, resbody) {\n if(optserr) {\n emitEvent('SlackEvent', { Error: \"Problem creating test link to requirement: \" + err });\n }\n else {\n // Success, we added a link!\n emitEvent('SlackEvent', { Linking: \"link added for TC: \" + testcase.name + \" to requirement \" + matchingFeature.issueKey });\n }\n });\n }\n });\n }\n }); \n });\n \n});\n\n\nfunction getTCBody(TCName) {\n return {\n url: \"https://\" + constants.ManagerURL + \"/api/v3/projects/\" + projectId + \"/search\",\n json: true,\n headers: standardHeaders,\n body: {\n \"object_type\": \"test-cases\",\n \"fields\": [\n \"*\"\n ],\n \"query\": \"Name = '\" + TCName + \"'\"\n }\n };\n}\n\nfunction getReqBody(key) {\n return {\n url: \"https://\" + constants.ManagerURL + \"/api/v3/projects/\" + projectId + \"/search\",\n json: true,\n headers: standardHeaders,\n body: {\n \"object_type\": \"requirements\",\n \"fields\": [\n \"*\"\n ],\n \"query\": \"Name ~ '\" + key + \"'\"\n }\n };\n}\n\nfunction getLinkBody(reqid, tcid) {\n return {\n url: \"https://\" + constants.ManagerURL + \"/api/v3/projects/\" + projectId + \"/requirements/\" + reqid + \"/link?type=test-cases\",\n json: true,\n headers: standardHeaders,\n body: [\n tcid\n ]\n };\n}\n\n\n\n","_id":"action-8"}],"rules":[{"name":"MessageSlack","webhook":"event-1","conditions":"[]","actions":["action-1"],"isEnabled":true,"_id":"rule-1"},{"name":"TriggerJenkins","webhook":"event-2","conditions":"[]","actions":["action-2"],"isEnabled":true,"_id":"rule-2"},{"name":"UploadJavaCucumberResults","webhook":"event-3","conditions":"[]","actions":["action-3"],"isEnabled":true,"_id":"rule-3"},{"name":"UploadJavaCucumberResultsWithScenario","webhook":"event-4","conditions":"[]","actions":["action-4","action-5"],"isEnabled":true,"_id":"rule-4"},{"name":"ParseAndUploadPythonPyTestResults","webhook":"event-6","conditions":"[]","actions":["action-6"],"isEnabled":true,"_id":"rule-5"},{"name":"ParseAndUploadPostmanJsonTestResults","webhook":"event-1","actions":["action-7"],"isEnabled":true,"_id":"rule-6"},{"name":"LinkTestCasesToRequirementsWithScenario","webhook":"event-8","actions":["action-8"],"isEnabled":true,"_id":"rule-7"}],"constants":[{"name":"SlackWebHook","value":"","_id":"constant-1"},{"name":"JenkinsURL","value":"","_id":"constant-2"},{"name":"JenkinsUserName","value":"","_id":"constant-3"},{"name":"JenkinsAPIToken","value":"","_id":"constant-4"},{"name":"JenkinsJobName","value":"","_id":"constant-5"},{"name":"JenkinsJobToken","value":"","_id":"constant-6"},{"name":"ManagerURL","value":"","_id":"constant-7"},{"name":"SCENARIO_PROJECT_ID","value":"","_id":"constant-8"},{"name":"SCENARIO_ACCOUNT_ID","value":"","_id":"constant-9"},{"name":"qTestAPIToken","value":"","_id":"constant-10"}]}
You can’t perform that action at this time.