You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by on...@apache.org on 2014/04/17 14:24:40 UTC

git commit: AMBARI-5492. Unit tests for steps 5. (onechiporenko)

Repository: ambari
Updated Branches:
  refs/heads/trunk 9935ff8a5 -> 8b385e075


AMBARI-5492. Unit tests for steps 5. (onechiporenko)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/8b385e07
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/8b385e07
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/8b385e07

Branch: refs/heads/trunk
Commit: 8b385e0751ac0a407cd13cff158b1df6dfae097b
Parents: 9935ff8
Author: Oleg Nechiporenko <on...@apache.org>
Authored: Thu Apr 17 15:19:36 2014 +0300
Committer: Oleg Nechiporenko <on...@apache.org>
Committed: Thu Apr 17 15:24:33 2014 +0300

----------------------------------------------------------------------
 ambari-web/app/assets/test/tests.js             |   1 +
 .../app/controllers/wizard/step5_controller.js  | 475 +++++-----
 ambari-web/app/templates/wizard/step5.hbs       |  21 +-
 ambari-web/app/views/wizard/step5_view.js       | 142 ++-
 ambari-web/test/installer/step5_test.js         | 880 ++++++++++++++++++-
 ambari-web/test/views/main/host/summary_test.js |   4 -
 ambari-web/test/views/wizard/step5_view_test.js | 300 +++++++
 7 files changed, 1536 insertions(+), 287 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/8b385e07/ambari-web/app/assets/test/tests.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/assets/test/tests.js b/ambari-web/app/assets/test/tests.js
index a3352fe..61a1e70 100644
--- a/ambari-web/app/assets/test/tests.js
+++ b/ambari-web/app/assets/test/tests.js
@@ -132,6 +132,7 @@ require('test/views/wizard/step0_view_test');
 require('test/views/wizard/step1_view_test');
 require('test/views/wizard/step2_view_test');
 require('test/views/wizard/step3_view_test');
+require('test/views/wizard/step5_view_test');
 require('test/views/wizard/step9_view_test');
 require('test/models/host_test');
 require('test/models/host_component_test');

http://git-wip-us.apache.org/repos/asf/ambari/blob/8b385e07/ambari-web/app/controllers/wizard/step5_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/wizard/step5_controller.js b/ambari-web/app/controllers/wizard/step5_controller.js
index cbe7aba..74cc401 100644
--- a/ambari-web/app/controllers/wizard/step5_controller.js
+++ b/ambari-web/app/controllers/wizard/step5_controller.js
@@ -21,7 +21,13 @@ var numberUtils = require('utils/number_utils');
 
 App.WizardStep5Controller = Em.Controller.extend({
 
-  name:"wizardStep5Controller",
+  name: "wizardStep5Controller",
+
+  /**
+   * Step title
+   * Custom if <code>App.ReassignMasterController</code> is used
+   * @type {string}
+   */
   title: function () {
     if (this.get('content.controllerName') == 'reassignMasterController') {
       return Em.I18n.t('installer.step5.reassign.header');
@@ -29,23 +35,39 @@ App.WizardStep5Controller = Em.Controller.extend({
     return Em.I18n.t('installer.step5.header');
   }.property('content.controllerName'),
 
+  /**
+   * Is ReassignWizard used
+   * @type {bool}
+   */
   isReassignWizard: function () {
     return this.get('content.controllerName') == 'reassignMasterController';
   }.property('content.controllerName'),
 
-  isAddServiceWizard: function() {
+  /**
+   * Is AddServiceWizard used
+   * @type {bool}
+   */
+  isAddServiceWizard: function () {
     return this.get('content.controllerName') == 'addServiceController';
   }.property('content.controllerName'),
 
+  /**
+   * Is Hive reassigning
+   * @type {bool}
+   */
   isReassignHive: function () {
     return this.get('servicesMasters').objectAt(0) && this.get('servicesMasters').objectAt(0).component_name == 'HIVE_SERVER' && this.get('isReassignWizard');
   }.property('isReassignWizard', 'servicesMasters'),
+
   /**
-   * master components which could be assigned to multiple hosts
+   * Master components which could be assigned to multiple hosts
+   * @type {string[]}
    */
   multipleComponents: ['ZOOKEEPER_SERVER', 'HBASE_MASTER'],
+
   /**
    * Define state for submit button. Return true only for Reassign Master Wizard and if more than one master component was reassigned.
+   * @type {bool}
    */
   isSubmitDisabled: function () {
     if (!this.get('isReassignWizard')) {
@@ -62,28 +84,104 @@ App.WizardStep5Controller = Em.Controller.extend({
     return reassigned !== 1;
   }.property('servicesMasters.@each.selectedHost'),
 
-  hosts:[],
+  /**
+   * List of hosts
+   * @type {Array}
+   */
+  hosts: [],
 
+  /**
+   * @type {Object|null}
+   */
   componentToRebalance: null,
+
+  /**
+   * @type {number}
+   */
   rebalanceComponentHostsCounter: 0,
 
-  servicesMasters:[],
-  selectedServicesMasters:[],
+  /**
+   * @type {Ember.Enumerable}
+   */
+  servicesMasters: [],
+
+  /**
+   * @type {Ember.Enumerable}
+   */
+  selectedServicesMasters: [],
+
+  /**
+   * Check if HIVE_SERVER component exist (also checks if this is not reassign)
+   * @type {bool}
+   */
+  hasHiveServer: function () {
+    return this.get('selectedServicesMasters').someProperty('component_name', 'HIVE_SERVER') && !this.get('isReassignWizard');
+  }.property('selectedServicesMasters'),
+
+  /**
+   * List of host with assigned masters
+   * Format:
+   * <code>
+   *   [
+   *     {
+   *       host_name: '',
+   *       hostInfo: {},
+   *       masterServices: []
+   *    },
+   *    ....
+   *   ]
+   * </code>
+   * @type {Ember.Enumerable}
+   */
+  masterHostMapping: function () {
+    var mapping = [], mappingObject, mappedHosts, hostObj;
+    //get the unique assigned hosts and find the master services assigned to them
+    mappedHosts = this.get("selectedServicesMasters").mapProperty("selectedHost").uniq();
+    mappedHosts.forEach(function (item) {
+      hostObj = this.get("hosts").findProperty("host_name", item);
+
+      mappingObject = Em.Object.create({
+        host_name: item,
+        hostInfo: hostObj.host_info,
+        masterServices: this.get("selectedServicesMasters").filterProperty("selectedHost", item)
+      });
+
+      mapping.pushObject(mappingObject);
+    }, this);
+
+    return mapping.sortProperty('host_name');
+  }.property("selectedServicesMasters.@each.selectedHost"),
+
+  /**
+   * Count of hosts without masters
+   * @type {number}
+   */
+  remainingHosts: function () {
+    return (this.get("hosts.length") - this.get("masterHostMapping.length"));
+  }.property("selectedServicesMasters.@each.selectedHost"),
 
-  clearStep:function () {
+  /**
+   * Clear controller data (hosts, masters etc)
+   * @method clearStep
+   */
+  clearStep: function () {
     this.set('hosts', []);
     this.set('selectedServicesMasters', []);
     this.set('servicesMasters', []);
   },
 
-  loadStep:function () {
+  /**
+   * Load controller data (hosts, host components etc)
+   * @method loadStep
+   */
+  loadStep: function () {
     console.log("WizardStep5Controller: Loading step5: Assign Masters");
     this.clearStep();
     this.renderHostInfo();
     this.renderComponents(this.loadComponents());
 
     this.updateComponent('ZOOKEEPER_SERVER');
-    if(App.supports.multipleHBaseMasters){
+    if (App.supports.multipleHBaseMasters) {
       this.updateComponent('HBASE_MASTER');
     }
 
@@ -95,29 +193,31 @@ App.WizardStep5Controller = Em.Controller.extend({
 
   /**
    * Used to set showAddControl flag for ZOOKEEPER_SERVER and HBASE_SERVER
+   * @method updateComponent
    */
-  updateComponent: function(componentName){
+  updateComponent: function (componentName) {
     var component = this.last(componentName);
-
+    if(!component) {
+      return;
+    }
     var services = this.get('content.services').filterProperty('isInstalled', true).mapProperty('serviceName');
     var currentService = componentName.split('_')[0];
     var showControl = !services.contains(currentService);
 
-    if (component) {
-      if(showControl){
-        if (this.get("selectedServicesMasters").filterProperty("component_name", componentName).length < this.get("hosts.length") && !this.get('isReassignWizard')) {
-          component.set('showAddControl', true);
-        } else {
-          component.set('showRemoveControl', false);
-        }
+    if (showControl) {
+      if (this.get("selectedServicesMasters").filterProperty("component_name", componentName).length < this.get("hosts.length") && !this.get('isReassignWizard')) {
+        component.set('showAddControl', true);
+      } else {
+        component.set('showRemoveControl', false);
       }
     }
   },
 
   /**
    * Load active host list to <code>hosts</code> variable
+   * @method renderHostInfo
    */
-  renderHostInfo:function () {
+  renderHostInfo: function () {
 
     var hostInfo = this.get('content.hosts');
     var result = [];
@@ -125,12 +225,12 @@ App.WizardStep5Controller = Em.Controller.extend({
     for (var index in hostInfo) {
       var _host = hostInfo[index];
       if (_host.bootStatus === 'REGISTERED') {
-        result.push(Ember.Object.create({
-          host_name:_host.name,
+        result.push(Em.Object.create({
+          host_name: _host.name,
 
-          cpu:_host.cpu,
-          memory:_host.memory,
-          disk_info:_host.disk_info,
+          cpu: _host.cpu,
+          memory: _host.memory,
+          disk_info: _host.disk_info,
           host_info: Em.I18n.t('installer.step5.hostInfo').fmt(_host.name, numberUtils.bytesToSize(_host.memory, 1, 'parseFloat', 1024), _host.cpu)
         }));
       }
@@ -139,6 +239,10 @@ App.WizardStep5Controller = Em.Controller.extend({
     this.sortHosts(this.get('hosts'));
   },
 
+  /**
+   * Sort list of host-objects by properties (memory - desc, cpu - desc, hostname - asc)
+   * @param {object[]} hosts
+   */
   sortHosts: function (hosts) {
     hosts.sort(function (a, b) {
       if (a.get('memory') == b.get('memory')) {
@@ -153,12 +257,11 @@ App.WizardStep5Controller = Em.Controller.extend({
 
   /**
    * Load services info to appropriate variable and return masterComponentHosts
-   * @return Array
+   * @return {Object[]}
    */
-  loadComponents:function () {
+  loadComponents: function () {
 
-    var services = this.get('content.services')
-      .filterProperty('isSelected', true).mapProperty('serviceName'); //list of shown services
+    var services = this.get('content.services').filterProperty('isSelected', true).mapProperty('serviceName'); //list of shown services
 
     var masterComponents = App.StackServiceComponent.find().filterProperty('isShownOnInstallerAssignMasterPage', true); //get full list from mock data
     var masterHosts = this.get('content.masterComponentHosts'); //saved to local storage info
@@ -216,18 +319,14 @@ App.WizardStep5Controller = Em.Controller.extend({
 
   /**
    * Put master components to <code>selectedServicesMasters</code>, which will be automatically rendered in template
-   * @param masterComponents
+   * @param {Ember.Enumerable} masterComponents
+   * @method renderComponents
    */
-  renderComponents:function (masterComponents) {
-    var self = this;
-    var services = this.get('content.services')
-      .filterProperty('isInstalled', true).mapProperty('serviceName'); //list of shown services
+  renderComponents: function (masterComponents) {
+    var services = this.get('content.services').filterProperty('isInstalled', true).mapProperty('serviceName'); //list of shown services
     var showRemoveControlZk = !services.contains('ZOOKEEPER') && masterComponents.filterProperty('component_name', 'ZOOKEEPER_SERVER').length > 1;
     var showRemoveControlHb = !services.contains('HBASE') && masterComponents.filterProperty('component_name', 'HBASE_MASTER').length > 1;
-    var zid = 1;
-    var hid = 1;
-    var nid = 1;
-    var result = [];
+    var zid = 1, hid = 1, nid = 1, result = [], self = this;
 
     masterComponents.forEach(function (item) {
 
@@ -239,17 +338,23 @@ App.WizardStep5Controller = Em.Controller.extend({
         }
       }
 
-      var componentObj = Ember.Object.create(item);
+      var componentObj = Em.Object.create(item);
       console.log("TRACE: render master component name is: " + item.component_name);
 
       if (item.component_name === "ZOOKEEPER_SERVER") {
         componentObj.set('zId', zid++);
         componentObj.set("showRemoveControl", showRemoveControlZk);
-      } else if (App.supports.multipleHBaseMasters && item.component_name === "HBASE_MASTER") {
-        componentObj.set('zId', hid++);
-        componentObj.set("showRemoveControl", showRemoveControlHb);
-      }  else if (item.component_name === "NAMENODE") {
-        componentObj.set('zId', nid++);
+      }
+      else {
+        if (App.supports.multipleHBaseMasters && item.component_name === "HBASE_MASTER") {
+          componentObj.set('zId', hid++);
+          componentObj.set("showRemoveControl", showRemoveControlHb);
+        }
+        else {
+          if (item.component_name === "NAMENODE") {
+            componentObj.set('zId', nid++);
+          }
+        }
       }
       result.push(componentObj);
     }, this);
@@ -259,24 +364,25 @@ App.WizardStep5Controller = Em.Controller.extend({
       var components = result.filterProperty('component_name', this.get('content.reassign.component_name'));
       components.setEach('isInstalled', false);
       this.set('servicesMasters', components);
-    } else {
+    }
+    else {
       this.set('servicesMasters', result);
     }
   },
 
-  hasHiveServer: function () {
-    return !!this.get('selectedServicesMasters').findProperty('component_name', 'HIVE_SERVER') && !this.get('isReassignWizard');
-  }.property('selectedServicesMasters'),
-
+  /**
+   * Update host for components HIVE_METASTORE and WEBHCAT_SERVER according to host with HIVE_SERVER
+   * @method updateHiveCoHosts
+   */
   updateHiveCoHosts: function () {
-    var hiveServer =  this.get('selectedServicesMasters').findProperty('component_name', 'HIVE_SERVER');
-    var hiveMetastore = this.get('selectedServicesMasters').findProperty('component_name', 'HIVE_METASTORE');
-    var webHCatServer = this.get('selectedServicesMasters').findProperty('component_name', 'WEBHCAT_SERVER');
+    var hiveServer = this.get('selectedServicesMasters').findProperty('component_name', 'HIVE_SERVER'),
+      hiveMetastore = this.get('selectedServicesMasters').findProperty('component_name', 'HIVE_METASTORE'),
+      webHCatServer = this.get('selectedServicesMasters').findProperty('component_name', 'WEBHCAT_SERVER');
     if (hiveServer && hiveMetastore && webHCatServer) {
       if (!this.get('isReassignHive') && this.get('servicesMasters').objectAt(0) && !(this.get('servicesMasters').objectAt(0).component_name == 'HIVE_METASTORE')) {
-        this.get('selectedServicesMasters').findProperty('component_name', 'HIVE_METASTORE').set('selectedHost', hiveServer.get('selectedHost'))
+        hiveMetastore.set('selectedHost', hiveServer.get('selectedHost'))
       }
-      this.get('selectedServicesMasters').findProperty('component_name', 'WEBHCAT_SERVER').set('selectedHost', hiveServer.get('selectedHost'));
+      webHCatServer.set('selectedHost', hiveServer.get('selectedHost'));
     }
   }.observes('selectedServicesMasters.@each.selectedHost'),
 
@@ -286,18 +392,19 @@ App.WizardStep5Controller = Em.Controller.extend({
    * if key more that number of hosts, then return value of that key.
    * Value is index of host in hosts array.
    *
-   * @param noOfHosts
-   * @param selectionScheme
-   * @return {*}
+   * @param {number} noOfHosts
+   * @param {object} selectionScheme
+   * @return {string}
+   * @method getHostForComponent
    */
-  getHostForComponent: function(noOfHosts, selectionScheme){
+  getHostForComponent: function (noOfHosts, selectionScheme) {
     var hosts = this.get('hosts');
-    if(hosts.length === 1 || $.isEmptyObject(selectionScheme)){
+    if (hosts.length === 1 || $.isEmptyObject(selectionScheme)) {
       return hosts[0];
     } else {
-      for(var i in selectionScheme){
-        if(window.isFinite(i)){
-          if(noOfHosts < window.parseInt(i)){
+      for (var i in selectionScheme) {
+        if (window.isFinite(i)) {
+          if (noOfHosts < window.parseInt(i)) {
             return hosts[selectionScheme[i]];
           }
         }
@@ -306,7 +413,13 @@ App.WizardStep5Controller = Em.Controller.extend({
     }
   },
 
-  getZooKeeperServer:function (noOfHosts) {
+  /**
+   * Get list of hostnames for ZK Server
+   * @param {number} noOfHosts
+   * @returns {string[]}
+   * @method getZooKeeperServer
+   */
+  getZooKeeperServer: function (noOfHosts) {
     var hosts = this.get('hosts');
     if (noOfHosts < 3) {
       return [hosts[0].host_name];
@@ -315,7 +428,13 @@ App.WizardStep5Controller = Em.Controller.extend({
     }
   },
 
-  getGangliaServer:function (noOfHosts) {
+  /**
+   * Get hostname based on number of available hosts
+   * @param {number} noOfHosts
+   * @returns {string}
+   * @method getServerHost
+   */
+  getServerHost: function (noOfHosts) {
     var hostNames = this.get('hosts').mapProperty('host_name');
     var hostExcAmbari = hostNames.without(location.hostname);
     if (noOfHosts > 1) {
@@ -325,157 +444,53 @@ App.WizardStep5Controller = Em.Controller.extend({
     }
   },
 
-  getNagiosServer:function (noOfHosts) {
-    return this.getGangliaServer(noOfHosts);
-  },
-
-  getHueServer:function (noOfHosts) {
-    return this.getGangliaServer(noOfHosts);
-  },
-
-  getOozieServer:function(){
-    return this.selectHost('OOZIE_SERVER');
-  },
-
-  getNimbusServer: function(noOfHosts) {
-    return this.getGangliaServer(noOfHosts);
-  },
   /**
    * Return hostName of masterNode for specified service
    * @param componentName
-   * @return {*}
+   * @return {string|string[]}
+   * @method selectHost
    */
-  selectHost:function (componentName) {
+  selectHost: function (componentName) {
     var noOfHosts = this.get('hosts').length;
-    switch (componentName) {
-      case 'KERBEROS_SERVER':
-        return this.getHostForComponent(noOfHosts, {
-          "3" : 1,
-          "6" : 1,
-          "31" : 3,
-          "else" : 5
-        }).host_name;
-      case 'NAMENODE':
-        return this.getHostForComponent(noOfHosts, {
-          "else" : 0
-        }).host_name;
-      case 'SECONDARY_NAMENODE':
-        return this.getHostForComponent(noOfHosts, {
-          "else" : 1
-        }).host_name;
-      case 'JOBTRACKER':
-        return this.getHostForComponent(noOfHosts, {
-          "3" : 1,
-          "6" : 1,
-          "31" : 1,
-          "else" : 2
-        }).host_name;
-      case 'HISTORYSERVER':
-        return this.getHostForComponent(noOfHosts, {
-          "3" : 1,
-          "6" : 1,
-          "31" : 1,
-          "else" : 2
-        }).host_name;
-      case 'RESOURCEMANAGER':
-        return this.getHostForComponent(noOfHosts, {
-          "3" : 1,
-          "6" : 1,
-          "31" : 1,
-          "else" : 2
-        }).host_name;
-      case 'HBASE_MASTER':
-        return [this.getHostForComponent(noOfHosts, {
-          "3" : 0,
-          "6" : 0,
-          "31" : 2,
-          "else" : 3
-        }).host_name];
-      case 'OOZIE_SERVER':
-        return this.getHostForComponent(noOfHosts, {
-          "3" : 1,
-          "6" : 1,
-          "31" : 2,
-          "else" : 3
-        }).host_name;
-      case 'HIVE_SERVER':
-        return this.getHostForComponent(noOfHosts, {
-          "3" : 1,
-          "6" : 1,
-          "31" : 2,
-          "else" : 4
-        }).host_name;
-      case 'HIVE_METASTORE':
-        return this.getHostForComponent(noOfHosts, {
-          "3" : 1,
-          "6" : 1,
-          "31" : 2,
-          "else" : 4
-        }).host_name;
-      case 'WEBHCAT_SERVER':
-        return this.getHostForComponent(noOfHosts, {
-          "3" : 1,
-          "6" : 1,
-          "31" : 2,
-          "else" : 4
-        }).host_name;
-      case 'ZOOKEEPER_SERVER':
-        return this.getZooKeeperServer(noOfHosts);
-      case 'GANGLIA_SERVER':
-        return this.getGangliaServer(noOfHosts);
-      case 'NAGIOS_SERVER':
-        return this.getNagiosServer(noOfHosts);
-      case 'HUE_SERVER':
-        return this.getHueServer(noOfHosts);
-      case 'APP_TIMELINE_SERVER':
-        return this.getHostForComponent(noOfHosts, {
-          "3" : 1,
-          "6" : 1,
-          "31" : 1,
-          "else" : 2
-        }).host_name;
-      case 'FALCON_SERVER':
-        return this.getOozieServer(noOfHosts);
-      case 'STORM_UI_SERVER':
-      case 'DRPC_SERVER':
-      case 'STORM_REST_API':
-      case 'NIMBUS':
-        return this.getNimbusServer(noOfHosts);
-      default:
-    }
-  },
 
-  masterHostMapping: function () {
-    var mapping = [], mappingObject, mappedHosts, hostObj;
-    //get the unique assigned hosts and find the master services assigned to them
-    mappedHosts = this.get("selectedServicesMasters").mapProperty("selectedHost").uniq();
-    mappedHosts.forEach(function (item) {
-      hostObj = this.get("hosts").findProperty("host_name", item);
+    if (componentName === 'KERBEROS_SERVER')
+      return this.getHostForComponent(noOfHosts, {"3": 1, "6": 1, "31": 3, "else": 5}).host_name;
 
-      mappingObject = Ember.Object.create({
-        host_name: item,
-        hostInfo: hostObj.host_info,
-        masterServices: this.get("selectedServicesMasters").filterProperty("selectedHost", item)
-      });
+    if (componentName === 'NAMENODE')
+      return this.getHostForComponent(noOfHosts, {"else": 0}).host_name;
 
-      mapping.pushObject(mappingObject);
-    }, this);
+    if (componentName === 'SECONDARY_NAMENODE')
+      return this.getHostForComponent(noOfHosts, {"else": 1}).host_name;
 
-    return mapping.sortProperty('host_name');
-  }.property("selectedServicesMasters.@each.selectedHost"),
+    if (componentName === 'HBASE_MASTER')
+      return [this.getHostForComponent(noOfHosts, {"3": 0, "6": 0, "31": 2, "else": 3}).host_name];
 
-  remainingHosts:function () {
-    return (this.get("hosts.length") - this.get("masterHostMapping.length"));
-  }.property("selectedServicesMasters.@each.selectedHost"),
+    if (componentName === 'ZOOKEEPER_SERVER')
+      return this.getZooKeeperServer(noOfHosts);
+
+    if (['JOBTRACKER', 'HISTORYSERVER', 'RESOURCEMANAGER', 'APP_TIMELINE_SERVER'].contains(componentName))
+      return this.getHostForComponent(noOfHosts, {"3": 1, "6": 1, "31": 1, "else": 2}).host_name;
+
+    if (['OOZIE_SERVER', 'FALCON_SERVER'].contains(componentName))
+      return this.getHostForComponent(noOfHosts, {"3": 1, "6": 1, "31": 2, "else": 3}).host_name;
+
+    if (['HIVE_SERVER', 'HIVE_METASTORE', 'WEBHCAT_SERVER'].contains(componentName))
+      return this.getHostForComponent(noOfHosts, {"3": 1, "6": 1, "31": 2, "else": 4}).host_name;
 
+    if (['STORM_UI_SERVER', 'DRPC_SERVER', 'STORM_REST_API', 'NIMBUS', 'GANGLIA_SERVER', 'NAGIOS_SERVER', 'HUE_SERVER'].contains(componentName))
+      return this.getServerHost(noOfHosts);
+
+    return '';
+  },
 
   /**
    * On change callback for selects
-   * @param componentName
-   * @param selectedHost
-   * @param zId
+   * @param {string} componentName
+   * @param {string} selectedHost
+   * @param {number} zId
+   * @method assignHostToMaster
    */
-  assignHostToMaster:function (componentName, selectedHost, zId) {
+  assignHostToMaster: function (componentName, selectedHost, zId) {
     if (selectedHost && componentName) {
       if (zId) {
         this.get('selectedServicesMasters').filterProperty('component_name', componentName).findProperty("zId", zId).set("selectedHost", selectedHost);
@@ -487,19 +502,21 @@ App.WizardStep5Controller = Em.Controller.extend({
 
   /**
    * Returns last component of selected type
-   * @param componentName
-   * @return {*}
+   * @param {string} componentName
+   * @return {Em.Object|null}
+   * @method last
    */
-  last: function(componentName){
+  last: function (componentName) {
     return this.get("selectedServicesMasters").filterProperty("component_name", componentName).get("lastObject");
   },
 
   /**
    * Add new component to ZooKeeper Server and Hbase master
-   * @param componentName
-   * @return {Boolean}
+   * @param {string} componentName
+   * @return {bool} true - added, false - not added
+   * @method addComponent
    */
-  addComponent:function (componentName) {
+  addComponent: function (componentName) {
     /*
      * Logic: If ZooKeeper or Hbase service is selected then there can be
      * minimum 1 ZooKeeper or Hbase master in total, and
@@ -525,7 +542,7 @@ App.WizardStep5Controller = Em.Controller.extend({
       currentMasters.set("lastObject.showRemoveControl", true);
 
       //create a new zookeeper based on an existing one
-      newMaster = Ember.Object.create({});
+      newMaster = Em.Object.create({});
       lastMaster = currentMasters.get("lastObject");
       newMaster.set("display_name", lastMaster.get("display_name"));
       newMaster.set("component_name", lastMaster.get("component_name"));
@@ -564,46 +581,44 @@ App.WizardStep5Controller = Em.Controller.extend({
 
   /**
    * Remove component from ZooKeeper server or Hbase Master
-   * @param componentName
-   * @param zId
-   * @return {Boolean}
+   * @param {string} componentName
+   * @param {number} zId
+   * @return {bool} true - removed, false - no
+   * @method removeComponent
    */
-  removeComponent:function (componentName, zId) {
+  removeComponent: function (componentName, zId) {
     var currentMasters = this.get("selectedServicesMasters").filterProperty("component_name", componentName);
 
     //work only if the Zookeeper service is selected in previous step
-    if (!currentMasters.length) {
+    if (currentMasters.length <= 1) {
       return false;
     }
 
-    if (currentMasters.get("length") > 1) {
-      this.get("selectedServicesMasters").removeAt(this.get("selectedServicesMasters").indexOf(currentMasters.findProperty("zId", zId)));
-
-      currentMasters = this.get("selectedServicesMasters").filterProperty("component_name", componentName);
-      if (currentMasters.get("length") < this.get("hosts.length")) {
-        currentMasters.set("lastObject.showAddControl", true);
-      }
-
-      if (currentMasters.get("length") === 1) {
-        currentMasters.set("lastObject.showRemoveControl", false);
-      }
+    this.get("selectedServicesMasters").removeAt(this.get("selectedServicesMasters").indexOf(currentMasters.findProperty("zId", zId)));
 
-      this.set('componentToRebalance', componentName);
-      this.incrementProperty('rebalanceComponentHostsCounter');
+    currentMasters = this.get("selectedServicesMasters").filterProperty("component_name", componentName);
+    if (currentMasters.get("length") < this.get("hosts.length")) {
+      currentMasters.set("lastObject.showAddControl", true);
+    }
 
-      return true;
+    if (currentMasters.get("length") === 1) {
+      currentMasters.set("lastObject.showRemoveControl", false);
     }
 
-    return false;
+    this.set('componentToRebalance', componentName);
+    this.incrementProperty('rebalanceComponentHostsCounter');
 
+    return true;
   },
 
+  /**
+   * Submit button click handler
+   * @metohd submit
+   */
   submit: function () {
-    if (!this.get('isSubmitDisabled')){
+    if (!this.get('isSubmitDisabled')) {
       App.router.send('next');
     }
   }
-});
-
-
 
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/8b385e07/ambari-web/app/templates/wizard/step5.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/wizard/step5.hbs b/ambari-web/app/templates/wizard/step5.hbs
index fb453d7..31619a7 100644
--- a/ambari-web/app/templates/wizard/step5.hbs
+++ b/ambari-web/app/templates/wizard/step5.hbs
@@ -18,7 +18,7 @@
 
 <h2>{{title}}</h2>
 <div class="alert alert-info">
-  {{view.body}}
+  {{t installer.step5.body}}
   {{#if hasHiveServer}}
     <br>
     {{t installer.step5.body.hive}}
@@ -30,7 +30,8 @@
       {{#if showCurrentHost}}
         <div class="span12 control-group mlc">
           <div class="row-fluid">
-            <div class="span4"><span class="pull-right control-label">{{t services.reassign.step2.currentHost}}</span></div>
+            <div class="span4"><span class="pull-right control-label">{{t services.reassign.step2.currentHost}}</span>
+            </div>
             <div class="span8"><span>{{currentHostId}}</span></div>
           </div>
         </div>
@@ -86,17 +87,17 @@
 
   <div class="host-assignments span5">
     {{#each masterHostMapping}}
-    <div class="mapping-box round-corners well">
-      <div class="hostString"><span>{{hostInfo}}</span></div>
-      {{#each masterServices}}
-      <span {{bindAttr class="isInstalled:assignedService:newService :round-corners"}}>{{display_name}}</span>
-      {{/each}}
-    </div>
+      <div class="mapping-box round-corners well">
+        <div class="hostString"><span>{{hostInfo}}</span></div>
+        {{#each masterServices}}
+          <span {{bindAttr class="isInstalled:assignedService:newService :round-corners"}}>{{display_name}}</span>
+        {{/each}}
+      </div>
     {{/each}}
 
     {{#if remainingHosts}}
-    <div class="remaining-hosts round-corners well">
-      <span><strong>{{remainingHosts}}</strong> {{t installer.step5.attention}}</span></div>
+      <div class="remaining-hosts round-corners well">
+        <span><strong>{{remainingHosts}}</strong> {{t installer.step5.attention}}</span></div>
     {{/if}}
   </div>
   <div class="clearfix"></div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/8b385e07/ambari-web/app/views/wizard/step5_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/wizard/step5_view.js b/ambari-web/app/views/wizard/step5_view.js
index c0d501e..9a43a99 100644
--- a/ambari-web/app/views/wizard/step5_view.js
+++ b/ambari-web/app/views/wizard/step5_view.js
@@ -22,25 +22,58 @@ var lazyloading = require('utils/lazy_loading');
 
 App.WizardStep5View = Em.View.extend({
 
-  templateName:require('templates/wizard/step5'),
+  templateName: require('templates/wizard/step5'),
 
-  didInsertElement:function () {
+  didInsertElement: function () {
     this.get('controller').loadStep();
-  },
-
-  body: Em.I18n.t('installer.step5.body')
+  }
 
 });
 
 App.SelectHostView = Em.Select.extend({
-  content:[],
-  zId:null,
-  selectedHost:null,
-  componentName:null,
-  attributeBindings:['disabled'],
+
+  /**
+   * List of avaiable host names
+   * @type {string[]}
+   */
+  content: [],
+
+  /**
+   * Index for multiple component (like ZOOKEEPER_SERVER)
+   * @type {number|null}
+   */
+  zId: null,
+
+  /**
+   * Selected host name for host component
+   * @type {string}
+   */
+  selectedHost: null,
+
+  /**
+   * Host component name
+   * @type {string}
+   */
+  componentName: null,
+
+  attributeBindings: ['disabled'],
+
+  /**
+   * Is data loaded
+   * @type {bool}
+   */
   isLoaded: false,
+
+  /**
+   * Is lazy loading used
+   * @type {bool}
+   */
   isLazyLoading: false,
 
+  /**
+   * Handler for selected value change
+   * @method change
+   */
   change: function () {
     this.get('controller').assignHostToMaster(this.get("componentName"), this.get("value"), this.get("zId"));
     this.set('selectedHost', this.get('value'));
@@ -49,7 +82,8 @@ App.SelectHostView = Em.Select.extend({
   },
 
   /**
-   * recalculate available hosts
+   * Recalculate available hosts
+   * @method rebalanceComponentHosts
    */
   rebalanceComponentHosts: function () {
     if (this.get('componentName') === this.get('controller.componentToRebalance')) {
@@ -60,18 +94,21 @@ App.SelectHostView = Em.Select.extend({
   }.observes('controller.rebalanceComponentHostsCounter'),
 
   /**
-   * get available hosts
-   * @multipleComponents component can be assigned to multiple hosts,
+   * Get available hosts
+   * multipleComponents component can be assigned to multiple hosts,
    * shared hosts among the same component should be filtered out
-   * @return {*}
+   * @return {string[]}
+   * @method getAvailableHosts
    */
   getAvailableHosts: function () {
-    var hosts = this.get('controller.hosts').slice();
-    var componentName = this.get('componentName');
-    var multipleComponents = this.get('controller.multipleComponents');
-    var occupiedHosts = this.get('controller.selectedServicesMasters')
-      .filterProperty('component_name', componentName)
-      .mapProperty('selectedHost').without(this.get('selectedHost'));
+    var hosts = this.get('controller.hosts').slice(),
+      componentName = this.get('componentName'),
+      multipleComponents = this.get('controller.multipleComponents'),
+      occupiedHosts = this.get('controller.selectedServicesMasters')
+        .filterProperty('component_name', componentName)
+        .mapProperty('selectedHost')
+        .without(this.get('selectedHost'));
+
     if (multipleComponents.contains(componentName)) {
       return hosts.filter(function (host) {
         return !occupiedHosts.contains(host.get('host_name'));
@@ -80,7 +117,8 @@ App.SelectHostView = Em.Select.extend({
     return hosts;
   },
   /**
-   * on click start lazy loading
+   * On click start lazy loading
+   * @method click
    */
   click: function () {
     var source = [];
@@ -90,7 +128,7 @@ App.SelectHostView = Em.Select.extend({
 
     if (!this.get('isLoaded') && this.get('isLazyLoading')) {
       //filter out hosts, which already pushed in select
-      source = availableHosts.filter(function(_host){
+      source = availableHosts.filter(function (_host) {
         return !this.get('content').someProperty('host_name', _host.host_name);
       }, this).slice();
       lazyloading.run({
@@ -112,10 +150,12 @@ App.SelectHostView = Em.Select.extend({
     this.initContent();
     this.set("value", this.get("selectedHost"));
   },
+
   /**
-   * extract hosts from controller,
+   * Extract hosts from controller,
    * filter out available to selection and
    * push them into Em.Select content
+   * @method initContent
    */
   initContent: function () {
     var hosts = this.getAvailableHosts();
@@ -126,31 +166,63 @@ App.SelectHostView = Em.Select.extend({
         initialHosts.unshift(hosts.findProperty('host_name', this.get('selectedHost')));
       }
       this.set("content", initialHosts);
-    } else {
+    }
+    else {
       this.set("content", hosts);
     }
   }
 });
 
 App.AddControlView = Em.View.extend({
-  componentName:null,
-  tagName:"span",
-  classNames:["badge", "badge-important"],
-  template:Ember.Handlebars.compile('+'),
 
-  click:function () {
+  /**
+   * Current component name
+   * @type {string}
+   */
+  componentName: null,
+
+  tagName: "span",
+
+  classNames: ["badge", "badge-important"],
+
+  template: Em.Handlebars.compile('+'),
+
+  /**
+   * Onclick handler
+   * Add selected component
+   * @method click
+   */
+  click: function () {
     this.get('controller').addComponent(this.get('componentName'));
   }
 });
 
 App.RemoveControlView = Em.View.extend({
-  zId:null,
-  componentName:null,
-  tagName:"span",
-  classNames:["badge", "badge-important"],
-  template:Ember.Handlebars.compile('-'),
 
-  click:function () {
+  /**
+   * Index for multiple component
+   * @type {number}
+   */
+  zId: null,
+
+  /**
+   * Current component name
+   * @type {string}
+   */
+  componentName: null,
+
+  tagName: "span",
+
+  classNames: ["badge", "badge-important"],
+
+  template: Em.Handlebars.compile('-'),
+
+  /**
+   * Onclick handler
+   * Remove current component
+   * @method click
+   */
+  click: function () {
     this.get('controller').removeComponent(this.get('componentName'), this.get("zId"));
   }
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/8b385e07/ambari-web/test/installer/step5_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/installer/step5_test.js b/ambari-web/test/installer/step5_test.js
index c759820..72f347b 100644
--- a/ambari-web/test/installer/step5_test.js
+++ b/ambari-web/test/installer/step5_test.js
@@ -19,12 +19,16 @@
 var Ember = require('ember');
 var App = require('app');
 require('controllers/wizard/step5_controller');
-
+var c;
 describe('App.WizardStep5Controller', function () {
+  beforeEach(function() {
+    c = App.WizardStep5Controller.create();
+  });
   var controller = App.WizardStep5Controller.create();
   controller.set('content', {});
   var cpu = 2, memory = 4;
-  var schemes = [
+
+  var schemes = Em.A([
     {'description': 'empty condition'},
     {
       'description': 'second host if amount more than 1',
@@ -43,7 +47,8 @@ describe('App.WizardStep5Controller', function () {
       "31": 2,
       "else": 5
     }
-  ];
+  ]);
+
   var test_config = [
     {
       title: '1 host',
@@ -126,14 +131,14 @@ describe('App.WizardStep5Controller', function () {
     });
   });
 
-  describe('#getGangliaServer', function() {
+  describe('#getServerHost', function() {
     it('should be host name if one host ', function() {
       var hosts = [
         {host_name: 'host1'}
       ];
 
       controller.set('hosts', hosts);
-      expect(controller.getGangliaServer(hosts.length)).to.eql('host1');
+      expect(controller.getServerHost(hosts.length)).to.eql('host1');
     });
 
     it('should be host name if hosts number more than one', function() {
@@ -143,7 +148,7 @@ describe('App.WizardStep5Controller', function () {
       ];
 
       controller.set('hosts', hosts);
-      expect(controller.getGangliaServer(hosts.length)).to.eql('host1');
+      expect(controller.getServerHost(hosts.length)).to.eql('host1');
     });
 
     it('should be host name different from localhost if hosts number more than one', function() {
@@ -155,7 +160,7 @@ describe('App.WizardStep5Controller', function () {
       //to implement current test case
 
       controller.set('hosts', hosts);
-      expect(controller.getGangliaServer(hosts.length)).to.eql('host2');
+      expect(controller.getServerHost(hosts.length)).to.eql('host2');
     });
   });
 
@@ -173,4 +178,863 @@ describe('App.WizardStep5Controller', function () {
     });
   });
 
-});
+  describe('#isAddServiceWizard', function() {
+    it('true if content.controllerName is addServiceController', function() {
+      controller.set('content.controllerName', 'addServiceController');
+      expect(controller.get('isAddServiceWizard')).to.equal(true);
+    });
+    it('false if content.controllerName is not addServiceController', function() {
+      controller.set('content.controllerName', 'mainController');
+      expect(controller.get('isAddServiceWizard')).to.equal(false);
+    });
+  });
+
+  describe('#isReassignHive', function() {
+
+    var tests = Em.A([
+      {
+        servicesMasters: Em.A([{component_name: 'HIVE_SERVER'}]),
+        controllerName: 'reassignMasterController',
+        e: true
+      },
+      {
+        servicesMasters: Em.A([{component_name: 'HIVE_SERVER'}]),
+        controllerName: 'addServiceController',
+        e: false
+      },
+      {
+        servicesMasters: Em.A([{component_name: 'ZOOKEEPER_SERVER'}]),
+        controllerName: 'reassignMasterController',
+        e: false
+      },
+      {
+        servicesMasters: Em.A([{component_name: 'ZOOKEEPER_SERVER'}]),
+        controllerName: 'addServiceController',
+        e: false
+      }
+    ]);
+
+    tests.forEach(function(test) {
+      it(test.controllerName + ' ' + test.servicesMasters.mapProperty('component_name').join(','), function() {
+        controller.set('content.controllerName', test.controllerName);
+        controller.set('servicesMasters', test.servicesMasters);
+        expect(controller.get('isReassignHive')).to.equal(test.e);
+      });
+    });
+
+  });
+
+  describe('#sortHosts', function() {
+
+    var tests = Em.A([
+      {
+        hosts: [
+          Em.Object.create({memory: 4, cpu: 1, host_name: 'host1', id: 1}),
+          Em.Object.create({memory: 3, cpu: 1, host_name: 'host2', id: 2}),
+          Em.Object.create({memory: 2, cpu: 1, host_name: 'host3', id: 3}),
+          Em.Object.create({memory: 1, cpu: 1, host_name: 'host4', id: 4})
+        ],
+        m: 'memory',
+        e: [1,2,3,4]
+      },
+      {
+        hosts: [
+          Em.Object.create({memory: 1, cpu: 4, host_name: 'host1', id: 1}),
+          Em.Object.create({memory: 1, cpu: 3, host_name: 'host2', id: 2}),
+          Em.Object.create({memory: 1, cpu: 2, host_name: 'host3', id: 3}),
+          Em.Object.create({memory: 1, cpu: 1, host_name: 'host4', id: 4})
+        ],
+        m: 'cpu',
+        e: [1,2,3,4]
+      },
+      {
+        hosts: [
+          Em.Object.create({memory: 1, cpu: 1, host_name: 'host4', id: 1}),
+          Em.Object.create({memory: 1, cpu: 1, host_name: 'host2', id: 2}),
+          Em.Object.create({memory: 1, cpu: 1, host_name: 'host3', id: 3}),
+          Em.Object.create({memory: 1, cpu: 1, host_name: 'host1', id: 4})
+        ],
+        m: 'host_name',
+        e: [4,2,3,1]
+      },
+      {
+        hosts: [
+          Em.Object.create({memory: 2, cpu: 1, host_name: 'host1', id: 1}),
+          Em.Object.create({memory: 1, cpu: 2, host_name: 'host3', id: 2}),
+          Em.Object.create({memory: 1, cpu: 1, host_name: 'host4', id: 3}),
+          Em.Object.create({memory: 1, cpu: 1, host_name: 'host2', id: 4})
+        ],
+        m: 'mix',
+        e: [1,2,4,3]
+      }
+    ]);
+
+    tests.forEach(function(test) {
+      it(test.m, function() {
+        var hosts = Em.copy(test.hosts);
+        controller.sortHosts(hosts);
+        expect(Em.A(hosts).mapProperty('id')).to.eql(test.e);
+      });
+    });
+
+  });
+
+  describe('#renderHostInfo', function() {
+
+    var tests = Em.A([
+      {
+        hosts: {
+          h1: {memory: 4, cpu: 1, name: 'host1', bootStatus: 'INIT'},
+          h2: {memory: 3, cpu: 1, name: 'host2', bootStatus: 'INIT'},
+          h3: {memory: 2, cpu: 1, name: 'host3', bootStatus: 'INIT'},
+          h4: {memory: 1, cpu: 1, name: 'host4', bootStatus: 'INIT'}
+        },
+        m: 'no one host is REGISTERED',
+        e: []
+      },
+      {
+        hosts: {
+          h1: {memory: 4, cpu: 1, name: 'host1', bootStatus: 'REGISTERED'},
+          h2: {memory: 3, cpu: 1, name: 'host2', bootStatus: 'REGISTERED'},
+          h3: {memory: 2, cpu: 1, name: 'host3', bootStatus: 'REGISTERED'},
+          h4: {memory: 1, cpu: 1, name: 'host4', bootStatus: 'REGISTERED'}
+        },
+        m: 'all hosts are REGISTERED, memory',
+        e: ['host1', 'host2', 'host3', 'host4']
+      },
+      {
+        hosts: {
+          h1: {memory: 1, cpu: 4, name: 'host1', bootStatus: 'REGISTERED'},
+          h2: {memory: 1, cpu: 3, name: 'host2', bootStatus: 'REGISTERED'},
+          h3: {memory: 1, cpu: 2, name: 'host3', bootStatus: 'REGISTERED'},
+          h4: {memory: 1, cpu: 1, name: 'host4', bootStatus: 'REGISTERED'}
+        },
+        m: 'all hosts are REGISTERED, cpu',
+        e: ['host1', 'host2', 'host3', 'host4']
+      },
+      {
+        hosts: {
+          h1: {memory: 1, cpu: 1, name: 'host4', bootStatus: 'REGISTERED'},
+          h2: {memory: 1, cpu: 1, name: 'host2', bootStatus: 'REGISTERED'},
+          h3: {memory: 1, cpu: 1, name: 'host3', bootStatus: 'REGISTERED'},
+          h4: {memory: 1, cpu: 1, name: 'host1', bootStatus: 'REGISTERED'}
+        },
+        m: 'all hosts are REGISTERED, host_name',
+        e: ['host1', 'host2', 'host3', 'host4']
+      },
+      {
+        hosts: {
+          h1: {memory: 2, cpu: 1, name: 'host1', bootStatus: 'REGISTERED'},
+          h2: {memory: 1, cpu: 2, name: 'host3', bootStatus: 'INIT'},
+          h3: {memory: 1, cpu: 1, name: 'host4', bootStatus: 'REGISTERED'},
+          h4: {memory: 1, cpu: 1, name: 'host2', bootStatus: 'INIT'}
+        },
+        m: 'mix',
+        e: ['host1', 'host4']
+      }
+    ]);
+
+    tests.forEach(function(test) {
+      it(test.m, function() {
+        controller.set('content', {hosts: test.hosts});
+        controller.renderHostInfo();
+        var r = controller.get('hosts');
+        expect(Em.A(r).mapProperty('host_name')).to.eql(test.e);
+      });
+    });
+
+  });
+
+  describe('#hasHiveServer', function() {
+
+    var tests = Em.A([
+      {
+        selectedServicesMasters: Em.A([{component_name: 'HIVE_SERVER'}]),
+        controllerName: 'reassignMasterController',
+        e: false
+      },
+      {
+        selectedServicesMasters: Em.A([{component_name: 'HIVE_SERVER'}]),
+        controllerName: 'addServiceController',
+        e: true
+      },
+      {
+        selectedServicesMasters: Em.A([{component_name: 'ANOTHER'}]),
+        controllerName: 'addServiceController',
+        e: false
+      },
+      {
+        selectedServicesMasters: Em.A([{component_name: 'ANOTHER'}]),
+        controllerName: 'reassignMasterController',
+        e: false
+      }
+    ]);
+
+    tests.forEach(function(test) {
+      it(test.controllerName + ' ' + test.selectedServicesMasters.mapProperty('component_name').join(','), function() {
+        controller.set('content.controllerName', test.controllerName);
+        controller.set('selectedServicesMasters', test.selectedServicesMasters);
+        expect(controller.get('hasHiveServer')).to.equal(test.e);
+      });
+    });
+
+  });
+
+  describe('#selectHost', function() {
+
+    var tests = Em.A([
+      {componentName: 'KERBEROS_SERVER', hostsCount: 1, e: 'host1'},
+      {componentName: 'KERBEROS_SERVER', hostsCount: 3, e: 'host2'},
+      {componentName: 'KERBEROS_SERVER', hostsCount: 6, e: 'host4'},
+      {componentName: 'KERBEROS_SERVER', hostsCount: 31, e: 'host6'},
+      {componentName: 'KERBEROS_SERVER', hostsCount: 32, e: 'host6'},
+      {componentName: 'NAMENODE', hostsCount: 1, e: 'host1'},
+      {componentName: 'NAMENODE', hostsCount: 2, e: 'host1'},
+      {componentName: 'SECONDARY_NAMENODE', hostsCount: 1, e: 'host1'},
+      {componentName: 'SECONDARY_NAMENODE', hostsCount: 2, e: 'host2'},
+      {componentName: 'JOBTRACKER', hostsCount: 1, e: 'host1'},
+      {componentName: 'JOBTRACKER', hostsCount: 3, e: 'host2'},
+      {componentName: 'JOBTRACKER', hostsCount: 6, e: 'host2'},
+      {componentName: 'JOBTRACKER', hostsCount: 31, e: 'host3'},
+      {componentName: 'JOBTRACKER', hostsCount: 32, e: 'host3'},
+      {componentName: 'HISTORYSERVER', hostsCount: 1, e: 'host1'},
+      {componentName: 'HISTORYSERVER', hostsCount: 3, e: 'host2'},
+      {componentName: 'HISTORYSERVER', hostsCount: 6, e: 'host2'},
+      {componentName: 'HISTORYSERVER', hostsCount: 31, e: 'host3'},
+      {componentName: 'HISTORYSERVER', hostsCount: 32, e: 'host3'},
+      {componentName: 'RESOURCEMANAGER', hostsCount: 1, e: 'host1'},
+      {componentName: 'RESOURCEMANAGER', hostsCount: 3, e: 'host2'},
+      {componentName: 'RESOURCEMANAGER', hostsCount: 6, e: 'host2'},
+      {componentName: 'RESOURCEMANAGER', hostsCount: 31, e: 'host3'},
+      {componentName: 'RESOURCEMANAGER', hostsCount: 32, e: 'host3'},
+      {componentName: 'HBASE_MASTER', hostsCount: 1, e: ['host1']},
+      {componentName: 'HBASE_MASTER', hostsCount: 3, e: ['host1']},
+      {componentName: 'HBASE_MASTER', hostsCount: 6, e: ['host3']},
+      {componentName: 'HBASE_MASTER', hostsCount: 31, e: ['host4']},
+      {componentName: 'HBASE_MASTER', hostsCount: 32, e: ['host4']},
+      {componentName: 'OOZIE_SERVER', hostsCount: 1, e: 'host1'},
+      {componentName: 'OOZIE_SERVER', hostsCount: 3, e: 'host2'},
+      {componentName: 'OOZIE_SERVER', hostsCount: 6, e: 'host3'},
+      {componentName: 'OOZIE_SERVER', hostsCount: 31, e: 'host4'},
+      {componentName: 'OOZIE_SERVER', hostsCount: 32, e: 'host4'},
+      {componentName: 'HIVE_SERVER', hostsCount: 1, e: 'host1'},
+      {componentName: 'HIVE_SERVER', hostsCount: 3, e: 'host2'},
+      {componentName: 'HIVE_SERVER', hostsCount: 6, e: 'host3'},
+      {componentName: 'HIVE_SERVER', hostsCount: 31, e: 'host5'},
+      {componentName: 'HIVE_SERVER', hostsCount: 32, e: 'host5'},
+      {componentName: 'HIVE_METASTORE', hostsCount: 1, e: 'host1'},
+      {componentName: 'HIVE_METASTORE', hostsCount: 3, e: 'host2'},
+      {componentName: 'HIVE_METASTORE', hostsCount: 6, e: 'host3'},
+      {componentName: 'HIVE_METASTORE', hostsCount: 31, e: 'host5'},
+      {componentName: 'HIVE_METASTORE', hostsCount: 32, e: 'host5'},
+      {componentName: 'WEBHCAT_SERVER', hostsCount: 1, e: 'host1'},
+      {componentName: 'WEBHCAT_SERVER', hostsCount: 3, e: 'host2'},
+      {componentName: 'WEBHCAT_SERVER', hostsCount: 6, e: 'host3'},
+      {componentName: 'WEBHCAT_SERVER', hostsCount: 31, e: 'host5'},
+      {componentName: 'WEBHCAT_SERVER', hostsCount: 32, e: 'host5'},
+      {componentName: 'APP_TIMELINE_SERVER', hostsCount: 1, e: 'host1'},
+      {componentName: 'APP_TIMELINE_SERVER', hostsCount: 3, e: 'host2'},
+      {componentName: 'APP_TIMELINE_SERVER', hostsCount: 6, e: 'host2'},
+      {componentName: 'APP_TIMELINE_SERVER', hostsCount: 31, e: 'host3'},
+      {componentName: 'APP_TIMELINE_SERVER', hostsCount: 32, e: 'host3'},
+      {componentName: 'FALCON_SERVER', hostsCount: 1, e: 'host1'},
+      {componentName: 'FALCON_SERVER', hostsCount: 3, e: 'host2'},
+      {componentName: 'FALCON_SERVER', hostsCount: 6, e: 'host3'},
+      {componentName: 'FALCON_SERVER', hostsCount: 31, e: 'host4'},
+      {componentName: 'FALCON_SERVER', hostsCount: 32, e: 'host4'},
+    ]);
+
+    tests.forEach(function(test) {
+      it(test.componentName + ' ' + test.hostsCount, function() {
+        controller.set('hosts', d3.range(1, test.hostsCount + 1).map(function(i) { return {host_name: 'host' + i.toString()};}));
+        expect(controller.selectHost(test.componentName)).to.eql(test.e);
+      });
+    });
+
+    describe('getServerHost should be called for', function() {
+      Em.A(['STORM_UI_SERVER','DRPC_SERVER','STORM_REST_API','NIMBUS','GANGLIA_SERVER','NAGIOS_SERVER','HUE_SERVER']).forEach(function(componentName) {
+        it(componentName, function() {
+          sinon.spy(controller, 'getServerHost');
+          controller.selectHost(componentName);
+          expect(controller.getServerHost.calledOnce).to.equal(true);
+          controller.getServerHost.restore();
+        });
+      });
+    });
+
+  });
+
+  describe('#last', function() {
+
+    var tests = Em.A([
+      {
+        selectedServicesMasters: Em.A([
+          {component_name: 'c1', indx: 1},
+          {component_name: 'c2', indx: 2},
+          {component_name: 'c1', indx: 2}
+        ]),
+        m: 'Components exists',
+        c: 'c1',
+        e: 2
+      },
+      {
+        selectedServicesMasters: Em.A([
+          {component_name: 'c1', indx: 1},
+          {component_name: 'c2', indx: 2},
+          {component_name: 'c1', indx: 2}
+        ]),
+        m: 'Components don\'t exists',
+        c: 'c3',
+        e: null
+      }
+    ]);
+
+    tests.forEach(function(test) {
+      it(test.m, function() {
+        controller.set('selectedServicesMasters', test.selectedServicesMasters);
+        if (!Em.isNone(test.e)) {
+          expect(controller.last(test.c).indx).to.equal(test.e);
+        }
+        else {
+          expect(Em.isNone(controller.last(test.c))).to.equal(true);
+        }
+      })
+    });
+
+  });
+
+  describe('#isSubmitDisabled', function() {
+    it('should be false if it\'s not a isReassignWizard', function() {
+      c.set('controllerName', 'addServiceController');
+      expect(c.get('isSubmitDisabled')).to.equal(false);
+    });
+  });
+
+  describe('#remainingHosts', function() {
+    it('should show count of hosts without masters', function() {
+      c.reopen({masterHostMapping: [{}]});
+      c.set('hosts', [{},{},{}]);
+      expect(c.get('remainingHosts')).to.equal(2);
+    });
+  });
+
+  describe('#clearStep', function() {
+    var tests = Em.A([
+      {p: 'hosts'},
+      {p: 'selectedServicesMasters'},
+      {p: 'servicesMasters'}
+    ]);
+    tests.forEach(function(test) {
+      it('should cleanup ' + test.p, function() {
+        c.set(test.p, [Em.Object.create({}),Em.Object.create({})]);
+        c.clearStep();
+        expect(c.get(test.p).length).to.equal(0);
+      });
+    });
+  });
+
+  describe('#updateComponent', function() {
+    var tests = Em.A([
+      {
+        componentName: 'HBASE_SERVER',
+        services: Em.A([
+          Em.Object.create({isInstalled: true, serviceName: 'HBASE'})
+        ]),
+        selectedServicesMasters: Em.A([
+          Em.Object.create({showAddControl: false, showRemoveControl: true, component_name: 'HBASE_SERVER'}),
+          Em.Object.create({showAddControl: true, showRemoveControl: false, component_name: 'HBASE_SERVER'})
+        ]),
+        hosts: Em.A([
+          Em.Object.create({})
+        ]),
+        controllerName: 'addServiceController',
+        m: 'service is installed',
+        e: {
+          showAddControl: true,
+          showRemoveControl: false
+        }
+      },
+      {
+        componentName: 'HBASE_SERVER',
+        services: Em.A([
+          Em.Object.create({isInstalled: false, serviceName: 'HBASE'})
+        ]),
+        selectedServicesMasters: Em.A([
+          Em.Object.create({showAddControl: true, showRemoveControl: false, component_name: 'HBASE_SERVER'})
+        ]),
+        hosts: Em.A([
+          Em.Object.create({})
+        ]),
+        controllerName: 'addServiceController',
+        m: 'service not installed, but all host already have provided component',
+        e: {
+          showAddControl: true,
+          showRemoveControl: false
+        }
+      },
+      {
+        componentName: 'HBASE_SERVER',
+        services: Em.A([
+          Em.Object.create({isInstalled: false, serviceName: 'HBASE'})
+        ]),
+        selectedServicesMasters: Em.A([
+          Em.Object.create({showAddControl: false, showRemoveControl: true, component_name: 'HBASE_SERVER'})
+        ]),
+        hosts: Em.A([
+          Em.Object.create({}),
+          Em.Object.create({})
+        ]),
+        controllerName: 'addServiceController',
+        m: 'service not installed, not all host already have provided component',
+        e: {
+          showAddControl: true,
+          showRemoveControl: true
+        }
+      },
+      {
+        componentName: 'HBASE_SERVER',
+        services: Em.A([
+          Em.Object.create({isInstalled: false, serviceName: 'HBASE'})
+        ]),
+        selectedServicesMasters: Em.A([
+          Em.Object.create({showAddControl: false, showRemoveControl: true, component_name: 'HBASE_SERVER'})
+        ]),
+        hosts: Em.A([
+          Em.Object.create({}),
+          Em.Object.create({})
+        ]),
+        controllerName: 'reassignMasterController',
+        m: 'service not installed, not all host already have provided component, but is reassignMasterController',
+        e: {
+          showAddControl: false,
+          showRemoveControl: false
+        }
+      }
+    ]);
+
+    tests.forEach(function(test) {
+      it(test.m, function() {
+        c.reopen({
+          content: Em.Object.create({
+            services: test.services,
+            controllerName: test.controllerName
+          }),
+          selectedServicesMasters: test.selectedServicesMasters
+        });
+        c.updateComponent(test.componentName);
+        Em.keys(test.e).forEach(function(k) {
+          expect(c.last(test.componentName).get(k)).to.equal(test.e[k]);
+        });
+      });
+    });
+  });
+
+  describe('#renderComponents', function() {
+    var tests = Em.A([
+      {
+        masterComponents: Em.A([
+          {component_name: 'ZOOKEEPER_SERVER'}
+        ]),
+        services: Em.A([]),
+        controllerName: 'reassignMasterController',
+        m: 'One component',
+        isHaEnabled: false,
+        component_name: 'ZOOKEEPER_SERVER',
+        e: {
+          selectedServicesMasters: ['ZOOKEEPER_SERVER'],
+          servicesMasters: ['ZOOKEEPER_SERVER'],
+          showRemoveControl: [false],
+          isInstalled: [false],
+          zId: [1]
+        }
+      },
+      {
+        masterComponents: Em.A([
+          {component_name: 'ZOOKEEPER_SERVER'},
+          {component_name: 'SECONDARY_NAMENODE'}
+        ]),
+        services: Em.A([]),
+        controllerName: 'addServiceController',
+        m: 'One component',
+        isHaEnabled: true,
+        component_name: 'ZOOKEEPER_SERVER',
+        e: {
+          selectedServicesMasters: ['ZOOKEEPER_SERVER'],
+          servicesMasters: ['ZOOKEEPER_SERVER'],
+          showRemoveControl: [false],
+          zId: [1]
+        }
+      },
+      {
+        masterComponents: Em.A([
+          {component_name: 'ZOOKEEPER_SERVER'},
+          {component_name: 'ZOOKEEPER_SERVER'}
+        ]),
+        services: Em.A([
+          Em.Object.create({serviceName:'ZOOKEEPER', isInstalled: true})
+        ]),
+        controllerName: 'addServiceController',
+        m: 'Two components, but service is installed',
+        isHaEnabled: false,
+        component_name: 'ZOOKEEPER_SERVER',
+        e: {
+          selectedServicesMasters: ['ZOOKEEPER_SERVER', 'ZOOKEEPER_SERVER'],
+          servicesMasters: ['ZOOKEEPER_SERVER', 'ZOOKEEPER_SERVER'],
+          showRemoveControl: [false, false],
+          zId: [1, 2]
+        }
+      },
+      {
+        masterComponents: Em.A([
+          {component_name: 'ZOOKEEPER_SERVER'},
+          {component_name: 'ZOOKEEPER_SERVER'},
+          {component_name: 'NAMENODE'}
+        ]),
+        services: Em.A([
+        ]),
+        controllerName: 'addServiceController',
+        m: 'Two components, but service is installed',
+        isHaEnabled: false,
+        component_name: 'ZOOKEEPER_SERVER',
+        e: {
+          selectedServicesMasters: ['ZOOKEEPER_SERVER', 'ZOOKEEPER_SERVER', 'NAMENODE'],
+          servicesMasters: ['ZOOKEEPER_SERVER', 'ZOOKEEPER_SERVER', 'NAMENODE'],
+          showRemoveControl: [true, true, undefined],
+          zId: [1, 2, 1]
+        }
+      }
+    ]);
+    tests.forEach(function(test) {
+      beforeEach(function() {
+        App.reopen({isHaEnabled: test.isHaEnabled});
+      });
+      it(test.m, function() {
+        App.set('isHaEnabled', test.isHaEnabled);
+        c.reopen({
+          content: Em.Object.create({
+            services: test.services,
+            controllerName: test.controllerName,
+            reassign: {component_name: test.component_name}
+          })
+        });
+        c.renderComponents(test.masterComponents);
+        expect(c.get('selectedServicesMasters').mapProperty('component_name')).to.eql(test.e.selectedServicesMasters);
+        expect(c.get('servicesMasters').mapProperty('component_name')).to.eql(test.e.servicesMasters);
+        expect(c.get('selectedServicesMasters').mapProperty('showRemoveControl')).to.eql(test.e.showRemoveControl);
+        expect(c.get('selectedServicesMasters').mapProperty('zId')).to.eql(test.e.zId);
+        if (c.get('isReasignController')) {
+          expect(c.get('servicesMasters').mapProperty('isInstalled')).to.eql(test.e.isInstalled);
+        }
+      });
+    });
+  });
+
+  describe('#updateHiveCoHosts', function() {
+    var tests = Em.A([
+      {
+        selectedServicesMasters: Em.A([
+          Em.Object.create({component_name: 'HIVE_SERVER', selectedHost: 'h1'}),
+          Em.Object.create({component_name: 'HIVE_METASTORE', selectedHost: 'h2'}),
+          Em.Object.create({component_name: 'WEBHCAT_SERVER', selectedHost: 'h3'})
+        ]),
+        servicesMasters: Em.A([
+          Em.Object.create({component_name: 'HIVE_SERVER', selectedHost: 'h1'})
+        ]),
+        isReassignHive: false,
+        m: 'should set new host for both',
+        e: ['h1','h1','h1']
+      },
+      {
+        selectedServicesMasters: Em.A([
+          Em.Object.create({component_name: 'HIVE_SERVER', selectedHost: 'h1'}),
+          Em.Object.create({component_name: 'HIVE_METASTORE', selectedHost: 'h2'}),
+          Em.Object.create({component_name: 'WEBHCAT_SERVER', selectedHost: 'h3'})
+        ]),
+        servicesMasters: Em.A([
+          Em.Object.create({component_name: 'HIVE_METASTORE', selectedHost: 'h1'})
+        ]),
+        isReassignHive: false,
+        m: 'should set new host for WEBHCAT_SERVER',
+        e: ['h1','h2','h1']
+      },
+      {
+        selectedServicesMasters: Em.A([
+          Em.Object.create({component_name: 'HIVE_METASTORE', selectedHost: 'h2'}),
+          Em.Object.create({component_name: 'WEBHCAT_SERVER', selectedHost: 'h3'})
+        ]),
+        servicesMasters: Em.A([
+          Em.Object.create({component_name: 'HIVE_METASTORE', selectedHost: 'h1'})
+        ]),
+        isReassignHive: false,
+        m: 'missing HIVE_SERVER',
+        e: ['h2','h3']
+      }
+    ]);
+
+    tests.forEach(function(test) {
+      it(test.m, function() {
+        c.set('selectedServicesMasters', test.selectedServicesMasters);
+        c.set('servicesMasters', test.servicesMasters);
+        c.reopen({isReassignHive: test.isReassignHive});
+        c.updateHiveCoHosts();
+        expect(c.get('selectedServicesMasters').mapProperty('selectedHost')).to.eql(test.e);
+      });
+    });
+
+  });
+
+  describe('#assignHostToMaster', function() {
+    var tests = Em.A([
+      {
+        componentName: 'c1',
+        selectedHost: 'h2',
+        zId: '1',
+        e: {
+          indx: 0
+        }
+      },
+      {
+        componentName: 'c2',
+        selectedHost: 'h3',
+        zId: '2',
+        e: {
+          indx: 3
+        }
+      },
+      {
+        componentName: 'c3',
+        selectedHost: 'h1',
+        e: {
+          indx: 2
+        }
+      },
+      {
+        componentName: 'c2',
+        selectedHost: 'h4',
+        e: {
+          indx: 1
+        }
+      }
+    ]),
+    selectedServicesMasters = Em.A([
+      Em.Object.create({component_name: 'c1', zId: '1', selectedHost: 'h1'}),
+      Em.Object.create({component_name: 'c2', zId: '1', selectedHost: 'h1'}),
+      Em.Object.create({component_name: 'c3', zId: '1', selectedHost: 'h3'}),
+      Em.Object.create({component_name: 'c2', zId: '2', selectedHost: 'h2'})
+    ]);
+
+    tests.forEach(function(test) {
+      it(test.componentName + ' ' + test.selectedHost + ' ' + test.zId, function() {
+        c.set('selectedServicesMasters', selectedServicesMasters);
+        c.assignHostToMaster(test.componentName, test.selectedHost, test.zId);
+        expect(c.get('selectedServicesMasters').objectAt(test.e.indx).get('selectedHost')).to.equal(test.selectedHost);
+      })
+    });
+  });
+
+  describe('#submit', function() {
+    beforeEach(function() {
+      sinon.spy(App.router, 'send');
+    });
+    afterEach(function() {
+      App.router.send.restore();
+    });
+    it('should go next if not isSubmitDisabled', function() {
+      c.reopen({isSubmitDisabled: false});
+      c.submit();
+      expect(App.router.send.calledWith('next')).to.equal(true);
+    });
+    it('shouldn\'t go next if isSubmitDisabled', function() {
+      c.reopen({isSubmitDisabled: true});
+      c.submit();
+      expect(App.router.send.called).to.equal(false);
+    });
+  });
+
+  describe('#removeComponent', function() {
+    var tests = Em.A([
+      {
+        componentName: 'c1',
+        zId: 1,
+        selectedServicesMasters: Em.A([]),
+        hosts: [],
+        m: 'empty selectedServicesMasters',
+        e: false
+      },
+      {
+        componentName: 'ZOOKEPEER_SERVER',
+        zId: 1,
+        selectedServicesMasters: Em.A([
+          Em.Object.create({zId: 1, component_name: 'HBASE_SERVER'})
+        ]),
+        hosts: [],
+        m: 'no such components',
+        e: false
+      },
+      {
+        componentName: 'ZOOKEPEER_SERVER',
+        zId: 1,
+        selectedServicesMasters: Em.A([
+          Em.Object.create({zId: 1, component_name: 'ZOOKEPEER_SERVER'})
+        ]),
+        hosts: [],
+        m: 'component is only 1',
+        e: false
+      },
+      {
+        componentName: 'ZOOKEPEER_SERVER',
+        zId: 2,
+        selectedServicesMasters: Em.A([
+          Em.Object.create({zId: 1, component_name: 'ZOOKEPEER_SERVER', showAddControl: false, showRemoveControl: false}),
+          Em.Object.create({zId: 2, component_name: 'ZOOKEPEER_SERVER', showAddControl: false, showRemoveControl: false})
+        ]),
+        hosts: [{},{}],
+        m: 'two components, add allowed, remove not allowed',
+        e: true,
+        showAddControl: true,
+        showRemoveControl: false
+      },
+      {
+        componentName: 'ZOOKEPEER_SERVER',
+        zId: 2,
+        selectedServicesMasters: Em.A([
+          Em.Object.create({zId: 1, component_name: 'ZOOKEPEER_SERVER', showAddControl: false, showRemoveControl: false}),
+          Em.Object.create({zId: 2, component_name: 'ZOOKEPEER_SERVER', showAddControl: false, showRemoveControl: false})
+        ]),
+        hosts: [{}],
+        m: 'two components, add not allowed, remove not allowed',
+        e: true,
+        showAddControl: false,
+        showRemoveControl: false
+      },
+      {
+        componentName: 'ZOOKEPEER_SERVER',
+        zId: 2,
+        selectedServicesMasters: Em.A([
+          Em.Object.create({zId: 1, component_name: 'ZOOKEPEER_SERVER', showAddControl: false, showRemoveControl: false}),
+          Em.Object.create({zId: 2, component_name: 'ZOOKEPEER_SERVER', showAddControl: false, showRemoveControl: false}),
+          Em.Object.create({zId: 3, component_name: 'ZOOKEPEER_SERVER', showAddControl: false, showRemoveControl: true})
+        ]),
+        hosts: [{},{}],
+        m: 'three components, add not allowed, remove allowed',
+        e: true,
+        showAddControl: false,
+        showRemoveControl: true
+      },
+      {
+        componentName: 'ZOOKEPEER_SERVER',
+        zId: 2,
+        selectedServicesMasters: Em.A([
+          Em.Object.create({zId: 1, component_name: 'ZOOKEPEER_SERVER', showAddControl: false, showRemoveControl: false}),
+          Em.Object.create({zId: 2, component_name: 'ZOOKEPEER_SERVER', showAddControl: false, showRemoveControl: false}),
+          Em.Object.create({zId: 3, component_name: 'ZOOKEPEER_SERVER', showAddControl: false, showRemoveControl: true})
+        ]),
+        hosts: [{},{}, {}],
+        m: 'three components, add allowed, remove allowed',
+        e: true,
+        showAddControl: true,
+        showRemoveControl: true
+      }
+    ]);
+    tests.forEach(function(test) {
+      it(test.m, function() {
+        c.set('selectedServicesMasters', test.selectedServicesMasters);
+        c.set('hosts', test.hosts);
+        expect(c.removeComponent(test.componentName, test.zId)).to.equal(test.e);
+        if(test.e) {
+          expect(c.get('selectedServicesMasters.lastObject.showRemoveControl')).to.equal(test.showRemoveControl);
+          expect(c.get('selectedServicesMasters.lastObject.showAddControl')).to.equal(test.showAddControl);
+        }
+      })
+    });
+  });
+
+  describe('#addComponent', function() {
+    var tests = Em.A([
+      {
+        componentName: 'c1',
+        selectedServicesMasters: Em.A([]),
+        hosts: [],
+        m: 'empty selectedServicesMasters',
+        e: false
+      },
+      {
+        componentName: 'ZOOKEPEER_SERVER',
+        selectedServicesMasters: Em.A([
+          Em.Object.create({zId: 1, component_name: 'HBASE_SERVER'})
+        ]),
+        hosts: [],
+        m: 'no such components',
+        e: false
+      },
+      {
+        componentName: 'ZOOKEPEER_SERVER',
+        selectedServicesMasters: Em.A([
+          Em.Object.create({zId: 1, component_name: 'ZOOKEPEER_SERVER'})
+        ]),
+        hosts: [],
+        m: 'one component, 0 hosts',
+        e: false
+      },
+      {
+        componentName: 'ZOOKEPEER_SERVER',
+        selectedServicesMasters: Em.A([
+          Em.Object.create({zId: 1, component_name: 'ZOOKEPEER_SERVER', showAddControl: false, showRemoveControl: false}),
+          Em.Object.create({zId: 2, component_name: 'ZOOKEPEER_SERVER', showAddControl: false, showRemoveControl: false})
+        ]),
+        hosts: [Em.Object.create({}), Em.Object.create({})],
+        m: 'two components, two hosts',
+        e: false
+      },
+      {
+        componentName: 'ZOOKEPEER_SERVER',
+        selectedServicesMasters: Em.A([
+          Em.Object.create({zId: 1, component_name: 'ZOOKEPEER_SERVER', showAddControl: false, showRemoveControl: false}),
+          Em.Object.create({zId: 2, component_name: 'ZOOKEPEER_SERVER', showAddControl: false, showRemoveControl: false})
+        ]),
+        hosts: [Em.Object.create({}), Em.Object.create({}), Em.Object.create({})],
+        m: 'two components, 3 hosts',
+        e: true
+      }
+    ]);
+    tests.forEach(function(test) {
+      it(test.m, function() {
+        c.set('selectedServicesMasters', test.selectedServicesMasters);
+        c.set('hosts', test.hosts);
+        expect(c.addComponent(test.componentName)).to.equal(test.e);
+      });
+    });
+  });
+
+  describe('#loadStep', function() {
+    var methods = Em.A(['clearStep', 'renderHostInfo', 'renderComponents', 'loadComponents']);
+    describe('should call several methods', function() {
+      beforeEach(function() {
+        methods.forEach(function(m) {
+          sinon.spy(c, m);
+        });
+        c.reopen({content: {services: Em.A([])}});
+      });
+      afterEach(function() {
+        methods.forEach(function(m) {
+          c[m].restore();
+        });
+      });
+      methods.forEach(function(m) {
+        it(m, function() {
+          c.loadStep();
+          expect(c[m].calledOnce).to.equal(true);
+        });
+      });
+    });
+    it('should update HBASE if App.supports.multipleHBaseMasters is true', function() {
+      App.set('supports.multipleHBaseMasters', true);
+      sinon.spy(c, 'updateComponent');
+      c.reopen({content: {services: Em.A([])}});
+      c.loadStep();
+      expect(c.updateComponent.calledTwice).to.equal(true);
+      c.updateComponent.restore();
+    });
+  });
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/8b385e07/ambari-web/test/views/main/host/summary_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/main/host/summary_test.js b/ambari-web/test/views/main/host/summary_test.js
index 309f7d6..83161b5 100644
--- a/ambari-web/test/views/main/host/summary_test.js
+++ b/ambari-web/test/views/main/host/summary_test.js
@@ -384,10 +384,6 @@ describe('App.MainHostSummaryView', function() {
       it(test.m, function() {
         mainHostSummaryView.set('content', test.content);
         mainHostSummaryView.set('installedServices', test.services);
-        //expect(mainHostSummaryView.get('addableComponents').mapProperty('componentName')).to.include.members(test.e);
-        console.log('!!!!!!!!!', mainHostSummaryView.get('addableComponents').mapProperty('componentName').join(', '));
-        console.log('@@@@@@@@@', test.e.join(', '));
-        console.log('#########', App.get('components.addableToHost').join(', '));
         expect(mainHostSummaryView.get('addableComponents').mapProperty('componentName')).to.eql(test.e);
       });
     });

http://git-wip-us.apache.org/repos/asf/ambari/blob/8b385e07/ambari-web/test/views/wizard/step5_view_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/wizard/step5_view_test.js b/ambari-web/test/views/wizard/step5_view_test.js
new file mode 100644
index 0000000..973f188
--- /dev/null
+++ b/ambari-web/test/views/wizard/step5_view_test.js
@@ -0,0 +1,300 @@
+/**
+ * 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.
+ */
+
+
+var App = require('app');
+var lazyloading = require('utils/lazy_loading');
+require('views/wizard/step5_view');
+var view;
+
+describe('App.WizardStep5View', function() {
+  beforeEach(function() {
+    view = App.WizardStep5View.create({
+      controller: App.WizardStep5Controller.create({})
+    });
+  });
+  describe('#didInsertElement', function() {
+    it('should call controller.loadStep', function() {
+      sinon.stub(view.get('controller'), 'loadStep', Em.K);
+      view.didInsertElement();
+      expect(view.get('controller').loadStep.calledOnce).to.equal(true);
+      view.get('controller').loadStep.restore();
+    });
+  });
+});
+
+describe('App.SelectHostView', function() {
+  beforeEach(function() {
+    view = App.SelectHostView.create({
+      controller: App.WizardStep5Controller.create({})
+    });
+  });
+
+  describe('#didInsertElement', function() {
+    beforeEach(function() {
+      sinon.stub(view, 'initContent', Em.K);
+    });
+    afterEach(function() {
+      view.initContent.restore();
+    });
+    it('should call initContent', function() {
+      view.didInsertElement();
+      expect(view.initContent.calledOnce).to.equal(true);
+    });
+    it('should set selectedHost to value', function() {
+      view.set('selectedHost', 'h1');
+      view.set('value', '');
+      view.didInsertElement();
+      expect(view.get('value')).to.equal('h1');
+    });
+  });
+
+  describe('#change', function() {
+    beforeEach(function() {
+      view.set('componentName', 'ZOOKEEPER_SERVER');
+      view.set('value', 'h1');
+      view.set('zId', 1);
+      view.set('controller.rebalanceComponentHostsCounter', 0);
+      view.set('controller.componentToRebalance', '');
+      sinon.stub(view.get('controller'), 'assignHostToMaster', Em.K);
+    });
+    afterEach(function() {
+      view.get('controller').assignHostToMaster.restore();
+    });
+    it('should call assignHostToMaster', function() {
+      view.change();
+      expect(view.get('controller').assignHostToMaster.calledWith('ZOOKEEPER_SERVER', 'h1', 1));
+    });
+    it('should increment rebalanceComponentHostsCounter', function() {
+      view.change();
+      expect(view.get('controller.rebalanceComponentHostsCounter')).to.equal(1);
+    });
+    it('should set componentToRebalance', function() {
+      view.change();
+      expect(view.get('controller.componentToRebalance')).to.equal('ZOOKEEPER_SERVER');
+    });
+  });
+
+  describe('#getAvailableHosts', function() {
+    var tests = Em.A([
+      {
+        hosts: Em.A([]),
+        selectedHost: 'h2',
+        componentName: 'ZOOKEEPER_SERVER',
+        selectedServicesMasters: Em.A([
+          Em.Object.create({component_name: 'ZOOKEEPER_SERVER', selectedHost: 'h1'})
+        ]),
+        m: 'Empty hosts',
+        e: []
+      },
+      {
+        hosts: Em.A([
+          Em.Object.create({host_name: 'h1'}),
+          Em.Object.create({host_name: 'h2'})
+        ]),
+        selectedHost: 'h2',
+        componentName: 'c1',
+        selectedServicesMasters: Em.A([
+          Em.Object.create({component_name: 'c2', selectedHost: 'h1'})
+        ]),
+        m: 'Two hosts',
+        e: ['h1', 'h2']
+      },
+      {
+        hosts: Em.A([
+          Em.Object.create({host_name: 'h1'}),
+          Em.Object.create({host_name: 'h2'})
+        ]),
+        selectedHost: 'h2',
+        componentName: 'ZOOKEEPER_SERVER',
+        selectedServicesMasters: Em.A([
+          Em.Object.create({component_name: 'ZOOKEEPER_SERVER', selectedHost: 'h1'})
+        ]),
+        m: 'Two hosts, ZOOKEEPER_SERVER',
+        e: ['h2']
+      },
+      {
+        hosts: Em.A([
+          Em.Object.create({host_name: 'h1'}),
+          Em.Object.create({host_name: 'h2'})
+        ]),
+        selectedHost: 'h2',
+        componentName: 'HBASE_MASTER',
+        selectedServicesMasters: Em.A([
+          Em.Object.create({component_name: 'HBASE_MASTER', selectedHost: 'h1'})
+        ]),
+        m: 'Two hosts, HBASE_MASTER',
+        e: ['h2']
+      }
+    ]);
+    tests.forEach(function(test) {
+      it(test.m, function() {
+        view.set('controller.hosts', test.hosts);
+        view.set('componentName', test.componentName);
+        view.set('controller.selectedServicesMasters', test.selectedServicesMasters);
+        var r = view.getAvailableHosts();
+        expect(r.mapProperty('host_name')).to.eql(test.e);
+      });
+    });
+  });
+
+  describe('#rebalanceComponentHosts', function() {
+    var tests = Em.A([
+      {
+        componentName: 'c1',
+        componentToRebalance: 'c2',
+        isLoaded: true,
+        content: [{}],
+        m: 'componentName not equal to componentToRebalance',
+        e: {
+          initContent: false,
+          isLoaded: true,
+          content: 1
+        }
+      },
+      {
+        componentName: 'c2',
+        componentToRebalance: 'c2',
+        isLoaded: true,
+        content: [{}],
+        m: 'componentName equal to componentToRebalance',
+        e: {
+          initContent: true,
+          isLoaded: false,
+          content: 0
+        }
+      }
+    ]);
+
+    tests.forEach(function(test) {
+      it(test.m, function() {
+        view.set('isLoaded', test.isLoaded);
+        view.set('content', test.content);
+        view.set('componentName', test.componentName);
+        view.set('controller.componentToRebalance', test.componentToRebalance);
+        sinon.stub(view, 'initContent', Em.K);
+        view.rebalanceComponentHosts();
+        expect(view.initContent.calledOnce).to.equal(test.e.initContent);
+        expect(view.get('isLoaded')).to.equal(test.e.isLoaded);
+        expect(view.get('content.length')).to.equal(test.e.content);
+        view.initContent.restore();
+      });
+    });
+  });
+
+  describe('#initContent', function() {
+    var tests = Em.A([
+      {
+        isLazyLoading: false,
+        hosts: 25,
+        m: 'not lazy loading, 25 hosts, no selected host',
+        e: 25
+      },
+      {
+        isLazyLoading: false,
+        hosts: 25,
+        h: 4,
+        m: 'not lazy loading, 25 hosts, one selected host',
+        e: 25
+      },
+      {
+        isLazyLoading: true,
+        hosts: 25,
+        h: 4,
+        m: 'lazy loading, 25 hosts, one selected host',
+        e: 25
+      },
+      {
+        isLazyLoading: true,
+        hosts: 25,
+        m: 'lazy loading, 25 hosts, no selected host',
+        e: 26
+      },
+      {
+        isLazyLoading: true,
+        hosts: 100,
+        h: 4,
+        m: 'lazy loading, 100 hosts, one selected host',
+        e: 30
+      },
+      {
+        isLazyLoading: true,
+        hosts: 100,
+        m: 'lazy loading, 100 hosts, no selected host',
+        e: 31
+      }
+    ]);
+    tests.forEach(function(test) {
+      it(test.m, function() {
+        view.reopen({getAvailableHosts: function() {return d3.range(0, test.hosts).map(function(indx){return Em.Object.create({host_name: indx})});}});
+        if (test.h) {
+          view.set('selectedHost', test.h);
+        }
+        view.set('isLazyLoading', test.isLazyLoading);
+        view.initContent();
+        expect(view.get('content.length')).to.equal(test.e);
+      });
+    });
+  });
+
+});
+
+describe('App.RemoveControlView', function() {
+  beforeEach(function() {
+    view = App.RemoveControlView.create({
+      controller: App.WizardStep5Controller.create({})
+    });
+  });
+
+  describe('#click', function() {
+    beforeEach(function() {
+      sinon.stub(view.get('controller'), 'removeComponent', Em.K);
+    });
+    afterEach(function() {
+      view.get('controller').removeComponent.restore();
+    });
+    it('should call removeComponent', function() {
+      view.set('zId', 1);
+      view.set('componentName', 'c1');
+      view.click();
+      expect(view.get('controller').removeComponent.calledWith('c1', 1)).to.equal(true);
+    });
+  });
+});
+
+describe('App.AddControlView', function() {
+  beforeEach(function() {
+    view = App.AddControlView.create({
+      controller: App.WizardStep5Controller.create({})
+    });
+  });
+
+  describe('#click', function() {
+    beforeEach(function() {
+      sinon.stub(view.get('controller'), 'addComponent', Em.K);
+    });
+    afterEach(function() {
+      view.get('controller').addComponent.restore();
+    });
+    it('should call addComponent', function() {
+      view.set('componentName', 'c1');
+      view.click();
+      expect(view.get('controller').addComponent.calledWith('c1')).to.equal(true);
+    });
+  });
+});
\ No newline at end of file