mirror of
https://github.com/ansible/awx.git
synced 2026-03-09 21:49:27 -02:30
workflow job elapsed timer
* Now with tests for elapsed timer feature.
This commit is contained in:
@@ -7,10 +7,12 @@
|
|||||||
import workflowStatusBar from './workflow-status-bar/main';
|
import workflowStatusBar from './workflow-status-bar/main';
|
||||||
import route from './workflow-results.route.js';
|
import route from './workflow-results.route.js';
|
||||||
import workflowResultsService from './workflow-results.service';
|
import workflowResultsService from './workflow-results.service';
|
||||||
|
import controller from './workflow-results.controller';
|
||||||
|
|
||||||
export default
|
export default
|
||||||
angular.module('workflowResults', [workflowStatusBar.name])
|
angular.module('workflowResults', [workflowStatusBar.name])
|
||||||
.run(['$stateExtender', function($stateExtender) {
|
.run(['$stateExtender', function($stateExtender) {
|
||||||
$stateExtender.addState(route);
|
$stateExtender.addState(route);
|
||||||
}])
|
}])
|
||||||
|
.controller('workflowResultsController', controller)
|
||||||
.service('workflowResultsService', workflowResultsService);
|
.service('workflowResultsService', workflowResultsService);
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ export default ['workflowData',
|
|||||||
'count',
|
'count',
|
||||||
'$state',
|
'$state',
|
||||||
'i18n',
|
'i18n',
|
||||||
|
'moment',
|
||||||
function(workflowData,
|
function(workflowData,
|
||||||
workflowResultsService,
|
workflowResultsService,
|
||||||
workflowDataOptions,
|
workflowDataOptions,
|
||||||
@@ -21,8 +22,10 @@ export default ['workflowData',
|
|||||||
WorkflowService,
|
WorkflowService,
|
||||||
count,
|
count,
|
||||||
$state,
|
$state,
|
||||||
i18n
|
i18n,
|
||||||
|
moment
|
||||||
) {
|
) {
|
||||||
|
var runTimeElapsedTimer = null;
|
||||||
|
|
||||||
var getTowerLinks = function() {
|
var getTowerLinks = function() {
|
||||||
var getTowerLink = function(key) {
|
var getTowerLink = function(key) {
|
||||||
@@ -57,6 +60,10 @@ export default ['workflowData',
|
|||||||
$scope.verbosity_label = getTowerLabel('verbosity');
|
$scope.verbosity_label = getTowerLabel('verbosity');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var updateWorkflowJobElapsedTimer = function(time) {
|
||||||
|
$scope.workflow.elapsed = time;
|
||||||
|
};
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
// put initially resolved request data on scope
|
// put initially resolved request data on scope
|
||||||
$scope.workflow = workflowData;
|
$scope.workflow = workflowData;
|
||||||
@@ -66,6 +73,11 @@ export default ['workflowData',
|
|||||||
$scope.count = count.val;
|
$scope.count = count.val;
|
||||||
$scope.showManualControls = false;
|
$scope.showManualControls = false;
|
||||||
|
|
||||||
|
// Start elapsed time updater for job known to be running
|
||||||
|
if ($scope.workflow.started !== null && $scope.workflow.status === 'running') {
|
||||||
|
runTimeElapsedTimer = workflowResultsService.createOneSecondTimer($scope.workflow.started, updateWorkflowJobElapsedTimer);
|
||||||
|
}
|
||||||
|
|
||||||
// stdout full screen toggle tooltip text
|
// stdout full screen toggle tooltip text
|
||||||
$scope.toggleStdoutFullscreenTooltip = i18n._("Expand Output");
|
$scope.toggleStdoutFullscreenTooltip = i18n._("Expand Output");
|
||||||
|
|
||||||
@@ -169,8 +181,12 @@ export default ['workflowData',
|
|||||||
// Update the workflow job's unified job:
|
// Update the workflow job's unified job:
|
||||||
if (parseInt(data.unified_job_id, 10) === parseInt($scope.workflow.id,10)) {
|
if (parseInt(data.unified_job_id, 10) === parseInt($scope.workflow.id,10)) {
|
||||||
$scope.workflow.status = data.status;
|
$scope.workflow.status = data.status;
|
||||||
|
// start internval counter for job that transitioned to running
|
||||||
|
if ($scope.workflow.status === 'running') {
|
||||||
|
runTimeElapsedTimer = workflowResultsService.createOneSecondTimer(moment(), updateWorkflowJobElapsedTimer);
|
||||||
|
}
|
||||||
|
|
||||||
if(data.status === "successful" || data.status === "failed"){
|
if(data.status === "successful" || data.status === "failed" || data.status === "error"){
|
||||||
$state.go('.', null, { reload: true });
|
$state.go('.', null, { reload: true });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -198,4 +214,8 @@ export default ['workflowData',
|
|||||||
$scope.$broadcast("refreshWorkflowChart");
|
$scope.$broadcast("refreshWorkflowChart");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$scope.$on('$destroy', function() {
|
||||||
|
workflowResultsService.destroyTimer(runTimeElapsedTimer);
|
||||||
|
});
|
||||||
}];
|
}];
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
*************************************************/
|
*************************************************/
|
||||||
|
|
||||||
|
|
||||||
export default ['$q', 'Prompt', '$filter', 'Wait', 'Rest', '$state', 'ProcessErrors', 'InitiatePlaybookRun', function ($q, Prompt, $filter, Wait, Rest, $state, ProcessErrors, InitiatePlaybookRun) {
|
export default ['$q', 'Prompt', '$filter', 'Wait', 'Rest', '$state', 'ProcessErrors', 'InitiatePlaybookRun', '$interval', 'moment', function ($q, Prompt, $filter, Wait, Rest, $state, ProcessErrors, InitiatePlaybookRun, $interval, moment) {
|
||||||
var val = {
|
var val = {
|
||||||
getCounts: function(workflowNodes){
|
getCounts: function(workflowNodes){
|
||||||
var nodeArr = [];
|
var nodeArr = [];
|
||||||
@@ -127,7 +127,20 @@ export default ['$q', 'Prompt', '$filter', 'Wait', 'Rest', '$state', 'ProcessErr
|
|||||||
relaunchJob: function(scope) {
|
relaunchJob: function(scope) {
|
||||||
InitiatePlaybookRun({ scope: scope, id: scope.workflow.id,
|
InitiatePlaybookRun({ scope: scope, id: scope.workflow.id,
|
||||||
relaunch: true, job_type: 'workflow_job' });
|
relaunch: true, job_type: 'workflow_job' });
|
||||||
}
|
},
|
||||||
|
createOneSecondTimer: function(startTime, fn) {
|
||||||
|
return $interval(function(){
|
||||||
|
fn(moment().diff(moment(startTime), 'seconds'));
|
||||||
|
}, 1000);
|
||||||
|
},
|
||||||
|
destroyTimer: function(timer) {
|
||||||
|
if (timer !== null) {
|
||||||
|
$interval.cancel(timer);
|
||||||
|
timer = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
return val;
|
return val;
|
||||||
}];
|
}];
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ module.exports = function(config) {
|
|||||||
'./client/src/app.js',
|
'./client/src/app.js',
|
||||||
'./node_modules/angular-mocks/angular-mocks.js',
|
'./node_modules/angular-mocks/angular-mocks.js',
|
||||||
{ pattern: './tests/**/*-test.js' },
|
{ pattern: './tests/**/*-test.js' },
|
||||||
|
{ pattern: './tests/**/*.json', included: false},
|
||||||
'client/src/**/*.html'
|
'client/src/**/*.html'
|
||||||
],
|
],
|
||||||
preprocessors: {
|
preprocessors: {
|
||||||
|
|||||||
@@ -52,17 +52,18 @@
|
|||||||
"grunt-newer": "^1.2.0",
|
"grunt-newer": "^1.2.0",
|
||||||
"grunt-webpack": "^1.0.11",
|
"grunt-webpack": "^1.0.11",
|
||||||
"imports-loader": "^0.6.5",
|
"imports-loader": "^0.6.5",
|
||||||
"jasmine-core": "^2.4.1",
|
"jasmine-core": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.5.2.tgz",
|
||||||
"jshint": "^2.9.4",
|
"jshint": "^2.9.4",
|
||||||
"jshint-loader": "^0.8.3",
|
"jshint-loader": "^0.8.3",
|
||||||
"jshint-stylish": "^2.2.0",
|
"jshint-stylish": "^2.2.0",
|
||||||
"karma": "^1.1.2",
|
"json-loader": "^0.5.4",
|
||||||
|
"karma": "^1.4.1",
|
||||||
"karma-chrome-launcher": "^1.0.1",
|
"karma-chrome-launcher": "^1.0.1",
|
||||||
"karma-coverage": "^1.1.1",
|
"karma-coverage": "^1.1.1",
|
||||||
"karma-firefox-launcher": "^1.0.0",
|
"karma-firefox-launcher": "^1.0.0",
|
||||||
"karma-html2js-preprocessor": "^1.0.0",
|
"karma-html2js-preprocessor": "^1.0.0",
|
||||||
"karma-jasmine": "^1.0.2",
|
"karma-jasmine": "^1.1.0",
|
||||||
"karma-junit-reporter": "^1.1.0",
|
"karma-junit-reporter": "^1.2.0",
|
||||||
"karma-phantomjs-launcher": "^1.0.2",
|
"karma-phantomjs-launcher": "^1.0.2",
|
||||||
"karma-sauce-launcher": "^1.0.0",
|
"karma-sauce-launcher": "^1.0.0",
|
||||||
"karma-sourcemap-loader": "^0.3.7",
|
"karma-sourcemap-loader": "^0.3.7",
|
||||||
|
|||||||
63
awx/ui/tests/spec/workflow--results/data/workflow_job.json
Normal file
63
awx/ui/tests/spec/workflow--results/data/workflow_job.json
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
{
|
||||||
|
"id": 109,
|
||||||
|
"type": "workflow_job",
|
||||||
|
"url": "/api/v1/workflow_jobs/109/",
|
||||||
|
"related": {
|
||||||
|
"created_by": "/api/v1/users/1/",
|
||||||
|
"unified_job_template": "/api/v1/workflow_job_templates/27/",
|
||||||
|
"workflow_job_template": "/api/v1/workflow_job_templates/27/",
|
||||||
|
"notifications": "/api/v1/workflow_jobs/109/notifications/",
|
||||||
|
"workflow_nodes": "/api/v1/workflow_jobs/109/workflow_nodes/",
|
||||||
|
"labels": "/api/v1/workflow_jobs/109/labels/",
|
||||||
|
"activity_stream": "/api/v1/workflow_jobs/109/activity_stream/",
|
||||||
|
"relaunch": "/api/v1/workflow_jobs/109/relaunch/",
|
||||||
|
"cancel": "/api/v1/workflow_jobs/109/cancel/"
|
||||||
|
},
|
||||||
|
"summary_fields": {
|
||||||
|
"workflow_job_template": {
|
||||||
|
"id": 27,
|
||||||
|
"name": "workflow timer",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"unified_job_template": {
|
||||||
|
"id": 27,
|
||||||
|
"name": "workflow timer",
|
||||||
|
"description": "",
|
||||||
|
"unified_job_type": "workflow_job"
|
||||||
|
},
|
||||||
|
"created_by": {
|
||||||
|
"id": 1,
|
||||||
|
"username": "admin",
|
||||||
|
"first_name": "",
|
||||||
|
"last_name": ""
|
||||||
|
},
|
||||||
|
"user_capabilities": {
|
||||||
|
"start": true,
|
||||||
|
"delete": true
|
||||||
|
},
|
||||||
|
"labels": {
|
||||||
|
"count": 0,
|
||||||
|
"results": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"created": "2017-02-01T14:56:47.416Z",
|
||||||
|
"modified": "2017-02-01T14:57:14.189Z",
|
||||||
|
"name": "workflow timer",
|
||||||
|
"description": "",
|
||||||
|
"unified_job_template": 27,
|
||||||
|
"launch_type": "manual",
|
||||||
|
"status": "successful",
|
||||||
|
"failed": false,
|
||||||
|
"started": "2017-02-01T14:56:47.754897Z",
|
||||||
|
"finished": "2017-02-01T14:57:14.182780Z",
|
||||||
|
"elapsed": 26.428,
|
||||||
|
"job_args": "",
|
||||||
|
"job_cwd": "",
|
||||||
|
"job_env": {},
|
||||||
|
"job_explanation": "",
|
||||||
|
"result_stdout": "stdout capture is missing",
|
||||||
|
"execution_node": "",
|
||||||
|
"result_traceback": "",
|
||||||
|
"workflow_job_template": 27,
|
||||||
|
"extra_vars": "{}"
|
||||||
|
}
|
||||||
@@ -0,0 +1,203 @@
|
|||||||
|
{
|
||||||
|
"name": "Workflow Job Detail",
|
||||||
|
"description": "# Retrieve Workflow Job:\n\nMake GET request to this resource to retrieve a single workflow job\nrecord containing the following fields:\n\n* `id`: Database ID for this workflow job. (integer)\n* `type`: Data type for this workflow job. (choice)\n* `url`: URL for this workflow job. (string)\n* `related`: Data structure with URLs of related resources. (object)\n* `summary_fields`: Data structure with name/description for related resources. (object)\n* `created`: Timestamp when this workflow job was created. (datetime)\n* `modified`: Timestamp when this workflow job was last modified. (datetime)\n* `name`: Name of this workflow job. (string)\n* `description`: Optional description of this workflow job. (string)\n* `unified_job_template`: (field)\n* `launch_type`: (choice)\n - `manual`: Manual\n - `relaunch`: Relaunch\n - `callback`: Callback\n - `scheduled`: Scheduled\n - `dependency`: Dependency\n - `workflow`: Workflow\n - `sync`: Sync\n* `status`: (choice)\n - `new`: New\n - `pending`: Pending\n - `waiting`: Waiting\n - `running`: Running\n - `successful`: Successful\n - `failed`: Failed\n - `error`: Error\n - `canceled`: Canceled\n* `failed`: (boolean)\n* `started`: The date and time the job was queued for starting. (datetime)\n* `finished`: The date and time the job finished execution. (datetime)\n* `elapsed`: Elapsed time in seconds that the job ran. (decimal)\n* `job_args`: (string)\n* `job_cwd`: (string)\n* `job_env`: (field)\n* `job_explanation`: A status field to indicate the state of the job if it wasn't able to run and capture stdout (string)\n* `result_stdout`: (field)\n* `execution_node`: The Tower node the job executed on. (string)\n* `result_traceback`: (string)\n* `workflow_job_template`: (field)\n* `extra_vars`: (string)\n\n\n\n# Delete Workflow Job:\n\nMake a DELETE request to this resource to delete this workflow job.\n\n\n\n\n\n\n\n\n\n\n\n> _New in Ansible Tower 3.1.0_",
|
||||||
|
"renders": [
|
||||||
|
"application/json",
|
||||||
|
"text/html"
|
||||||
|
],
|
||||||
|
"parses": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"actions": {
|
||||||
|
"GET": {
|
||||||
|
"id": {
|
||||||
|
"type": "integer",
|
||||||
|
"label": "ID",
|
||||||
|
"help_text": "Database ID for this workflow job."
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "choice",
|
||||||
|
"label": "Type",
|
||||||
|
"help_text": "Data type for this workflow job.",
|
||||||
|
"choices": [
|
||||||
|
[
|
||||||
|
"workflow_job",
|
||||||
|
"Workflow Job"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"type": "string",
|
||||||
|
"label": "Url",
|
||||||
|
"help_text": "URL for this workflow job."
|
||||||
|
},
|
||||||
|
"related": {
|
||||||
|
"type": "object",
|
||||||
|
"label": "Related",
|
||||||
|
"help_text": "Data structure with URLs of related resources."
|
||||||
|
},
|
||||||
|
"summary_fields": {
|
||||||
|
"type": "object",
|
||||||
|
"label": "Summary fields",
|
||||||
|
"help_text": "Data structure with name/description for related resources."
|
||||||
|
},
|
||||||
|
"created": {
|
||||||
|
"type": "datetime",
|
||||||
|
"label": "Created",
|
||||||
|
"help_text": "Timestamp when this workflow job was created."
|
||||||
|
},
|
||||||
|
"modified": {
|
||||||
|
"type": "datetime",
|
||||||
|
"label": "Modified",
|
||||||
|
"help_text": "Timestamp when this workflow job was last modified."
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"label": "Name",
|
||||||
|
"help_text": "Name of this workflow job."
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": "string",
|
||||||
|
"label": "Description",
|
||||||
|
"help_text": "Optional description of this workflow job."
|
||||||
|
},
|
||||||
|
"unified_job_template": {
|
||||||
|
"type": "field",
|
||||||
|
"label": "unified job template"
|
||||||
|
},
|
||||||
|
"launch_type": {
|
||||||
|
"type": "choice",
|
||||||
|
"label": "Launch type",
|
||||||
|
"choices": [
|
||||||
|
[
|
||||||
|
"manual",
|
||||||
|
"Manual"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"relaunch",
|
||||||
|
"Relaunch"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"callback",
|
||||||
|
"Callback"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"scheduled",
|
||||||
|
"Scheduled"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"dependency",
|
||||||
|
"Dependency"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"workflow",
|
||||||
|
"Workflow"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"sync",
|
||||||
|
"Sync"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"type": "choice",
|
||||||
|
"label": "Status",
|
||||||
|
"choices": [
|
||||||
|
[
|
||||||
|
"new",
|
||||||
|
"New"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"pending",
|
||||||
|
"Pending"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"waiting",
|
||||||
|
"Waiting"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"running",
|
||||||
|
"Running"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"successful",
|
||||||
|
"Successful"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"failed",
|
||||||
|
"Failed"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"error",
|
||||||
|
"Error"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"canceled",
|
||||||
|
"Canceled"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"failed": {
|
||||||
|
"type": "boolean",
|
||||||
|
"label": "Failed"
|
||||||
|
},
|
||||||
|
"started": {
|
||||||
|
"type": "datetime",
|
||||||
|
"label": "Started",
|
||||||
|
"help_text": "The date and time the job was queued for starting."
|
||||||
|
},
|
||||||
|
"finished": {
|
||||||
|
"type": "datetime",
|
||||||
|
"label": "Finished",
|
||||||
|
"help_text": "The date and time the job finished execution."
|
||||||
|
},
|
||||||
|
"elapsed": {
|
||||||
|
"type": "decimal",
|
||||||
|
"label": "Elapsed",
|
||||||
|
"help_text": "Elapsed time in seconds that the job ran."
|
||||||
|
},
|
||||||
|
"job_args": {
|
||||||
|
"type": "string",
|
||||||
|
"label": "Job args"
|
||||||
|
},
|
||||||
|
"job_cwd": {
|
||||||
|
"type": "string",
|
||||||
|
"label": "Job cwd"
|
||||||
|
},
|
||||||
|
"job_env": {
|
||||||
|
"type": "field",
|
||||||
|
"label": "job_env"
|
||||||
|
},
|
||||||
|
"job_explanation": {
|
||||||
|
"type": "string",
|
||||||
|
"label": "Job explanation",
|
||||||
|
"help_text": "A status field to indicate the state of the job if it wasn't able to run and capture stdout"
|
||||||
|
},
|
||||||
|
"result_stdout": {
|
||||||
|
"type": "field",
|
||||||
|
"label": "Result stdout"
|
||||||
|
},
|
||||||
|
"execution_node": {
|
||||||
|
"type": "string",
|
||||||
|
"label": "Execution node",
|
||||||
|
"help_text": "The Tower node the job executed on."
|
||||||
|
},
|
||||||
|
"result_traceback": {
|
||||||
|
"type": "string",
|
||||||
|
"label": "Result traceback"
|
||||||
|
},
|
||||||
|
"workflow_job_template": {
|
||||||
|
"type": "field",
|
||||||
|
"label": "Workflow job template"
|
||||||
|
},
|
||||||
|
"extra_vars": {
|
||||||
|
"type": "string",
|
||||||
|
"label": "Extra vars"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"added_in_version": "3.1.0",
|
||||||
|
"types": [
|
||||||
|
"workflow_job"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
'use strict';
|
||||||
|
import moment from 'moment';
|
||||||
|
import workflow_job_options_json from 'json!./data/workflow_job_options.json';
|
||||||
|
import workflow_job_json from 'json!./data/workflow_job.json';
|
||||||
|
|
||||||
|
describe('Controller: workflowResults', () => {
|
||||||
|
let $controller;
|
||||||
|
let workflowResults;
|
||||||
|
let $rootScope;
|
||||||
|
let ParseVariableString;
|
||||||
|
let workflowResultsService;
|
||||||
|
let $interval;
|
||||||
|
|
||||||
|
let treeData = {
|
||||||
|
data: {
|
||||||
|
children: []
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(angular.mock.module('VariablesHelper'));
|
||||||
|
|
||||||
|
beforeEach(angular.mock.module('workflowResults', ($provide) => {
|
||||||
|
['PromptDialog', 'Prompt', 'Wait', 'Rest', '$state', 'ProcessErrors',
|
||||||
|
'InitiatePlaybookRun', 'jobLabels', 'workflowNodes', 'count',
|
||||||
|
].forEach((item) => {
|
||||||
|
$provide.value(item, {});
|
||||||
|
});
|
||||||
|
$provide.value('$stateExtender', { addState: jasmine.createSpy('addState'), });
|
||||||
|
$provide.value('moment', moment);
|
||||||
|
$provide.value('workflowData', workflow_job_json);
|
||||||
|
$provide.value('workflowDataOptions', workflow_job_options_json);
|
||||||
|
$provide.value('ParseTypeChange', function() {});
|
||||||
|
$provide.value('i18n', { '_': (a) => { return a; } });
|
||||||
|
$provide.provider('$stateProvider', { '$get': function() { return function() {} } });
|
||||||
|
$provide.service('WorkflowService', function($q) {
|
||||||
|
return {
|
||||||
|
buildTree: function() {
|
||||||
|
var deferred = $q.defer();
|
||||||
|
deferred.resolve(treeData);
|
||||||
|
return deferred.promise;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(angular.mock.inject(function(_$controller_, _$rootScope_, _ParseVariableString_, _workflowResultsService_, _$interval_){
|
||||||
|
$controller = _$controller_;
|
||||||
|
$rootScope = _$rootScope_;
|
||||||
|
ParseVariableString = _ParseVariableString_;
|
||||||
|
workflowResultsService = _workflowResultsService_;
|
||||||
|
$interval = _$interval_;
|
||||||
|
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('elapsed timer', () => {
|
||||||
|
let scope;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
scope = $rootScope.$new();
|
||||||
|
spyOn(workflowResultsService, 'createOneSecondTimer').and.callThrough();
|
||||||
|
spyOn(workflowResultsService, 'destroyTimer').and.callThrough();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
function jobWaitingWorkflowResultsControllerFixture(started, status) {
|
||||||
|
workflow_job_json.started = started;
|
||||||
|
workflow_job_json.status = status;
|
||||||
|
workflowResults = $controller('workflowResultsController', {
|
||||||
|
$scope: scope,
|
||||||
|
$rootScope: $rootScope,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('init()', () => {
|
||||||
|
describe('job running', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
jobWaitingWorkflowResultsControllerFixture(moment(), 'running');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Note: Ensuring the outside service method is called to create a timer may
|
||||||
|
// be overkill. Especially since we validate the side effect in the next test.
|
||||||
|
it('should call to start timer on load when job is already running', () => {
|
||||||
|
expect(workflowResultsService.createOneSecondTimer).toHaveBeenCalled();
|
||||||
|
expect(workflowResultsService.createOneSecondTimer.calls.argsFor(0)[0]).toBe(workflow_job_json.started);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set update scope var with elapsed time', () => {
|
||||||
|
$interval.flush(10 * 1000);
|
||||||
|
|
||||||
|
// TODO: mock moment() so when we fast-forward time with $interval
|
||||||
|
// the system clocks seems to fast forward too.
|
||||||
|
//expect(scope.workflow.elapsed).toBe(10);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call to destroy timer on destroy', () => {
|
||||||
|
scope.$destroy();
|
||||||
|
expect(workflowResultsService.destroyTimer).toHaveBeenCalled();
|
||||||
|
expect(workflowResultsService.destroyTimer.calls.argsFor(0)[0]).not.toBe(null);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('job is not running', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
jobWaitingWorkflowResultsControllerFixture(null, 'waiting');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not start elapsed timer', () => {
|
||||||
|
expect(workflowResultsService.createOneSecondTimer).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('job transitions to running', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
jobWaitingWorkflowResultsControllerFixture(null, 'waiting');
|
||||||
|
$rootScope.$broadcast('ws-jobs', { unified_job_id: workflow_job_json.id, status: "running" });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should start elapsed timer', () => {
|
||||||
|
expect(scope.workflow.status).toBe("running");
|
||||||
|
expect(workflowResultsService.createOneSecondTimer).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('job finished', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
jobWaitingWorkflowResultsControllerFixture(null, 'waiting');
|
||||||
|
$rootScope.$broadcast('ws-jobs', { unified_job_id: workflow_job_json.id, status: "running" });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should start elapsed timer', () => {
|
||||||
|
expect(scope.workflow.status).toBe("running");
|
||||||
|
expect(workflowResultsService.createOneSecondTimer).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
'use strict';
|
||||||
|
import moment from 'moment';
|
||||||
|
|
||||||
|
describe('workflowResultsService', () => {
|
||||||
|
let workflowResultsService;
|
||||||
|
let $interval;
|
||||||
|
|
||||||
|
beforeEach(angular.mock.module('workflowResults', ($provide) => {
|
||||||
|
['PromptDialog', 'Prompt', 'Wait', 'Rest', 'ProcessErrors', 'InitiatePlaybookRun', '$state'].forEach(function(item) {
|
||||||
|
$provide.value(item, {});
|
||||||
|
});
|
||||||
|
$provide.value('$stateExtender', { addState: jasmine.createSpy('addState'), });
|
||||||
|
$provide.value('moment', moment);
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(angular.mock.inject((_workflowResultsService_, _$interval_) => {
|
||||||
|
workflowResultsService = _workflowResultsService_;
|
||||||
|
$interval = _$interval_;
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('createOneSecondTimer()', () => {
|
||||||
|
it('should create a timer that runs every second, incremented by a second', (done) => {
|
||||||
|
let ticks = 0;
|
||||||
|
let ticks_expected = 10;
|
||||||
|
|
||||||
|
workflowResultsService.createOneSecondTimer(moment(), function(time) {
|
||||||
|
ticks += 1;
|
||||||
|
if (ticks >= ticks_expected) {
|
||||||
|
expect(ticks).toBe(ticks_expected);
|
||||||
|
// TODO: should verify time is 10 but this requires mocking moment()
|
||||||
|
// because we "artificially" accelerate time.
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$interval.flush(ticks_expected * 1000);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('destroyTimer()', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
$interval.cancel = jasmine.createSpy('cancel');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not destroy null timer', () => {
|
||||||
|
workflowResultsService.destroyTimer(null);
|
||||||
|
|
||||||
|
expect($interval.cancel).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should destroy passed in timer', () => {
|
||||||
|
let timer = jasmine.createSpy('timer');
|
||||||
|
|
||||||
|
workflowResultsService.destroyTimer(timer);
|
||||||
|
|
||||||
|
expect($interval.cancel).toHaveBeenCalledWith(timer);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user