You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by at...@apache.org on 2017/06/07 16:23:27 UTC
ambari git commit: AMBARI-21194 Integrate background operations with
websocket events. (atkach)
Repository: ambari
Updated Branches:
refs/heads/branch-3.0-perf c2ab4a3ce -> b1d357ad1
AMBARI-21194 Integrate background operations with websocket events. (atkach)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/b1d357ad
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/b1d357ad
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/b1d357ad
Branch: refs/heads/branch-3.0-perf
Commit: b1d357ad11c7e4ac23aa61e7a446bd94030b8f44
Parents: c2ab4a3
Author: Andrii Tkach <at...@apache.org>
Authored: Wed Jun 7 19:03:50 2017 +0300
Committer: Andrii Tkach <at...@apache.org>
Committed: Wed Jun 7 19:03:50 2017 +0300
----------------------------------------------------------------------
.../global/background_operations_controller.js | 196 ++++++--
.../app/controllers/main/admin/kerberos.js | 4 +-
ambari-web/app/controllers/main/service.js | 6 +-
ambari-web/app/templates/application.hbs | 4 +-
ambari-web/app/utils/host_progress_popup.js | 2 +-
.../global/background_operations_test.js | 485 +++++++++++--------
.../test/controllers/main/service_test.js | 2 +-
7 files changed, 437 insertions(+), 262 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/b1d357ad/ambari-web/app/controllers/global/background_operations_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/global/background_operations_controller.js b/ambari-web/app/controllers/global/background_operations_controller.js
index d833661..8be7b87 100644
--- a/ambari-web/app/controllers/global/background_operations_controller.js
+++ b/ambari-web/app/controllers/global/background_operations_controller.js
@@ -26,18 +26,21 @@ App.BackgroundOperationsController = Em.Controller.extend({
*/
isWorking : false,
- allOperationsCount : 0,
+ runningOperationsCount : function() {
+ return this.get('services').filterProperty('isRunning').length;
+ }.property('services.@each.isRunning'),
/**
- * For host component popup
+ * List of requests
*/
- services:[],
+ services: Em.A([]),
serviceTimestamp: null,
/**
* Number of operation to load
*/
operationsCount: 10,
+
/**
* Possible levels:
* REQUESTS_LIST
@@ -51,15 +54,125 @@ App.BackgroundOperationsController = Em.Controller.extend({
taskId: null
}),
+ handleRequestsUpdates: function () {
+ if (this.get('isWorking')) {
+ this.requestMostRecent(() => {
+ App.StompClient.subscribe('/events/requests', this.updateRequests.bind(this));
+ });
+ } else {
+ App.StompClient.unsubscribe('/events/requests');
+ }
+ }.observes('isWorking'),
+
+ updateRequests: function(event) {
+ const request = this.get('services').findProperty('id', event.requestId);
+ const context = this.parseRequestContext(event.requestContext);
+ const visibleOperationsCount = this.get('operationsCount');
+ const map = this.generateTasksMapOfRequest(event, request);
+ const updatedState = {
+ progress: Math.floor(event.progressPercent),
+ status: event.requestStatus,
+ isRunning: this.isRunning(event.requestStatus),
+ startTime: App.dateTimeWithTimeZone(event.startTime),
+ endTime: event.endTime > 0 ? App.dateTimeWithTimeZone(event.endTime) : event.endTime,
+ previousTaskStatusMap: map.currentTaskStatusMap,
+ hostsMap: map.hostsMap
+ };
+
+ if (request) {
+ request.setProperties(updatedState);
+ } else {
+ this.get('services').unshift(Em.Object.create(updatedState, {
+ id: event.requestId,
+ name: context.requestContext,
+ displayName: context.requestContext,
+ tasks: event.Tasks
+ }));
+ if (this.get('services').length >= visibleOperationsCount) {
+ this.set('isShowMoreAvailable', true);
+ this.get('services').pop();
+ }
+ }
+ this.set('serviceTimestamp', App.dateTime());
+ this.propertyDidChange('services');
+ },
+
/**
- * Start polling, when <code>isWorking</code> become true
+ *
+ * @param {object} event
+ * @param {Em.Object} request
+ * @returns {{}}
*/
- startPolling: function(){
- if(this.get('isWorking')){
- this.requestMostRecent();
- App.updater.run(this, 'requestMostRecent', 'isWorking', App.bgOperationsUpdateInterval);
+ generateTasksMapOfRequest: function(event, request) {
+ const hostsMap = request ? request.get('hostsMap') : {};
+ const previousTaskStatusMap = request ? request.get('previousTaskStatusMap') : {};
+ const currentTaskStatusMap = {};
+ event.Tasks.forEach((task) => {
+ const host = hostsMap[task.hostName];
+ if (host) {
+ const existedTask = host.logTasks.findProperty('Tasks.id', task.id);
+ if (existedTask) {
+ existedTask.Tasks.status = task.status;
+ } else {
+ host.logTasks.push(this.convertTaskFromEventToApi(task));
+ }
+ host.isModified = (host.isModified) ? true : previousTaskStatusMap[task.id] !== task.status;
+ } else {
+ hostsMap[task.hostName] = {
+ name: task.hostName,
+ publicName: task.hostName,
+ logTasks: [this.convertTaskFromEventToApi(task)],
+ isModified: previousTaskStatusMap[task.id] !== task.status
+ };
+ }
+ currentTaskStatusMap[task.id] = task.status;
+ }, this);
+ return {
+ currentTaskStatusMap,
+ hostsMap
}
- }.observes('isWorking'),
+ },
+
+ convertTaskFromEventToApi: function(task) {
+ return {
+ Tasks: {
+ status: task.status,
+ host_name: task.hostName,
+ id: task.id,
+ request_id: task.requestId
+ }
+ }
+ },
+
+ handleTaskUpdates: function() {
+ const levelInfo = this.get('levelInfo');
+ if (!levelInfo.get('requestId') || !levelInfo.get('taskId')) {
+ return;
+ }
+ const request = this.get('services').findProperty('id', levelInfo.get('requestId'));
+ const taskStatus = request.get('previousTaskStatusMap')[levelInfo.get('taskId')];
+ if (levelInfo.get('name') === 'TASK_DETAILS' && !this.isFinished(taskStatus)) {
+ App.StompClient.subscribe(`/events/tasks/${levelInfo.get('taskId')}`, (updatedTask) => {
+ this.updateTask(updatedTask);
+ if (this.isFinished(updatedTask.status)) {
+ App.StompClient.unsubscribe(`/events/tasks/${updatedTask.id}`);
+ }
+ });
+ }
+ }.observes('levelInfo.name'),
+
+ updateTask: function(updatedTask) {
+ const request = this.get('services').findProperty('id', updatedTask.requestId);
+ const host = request.get('hostsMap')[updatedTask.hostName];
+ const task = host.logTasks.findProperty('Tasks.id', updatedTask.id);
+ task.Tasks.status = updatedTask.status;
+ task.Tasks.stdout = updatedTask.stdout;
+ task.Tasks.stderr = updatedTask.stderr;
+ task.Tasks.structured_out = updatedTask.structured_out;
+ task.Tasks.output_log = updatedTask.outLog;
+ task.Tasks.error_log = updatedTask.errorLog;
+ this.set('serviceTimestamp', App.dateTime());
+ },
/**
* Get requests data from server
@@ -103,7 +216,7 @@ App.BackgroundOperationsController = Em.Controller.extend({
'operationsCount': count
}
};
- if (levelInfo.get('name') === 'TASK_DETAILS' && !App.get('testMode')) {
+ if (levelInfo.get('name') === 'TASK_DETAILS') {
result.name = 'background_operations.get_by_task';
result.successCallback = 'callBackFilteredByTask';
result.data = {
@@ -123,10 +236,8 @@ App.BackgroundOperationsController = Em.Controller.extend({
/**
* Push hosts and their tasks to request
* @param data
- * @param ajaxQuery
- * @param params
*/
- callBackFilteredByRequest: function (data, ajaxQuery, params) {
+ callBackFilteredByRequest: function (data) {
var requestId = data.Requests.id;
var requestInputs = data.Requests.inputs;
var request = this.get('services').findProperty('id', requestId);
@@ -150,16 +261,6 @@ App.BackgroundOperationsController = Em.Controller.extend({
}
currentTaskStatusMap[task.Tasks.id] = task.Tasks.status;
}, this);
- /**
- * sync up request progress with up to date progress of hosts on Host's list,
- * to avoid discrepancies while waiting for response with latest progress of request
- * after switching to operation's list
- */
- if (request.get('isRunning')) {
- request.set('progress', App.HostPopup.getProgress(data.tasks));
- request.set('status', App.HostPopup.getStatus(data.tasks)[0]);
- request.set('isRunning', request.get('progress') !== 100);
- }
request.set('previousTaskStatusMap', currentTaskStatusMap);
request.set('hostsMap', hostsMap);
this.set('serviceTimestamp', App.dateTime());
@@ -203,7 +304,6 @@ App.BackgroundOperationsController = Em.Controller.extend({
* @param data
*/
callBackForMostRecent: function (data) {
- var runningServices = 0;
var currentRequestIds = [];
var countIssued = this.get('operationsCount');
var countGot = data.itemTotal;
@@ -211,37 +311,33 @@ App.BackgroundOperationsController = Em.Controller.extend({
data.items.forEach(function (request) {
if (this.isUpgradeRequest(request)) {
- if (!App.get('upgradeIsRunning') && !App.get('testMode')) {
+ if (!App.get('upgradeIsRunning')) {
restoreUpgradeState = true;
}
return;
}
var rq = this.get("services").findProperty('id', request.Requests.id);
- var isRunning = this.isRequestRunning(request);
+ var isRunning = this.isRunning(request.Requests.request_status);
var requestParams = this.parseRequestContext(request.Requests.request_context);
+ const requestState = {
+ progress: Math.floor(request.Requests.progress_percent),
+ status: request.Requests.request_status,
+ isRunning: isRunning,
+ startTime: App.dateTimeWithTimeZone(request.Requests.start_time),
+ endTime: request.Requests.end_time > 0 ? App.dateTimeWithTimeZone(request.Requests.end_time) : request.Requests.end_time
+ };
this.assignScheduleId(request, requestParams);
currentRequestIds.push(request.Requests.id);
if (rq) {
- rq.setProperties({
- progress: Math.floor(request.Requests.progress_percent),
- status: request.Requests.request_status,
- isRunning: isRunning,
- startTime: App.dateTimeWithTimeZone(request.Requests.start_time),
- endTime: request.Requests.end_time > 0 ? App.dateTimeWithTimeZone(request.Requests.end_time) : request.Requests.end_time
- });
+ rq.setProperties(requestState);
} else {
- rq = Em.Object.create({
+ rq = Em.Object.create(requestState, {
id: request.Requests.id,
name: requestParams.requestContext,
displayName: requestParams.requestContext,
- progress: Math.floor(request.Requests.progress_percent),
- status: request.Requests.request_status,
- isRunning: isRunning,
hostsMap: {},
tasks: [],
- startTime: App.dateTimeWithTimeZone(request.Requests.start_time),
- endTime: request.Requests.end_time > 0 ? App.dateTimeWithTimeZone(request.Requests.end_time) : request.Requests.end_time,
dependentService: requestParams.dependentService,
sourceRequestScheduleId: request.Requests.request_schedule && request.Requests.request_schedule.schedule_id,
previousTaskStatusMap: {},
@@ -251,13 +347,11 @@ App.BackgroundOperationsController = Em.Controller.extend({
//To sort DESC by request id
this.set("services", this.get("services").sortProperty('id').reverse());
}
- runningServices += ~~isRunning;
}, this);
if (restoreUpgradeState) {
App.router.get('clusterController').restoreUpgradeState();
}
this.removeOldRequests(currentRequestIds);
- this.set("allOperationsCount", runningServices);
this.set('isShowMoreAvailable', countGot >= countIssued);
this.set('serviceTimestamp', App.dateTimeWithTimeZone());
},
@@ -282,15 +376,23 @@ App.BackgroundOperationsController = Em.Controller.extend({
},
/**
- * identify whether request is running by task counters
- * @param request
+ * identify whether request or task is running by status
+ * @param status
* @return {Boolean}
*/
- isRequestRunning: function (request) {
- return (request.Requests.task_count -
- (request.Requests.aborted_task_count + request.Requests.completed_task_count + request.Requests.failed_task_count
- + request.Requests.timed_out_task_count - request.Requests.queued_task_count)) > 0;
+ isRunning: function (status) {
+ return ['IN_PROGRESS', 'QUEUED', 'PENDING'].contains(status);
},
+
+ /**
+ * identify whether request or task is finished by status
+ * @param status
+ * @return {Boolean}
+ */
+ isFinished: function (status) {
+ return ['FAILED', 'ABORTED', 'COMPLETED'].contains(status);
+ },
+
/**
* identify whether there is only one host in request
* @param inputs
http://git-wip-us.apache.org/repos/asf/ambari/blob/b1d357ad/ambari-web/app/controllers/main/admin/kerberos.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/admin/kerberos.js b/ambari-web/app/controllers/main/admin/kerberos.js
index 564fb35..1b94758 100644
--- a/ambari-web/app/controllers/main/admin/kerberos.js
+++ b/ambari-web/app/controllers/main/admin/kerberos.js
@@ -215,13 +215,13 @@ App.MainAdminKerberosController = App.KerberosWizardStep4Controller.extend({
* @return {$.ajax}
*/
restartAllServices: function () {
- if (!App.router.get('backgroundOperationsController.allOperationsCount')) {
+ if (!App.router.get('backgroundOperationsController.runningOperationsCount')) {
if (this.get('needsRestartAfterRegenerate')) {
this.set('needsRestartAfterRegenerate', false);
App.router.get('mainServiceController').restartAllServices();
}
}
- }.observes('controllers.backgroundOperationsController.allOperationsCount'),
+ }.observes('controllers.backgroundOperationsController.runningOperationsCount'),
/**
* performs cluster check before kerbefos security
http://git-wip-us.apache.org/repos/asf/ambari/blob/b1d357ad/ambari-web/app/controllers/main/service.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/service.js b/ambari-web/app/controllers/main/service.js
index eb9df0d..983e8b4 100644
--- a/ambari-web/app/controllers/main/service.js
+++ b/ambari-web/app/controllers/main/service.js
@@ -93,7 +93,7 @@ App.MainServiceController = Em.ArrayController.extend(App.SupportClientConfigsDo
/**
* @type {bool}
*/
- isStartStopAllClicked: Em.computed.notEqual('App.router.backgroundOperationsController.allOperationsCount', 0),
+ isStartStopAllClicked: Em.computed.notEqual('App.router.backgroundOperationsController.runningOperationsCount', 0),
/**
* Callback for <code>start all service</code> button
@@ -234,7 +234,7 @@ App.MainServiceController = Em.ArrayController.extend(App.SupportClientConfigsDo
*/
silentStartAllServices: function () {
if (
- !App.router.get('backgroundOperationsController').get('allOperationsCount')
+ !App.router.get('backgroundOperationsController').get('runningOperationsCount')
&& this.get('shouldStart')
&& !this.isStopAllServicesFailed()
) {
@@ -252,7 +252,7 @@ App.MainServiceController = Em.ArrayController.extend(App.SupportClientConfigsDo
showLoadingPopup: true
});
}
- }.observes('shouldStart', 'controllers.backgroundOperationsController.allOperationsCount'),
+ }.observes('shouldStart', 'controllers.backgroundOperationsController.runningOperationsCount'),
/**
* Success callback for silent start
http://git-wip-us.apache.org/repos/asf/ambari/blob/b1d357ad/ambari-web/app/templates/application.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/application.hbs b/ambari-web/app/templates/application.hbs
index 03c47db..e56232c 100644
--- a/ambari-web/app/templates/application.hbs
+++ b/ambari-web/app/templates/application.hbs
@@ -127,8 +127,8 @@
<a href="#" class="bg-label" {{action "showPopup" target="App.router.backgroundOperationsController"}}>
{{#with App.router.backgroundOperationsController}}
<span class="glyphicon glyphicon-cog"></span>
- <span id="span-bg-operation-count" {{bindAttr class="allOperationsCount:operations-count :numberCircle"}}>
- {{allOperationsCount}}
+ <span id="span-bg-operation-count" {{bindAttr class="runningOperationsCount:operations-count :numberCircle"}}>
+ {{runningOperationsCount}}
</span>
{{/with}}
</a>
http://git-wip-us.apache.org/repos/asf/ambari/blob/b1d357ad/ambari-web/app/utils/host_progress_popup.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/host_progress_popup.js b/ambari-web/app/utils/host_progress_popup.js
index c615cae..b5715db 100644
--- a/ambari-web/app/utils/host_progress_popup.js
+++ b/ambari-web/app/utils/host_progress_popup.js
@@ -425,7 +425,7 @@ App.HostPopup = Em.Object.create({
*/
setBackgroundOperationHeader: function (isServiceListHidden) {
if (this.get('isBackgroundOperations') && !isServiceListHidden) {
- var numRunning = App.router.get('backgroundOperationsController.allOperationsCount');
+ var numRunning = App.router.get('backgroundOperationsController.runningOperationsCount');
this.set("popupHeaderName", numRunning + Em.I18n.t('hostPopup.header.postFix').format(numRunning === 1 ? "" : "s"));
}
},
http://git-wip-us.apache.org/repos/asf/ambari/blob/b1d357ad/ambari-web/test/controllers/global/background_operations_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/global/background_operations_test.js b/ambari-web/test/controllers/global/background_operations_test.js
index 8d982bb..8f0c79e 100644
--- a/ambari-web/test/controllers/global/background_operations_test.js
+++ b/ambari-web/test/controllers/global/background_operations_test.js
@@ -112,6 +112,10 @@ describe('App.BackgroundOperationsController', function () {
tests.forEach(function (test) {
it(test.m, function () {
controller.set('levelInfo', test.levelInfo);
+ controller.set('services', [Em.Object.create({
+ id: 1,
+ previousTaskStatusMap: {}
+ })]);
var r = controller.getQueryParams();
expect(r.name).to.equal(test.e.name);
expect(r.successCallback).to.equal(test.e.successCallback);
@@ -120,27 +124,6 @@ describe('App.BackgroundOperationsController', function () {
});
});
- describe('#startPolling()', function () {
-
- beforeEach(function () {
- sinon.spy(controller, 'requestMostRecent');
- });
- afterEach(function () {
- controller.requestMostRecent.restore();
- });
-
- it('isWorking = false', function () {
- controller.set('isWorking', false);
- expect(App.updater.run.calledOnce).to.equal(false);
- expect(controller.requestMostRecent.calledOnce).to.equal(false);
- });
- it('isWorking = true', function () {
- controller.set('isWorking', true);
- expect(App.updater.run.calledOnce).to.equal(true);
- expect(controller.requestMostRecent.calledOnce).to.equal(true);
- });
- });
-
describe('#isUpgradeRequest', function() {
it('defines if request is upgrade task (true)', function() {
@@ -179,7 +162,7 @@ describe('App.BackgroundOperationsController', function () {
items: []
};
controller.callBackForMostRecent(data);
- expect(controller.get("allOperationsCount")).to.equal(0);
+ expect(controller.get("runningOperationsCount")).to.equal(0);
expect(controller.get("services.length")).to.equal(0);
});
it('One non-running request', function () {
@@ -200,7 +183,7 @@ describe('App.BackgroundOperationsController', function () {
]
};
controller.callBackForMostRecent(data);
- expect(controller.get("allOperationsCount")).to.equal(0);
+ expect(controller.get("runningOperationsCount")).to.equal(0);
expect(controller.get("services").mapProperty('id')).to.eql([1]);
});
@@ -216,7 +199,7 @@ describe('App.BackgroundOperationsController', function () {
]
};
controller.callBackForMostRecent(data);
- expect(controller.get("allOperationsCount")).to.equal(0);
+ expect(controller.get("runningOperationsCount")).to.equal(0);
expect(controller.get("services").mapProperty('id')).to.eql([]);
});
@@ -227,18 +210,13 @@ describe('App.BackgroundOperationsController', function () {
Requests: {
id: 1,
request_context: '',
- task_count: 1,
- aborted_task_count: 0,
- completed_task_count: 0,
- failed_task_count: 0,
- timed_out_task_count: 0,
- queued_task_count: 0
+ request_status: 'IN_PROGRESS'
}
}
]
};
controller.callBackForMostRecent(data);
- expect(controller.get("allOperationsCount")).to.equal(1);
+ expect(controller.get("runningOperationsCount")).to.equal(1);
expect(controller.get("services").mapProperty('id')).to.eql([1]);
});
it('Two requests in order', function () {
@@ -259,7 +237,7 @@ describe('App.BackgroundOperationsController', function () {
]
};
controller.callBackForMostRecent(data);
- expect(controller.get("allOperationsCount")).to.equal(0);
+ expect(controller.get("runningOperationsCount")).to.equal(0);
expect(controller.get("services").mapProperty('id')).to.eql([2, 1]);
});
});
@@ -331,179 +309,7 @@ describe('App.BackgroundOperationsController', function () {
it(test.title, function () {
controller.set('services', test.content.services);
controller.removeOldRequests(test.content.currentRequestIds);
- expect(controller.get('services')).to.eql(test.result);
- });
- });
- });
-
- describe('#isRequestRunning()', function () {
- var testCases = [
- {
- title: 'Counters are missing',
- request: {
- Requests: {}
- },
- result: false
- },
- {
- title: 'Request has zero tasks',
- request: {
- Requests: {
- task_count: 0,
- aborted_task_count: 0,
- completed_task_count: 0,
- failed_task_count: 0,
- timed_out_task_count: 0,
- queued_task_count: 0
- }
- },
- result: false
- },
- {
- title: 'One task in running status',
- request: {
- Requests: {
- task_count: 1,
- aborted_task_count: 0,
- completed_task_count: 0,
- failed_task_count: 0,
- timed_out_task_count: 0,
- queued_task_count: 0
- }
- },
- result: true
- },
- {
- title: 'One task in queued status',
- request: {
- Requests: {
- task_count: 1,
- aborted_task_count: 0,
- completed_task_count: 0,
- failed_task_count: 0,
- timed_out_task_count: 0,
- queued_task_count: 1
- }
- },
- result: true
- },
- {
- title: 'One task in aborted status',
- request: {
- Requests: {
- task_count: 1,
- aborted_task_count: 1,
- completed_task_count: 0,
- failed_task_count: 0,
- timed_out_task_count: 0,
- queued_task_count: 0
- }
- },
- result: false
- },
- {
- title: 'One task in completed status',
- request: {
- Requests: {
- task_count: 1,
- aborted_task_count: 0,
- completed_task_count: 1,
- failed_task_count: 0,
- timed_out_task_count: 0,
- queued_task_count: 0
- }
- },
- result: false
- },
- {
- title: 'One task in failed status',
- request: {
- Requests: {
- task_count: 1,
- aborted_task_count: 0,
- completed_task_count: 0,
- failed_task_count: 1,
- timed_out_task_count: 0,
- queued_task_count: 0
- }
- },
- result: false
- },
- {
- title: 'One task in timed out status',
- request: {
- Requests: {
- task_count: 1,
- aborted_task_count: 0,
- completed_task_count: 0,
- failed_task_count: 0,
- timed_out_task_count: 1,
- queued_task_count: 0
- }
- },
- result: false
- },
- {
- title: 'One task in timed out status and the second one in running',
- request: {
- Requests: {
- task_count: 2,
- aborted_task_count: 0,
- completed_task_count: 0,
- failed_task_count: 0,
- timed_out_task_count: 1,
- queued_task_count: 0
- }
- },
- result: true
- },
- {
- title: 'One task in each status',
- request: {
- Requests: {
- task_count: 5,
- aborted_task_count: 1,
- completed_task_count: 1,
- failed_task_count: 1,
- timed_out_task_count: 1,
- queued_task_count: 1
- }
- },
- result: true
- },
- {
- title: 'One task in each status except queued',
- request: {
- Requests: {
- task_count: 5,
- aborted_task_count: 1,
- completed_task_count: 1,
- failed_task_count: 1,
- timed_out_task_count: 1,
- queued_task_count: 0
- }
- },
- result: true
- },
- {
- title: 'No tasks in running status',
- request: {
- Requests: {
- task_count: 4,
- aborted_task_count: 1,
- completed_task_count: 1,
- failed_task_count: 1,
- timed_out_task_count: 1,
- queued_task_count: 0
- }
- },
- result: false
- }
- ];
-
- testCases.forEach(function (test) {
- it(test.title, function () {
- expect(controller.isRequestRunning(test.request)).to.eql(test.result);
+ expect(JSON.stringify(controller.get('services'))).to.equal(JSON.stringify(test.result));
});
});
});
@@ -674,7 +480,6 @@ describe('App.BackgroundOperationsController', function () {
controller.callBackFilteredByRequest(data);
expect(request.get('previousTaskStatusMap')).to.eql({"1": "COMPLETED"});
expect(request.get('hostsMap.host1.logTasks.length')).to.equal(1);
- expect(request.get('isRunning')).to.equal(false);
});
it('request has one completed task and one running task', function () {
@@ -939,4 +744,272 @@ describe('App.BackgroundOperationsController', function () {
expect(controller.get('operationsCount')).to.be.equal(10);
});
});
+
+ describe('#handleRequestsUpdates', function() {
+ beforeEach(function() {
+ sinon.stub(controller, 'requestMostRecent', Em.clb);
+ sinon.stub(App.StompClient, 'subscribe');
+ sinon.stub(App.StompClient, 'unsubscribe');
+ });
+ afterEach(function() {
+ controller.requestMostRecent.restore();
+ App.StompClient.subscribe.restore();
+ App.StompClient.unsubscribe.restore();
+ });
+
+ it('App.StompClient.subscribe should be called', function() {
+ controller.set('isWorking', true);
+ expect(App.StompClient.subscribe.calledWith('/events/requests')).to.be.true;
+ });
+
+ it('App.StompClient.unsubscribe should be called', function() {
+ controller.set('isWorking', false);
+ expect(App.StompClient.unsubscribe.calledWith('/events/requests')).to.be.true;
+ });
+ });
+
+ describe('#updateRequests', function() {
+ beforeEach(function() {
+ sinon.stub(controller, 'parseRequestContext').returns({
+ requestContext: 'r1'
+ });
+ sinon.stub(controller, 'generateTasksMapOfRequest').returns({
+ currentTaskStatusMap: {},
+ hostsMap: {}
+ });
+ sinon.stub(controller, 'propertyDidChange');
+ });
+ afterEach(function() {
+ controller.parseRequestContext.restore();
+ controller.generateTasksMapOfRequest.restore();
+ controller.propertyDidChange.restore();
+ });
+
+ it('should add request to list', function() {
+ controller.set('services', []);
+ controller.updateRequests({
+ progressPercent: 0,
+ requestStatus: 'PENDING',
+ startTime: 1,
+ endTime: -1,
+ requestId: 1,
+ requestContext: '',
+ Tasks: []
+ });
+ expect(controller.get('services').objectAt(0)).to.be.eql(Em.Object.create({
+ id: 1,
+ name: 'r1',
+ displayName: 'r1',
+ tasks: [],
+ progress: 0,
+ status: 'PENDING',
+ isRunning: true,
+ startTime: 1,
+ endTime: -1,
+ previousTaskStatusMap: {},
+ hostsMap: {}
+ }));
+ expect(controller.propertyDidChange.calledWith('services')).to.be.true;
+ });
+
+ it('should update request status', function() {
+ controller.set('services', [Em.Object.create({
+ id: 1,
+ name: 'r1',
+ displayName: 'r1',
+ tasks: [],
+ progress: 0,
+ status: 'PENDING',
+ isRunning: true,
+ startTime: 1,
+ endTime: -1,
+ previousTaskStatusMap: {},
+ hostsMap: {}
+ })]);
+ controller.updateRequests({
+ progressPercent: 100,
+ requestStatus: 'COMPLETED',
+ startTime: 1,
+ endTime: 1,
+ requestId: 1,
+ requestContext: '',
+ Tasks: []
+ });
+ expect(controller.get('services').objectAt(0)).to.be.eql(Em.Object.create({
+ id: 1,
+ name: 'r1',
+ displayName: 'r1',
+ tasks: [],
+ progress: 100,
+ status: 'COMPLETED',
+ isRunning: false,
+ startTime: 1,
+ endTime: 1,
+ previousTaskStatusMap: {},
+ hostsMap: {}
+ }))
+ });
+ });
+
+ describe('#generateTasksMapOfRequest', function() {
+
+ it('should return tasks map', function() {
+ var event = {
+ Tasks: [
+ {
+ hostName: 'host1',
+ id: 1,
+ status: 'PENDING',
+ requestId: 1
+ },
+ {
+ hostName: 'host1',
+ id: 2,
+ status: 'PENDING',
+ requestId: 1
+ },
+ {
+ hostName: 'host2',
+ id: 3,
+ status: 'COMPLETED',
+ requestId: 1
+ }
+ ]
+ };
+ expect(JSON.stringify(controller.generateTasksMapOfRequest(event, null).hostsMap)).to.be.equal(JSON.stringify({
+ "host1": {
+ "name": "host1",
+ "publicName": "host1",
+ "logTasks": [
+ {
+ "Tasks": {
+ "status": "PENDING",
+ "host_name": "host1",
+ "id": 1,
+ "request_id": 1
+ }
+ },
+ {
+ "Tasks": {
+ "status": "PENDING",
+ "host_name": "host1",
+ "id": 2,
+ "request_id": 1
+ }
+ }
+ ],
+ "isModified": true
+ },
+ "host2": {
+ "name": "host2",
+ "publicName": "host2",
+ "logTasks": [{"Tasks": {"status": "COMPLETED", "host_name": "host2", "id": 3, "request_id": 1}}],
+ "isModified": true
+ }
+ }));
+ expect(controller.generateTasksMapOfRequest(event, null).currentTaskStatusMap).to.be.eql({
+ "1": "PENDING",
+ "2": "PENDING",
+ "3": "COMPLETED"
+ });
+ });
+ });
+
+ describe('#convertTaskFromEventToApi', function() {
+
+ it('should return converted task object', function() {
+ expect(controller.convertTaskFromEventToApi({
+ status: 'PENDING',
+ hostName: 'host1',
+ id: 1,
+ requestId: 1
+ })).to.be.eql({
+ Tasks: {
+ status: 'PENDING',
+ host_name: 'host1',
+ id: 1,
+ request_id: 1
+ }
+ });
+ });
+ });
+
+ describe('#handleTaskUpdates', function() {
+ beforeEach(function() {
+ sinon.stub(controller, 'updateTask');
+ sinon.stub(App.StompClient, 'subscribe', function(arg1, clb) {
+ clb({status: 'COMPLETED', id: 1});
+ });
+ sinon.stub(App.StompClient, 'unsubscribe');
+ });
+ afterEach(function() {
+ controller.updateTask.restore();
+ App.StompClient.subscribe.restore();
+ App.StompClient.unsubscribe.restore();
+ });
+
+ it('should subscribe and when task is finished unsubscribe', function() {
+ controller.set('services', [Em.Object.create({
+ id: 1,
+ previousTaskStatusMap: {
+ 1: 'PENDING'
+ }
+ })]);
+ controller.set('levelInfo', Em.Object.create({
+ name: 'TASK_DETAILS',
+ requestId: 1,
+ taskId: 1
+ }));
+ expect(App.StompClient.subscribe.calledWith('/events/tasks/1')).to.be.true;
+ expect(controller.updateTask.calledOnce).to.be.true;
+ expect(App.StompClient.unsubscribe.calledWith('/events/tasks/1')).to.be.true;
+ });
+ });
+
+ describe('#updateTask', function() {
+
+ it('should update task properties', function() {
+ var event = {
+ requestId: 1,
+ id: 1,
+ hostName: 'host1',
+ status: 'COMPLETED',
+ stdout: 'stdout',
+ stderr: 'stderr',
+ structured_out: 'structured_out',
+ outLog: 'outLog',
+ errorLog: 'errorLog'
+ };
+ controller.set('services', [Em.Object.create({
+ id: 1,
+ hostsMap: {
+ host1: {
+ logTasks: [
+ {
+ Tasks: {
+ id: 1,
+ requestId: 1,
+ hostName: 'host1'
+ }
+ }
+ ]
+ }
+ }
+ })]);
+ controller.updateTask(event);
+ expect(controller.get('services').objectAt(0).get('hostsMap')['host1'].logTasks[0]).to.be.eql({
+ Tasks: {
+ requestId: 1,
+ id: 1,
+ hostName: 'host1',
+ status: 'COMPLETED',
+ stdout: 'stdout',
+ stderr: 'stderr',
+ structured_out: 'structured_out',
+ output_log: 'outLog',
+ error_log: 'errorLog'
+ }
+ });
+ });
+ });
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/b1d357ad/ambari-web/test/controllers/main/service_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/service_test.js b/ambari-web/test/controllers/main/service_test.js
index 7ed7641..869b06f 100644
--- a/ambari-web/test/controllers/main/service_test.js
+++ b/ambari-web/test/controllers/main/service_test.js
@@ -87,7 +87,7 @@ describe('App.MainServiceController', function () {
mainServiceController.destroy();
});
- App.TestAliases.testAsComputedNotEqual(getController(), 'isStartStopAllClicked', 'App.router.backgroundOperationsController.allOperationsCount', 0);
+ App.TestAliases.testAsComputedNotEqual(getController(), 'isStartStopAllClicked', 'App.router.backgroundOperationsController.runningOperationsCount', 0);
describe('#isStartAllDisabled', function () {
tests.forEach(function (test) {