Return-Path: X-Original-To: apmail-ambari-commits-archive@www.apache.org Delivered-To: apmail-ambari-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id C6884117D5 for ; Fri, 6 Jun 2014 12:50:15 +0000 (UTC) Received: (qmail 28306 invoked by uid 500); 6 Jun 2014 12:50:15 -0000 Delivered-To: apmail-ambari-commits-archive@ambari.apache.org Received: (qmail 28276 invoked by uid 500); 6 Jun 2014 12:50:15 -0000 Mailing-List: contact commits-help@ambari.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: ambari-dev@ambari.apache.org Delivered-To: mailing list commits@ambari.apache.org Received: (qmail 28269 invoked by uid 99); 6 Jun 2014 12:50:15 -0000 Received: from tyr.zones.apache.org (HELO tyr.zones.apache.org) (140.211.11.114) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 06 Jun 2014 12:50:15 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id 4B67A1F16; Fri, 6 Jun 2014 12:50:13 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: onechiporenko@apache.org To: commits@ambari.apache.org Message-Id: <30d2fb064b584de8951850802cd6a9cf@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: git commit: AMBARI-6046. Lags on Assign Masters step on big cluster. (onechiporenko) Date: Fri, 6 Jun 2014 12:50:13 +0000 (UTC) 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 Authored: Fri Jun 6 15:47:33 2014 +0300 Committer: Oleg Nechiporenko 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 * }, * .... * ] * * @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: + *
    + *
  • host name shouldn't be empty
  • + *
  • host should exist
  • + *
  • host should have only one component with componentName
  • + *
+ * @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 isHostNameValid property with flag value + * for component with name componentName and + * zId-property equal to zId-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}} {{else}} - {{view App.SelectHostView - optionValuePath="content.host_name" - optionLabelPath="content.host_info" - selectedHostBinding="selectedHost" - componentNameBinding="component_name" - class="host-select" - zIdBinding="zId" - disabledBinding="isInstalled" - }} +
+ {{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}} +
{{/if}} @@ -90,7 +84,7 @@ {{#each masterHostMapping}}
{{hostInfo}}
- {{#each masterServices}} + {{#each masterServicesToDisplay}} {{display_name}} {{/each}}
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 controller.servicesMasters + * 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 changeHandler 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 error 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 value (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 component.isHostNameValid 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 source property of typeahead 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); }); + }); });