/**
* Created by 212392192 on 7/22/16.
*
* A util to help query and update rally using rally-node
*/
(function(){
var rally = require('rally');
queryUtils = rally.util.query;
refUtils = rally.util.ref;
logger = require('./Logger.js');
rallylog = require("./RallyLog.js");
var apiKey;
if (process.env.apiKey != undefined) {
apiKey = process.env.apiKey;
rallylog.info('apikey is ' + "\'" + apiKey + "\'");
}
else {
rallylog.info('no apiKey defined');
return;
}
if (process.env.method != undefined)
var method = process.env.method;
else
var method = "Automated"; // default workspace
var project = process.env.project;
var ws = process.env.rallyworkspace
var proxy = process.env.rallyProxy;
var baseUrl = 'https://rally1.rallydev.com/slm/webservice/v2.0/';
var type;
if(process.env.type != undefined){
type = process.env.type.trim();
if( ((type != 'Acceptance') && (type != 'Functional') && (type != 'Performance') && (type != 'Regression') &&
(type != 'Usability') && (type != 'User Interface'))){
console.log('Typo in the .env file type= : setting Type to default value "Acceptance"');
rallylog.info('Typo in the .env file type= ' + "\'" + type + "\'" + ' setting Type to default value "Acceptance"');
type = "Acceptance"
}
} else {
type = 'Acceptance'
}
restApi = rally({
apiKey: apiKey, //preferred, required if no user/pass, defaults to process.env.RALLY_API_KEY
apiVersion: 'v2.0', //this is the default and may be omitted
server: 'https://rally1.rallydev.com', //this is the default and may be omitted
requestOptions: {
headers: {
'X-RallyIntegrationName': 'Rally Result Logger for ProUI', //while optional, it is good practice to
'X-RallyIntegrationVendor': 'GE Digital', //provide this header information
'X-RallyIntegrationVersion': '1.0'
},
proxy: proxy
}
});
/**
* RallyLogger
*/
var RallyLogger = function () {
return {
/**
* Get the rally object ref in form of '/[Object]/12345678', e.g. '/testfolder/59651570691'
* @param objType The object type. e.g. 'project', 'testfodler', 'testcase' etc.
* @param objName The name of the object, e.g. 'QE Automation Engineering'
* @param project/ws The project/workspace specified in .env i.e. 'GE Digital'/'QE Automation Engineering'
* @param callback The object reference of the requested object if found or 'NOT_FOUND' otherwise.
*/
getObjectRef: function(objType, objName, project, ws, callback) {
//by object name
if(objName == '') {
console.log('No workspace/project provided - using default');
logger.info('No workspace/project provided - using default');
callback('');
} else {
var qr = queryUtils.where('name', '=', objName);
restApi.query({
type: objType, //the type to query
start: 1, //the 1-based start index, defaults to 1
pageSize: 200, //the page size (1-200, defaults to 200)
limit: Infinity, //the maximum number of results to return- enables auto paging
fetch: ['FormattedID', 'Name', 'TestCases', 'ObjectID', 'LastResult', 'RevisionHistory', 'Steps'],
query: qr,
scope: {
workspace: ws,
project: project
}
}, function (error, result) {
if (error) {
console.log(error);
throw error;
} else {
//console.log(result.Results);
var last_run = false;
var test_case_result_id = 0;
var revision_history_ref = '';
var obj = JSON.parse(JSON.stringify(result.Results));
if (obj.length > 0) {
if (obj[0].LastResult != undefined) {
if (obj[0].LastResult == null) {
last_run = false;
} else {
last_run = true;
test_case_result_id = obj[0].LastResult._ref;
test_case_result_id = test_case_result_id.split('/');
test_case_result_id = test_case_result_id[7];
}
} else {
last_run = false;
}
if (obj[0].RevisionHistory != undefined) {
revision_history_ref = obj[0].RevisionHistory._ref;
}
// if(obj[0].Steps != undefined) {
// if (obj[0].Steps.Count > 0){
// //console.log('test case has ' + obj[0].Steps.Count + ' steps');
// } else {
// //console.log('test case has no steps');
// }
// }
var myref = obj[0]._ref; var id = result.Results[0].ObjectID; var ref = refUtils.getRelative(myref)
callback({ref:ref, id:id, last_run:last_run, test_case_result_id:test_case_result_id, revision_history_ref:revision_history_ref});
} else {
callback('NOT_FOUND');
}
}
});
}
},
/**
* Get the rally User permissions (workspace/projects able to edit), and owner ID information
* @param type The object type - only 2 used: 'workspace' and 'project'
* @param object The name of the object, e.g. 'QE Automation Engineering'
* @param callback The object reference of the requested object if found or 'NOT_FOUND' otherwise.
*/
UserPermissions: function(type, object, callback) {
var proj_ref='';
var ws_ref = '';
restApi.query({
type: 'userpermission', //the type to query
start: 1, //the 1-based start index, defaults to 1
pageSize: 200, //the page size (1-200, defaults to 200)
limit: Infinity, //the maximum number of results to return- enables auto paging
fetch: ['Workspace', 'Name', 'Project', 'ObjectID', 'User'], //the fields to retrieve
scope: {
}
}, function (error, result) {
if (error) {
console.error(error);
callback(error);
} else {
var obj = JSON.parse(JSON.stringify(result.Results));
if (obj.length > 0) {
var myref = obj[0].User._ref;
var ref = refUtils.getRelative(myref);
var owner_id = obj[0].User.ObjectID;
for(var i=0; i < obj.length; i++) {
if(type == 'workspace') {
if(obj[i].Workspace.Name == object){
//console.log('found workspace - user has permissions');
ws_ref = obj[i].Workspace._ref;
ws_ref = refUtils.getRelative(ws_ref);
break;
}
} else if(type == 'project') {
if(obj[i].Project != undefined) {
if (obj[i].Project.Name == object) {
//console.log('found project - user has permissions');
proj_ref = obj[i].Project._ref;
proj_ref = refUtils.getRelative(proj_ref);
break;
}
}
}
}
if((i == obj.length) && (object != '')) {
callback('NOT_FOUND');
} else {
callback({owner_id:owner_id, wsRef:ws_ref, projRef:proj_ref});
}
} else {
callback('NOT_FOUND');
}
}
});
},
/**
* Get a rally user story and test set reference
* @param USTS the user story. e.g. 'US6400' or testset e.g. 'TS20'
* @param ws/proj the workspace and project the user story belongs to
* @param callback the user story ref in the form of '/hierarchicalrequirement/1234567889'
*/
getUSTSRef: function (USTS, ws, proj, type, callback) {
if(USTS == '') {
callback({id: ''});
} else {
var qr = queryUtils.where('FormattedID', '=', USTS);
restApi.query({
type: type,
start: 1, //the 1-based start index, defaults to 1
pageSize: 200, //the page size (1-200, defaults to 200)
limit: Infinity, //the maximum number of results to return- enables auto paging
fetch: ['Name', 'ObjectID'],//, 'ScheduleState', 'PlanEstimate', 'Iteration'],
query: qr,
scope: {
workspace: ws,
project: proj
}
}, function (error, result) {
if (error) {
console.log(error);
throw error;
} else {
//console.log('query USTS' + result.Results);
var obj = JSON.parse(JSON.stringify(result.Results));
if(obj.length > 0) {
var myref = obj[0]._ref;
var ref = refUtils.getRelative(myref);
var id = obj[0].ObjectID;
//console.log('USTS ref: ' + refUtils.getRelative(myref));
callback({ref: ref, id: id});
} else {
ref = ''; id='';
callback({ref: ref, id: id});
}
}
});
}
},
/**
* Create a test folder
* @param name test folder name from feature file
* @param ws the workspace
* @param proj the project
* @param callback returns the objectID of the newly created test folder
*/
createTestPlan: function (name, ws, proj, callback) {
restApi.create({
type: 'testfolder', //the type to create
data: {
Name: name,
},
fetch: ['FormattedID', 'ObjectID'], //the fields to be returned on the created object
scope: {
workspace: ws,
project: proj
},
requestOptions: {} //optional additional options to pass through to request
}, function (error, result) {
if (error) {
console.log(error);
throw error;
} else {
//console.log('created test plan: ' + result.Results);
var testfolderRef = refUtils.getRelative(JSON.parse(JSON.stringify(result.Object)));
var id = result.Object.ObjectID
//console.log("new test folder ref" + testfolderRef);
callback({id: id});
}
});
},
/**
* Create a testcase
* @param opts - contains kObject (duration),
* and tcObject (parent folder id, description, name, user story, owner), and error
* @param ws/project workspace and project of the test case
* @param callback returns the testcase ObjectID
*/
createTestcase: function (opts, ws, project, callback) {
//console.log('inside create test case function');
if (opts.kObj.duration == undefined) {
opts.kObj.duration = 0;
}
if (opts.tcObj.glb_folder_id == null) {
opts.tcObj.glb_folder_id = 0;
}
if (opts.tcObj.test_case_description == "") {
opts.tcObj.stepsArray = opts.tcObj.stepsArray.toString().split('"').join('');
opts.tcObj.test_case_description = "N/A<br>" + opts.tcObj.stepsArray;
} else {
opts.tcObj.stepsArray = opts.tcObj.stepsArray.toString().split('"').join('');
opts.tcObj.test_case_description = opts.tcObj.test_case_description + "<br>" + opts.tcObj.stepsArray;
}
restApi.create({
type: 'testcase', //the type to create
data: {
Name: opts.tcObj.test_case_name,
Description: opts.tcObj.test_case_description,
Method: method,
TestFolder: opts.tcObj.glb_folder_id,
WorkProduct: opts.tcObj.User_Story,
Owner: opts.tcObj.owner,
Notes: opts.error,
Type: type
},
fetch: ['FormattedID', 'ObjectID'],
scope: {
workspace: ws,
project: project
}
}, function (error, result) {
if (error) {
console.log('error: ' + error);
//throw error;
callback({id: ''});
} else {
//console.log("created test case: " + JSON.parse(JSON.stringify(result.Object)));
var testcaseRef = refUtils.getRelative(JSON.parse(JSON.stringify(result.Object)));
opts.tcObj.glb_test_case_id = result.Object.ObjectID;
//console.log("new testcase ref" + testcaseRef);
callback({id: opts.tcObj.glb_test_case_id});
}
});
},
/**
* Create a testcase result of a given testcase.
* @param opts - contains duration, status, testcase ID, buildnumber
* @param ws/proj - workspace and project IDs
* @param callback - returns id off the test case result created
*/
createTestcaseResult: function (opts, ws, proj, callback) {
if((opts.resp.duration == undefined) || (opts.resp.duration == 'undefined')
|| (opts.resp.duration == null) || (opts.resp.duration == NaN) || (opts.resp.duration == 'NaN')) {
opts.resp.duration = 0;
} else if (opts.resp.duration > 9999999999) {
opts.resp.duration = 9999999999;
}
if (opts.resp.status == 'passed') {
opts.resp.status = 'Pass';
} else if (opts.resp.status == "failed") {
opts.resp.status = 'Fail';
} else if (opts.resp.status == "skipped") {
opts.resp.status = 'Inconclusive';
duration = 0;
}
restApi.create({
type: 'testcaseresult', //the type to create
data: {
TestCase: opts.tcObj.glb_test_case_id,
Build: opts.tcObj.build_num,
Duration: opts.resp.duration,
Verdict: opts.resp.status,
Date: (new Date).toISOString(),
TestSet: opts.resp.id
},
fetch: ['ObjectID'], //the fields to be returned on the created object
scope: {
workspace: ws,
project: proj
}
}, function (error, result) {
if (error) {
console.log(error);
throw error;
} else {
//console.log(result.Object);
var id = result.Object.ObjectID;
callback({id:id});
}
});
},
/**
* Update the result of a given testcase.
* @param opts
* @param ws
* @param callback
*/
updateTestCaseResult: function(opts, ws, proj, callback) {
if (opts.resp.duration == undefined) {
opts.resp.duration = 0;
}
if ((opts.resp.duration != undefined) && (opts.resp.duration > 9999999999)) {
opts.resp.duration = 9999999999;
}
if (opts.resp.status == 'passed') {
opts.resp.status = 'Pass';
} else if (opts.resp.status == "failed") {
opts.resp.status = 'Fail';
} else if (opts.resp.status == "skipped") {
opts.resp.status = 'Inconclusive';
opts.resp.duration = 0;
}
restApi.update({
ref: '/testcaseresult/' + opts.tcObj.glb_test_result_id,
data: {
Build: opts.tcObj.build_num,
Duration: opts.resp.duration,
Verdict: opts.resp.status,
Date: (new Date).toISOString(),
TestCase:opts.tcObj.resp.ref,
TestSet: opts.resp.id
},
fetch: [], //the fields to be returned on the created object
scope: {
workspace: ws,
project: proj
},
requestOptions: {} //optional additional options to pass through to request
}, function (error, result) {
if (error) {
console.log(error);
} else {
//console.log(result.Object);
callback();
}
});
},
/**
* Update the testcase of a given testcase.
* @param opts
* @param ws
* @param callback
*/
updateTestCase: function (opts, ws, proj, callback) {
if (opts.tcObj.test_case_description == "") {
opts.tcObj.stepsArray = opts.tcObj.stepsArray.toString().split('"').join('');
opts.tcObj.test_case_description = "N/A<br>" + opts.tcObj.stepsArray;
} else {
opts.tcObj.stepsArray = opts.tcObj.stepsArray.toString().split('"').join('');
opts.tcObj.test_case_description = opts.tcObj.test_case_description + "<br>" + opts.tcObj.stepsArray;
}
var request = require('request-promise');
restApi.update({
ref: opts.tcObj.resp.ref, //the type to create
data: {
WorkProduct: opts.resp.id,
Method: method,
Owner: opts.owner,
Notes: opts.error,
Type: type,
Description: opts.tcObj.test_case_description
},
fetch: ['FormattedID', 'Project'], //the fields to be returned on the created object
scope: {
workspace: ws,
project: proj
}
}, function (error, result) {
if (error) {
console.log(error);
callback( error );
} else {
//console.log(result.Object);
callback();
}
});
},
/**
* Update Test Set to add test case
* @param tcObj object w/ User_Story, resp, j, test_case_name, test_case_description, glb_folder_id,
* build_num, testset, glb_test_case_id, glb_test_result_id, last_run, glb_i_length, glb_j_length
* @param resp resonse from query TestSet
* @param callback callback on error and http response
*/
updateTestSet: function(tcObj, resp, callbck){
var request = require('request-promise');
var to_return;
if(resp.id == ''){
to_return = {
id:'', status:resp.status, duration:resp.duration, glb_test_case_id:resp.glb_test_case_id,
glb_folder_id:tcObj.glb_folder_id, json:resp.json, i:resp.i, j:resp.j, k:k
};
callbck(to_return);
} else {
to_return = {
id: resp.id, status: resp.status, duration: resp.duration,
glb_test_case_id: resp.glb_test_case_id, glb_folder_id: tcObj.glb_folder_id, json: resp.json,
i: resp.i, j: resp.j, k: k
};
var options = {
method: 'POST',
url: 'https://rally1.rallydev.com/slm/webservice/v2.x/TestSet/' + resp.id + '/TestCases/add?fetch=true',
headers: {zsessionid: apiKey},
proxy: proxy,
body: '{"CollectionItems":[{"_ref":"/testcase/' + tcObj.glb_test_case_id + '"}]}'
};
request(options)
.then(function (body, error) {
//console.log('updated test set: ' + body);
callbck(to_return);
});
}
}
}
};
module.exports = new RallyLogger();
})();