ambari-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From onechipore...@apache.org
Subject git commit: AMBARI-6046. Lags on Assign Masters step on big cluster. (onechiporenko)
Date Fri, 06 Jun 2014 12:50:13 GMT
Repository: ambari
Updated Branches:
  refs/heads/trunk 5e1f13dcd -> 441b02580


AMBARI-6046. Lags on Assign Masters step on big cluster. (onechiporenko)


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

Branch: refs/heads/trunk
Commit: 441b02580002b75cbffbf51b1fe777459181d769
Parents: 5e1f13d
Author: Oleg Nechiporenko <onechiporenko@apache.org>
Authored: Fri Jun 6 15:47:33 2014 +0300
Committer: Oleg Nechiporenko <onechiporenko@apache.org>
Committed: Fri Jun 6 15:48:37 2014 +0300

----------------------------------------------------------------------
 .../app/controllers/wizard/step5_controller.js  | 217 +++++++++++--------
 ambari-web/app/styles/application.less          |   4 +
 ambari-web/app/templates/wizard/step5.hbs       |  14 +-
 ambari-web/app/views/wizard/step5_view.js       | 162 ++++++++------
 .../test/controllers/wizard/step5_test.js       | 150 +++++++------
 ambari-web/test/views/wizard/step5_view_test.js | 144 ++++--------
 6 files changed, 347 insertions(+), 344 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/441b0258/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 6bcf6f0..8300b2e 100644
--- a/ambari-web/app/controllers/wizard/step5_controller.js
+++ b/ambari-web/app/controllers/wizard/step5_controller.js
@@ -18,7 +18,6 @@
 
 var App = require('app');
 var numberUtils = require('utils/number_utils');
-var lazyLoading = require('utils/lazy_loading');
 
 App.WizardStep5Controller = Em.Controller.extend({
 
@@ -66,38 +65,18 @@ App.WizardStep5Controller = Em.Controller.extend({
    */
   multipleComponents: ['ZOOKEEPER_SERVER', 'HBASE_MASTER'],
 
+  /**
+   * Define state for submit button
+   * @type {bool}
+   */
   submitDisabled: false,
 
   /**
-   * Define state for submit button. Return true only for Reassign Master Wizard and if more
than one master component was reassigned.
+   * Trigger for executing host names check for components
+   * Should de "triggered" when host changed for some component and when new multiple component
is added/removed
    * @type {bool}
    */
-  isSubmitDisabled: function () {
-    if (!this.get('isReassignWizard')) {
-      this.set('submitDisabled', false);
-    } else {
-      App.ajax.send({
-        name: 'host_components.all',
-        sender: this,
-        data: {
-          clusterName: App.get('clusterName')
-        },
-        success: 'isSubmitDisabledSuccessCallBack'
-      });
-    }
-  }.observes('servicesMasters.@each.selectedHost'),
-
-  isSubmitDisabledSuccessCallBack: function (response) {
-    var reassigned = 0;
-    var arr1 = response.items.mapProperty('HostRoles').filterProperty('component_name', this.get('content.reassign.component_name')).mapProperty('host_name');
-    var arr2 = this.get('servicesMasters').mapProperty('selectedHost');
-    arr1.forEach(function (host) {
-      if (!arr2.contains(host)) {
-        reassigned++;
-      }
-    }, this);
-    this.set('submitDisabled', reassigned !== 1);
-  },
+  hostNameCheckTrigger: false,
 
   /**
    * List of hosts
@@ -106,11 +85,13 @@ App.WizardStep5Controller = Em.Controller.extend({
   hosts: [],
 
   /**
+   * Name of multiple component which host name was changed last
    * @type {Object|null}
    */
   componentToRebalance: null,
 
   /**
+   * Flag for rebalance multiple components
    * @type {number}
    */
   rebalanceComponentHostsCounter: 0,
@@ -126,6 +107,12 @@ App.WizardStep5Controller = Em.Controller.extend({
   selectedServicesMasters: [],
 
   /**
+   * Is data for current step loaded
+   * @type {bool}
+   */
+  isLoaded: false,
+
+  /**
    * Check if HIVE_SERVER component exist (also checks if this is not reassign)
    * @type {bool}
    */
@@ -141,69 +128,40 @@ App.WizardStep5Controller = Em.Controller.extend({
    *     {
    *       host_name: '',
    *       hostInfo: {},
-   *       masterServices: []
+   *       masterServices: [],
+   *       masterServicesToDisplay: [] // used only in template
    *    },
    *    ....
    *   ]
    * </code>
    * @type {Ember.Enumerable}
    */
-  masterHostMapping: [],
-
-  isLoaded: false,
-
-  /**
-   * 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'),
-
-  masterHostMappingObserver: function () {
-    var requestName = this.get('content.controllerName') == 'installerController' ? 'hosts.confirmed.install'
: 'hosts.confirmed'
-    App.ajax.send({
-      name: requestName,
-      sender: this,
-      data: {
-        clusterName: App.get('clusterName')
-      },
-      success: 'masterHostMappingSuccessCallback'
-    });
-  }.observes('selectedServicesMasters', 'selectedServicesMasters.@each.selectedHost'),
-
-  masterHostMappingSuccessCallback: function (response) {
+  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().without(undefined);
+    mappedHosts = this.get("selectedServicesMasters").mapProperty("selectedHost").uniq();
     mappedHosts.forEach(function (item) {
-      var host = response.items.mapProperty('Hosts').findProperty('host_name', item);
-      hostObj = {
-        name: host.host_name,
-        memory: host.total_mem,
-        cpu: host.cpu_count
-      };
-
+      hostObj = this.get("hosts").findProperty("host_name", item);
+      // User may input invalid host name (this is handled in hostname checker). Here we
just skip it
+      if (!hostObj) return;
+      var masterServices = this.get("selectedServicesMasters").filterProperty("selectedHost",
item),
+        masterServicesToDisplay = [];
+      masterServices.mapProperty('display_name').uniq().forEach(function(n) {
+        masterServicesToDisplay.pushObject(masterServices.findProperty('display_name', n));
+      });
       mappingObject = Em.Object.create({
         host_name: item,
-        hostInfo: Em.I18n.t('installer.step5.hostInfo').fmt(hostObj.name, numberUtils.bytesToSize(hostObj.memory,
1, 'parseFloat', 1024), hostObj.cpu),
-        masterServices: this.get("selectedServicesMasters").filterProperty("selectedHost",
item)
+        hostInfo: hostObj.host_info,
+        masterServices: masterServices,
+        masterServicesToDisplay: masterServicesToDisplay
       });
 
       mapping.pushObject(mappingObject);
     }, this);
 
-    this.set('masterHostMapping', []);
-    lazyLoading.run({
-      initSize: 20,
-      chunkSize: 50,
-      delay: 50,
-      destination: this.get('masterHostMapping'),
-      source: mapping.sortProperty('host_name'),
-      context: Em.Object.create()
-    });
-  },
-
+    return mapping.sortProperty('host_name');
+  }.property("selectedServicesMasters.@each.selectedHost", 'selectedServicesMasters.@each.isHostNameValid'),
+  
   /**
    * Count of hosts without masters
    * @type {number}
@@ -213,10 +171,49 @@ App.WizardStep5Controller = Em.Controller.extend({
      return 0;
     } else {
       return (this.get("hosts.length") - this.get("masterHostMapping.length"));
-    };
+    }
   }.property('masterHostMapping.length', 'selectedServicesMasters.@each.selectedHost'),
 
   /**
+   * Update submit button status
+   * @metohd getIsSubmitDisabled
+   */
+  getIsSubmitDisabled: function () {
+    if (!this.get('isReassignWizard')) {
+      this.set('submitDisabled', this.get('servicesMasters').someProperty('isHostNameValid',
false));
+    }
+    else {
+      App.ajax.send({
+        name: 'host_components.all',
+        sender: this,
+        data: {
+          clusterName: App.get('clusterName')
+        },
+        success: 'getIsSubmitDisabledSuccessCallBack'
+      });
+    }
+  }.observes('servicesMasters.@each.selectedHost', 'servicesMasters.@each.isHostNameValid'),
+
+  /**
+   * Success callback for getIsSubmitDisabled method
+   * Set true for Reassign Master Wizard and if more than one master component was reassigned.
+   * For installer, addHost and addService verify that provided host names for components
are valid
+   * @param {object} response
+   * @method getIsSubmitDisabledSuccessCallBack
+   */
+  getIsSubmitDisabledSuccessCallBack: function (response) {
+    var reassigned = 0;
+    var arr1 = response.items.mapProperty('HostRoles').filterProperty('component_name', this.get('content.reassign.component_name')).mapProperty('host_name');
+    var arr2 = this.get('servicesMasters').mapProperty('selectedHost');
+    arr1.forEach(function (host) {
+      if (!arr2.contains(host)) {
+        reassigned++;
+      }
+    }, this);
+    this.set('submitDisabled', reassigned !== 1);
+  },
+
+  /**
    * Clear controller data (hosts, masters etc)
    * @method clearStep
    */
@@ -291,15 +288,7 @@ App.WizardStep5Controller = Em.Controller.extend({
         }));
       }
     }
-    this.set("hosts", []);
-    lazyLoading.run({
-      initSize: 20,
-      chunkSize: 50,
-      delay: 50,
-      destination: this.get('hosts'),
-      source: result,
-      context: Em.Object.create()
-    });
+    this.set("hosts", result);
     this.sortHosts(this.get('hosts'));
     this.set('isLoaded', true);
   },
@@ -431,6 +420,7 @@ App.WizardStep5Controller = Em.Controller.extend({
           }
         }
       }
+      componentObj.set('isHostNameValid', true);
       result.push(componentObj);
     }, this);
 
@@ -559,18 +549,61 @@ App.WizardStep5Controller = Em.Controller.extend({
   },
 
   /**
-   * On change callback for selects
+   * On change callback for inputs
    * @param {string} componentName
    * @param {string} selectedHost
    * @param {number} zId
    * @method assignHostToMaster
    */
   assignHostToMaster: function (componentName, selectedHost, zId) {
-    if (selectedHost && componentName) {
+    var flag = this.isHostNameValid(componentName, selectedHost);
+    this.updateIsHostNameValidFlag(componentName, zId, flag);
+    if (zId) {
+      this.get('selectedServicesMasters').filterProperty('component_name', componentName).findProperty("zId",
zId).set("selectedHost", selectedHost);
+    }
+    else {
+      this.get('selectedServicesMasters').findProperty("component_name", componentName).set("selectedHost",
selectedHost);
+    }
+  },
+
+  /**
+   * Determines if hostName is valid for component:
+   * <ul>
+   *  <li>host name shouldn't be empty</li>
+   *  <li>host should exist</li>
+   *  <li>host should have only one component with <code>componentName</code></li>
+   * </ul>
+   * @param {string} componentName
+   * @param {string} selectedHost
+   * @returns {boolean} true - valid, false - invalid
+   * @method isHostNameValid
+   */
+  isHostNameValid: function(componentName, selectedHost) {
+    return (selectedHost.trim() !== '') &&
+      this.get('hosts').mapProperty('host_name').contains(selectedHost) &&
+      (this.get('selectedServicesMasters').
+        filterProperty('component_name', componentName).
+        mapProperty('selectedHost').
+        filter(function(h) {
+          return h === selectedHost;
+        }).length <= 1);
+  },
+
+  /**
+   * Update <code>isHostNameValid</code> property with <code>flag</code>
value
+   * for component with name <code>componentName</code> and
+   * <code>zId</code>-property equal to <code>zId</code>-parameter
value
+   * @param {string} componentName
+   * @param {number} zId
+   * @param {bool} flag
+   * @method updateIsHostNameValidFlag
+   */
+  updateIsHostNameValidFlag: function (componentName, zId, flag) {
+    if (componentName) {
       if (zId) {
-        this.get('selectedServicesMasters').filterProperty('component_name', componentName).findProperty("zId",
zId).set("selectedHost", selectedHost);
+        this.get('selectedServicesMasters').filterProperty('component_name', componentName).findProperty("zId",
zId).set("isHostNameValid", flag);
       } else {
-        this.get('selectedServicesMasters').findProperty("component_name", componentName).set("selectedHost",
selectedHost);
+        this.get('selectedServicesMasters').findProperty("component_name", componentName).set("isHostNameValid",
flag);
       }
     }
   },
@@ -648,7 +681,7 @@ App.WizardStep5Controller = Em.Controller.extend({
 
       this.set('componentToRebalance', componentName);
       this.incrementProperty('rebalanceComponentHostsCounter');
-
+      this.toggleProperty('hostNameCheckTrigger');
       return true;
     }
     return false;//if no more zookeepers can be added
@@ -682,7 +715,7 @@ App.WizardStep5Controller = Em.Controller.extend({
 
     this.set('componentToRebalance', componentName);
     this.incrementProperty('rebalanceComponentHostsCounter');
-
+    this.toggleProperty('hostNameCheckTrigger');
     return true;
   },
 
@@ -691,7 +724,7 @@ App.WizardStep5Controller = Em.Controller.extend({
    * @metohd submit
    */
   submit: function () {
-    this.isSubmitDisabled();
+    this.getIsSubmitDisabled();
     if (!this.get('submitDisabled')) {
       App.router.send('next');
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/441b0258/ambari-web/app/styles/application.less
----------------------------------------------------------------------
diff --git a/ambari-web/app/styles/application.less b/ambari-web/app/styles/application.less
index 77d822b..39a76d2 100644
--- a/ambari-web/app/styles/application.less
+++ b/ambari-web/app/styles/application.less
@@ -79,6 +79,10 @@ wbr {
   display: inline-block;
 }
 
+ul.typeahead.dropdown-menu {
+  z-index: 3000000 !important;
+}
+
 #wrapper {
   min-height: 100%;
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/441b0258/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 2718a81..009e978 100644
--- a/ambari-web/app/templates/wizard/step5.hbs
+++ b/ambari-web/app/templates/wizard/step5.hbs
@@ -61,21 +61,15 @@
                         {{selectedHost}}<i class="icon-asterisks">&#10037;</i>
                       </div>
                     {{else}}
-                      {{view App.SelectHostView
-                      optionValuePath="content.host_name"
-                      optionLabelPath="content.host_info"
-                      selectedHostBinding="selectedHost"
-                      componentNameBinding="component_name"
-                      class="host-select"
-                      zIdBinding="zId"
-                      disabledBinding="isInstalled"
-                      }}
+                    <div class="control-group">
+                      {{view App.SelectHostView componentBinding="this" disabledBinding="isInstalled"
}}
                       {{#if showAddControl}}
                         {{view App.AddControlView componentNameBinding="component_name"}}
                       {{/if}}
                       {{#if showRemoveControl}}
                         {{view App.RemoveControlView componentNameBinding="component_name"
zIdBinding="zId"}}
                       {{/if}}
+                      </div>
                     {{/if}}
                   </div>
                 </div>
@@ -90,7 +84,7 @@
       {{#each masterHostMapping}}
         <div class="mapping-box round-corners well">
           <div class="hostString"><span>{{hostInfo}}</span></div>
-          {{#each masterServices}}
+          {{#each masterServicesToDisplay}}
             <span {{bindAttr class="isInstalled:assignedService:newService :round-corners"}}>{{display_name}}</span>
           {{/each}}
         </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/441b0258/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 5a55e0f..1ef4932 100644
--- a/ambari-web/app/views/wizard/step5_view.js
+++ b/ambari-web/app/views/wizard/step5_view.js
@@ -18,7 +18,6 @@
 
 
 var App = require('app');
-var lazyloading = require('utils/lazy_loading');
 
 App.WizardStep5View = Em.View.extend({
 
@@ -30,25 +29,20 @@ App.WizardStep5View = Em.View.extend({
 
 });
 
-App.SelectHostView = Em.Select.extend({
+App.SelectHostView = Em.TextField.extend({
 
   /**
-   * List of avaiable host names
-   * @type {string[]}
+   * Element of <code>controller.servicesMasters</code>
+   * Binded from template
+   * @type {object}
    */
-  content: [],
-
-  /**
-   * Index for multiple component (like ZOOKEEPER_SERVER)
-   * @type {number|null}
-   */
-  zId: null,
+  component: null,
 
   /**
-   * Selected host name for host component
-   * @type {string}
+   * List of avaiable host names
+   * @type {string[]}
    */
-  selectedHost: null,
+  content: [],
 
   /**
    * Host component name
@@ -59,39 +53,79 @@ App.SelectHostView = Em.Select.extend({
   attributeBindings: ['disabled'],
 
   /**
-   * Is data loaded
-   * @type {bool}
+   * Saved typeahead component
+   * @type {$}
    */
-  isLoaded: false,
-
-  /**
-   * Is lazy loading used
-   * @type {bool}
-   */
-  isLazyLoading: false,
+  typeahead: null,
 
   /**
    * Handler for selected value change
+   * Triggers <code>changeHandler</code> execution
    * @method change
    */
   change: function () {
-    this.get('controller').assignHostToMaster(this.get("componentName"), this.get("value"),
this.get("zId"));
-    this.set('selectedHost', this.get('value'));
-    this.get('controller').set('componentToRebalance', this.get("componentName"));
-    this.get('controller').incrementProperty('rebalanceComponentHostsCounter');
+    if ('destroyed' === this.get('state')) return;
+    this.get('controller').toggleProperty('hostNameCheckTrigger');
+  },
+
+  /**
+   * Add or remove <code>error</code> class from parent div-element
+   * @param {bool} flag true - add class, false - remove
+   * @method updateErrorStatus
+   */
+  updateErrorStatus: function(flag) {
+    var parentBlock = this.$().parent('div');
+    /* istanbul ignore next */
+    if (flag) {
+      parentBlock.removeClass('error');
+    }
+    else {
+      parentBlock.addClass('error');
+    }
   },
 
   /**
+   * When <code>value</code> (hostname) is changed this method is triggered
+   * If new hostname is valid, this host is assigned to master component
+   * @method changeHandler
+   */
+  changeHandler: function() {
+    if ('destroyed' === this.get('state')) return;
+    var componentIsMultiple = this.get('controller.multipleComponents').contains(this.get("component.component_name"));
+    this.get('controller').assignHostToMaster(this.get("component.component_name"), this.get("value"),
this.get("component.zId"));
+    if(componentIsMultiple) {
+      this.get('controller').set('componentToRebalance', this.get("component.component_name"));
+      this.get('controller').incrementProperty('rebalanceComponentHostsCounter');
+    }
+  }.observes('controller.hostNameCheckTrigger'),
+
+  /**
+   * If <code>component.isHostNameValid</code> was changed,
+   * error status should be updated according to new value
+   * @method isHostNameValidObs
+   */
+  isHostNameValidObs: function() {
+    this.updateErrorStatus(this.get('component.isHostNameValid'));
+  }.observes('component.isHostNameValid'),
+
+  /**
    * Recalculate available hosts
+   * This should be done only once per Ember loop
    * @method rebalanceComponentHosts
    */
   rebalanceComponentHosts: function () {
-    if (this.get('componentName') === this.get('controller.componentToRebalance')) {
-      this.get('content').clear();
-      this.set('isLoaded', false);
+    Em.run.next(this, 'rebalanceComponentHostsOnce');
+  }.observes('controller.rebalanceComponentHostsCounter'),
+
+  /**
+   * Recalculate available hosts
+   * @method rebalanceComponentHostsOnce
+   */
+  rebalanceComponentHostsOnce: function() {
+    if (this.get('component.component_name') === this.get('controller.componentToRebalance'))
{
       this.initContent();
     }
-  }.observes('controller.rebalanceComponentHostsCounter'),
+  },
 
   /**
    * Get available hosts
@@ -102,12 +136,12 @@ App.SelectHostView = Em.Select.extend({
    */
   getAvailableHosts: function () {
     var hosts = this.get('controller.hosts').slice(),
-      componentName = this.get('componentName'),
+      componentName = this.get('component.component_name'),
       multipleComponents = this.get('controller.multipleComponents'),
       occupiedHosts = this.get('controller.selectedServicesMasters')
         .filterProperty('component_name', componentName)
         .mapProperty('selectedHost')
-        .without(this.get('selectedHost'));
+        .without(this.get('component.selectedHost'));
 
     if (multipleComponents.contains(componentName)) {
       return hosts.filter(function (host) {
@@ -117,37 +151,30 @@ App.SelectHostView = Em.Select.extend({
     return hosts;
   },
 
-  /**
-   * On click start lazy loading
-   * @method click
-   */
-  click: function () {
-    var source = [];
-    var availableHosts = this.getAvailableHosts();
-
-    if (!this.get('isLoaded') && this.get('isLazyLoading')) {
-      //filter out hosts, which already pushed in select
-      source = availableHosts.filter(function (_host) {
-        return !this.get('content').someProperty('host_name', _host.host_name);
-      }, this).slice();
-      lazyloading.run({
-        destination: this.get('content'),
-        source: source,
-        context: this,
-        initSize: 30,
-        chunkSize: 200,
-        delay: 50
+  didInsertElement: function () {
+    this.initContent();
+    this.set("value", this.get("component.selectedHost"));
+    var content = this.get('content').mapProperty('host_name'),
+      self = this,
+      typeahead = this.$().typeahead({items: 10, source: content});
+    typeahead.on('blur', function() {
+      self.change();
+    }).on('keyup', function(e) {
+        self.set('value', $(e.currentTarget).val());
+        self.change();
       });
-    }
+    this.set('typeahead', typeahead);
   },
 
-  didInsertElement: function () {
-    //The lazy loading for select elements supported only by Firefox and Chrome
-    var isBrowserSupported = $.browser.mozilla || ($.browser.safari && navigator.userAgent.indexOf('Chrome')
!== -1);
-    var isLazyLoading = isBrowserSupported && this.get('controller.hosts').length
> 100;
-    this.set('isLazyLoading', isLazyLoading);
-    this.initContent();
-    this.set("value", this.get("selectedHost"));
+  /**
+   * Update <code>source</code> property of <code>typeahead</code>
with a new list of hosts
+   * @param {string[]} hosts
+   * @method updateTypeaheadData
+   */
+  updateTypeaheadData: function(hosts) {
+    if (this.get('typeahead')) {
+      this.get('typeahead').data('typeahead').source = hosts;
+    }
   },
 
   /**
@@ -158,17 +185,8 @@ App.SelectHostView = Em.Select.extend({
    */
   initContent: function () {
     var hosts = this.getAvailableHosts();
-    if (this.get('isLazyLoading')) {
-      //select need at least 30 hosts to have scrollbar
-      var initialHosts = hosts.slice(0, 30);
-      if (!initialHosts.someProperty('host_name', this.get('selectedHost'))) {
-        initialHosts.unshift(hosts.findProperty('host_name', this.get('selectedHost')));
-      }
-      this.set("content", initialHosts);
-    }
-    else {
-      this.set("content", hosts);
-    }
+    this.set("content", hosts);
+    this.updateTypeaheadData(hosts.mapProperty('host_name'));
   }
 });
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/441b0258/ambari-web/test/controllers/wizard/step5_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/wizard/step5_test.js b/ambari-web/test/controllers/wizard/step5_test.js
index d3f5a91..b812bcc 100644
--- a/ambari-web/test/controllers/wizard/step5_test.js
+++ b/ambari-web/test/controllers/wizard/step5_test.js
@@ -19,6 +19,7 @@
 var Ember = require('ember');
 var App = require('app');
 require('controllers/wizard/step5_controller');
+require('utils/ajax/ajax');
 var c;
 describe('App.WizardStep5Controller', function () {
   beforeEach(function() {
@@ -191,6 +192,14 @@ describe('App.WizardStep5Controller', function () {
 
   describe('#isReassignHive', function() {
 
+    beforeEach(function() {
+      sinon.stub(controller, 'getIsSubmitDisabled', Em.K);
+    });
+
+    afterEach(function() {
+      controller.getIsSubmitDisabled.restore();
+    });
+
     var tests = Em.A([
       {
         servicesMasters: Em.A([{component_name: 'HIVE_SERVER'}]),
@@ -503,10 +512,15 @@ describe('App.WizardStep5Controller', function () {
 
   });
 
-  describe('#isSubmitDisabled', function() {
-    it('should be false if it\'s not a isReassignWizard', function() {
+  describe('#getIsSubmitDisabled', function() {
+    it('should base on selected host to masters if it\'s not a isReassignWizard', function()
{
       c.set('controllerName', 'addServiceController');
-      expect(c.get('isSubmitDisabled')).to.equal(false);
+      c.reopen({servicesMasters: [{isHostNameValid: true}, {isHostNameValid: false}]});
+      c.getIsSubmitDisabled();
+      expect(c.get('submitDisabled')).to.equal(true);
+      c.reopen({servicesMasters: [{isHostNameValid: true}, {isHostNameValid: true}]});
+      c.getIsSubmitDisabled();
+      expect(c.get('submitDisabled')).to.equal(false);
     });
   });
 
@@ -630,6 +644,7 @@ describe('App.WizardStep5Controller', function () {
   });
 
   describe('#renderComponents', function() {
+
     var tests = Em.A([
       {
         masterComponents: Em.A([
@@ -705,19 +720,21 @@ describe('App.WizardStep5Controller', function () {
       }
     ]);
     tests.forEach(function(test) {
-      beforeEach(function() {
-        App.reopen({isHaEnabled: test.isHaEnabled});
-      });
       it(test.m, function() {
-        App.set('isHaEnabled', test.isHaEnabled);
+        sinon.stub(App, 'get', function(k) {
+          if ('isHaEnabled' === k) return test.isHaEnabled;
+          return Em.get(App, k);
+        });
         c.reopen({
           content: Em.Object.create({
+            getIsSubmitDisabled: Em.K,
             services: test.services,
             controllerName: test.controllerName,
             reassign: {component_name: test.component_name}
           })
         });
         c.renderComponents(test.masterComponents);
+        App.get.restore();
         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);
@@ -834,18 +851,21 @@ describe('App.WizardStep5Controller', function () {
 
   describe('#submit', function() {
     beforeEach(function() {
-      sinon.spy(App.router, 'send');
+      if(!App.router) {
+        App.router = Em.Object.create({send: Em.K});
+      }
+      sinon.stub(App.router, 'send', Em.K);
     });
     afterEach(function() {
       App.router.send.restore();
     });
     it('should go next if not isSubmitDisabled', function() {
-      c.reopen({isSubmitDisabled: false});
+      c.reopen({servicesMasters: [{isHostNameValid: true}]});
       c.submit();
       expect(App.router.send.calledWith('next')).to.equal(true);
     });
     it('shouldn\'t go next if isSubmitDisabled', function() {
-      c.reopen({isSubmitDisabled: true});
+      c.reopen({servicesMasters: [{isHostNameValid: false}]});
       c.submit();
       expect(App.router.send.called).to.equal(false);
     });
@@ -1048,63 +1068,6 @@ describe('App.WizardStep5Controller', function () {
     });
   });
 
-  describe('#isSubmitDisabled', function() {
-    it('should be false if no isReassignWizard', function() {
-      c.reopen({isReassignWizard: false});
-      expect(c.get('isSubmitDisabled')).to.equal(false);
-    });
-    it('should be true if isReassignWizard', function() {
-      var hostComponents = Em.A([
-        Em.Object.create({componentName: 'c1', host: Em.Object.create({hostName: 'h1'})}),
-        Em.Object.create({componentName: 'c1', host: Em.Object.create({hostName: 'h2'})})
-      ]);
-      sinon.stub(App.HostComponent, 'find', function() {
-        return hostComponents;
-      });
-      c.reopen({
-        isReassignWizard: true,
-        content:{
-          reassign:{
-            component_name: 'c1'
-          }
-        },
-        servicesMasters: [
-          {selectedHost: 'h5'},
-          {selectedHost: 'h4'},
-          {selectedHost: 'h3'}
-        ]
-      });
-      expect(c.get('isSubmitDisabled')).to.equal(true);
-      App.HostComponent.find.restore();
-    });
-
-    it('should be false if isReassignWizard', function() {
-      var hostComponents = Em.A([
-        Em.Object.create({componentName: 'c1', host: Em.Object.create({hostName: 'h1'})}),
-        Em.Object.create({componentName: 'c1', host: Em.Object.create({hostName: 'h2'})}),
-        Em.Object.create({componentName: 'c1', host: Em.Object.create({hostName: 'h3'})})
-      ]);
-      sinon.stub(App.HostComponent, 'find', function() {
-        return hostComponents;
-      });
-      c.reopen({
-        isReassignWizard: true,
-        content:{
-          reassign:{
-            component_name: 'c1'
-          }
-        },
-        servicesMasters: [
-          {selectedHost: 'h1'},
-          {selectedHost: 'h2'}
-        ]
-      });
-      expect(c.get('isSubmitDisabled')).to.equal(false);
-      App.HostComponent.find.restore();
-    });
-
-  });
-
   describe('#masterHostMapping', function() {
     Em.A([
         {
@@ -1353,4 +1316,57 @@ describe('App.WizardStep5Controller', function () {
       });
   });
 
+  describe('#isHostNameValid', function() {
+
+    beforeEach(function() {
+      controller.set('hosts', [{host_name: 'h1'}]);
+      controller.set('selectedServicesMasters', [{component_name: 'c1', selectedHost: 'h2'}]);
+    });
+
+    it('hostname is empty', function() {
+      expect(controller.isHostNameValid('c1', '')).to.be.false;
+    });
+
+    it('hostname not exists', function() {
+      expect(controller.isHostNameValid('c1', 'h2')).to.be.false;
+    });
+
+    it('hostname is assigned to such component', function() {
+      controller.get('selectedServicesMasters').pushObject({component_name: 'c1', selectedHost:
'h2'});
+      expect(controller.isHostNameValid('c1', 'h2')).to.be.false;
+    });
+
+    it('hostname is valid', function() {
+      expect(controller.isHostNameValid('c1', 'h1')).to.be.true;
+    });
+
+  });
+
+  describe('#updateIsHostNameValidFlag', function() {
+
+    beforeEach(function() {
+      controller.set('selectedServicesMasters', [
+        Em.Object.create({component_name: 'ZOOKEEPER_SERVER', zId: 1, isHostNameValid: true}),
+        Em.Object.create({component_name: 'ZOOKEEPER_SERVER', zId: 2, isHostNameValid: true}),
+        Em.Object.create({component_name: 'c1', zId: null, isHostNameValid: true})
+      ]);
+    });
+
+    it('shouldn\'t do nothing componentName not provided', function() {
+      controller.updateIsHostNameValidFlag(null, null, false);
+      expect(controller.get('selectedServicesMasters').everyProperty('isHostNameValid', true)).to.be.true;
+    });
+
+    it('should update one multiple component', function() {
+      controller.updateIsHostNameValidFlag('ZOOKEEPER_SERVER', 2, false);
+      expect(controller.get('selectedServicesMasters').mapProperty('isHostNameValid')).to.eql([true,
false, true]);
+    });
+
+    it('should update single component', function() {
+      controller.updateIsHostNameValidFlag('c1', null, false);
+      expect(controller.get('selectedServicesMasters').mapProperty('isHostNameValid')).to.eql([true,
true, false]);
+    });
+
+  });
+
 });
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/441b0258/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
index d2e94ce..5e5031d 100644
--- a/ambari-web/test/views/wizard/step5_view_test.js
+++ b/ambari-web/test/views/wizard/step5_view_test.js
@@ -45,7 +45,9 @@ describe('App.SelectHostView', function() {
 
   beforeEach(function() {
     view = App.SelectHostView.create({
-      controller: App.WizardStep5Controller.create({})
+      controller: App.WizardStep5Controller.create({}),
+      $: function() {return {typeahead: function(){return {on: Em.K}}}},
+      updateErrorStatus: Em.K
     });
   });
 
@@ -60,19 +62,18 @@ describe('App.SelectHostView', function() {
       view.didInsertElement();
       expect(view.initContent.calledOnce).to.equal(true);
     });
-    it('should set selectedHost to value', function() {
-      view.set('selectedHost', 'h1');
+    it('should set component.selectedHost to value', function() {
+      view.set('component', {selectedHost: 'h1'});
       view.set('value', '');
       view.didInsertElement();
       expect(view.get('value')).to.equal('h1');
     });
   });
 
-  describe('#change', function() {
+  describe('#changeHandler', function() {
     beforeEach(function() {
-      view.set('componentName', 'ZOOKEEPER_SERVER');
+      view.set('component', {component_name: 'ZOOKEEPER_SERVER', zId: 1});
       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);
@@ -80,16 +81,23 @@ describe('App.SelectHostView', function() {
     afterEach(function() {
       view.get('controller').assignHostToMaster.restore();
     });
+
+    it('shouldn\'t do nothing if view is destroyed', function() {
+      view.set('state', 'destroyed');
+      expect(view.get('controller').assignHostToMaster.called).to.be.false;
+    });
+
     it('should call assignHostToMaster', function() {
-      view.change();
+      view.changeHandler();
       expect(view.get('controller').assignHostToMaster.calledWith('ZOOKEEPER_SERVER', 'h1',
1));
     });
-    it('should increment rebalanceComponentHostsCounter', function() {
-      view.change();
+    it('should increment rebalanceComponentHostsCounter if component is multiple', function()
{
+      view.set('component', {component_name: 'ZOOKEEPER_SERVER'});
+      view.changeHandler();
       expect(view.get('controller.rebalanceComponentHostsCounter')).to.equal(1);
     });
     it('should set componentToRebalance', function() {
-      view.change();
+      view.changeHandler();
       expect(view.get('controller.componentToRebalance')).to.equal('ZOOKEEPER_SERVER');
     });
   });
@@ -149,7 +157,7 @@ describe('App.SelectHostView', function() {
     tests.forEach(function(test) {
       it(test.m, function() {
         view.set('controller.hosts', test.hosts);
-        view.set('componentName', test.componentName);
+        view.set('component', {component_name: test.componentName});
         view.set('controller.selectedServicesMasters', test.selectedServicesMasters);
         var r = view.getAvailableHosts();
         expect(r.mapProperty('host_name')).to.eql(test.e);
@@ -157,45 +165,36 @@ describe('App.SelectHostView', function() {
     });
   });
 
-  describe('#rebalanceComponentHosts', function() {
+  describe('#rebalanceComponentHostsOnce', 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
+          initContent: false
         }
       },
       {
         componentName: 'c2',
         componentToRebalance: 'c2',
-        isLoaded: true,
         content: [{}],
         m: 'componentName equal to componentToRebalance',
         e: {
-          initContent: true,
-          isLoaded: false,
-          content: 0
+          initContent: true
         }
       }
     ]);
 
     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('component', {component_name: test.componentName});
         view.set('controller.componentToRebalance', test.componentToRebalance);
         sinon.stub(view, 'initContent', Em.K);
-        view.rebalanceComponentHosts();
+        view.rebalanceComponentHostsOnce();
         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();
       });
     });
@@ -204,43 +203,15 @@ describe('App.SelectHostView', function() {
   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) {
@@ -249,68 +220,35 @@ describe('App.SelectHostView', function() {
         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('#click', function() {
+  describe('#change', function() {
+
     beforeEach(function() {
-      sinon.stub(lazyloading, 'run', Em.K);
+      sinon.stub(view, 'changeHandler', Em.K);
     });
+
     afterEach(function() {
-      lazyloading.run.restore();
+      view.changeHandler.restore();
     });
-    Em.A([
-        {
-          isLoaded: true,
-          isLazyLoading: true,
-          e: false
-        },
-        {
-          isLoaded: true,
-          isLazyLoading: false,
-          e: false
-        },
-        {
-          isLoaded: false,
-          isLazyLoading: true,
-          e: true
-        },
-        {
-          isLoaded: false,
-          isLazyLoading: false,
-          e: false
-        }
-      ]).forEach(function(test) {
-      it('isLoaded = ' + test.isLoaded.toString() + ', isLazyLoading = ' + test.isLazyLoading.toString(),
function() {
-        view.reopen({
-          isLazyLoading: test.isLazyLoading,
-          isLoaded: test.isLoaded
-        });
-        view.click();
-        if(test.e) {
-          expect(lazyloading.run.calledOnce).to.equal(true);
-        }
-        else {
-          expect(lazyloading.run.called).to.equal(false);
-        }
-      });
+
+    it('shouldn\'t do nothing if view is destroyed', function() {
+      view.set('controller.hostNameCheckTrigger', false);
+      view.set('state', 'destroyed');
+      view.change();
+      expect(view.get('controller.hostNameCheckTrigger')).to.equal(false);
     });
-    it('check lazyLoading parameters', function() {
-      view.reopen({
-        isLoaded: false,
-        isLazyLoading: true,
-        content: [{host_name: 'host1'}, {host_name: 'host2'}]
-      });
-      var availableHosts = d3.range(1, 100).map(function(i) {return {host_name: 'host' +
i.toString()};});
-      sinon.stub(view, 'getAvailableHosts', function() {return availableHosts;});
-      view.click();
-      expect(lazyloading.run.args[0][0].source.length).to.equal(97); // 99-2
-      view.getAvailableHosts.restore();
+
+    it('should toggle hostNameCheckTrigger', function() {
+      view.set('controller.hostNameCheckTrigger', false);
+      view.change();
+      expect(view.get('controller.hostNameCheckTrigger')).to.equal(true);
     });
+
   });
 
 });


Mime
View raw message