Name
global.TestExecutorAjax
Description
No description available
Script
var TestExecutorAjax = Class.create();
TestExecutorAjax.prototype = Object.extendsObject(AbstractAjaxProcessor, {
process: function() {
var name = this.getParameter('sysparm_name');
if (name == 'claimTest')
return this.claimTest();
else if (name == 'decodeFieldValues')
return this.decodeFieldValues();
else if (name == 'addTestsToTestSuite')
return this.addTestsToTestSuite();
else if (name == 'findOldestScheduledTest')
return this.findOldestScheduledTest();
else if (name == 'resolveInputs')
return this.resolveInputs();
else if (name =='validateFormParameters')
return this.validateFormParameters();
else if (name == 'impersonate')
return this.impersonate();
else if (name == 'unimpersonate')
return this.unimpersonate();
else if (name == 'getDisplay')
return this.getDisplay();
else if (name == 'isImpersonating')
return this.isImpersonating();
else if (name == 'uploadAttachments')
return this.uploadAttachments();
else if (name == "getWorkspaceName")
return this.getWorkspaceName(this.getParameter("sysparm_workspace_slug"));
else if (name == "extendsTable")
return this.extendsTable(this.getParameter("sysparm_table"), this.getParameter("sysparm_parent"));
else if (name == "pauseTest")
return this.pauseTest(this.getParameter("sysparm_test_result_id"));
else if (name == "unpauseTest")
return this.unpauseTest(this.getParameter("sysparm_test_result_id"));
else if (name == "stepOver")
return this.stepOver(this.getParameter("sysparm_test_result_id"));
else if (name == "getPauseInfo")
return this.getPauseInfo(this.getParameter("sysparm_test_result_id"));
else if (name == "getServerErrors")
return this.getServerErrors(this.getParameter("sysparm_test_result_id"));
var utTestSysId = this.getParameter("sysparm_ajax_processor_ut_test_id");
var utTestSuiteId = this.getParameter("sysparm_ajax_processor_ut_test_suite_id");
var trackerId = this.getParameter("sysparm_ajax_processor_tracker_id");
var testResultId = this.getParameter("sysparm_ajax_processor_test_result_id");
var testSuiteResultId = this.getParameter("sysparm_ajax_processor_test_suite_result_id");
if (this.getType() == 'cancelTestRun')
return this.cancelTestRun(trackerId);
if (this.getType() == 'killTestRun')
return this.killTestRun(trackerId);
if (utTestSuiteId)
return this.runUserTestSuite(utTestSuiteId);
if (utTestSysId)
return this.runUserTest(utTestSysId);
if (testResultId)
return this.getTrackerIdFromTestResult(testResultId);
if (testSuiteResultId)
return this.getTrackerIdFromTestSuiteResult(testSuiteResultId);
},
getTrackerIdFromTestResult: function(testResultId) {
var gr = new GlideRecord('sys_atf_test_result');
if (!gr.get(testResultId)) {
gs.log("Could not find test result with id: " + testResultId);
return;
}
return gr.execution_tracker.sys_id;
},
getTrackerIdFromTestSuiteResult: function(testSuiteResultId) {
var gr = new GlideRecord('sys_atf_test_suite_result');
if (!gr.get(testSuiteResultId)) {
gs.log("Could not find test result with id: " + testResultId);
return;
}
return gr.execution_tracker.sys_id;
},
claimTest: function() {
var test_result_sys_id = this.getParameter('sysparm_test_result_sys_id');
var ui_batch_execution_tracker_sys_id = this.getParameter('sysparm_batch_execution_tracker_sys_id');
var batch_length = this.getParameter('sysparm_batch_length');
return new sn_atf.TestClaimer()
.setATFTestRecordSysId(test_result_sys_id)
.setUIBatchTrackerSysId(ui_batch_execution_tracker_sys_id)
.setBatchLength(batch_length)
.claim();
},
/**
* Queries for a test to be executed by the test runner
* by matching the message reference passed with the test result's message_reference
* If a test to be executed is found, tries to claim the test
* If successful, returns the test case json string
* If not, returns null
*/
findOldestScheduledTest: function() {
var userName = this.getParameter("sysparm_user_name");
var messageReference = this.getParameter("sysparm_message_reference");
if (!messageReference) {
gs.log("TestExecutorAjax.findOldestScheduledTest has no message reference argument");
return null;
}
//finds the oldest scheduled test and returns its test_case_json (or null if none found)
gs.log("TestExecutorAjax looking for a scheduled test to run for user: " + userName + ", message reference: " + messageReference);
var gr = new GlideRecord('sys_atf_test_result');
gr.addQuery('status', 'waiting');
var isCloudRunner = this.getParameter("sysparm_cloud_runner") == "true";
var rootTrackerId = this.getParameter("sysparm_root_tracker_id");
// cloud runners match on 'cloud' message reference and the root tracker id
if (isCloudRunner) {
gr.addQuery('message_reference', 'cloud');
gr.addQuery('root_tracker_id', rootTrackerId);
} else
gr.addQuery('message_reference', messageReference);
gr.orderBy('sys_created_on');
gr.query();
if (gr.next()) {
//found a test to run, try to claim it
var testResultSysId = gr.getUniqueValue();
var testCaseJSONString = gr.getValue('test_case_json');
var testCaseJSON = JSON.parse(testCaseJSONString);
var uiBatchTrackerSysId = testCaseJSON.tracker_sys_id;
var successfulClaim = new sn_atf.TestClaimer()
.setATFTestRecordSysId(testResultSysId)
.setUIBatchTrackerSysId(uiBatchTrackerSysId)
.setBatchLength(testCaseJSON.sys_atf_steps.length)
.claim();
if (successfulClaim) {
gs.log("Successfully claimed scheduled test " + testResultSysId);
return testCaseJSONString;
} else {
gs.log("TestExecutorAjax tried to claim a scheduled test, but was not successful");
return null;
}
} else {
gs.log("TestExecutorAjax did not find any tests in the 'waiting' state");
return null;
}
},
runUserTestSuite: function(utTestSuiteId) {
var testRunnerSessionId = this.getParameter('sysparm_ajax_processor_test_runner_session_id');
gs.log("TestexecutorAjax runUserTestSuite called with test runner session id: " + testRunnerSessionId);
var gr = new GlideRecord('sys_atf_test_suite');
if (!gr.get(utTestSuiteId)) {
gs.log("Could not find the Test suite with id: " + utTestSuiteId);
return;
}
if (this.isImpersonating()) {
gs.log("Running tests and test suites is disabled while impersonating another user. Unable to run suite with id:" + utTestSuiteId);
return;
}
var executor;
var previousSuiteResultId = this.getParameter("sysparm_ajax_processor_previous_suite_result_id");
var isPausingEnabled = "true" == this.getParameter('sysparm_ajax_processor_is_pausing_enabled');
var pauseBeforeRollback = "true" == this.getParameter('sysparm_ajax_processor_pause_before_rollback');
var useCloudRunner = "true" == this.getParameter('sysparm_ajax_processor_use_cloud_runner');
if (previousSuiteResultId) {
executor = new sn_atf.RerunTestSuiteExecutor();
executor.setTestSuiteSysId(utTestSuiteId);
executor.setTestRunnerSessionId(testRunnerSessionId);
executor.setRerunSuiteResultId(previousSuiteResultId);
executor.setUseCloudRunner(useCloudRunner);
return executor.start();
}
else {
executor = new sn_atf.UserTestSuiteExecutor();
executor.setTestSuiteSysId(utTestSuiteId);
executor.setTestRunnerSessionId(testRunnerSessionId);
executor.setPausingEnabled(isPausingEnabled, pauseBeforeRollback);
executor.setUseCloudRunner(useCloudRunner);
return executor.start();
}
},
runUserTest: function(utTestSysId) {
var testRunnerSessionId = this.getParameter('sysparm_ajax_processor_test_runner_session_id');
gs.log("TestexecutorAjax runUserTest called with test runner session id: " + testRunnerSessionId);
var gr = new GlideRecord('sys_atf_test');
if (!gr.get(utTestSysId)) {
gs.log("couldn't find the Test record with id: " + utTestSysId);
return;
}
if (this.isImpersonating()) {
gs.log("Running tests and test suites is disabled while impersonating another user. Unable to run test with id:" + utTestSysId);
return;
}
var capturePageData = "true" == this.getParameter('sysparm_ajax_processor_page_data_capture');
var retrieveComponentsStep = this.getParameter('sysparm_ajax_processor_retrieve_components_step');
var isPausingEnabled = "true" == this.getParameter('sysparm_ajax_processor_is_pausing_enabled');
var pauseBeforeRollback = "true" == this.getParameter('sysparm_ajax_processor_pause_before_rollback');
var useCloudRunner = "true" == this.getParameter('sysparm_ajax_processor_use_cloud_runner');
return new sn_atf.ExecuteUserTest()
.setCapturePageData(utTestSysId, capturePageData)
.setRetrieveComponentsStep(utTestSysId, retrieveComponentsStep)
.setTestRecordSysId(utTestSysId)
.setTestRunnerSessionId(testRunnerSessionId)
.setPausingEnabled(isPausingEnabled, pauseBeforeRollback)
.setUseCloudRunner(useCloudRunner)
.start();
},
cancelTestRun: function(trackerId) {
return sn_atf.AutomatedTestingFramework.cancelTestRun(trackerId);
},
killTestRun: function(trackerId) {
return sn_atf.AutomatedTestingFramework.killTestRun(trackerId, false); // false means the kill request is not sent from cluster message
},
/*
* Converts an encoded query (condition) into a list of field/value pairs to be used when setting a value in a
* client script via g_form.setValue. This code builds on top of the template feature which performs nearly
* identical operations.
*/
decodeFieldValues: function() {
var table = this.getParameter('sysparm_table_name');
var encodedQuery = this.getParameter('sysparm_field_values');
// Use GlideTemplate so we can re-use existing code.
var fakeTemplateGR = new GlideRecord("sys_template");
fakeTemplateGR.setValue("template", encodedQuery);
fakeTemplateGR.setValue("next_child",false);
fakeTemplateGR.setValue("table",table);
// GlideTemplate is a Java class used when applying templates from the UI
var glideTemplate = GlideTemplate.getFromRecord(fakeTemplateGR);
glideTemplate.setApplyChildren(false); // n/a for this use case
var targetGR = glideTemplate.apply();
var fieldList = glideTemplate.getTemplateElements();
// Template is a Ajax script include used when applying templates
var template = new Template();
for (var i = 0; i < fieldList.size(); i++) {
var fieldName = fieldList.get(i);
var ge = targetGR.getElement(fieldName);
if (ge.getED().isVirtual())
continue;
var value = template.getValue(ge);
var fieldValue = this.newItem("fieldValue");
fieldValue.setAttribute("field", fieldName);
fieldValue.setAttribute("value", value);
}
},
resolveInputs: function() {
var resultId = this.getParameter("sysparm_atf_test_result");
var stepId = this.getParameter("sysparm_atf_step_id");
var parameterSetOrder = this.getParameter("sysparm_atf_parameter_set_order");
var testProcessor = new sn_atf.UserTestProcessor();
return testProcessor.generateStepJSON(stepId, resultId, parameterSetOrder);
},
addTestsToTestSuite: function() {
var testSuiteId = this.getParameter("sysparm_atf_test_suite_id");
var testIds = this.getParameter("sysparm_atf_test_ids");
var testQuery = this.getParameter("sysparm_atf_test_query");
var testsToAdd = [];
if (testIds)
testsToAdd = testIds.split(",");
else {
var testGR = new GlideRecord('sys_atf_test');
if (testQuery)
testGR.addEncodedQuery(testQuery);
testGR.query();
while (testGR.next())
testsToAdd.push(testGR.getValue('sys_id'));
}
var testSuiteProcessor = new sn_atf.TestSuiteProcessor();
return testSuiteProcessor.addTestsToTestSuite(testSuiteId, testsToAdd);
},
/**
* Validates the table, view and sys_id provided as parameters to the open a new form and open an existing form steps
* If all three are valid, returns true. If not, it returns the the message invalid table/view/sys id
*/
validateFormParameters: function() {
var formView = this.getParameter('sysparm_view_name');
var formTable = this.getParameter('sysparm_table_name');
var sysId = this.getParameter('sysparm_sys_id');
gs.log("TestExecutorAjax validateFormParameters called with table: " + formTable + ", view: " + formView + ", sysId: " + sysId);
var gr = new GlideRecord(formTable);
if (!gr.isValid()) {
gs.log("TestExecutorAjax validateFormParameters: Invalid table name: " + formTable);
return "invalid table";
}
if (!this.validateFormView(formView, formTable)) {
gs.log("TestExecutorAjax validateFormParameters: Invalid view: " + formView + " for table " + formTable);
return "invalid view";
}
if (sysId && !gr.get(sysId)) {
gs.log("TestExecutorAjax validateFormParameters: Invalid sysId: " + sysId + " for table " + formTable);
return "invalid sys id";
}
return true;
},
validateFormView: function(formView, formTable) {
if(GlideStringUtil.nil(formView) || formView.toLowerCase() == "default")
return true;
var viewManager = new GlideScriptViewManager(null);
viewManager.setTable(formTable);
viewManager.setTarget("section");
var cl = viewManager.getList();
return cl.contains(formView);
},
impersonate: function() {
var impersonatingUser = this.getParameter("sysparm_impersonating_user");
gs.log("TestExecutorAjax impersonate called with impersonating user: " + impersonatingUser);
if (gs.getUserID() != impersonatingUser)
gs.getSession().onlineImpersonate(impersonatingUser);
// Return the currently logged in user Id so that impersonation outcome can be verified
return gs.getUserID();
},
unimpersonate: function() {
gs.log("TestExecutorAjax unimpersonating");
// Only unimpersonate if there is currently an impersonation. In case onlineUnimpersonate was ran before then
// we do not need to unimpersonate again as this will put the instance in a bad state
if(this.isImpersonating()) {
gs.getSession().onlineUnimpersonate();
// Return the currently logged in user Id so that we can verify if unimpersonation was successful
return gs.getUserID();
} else {
return "";
}
},
isImpersonating: function() {
return (new GlideImpersonate()).isImpersonating();
},
/**
* Returns a choice list of supported Jasmine versions for use with the "Run Server Side Script" test step.
*/
getJasmineChoiceList: function() {
var str = GlidePropertiesDB.get('sn_atf.jasmine.versions', '3.1');
var splitstr = str.split(',');
var list = new GlideChoiceList();
splitstr.forEach(function(item) {
list.add(new GlideChoice(item, item));
});
return list;
},
getDisplay: function() {
return getDisplayValueOf(this.getParameter('sysparm_table'),this.getValue());
},
/**
* Client-callable API for uploading attachments in an ATF context
* Uses the attachments on the current step record, as well as a user-specified table and target_id (sys_id of the record to attach to)
*/
uploadAttachments: function() {
var stepID = this.getParameter("sysparm_atf_step_sys_id");
var table = this.getParameter("sysparm_table");
var targetID = this.getParameter("sysparm_target_id");
return sn_atf.AutomatedTestingFramework.uploadAttachments(stepID, table, targetID);
},
getWorkspaceName: function(workspaceSlug) {
var workspaceGr = new GlideRecord('sys_aw_master_config');
workspaceGr.addQuery('workspace_url', workspaceSlug);
workspaceGr.query();
if (workspaceGr.next())
return workspaceGr.getValue('name');
else
return gs.getMessage('Unknown');
},
/**
* Check if a table extends another table
* Since this is a publicly callable API without ACLs, only return a value if the session owner has rights to see both tables
*/
extendsTable: function(table, parent) {
var tableGR = new GlideRecord(table);
var parentGR = new GlideRecord(parent);
// If either table is invalid or the session owner can't see one of them, return without even giving an answer
if (!tableGR.isValid() || !parentGR.isValid() || !tableGR.canRead() || !parentGR.canRead())
return;
// Both tables are valid and the session owner can see both of them so return whether table extends parent
return tableGR.instanceOf(parent);
},
/**
* Pauses a running test. Returns the maximum amount of time that the test can remain paused
*/
pauseTest: function(resultID) {
sn_atf.ATFBreakpoint.pauseTest(resultID);
return sn_atf.ATFBreakpoint.getMaximumPauseTime();
},
/**
* Unpause a paused test from a test result sys_id. If the test is not paused this has no side effects
*/
unpauseTest: function(resultID) {
sn_atf.ATFBreakpoint.unpauseTest(resultID);
},
/**
* Step over the current step in a paused test from a test result sys_id. If the test is not paused this has no side effects
*/
stepOver: function(resultID) {
sn_atf.ATFBreakpoint.stepOver(resultID);
},
/**
* Returns a stringified JSON object containing a "paused" property indicating if the test is paused or not,
* and a "pause_time_left" field indicating how much longer the test can stay paused (only if "paused" is true)
*/
getPauseInfo: function(resultID) {
return JSON.stringify(sn_atf.ATFBreakpoint.getPauseInfo(resultID));
},
/**
* Gets all server errors caught by the test result with the specified sys_id that are unaccounted for
* If an error turns out to be ignored, the client test runner will update its status accordingly,
* and it won't be returned in subsequent calls of this function
*/
getServerErrors: function(resultID) {
var errorsGR = new GlideRecord("sys_atf_test_result_item");
errorsGR.addQuery("test_result", resultID);
errorsGR.addQuery("type", "server_error");
// Only look at errors with status "Failure"; if it turns out they're ignored, the client test runner will
// change the state to "Ignored" or "Warning" and they won't be returned the next time this function is called
errorsGR.addQuery("status", "failure");
errorsGR.query();
while (errorsGR.next()) {
var item = this.newItem("server_error");
item.setAttribute("sys_id", errorsGR.getUniqueValue());
item.setAttribute("output", errorsGR.getValue("output"));
}
},
type: 'TestExecutorAjax'
});
Sys ID
0380e2605b2212006f23efe5f0f91abd