Repository: ambari Updated Branches: refs/heads/trunk 7acc90952 -> 07b423677
AMBARI-17813 Cover configurations mixin with unit tests. (atkach) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/07b42367 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/07b42367 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/07b42367 Branch: refs/heads/trunk Commit: 07b423677ab3ab87debffdb732b5d95a7f9ae13c Parents: 7acc909 Author: Andrii Tkach <[email protected]> Authored: Wed Jul 20 18:23:18 2016 +0300 Committer: Andrii Tkach <[email protected]> Committed: Thu Jul 21 14:09:11 2016 +0300 ---------------------------------------------------------------------- ambari-web/app/assets/test/tests.js | 1 + .../configs/component_actions_by_configs.js | 149 +++--- .../main/service/configs/config_overridable.js | 143 +++-- .../service/configs/widget_popover_support.js | 2 +- .../component_actions_by_configs_test.js | 519 +++++++++++++++++++ .../service/configs/config_overridable_test.js | 357 ++++++++++++- .../configs/widget_popover_support_test.js | 165 +++++- 7 files changed, 1212 insertions(+), 124 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/07b42367/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 2b73b39..0bd8c2d 100644 --- a/ambari-web/app/assets/test/tests.js +++ b/ambari-web/app/assets/test/tests.js @@ -168,6 +168,7 @@ var files = [ 'test/mixins/main/host/details/host_components/install_component_test', 'test/mixins/main/service/configs/widget_popover_support_test', 'test/mixins/main/service/configs/config_overridable_test', + 'test/mixins/main/service/configs/component_actions_by_configs_test', 'test/mixins/routers/redirections_test', 'test/mixins/wizard/addSeccurityConfigs_test', 'test/mixins/wizard/assign_master_components_test', http://git-wip-us.apache.org/repos/asf/ambari/blob/07b42367/ambari-web/app/mixins/main/service/configs/component_actions_by_configs.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/mixins/main/service/configs/component_actions_by_configs.js b/ambari-web/app/mixins/main/service/configs/component_actions_by_configs.js index 9271675..c7bb047 100644 --- a/ambari-web/app/mixins/main/service/configs/component_actions_by_configs.js +++ b/ambari-web/app/mixins/main/service/configs/component_actions_by_configs.js @@ -31,7 +31,7 @@ App.ComponentActionsByConfigs = Em.Mixin.create({ * @public * @method doConfigActions */ - doConfigActions: function() { + doConfigActions: function () { var serviceConfigs = this.get('stepConfigs').findProperty('serviceName', this.get('content.serviceName')).get('configs'); var configActionComponents = serviceConfigs.filterProperty('configActionComponent'); this.doComponentDeleteActions(configActionComponents); @@ -44,7 +44,7 @@ App.ComponentActionsByConfigs = Em.Mixin.create({ * @public * @method isComponentActionsPresent */ - isComponentActionsPresent: function() { + isComponentActionsPresent: function () { var serviceConfigs = this.get('stepConfigs').findProperty('serviceName', this.get('content.serviceName')).get('configs'); var configActionComponents = serviceConfigs.filterProperty('configActionComponent'); return !!(this.getComponentsToDelete(configActionComponents).length + this.getComponentsToAdd(configActionComponents).length); @@ -57,11 +57,13 @@ App.ComponentActionsByConfigs = Em.Mixin.create({ * @private * @method getComponentsToDelete */ - getComponentsToDelete: function(configActionComponents) { - return configActionComponents.filterProperty('configActionComponent.action', 'delete').map(function(item){ + getComponentsToDelete: function (configActionComponents) { + var hostComponents = App.HostComponent.find(); + return configActionComponents.filterProperty('configActionComponent.action', 'delete').map(function (item) { return item.configActionComponent; - }).filter(function(_componentToDelete){ - return App.HostComponent.find().filterProperty('componentName',_componentToDelete.componentName).someProperty('hostName', _componentToDelete.hostName); + }).filter(function (_componentToDelete) { + return hostComponents.filterProperty('componentName', _componentToDelete.componentName) + .someProperty('hostName', _componentToDelete.hostName); }, this); }, @@ -72,15 +74,17 @@ App.ComponentActionsByConfigs = Em.Mixin.create({ * @private * @method getComponentsToDelete */ - getComponentsToAdd: function(configActionComponents) { - return configActionComponents.filterProperty('configActionComponent.action', 'add').map(function(item){ + getComponentsToAdd: function (configActionComponents) { + var ssc = App.StackServiceComponent.find(), + services = App.Service.find(); + return configActionComponents.filterProperty('configActionComponent.action', 'add').map(function (item) { return item.configActionComponent; - }).filter(function(_componentToAdd) { - var serviceNameForcomponent = App.StackServiceComponent.find().findProperty('componentName',_componentToAdd.componentName).get('serviceName'); + }).filter(function (_componentToAdd) { + var serviceNameForcomponent = ssc.findProperty('componentName', _componentToAdd.componentName).get('serviceName'); // List of host components to be added should not include ones that are already present in the cluster. // Need to do below check from App.Service model as it keeps getting polled and updated on service page. - return !App.Service.find().findProperty('serviceName', serviceNameForcomponent).get('hostComponents'). - filterProperty('componentName',_componentToAdd.componentName).someProperty('hostName', _componentToAdd.hostName); + return !services.findProperty('serviceName', serviceNameForcomponent).get('hostComponents'). + filterProperty('componentName', _componentToAdd.componentName).someProperty('hostName', _componentToAdd.hostName); }, this); }, @@ -90,16 +94,16 @@ App.ComponentActionsByConfigs = Em.Mixin.create({ * @private * @method {configActionComponents} */ - doComponentDeleteActions: function(configActionComponents) { + doComponentDeleteActions: function (configActionComponents) { var componentsToDelete = this.getComponentsToDelete(configActionComponents); if (componentsToDelete.length) { // There is always only one item to delete when doing config actions. - var componentToDelete = componentsToDelete[0]; + var componentToDelete = componentsToDelete[0]; var componentName = componentToDelete.componentName; var hostName = componentToDelete.hostName; - var displayName = App.StackServiceComponent.find().findProperty('componentName', componentToDelete.componentName).get('displayName'); + var displayName = App.StackServiceComponent.find().findProperty('componentName', componentToDelete.componentName).get('displayName'); var context = Em.I18n.t('requestInfo.stop').format(displayName); - var batches =[]; + var batches = []; this.setRefreshYarnQueueRequest(batches); batches.push(this.getInstallHostComponentsRequest(hostName, componentName, context)); @@ -124,37 +128,23 @@ App.ComponentActionsByConfigs = Em.Mixin.create({ * @private * @method {doComponentAddActions} */ - doComponentAddActions: function(configActionComponents) { - var self = this; + doComponentAddActions: function (configActionComponents) { var componentsToAdd = this.getComponentsToAdd(configActionComponents); - var dependentComponents = []; + if (componentsToAdd.length) { - componentsToAdd.forEach(function(_component) { - var dependencies = App.StackServiceComponent.find(_component.componentName).get('dependencies').filterProperty('scope', 'host').map(function(_dependency){ - return { - componentName: _dependency.componentName, - hostName: _component.hostName, - isClient: App.StackServiceComponent.find(_dependency.componentName).get('isClient') - } - }, this); - var dependenciesToInstall = dependencies.filter(function (_dependencyToAdd) { - var isInstalled = App.HostComponent.find().filterProperty('componentName', _dependencyToAdd.componentName).someProperty('hostName', _dependencyToAdd.hostName); - var isAddedToInstall = dependentComponents.filterProperty('componentName',_dependencyToAdd.componentName).someProperty('hostName', _dependencyToAdd.hostName); - return !(isInstalled || isAddedToInstall); - }, this); - dependentComponents = dependentComponents.concat(dependenciesToInstall); - }, this); - var allComponentsToAdd = componentsToAdd.concat(dependentComponents); + var allComponentsToAdd = componentsToAdd.concat(this.getDependentComponents(componentsToAdd)); var allComponentsToAddHosts = allComponentsToAdd.mapProperty('hostName').uniq(); - allComponentsToAddHosts.forEach(function(_hostName){ + + allComponentsToAddHosts.forEach(function (_hostName) { var hostComponents = allComponentsToAdd.filterProperty('hostName', _hostName).mapProperty('componentName').uniq(); - var masterHostComponents = allComponentsToAdd.filterProperty('hostName', _hostName).filterProperty('isClient', false).mapProperty('componentName').uniq(); - var displayNames = masterHostComponents.map(function(item) { + var masterHostComponents = allComponentsToAdd.filterProperty('hostName', _hostName).filterProperty('isClient', false).mapProperty('componentName').uniq(); + var displayNames = masterHostComponents.map(function (item) { return App.StackServiceComponent.find().findProperty('componentName', item).get('displayName'); }); - var displayStr = stringUtils.getFormattedStringFromArray(displayNames); + + var displayStr = stringUtils.getFormattedStringFromArray(displayNames); var context = Em.I18n.t('requestInfo.start').format(displayStr); - var batches =[]; + var batches = []; this.setCreateComponentRequest(batches, hostComponents); batches.push(this.getCreateHostComponentsRequest(_hostName, hostComponents)); batches.push(this.getInstallHostComponentsRequest(_hostName, hostComponents)); @@ -176,13 +166,39 @@ App.ComponentActionsByConfigs = Em.Mixin.create({ }, /** + * @method getDependentComponents + * @param {Array} componentsToAdd + * @returns {Array} + */ + getDependentComponents: function(componentsToAdd) { + var dependentComponents = []; + + componentsToAdd.forEach(function (_component) { + var dependencies = App.StackServiceComponent.find(_component.componentName).get('dependencies').filterProperty('scope', 'host').map(function (_dependency) { + return { + componentName: _dependency.componentName, + hostName: _component.hostName, + isClient: App.StackServiceComponent.find(_dependency.componentName).get('isClient') + } + }, this); + var dependenciesToInstall = dependencies.filter(function (_dependencyToAdd) { + var isInstalled = App.HostComponent.find().filterProperty('componentName', _dependencyToAdd.componentName).someProperty('hostName', _dependencyToAdd.hostName); + var isAddedToInstall = dependentComponents.filterProperty('componentName', _dependencyToAdd.componentName).someProperty('hostName', _dependencyToAdd.hostName); + return !(isInstalled || isAddedToInstall); + }, this); + dependentComponents = dependentComponents.concat(dependenciesToInstall); + }, this); + return dependentComponents; + }, + + /** * Sets order_id for each batch request in the `batches` array * @param batches {Array} * @private * @method {setOrderIdForBatches} */ - setOrderIdForBatches: function(batches) { - batches.forEach(function(_batch, index){ + setOrderIdForBatches: function (batches) { + batches.forEach(function (_batch, index) { _batch.order_id = index + 1; }, this); }, @@ -193,18 +209,18 @@ App.ComponentActionsByConfigs = Em.Mixin.create({ * @param components {String[]}|{String} * @return {Object} Deferred promise */ - getCreateHostComponentsRequest: function(hostName, components) { - var query = "Hosts/host_name.in(" + hostName + ")"; + getCreateHostComponentsRequest: function (hostName, components) { + var query = "Hosts/host_name.in(" + hostName + ")"; components = (Array.isArray(components)) ? components : [components]; - var hostComponent = components.map(function(_componentName){ + var hostComponent = components.map(function (_componentName) { return { - "HostRoles":{ - "component_name":_componentName + "HostRoles": { + "component_name": _componentName } } }, this); - return { + return { "type": 'POST', "uri": App.get('apiPrefix') + "/clusters/" + App.get('clusterName') + "/hosts", "RequestBodyInfo": { @@ -225,7 +241,7 @@ App.ComponentActionsByConfigs = Em.Mixin.create({ * @param context {String} Optional * @return {Object} */ - getInstallHostComponentsRequest: function(hostName, components, context) { + getInstallHostComponentsRequest: function (hostName, components, context) { context = context || Em.I18n.t('requestInfo.installComponents'); return this.getUpdateHostComponentsRequest(hostName, components, App.HostComponentStatus.stopped, context); }, @@ -237,7 +253,7 @@ App.ComponentActionsByConfigs = Em.Mixin.create({ * @param context {String} Optional * @return {Object} */ - getStartHostComponentsRequest: function(hostName, components, context) { + getStartHostComponentsRequest: function (hostName, components, context) { context = context || Em.I18n.t('requestInfo.startHostComponents'); return this.getUpdateHostComponentsRequest(hostName, components, App.HostComponentStatus.started, context); }, @@ -253,11 +269,11 @@ App.ComponentActionsByConfigs = Em.Mixin.create({ * @method {getUpdateHostComponentsRequest} * @return {Object} */ - getUpdateHostComponentsRequest: function(hostName, components, desiredState, context) { + getUpdateHostComponentsRequest: function (hostName, components, desiredState, context) { components = (Array.isArray(components)) ? components : [components]; var query = "HostRoles/component_name.in(" + components.join(',') + ")"; - return { + return { "type": 'PUT', "uri": App.get('apiPrefix') + "/clusters/" + App.get('clusterName') + "/hosts/" + hostName + "/host_components", "RequestBodyInfo": { @@ -287,7 +303,7 @@ App.ComponentActionsByConfigs = Em.Mixin.create({ * @method {getDeleteHostComponentRequest} * @return {Object} */ - getDeleteHostComponentRequest: function(hostName, component) { + getDeleteHostComponentRequest: function (hostName, component) { return { "type": 'DELETE', "uri": App.get('apiPrefix') + "/clusters/" + App.get('clusterName') + "/hosts/" + hostName + "/host_components/" + component @@ -301,10 +317,13 @@ App.ComponentActionsByConfigs = Em.Mixin.create({ * @private * @method {setCreateComponentRequest} */ - setCreateComponentRequest: function(batches, hostComponents) { - hostComponents.forEach(function(_componentName){ - var serviceName = App.StackServiceComponent.find().findProperty('componentName', _componentName).get('serviceName'); - var serviceComponents = App.Service.find().findProperty('serviceName', serviceName).get('serviceComponents'); + setCreateComponentRequest: function (batches, hostComponents) { + var stackServices = App.StackServiceComponent.find(), + services = App.Service.find(); + + hostComponents.forEach(function (_componentName) { + var serviceName = stackServices.findProperty('componentName', _componentName).get('serviceName'); + var serviceComponents = services.findProperty('serviceName', serviceName).get('serviceComponents'); if (!serviceComponents.contains(_componentName)) { batches.push({ "type": 'POST', @@ -320,25 +339,27 @@ App.ComponentActionsByConfigs = Em.Mixin.create({ * @private * @method {setRefreshYarnQueueRequest} */ - setRefreshYarnQueueRequest: function(batches) { - var capacitySchedulerConfigs = this.get('allConfigs').filterProperty('filename', 'capacity-scheduler.xml').filter(function(item){ + setRefreshYarnQueueRequest: function (batches) { + var capacitySchedulerConfigs = this.get('allConfigs') + .filterProperty('filename', 'capacity-scheduler.xml') + .filter(function (item) { return item.get('value') !== item.get('initialValue'); }); if (capacitySchedulerConfigs.length) { var serviceName = 'YARN'; var componentName = 'RESOURCEMANAGER'; - var commandName = 'REFRESHQUEUES'; - var tag = 'capacity-scheduler'; - var hostNames = App.Service.find(serviceName).get('hostComponents').filterProperty('componentName', componentName).mapProperty('hostName'); + var hostNames = App.Service.find(serviceName).get('hostComponents') + .filterProperty('componentName', componentName) + .mapProperty('hostName'); batches.push({ "type": 'POST', "uri": App.get('apiPrefix') + "/clusters/" + App.get('clusterName') + "/requests", "RequestBodyInfo": { "RequestInfo": { "context": Em.I18n.t('services.service.actions.run.yarnRefreshQueues.context'), - "command": commandName, - "parameters/forceRefreshConfigTags": tag + "command": "REFRESHQUEUES", + "parameters/forceRefreshConfigTags": "capacity-scheduler" }, "Requests/resource_filters": [ { http://git-wip-us.apache.org/repos/asf/ambari/blob/07b42367/ambari-web/app/mixins/main/service/configs/config_overridable.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/mixins/main/service/configs/config_overridable.js b/ambari-web/app/mixins/main/service/configs/config_overridable.js index 920e5c4..a8bd273 100644 --- a/ambari-web/app/mixins/main/service/configs/config_overridable.js +++ b/ambari-web/app/mixins/main/service/configs/config_overridable.js @@ -63,7 +63,10 @@ App.ConfigOverridable = Em.Mixin.create({ } else { var valueForOverride = (serviceConfigProperty.get('widget') || serviceConfigProperty.get('displayType') == 'checkbox') ? serviceConfigProperty.get('value') : ''; - App.config.createOverride(serviceConfigProperty, { "value": valueForOverride, "isEditable": true }, selectedConfigGroup); + App.config.createOverride(serviceConfigProperty, { + "value": valueForOverride, + "isEditable": true + }, selectedConfigGroup); } Em.$('body>.tooltip').remove(); }, @@ -253,35 +256,45 @@ App.ConfigOverridable = Em.Mixin.create({ }) } }; - var sendData = { + return App.ajax.send({ name: 'config_groups.create', + sender: this, data: { data: [newGroupData], modelData: newConfigGroupData }, - success: 'successFunction', - error: 'errorFunction', - successFunction: function (response, opt, params) { - var modelData = params.modelData; - modelData.id = response.resources[0].ConfigGroup.id; - App.store.load(App.ServiceConfigGroup, modelData); - App.store.commit(); - App.ServiceConfigGroup.deleteTemporaryRecords(); - if (callback) { - callback(); - } - }, - errorFunction: function (xhr, text, errorThrown) { - if (callback) { - callback(xhr, text, errorThrown); - } + success: 'postNewConfigurationGroupSuccess', + error: 'postNewConfigurationGroupError' + }).always(function (xhr, text, errorThrown) { + if (callback) { + callback(xhr, text, errorThrown); } - }; - sendData.sender = sendData; - return App.ajax.send(sendData); + }); }, /** + * + * @param {string} response + * @param {object} opt + * @param {object} params + */ + postNewConfigurationGroupSuccess: function (response, opt, params) { + var modelData = params.modelData; + modelData.id = response.resources[0].ConfigGroup.id; + App.store.load(App.ServiceConfigGroup, modelData); + App.store.commit(); + App.ServiceConfigGroup.deleteTemporaryRecords(); + }, + + /** + * + * @param {object} xhr + * @param {string} text + * @param {Error} errorThrown + */ + postNewConfigurationGroupError: Em.K, + + /** * PUTs the new configuration-group on the server. * Changes possible here are the name, description and * host memberships of the configuration-group. @@ -293,31 +306,11 @@ App.ConfigOverridable = Em.Mixin.create({ * @method updateConfigurationGroup */ updateConfigurationGroup: function (configGroup, successCallback, errorCallback) { - var desiredConfigs = configGroup.get('desiredConfigs') || []; - var putConfigGroup = { - ConfigGroup: { - group_name: configGroup.get('name'), - description: configGroup.get('description'), - tag: configGroup.get('service.id'), - hosts: configGroup.get('hosts').map(function (h) { - return { - host_name: h - }; - }), - desired_configs: desiredConfigs.map(function (cst) { - return { - type: Em.get(cst, 'site') || Em.get(cst, 'type'), - tag: Em.get(cst, 'tag') - }; - }) - } - }; - var sendData = { name: 'config_groups.update', data: { id: configGroup.get('id'), - data: putConfigGroup + data: this.getConfigGroupData(configGroup) }, success: 'successFunction', error: 'errorFunction', @@ -337,6 +330,34 @@ App.ConfigOverridable = Em.Mixin.create({ }, /** + * + * @param {Em.Object} configGroup + * @returns {{ConfigGroup: {group_name: *, description: *, tag: *, hosts: *, desired_configs: (Array|*)}}} + */ + getConfigGroupData: function (configGroup) { + var desiredConfigs = configGroup.get('desiredConfigs') || []; + + return { + ConfigGroup: { + group_name: configGroup.get('name'), + description: configGroup.get('description'), + tag: configGroup.get('service.id'), + hosts: configGroup.get('hosts').map(function (h) { + return { + host_name: h + }; + }), + desired_configs: desiredConfigs.map(function (cst) { + return { + type: Em.get(cst, 'site') || Em.get(cst, 'type'), + tag: Em.get(cst, 'tag') + }; + }) + } + }; + }, + + /** * launch dialog where can be assigned another group to host * @param {App.ConfigGroup} selectedGroup * @param {App.ConfigGroup[]} configGroups @@ -391,6 +412,7 @@ App.ConfigOverridable = Em.Mixin.create({ * @method deleteConfigurationGroup */ deleteConfigurationGroup: function (configGroup, successCallback, errorCallback) { + var self = this; var sendData = { name: 'common.delete.config_group', sender: this, @@ -400,13 +422,7 @@ App.ConfigOverridable = Em.Mixin.create({ success: 'successFunction', error: 'errorFunction', successFunction: function (data, xhr, params) { - var groupFromModel = App.ServiceConfigGroup.find().findProperty('id', params.id); - if (groupFromModel) { - if (groupFromModel.get('stateManager.currentState.name') !== 'saved') { - groupFromModel.get('stateManager').transitionTo('loaded'); - } - App.configGroupsMapper.deleteRecord(groupFromModel); - } + self.deleteConfigurationGroupSuccess(data, xhr, params); if (successCallback) { successCallback(); } @@ -421,6 +437,23 @@ App.ConfigOverridable = Em.Mixin.create({ return App.ajax.send(sendData); }, + + /** + * + * @param {object} data + * @param {object} xhr + * @param {object} params + */ + deleteConfigurationGroupSuccess: function (data, xhr, params) { + var groupFromModel = App.ServiceConfigGroup.find().findProperty('id', params.id); + if (groupFromModel) { + if (groupFromModel.get('stateManager.currentState.name') !== 'saved') { + groupFromModel.get('stateManager').transitionTo('loaded'); + } + App.configGroupsMapper.deleteRecord(groupFromModel); + } + }, + /** * Launches a dialog where an existing config-group can be selected, or a new * one can be created. This is different than the config-group management @@ -444,11 +477,11 @@ App.ConfigOverridable = Em.Mixin.create({ bodyClass: Em.View.extend({ templateName: require('templates/common/configs/saveConfigGroup') }), - onPrimary:function() { - if (self.get('controller.name') == 'mainServiceInfoConfigsController') { - self.get('controller').loadConfigGroups([self.get('controller.content.serviceName')]).done(function() { - var group = App.ServiceConfigGroup.find().find(function(g) { - return g.get('serviceName') == self.get('controller.content.serviceName') && g.get('name') == groupName; + onPrimary: function () { + if (self.get('controller.name') === 'mainServiceInfoConfigsController') { + self.get('controller').loadConfigGroups([self.get('controller.content.serviceName')]).done(function () { + var group = App.ServiceConfigGroup.find().find(function (g) { + return g.get('serviceName') === self.get('controller.content.serviceName') && g.get('name') === groupName; }); self.get('controller').doSelectConfigGroup({context: group}); }); @@ -469,7 +502,7 @@ App.ConfigOverridable = Em.Mixin.create({ persistConfigGroups: function () { var installerController = App.router.get('installerController'); var step7Controller = App.router.get('wizardStep7Controller'); - installerController.saveServiceConfigGroups(step7Controller, step7Controller.get('content.controllerName') == 'addServiceController'); + installerController.saveServiceConfigGroups(step7Controller, step7Controller.get('content.controllerName') === 'addServiceController'); App.clusterStatus.setClusterStatus({ localdb: App.db.data }); http://git-wip-us.apache.org/repos/asf/ambari/blob/07b42367/ambari-web/app/mixins/main/service/configs/widget_popover_support.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/mixins/main/service/configs/widget_popover_support.js b/ambari-web/app/mixins/main/service/configs/widget_popover_support.js index ded8dd9..dc9f7d3 100644 --- a/ambari-web/app/mixins/main/service/configs/widget_popover_support.js +++ b/ambari-web/app/mixins/main/service/configs/widget_popover_support.js @@ -44,7 +44,7 @@ App.WidgetPopoverSupport = Em.Mixin.create({ * @type {string} */ popoverPlacement: function () { - return this.get('section.isLastColumn') && this.get('subSection.isLastColumn')? 'left' : 'right'; + return this.get('section.isLastColumn') && this.get('subSection.isLastColumn') ? 'left' : 'right'; }.property('section.isLastColumn', 'subSection.isLastColumn'), initPopover: function () { http://git-wip-us.apache.org/repos/asf/ambari/blob/07b42367/ambari-web/test/mixins/main/service/configs/component_actions_by_configs_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/mixins/main/service/configs/component_actions_by_configs_test.js b/ambari-web/test/mixins/main/service/configs/component_actions_by_configs_test.js new file mode 100644 index 0000000..a6877fe --- /dev/null +++ b/ambari-web/test/mixins/main/service/configs/component_actions_by_configs_test.js @@ -0,0 +1,519 @@ +/** + * 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. + */ + +require('mixins/main/service/configs/component_actions_by_configs'); +var testHelpers = require('test/helpers'); +var stringUtils = require('utils/string_utils'); + + +var mixin; + +describe('App.ComponentActionsByConfigs', function () { + + beforeEach(function() { + mixin = Em.Object.create(App.ComponentActionsByConfigs, { + stepConfigs: [], + content: Em.Object.create() + }); + }); + + describe("#doConfigActions()", function () { + + beforeEach(function() { + sinon.stub(mixin, 'doComponentDeleteActions'); + sinon.stub(mixin, 'doComponentAddActions'); + mixin.set('stepConfigs', [Em.Object.create({ + serviceName: 'S1', + configs: [{ + configActionComponent: {} + }] + })]); + mixin.set('content.serviceName', 'S1'); + mixin.doConfigActions(); + }); + + afterEach(function() { + mixin.doComponentDeleteActions.restore(); + mixin.doComponentAddActions.restore(); + }); + + it("doComponentDeleteActions should be called", function() { + expect(mixin.doComponentDeleteActions.calledWith([{ + configActionComponent: {} + }])).to.be.true; + }); + + it("doComponentAddActions should be called", function() { + expect(mixin.doComponentAddActions.calledWith([{ + configActionComponent: {} + }])).to.be.true; + }); + }); + + describe("#isComponentActionsPresent()", function () { + + beforeEach(function() { + this.mockDelete = sinon.stub(mixin, 'getComponentsToDelete').returns(1); + this.mockAdd = sinon.stub(mixin, 'getComponentsToAdd').returns(1); + mixin.set('stepConfigs', [Em.Object.create({ + serviceName: 'S1', + configs: [{ + configActionComponent: {} + }] + })]); + mixin.set('content.serviceName', 'S1'); + }); + + afterEach(function() { + this.mockAdd.restore(); + this.mockDelete.restore(); + }); + + it("no delete or add components", function() { + this.mockAdd.returns([]); + this.mockDelete.returns([]); + expect(mixin.isComponentActionsPresent()).to.be.false; + }); + + it("has delete and no add components", function() { + this.mockAdd.returns([]); + this.mockDelete.returns([{}]); + expect(mixin.isComponentActionsPresent()).to.be.true; + }); + + it("no delete and has add components", function() { + this.mockAdd.returns([{}]); + this.mockDelete.returns([]); + expect(mixin.isComponentActionsPresent()).to.be.true; + }); + }); + + describe("#getComponentsToDelete()", function () { + + beforeEach(function() { + sinon.stub(App.HostComponent, 'find').returns([ + Em.Object.create({ + componentName: 'C1', + hostName: 'host1' + }) + ]); + }); + + afterEach(function() { + App.HostComponent.find.restore(); + }); + + it("should return array of components to delete", function() { + var configActionComponents = [ + { + configActionComponent: { + action: 'delete', + componentName: 'C1', + hostName: 'host1' + } + } + ]; + expect(mixin.getComponentsToDelete(configActionComponents)).to.be.eql([{ + action: 'delete', + componentName: 'C1', + hostName: 'host1' + }]); + }); + }); + + describe("#getComponentsToAdd()", function () { + + beforeEach(function() { + sinon.stub(App.StackServiceComponent, 'find').returns([ + Em.Object.create({ + componentName: 'C1', + serviceName: 'S1' + }) + ]); + sinon.stub(App.Service, 'find').returns([ + Em.Object.create({ + serviceName: 'S1', + hostComponents: [ + Em.Object.create({ + componentName: 'C1', + hostName: 'host2' + }) + ] + }) + ]); + }); + + afterEach(function() { + App.StackServiceComponent.find.restore(); + App.Service.find.restore(); + }); + + it("should return array of components to add", function() { + var configActionComponents = [ + { + configActionComponent: { + action: 'add', + componentName: 'C1', + hostName: 'host1' + } + } + ]; + expect(mixin.getComponentsToAdd(configActionComponents)).to.be.eql([{ + action: 'add', + componentName: 'C1', + hostName: 'host1' + }]); + }); + }); + + describe("#doComponentDeleteActions()", function () { + + beforeEach(function() { + this.mockDelete = sinon.stub(mixin, 'getComponentsToDelete'); + sinon.stub(App.StackServiceComponent, 'find').returns([ + Em.Object.create({ + componentName: 'C1', + displayName: 'c1' + }) + ]); + sinon.stub(mixin, 'setRefreshYarnQueueRequest'); + sinon.stub(mixin, 'getInstallHostComponentsRequest').returns({}); + sinon.stub(mixin, 'getDeleteHostComponentRequest').returns({}); + sinon.stub(mixin, 'setOrderIdForBatches'); + }); + + afterEach(function() { + this.mockDelete.restore(); + App.StackServiceComponent.find.restore(); + mixin.setRefreshYarnQueueRequest.restore(); + mixin.getDeleteHostComponentRequest.restore(); + mixin.setOrderIdForBatches.restore(); + mixin.getInstallHostComponentsRequest.restore(); + }); + + it("App.ajax.send should not be called", function() { + this.mockDelete.returns([]); + mixin.doComponentDeleteActions(); + expect(testHelpers.findAjaxRequest('name', 'common.batch.request_schedules')).to.not.exists; + }); + + it("App.ajax.send should be called", function() { + this.mockDelete.returns([{ + componentName: 'C1', + hostName: 'host1' + }]); + mixin.doComponentDeleteActions(); + var args = testHelpers.findAjaxRequest('name', 'common.batch.request_schedules'); + expect(args[0]).to.be.eql({ + name: 'common.batch.request_schedules', + sender: mixin, + data: { + intervalTimeSeconds: 1, + tolerateSize: 0, + batches: [{}, {}] + } + }); + }); + }); + + describe("#doComponentAddActions()", function () { + + beforeEach(function() { + this.mockAdd = sinon.stub(mixin, 'getComponentsToAdd'); + sinon.stub(mixin, 'getDependentComponents').returns([]); + sinon.stub(App.StackServiceComponent, 'find').returns([ + Em.Object.create({ + componentName: 'C1', + displayName: 'c1' + }) + ]); + sinon.stub(mixin, 'setCreateComponentRequest'); + sinon.stub(mixin, 'getCreateHostComponentsRequest').returns({}); + sinon.stub(mixin, 'getInstallHostComponentsRequest').returns({}); + sinon.stub(mixin, 'setRefreshYarnQueueRequest'); + sinon.stub(mixin, 'getStartHostComponentsRequest').returns({}); + sinon.stub(mixin, 'setOrderIdForBatches'); + sinon.stub(stringUtils, 'getFormattedStringFromArray').returns('c1'); + }); + + afterEach(function() { + this.mockAdd.restore(); + mixin.getDependentComponents.restore(); + App.StackServiceComponent.find.restore(); + mixin.setCreateComponentRequest.restore(); + mixin.getCreateHostComponentsRequest.restore(); + mixin.getInstallHostComponentsRequest.restore(); + mixin.setRefreshYarnQueueRequest.restore(); + mixin.getStartHostComponentsRequest.restore(); + mixin.setOrderIdForBatches.restore(); + stringUtils.getFormattedStringFromArray.restore(); + }); + + it("App.ajax.send should not be called", function() { + this.mockAdd.returns([]); + mixin.doComponentAddActions(); + expect(testHelpers.findAjaxRequest('name', 'common.batch.request_schedules')).to.not.exists; + }); + + it("App.ajax.send should be called", function() { + this.mockAdd.returns([{ + componentName: 'C1', + hostName: 'host1', + isClient: false + }]); + mixin.doComponentAddActions(); + var args = testHelpers.findAjaxRequest('name', 'common.batch.request_schedules'); + expect(args[0]).to.be.eql({ + name: 'common.batch.request_schedules', + sender: mixin, + data: { + intervalTimeSeconds: 1, + tolerateSize: 0, + batches: [{}, {}, {}] + } + }); + }); + }); + + describe("#getDependentComponents()", function () { + + beforeEach(function() { + sinon.stub(App.StackServiceComponent, 'find').returns(Em.Object.create({ + dependencies: [{ + scope: 'host', + componentName: 'C2' + }], + isClient: false + })); + sinon.stub(App.HostComponent, 'find').returns([]); + }); + + afterEach(function() { + App.StackServiceComponent.find.restore(); + App.HostComponent.find.restore(); + }); + + it("should return dependent components", function() { + var componentsToAdd = [{ + componentName: 'C1', + hostName: 'host1' + }]; + expect(mixin.getDependentComponents(componentsToAdd)).to.be.eql([ + { + componentName: 'C2', + hostName: 'host1', + isClient: false + } + ]); + }); + }); + + describe("#setOrderIdForBatches()", function () { + + it("should set order_id", function() { + var batches = [{}, {}, {}]; + mixin.setOrderIdForBatches(batches); + expect(batches).to.be.eql([ + {order_id: 1}, + {order_id: 2}, + {order_id: 3} + ]); + }); + }); + + describe("#getCreateHostComponentsRequest()", function () { + + it("App.ajax.send should be called", function() { + expect(mixin.getCreateHostComponentsRequest('host1', ['C1'])).to.be.eql({ + "type": 'POST', + "uri": "/api/v1/clusters/mycluster/hosts", + "RequestBodyInfo": { + "RequestInfo": { + "query": "Hosts/host_name.in(host1)" + }, + "Body": { + "host_components": [{ + "HostRoles": { + "component_name": 'C1' + } + }] + } + } + }); + }); + }); + + describe("#getInstallHostComponentsRequest()", function () { + + beforeEach(function() { + sinon.stub(mixin, 'getUpdateHostComponentsRequest').returns({}); + }); + + afterEach(function() { + mixin.getUpdateHostComponentsRequest.restore(); + }); + + it("should return request object", function() { + expect(mixin.getInstallHostComponentsRequest('host1', [{componentName: 'C1'}])).to.be.eql({}); + expect(mixin.getUpdateHostComponentsRequest.calledWith( + 'host1', + [{componentName: 'C1'}], + App.HostComponentStatus.stopped, + Em.I18n.t('requestInfo.installComponents'))).to.be.true; + }); + }); + + describe("#getStartHostComponentsRequest()", function () { + + beforeEach(function() { + sinon.stub(mixin, 'getUpdateHostComponentsRequest').returns({}); + }); + + afterEach(function() { + mixin.getUpdateHostComponentsRequest.restore(); + }); + + it("should return request object", function() { + expect(mixin.getStartHostComponentsRequest('host1', [{componentName: 'C1'}])).to.be.eql({}); + expect(mixin.getUpdateHostComponentsRequest.calledWith( + 'host1', + [{componentName: 'C1'}], + App.HostComponentStatus.started, + Em.I18n.t('requestInfo.startHostComponents'))).to.be.true; + }); + }); + + describe("#getUpdateHostComponentsRequest()", function () { + + it("should return request object", function() { + expect(mixin.getUpdateHostComponentsRequest('host1', ['C1', 'C2'], 'INSTALLED', 'context')).to.be.eql({ + "type": 'PUT', + "uri": "/api/v1/clusters/mycluster/hosts/host1/host_components", + "RequestBodyInfo": { + "RequestInfo": { + "context": 'context', + "operation_level": { + "level": "HOST", + "cluster_name": 'mycluster', + "host_names": 'host1' + }, + "query": "HostRoles/component_name.in(C1,C2)" + }, + "Body": { + "HostRoles": { + "state": 'INSTALLED' + } + } + } + }); + }); + }); + + describe("#getDeleteHostComponentRequest()", function () { + + it("should return request object", function() { + expect(mixin.getDeleteHostComponentRequest('host1', 'C1')).to.be.eql({ + "type": 'DELETE', + "uri": "/api/v1/clusters/mycluster/hosts/host1/host_components/C1" + }); + }); + }); + + describe("#setCreateComponentRequest()", function () { + + beforeEach(function() { + sinon.stub(App.StackServiceComponent, 'find').returns([Em.Object.create({ + componentName: 'C1', + serviceName: 'S1' + })]); + sinon.stub(App.Service, 'find').returns([Em.Object.create({ + serviceName: 'S1', + serviceComponents: [] + })]); + }); + + afterEach(function() { + App.StackServiceComponent.find.restore(); + App.Service.find.restore(); + }); + + it("should add batch", function() { + var batches = []; + mixin.setCreateComponentRequest(batches, ["C1"]); + expect(batches).to.be.eql([ + { + "type": 'POST', + "uri": "/api/v1/clusters/mycluster/services/S1/components/C1" + } + ]); + + }); + }); + + describe("#setRefreshYarnQueueRequest()", function () { + + beforeEach(function() { + sinon.stub(App.Service, 'find').returns(Em.Object.create({ + hostComponents: [Em.Object.create({ + componentName: 'RESOURCEMANAGER', + hostName: 'host1' + })] + })); + }); + + afterEach(function() { + App.Service.find.restore(); + }); + + it("should not add a batch", function() { + var batches = []; + mixin.set('allConfigs', []); + mixin.setRefreshYarnQueueRequest(batches); + expect(batches).to.be.empty; + }); + + it("should add a batch", function() { + var batches = []; + mixin.set('allConfigs', [Em.Object.create({ + filename: 'capacity-scheduler.xml', + value: 'val1', + initialValue: 'val2' + })]); + mixin.setRefreshYarnQueueRequest(batches); + expect(batches).to.be.eql([{ + "type": 'POST', + "uri": "/api/v1/clusters/mycluster/requests", + "RequestBodyInfo": { + "RequestInfo": { + "context": Em.I18n.t('services.service.actions.run.yarnRefreshQueues.context'), + "command": "REFRESHQUEUES", + "parameters/forceRefreshConfigTags": "capacity-scheduler" + }, + "Requests/resource_filters": [ + { + service_name: "YARN", + component_name: "RESOURCEMANAGER", + hosts: "host1" + } + ] + } + }]); + }); + }); + +}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/07b42367/ambari-web/test/mixins/main/service/configs/config_overridable_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/mixins/main/service/configs/config_overridable_test.js b/ambari-web/test/mixins/main/service/configs/config_overridable_test.js index 3c88819..b1eb099 100644 --- a/ambari-web/test/mixins/main/service/configs/config_overridable_test.js +++ b/ambari-web/test/mixins/main/service/configs/config_overridable_test.js @@ -19,6 +19,7 @@ var App = require('app'); require('mixins/main/service/configs/config_overridable'); +var testHelpers = require('test/helpers'); var configOverridable; @@ -28,13 +29,19 @@ var configGroups = [ Em.Object.create({name: 'configGroup3'}) ]; -describe('App.Decommissionable', function () { +describe('App.ConfigOverridable', function () { beforeEach(function () { - configOverridable = Em.Object.create(App.ConfigOverridable); + configOverridable = Em.Object.create(App.ConfigOverridable, { + controller: Em.Object.create({ + loadConfigGroups: Em.K, + doSelectConfigGroup: Em.K + }), + isView: true + }); }); - describe('#validate of Config Group Selection Creation Dialog', function () { + describe('#launchConfigGroupSelectionCreationDialog()', function () { var testCases = [ { @@ -92,4 +99,348 @@ describe('App.Decommissionable', function () { }); }); + describe("#createOverrideProperty()", function () { + + beforeEach(function() { + sinon.stub(configOverridable, 'launchConfigGroupSelectionCreationDialog'); + sinon.stub(App.ModalPopup, 'show'); + sinon.stub(App.config, 'createOverride'); + }); + + afterEach(function() { + configOverridable.launchConfigGroupSelectionCreationDialog.restore(); + App.ModalPopup.show.restore(); + App.config.createOverride.restore(); + }); + + it("App.ModalPopup.show should be called", function() { + var event = { + contexts: [ + Em.Object.create({ + isUserProperty: true, + isNotSaved: true + }) + ] + }; + configOverridable.set('controller.name', ''); + configOverridable.createOverrideProperty(event); + expect(App.ModalPopup.show.calledOnce).to.be.true; + }); + + it("launchConfigGroupSelectionCreationDialogshould be called", function() { + var event = { + contexts: [ + Em.Object.create() + ] + }; + configOverridable.set('controller.selectedConfigGroup', Em.Object.create({ + isDefault: true + })); + configOverridable.createOverrideProperty(event); + expect(configOverridable.launchConfigGroupSelectionCreationDialog.calledOnce).to.be.true; + }); + + it("App.config.createOverride be called", function() { + var event = { + contexts: [ + Em.Object.create({ + widget: true, + value: 'val' + }) + ] + }; + configOverridable.set('controller.selectedConfigGroup', Em.Object.create({ + isDefault: false + })); + configOverridable.createOverrideProperty(event); + expect(App.config.createOverride.calledOnce).to.be.true; + }); + }); + + describe("#postNewConfigurationGroup()", function () { + + it("App.ajax.send should be called", function() { + var newConfigGroupData = { + properties: [], + name: 'cg1', + service_id: 'S1', + description: '', + desired_configs: [], + hosts: ['host1'] + }; + configOverridable.postNewConfigurationGroup(newConfigGroupData); + + var args = testHelpers.findAjaxRequest('name', 'config_groups.create'); + expect(args[0]).to.be.eql({ + name: 'config_groups.create', + sender: configOverridable, + data: { + data: [{ + "ConfigGroup": { + "group_name": 'cg1', + "tag": 'S1', + "description": '', + "desired_configs": [], + "hosts": [{host_name: 'host1'}] + } + }], + modelData: newConfigGroupData + }, + success: 'postNewConfigurationGroupSuccess', + error: 'postNewConfigurationGroupError' + }); + }); + }); + + describe("#postNewConfigurationGroupSuccess()", function () { + + beforeEach(function() { + sinon.stub(App.store, 'load'); + sinon.stub(App.store, 'commit'); + sinon.stub(App.ServiceConfigGroup, 'deleteTemporaryRecords'); + configOverridable.postNewConfigurationGroupSuccess({ + resources: [ + { + ConfigGroup: { + id: 'cg1' + } + } + ] + }, {}, {modelData: {}}); + }); + + afterEach(function() { + App.ServiceConfigGroup.deleteTemporaryRecords.restore(); + App.store.commit.restore(); + App.store.load.restore(); + }); + + it("App.store.load should be called", function() { + expect(App.store.load.calledWith(App.ServiceConfigGroup, {id: 'cg1'})).to.be.true; + }); + + it("App.store.commit should be called", function() { + expect(App.store.commit.calledOnce).to.be.true; + }); + + it("App.ServiceConfigGroup.deleteTemporaryRecords should be called", function() { + expect(App.ServiceConfigGroup.deleteTemporaryRecords.calledOnce).to.be.true; + }); + }); + + describe("#updateConfigurationGroup()", function () { + + beforeEach(function() { + sinon.stub(configOverridable, 'getConfigGroupData'); + }); + + afterEach(function() { + configOverridable.getConfigGroupData.restore(); + }); + + it("App.ajax.send should be called", function() { + configOverridable.updateConfigurationGroup(Em.Object.create()); + expect(testHelpers.findAjaxRequest('name', 'config_groups.update')).to.be.exist; + }); + }); + + describe("#getConfigGroupData()", function () { + + it("should return config group data", function() { + var configGroup = Em.Object.create({ + name: 'cg1', + description: 'dsc', + service: { + id: 'S1' + }, + hosts: ['host1'], + desiredConfigs: [{ + site: 'type1', + tag: 'tag1' + }] + }); + expect(configOverridable.getConfigGroupData(configGroup)).to.be.eql({ + ConfigGroup: { + group_name: 'cg1', + description: 'dsc', + tag: 'S1', + hosts: [{ + host_name: 'host1' + }], + desired_configs: [{ + type: 'type1', + tag: 'tag1' + }] + } + }); + }); + }); + + describe("#launchSwitchConfigGroupOfHostDialog()", function () { + var mock = { + callback: Em.K + }; + + beforeEach(function() { + sinon.spy(App.ModalPopup, 'show'); + sinon.stub(configOverridable, 'updateConfigurationGroup'); + sinon.spy(mock, 'callback'); + }); + + afterEach(function() { + configOverridable.updateConfigurationGroup.restore(); + App.ModalPopup.show.restore(); + mock.callback.restore(); + }); + + it("updateConfigurationGroup should be called", function() { + var popup = configOverridable.launchSwitchConfigGroupOfHostDialog(Em.Object.create({ + name: 'cg1', + isDefault: false, + hosts: ['host1'] + }), + [],'host1', Em.K); + popup.onPrimary(); + expect(configOverridable.updateConfigurationGroup.calledTwice).to.be.true; + }); + + it("callback should be called", function() { + var group = Em.Object.create({ + name: 'cg1', + isDefault: false, + hosts: ['host1'] + }); + var popup = configOverridable.launchSwitchConfigGroupOfHostDialog(group, [], 'host1', mock.callback); + popup.onPrimary(); + expect(mock.callback.calledOnce).to.be.true; + }); + }); + + describe("#deleteConfigurationGroup()", function () { + + it("App.ajax.send should be called", function() { + configOverridable.deleteConfigurationGroup(Em.Object.create()); + expect(testHelpers.findAjaxRequest('name', 'common.delete.config_group')).to.be.exist; + }); + }); + + describe("#deleteConfigurationGroupSuccess()", function () { + var group = Em.Object.create({ + id: 'cg1', + stateManager: Em.Object.create({ + transitionTo: Em.K + }) + }); + + beforeEach(function() { + sinon.stub(App.ServiceConfigGroup, 'find').returns([ + group + ]); + sinon.stub(App.configGroupsMapper, 'deleteRecord'); + }); + + afterEach(function() { + App.ServiceConfigGroup.find.restore(); + App.configGroupsMapper.deleteRecord.restore(); + }); + + it("App.configGroupsMapper.deleteRecord should be called", function() { + configOverridable.deleteConfigurationGroupSuccess({}, {}, {id: 'cg1'}); + expect(App.configGroupsMapper.deleteRecord.calledWith(group)).to.be.true; + }); + + it("App.configGroupsMapper.deleteRecord should not be called", function() { + configOverridable.deleteConfigurationGroupSuccess({}, {}, {id: 'cg2'}); + expect(App.configGroupsMapper.deleteRecord.called).to.be.false; + }); + }); + + describe("#saveGroupConfirmationPopup()", function () { + var group = Em.Object.create({ + serviceName: 'S1', + name: 'cg1' + }); + var mock = { + manageConfigurationGroups: Em.K + }; + + beforeEach(function() { + sinon.stub(configOverridable.get('controller'), 'loadConfigGroups').returns({ + done: function (callback) { + callback(); + } + }); + sinon.stub(configOverridable.get('controller'), 'doSelectConfigGroup'); + sinon.stub(App.ServiceConfigGroup, 'find').returns([group]); + sinon.spy(App.ModalPopup, 'show'); + sinon.stub(App.router, 'get').returns(mock); + sinon.spy(mock, 'manageConfigurationGroups'); + }); + + afterEach(function() { + configOverridable.get('controller').loadConfigGroups.restore(); + configOverridable.get('controller').doSelectConfigGroup.restore(); + App.ServiceConfigGroup.find.restore(); + App.ModalPopup.show.restore(); + App.router.get.restore(); + mock.manageConfigurationGroups.restore(); + }); + + it("onPrimary", function() { + configOverridable.set('controller.name', 'mainServiceInfoConfigsController'); + configOverridable.set('controller.content', Em.Object.create({ + serviceName: 'S1' + })); + var popup = configOverridable.saveGroupConfirmationPopup('cg1'); + popup.onPrimary(); + expect(configOverridable.get('controller').doSelectConfigGroup.calledWith({context: group})).to.be.true; + }); + + it("onSecondary", function() { + configOverridable.set('controller.content', Em.Object.create({ + serviceName: 'S1' + })); + var popup = configOverridable.saveGroupConfirmationPopup('cg1'); + popup.onSecondary(); + expect(mock.manageConfigurationGroups.calledWith(null, Em.Object.create({ + serviceName: 'S1' + }))).to.be.true; + }); + }); + + describe("#persistConfigGroups()", function () { + var mockInstaller = Em.Object.create({ + saveServiceConfigGroups: Em.K + }); + var mockStep7 = Em.Object.create({ + content: Em.Object.create({ + controllerName: 'addServiceController' + }) + }); + + beforeEach(function() { + sinon.stub(mockInstaller, 'saveServiceConfigGroups'); + this.mock = sinon.stub(App.router, 'get'); + sinon.stub(App.clusterStatus, 'setClusterStatus'); + this.mock.withArgs('installerController').returns(mockInstaller); + this.mock.withArgs('wizardStep7Controller').returns(mockStep7); + configOverridable.persistConfigGroups(); + }); + + afterEach(function() { + App.clusterStatus.setClusterStatus.restore(); + App.router.get.restore(); + this.mock.restore(); + mockInstaller.saveServiceConfigGroups.restore(); + }); + + it("saveServiceConfigGroups should be called", function() { + expect(mockInstaller.saveServiceConfigGroups.calledWith(mockStep7, true)).to.be.true; + }); + + it("App.clusterStatus.setClusterStatus should be called", function() { + expect(App.clusterStatus.setClusterStatus.calledOnce).to.be.true; + }); + }); + }); http://git-wip-us.apache.org/repos/asf/ambari/blob/07b42367/ambari-web/test/mixins/main/service/configs/widget_popover_support_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/mixins/main/service/configs/widget_popover_support_test.js b/ambari-web/test/mixins/main/service/configs/widget_popover_support_test.js index 449ff5d..d4057b8 100644 --- a/ambari-web/test/mixins/main/service/configs/widget_popover_support_test.js +++ b/ambari-web/test/mixins/main/service/configs/widget_popover_support_test.js @@ -16,4 +16,167 @@ * limitations under the License. */ -describe('App.WidgetPopoverSupport', function () {}); \ No newline at end of file +require('mixins/main/service/configs/widget_popover_support'); + +var mixin; + +describe('App.WidgetPopoverSupport', function () { + + beforeEach(function() { + mixin = Em.Object.create(App.WidgetPopoverSupport, { + stepConfigs: [], + content: Em.Object.create(), + on: Em.K, + $: Em.K + }); + }); + + describe("#popoverPlacement", function () { + + var testCases = [ + { + sectionLastColumn: false, + subSectionLastColumn: false, + expected: 'right' + }, + { + sectionLastColumn: true, + subSectionLastColumn: false, + expected: 'right' + }, + { + sectionLastColumn: false, + subSectionLastColumn: true, + expected: 'right' + }, + { + sectionLastColumn: true, + subSectionLastColumn: true, + expected: 'left' + } + ]; + + testCases.forEach(function(test) { + it("subSection.isLastColumn = " + test.subSectionLastColumn + + "section.isLastColumn = " + test.sectionLastColumn, function() { + mixin.setProperties({ + section: { + isLastColumn: test.sectionLastColumn + }, + subSection: { + isLastColumn: test.subSectionLastColumn + } + }); + mixin.propertyDidChange('popoverPlacement'); + expect(mixin.get('popoverPlacement')).to.be.equal(test.expected); + }); + }); + }); + + describe("#initPopover()", function () { + + beforeEach(function() { + sinon.stub(mixin, 'destroyPopover'); + sinon.stub(App, 'popover'); + sinon.stub(mixin, 'on'); + sinon.stub(mixin, '$') + }); + + afterEach(function() { + mixin.on.restore(); + App.popover.restore(); + mixin.destroyPopover.restore(); + mixin.$.restore(); + }); + + it("destroyPopover should not be called", function() { + mixin.set('isPopoverEnabled', false); + mixin.initPopover(); + expect(mixin.destroyPopover.called).to.be.false; + }); + + it("App.popover should not be called", function() { + mixin.set('isPopoverEnabled', false); + mixin.initPopover(); + expect(App.popover.called).to.be.false; + }); + + it("on should not be called", function() { + mixin.set('isPopoverEnabled', false); + mixin.initPopover(); + expect(mixin.on.called).to.be.false; + }); + + it("destroyPopover should be called", function() { + mixin.set('isPopoverEnabled', true); + mixin.initPopover(); + expect(mixin.destroyPopover.calledOnce).to.be.true; + }); + + it("App.popover should be called", function() { + mixin.set('isPopoverEnabled', true); + mixin.initPopover(); + expect(App.popover.calledOnce).to.be.true; + }); + + it("on should be called", function() { + mixin.set('isPopoverEnabled', true); + mixin.initPopover(); + expect(mixin.on.calledWith('willDestroyElement', mixin, mixin.destroyPopover)).to.be.true; + }); + }); + + describe("#destroyPopover()", function () { + + beforeEach(function() { + sinon.stub(mixin, 'movePopover'); + }); + + afterEach(function() { + mixin.movePopover.restore(); + }); + + it("movePopover should be called", function() { + mixin.destroyPopover(); + expect(mixin.movePopover.calledWith('destroy')).to.be.true; + }); + }); + + describe("#hidePopover()", function () { + + beforeEach(function() { + sinon.stub(mixin, 'movePopover'); + }); + + afterEach(function() { + mixin.movePopover.restore(); + }); + + it("movePopover should be called", function() { + mixin.hidePopover(); + expect(mixin.movePopover.calledWith('hide')).to.be.true; + }); + }); + + describe("#movePopover()", function () { + var mock = { + popover: Em.K + }; + + beforeEach(function() { + sinon.stub(mixin, '$').returns(mock); + sinon.stub(mock, 'popover'); + }); + + afterEach(function() { + mock.popover.restore(); + mixin.$.restore(); + }); + + it("popover should be called", function() { + mixin.movePopover('action'); + expect(mock.popover.calledWith('action')).to.be.true; + }); + }); + +}); \ No newline at end of file
