AMBARI-18973 Service Auto Start: discard popup appears even when no changes were made. (atkach)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/29db2273 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/29db2273 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/29db2273 Branch: refs/heads/branch-feature-AMBARI-18634 Commit: 29db2273e77b8fd4f36c15a2001495a08099250a Parents: 6088c17 Author: Andrii Tkach <atk...@apache.org> Authored: Wed Nov 23 13:52:31 2016 +0200 Committer: Andrii Tkach <atk...@apache.org> Committed: Wed Nov 23 15:25:58 2016 +0200 ---------------------------------------------------------------------- ambari-web/app/assets/test/tests.js | 4 +- .../main/admin/service_auto_start.js | 342 +++++++++++-------- .../templates/main/admin/service_auto_start.hbs | 12 +- .../service_auto_start/component_auto_start.hbs | 2 +- .../app/views/main/admin/service_auto_start.js | 68 +--- .../service_auto_start/component_auto_start.js | 15 +- .../main/admin/service_auto_start_test.js | 326 ++++++++++++++++++ .../component_auto_start_test.js | 64 ++++ .../views/main/admin/service_auto_start_test.js | 83 +++++ 9 files changed, 703 insertions(+), 213 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/29db2273/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 959d1c6..4263016 100644 --- a/ambari-web/app/assets/test/tests.js +++ b/ambari-web/app/assets/test/tests.js @@ -65,7 +65,7 @@ var files = [ 'test/controllers/main/admin/kerberos/step6_controller_test', 'test/controllers/main/admin/kerberos/step7_controller_test', 'test/controllers/main/admin/kerberos/step8_controller_test', - + 'test/controllers/main/admin/service_auto_start_test', 'test/controllers/main/admin/stack_and_upgrade_controller_test', 'test/controllers/main/admin/stack_upgrade_history_controller_test', 'test/controllers/main/admin/serviceAccounts_controller_test', @@ -269,6 +269,8 @@ var files = [ 'test/views/main/admin/stack_upgrade/services_view_test', 'test/views/main/admin/stack_upgrade/menu_view_test', 'test/views/main/admin/stack_upgrade/failed_hosts_modal_view_test', + 'test/views/main/admin/service_auto_start/component_auto_start_test', + 'test/views/main/admin/service_auto_start_test', 'test/views/main/dashboard/config_history_view_test', 'test/views/main/dashboard/widget_test', 'test/views/main/dashboard/widgets_test', http://git-wip-us.apache.org/repos/asf/ambari/blob/29db2273/ambari-web/app/controllers/main/admin/service_auto_start.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers/main/admin/service_auto_start.js b/ambari-web/app/controllers/main/admin/service_auto_start.js index 3365cae..501e6bb 100644 --- a/ambari-web/app/controllers/main/admin/service_auto_start.js +++ b/ambari-web/app/controllers/main/admin/service_auto_start.js @@ -21,12 +21,87 @@ var App = require('app'); App.MainAdminServiceAutoStartController = Em.Controller.extend({ name: 'mainAdminServiceAutoStartController', + /** + * @type {?object} + * @default null + */ clusterConfigs: null, + + /** + * @type {Array} + */ componentsConfigs: [], + + /** + * @type {boolean} + * @default false + */ isSaveDisabled: true, - valueChanged: false, - syncTrigger: false, // trigger status reset in switch view after "save" - revertTrigger: false, // trigger status reset in switch view after "discard" + + /** + * Current value of servicesAutoStart + * @type {boolean} + */ + servicesAutoStart: false, + + /** + * Value of servicesAutoStart saved on server + * @type {boolean} + */ + servicesAutoStartSaved: false, + + /** + * config version tag, + * required to sync cluster configs locally without reload + * @type {?object} + */ + tag: null, + + /** + * @type {boolean} + */ + isServicesAutoStartChanged: Em.computed.notEqualProperties('servicesAutoStart', 'servicesAutoStartSaved'), + + valueChanged: function() { + var isSaveDisabled = true; + + if (this.get('isServicesAutoStartChanged')) { + this.set('clusterConfigs.recovery_enabled', this.get('servicesAutoStart') + ''); + isSaveDisabled = false; + } + this.get('tabs').forEach(function(tab) { + if (isSaveDisabled) { + isSaveDisabled = !tab.get('components').someProperty('isChanged'); + } + }); + + this.set('isSaveDisabled', isSaveDisabled); + }, + + load: function() { + var self = this; + var dfd = $.Deferred(); + + return this.loadClusterConfig().done(function (data) { + var tag = [ + { + siteName: 'cluster-env', + tagName: data.Clusters.desired_configs['cluster-env'].tag, + newTagName: null + } + ]; + self.set('tag', tag); + App.router.get('configurationController').getConfigsByTags(tag).done(function (data) { + var servicesAutoStart = data[0].properties.recovery_enabled === 'true'; + self.set('clusterConfigs', data[0].properties); + self.set('servicesAutoStart', servicesAutoStart); + self.set('servicesAutoStartSaved', servicesAutoStart); + self.loadComponentsConfigs().done(dfd.resolve).fail(dfd.reject); + }).fail(dfd.reject); + }).fail(dfd.reject); + + return dfd.promise(); + }, loadClusterConfig: function () { return App.ajax.send({ @@ -50,64 +125,53 @@ App.MainAdminServiceAutoStartController = Em.Controller.extend({ this.set('componentsConfigs', data.items); }, + saveClusterConfigs: function (clusterConfigs) { + return App.ajax.send({ + name: 'admin.save_configs', + sender: this, + data: { + siteName: 'cluster-env', + properties: clusterConfigs + } + }); + }, + + saveComponentSettingsCall: function(recoveryEnabled, components) { + return App.ajax.send({ + name: 'components.update', + sender: this, + data: { + ServiceComponentInfo: { + recovery_enabled: recoveryEnabled + }, + query: 'ServiceComponentInfo/component_name.in(' + components.join(',') + ')' + } + }); + }, + tabs: function() { var services = {}; var tabs = []; - this.get('componentsConfigs').forEach(function(component) { + + this.get('componentsConfigs').forEach(function (component) { var serviceComponentInfo = component.ServiceComponentInfo; if (serviceComponentInfo.total_count) { if (serviceComponentInfo.category === "MASTER" || serviceComponentInfo.category === "SLAVE") { - var componentRecovery = Ember.Object.create({ - display_name: App.format.role(serviceComponentInfo.component_name, false), - component_name: serviceComponentInfo.component_name, - recovery_enabled: serviceComponentInfo.recovery_enabled === 'true', - valueChanged: false, - service_name: serviceComponentInfo.service_name, - syncTrigger: false, - revertTrigger: false, - }); - if (services[serviceComponentInfo.service_name]) { - services[serviceComponentInfo.service_name].get('componentRecovery').push(componentRecovery); - services[serviceComponentInfo.service_name].set('enabledComponents', services[serviceComponentInfo.service_name].get('enabledComponents') + (componentRecovery.get('recovery_enabled') ? 1 : 0)); - services[serviceComponentInfo.service_name].set('totalComponents', services[serviceComponentInfo.service_name].get('totalComponents') + 1); + var componentRecovery = this.createRecoveryComponent(serviceComponentInfo); + var service = services[serviceComponentInfo.service_name]; + + if (service) { + service.get('components').pushObject(componentRecovery); + service.set('enabledComponents', services[serviceComponentInfo.service_name].get('enabledComponents') + (componentRecovery.get('recovery_enabled') ? 1 : 0)); + service.set('totalComponents', services[serviceComponentInfo.service_name].get('totalComponents') + 1); } else { - services[serviceComponentInfo.service_name] = Ember.Object.create({ - service_name: serviceComponentInfo.service_name, - display_name: App.format.role(serviceComponentInfo.service_name, true), - headingClass: "." + serviceComponentInfo.service_name, - isActive: false, - tooltip: function () { - var percentage = this.get('enabledComponents') / this.get('totalComponents'); - var tooltip = ''; - if (percentage === 1) { - tooltip = Em.I18n.t('admin.serviceAutoStart.tooltip.text').format("All"); - } else if (percentage === 0) { - tooltip = Em.I18n.t('admin.serviceAutoStart.tooltip.text').format("No"); - } else { - tooltip = Em.I18n.t('admin.serviceAutoStart.tooltip.text').format(this.get('enabledComponents') + "/" + this.get('totalComponents')); - } - return tooltip; - }.property('enabledComponents', 'totalComponents'), - componentRecovery: [componentRecovery], - enabledComponents: componentRecovery.recovery_enabled ? 1 : 0, - totalComponents: 1, - indicator: function () { - var percentage = this.get('enabledComponents') / this.get('totalComponents'); - var indicator = "icon-adjust"; - if (percentage === 1) { - indicator = "icon-circle"; - } else if (percentage === 0) { - indicator = "icon-circle-blank"; - } - return indicator; - }.property('enabledComponents', 'totalComponents') - }); + services[serviceComponentInfo.service_name] = this.createTab(serviceComponentInfo, componentRecovery); } } } - }); - for (var service in services ) { - tabs.push(services[service]); + }, this); + for (var name in services ) { + tabs.push(services[name]); } if (tabs.length) { tabs[0].set('isActive', true); @@ -115,54 +179,93 @@ App.MainAdminServiceAutoStartController = Em.Controller.extend({ return tabs; }.property('componentsConfigs'), - checkValuesChange: function () { - var valuesChanged = this.get('valueChanged'); - this.get('tabs').forEach(function (service) { - service.get('componentRecovery').forEach(function (component) { - valuesChanged = valuesChanged || component.get('valueChanged'); + createRecoveryComponent: function(serviceComponentInfo) { + return Ember.Object.create({ + displayName: App.format.role(serviceComponentInfo.component_name, false), + componentName: serviceComponentInfo.component_name, + recoveryEnabled: serviceComponentInfo.recovery_enabled === 'true', + recoveryEnabledSaved: serviceComponentInfo.recovery_enabled === 'true', + isChanged: Em.computed.notEqualProperties('recoveryEnabled', 'recoveryEnabledSaved'), + serviceName: serviceComponentInfo.service_name + }); + }, + + createTab: function(serviceComponentInfo, componentRecovery) { + return Ember.Object.create({ + service_name: serviceComponentInfo.service_name, + display_name: App.format.role(serviceComponentInfo.service_name, true), + headingClass: "." + serviceComponentInfo.service_name, + isActive: false, + tooltip: function () { + var percentage = this.get('enabledComponents') / this.get('totalComponents'); + var text = Em.I18n.t('admin.serviceAutoStart.tooltip.text'); + if (percentage === 1) { + return text.format("All"); + } else if (percentage === 0) { + return text.format("No"); + } else { + return text.format(this.get('enabledComponents') + "/" + this.get('totalComponents')); + } + }.property('enabledComponents', 'totalComponents'), + components: Em.A([componentRecovery]), + enabledComponents: componentRecovery.recovery_enabled ? 1 : 0, + totalComponents: 1, + indicator: function () { + var percentage = this.get('enabledComponents') / this.get('totalComponents'); + var indicator = "icon-adjust"; + if (percentage === 1) { + indicator = "icon-circle"; + } else if (percentage === 0) { + indicator = "icon-circle-blank"; + } + return indicator; + }.property('enabledComponents', 'totalComponents') + }); + }, + + filterTabsByRecovery: function(tabs, isRecoveryEnabled) { + var components = []; + + tabs.forEach(function (service) { + service.get('components').forEach(function (component) { + if (component.get('isChanged') && component.get('recoveryEnabled') === isRecoveryEnabled) { + components.push(component.get('componentName')); + } }); }); - this.set('isSaveDisabled', !valuesChanged); - }.observes('valueChanged'), + return components; + }, syncStatus: function () { - // component level switches - this.get('tabs').forEach(function (service) { - service.get('componentRecovery').forEach(function (component) { - component.set('valueChanged', false); - component.toggleProperty('syncTrigger'); + var servicesAutoStart = this.get('servicesAutoStart'); + this.set('servicesAutoStartSaved', servicesAutoStart); + App.router.get('configurationController').getConfigsByTags(this.get('tag')).done(function(data) { + data[0].properties.recovery_enabled = servicesAutoStart + ''; + App.router.get('configurationController').saveToDB(data); + }); + this.get('tabs').forEach(function(tab) { + tab.get('components').forEach(function(component) { + component.set('recoveryEnabledSaved', component.get('recoveryEnabled')); }); }); - // service level switch - this.toggleProperty('syncTrigger'); - this.set('valueChanged', false); - this.set('isSaveDisabled', true); + this.valueChanged(); }, revertStatus: function () { - // component level switches - this.get('tabs').forEach(function (service) { - service.get('componentRecovery').forEach(function (component) { - component.set('valueChanged', false); - component.toggleProperty('revertTrigger'); + this.set('servicesAutoStart', this.get('servicesAutoStartSaved')); + this.get('tabs').forEach(function(tab) { + tab.get('components').forEach(function(component) { + component.set('recoveryEnabled', component.get('recoveryEnabledSaved')); }); }); - // service level switch - this.toggleProperty('revertTrigger'); - this.set('valueChanged', false); - this.set('isSaveDisabled', true); }, enableAll: function (event) { - event.context.get('componentRecovery').forEach(function (component) { - component.set('recoveryEnabled', true); - }); + event.context.get('components').setEach('recoveryEnabled', true); }, disableAll: function (event) { - event.context.get('componentRecovery').forEach(function (component) { - component.set('recoveryEnabled', false); - }); + event.context.get('components').setEach('recoveryEnabled', false); }, /** @@ -193,79 +296,38 @@ App.MainAdminServiceAutoStartController = Em.Controller.extend({ primary: Em.I18n.t('common.save'), secondary: Em.I18n.t('common.cancel'), onSave: function () { - //save cluster setting - if (self.get('valueChanged')) { - self.saveClusterConfigs(self.get('clusterConfigs')); + var clusterConfigsCall, enabledComponentsCall, disabledComponentsCall; + + if (self.get('isServicesAutoStartChanged')) { + clusterConfigsCall = self.saveClusterConfigs(self.get('clusterConfigs')); } - //save component settings - var enabledComponents = []; - var disabledComponents = []; - self.get('tabs').forEach(function (service) { - service.get('componentRecovery').forEach(function (component) { - if (component.get('valueChanged')) { - if (component.get('recovery_enabled')) { - enabledComponents.push(component.get('component_name')); - } else { - disabledComponents.push(component.get('component_name')); - } - } - }); - }); - if (enabledComponents.length){ - var promise1 = App.ajax.send({ - name: 'components.update', - sender: this, - data: { - ServiceComponentInfo: { - recovery_enabled: "true" - }, - query: 'ServiceComponentInfo/component_name.in(' + enabledComponents.join(',') + ')' - } - }); + var enabledComponents = self.filterTabsByRecovery(self.get('tabs'), true); + var disabledComponents = self.filterTabsByRecovery(self.get('tabs'), false); + + if (enabledComponents.length) { + enabledComponentsCall = self.saveComponentSettingsCall('true', enabledComponents); } - if (disabledComponents.length){ - var promise2 = App.ajax.send({ - name: 'components.update', - sender: this, - data: { - ServiceComponentInfo: { - recovery_enabled: "false" - }, - query: 'ServiceComponentInfo/component_name.in(' + disabledComponents.join(',') + ')' - } - }); + if (disabledComponents.length) { + disabledComponentsCall = self.saveComponentSettingsCall('false', disabledComponents); } - $.when(promise1, promise2).done( - function () { - if (typeof transitionCallback === 'function') { - transitionCallback(); - } - self.syncStatus(); + $.when(clusterConfigsCall, enabledComponentsCall, disabledComponentsCall).done(function () { + if (typeof transitionCallback === 'function') { + transitionCallback(); } - ); + self.syncStatus(); + }); this.hide(); }, onDiscard: function () { + self.revertStatus(); if (typeof transitionCallback === 'function') { transitionCallback(); } - self.revertStatus(); this.hide(); }, onCancel: function () { this.hide(); } }); - }, - - saveClusterConfigs: function (clusterConfigs) { - return App.ajax.send({ - name: 'admin.save_configs', - sender: this, - data: { - siteName: 'cluster-env', - properties: clusterConfigs - } - }); } }); http://git-wip-us.apache.org/repos/asf/ambari/blob/29db2273/ambari-web/app/templates/main/admin/service_auto_start.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/main/admin/service_auto_start.hbs b/ambari-web/app/templates/main/admin/service_auto_start.hbs index 91d3706..be101e7 100644 --- a/ambari-web/app/templates/main/admin/service_auto_start.hbs +++ b/ambari-web/app/templates/main/admin/service_auto_start.hbs @@ -24,7 +24,7 @@ <strong>{{t admin.serviceAutoStart.body.text}}</strong> </div> <div class="col-md-4"> - {{view App.CheckboxView checkedBinding="view.switcherValue"}} + {{view App.CheckboxView checkedBinding="controller.servicesAutoStart"}} </div> <div class="col-md-6"> <div class="pull-right operations-button"> @@ -33,7 +33,7 @@ </div> </div> </div> - {{#if view.switcherValue}} + {{#if view.isLoaded}} <hr> <div class="row"> <div class="col-md-4 col-lg-3"><h5>{{t common.service}}</h5></div> @@ -59,20 +59,22 @@ {{#each tab in controller.tabs}} <div {{bindAttr class=":tab-pane tab.isActive:active tab.service_name"}}> <table class="table"> - {{#each component in tab.componentRecovery}} + {{#each component in tab.components}} <tr> <td class="col-md-4"> {{component.display_name}} </td> <td class="col-md-8"> - {{view App.MainAdminServiceAutoStartComponentView recoveryEnabledBinding="component.recovery_enabled" componentBinding="component" tabBinding="tab"}} + {{view App.MainAdminServiceAutoStartComponentView componentBinding="component" tabBinding="tab"}} </td> </tr> {{/each}} <tr> <td class="col-md-4"></td> <td class="col-md-8"> - <a href="#" class="enable-all-link" {{action enableAll tab target="controller"}}>{{t common.enableAll}}</a> | + <a href="#" class="enable-all-link" {{action enableAll tab target="controller"}}> + {{t common.enableAll}} + </a> | <a href="#" {{action disableAll tab target="controller"}}>{{t common.disableAll}}</a> </td> </tr> http://git-wip-us.apache.org/repos/asf/ambari/blob/29db2273/ambari-web/app/templates/main/admin/service_auto_start/component_auto_start.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/main/admin/service_auto_start/component_auto_start.hbs b/ambari-web/app/templates/main/admin/service_auto_start/component_auto_start.hbs index 06a17f8..a52dcfd 100644 --- a/ambari-web/app/templates/main/admin/service_auto_start/component_auto_start.hbs +++ b/ambari-web/app/templates/main/admin/service_auto_start/component_auto_start.hbs @@ -16,4 +16,4 @@ * limitations under the License. }} -{{view App.CheckboxView checkedBinding="view.recoveryEnabled"}} +{{view App.CheckboxView checkedBinding="view.component.recoveryEnabled"}} http://git-wip-us.apache.org/repos/asf/ambari/blob/29db2273/ambari-web/app/views/main/admin/service_auto_start.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/main/admin/service_auto_start.js b/ambari-web/app/views/main/admin/service_auto_start.js index 5b10d1b..7b4e46c 100644 --- a/ambari-web/app/views/main/admin/service_auto_start.js +++ b/ambari-web/app/views/main/admin/service_auto_start.js @@ -20,49 +20,26 @@ var App = require('app'); App.MainAdminServiceAutoStartView = Em.View.extend({ templateName: require('templates/main/admin/service_auto_start'), + /** - * Value used in the checkbox. - * - * @property switcherValue * @type {boolean} + * @default false */ - switcherValue: false, - - savedRecoveryEnabled: false, + isLoaded: false, didInsertElement: function () { var self = this; - this.get('controller').loadClusterConfig().done(function (data) { - var tag = [ - { - siteName: 'cluster-env', - tagName: data.Clusters.desired_configs['cluster-env'].tag, - newTagName: null - } - ]; - App.router.get('configurationController').getConfigsByTags(tag).done(function (data) { - self.set('controller.clusterConfigs', data[0].properties); - self.set('switcherValue', data[0].properties.recovery_enabled === 'true'); - self.set('savedRecoveryEnabled', self.get('switcherValue')); - // plugin should be initiated after applying binding for switcherValue - Em.run.later('sync', function() { - self.initSwitcher(); - }.bind(self), 10); - self.get('controller').loadComponentsConfigs(); - }); + this.get('controller').load().then(function() { + self.set('isLoaded', true); + self.initSwitcher(); }); }, - /** - * Init switcher plugin. - * - * @method initSwitcher - */ - updateClusterConfigs: function (state){ - this.set('switcherValue', state); - this.set('controller.clusterConfigs.recovery_enabled', '' + state); - this.set('controller.valueChanged', this.get('savedRecoveryEnabled') !== state); - }, + onValueChange: function () { + if (this.get('switcher')) { + this.get('switcher').bootstrapSwitch('state', this.get('controller.servicesAutoStart')); + } + }.observes('controller.servicesAutoStart'), /** * Init switcher plugin. @@ -71,33 +48,20 @@ App.MainAdminServiceAutoStartView = Em.View.extend({ */ initSwitcher: function () { var self = this; - if (this.$()) { + if (this.$) { this.set('switcher', this.$("input:eq(0)").bootstrapSwitch({ + state: self.get('controller.servicesAutoStart'), onText: Em.I18n.t('common.enabled'), offText: Em.I18n.t('common.disabled'), offColor: 'default', onColor: 'success', handleWidth: Math.max(Em.I18n.t('common.enabled').length, Em.I18n.t('common.disabled').length) * 8, onSwitchChange: function (event, state) { - self.updateClusterConfigs(state); + self.set('controller.servicesAutoStart', state); + self.get('controller').valueChanged(); } })); } - }, - - syncComponentRecoveryStatus: function () { - this.set('savedRecoveryEnabled', this.get('switcherValue')); - }.observes('controller.syncTrigger'), - - revertComponentRecoveryStatus: function () { - this.set('switcherValue', this.get('savedRecoveryEnabled')); - if (this.get('controller.clusterConfigs')) { - this.set('controller.clusterConfigs.recovery_enabled', '' + this.get('savedRecoveryEnabled')); - } - var switcher = this.get('switcher'); - if (switcher) { - switcher.bootstrapSwitch('state', this.get('savedRecoveryEnabled')); - } - }.observes('controller.revertTrigger') + } }); http://git-wip-us.apache.org/repos/asf/ambari/blob/29db2273/ambari-web/app/views/main/admin/service_auto_start/component_auto_start.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/main/admin/service_auto_start/component_auto_start.js b/ambari-web/app/views/main/admin/service_auto_start/component_auto_start.js index ceafd21..8588b04 100644 --- a/ambari-web/app/views/main/admin/service_auto_start/component_auto_start.js +++ b/ambari-web/app/views/main/admin/service_auto_start/component_auto_start.js @@ -21,24 +21,13 @@ var App = require('app'); App.MainAdminServiceAutoStartComponentView = Em.View.extend({ templateName: require('templates/main/admin/service_auto_start/component_auto_start'), - recoveryEnabled: false, - savedRecoveryEnabled: false, tab: null, component: null, didInsertElement: function () { - this.set('savedRecoveryEnabled', this.get('recoveryEnabled')); this.initSwitcher(); }, - syncComponentRecoveryStatus: function () { - this.set('savedRecoveryEnabled', this.get('component.recoveryEnabled')) - }.observes('component.syncTrigger'), - - revertComponentRecoveryStatus: function () { - this.set('component.recoveryEnabled', this.get('savedRecoveryEnabled')); - }.observes('component.revertTrigger'), - onValueChange: function () { this.get('switcher').bootstrapSwitch('state', this.get('component.recoveryEnabled')); }.observes('component.recoveryEnabled'), @@ -59,10 +48,8 @@ App.MainAdminServiceAutoStartComponentView = Em.View.extend({ handleWidth: Math.max(Em.I18n.t('common.enabled').length, Em.I18n.t('common.disabled').length) * 8, onSwitchChange: function (event, state) { self.set('tab.enabledComponents', self.get('tab.enabledComponents') + (state ? 1 : -1)); - self.set('recoveryEnabled', state); self.set('component.recoveryEnabled', state); - self.set('component.valueChanged', self.get('savedRecoveryEnabled') !== state); - self.get('parentView.controller').checkValuesChange(); + self.get('controller').valueChanged(); } })); } http://git-wip-us.apache.org/repos/asf/ambari/blob/29db2273/ambari-web/test/controllers/main/admin/service_auto_start_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/controllers/main/admin/service_auto_start_test.js b/ambari-web/test/controllers/main/admin/service_auto_start_test.js new file mode 100644 index 0000000..8cb176e --- /dev/null +++ b/ambari-web/test/controllers/main/admin/service_auto_start_test.js @@ -0,0 +1,326 @@ +/** + * 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 testHelpers = require('test/helpers'); + +describe('App.MainAdminServiceAutoStartController', function() { + var controller; + + beforeEach(function() { + controller = App.MainAdminServiceAutoStartController.create({ + clusterConfigs: {} + }); + }); + + + describe('#valueChanged()', function() { + + it('servicesAutoStart is changed', function() { + controller.reopen({ + servicesAutoStart: true, + servicesAutoStartSaved: false, + tabs: [] + }); + controller.valueChanged(); + expect(controller.get('isSaveDisabled')).to.be.false; + }); + + it('servicesAutoStart is not changed', function() { + controller.reopen({ + servicesAutoStart: true, + servicesAutoStartSaved: true, + tabs: [] + }); + controller.valueChanged(); + expect(controller.get('isSaveDisabled')).to.be.true; + }); + + it('components state is not changed', function() { + controller.reopen({ + servicesAutoStart: true, + servicesAutoStartSaved: true, + tabs: [Em.Object.create({ + components: [ + Em.Object.create({ + isChanged: false + }) + ] + })] + }); + controller.valueChanged(); + expect(controller.get('isSaveDisabled')).to.be.true; + }); + + it('components state is changed', function() { + controller.reopen({ + servicesAutoStart: true, + servicesAutoStartSaved: true, + tabs: [Em.Object.create({ + components: [ + Em.Object.create({ + isChanged: true + }) + ] + })] + }); + controller.valueChanged(); + expect(controller.get('isSaveDisabled')).to.be.false; + }); + }); + + describe('#loadClusterConfig()', function() { + + it('App.ajax.send should be called', function() { + controller.loadClusterConfig(); + var args = testHelpers.findAjaxRequest('name', 'config.tags.site'); + expect(args[0]).to.be.eql({ + name: 'config.tags.site', + sender: controller, + data: { + site: 'cluster-env' + } + }); + }); + }); + + describe('#loadComponentsConfigs()', function() { + + it('App.ajax.send should be called', function() { + controller.loadComponentsConfigs(); + var args = testHelpers.findAjaxRequest('name', 'components.get_category'); + expect(args[0]).to.be.eql({ + name: 'components.get_category', + sender: controller, + success: 'loadComponentsConfigsSuccess' + }); + }); + }); + + describe('#loadComponentsConfigsSuccess()', function() { + + it('componentsConfigs should be set', function() { + controller.loadComponentsConfigsSuccess({items: {prop1: 'val1'}}); + expect(controller.get('componentsConfigs')).to.be.eql({prop1: 'val1'}); + }); + }); + + describe('#saveClusterConfigs()', function() { + var clusterConfigs = {}; + + it('App.ajax.send should be called', function() { + controller.saveClusterConfigs(clusterConfigs); + var args = testHelpers.findAjaxRequest('name', 'admin.save_configs'); + expect(args[0]).to.be.eql({ + name: 'admin.save_configs', + sender: controller, + data: { + siteName: 'cluster-env', + properties: clusterConfigs + } + }); + }); + }); + + describe('#saveComponentSettingsCall()', function() { + it('App.ajax.send should be called', function() { + controller.saveComponentSettingsCall(true, ['c1', 'c2']); + var args = testHelpers.findAjaxRequest('name', 'components.update'); + expect(args[0]).to.be.eql({ + name: 'components.update', + sender: controller, + data: { + ServiceComponentInfo: { + recovery_enabled: true + }, + query: 'ServiceComponentInfo/component_name.in(c1,c2)' + } + }); + }); + }); + + describe('#createRecoveryComponent()', function() { + + it('should return recovery component', function() { + var serviceComponentInfo = { + component_name: 'c1', + recovery_enabled: 'true', + service_name: 's1' + }; + expect(controller.createRecoveryComponent(serviceComponentInfo)).to.be.an.object; + }); + }); + + describe('#createTab()', function() { + + it('should return tab', function() { + var serviceComponentInfo = { + component_name: 'c1', + recovery_enabled: 'true', + service_name: 's1' + }; + expect(controller.createTab(serviceComponentInfo, {})).to.be.an.object; + }); + }); + + describe('#filterTabsByRecovery()', function() { + + it('should return empty when no components were changed', function() { + var tabs = [Em.Object.create({ + components: [ + Em.Object.create({ + isChanged: false + }) + ] + })]; + expect(controller.filterTabsByRecovery(tabs, true)).to.be.empty; + }); + + it('should return enabled components ', function() { + var tabs = [Em.Object.create({ + components: [ + Em.Object.create({ + isChanged: true, + recoveryEnabled: true + }) + ] + })]; + expect(controller.filterTabsByRecovery(tabs, true)).to.have.length(1); + }); + + it('should return disabled components ', function() { + var tabs = [Em.Object.create({ + components: [ + Em.Object.create({ + isChanged: true, + recoveryEnabled: false + }) + ] + })]; + expect(controller.filterTabsByRecovery(tabs, false)).to.have.length(1); + }); + }); + + describe('#syncStatus()', function() { + var mock = { + getConfigsByTags: function() { + return { + done: function(callback) { + callback([{properties: {}}]); + } + } + }, + saveToDB: Em.K + }; + + beforeEach(function() { + sinon.stub(App.router, 'get').returns(mock); + sinon.spy(mock, 'saveToDB'); + sinon.stub(controller, 'valueChanged'); + }); + + afterEach(function() { + App.router.get.restore(); + mock.saveToDB.restore(); + controller.valueChanged.restore(); + }); + + it('should save servicesAutoStart to local DB', function() { + controller.setProperties({ + servicesAutoStart: true + }); + controller.syncStatus(); + expect(mock.saveToDB.getCall(0).args[0]).to.be.eql([{ + properties: { + recovery_enabled: 'true' + } + }]); + }); + + it('recoveryEnabledSaved should be synced with recoveryEnabled', function() { + controller.reopen({ + servicesAutoStart: true, + tabs: [Em.Object.create({ + components: [ + Em.Object.create({ + recoveryEnabled: true, + recoveryEnabledSaved: false + }) + ] + })] + }); + controller.syncStatus(); + expect(controller.get('tabs')[0].get('components')[0].get('recoveryEnabledSaved')).to.be.true; + }); + + it('valueChanged should be called', function() { + controller.syncStatus(); + expect(controller.valueChanged).to.be.calledonce; + }); + }); + + describe('#revertStatus()', function() { + + it('component recoveryEnabled should be reverted', function() { + controller.reopen({ + tabs: [Em.Object.create({ + components: [ + Em.Object.create({ + recoveryEnabled: true, + recoveryEnabledSaved: false + }) + ] + })] + }); + controller.revertStatus(); + expect(controller.get('tabs')[0].get('components')[0].get('recoveryEnabled')).to.be.false; + }); + + it('servicesAutoStart should be reverted', function() { + controller.reopen({ + servicesAutoStart: true, + servicesAutoStartSaved: false + }); + controller.revertStatus(); + expect(controller.get('servicesAutoStart')).to.be.false; + }); + }); + + describe('#enableAll()', function() { + + it('should set each recoveryEnabled to true', function() { + var components = [ + Em.Object.create({recoveryEnabled: false}) + ]; + controller.enableAll({context: Em.Object.create({components: components})}); + expect(components[0].get('recoveryEnabled')).to.be.true; + }); + }); + + describe('#disableAll()', function() { + + it('should set each recoveryEnabled to false', function() { + var components = [ + Em.Object.create({recoveryEnabled: true}) + ]; + controller.disableAll({context: Em.Object.create({components: components})}); + expect(components[0].get('recoveryEnabled')).to.be.false; + }); + }); + +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/29db2273/ambari-web/test/views/main/admin/service_auto_start/component_auto_start_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/views/main/admin/service_auto_start/component_auto_start_test.js b/ambari-web/test/views/main/admin/service_auto_start/component_auto_start_test.js new file mode 100644 index 0000000..70fd61e --- /dev/null +++ b/ambari-web/test/views/main/admin/service_auto_start/component_auto_start_test.js @@ -0,0 +1,64 @@ +/** + * 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 view; + +describe('App.MainAdminServiceAutoStartComponentView', function () { + + beforeEach(function () { + view = App.MainAdminServiceAutoStartComponentView.create(); + }); + + + describe('#didInsertElement()', function() { + + beforeEach(function() { + sinon.stub(view, 'initSwitcher'); + }); + + afterEach(function() { + view.initSwitcher.restore(); + }); + + it('initSwitcher should be called', function() { + view.didInsertElement(); + expect(view.initSwitcher).to.be.calledOnce; + }); + }); + + describe('#onValueChange()', function() { + var mock = { + bootstrapSwitch: Em.K + }; + + beforeEach(function() { + sinon.spy(mock, 'bootstrapSwitch'); + }); + + afterEach(function() { + mock.bootstrapSwitch.restore(); + }); + + it('bootstrapSwitch should be called', function() { + view.set('switcher', mock); + view.onValueChange(); + expect(mock.bootstrapSwitch).to.be.calledOnce; + }); + }); +}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/29db2273/ambari-web/test/views/main/admin/service_auto_start_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/views/main/admin/service_auto_start_test.js b/ambari-web/test/views/main/admin/service_auto_start_test.js new file mode 100644 index 0000000..f45f784 --- /dev/null +++ b/ambari-web/test/views/main/admin/service_auto_start_test.js @@ -0,0 +1,83 @@ +/** + * 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 view; + +describe('App.MainAdminServiceAutoStartView', function () { + + beforeEach(function () { + view = App.MainAdminServiceAutoStartView.create({ + controller: Em.Object.create({ + load: Em.K + }) + }); + }); + + + describe('#didInsertElement()', function() { + + beforeEach(function() { + sinon.stub(view, 'initSwitcher'); + sinon.stub(view.get('controller'), 'load').returns({ + then: Em.clb + }) + }); + + afterEach(function() { + view.initSwitcher.restore(); + view.get('controller').load.restore(); + }); + + it('initSwitcher should be called', function() { + view.didInsertElement(); + expect(view.initSwitcher).to.be.calledOnce; + }); + + it('isLoaded should be true', function() { + view.didInsertElement(); + expect(view.get('isLoaded')).to.be.true; + }); + }); + + describe('#onValueChange()', function() { + var mock = { + bootstrapSwitch: Em.K + }; + + beforeEach(function() { + sinon.spy(mock, 'bootstrapSwitch'); + }); + + afterEach(function() { + mock.bootstrapSwitch.restore(); + }); + + it('bootstrapSwitch should not be called', function() { + view.set('switcher', null); + view.onValueChange(); + expect(mock.bootstrapSwitch).to.not.be.called; + }); + + it('bootstrapSwitch should be called', function() { + view.set('switcher', mock); + view.onValueChange(); + expect(mock.bootstrapSwitch).to.be.calledOnce; + }); + }); +}); \ No newline at end of file