浏览代码

AMBARI-7689 Unit tests for controllers of component reassign. (atkach)

atkach 10 年之前
父节点
当前提交
48ede6cfce

+ 1 - 0
ambari-web/app/assets/test/tests.js

@@ -74,6 +74,7 @@ var files = ['test/init_model_test',
   'test/controllers/main/service/reassign_controller_test',
   'test/controllers/main/service/reassign_controller_test',
   'test/controllers/main/service/reassign/step2_controller_test',
   'test/controllers/main/service/reassign/step2_controller_test',
   'test/controllers/main/service/reassign/step4_controller_test',
   'test/controllers/main/service/reassign/step4_controller_test',
+  'test/controllers/main/service/reassign/step6_controller_test',
   'test/controllers/main/dashboard_test',
   'test/controllers/main/dashboard_test',
   'test/controllers/main/host_test',
   'test/controllers/main/host_test',
   'test/controllers/main/service/item_test',
   'test/controllers/main/service/item_test',

+ 0 - 21
ambari-web/app/controllers/main/admin/highAvailability/progress_controller.js

@@ -36,7 +36,6 @@ App.HighAvailabilityProgressPageController = App.HighAvailabilityWizardControlle
   tasksMessagesPrefix: 'admin.highAvailability.wizard.step',
   tasksMessagesPrefix: 'admin.highAvailability.wizard.step',
 
 
   loadStep: function () {
   loadStep: function () {
-    console.warn('func: loadStep');
     this.clearStep();
     this.clearStep();
     this.initializeTasks();
     this.initializeTasks();
     this.loadTasks();
     this.loadTasks();
@@ -45,14 +44,12 @@ App.HighAvailabilityProgressPageController = App.HighAvailabilityWizardControlle
   },
   },
 
 
   clearStep: function () {
   clearStep: function () {
-    console.warn('func: clearStep');
     this.set('isSubmitDisabled', true);
     this.set('isSubmitDisabled', true);
     this.set('tasks', []);
     this.set('tasks', []);
     this.set('currentRequestIds', []);
     this.set('currentRequestIds', []);
   },
   },
 
 
   initializeTasks: function () {
   initializeTasks: function () {
-    console.warn('func: initializeTasks');
     var commands = this.get('commands');
     var commands = this.get('commands');
     var currentStep = App.router.get(this.get('content.controllerName') + '.currentStep');
     var currentStep = App.router.get(this.get('content.controllerName') + '.currentStep');
     var tasksMessagesPrefix = this.get('tasksMessagesPrefix');
     var tasksMessagesPrefix = this.get('tasksMessagesPrefix');
@@ -74,7 +71,6 @@ App.HighAvailabilityProgressPageController = App.HighAvailabilityWizardControlle
   },
   },
 
 
   loadTasks: function () {
   loadTasks: function () {
-    console.warn('func: loadTasks');
     var self = this;
     var self = this;
     var loadedStatuses = this.get('content.tasksStatuses');
     var loadedStatuses = this.get('content.tasksStatuses');
     var loadedRequestIds = this.get('content.tasksRequestIds');
     var loadedRequestIds = this.get('content.tasksRequestIds');
@@ -97,7 +93,6 @@ App.HighAvailabilityProgressPageController = App.HighAvailabilityWizardControlle
   },
   },
 
 
   setTaskStatus: function (taskId, status) {
   setTaskStatus: function (taskId, status) {
-    console.warn('func: setTaskStatus');
     this.get('tasks').findProperty('id', taskId).set('status', status);
     this.get('tasks').findProperty('id', taskId).set('status', status);
   },
   },
 
 
@@ -106,7 +101,6 @@ App.HighAvailabilityProgressPageController = App.HighAvailabilityWizardControlle
   },
   },
 
 
   retryTask: function () {
   retryTask: function () {
-    console.warn('func: retryTask');
     var task = this.get('tasks').findProperty('status', 'FAILED');
     var task = this.get('tasks').findProperty('status', 'FAILED');
     task.set('showRetry', false);
     task.set('showRetry', false);
     task.set('showRollback', false);
     task.set('showRollback', false);
@@ -114,7 +108,6 @@ App.HighAvailabilityProgressPageController = App.HighAvailabilityWizardControlle
   },
   },
 
 
   manualRollback: function () {
   manualRollback: function () {
-    console.warn('func: manualRollback');
     App.ModalPopup.show({
     App.ModalPopup.show({
       header: Em.I18n.t('admin.highAvailability.confirmRollbackHeader'),
       header: Em.I18n.t('admin.highAvailability.confirmRollbackHeader'),
       primary: Em.I18n.t('yes'),
       primary: Em.I18n.t('yes'),
@@ -143,7 +136,6 @@ App.HighAvailabilityProgressPageController = App.HighAvailabilityWizardControlle
   },
   },
 
 
   rollback: function () {
   rollback: function () {
-    console.warn('func: rollback');
     var task = this.get('tasks').findProperty('status', 'FAILED');
     var task = this.get('tasks').findProperty('status', 'FAILED');
     App.router.get(this.get('content.controllerName')).saveFailedTask(task);
     App.router.get(this.get('content.controllerName')).saveFailedTask(task);
     App.ModalPopup.show({
     App.ModalPopup.show({
@@ -161,11 +153,9 @@ App.HighAvailabilityProgressPageController = App.HighAvailabilityWizardControlle
   },
   },
 
 
   onTaskStatusChange: function () {
   onTaskStatusChange: function () {
-    console.warn('func: onTaskStatusChange1');
     var statuses = this.get('tasks').mapProperty('status');
     var statuses = this.get('tasks').mapProperty('status');
     var tasksRequestIds = this.get('tasks').mapProperty('requestIds');
     var tasksRequestIds = this.get('tasks').mapProperty('requestIds');
     var requestIds = this.get('currentRequestIds');
     var requestIds = this.get('currentRequestIds');
-    console.warn('func: onTaskStatusChange5', statuses, tasksRequestIds, requestIds);
     // save task info
     // save task info
     App.router.get(this.get('content.controllerName')).saveTasksStatuses(statuses);
     App.router.get(this.get('content.controllerName')).saveTasksStatuses(statuses);
     App.router.get(this.get('content.controllerName')).saveTasksRequestIds(tasksRequestIds);
     App.router.get(this.get('content.controllerName')).saveTasksRequestIds(tasksRequestIds);
@@ -187,18 +177,15 @@ App.HighAvailabilityProgressPageController = App.HighAvailabilityWizardControlle
     if (!this.get('tasks').someProperty('status', 'IN_PROGRESS') && !this.get('tasks').someProperty('status', 'QUEUED') && !this.get('tasks').someProperty('status', 'FAILED')) {
     if (!this.get('tasks').someProperty('status', 'IN_PROGRESS') && !this.get('tasks').someProperty('status', 'QUEUED') && !this.get('tasks').someProperty('status', 'FAILED')) {
       var nextTask = this.get('tasks').findProperty('status', 'PENDING');
       var nextTask = this.get('tasks').findProperty('status', 'PENDING');
       if (nextTask) {
       if (nextTask) {
-        console.warn('func: onTaskStatusChange2');
         this.set('status', 'IN_PROGRESS');
         this.set('status', 'IN_PROGRESS');
         this.setTaskStatus(nextTask.get('id'), 'QUEUED');
         this.setTaskStatus(nextTask.get('id'), 'QUEUED');
         this.set('currentTaskId', nextTask.get('id'));
         this.set('currentTaskId', nextTask.get('id'));
         this.runTask(nextTask.get('id'));
         this.runTask(nextTask.get('id'));
       } else {
       } else {
-        console.warn('func: onTaskStatusChange3');
         this.set('status', 'COMPLETED');
         this.set('status', 'COMPLETED');
         this.set('isSubmitDisabled', false);
         this.set('isSubmitDisabled', false);
       }
       }
     } else if (this.get('tasks').someProperty('status', 'FAILED')) {
     } else if (this.get('tasks').someProperty('status', 'FAILED')) {
-      console.warn('func: onTaskStatusChange4');
       this.set('status', 'FAILED');
       this.set('status', 'FAILED');
       this.get('tasks').findProperty('status', 'FAILED').set('showRetry', true);
       this.get('tasks').findProperty('status', 'FAILED').set('showRetry', true);
       if (App.supports.autoRollbackHA) {
       if (App.supports.autoRollbackHA) {
@@ -213,17 +200,14 @@ App.HighAvailabilityProgressPageController = App.HighAvailabilityWizardControlle
    * Run command of appropriate task
    * Run command of appropriate task
    */
    */
   runTask: function (taskId) {
   runTask: function (taskId) {
-    console.warn('func: runTask', taskId);
     this[this.get('tasks').findProperty('id', taskId).get('command')]();
     this[this.get('tasks').findProperty('id', taskId).get('command')]();
   },
   },
 
 
   onTaskError: function () {
   onTaskError: function () {
-    console.warn('func: onTaskError');
     this.setTaskStatus(this.get('currentTaskId'), 'FAILED');
     this.setTaskStatus(this.get('currentTaskId'), 'FAILED');
   },
   },
 
 
   onTaskCompleted: function () {
   onTaskCompleted: function () {
-    console.warn('func: onTaskCompleted');
     this.setTaskStatus(this.get('currentTaskId'), 'COMPLETED');
     this.setTaskStatus(this.get('currentTaskId'), 'COMPLETED');
   },
   },
 
 
@@ -329,22 +313,18 @@ App.HighAvailabilityProgressPageController = App.HighAvailabilityWizardControlle
 
 
   startPolling: function (data) {
   startPolling: function (data) {
     if (data) {
     if (data) {
-      console.warn('func: startPolling1');
       this.get('currentRequestIds').push(data.Requests.id);
       this.get('currentRequestIds').push(data.Requests.id);
       var tasksCount = arguments[2].taskNum || 1;
       var tasksCount = arguments[2].taskNum || 1;
       if (tasksCount === this.get('currentRequestIds').length) {
       if (tasksCount === this.get('currentRequestIds').length) {
         this.setRequestIds(this.get('currentTaskId'), this.get('currentRequestIds'));
         this.setRequestIds(this.get('currentTaskId'), this.get('currentRequestIds'));
-        console.warn('func: startPolling2');
         this.doPolling();
         this.doPolling();
       }
       }
     } else {
     } else {
-      console.warn('func: startPolling3');
       this.onTaskCompleted();
       this.onTaskCompleted();
     }
     }
   },
   },
 
 
   doPolling: function () {
   doPolling: function () {
-    console.warn('func: doPolling');
     this.setTaskStatus(this.get('currentTaskId'), 'IN_PROGRESS');
     this.setTaskStatus(this.get('currentTaskId'), 'IN_PROGRESS');
     var requestIds = this.get('currentRequestIds');
     var requestIds = this.get('currentRequestIds');
     this.set('logs', []);
     this.set('logs', []);
@@ -362,7 +342,6 @@ App.HighAvailabilityProgressPageController = App.HighAvailabilityWizardControlle
   },
   },
 
 
   parseLogs: function (logs) {
   parseLogs: function (logs) {
-    console.warn('func: parseLogs');
     this.get('logs').pushObject(logs.tasks);
     this.get('logs').pushObject(logs.tasks);
     if (this.get('currentRequestIds').length === this.get('logs').length) {
     if (this.get('currentRequestIds').length === this.get('logs').length) {
       var tasks = [];
       var tasks = [];

+ 60 - 47
ambari-web/app/controllers/main/service/reassign/step4_controller.js

@@ -269,6 +269,7 @@ App.ReassignMasterWizardStep4Controller = App.HighAvailabilityProgressPageContro
 
 
   /**
   /**
    * compute data for call to stop services
    * compute data for call to stop services
+   * @return {Object}
    */
    */
   getStopServicesData: function () {
   getStopServicesData: function () {
     var data = {
     var data = {
@@ -430,6 +431,23 @@ App.ReassignMasterWizardStep4Controller = App.HighAvailabilityProgressPageContro
    * @param configs
    * @param configs
    */
    */
   saveConfigsToServer: function (configs) {
   saveConfigsToServer: function (configs) {
+    App.ajax.send({
+      name: 'common.across.services.configurations',
+      sender: this,
+      data: {
+        data: '[' + this.getServiceConfigData(configs).toString() + ']'
+      },
+      success: 'onSaveConfigs',
+      error: 'onTaskError'
+    });
+  },
+  /**
+   * gather and format config data before sending to server
+   * @param configs
+   * @return {Array}
+   * @method getServiceConfigData
+   */
+  getServiceConfigData: function (configs) {
     var componentName = this.get('content.reassign.component_name');
     var componentName = this.get('content.reassign.component_name');
     var tagName = 'version' + (new Date).getTime();
     var tagName = 'version' + (new Date).getTime();
     var configData = Object.keys(configs).map(function (_siteName) {
     var configData = Object.keys(configs).map(function (_siteName) {
@@ -440,10 +458,9 @@ App.ReassignMasterWizardStep4Controller = App.HighAvailabilityProgressPageContro
         service_config_version_note: Em.I18n.t('services.reassign.step4.save.configuration.note').format(App.format.role(componentName))
         service_config_version_note: Em.I18n.t('services.reassign.step4.save.configuration.note').format(App.format.role(componentName))
       }
       }
     });
     });
-
-    var installedServices = App.Service.find();
     var allConfigData = [];
     var allConfigData = [];
-    installedServices.forEach(function (service) {
+
+    App.Service.find().forEach(function (service) {
       var stackService = App.StackService.find().findProperty('serviceName', service.get('serviceName'));
       var stackService = App.StackService.find().findProperty('serviceName', service.get('serviceName'));
       if (stackService) {
       if (stackService) {
         var serviceConfigData = [];
         var serviceConfigData = [];
@@ -460,16 +477,7 @@ App.ReassignMasterWizardStep4Controller = App.HighAvailabilityProgressPageContro
         }));
         }));
       }
       }
     }, this);
     }, this);
-
-    App.ajax.send({
-      name: 'common.across.services.configurations',
-      sender: this,
-      data: {
-        data: '[' + allConfigData.toString() + ']'
-      },
-      success: 'onSaveConfigs',
-      error: 'onTaskError'
-    });
+    return allConfigData;
   },
   },
 
 
   /**
   /**
@@ -482,15 +490,10 @@ App.ReassignMasterWizardStep4Controller = App.HighAvailabilityProgressPageContro
 
 
     if (App.get('isHadoop2Stack') && App.get('isHaEnabled')) {
     if (App.get('isHadoop2Stack') && App.get('isHaEnabled')) {
       var nameServices = configs['hdfs-site']['dfs.nameservices'];
       var nameServices = configs['hdfs-site']['dfs.nameservices'];
-      if (configs['hdfs-site']['dfs.namenode.http-address.' + nameServices + '.nn1'] === sourceHostName + ':50070') {
-        configs['hdfs-site']['dfs.namenode.http-address.' + nameServices + '.nn1'] = targetHostName + ':50070';
-        configs['hdfs-site']['dfs.namenode.https-address.' + nameServices + '.nn1'] = targetHostName + ':50470';
-        configs['hdfs-site']['dfs.namenode.rpc-address.' + nameServices + '.nn1'] = targetHostName + ':8020';
-      } else {
-        configs['hdfs-site']['dfs.namenode.http-address.' + nameServices + '.nn2'] = targetHostName + ':50070';
-        configs['hdfs-site']['dfs.namenode.https-address.' + nameServices + '.nn2'] = targetHostName + ':50470';
-        configs['hdfs-site']['dfs.namenode.rpc-address.' + nameServices + '.nn2'] = targetHostName + ':8020';
-      }
+      var suffix = (configs['hdfs-site']['dfs.namenode.http-address.' + nameServices + '.nn1'] === sourceHostName + ':50070') ? '.nn1' : '.nn2';
+      configs['hdfs-site']['dfs.namenode.http-address.' + nameServices + suffix] = targetHostName + ':50070';
+      configs['hdfs-site']['dfs.namenode.https-address.' + nameServices + suffix] = targetHostName + ':50470';
+      configs['hdfs-site']['dfs.namenode.rpc-address.' + nameServices + suffix] = targetHostName + ':8020';
     }
     }
     if (!App.get('isHaEnabled') && App.Service.find('HBASE').get('isLoaded')) {
     if (!App.get('isHaEnabled') && App.Service.find('HBASE').get('isLoaded')) {
       configs['hbase-site']['hbase.rootdir'] = configs['hbase-site']['hbase.rootdir'].replace(/\/\/[^\/]*/, '//' + targetHostName + ':8020');
       configs['hbase-site']['hbase.rootdir'] = configs['hbase-site']['hbase.rootdir'].replace(/\/\/[^\/]*/, '//' + targetHostName + ':8020');
@@ -512,7 +515,6 @@ App.ReassignMasterWizardStep4Controller = App.HighAvailabilityProgressPageContro
         configs['yarn-site']['yarn.resourcemanager.hostname.rm2'] = targetHostName;
         configs['yarn-site']['yarn.resourcemanager.hostname.rm2'] = targetHostName;
       }
       }
     }
     }
-
   },
   },
 
 
   /**
   /**
@@ -588,42 +590,53 @@ App.ReassignMasterWizardStep4Controller = App.HighAvailabilityProgressPageContro
     this.updateComponent('NAMENODE', components.mapProperty('hostName').without(this.get('content.reassignHosts.source')), "HDFS", "Start");
     this.updateComponent('NAMENODE', components.mapProperty('hostName').without(this.get('content.reassignHosts.source')), "HDFS", "Start");
   },
   },
 
 
+  /**
+   * make server call to start services
+   */
   startServices: function () {
   startServices: function () {
+    App.ajax.send({
+      name: 'common.services.update',
+      sender: this,
+      data: this.getStartServicesData(),
+      success: 'startPolling',
+      error: 'onTaskError'
+    });
+  },
+
+  /**
+   * compute data for call to start services
+   * @return {Object}
+   */
+  getStartServicesData: function () {
     var unrelatedServices = this.get('unrelatedServicesMap')[this.get('content.reassign.component_name')];
     var unrelatedServices = this.get('unrelatedServicesMap')[this.get('content.reassign.component_name')];
+    var data = {};
+
     if (unrelatedServices) {
     if (unrelatedServices) {
       var list = App.Service.find().mapProperty("serviceName").filter(function (s) {
       var list = App.Service.find().mapProperty("serviceName").filter(function (s) {
         return !unrelatedServices.contains(s)
         return !unrelatedServices.contains(s)
       }).join(',');
       }).join(',');
-      var conf = {
-        name: 'common.services.update',
-        sender: this,
-        data: {
-          "context": "Start required services",
-          "ServiceInfo": {
-            "state": "STARTED"
-          },
-          urlParams: "ServiceInfo/service_name.in(" + list + ")"},
-        success: 'startPolling',
-        error: 'onTaskError'
+      data = {
+        "context": "Start required services",
+        "ServiceInfo": {
+          "state": "STARTED"
+        },
+        "urlParams": "ServiceInfo/service_name.in(" + list + ")"
       };
       };
-      App.ajax.send(conf);
     } else {
     } else {
-      App.ajax.send({
-        name: 'common.services.update',
-        sender: this,
-        data: {
-          "context": "Start all services",
-          "ServiceInfo": {
-            "state": "STARTED"
-          },
-          urlParams: "params/run_smoke_test=true"
+      data = {
+        "context": "Start all services",
+        "ServiceInfo": {
+          "state": "STARTED"
         },
         },
-        success: 'startPolling',
-        error: 'onTaskError'
-      });
+        "urlParams": "params/run_smoke_test=true"
+      };
     }
     }
+    return data;
   },
   },
 
 
+  /**
+   * make DELETE call for each host component on host
+   */
   deleteHostComponents: function () {
   deleteHostComponents: function () {
     this.set('multiTaskCounter', 0);
     this.set('multiTaskCounter', 0);
     var hostComponents = this.get('hostComponents');
     var hostComponents = this.get('hostComponents');

+ 594 - 59
ambari-web/test/controllers/main/service/reassign/step4_controller_test.js

@@ -136,59 +136,6 @@ describe('App.ReassignMasterWizardStep4Controller', function () {
     });
     });
   });
   });
 
 
-  /*  describe('#loadStep()', function () {
-   var isHaEnabled = true;
-
-   beforeEach(function () {
-   controller.set('content.reassign.service_id', 'service1');
-   sinon.stub(controller, 'onTaskStatusChange', Em.K);
-   sinon.stub(App, 'get', function () {
-   return isHaEnabled;
-   });
-   });
-   afterEach(function () {
-   App.get.restore();
-   controller.onTaskStatusChange.restore();
-   });
-
-   it('reassign component is NameNode and HA enabled', function () {
-   isHaEnabled = true;
-   controller.set('content.reassign.component_name', 'NAMENODE');
-
-   controller.loadStep();
-   expect(controller.get('hostComponents')).to.eql(['NAMENODE', 'ZKFC']);
-   expect(controller.get('restartYarnMRComponents')).to.be.false;
-   expect(controller.get('serviceName')).to.eql(['service1']);
-   });
-   it('reassign component is NameNode and HA disabled', function () {
-   isHaEnabled = false;
-   controller.set('content.reassign.component_name', 'NAMENODE');
-
-   controller.loadStep();
-   expect(controller.get('hostComponents')).to.eql(['NAMENODE']);
-   expect(controller.get('restartYarnMRComponents')).to.be.false;
-   expect(controller.get('serviceName')).to.eql(['service1']);
-   });
-   it('reassign component is JOBTRACKER and HA enabled', function () {
-   isHaEnabled = true;
-   controller.set('content.reassign.component_name', 'JOBTRACKER');
-
-   controller.loadStep();
-   expect(controller.get('hostComponents')).to.eql(['JOBTRACKER']);
-   expect(controller.get('restartYarnMRComponents')).to.be.true;
-   expect(controller.get('serviceName')).to.eql(['service1']);
-   });
-   it('reassign component is RESOURCEMANAGER and HA enabled', function () {
-   isHaEnabled = true;
-   controller.set('content.reassign.component_name', 'RESOURCEMANAGER');
-
-   controller.loadStep();
-   expect(controller.get('hostComponents')).to.eql(['RESOURCEMANAGER']);
-   expect(controller.get('restartYarnMRComponents')).to.be.true;
-   expect(controller.get('serviceName')).to.eql(['service1']);
-   });
-   });*/
-
   describe('#getHostComponentsNames()', function () {
   describe('#getHostComponentsNames()', function () {
     it('No host-components', function () {
     it('No host-components', function () {
       controller.set('hostComponents', []);
       controller.set('hostComponents', []);
@@ -587,6 +534,7 @@ describe('App.ReassignMasterWizardStep4Controller', function () {
       sinon.stub(controller, 'setAdditionalConfigs', Em.K);
       sinon.stub(controller, 'setAdditionalConfigs', Em.K);
       sinon.stub(controller, 'setSecureConfigs', Em.K);
       sinon.stub(controller, 'setSecureConfigs', Em.K);
       sinon.stub(controller, 'setSpecificNamenodeConfigs', Em.K);
       sinon.stub(controller, 'setSpecificNamenodeConfigs', Em.K);
+      sinon.stub(controller, 'setSpecificResourceMangerConfigs', Em.K);
       sinon.stub(controller, 'getComponentDir', Em.K);
       sinon.stub(controller, 'getComponentDir', Em.K);
       sinon.stub(controller, 'saveClusterStatus', Em.K);
       sinon.stub(controller, 'saveClusterStatus', Em.K);
       sinon.stub(controller, 'saveConfigsToServer', Em.K);
       sinon.stub(controller, 'saveConfigsToServer', Em.K);
@@ -596,6 +544,7 @@ describe('App.ReassignMasterWizardStep4Controller', function () {
       controller.setAdditionalConfigs.restore();
       controller.setAdditionalConfigs.restore();
       controller.setSecureConfigs.restore();
       controller.setSecureConfigs.restore();
       controller.setSpecificNamenodeConfigs.restore();
       controller.setSpecificNamenodeConfigs.restore();
+      controller.setSpecificResourceMangerConfigs.restore();
       controller.getComponentDir.restore();
       controller.getComponentDir.restore();
       controller.saveClusterStatus.restore();
       controller.saveClusterStatus.restore();
       controller.saveConfigsToServer.restore();
       controller.saveConfigsToServer.restore();
@@ -628,12 +577,598 @@ describe('App.ReassignMasterWizardStep4Controller', function () {
       expect(controller.saveClusterStatus.calledWith([])).to.be.true;
       expect(controller.saveClusterStatus.calledWith([])).to.be.true;
       expect(controller.saveConfigsToServer.calledWith({'hdfs-site': {}})).to.be.true;
       expect(controller.saveConfigsToServer.calledWith({'hdfs-site': {}})).to.be.true;
     });
     });
+    it('component is RESOURCEMANAGER, has configs', function () {
+      controller.set('content.reassign.component_name', 'RESOURCEMANAGER');
+
+      controller.onLoadConfigs({items: [
+        {
+          type: 'hdfs-site',
+          properties: {}
+        }
+      ]});
+      expect(controller.setAdditionalConfigs.calledWith({'hdfs-site': {}}, 'RESOURCEMANAGER', 'host1')).to.be.true;
+      expect(controller.setSecureConfigs.calledWith([], {'hdfs-site': {}}, 'RESOURCEMANAGER')).to.be.true;
+      expect(controller.setSpecificResourceMangerConfigs.calledWith({'hdfs-site': {}}, 'host1')).to.be.true;
+      expect(controller.getComponentDir.calledWith({'hdfs-site': {}}, 'RESOURCEMANAGER')).to.be.true;
+      expect(controller.saveClusterStatus.calledWith([])).to.be.true;
+      expect(controller.saveConfigsToServer.calledWith({'hdfs-site': {}})).to.be.true;
+    });
+  });
+
+  describe('#loadStep()', function () {
+    var isHaEnabled = true;
+
+    beforeEach(function () {
+      controller.set('content.reassign.service_id', 'service1');
+      sinon.stub(controller, 'onTaskStatusChange', Em.K);
+      sinon.stub(controller, 'initializeTasks', Em.K);
+      sinon.stub(App, 'get', function () {
+        return isHaEnabled;
+      });
+    });
+    afterEach(function () {
+      controller.onTaskStatusChange.restore();
+      controller.initializeTasks.restore();
+      App.get.restore();
+    });
+
+    it('reassign component is NameNode and HA enabled', function () {
+      isHaEnabled = true;
+      controller.set('content.reassign.component_name', 'NAMENODE');
+
+      controller.loadStep();
+      expect(controller.get('hostComponents')).to.eql(['NAMENODE', 'ZKFC']);
+      expect(controller.get('serviceName')).to.eql(['service1']);
+    });
+    it('reassign component is NameNode and HA disabled', function () {
+      isHaEnabled = false;
+      controller.set('content.reassign.component_name', 'NAMENODE');
+
+      controller.loadStep();
+      expect(controller.get('hostComponents')).to.eql(['NAMENODE']);
+      expect(controller.get('serviceName')).to.eql(['service1']);
+    });
+    it('reassign component is JOBTRACKER and HA enabled', function () {
+      isHaEnabled = true;
+      controller.set('content.reassign.component_name', 'JOBTRACKER');
+
+      controller.loadStep();
+      expect(controller.get('hostComponents')).to.eql(['JOBTRACKER']);
+      expect(controller.get('serviceName')).to.eql(['service1']);
+    });
+    it('reassign component is RESOURCEMANAGER and HA enabled', function () {
+      isHaEnabled = true;
+      controller.set('content.reassign.component_name', 'RESOURCEMANAGER');
+
+      controller.loadStep();
+      expect(controller.get('hostComponents')).to.eql(['RESOURCEMANAGER']);
+      expect(controller.get('serviceName')).to.eql(['service1']);
+    });
   });
   });
 
 
 
 
- /* describe('#setSpecificNamenodeConfigs()', function () {
-   it('configs is empty', function () {
-   controller.setSpecificNamenodeConfigs();
-   });
-   });*/
-});
+  describe('#saveConfigsToServer()', function () {
+    beforeEach(function () {
+      sinon.stub(controller, 'getServiceConfigData', Em.K);
+    });
+    afterEach(function () {
+      controller.getServiceConfigData.restore();
+    });
+    it('', function () {
+      controller.saveConfigsToServer([1]);
+      expect(controller.getServiceConfigData.calledWith([1])).to.be.true;
+      expect(App.ajax.send.calledOnce).to.be.true;
+    });
+  });
+
+  describe('#setSpecificNamenodeConfigs()', function () {
+    var isHaEnabled = false;
+    var service = Em.Object.create();
+    beforeEach(function () {
+      sinon.stub(App, 'get', function () {
+        return isHaEnabled;
+      });
+      sinon.stub(App.Service, 'find', function () {
+        return service;
+      });
+      controller.set('content.reassignHosts.source', 'host1');
+    });
+    afterEach(function () {
+      App.get.restore();
+      App.Service.find.restore();
+    });
+    it('HA isn\'t enabled and no HBASE service', function () {
+      isHaEnabled = false;
+      var configs = {};
+      controller.setSpecificNamenodeConfigs(configs, 'host1');
+      expect(configs).to.eql({});
+    });
+    it('HA isn\'t enabled and HBASE service', function () {
+      isHaEnabled = false;
+      service = Em.Object.create({
+        isLoaded: true
+      });
+      var configs = {
+        'hbase-site': {
+          'hbase.rootdir': 'hdfs://localhost:8020/apps/hbase/data'
+        }
+      };
+      controller.setSpecificNamenodeConfigs(configs, 'host1');
+      expect(configs['hbase-site']['hbase.rootdir']).to.equal('hdfs://host1:8020/apps/hbase/data');
+    });
+    it('HA enabled and namenode 1', function () {
+      isHaEnabled = true;
+      var configs = {
+        'hdfs-site': {
+          'dfs.nameservices': 's',
+          'dfs.namenode.http-address.s.nn1': 'host1:50070',
+          'dfs.namenode.https-address.s.nn1': '',
+          'dfs.namenode.rpc-address.s.nn1': ''
+        }
+      };
+      controller.setSpecificNamenodeConfigs(configs, 'host2');
+      expect(configs['hdfs-site']).to.eql({
+        "dfs.nameservices": "s",
+        "dfs.namenode.http-address.s.nn1": "host2:50070",
+        "dfs.namenode.https-address.s.nn1": "host2:50470",
+        "dfs.namenode.rpc-address.s.nn1": "host2:8020"
+      });
+    });
+    it('HA enabled and namenode 2', function () {
+      isHaEnabled = true;
+      var configs = {
+        'hdfs-site': {
+          'dfs.nameservices': 's',
+          'dfs.namenode.http-address.s.nn2': 'host2:50070',
+          'dfs.namenode.https-address.s.nn2': '',
+          'dfs.namenode.rpc-address.s.nn2': ''
+        }
+      };
+      controller.setSpecificNamenodeConfigs(configs, 'host1');
+      expect(configs['hdfs-site']).to.eql({
+        "dfs.nameservices": "s",
+        "dfs.namenode.http-address.s.nn2": "host1:50070",
+        "dfs.namenode.https-address.s.nn2": "host1:50470",
+        "dfs.namenode.rpc-address.s.nn2": "host1:8020"
+      });
+    });
+  });
+
+  describe('#setSpecificResourceMangerConfigs()', function () {
+    var isRMHaEnabled = false;
+    var service = Em.Object.create();
+    beforeEach(function () {
+      sinon.stub(App, 'get', function () {
+        return isRMHaEnabled;
+      });
+      controller.set('content.reassignHosts.source', 'host1');
+    });
+    afterEach(function () {
+      App.get.restore();
+    });
+
+    it('HA isn\'t enabled', function () {
+      isRMHaEnabled = false;
+      var configs = {};
+      controller.setSpecificResourceMangerConfigs(configs, 'host1');
+      expect(configs).to.eql({});
+    });
+    it('HA enabled and resource manager 1', function () {
+      isRMHaEnabled = true;
+      var configs = {
+        'yarn-site': {
+          'yarn.resourcemanager.hostname.rm1': 'host1'
+        }
+      };
+      controller.setSpecificResourceMangerConfigs(configs, 'host2');
+      expect(configs['yarn-site']).to.eql({
+        'yarn.resourcemanager.hostname.rm1': 'host2'
+      });
+    });
+    it('HA enabled and resource manager 2', function () {
+      isRMHaEnabled = true;
+      var configs = {
+        'yarn-site': {
+          'yarn.resourcemanager.hostname.rm2': 'host2'
+        }
+      };
+      controller.setSpecificResourceMangerConfigs(configs, 'host1');
+      expect(configs['yarn-site']).to.eql({
+        'yarn.resourcemanager.hostname.rm2': 'host1'
+      });
+    });
+  });
+
+  describe('#setSecureConfigs()', function () {
+    it('undefined component and security disabled', function () {
+      var secureConfigs = [];
+      controller.set('content.securityEnabled', false);
+      controller.set('secureConfigsMap', []);
+      expect(controller.setSecureConfigs(secureConfigs, {}, 'COMP1')).to.be.false;
+      expect(secureConfigs).to.eql([]);
+    });
+    it('undefined component and security enabled', function () {
+      var secureConfigs = [];
+      controller.set('content.securityEnabled', true);
+      controller.set('secureConfigsMap', []);
+      expect(controller.setSecureConfigs(secureConfigs, {}, 'COMP1')).to.be.false;
+      expect(secureConfigs).to.eql([]);
+    });
+    it('component exist and security disabled', function () {
+      var secureConfigs = [];
+      controller.set('content.securityEnabled', false);
+      controller.set('secureConfigsMap', [{
+        componentName: 'COMP1'
+      }]);
+      expect(controller.setSecureConfigs(secureConfigs, {}, 'COMP1')).to.be.false;
+      expect(secureConfigs).to.eql([]);
+    });
+    it('component exist and security enabled', function () {
+      var secureConfigs = [];
+      var configs = {'s1': {
+        'k1': 'kValue',
+        'p1': 'pValue'
+      }};
+      controller.set('content.securityEnabled', true);
+      controller.set('secureConfigsMap', [{
+        componentName: 'COMP1',
+        configs: [{
+          site: 's1',
+          keytab: 'k1',
+          principal: 'p1'
+        }]
+      }]);
+      expect(controller.setSecureConfigs(secureConfigs, configs, 'COMP1')).to.be.true;
+      expect(secureConfigs).to.eql([
+        {
+          "keytab": "kValue",
+          "principal": "pValue"
+        }
+      ]);
+    });
+  });
+
+  describe('#getComponentDir()', function () {
+    var isHadoop2Stack = false;
+    beforeEach(function () {
+      sinon.stub(App, 'get', function () {
+        return isHadoop2Stack;
+      });
+    });
+    afterEach(function () {
+      App.get.restore();
+    });
+
+    var configs = {
+      'hdfs-site': {
+        'dfs.name.dir': 'case1',
+        'dfs.namenode.name.dir': 'case2',
+        'dfs.namenode.checkpoint.dir': 'case3'
+      },
+      'core-site': {
+        'fs.checkpoint.dir': 'case4'
+      }
+    };
+
+    it('unknown component name', function () {
+      expect(controller.getComponentDir(configs, 'COMP1')).to.be.empty;
+    });
+    it('NAMENODE component and isHadoop2Stack is false', function () {
+      expect(controller.getComponentDir(configs, 'NAMENODE')).to.equal('case1');
+    });
+    it('NAMENODE component and isHadoop2Stack is true', function () {
+      isHadoop2Stack = true;
+      expect(controller.getComponentDir(configs, 'NAMENODE')).to.equal('case2');
+    });
+    it('SECONDARY_NAMENODE component and isHadoop2Stack is true', function () {
+      isHadoop2Stack = true;
+      expect(controller.getComponentDir(configs, 'SECONDARY_NAMENODE')).to.equal('case3');
+    });
+    it('SECONDARY_NAMENODE component and isHadoop2Stack is false', function () {
+      isHadoop2Stack = false;
+      expect(controller.getComponentDir(configs, 'SECONDARY_NAMENODE')).to.equal('case4');
+    });
+  });
+
+  describe('#saveClusterStatus()', function () {
+    var mock = {
+      saveComponentDir: Em.K,
+      saveSecureConfigs: Em.K
+    };
+    beforeEach(function () {
+      sinon.stub(App.clusterStatus, 'setClusterStatus', Em.K);
+      sinon.stub(App.router, 'get', function() {
+        return mock;
+      });
+      sinon.spy(mock, 'saveComponentDir');
+      sinon.spy(mock, 'saveSecureConfigs');
+    });
+    afterEach(function () {
+      App.clusterStatus.setClusterStatus.restore();
+      App.router.get.restore();
+      mock.saveSecureConfigs.restore();
+      mock.saveComponentDir.restore();
+    });
+
+    it('componentDir undefined and secureConfigs is empty', function () {
+      expect(controller.saveClusterStatus([], null)).to.be.false;
+    });
+    it('componentDir defined and secureConfigs is empty', function () {
+      expect(controller.saveClusterStatus([], 'dir1')).to.be.true;
+      expect(mock.saveComponentDir.calledWith('dir1')).to.be.true;
+      expect(mock.saveSecureConfigs.calledWith([])).to.be.true;
+    });
+    it('componentDir undefined and secureConfigs has data', function () {
+      expect(controller.saveClusterStatus([1], null)).to.be.true;
+      expect(mock.saveComponentDir.calledWith(null)).to.be.true;
+      expect(mock.saveSecureConfigs.calledWith([1])).to.be.true;
+    });
+    it('componentDir defined and secureConfigs has data', function () {
+      expect(controller.saveClusterStatus([1], 'dir1')).to.be.true;
+      expect(mock.saveComponentDir.calledWith('dir1')).to.be.true;
+      expect(mock.saveSecureConfigs.calledWith([1])).to.be.true;
+    });
+  });
+
+  describe('#onSaveConfigs()', function () {
+    beforeEach(function () {
+      sinon.stub(controller, 'onTaskCompleted', Em.K);
+    });
+    afterEach(function () {
+      controller.onTaskCompleted.restore();
+    });
+
+    it('', function () {
+      controller.onSaveConfigs();
+      expect(controller.onTaskCompleted.calledOnce).to.be.true;
+    });
+  });
+
+  describe('#startZooKeeperServers()', function () {
+    beforeEach(function () {
+      sinon.stub(controller, 'updateComponent', Em.K);
+    });
+    afterEach(function () {
+      controller.updateComponent.restore();
+    });
+
+    it('', function () {
+      controller.set('content.masterComponentHosts', [{
+        component: 'ZOOKEEPER_SERVER',
+        hostName: 'host1'
+      }]);
+      controller.startZooKeeperServers();
+      expect(controller.updateComponent.calledWith('ZOOKEEPER_SERVER', ['host1'], 'ZOOKEEPER', 'Start')).to.be.true;
+    });
+  });
+
+  describe('#startNameNode()', function () {
+    beforeEach(function () {
+      sinon.stub(controller, 'updateComponent', Em.K);
+    });
+    afterEach(function () {
+      controller.updateComponent.restore();
+    });
+
+    it('reassign host does not match current', function () {
+      controller.set('content.masterComponentHosts', [{
+        component: 'NAMENODE',
+        hostName: 'host1'
+      }]);
+      controller.set('content.reassignHosts.source', 'host2');
+      controller.startNameNode();
+      expect(controller.updateComponent.calledWith('NAMENODE', ['host1'], 'HDFS', 'Start')).to.be.true;
+    });
+    it('reassign host matches current', function () {
+      controller.set('content.masterComponentHosts', [{
+        component: 'NAMENODE',
+        hostName: 'host1'
+      }]);
+      controller.set('content.reassignHosts.source', 'host1');
+      controller.startNameNode();
+      expect(controller.updateComponent.calledWith('NAMENODE', [], 'HDFS', 'Start')).to.be.true;
+    });
+  });
+
+  describe('#startServices()', function () {
+    beforeEach(function () {
+      sinon.stub(controller, 'getStartServicesData', Em.K);
+    });
+    afterEach(function () {
+      controller.getStartServicesData.restore();
+    });
+
+    it('', function () {
+      controller.startServices();
+      expect(controller.getStartServicesData.calledOnce).to.be.true;
+      expect(App.ajax.send.calledOnce).to.be.true;
+    });
+  });
+
+  describe('#getStartServicesData()', function () {
+    beforeEach(function () {
+      sinon.stub(App.Service, 'find', function () {
+        return [
+          {serviceName: 'SERVICE1'},
+          {serviceName: 'SERVICE2'}
+        ]
+      })
+    });
+    afterEach(function () {
+      App.Service.find.restore();
+    });
+
+    it('No unrelated services', function () {
+      controller.set('unrelatedServicesMap', {
+        'COMP1': ['SERVICE1']
+      });
+      controller.set('content.reassign.component_name', 'COMP2');
+      expect(controller.getStartServicesData()).to.eql({
+        "context": "Start all services",
+        "ServiceInfo": {
+          "state": "STARTED"
+        },
+        "urlParams": "params/run_smoke_test=true"
+      });
+    });
+    it('Present unrelated services', function () {
+      controller.set('unrelatedServicesMap', {
+        'COMP1': ['SERVICE1']
+      });
+      controller.set('content.reassign.component_name', 'COMP1');
+      expect(controller.getStartServicesData()).to.eql({
+        "context": "Start required services",
+        "ServiceInfo": {
+          "state": "STARTED"
+        },
+        "urlParams": "ServiceInfo/service_name.in(SERVICE2)"
+      });
+    });
+  });
+
+  describe('#deleteHostComponents()', function () {
+
+    it('No host components', function () {
+      controller.set('hostComponents', []);
+      controller.set('content.reassignHosts.source', 'host1');
+      controller.deleteHostComponents();
+      expect(App.ajax.send.called).to.be.false;
+    });
+    it('delete two components', function () {
+      controller.set('hostComponents', [1, 2]);
+      controller.set('content.reassignHosts.source', 'host1');
+      controller.deleteHostComponents();
+      expect(App.ajax.send.getCall(0).args[0].data).to.eql({
+        "hostName": "host1",
+        "componentName": 1
+      });
+      expect(App.ajax.send.getCall(1).args[0].data).to.eql({
+        "hostName": "host1",
+        "componentName": 2
+      });
+    });
+  });
+
+  describe('#onDeleteHostComponentsError()', function () {
+    beforeEach(function () {
+      sinon.stub(controller, 'onComponentsTasksSuccess', Em.K);
+      sinon.stub(controller, 'onTaskError', Em.K);
+    });
+    afterEach(function () {
+      controller.onComponentsTasksSuccess.restore();
+      controller.onTaskError.restore();
+    });
+
+    it('task success', function () {
+      var error = {
+        responseText: 'org.apache.ambari.server.controller.spi.NoSuchResourceException'
+      }
+      controller.onDeleteHostComponentsError(error);
+      expect(controller.onComponentsTasksSuccess.calledOnce).to.be.true;
+    });
+    it('unknown error', function () {
+      var error = {
+        responseText: ''
+      }
+      controller.onDeleteHostComponentsError(error);
+      expect(controller.onTaskError.calledOnce).to.be.true;
+    });
+  });
+
+  describe('#done()', function () {
+    beforeEach(function () {
+      sinon.stub(controller, 'removeObserver', Em.K);
+      sinon.stub(App.router, 'send', Em.K);
+    });
+    afterEach(function () {
+      controller.removeObserver.restore();
+      App.router.send.restore();
+    });
+
+    it('submit disabled', function () {
+      controller.set('isSubmitDisabled', true);
+      controller.done();
+      expect(App.router.send.called).to.be.false;
+    });
+    it('submit enabled and does not have manual steps', function () {
+      controller.set('isSubmitDisabled', false);
+      controller.set('content.hasManualSteps', false);
+      controller.done();
+      expect(controller.removeObserver.calledWith('tasks.@each.status', controller, 'onTaskStatusChange')).to.be.true;
+      expect(App.router.send.calledWith('complete')).to.be.true;
+    });
+    it('submit enabled and has manual steps', function () {
+      controller.set('isSubmitDisabled', false);
+      controller.set('content.hasManualSteps', true);
+      controller.done();
+      expect(controller.removeObserver.calledWith('tasks.@each.status', controller, 'onTaskStatusChange')).to.be.true;
+      expect(App.router.send.calledWith('next')).to.be.true;
+    });
+  });
+
+  describe('#getServiceConfigData()', function () {
+    var services = [];
+    var stackServices = [];
+    beforeEach(function () {
+      sinon.stub(App.Service, 'find', function () {
+        return services;
+      });
+      sinon.stub(App.StackService, 'find', function () {
+        return stackServices;
+      });
+    });
+    afterEach(function () {
+      App.Service.find.restore();
+      App.StackService.find.restore();
+    });
+
+    it('No services', function () {
+      services = [];
+      controller.set('content.reassign.component_name', 'COMP1');
+      expect(controller.getServiceConfigData([])).to.eql([]);
+    });
+    it('No services in stackServices', function () {
+      services = [Em.Object.create({serviceName: 'S1'})];
+      stackServices = [];
+      controller.set('content.reassign.component_name', 'COMP1');
+      expect(controller.getServiceConfigData([])).to.eql([]);
+    });
+    it('Services in stackServicesm but configTypesRendered is empty', function () {
+      services = [Em.Object.create({serviceName: 'S1'})];
+      stackServices = [Em.Object.create({
+        serviceName: 'S1',
+        configTypesRendered: {}
+      })];
+      controller.set('content.reassign.component_name', 'COMP1');
+      expect(controller.getServiceConfigData([])[0]).to.equal("{\"Clusters\":{\"desired_config\":[]}}");
+    });
+    it('Services in stackServicesm and configTypesRendered has data, but configs is empty', function () {
+      services = [Em.Object.create({serviceName: 'S1'})];
+      stackServices = [
+        Em.Object.create({
+          serviceName: 'S1',
+          configTypesRendered: {'type1': {}}
+        })
+      ];
+      controller.set('content.reassign.component_name', 'COMP1');
+      expect(controller.getServiceConfigData([])[0]).to.equal("{\"Clusters\":{\"desired_config\":[]}}");
+    });
+    it('Services in stackServicesm and configTypesRendered has data, and configs present', function () {
+      services = [Em.Object.create({serviceName: 'S1'})];
+      stackServices = [
+        Em.Object.create({
+          serviceName: 'S1',
+          configTypesRendered: {'type1': {}}
+        })
+      ];
+      var configs = {
+        'type1': {
+          'prop1': 'value1'
+        }
+      };
+      controller.set('content.reassign.component_name', 'COMP1');
+      expect(JSON.parse(controller.getServiceConfigData(configs)[0]).Clusters.desired_config.length).to.equal(1);
+    });
+
+  });
+});

+ 207 - 0
ambari-web/test/controllers/main/service/reassign/step6_controller_test.js

@@ -0,0 +1,207 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+App = require('app');
+
+require('controllers/main/service/reassign/step6_controller');
+
+describe('App.ReassignMasterWizardStep6Controller', function () {
+
+  var controller = App.ReassignMasterWizardStep6Controller.create({
+    content: Em.Object.create({
+      reassign: Em.Object.create(),
+      reassignHosts: Em.Object.create()
+    })
+  });
+
+  beforeEach(function () {
+    sinon.stub(App.ajax, 'send', Em.K);
+  });
+  afterEach(function () {
+    App.ajax.send.restore();
+  });
+
+
+  describe('#initializeTasks()', function () {
+    it('No commands', function () {
+      controller.set('commands', []);
+      controller.set('hostComponents', []);
+      controller.initializeTasks();
+
+      expect(controller.get('tasks')).to.be.empty;
+    });
+    it('One command', function () {
+      controller.set('commands', ['COMMAND1']);
+      controller.initializeTasks();
+
+      expect(controller.get('tasks')[0].get('id')).to.equal(0);
+      expect(controller.get('tasks')[0].get('command')).to.equal('COMMAND1');
+    });
+  });
+
+  describe('#hideRollbackButton()', function () {
+
+    it('No showRollback command', function () {
+      controller.set('tasks', [Em.Object.create({
+        showRollback: false
+      })]);
+      controller.hideRollbackButton();
+      expect(controller.get('tasks')[0].get('showRollback')).to.be.false;
+    });
+    it('showRollback command is present', function () {
+      controller.set('tasks', [Em.Object.create({
+        showRollback: true
+      })]);
+      controller.hideRollbackButton();
+      expect(controller.get('tasks')[0].get('showRollback')).to.be.false;
+    });
+  });
+
+  describe('#onComponentsTasksSuccess()', function () {
+    beforeEach(function () {
+      sinon.stub(controller, 'onTaskCompleted', Em.K);
+    });
+    afterEach(function () {
+      controller.onTaskCompleted.restore();
+    });
+
+    it('No host-components', function () {
+      controller.set('multiTaskCounter', 0);
+      controller.set('hostComponents', []);
+      controller.onComponentsTasksSuccess();
+      expect(controller.get('multiTaskCounter')).to.equal(1);
+      expect(controller.onTaskCompleted.calledOnce).to.be.true;
+    });
+    it('One host-component', function () {
+      controller.set('multiTaskCounter', 0);
+      controller.set('hostComponents', [
+        {}
+      ]);
+      controller.onComponentsTasksSuccess();
+      expect(controller.get('multiTaskCounter')).to.equal(1);
+      expect(controller.onTaskCompleted.calledOnce).to.be.true;
+    });
+    it('two host-components', function () {
+      controller.set('multiTaskCounter', 0);
+      controller.set('hostComponents', [
+        {},
+        {}
+      ]);
+      controller.onComponentsTasksSuccess();
+      expect(controller.get('multiTaskCounter')).to.equal(1);
+      expect(controller.onTaskCompleted.called).to.be.false;
+    });
+  });
+
+
+  describe('#loadStep()', function () {
+    var isHaEnabled = true;
+
+    beforeEach(function () {
+      controller.set('content.reassign.service_id', 'service1');
+      sinon.stub(controller, 'onTaskStatusChange', Em.K);
+      sinon.stub(controller, 'initializeTasks', Em.K);
+      sinon.stub(App, 'get', function () {
+        return isHaEnabled;
+      });
+    });
+    afterEach(function () {
+      controller.onTaskStatusChange.restore();
+      controller.initializeTasks.restore();
+      App.get.restore();
+    });
+
+    it('reassign component is NameNode and HA enabled', function () {
+      isHaEnabled = true;
+      controller.set('content.reassign.component_name', 'NAMENODE');
+
+      controller.loadStep();
+      expect(controller.get('hostComponents')).to.eql(['NAMENODE', 'ZKFC']);
+    });
+    it('reassign component is NameNode and HA disabled', function () {
+      isHaEnabled = false;
+      controller.set('content.reassign.component_name', 'NAMENODE');
+
+      controller.loadStep();
+      expect(controller.get('hostComponents')).to.eql(['NAMENODE']);
+    });
+    it('reassign component is RESOURCEMANAGER', function () {
+      controller.set('content.reassign.component_name', 'RESOURCEMANAGER');
+
+      controller.loadStep();
+      expect(controller.get('hostComponents')).to.eql(['RESOURCEMANAGER']);
+    });
+  });
+
+  describe('#startServices()', function () {
+    it('', function () {
+      controller.startServices();
+      expect(App.ajax.send.calledOnce).to.be.true;
+    });
+  });
+
+  describe('#deleteHostComponents()', function () {
+
+    it('No host components', function () {
+      controller.set('hostComponents', []);
+      controller.set('content.reassignHosts.source', 'host1');
+      controller.deleteHostComponents();
+      expect(App.ajax.send.called).to.be.false;
+    });
+    it('delete two components', function () {
+      controller.set('hostComponents', [1, 2]);
+      controller.set('content.reassignHosts.source', 'host1');
+      controller.deleteHostComponents();
+      expect(App.ajax.send.getCall(0).args[0].data).to.eql({
+        "hostName": "host1",
+        "componentName": 1
+      });
+      expect(App.ajax.send.getCall(1).args[0].data).to.eql({
+        "hostName": "host1",
+        "componentName": 2
+      });
+    });
+  });
+
+  describe('#onDeleteHostComponentsError()', function () {
+    beforeEach(function () {
+      sinon.stub(controller, 'onComponentsTasksSuccess', Em.K);
+      sinon.stub(controller, 'onTaskError', Em.K);
+    });
+    afterEach(function () {
+      controller.onComponentsTasksSuccess.restore();
+      controller.onTaskError.restore();
+    });
+
+    it('task success', function () {
+      var error = {
+        responseText: 'org.apache.ambari.server.controller.spi.NoSuchResourceException'
+      }
+      controller.onDeleteHostComponentsError(error);
+      expect(controller.onComponentsTasksSuccess.calledOnce).to.be.true;
+    });
+    it('unknown error', function () {
+      var error = {
+        responseText: ''
+      }
+      controller.onDeleteHostComponentsError(error);
+      expect(controller.onTaskError.calledOnce).to.be.true;
+    });
+  });
+
+});