AMBARI-20770 Cover assign master controller 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/cebbff05 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/cebbff05 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/cebbff05 Branch: refs/heads/branch-feature-AMBARI-12556 Commit: cebbff057baf9b30359aea108533feb8d9cce9ed Parents: 1c37ffc Author: Andrii Tkach <atk...@apache.org> Authored: Fri Apr 14 16:37:36 2017 +0300 Committer: Andrii Tkach <atk...@apache.org> Committed: Thu Apr 20 16:36:53 2017 +0300 ---------------------------------------------------------------------- .../wizard/step7/assign_master_controller.js | 275 ++++--- .../step7/assign_master_controller_test.js | 780 ++++++++++++++++--- 2 files changed, 840 insertions(+), 215 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/cebbff05/ambari-web/app/controllers/wizard/step7/assign_master_controller.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers/wizard/step7/assign_master_controller.js b/ambari-web/app/controllers/wizard/step7/assign_master_controller.js index 8bdab28..099931a 100644 --- a/ambari-web/app/controllers/wizard/step7/assign_master_controller.js +++ b/ambari-web/app/controllers/wizard/step7/assign_master_controller.js @@ -65,7 +65,7 @@ App.AssignMasterOnStep7Controller = Em.Controller.extend(App.BlueprintMixin, App switch (action) { case 'ADD': - if (hostComponent.componentName == "HIVE_SERVER_INTERACTIVE") { + if (hostComponent.componentName === "HIVE_SERVER_INTERACTIVE") { this.getPendingBatchRequests(hostComponent); } else { this.showPopup(hostComponent); @@ -94,9 +94,9 @@ App.AssignMasterOnStep7Controller = Em.Controller.extend(App.BlueprintMixin, App pendingBatchRequestsAjaxError: function(data) { var error = Em.I18n.t('services.service.actions.run.yarnRefreshQueues.error'); - if(data && data.responseText){ + if (data && data.responseText) { try { - var json = $.parseJSON(data.responseText); + var json = JSON.parse(data.responseText); error += json.message; } catch (err) {} } @@ -105,21 +105,11 @@ App.AssignMasterOnStep7Controller = Em.Controller.extend(App.BlueprintMixin, App pendingBatchRequestsAjaxSuccess : function(data, opt, params) { var self = this; - var showAlert = false; - if (data.hasOwnProperty('items') && data.items.length > 0) { - data.items.forEach( function(_item) { - _item.RequestSchedule.batch.batch_requests.forEach( function(batchRequest) { - // Check if a DELETE request on HIVE_SERVER_INTERACTIVE is in progress - if (batchRequest.request_type == "DELETE" && batchRequest.request_uri.indexOf("HIVE_SERVER_INTERACTIVE") > -1) { - showAlert = true; - } - }); - }); - } - if (showAlert) { - App.showAlertPopup(Em.I18n.t('services.service.actions.hsi.alertPopup.header'), Em.I18n.t('services.service.actions.hsi.alertPopup.body'), function() { + if (this.shouldShowAlertOnBatchRequest(data)) { + App.showAlertPopup(Em.I18n.t('services.service.actions.hsi.alertPopup.header'), + Em.I18n.t('services.service.actions.hsi.alertPopup.body'), function() { var configWidgetContext = self.get('configWidgetContext'); - var config = self.get('configWidgetContext.config'); + var config = configWidgetContext.get('config'); configWidgetContext.toggleProperty('controller.forceUpdateBoundaries'); var value = config.get('initialValue'); config.set('value', value); @@ -131,6 +121,21 @@ App.AssignMasterOnStep7Controller = Em.Controller.extend(App.BlueprintMixin, App this.showPopup(params.hostComponent); } }, + + shouldShowAlertOnBatchRequest: function(data) { + var showAlert = false; + if (data.hasOwnProperty('items') && data.items.length > 0) { + data.items.forEach( function(_item) { + _item.RequestSchedule.batch.batch_requests.forEach( function(batchRequest) { + // Check if a DELETE request on HIVE_SERVER_INTERACTIVE is in progress + if (batchRequest.request_type === "DELETE" && batchRequest.request_uri.indexOf("HIVE_SERVER_INTERACTIVE") > -1) { + showAlert = true; + } + }); + }); + } + return showAlert; + }, showPopup: function(hostComponent) { var missingDependentServices = this.getAllMissingDependentServices(); @@ -461,7 +466,6 @@ App.AssignMasterOnStep7Controller = Em.Controller.extend(App.BlueprintMixin, App var configActionComponent = self.get('configActionComponent'); var componentHostName = self.getSelectedHostName(configActionComponent.componentName); var config = self.get('configWidgetContext.config'); - var oldValueKey = context.get('controller.wizardController.name') === 'installerController' ? 'initialValue' : 'savedValue'; // TODO remove after stack advisor is able to handle this case // workaround for hadoop.proxyuser.{{hiveUser}}.hosts after adding Hive Server Interactive from Install Wizard @@ -484,114 +488,159 @@ App.AssignMasterOnStep7Controller = Em.Controller.extend(App.BlueprintMixin, App configActionComponent.hostName = componentHostName; config.set('configActionComponent', configActionComponent); /* TODO uncomment after stack advisor is able to handle this case - context.get('controller').loadConfigRecommendations([{ + var oldValueKey = context.get('controller.wizardController.name') === 'installerController' ? 'initialValue' : 'savedValue'; + context.get('controller').loadConfigRecommendations([{ type: App.config.getConfigTagFromFileName(config.get('fileName')), name: config.get('name'), old_value: config.get(oldValueKey) }]); */ + self.resolveDependencies(dependencies, serviceConfigs, context); + }); + }, - // TODO remove after stack advisor is able to handle this case - // workaround for hadoop.proxyuser.{{hiveUser}}.hosts after adding Hive Server Interactive - if (dependencies) { - var foreignKeys = {}; - if (dependencies.foreignKeys) { - dependencies.foreignKeys.forEach(function (dependency) { - var matchingProperty = serviceConfigs.find(function (property) { - return property.get('filename') === App.config.getOriginalFileName(dependency.fileName) && property.get('name') === dependency.propertyName; + /** + * TODO remove after stack advisor is able to handle this case + * workaround for hadoop.proxyuser.{{hiveUser}}.hosts after adding Hive Server Interactive + * @param {object} dependencies + * @param {array} serviceConfigs + * @param {Em.Object} context + */ + resolveDependencies: function(dependencies, serviceConfigs, context) { + if (dependencies) { + var foreignKeys = this.getDependenciesForeignKeys(dependencies, serviceConfigs); + + if (dependencies.properties && dependencies.initializer) { + var initializer = App.get(dependencies.initializer.name); + var setup = Em.getProperties(foreignKeys, dependencies.initializer.setupKeys); + initializer.setup(setup); + var blueprintObject = {}; + dependencies.properties.forEach(function (property) { + var propertyObject = Em.getProperties(property, ['name', 'fileName']); + if (property.nameTemplate) { + var name = property.nameTemplate; + Em.keys(foreignKeys).forEach(function (key) { + name = name.replace('{{' + key + '}}', foreignKeys[key]); }); - if (matchingProperty) { - foreignKeys[dependency.key] = matchingProperty.get('value'); - } + propertyObject.name = name; + } + if (!blueprintObject[property.fileName]) { + blueprintObject[property.fileName] = { + properties: {} + }; + } + var result = initializer.initialValue(propertyObject, { + masterComponentHosts: this.getMasterComponents(dependencies, context) }); - } - if (dependencies.properties && dependencies.initializer) { - var initializer = App.get(dependencies.initializer.name); - var setup = Em.getProperties(foreignKeys, dependencies.initializer.setupKeys); - initializer.setup(setup); - var blueprintObject = {}; - dependencies.properties.forEach(function (property) { - var propertyObject = Em.getProperties(property, ['name', 'fileName']); - if (property.nameTemplate) { - var name = property.nameTemplate; - Em.keys(foreignKeys).forEach(function (key) { - name = name.replace('{{' + key + '}}', foreignKeys[key]); - }); - propertyObject.name = name; - } - if (!blueprintObject[property.fileName]) { - blueprintObject[property.fileName] = { - properties: {} - }; - } - var masterComponents = []; - if (self.get('content.controllerName')) { - var savedMasterComponents = context.get('controller.content.masterComponentHosts').filter(function (componentObject) { - return dependencies.initializer.componentNames.contains(componentObject.component); - }); - masterComponents = savedMasterComponents.map(function (componentObject) { - var masterComponent = Em.getProperties(componentObject, ['component', 'hostName']); - masterComponent.isInstalled = true; - return masterComponent; - }); - } else { - var hostsMap = blueprintUtils.getComponentForHosts(); - Em.keys(hostsMap).forEach(function (hostName) { - hostsMap[hostName].forEach(function (componentName) { - if (dependencies.initializer.componentNames.contains(componentName)) { - masterComponents.push({ - component: componentName, - hostName: hostName, - isInstalled: true - }); - } - }); + + var propertiesMap = blueprintObject[propertyObject.fileName].properties; + propertiesMap[propertyObject.name] = result.value; + + if (property.isHostsList) { + var service = App.config.get('serviceByConfigTypeMap')[propertyObject.fileName]; + if (service) { + var serviceName = service.get('serviceName'); + var configs = serviceName === context.get('controller.selectedService.serviceName') ? serviceConfigs : + context.get('controller.stepConfigs').findProperty('serviceName', serviceName).get('configs'); + var originalFileName = App.config.getOriginalFileName(propertyObject.fileName); + var currentProperty = configs.find(function (configProperty) { + return configProperty.get('filename') === originalFileName && configProperty.get('name') === propertyObject.name; }); - } - var result = initializer.initialValue(propertyObject, { - masterComponentHosts: masterComponents - }); - var propertiesMap = blueprintObject[propertyObject.fileName].properties; - propertiesMap[propertyObject.name] = result.value; - if (property.isHostsList) { - var service = App.config.get('serviceByConfigTypeMap')[propertyObject.fileName]; - if (service) { - var serviceName = service.get('serviceName'); - var configs = serviceName === context.get('controller.selectedService.serviceName') ? serviceConfigs : - context.get('controller.stepConfigs').findProperty('serviceName', serviceName).get('configs'); - var originalFileName = App.config.getOriginalFileName(propertyObject.fileName); - var currentProperty = configs.find(function (configProperty) { - return configProperty.get('filename') === originalFileName && configProperty.get('name') === propertyObject.name; - }); - if (currentProperty) { - propertiesMap[propertyObject.name] = currentProperty.get('value'); - App.config.updateHostsListValue(propertiesMap, propertyObject.fileName, propertyObject.name, propertyObject.value, property.isHostsArray); - } + if (currentProperty) { + propertiesMap[propertyObject.name] = currentProperty.get('value'); + App.config.updateHostsListValue(propertiesMap, propertyObject.fileName, propertyObject.name, propertyObject.value, property.isHostsArray); } } - context.get('controller').loadRecommendationsSuccess({ - resources: [ - { - recommendations: { - blueprint: { - configurations: blueprintObject - } - } - } - ] - }, null, { - dataToSend: { - changed_configurations: [{ - type: App.config.getConfigTagFromFileName(config.get('fileName')), - name: config.get('name'), - old_value: config.get(oldValueKey) - }] - } - }); - initializer.cleanup(); - }); + } + this.saveRecommendations(context, blueprintObject); + initializer.cleanup(); + }, this); + } + } + }, + + /** + * + * @param {Em.Object} context + * @param {object} blueprintObject + */ + saveRecommendations: function(context, blueprintObject) { + var oldValueKey = context.get('controller.wizardController.name') === 'installerController' ? 'initialValue' : 'savedValue'; + var config = this.get('configWidgetContext.config'); + + context.get('controller').loadRecommendationsSuccess({ + resources: [ + { + recommendations: { + blueprint: { + configurations: blueprintObject + } + } } + ] + }, null, { + dataToSend: { + changed_configurations: [{ + type: App.config.getConfigTagFromFileName(config.get('fileName')), + name: config.get('name'), + old_value: config.get(oldValueKey) + }] } }); + }, + + /** + * + * @param dependencies + * @param serviceConfigs + * @returns {{}} + */ + getDependenciesForeignKeys: function(dependencies, serviceConfigs) { + var foreignKeys = {}; + if (dependencies.foreignKeys) { + dependencies.foreignKeys.forEach(function (dependency) { + var matchingProperty = serviceConfigs.find(function (property) { + return property.get('filename') === App.config.getOriginalFileName(dependency.fileName) && property.get('name') === dependency.propertyName; + }); + if (matchingProperty) { + foreignKeys[dependency.key] = matchingProperty.get('value'); + } + }); + } + return foreignKeys; + }, + + /** + * + * @param dependencies + * @param context + * @returns {Array} + */ + getMasterComponents: function(dependencies, context) { + var masterComponents = []; + if (this.get('content.controllerName')) { + var savedMasterComponents = context.get('controller.content.masterComponentHosts').filter(function (componentObject) { + return dependencies.initializer.componentNames.contains(componentObject.component); + }); + masterComponents = savedMasterComponents.map(function (componentObject) { + var masterComponent = Em.getProperties(componentObject, ['component', 'hostName']); + masterComponent.isInstalled = true; + return masterComponent; + }); + } else { + var hostsMap = blueprintUtils.getComponentForHosts(); + Em.keys(hostsMap).forEach(function (hostName) { + hostsMap[hostName].forEach(function (componentName) { + if (dependencies.initializer.componentNames.contains(componentName)) { + masterComponents.push({ + component: componentName, + hostName: hostName, + isInstalled: true + }); + } + }); + }); + } + return masterComponents; } }); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/cebbff05/ambari-web/test/controllers/wizard/step7/assign_master_controller_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/controllers/wizard/step7/assign_master_controller_test.js b/ambari-web/test/controllers/wizard/step7/assign_master_controller_test.js index e70055b..1380ef2 100644 --- a/ambari-web/test/controllers/wizard/step7/assign_master_controller_test.js +++ b/ambari-web/test/controllers/wizard/step7/assign_master_controller_test.js @@ -19,6 +19,8 @@ var App = require('app'); var stringUtils = require('utils/string_utils'); var numberUtils = require('utils/number_utils'); +var blueprintUtils = require('utils/blueprint'); +var testHelpers = require('test/helpers'); require('models/stack_service_component'); describe('App.AssignMasterOnStep7Controller', function () { @@ -50,58 +52,51 @@ describe('App.AssignMasterOnStep7Controller', function () { describe("#execute()", function () { var context = Em.Object.create({ controller: { - content: Em.Object.create({ - controllerName: "" - }) + content: {} } }); beforeEach(function() { - this.mock = sinon.stub(view, 'getAllMissingDependentServices'); - sinon.stub(view, 'showInstallServicesPopup'); - sinon.stub(view, 'showAssignComponentPopup'); + sinon.stub(view, 'showPopup'); sinon.stub(view, 'removeMasterComponent'); - view.reopen({ - content: Em.Object.create() - }); - }); + sinon.stub(view, 'getPendingBatchRequests'); + }); afterEach(function() { - this.mock.restore(); - view.showInstallServicesPopup.restore(); - view.showAssignComponentPopup.restore(); + view.getPendingBatchRequests.restore(); + view.showPopup.restore(); view.removeMasterComponent.restore(); }); - it("ADD action, controllerName is empty", function() { - this.mock.returns([{}]); + it("should set configWidgetContext", function() { view.execute(context, 'ADD', {componentName: 'C1'}); - expect(view.showInstallServicesPopup.calledOnce).to.be.true; + expect(view.get('configWidgetContext')).to.be.eql(context); }); - it("ADD action, controllerName is set", function() { - context = Em.Object.create({ - controller: { - content: Em.Object.create({ - controllerName: "ctrl1" - }) - } - }); - this.mock.returns([{}]); + it("should set content", function() { view.execute(context, 'ADD', {componentName: 'C1'}); - expect(view.showAssignComponentPopup.calledOnce).to.be.true; + expect(view.get('content')).to.be.eql({}); }); - it("ADD action, no dependent services", function() { - this.mock.returns([]); + it("should set configActionComponent", function() { view.execute(context, 'ADD', {componentName: 'C1'}); - expect(view.showAssignComponentPopup.calledOnce).to.be.true; + expect(view.get('configActionComponent')).to.be.eql({componentName: 'C1'}); }); - it("DELETE action", function() { - this.mock.returns([{}]); + it("should call showPopup when action is ADD", function() { + view.execute(context, 'ADD', {componentName: 'C1'}); + expect(view.showPopup.calledWith({componentName: 'C1'})).to.be.true; + }); + + it("should call getPendingBatchRequests when action is ADD and HIVE_SERVER_INTERACTIVE", function() { + view.execute(context, 'ADD', {componentName: 'HIVE_SERVER_INTERACTIVE'}); + expect(view.getPendingBatchRequests.calledWith({componentName: 'HIVE_SERVER_INTERACTIVE'})).to.be.true; + }); + + it("should call removeMasterComponent when action is DELETE", function() { view.execute(context, 'DELETE', {componentName: 'C1'}); expect(view.removeMasterComponent.calledOnce).to.be.true; + expect(view.get('mastersToCreate')).to.be.eql(['C1']); }); }); @@ -186,11 +181,20 @@ describe('App.AssignMasterOnStep7Controller', function () { beforeEach(function() { sinon.stub(App.router, 'get').returns(mock); sinon.stub(mock, 'setDBProperty'); + sinon.stub(view, 'clearComponentsToBeAdded'); + sinon.stub(App.HostComponent, 'find').returns([ + Em.Object.create({ + componentName: 'C1', + hostName: 'host1' + }) + ]); }); afterEach(function() { App.router.get.restore(); mock.setDBProperty.restore(); + view.clearComponentsToBeAdded.restore(); + App.HostComponent.find.restore(); }); it("should set masterComponentHosts", function() { @@ -216,6 +220,22 @@ describe('App.AssignMasterOnStep7Controller', function () { expect(view.get('content.masterComponentHosts')).to.be.eql([{component: 'C1'}]); expect(view.get('content.recommendationsHostGroups').blueprint).to.be.eql({host_groups: [{name: 'host-group-1', components: [{name: 'C1'}]}]}); }); + + it("should call clearComponentsToBeAdded when controllerName is null", function() { + view.setProperties({ + content: Em.Object.create(), + mastersToCreate: ['C1'], + configWidgetContext: { + config: Em.Object.create() + } + }); + view.removeMasterComponent(); + expect(view.clearComponentsToBeAdded.calledWith('C1')).to.be.true; + expect(App.get('componentToBeDeleted')).to.be.eql(Em.Object.create({ + componentName: 'C1', + hostName: 'host1' + })); + }); }); describe("#renderHostInfo()", function () { @@ -318,101 +338,657 @@ describe('App.AssignMasterOnStep7Controller', function () { }); }); - describe("#submit()", function () { - var popup = { - hide: Em.K + describe('#getPendingBatchRequests', function() { + + it('App.ajax.send should be called', function() { + view.getPendingBatchRequests({componentName: 'C1'}); + var args = testHelpers.findAjaxRequest('name', 'request_schedule.get.pending'); + expect(args[0]).to.be.eql({ + name : 'request_schedule.get.pending', + sender: view, + error : 'pendingBatchRequestsAjaxError', + success: 'pendingBatchRequestsAjaxSuccess', + data: { + hostComponent: {componentName: 'C1'} + } + }); + }); + }); + + describe('#pendingBatchRequestsAjaxError', function() { + beforeEach(function() { + sinon.stub(App, 'showAlertPopup'); + }); + afterEach(function() { + App.showAlertPopup.restore(); + }); + + it('should call showAlertPopup, invalid JSON', function() { + view.pendingBatchRequestsAjaxError({responseText: null}); + expect(App.showAlertPopup.calledWith( + Em.I18n.t('services.service.actions.run.yarnRefreshQueues.error'), + Em.I18n.t('services.service.actions.run.yarnRefreshQueues.error'), + null + )).to.be.true; + }); + + it('should call showAlertPopup, valid JSON', function() { + view.pendingBatchRequestsAjaxError({responseText: '{"message":"foo"}'}); + expect(App.showAlertPopup.calledWith( + Em.I18n.t('services.service.actions.run.yarnRefreshQueues.error'), + Em.I18n.t('services.service.actions.run.yarnRefreshQueues.error') + 'foo', + null + )).to.be.true; + }); + }); + + describe('#pendingBatchRequestsAjaxSuccess', function() { + var configWidgetContext = Em.Object.create({ + config: Em.Object.create({ + initialValue: 'iv1', + value: 'v1' + }), + controller: { + forceUpdateBoundaries: false + }, + setValue: sinon.spy(), + sendRequestRorDependentConfigs: sinon.spy() + }); + beforeEach(function() { + this.mock = sinon.stub(view, 'shouldShowAlertOnBatchRequest'); + sinon.stub(App, 'showAlertPopup', function() { + arguments[2].apply({hide: Em.K}); + }); + sinon.stub(view, 'showPopup'); + view.set('configWidgetContext', configWidgetContext); + }); + afterEach(function() { + this.mock.restore(); + App.showAlertPopup.restore(); + view.showPopup.restore(); + }); + + it('showPopup should be called', function() { + this.mock.returns(false); + view.pendingBatchRequestsAjaxSuccess({}, {}, {hostComponent: {componentName: 'C1'}}); + expect(view.showPopup.calledWith({componentName: 'C1'})).to.be.true; + }); + + it('showAlertPopup should be called', function() { + this.mock.returns(true); + view.pendingBatchRequestsAjaxSuccess({}, {}, {hostComponent: {componentName: 'C1'}}); + expect(App.showAlertPopup.calledWith( + Em.I18n.t('services.service.actions.hsi.alertPopup.header'), + Em.I18n.t('services.service.actions.hsi.alertPopup.body') + )).to.be.true; + expect(configWidgetContext.get('config.value')).to.be.equal('iv1'); + expect(configWidgetContext.get('controller.forceUpdateBoundaries')).to.be.true; + expect(configWidgetContext.setValue.calledWith('iv1')).to.be.true; + expect(configWidgetContext.sendRequestRorDependentConfigs.calledWith( + configWidgetContext.get('config') + )).to.be.true; + }); + }); + + describe('#shouldShowAlertOnBatchRequest', function() { + var testCases = [ + { + input: {}, + expected: false }, - mock = { - saveMasterComponentHosts: Em.K, - loadMasterComponentHosts: Em.K, - setDBProperty: Em.K + { + input: { + items: [] + }, + expected: false + }, + { + input: { + items: [ + { + RequestSchedule: { + batch: { + batch_requests: [ + { + request_type: 'ADD', + request_uri: '' + } + ] + } + } + } + ] + }, + expected: false }, - config = Em.Object.create({ - filename: 'file1', - name: 'conf1' + { + input: { + items: [ + { + RequestSchedule: { + batch: { + batch_requests: [ + { + request_type: 'DELETE', + request_uri: 'HIVE_SERVER_INTERACTIVE' + } + ] + } + } + } + ] + }, + expected: true + } + ]; + + testCases.forEach(function(test) { + it('should return ' + test.expected + ' when data = ' + JSON.stringify(test.input), function() { + expect(view.shouldShowAlertOnBatchRequest(test.input)).to.be.equal(test.expected); }); + }); + }); + + describe('#updateComponent and showAddControl should be false for component', function() { beforeEach(function() { - sinon.stub(popup, 'hide'); - sinon.stub(App.router, 'get').returns(mock); - sinon.stub(mock, 'saveMasterComponentHosts'); - sinon.stub(mock, 'loadMasterComponentHosts'); - sinon.stub(mock, 'setDBProperty'); - sinon.stub(App.config, 'getConfigTagFromFileName', function (value) { - return value; + sinon.stub(App.StackServiceComponent, 'find').returns([ + Em.Object.create({ + componentName: 'C1', + stackService: Em.Object.create({ + isInstalled: false + }) + }) + ]); + }); + afterEach(function() { + App.StackServiceComponent.find.restore(); + }); + + it('showRemoveControl ', function() { + var component = Em.Object.create({ + component_name: 'C1', + showAddControl: true, + showRemoveControl: true }); + view.setProperties({ + mastersToCreate: [], + selectedServicesMasters: [ component, {component_name: 'C2'} ] + }); + view.updateComponent('C1'); + expect(component.get('showAddControl')).to.be.false; + expect(component.get('showRemoveControl')).to.be.false; + }); + }); + + describe('#saveRecommendationsHostGroups', function() { + beforeEach(function() { + sinon.stub(view, 'getSelectedHostName').returns('host1'); + }); + afterEach(function() { + view.getSelectedHostName.restore(); + }); + + it('should add component to recommendations', function() { + var recommendationsHostGroups = { + blueprint_cluster_binding: { + host_groups: [ + { + name: 'g1', + hosts: [ + { + fqdn: 'host1' + } + ] + } + ] + }, + blueprint: { + host_groups: [ + { + name: 'g1', + components: [] + } + ] + } + }; view.reopen({ + mastersToCreate: ['C1'], content: Em.Object.create({ - controllerName: 'ctrl1', - componentsFromConfigs: [] - }), - selectedServicesMasters: [ - { - component_name: 'C1', - selectedHost: 'host1' - } - ], - popup: popup, - configActionComponent: { - componentName: 'C1' - }, - configWidgetContext: Em.Object.create({ - config: Em.Object.create({ - fileName: 'file1', - name: 'conf1', + recommendationsHostGroups: recommendationsHostGroups + }) + }); + view.saveRecommendationsHostGroups(); + expect(view.get('content.recommendationsHostGroups')).to.be.eql(Object.assign(recommendationsHostGroups, { + blueprint: { + host_groups: [ + { + name: 'g1', + components: [{name: 'C1'}] + } + ] + } + })); + }); + }); + + describe('#setGlobalComponentToBeAdded', function() { + + it('should set componentToBeAdded', function() { + view.setGlobalComponentToBeAdded('C1', 'host1'); + expect(App.get('componentToBeAdded')).to.be.eql(Em.Object.create({ + componentName: 'C1', + hostNames: ['host1'] + })); + }); + }); + + describe('#clearComponentsToBeDeleted', function() { + + it('should clear componentToBeDeleted', function() { + App.set('componentToBeDeleted', Em.Object.create({ + componentName: 'C1' + })); + view.clearComponentsToBeDeleted('C1'); + expect(App.get('componentToBeDeleted')).to.be.empty; + }); + }); + + describe('#clearComponentsToBeAdded', function() { + + it('should clear componentToBeAdded', function() { + App.set('componentToBeAdded', Em.Object.create({ + componentName: 'C1' + })); + view.clearComponentsToBeAdded('C1'); + expect(App.get('componentToBeAdded')).to.be.empty; + }); + }); + + describe('#showPopup', function() { + beforeEach(function() { + this.mock = sinon.stub(view, 'getAllMissingDependentServices'); + sinon.stub(view, 'showInstallServicesPopup'); + sinon.stub(view, 'showAssignComponentPopup'); + }); + afterEach(function() { + this.mock.restore(); + view.showInstallServicesPopup.restore(); + view.showAssignComponentPopup.restore(); + }); + + it('showAssignComponentPopup should be called', function() { + this.mock.returns([]); + view.showPopup({componentName: 'C1'}); + expect(view.get('mastersToCreate')).to.be.eql(['C1']); + expect(view.showAssignComponentPopup.calledOnce).to.be.true; + }); + + it('showInstallServicesPopup should be called', function() { + this.mock.returns([{}]); + view.reopen({ + content: Em.Object.create() + }); + view.showPopup({componentName: 'C1'}); + expect(view.showInstallServicesPopup.calledWith([{}])).to.be.true; + }); + }); + + describe('#submit', function() { + var configWidgetContext = Em.Object.create({ + controller: { + forceUpdateBoundaries: false, + stepConfigs: [ + Em.Object.create({ serviceName: 'S1', - savedValue: 'val1', - toggleProperty: Em.K + configs: [] }), - controller: Em.Object.create({ - selectedService: { - serviceName: 'S1' - }, - wizardController: { - name: 'ctrl' - }, - stepConfigs: [ - Em.Object.create({ - serviceName: 'S1', - configs: [ - config - ] - }), - Em.Object.create({ - serviceName: 'MISC', - configs: [ - config - ] - }) - ] + Em.Object.create({ + serviceName: 'MISC', + configs: [] }) - }) + ], + selectedService: { + serviceName: 'S1' + } + }, + config: Em.Object.create({ + configAction: { + dependencies: [] + } + }) + }); + beforeEach(function() { + sinon.stub(view, 'resolveDependencies'); + sinon.stub(view, 'saveMasterComponentHosts'); + sinon.stub(view, 'saveRecommendationsHostGroups'); + sinon.stub(view, 'setGlobalComponentToBeAdded'); + sinon.stub(view, 'clearComponentsToBeDeleted'); + sinon.stub(App, 'get').returns({ + getKDCSessionState: Em.clb + }); + sinon.stub(view, 'getSelectedHostName').returns('host1'); + view.setProperties({ + configWidgetContext: configWidgetContext, + configActionComponent: { componentName: 'C1'}, + popup: { + hide: sinon.spy() + } + }); + }); + afterEach(function() { + App.get.restore(); + view.resolveDependencies.restore(); + view.clearComponentsToBeDeleted.restore(); + view.setGlobalComponentToBeAdded.restore(); + view.saveRecommendationsHostGroups.restore(); + view.saveMasterComponentHosts.restore(); + view.getSelectedHostName.restore(); + }); + + it('saveMasterComponentHosts should be called when controllerName defined', function() { + view.reopen({ + content: { + controllerName: 'ctrl1' + } + }); + view.submit(); + expect(view.saveMasterComponentHosts.calledOnce).to.be.true; + }); + it('saveRecommendationsHostGroups should be called when controllerName defined', function() { + view.reopen({ + content: { + controllerName: 'ctrl1' + } + }); + view.submit(); + expect(view.saveRecommendationsHostGroups.calledOnce).to.be.true; + }); + it('setGlobalComponentToBeAdded should be called when controllerName undefined', function() { + view.reopen({ + content: { + controllerName: undefined + } + }); + view.submit(); + expect(view.setGlobalComponentToBeAdded.calledWith('C1', 'host1')).to.be.true; + }); + it('clearComponentsToBeDeleted should be called when controllerName undefined', function() { + view.reopen({ + content: { + controllerName: undefined + } }); view.submit(); + expect(view.clearComponentsToBeDeleted.calledWith('C1')).to.be.true; + }); + it('resolveDependencies should be called', function() { + view.submit(); + expect(view.resolveDependencies.calledWith([], [])).to.be.true; + }); + it('hide should be called', function() { + view.submit(); + expect(view.get('popup').hide.calledOnce).to.be.true; + }); + it('configActionComponent should be set', function() { + view.submit(); + expect(view.get('configWidgetContext.config.configActionComponent')).to.be.eql({ + componentName: 'C1', + hostName: 'host1' + }); + }); + }); + + describe('#resolveDependencies', function() { + var initializer = { + setup: sinon.spy(), + initialValue: sinon.stub().returns({value: 'val1'}), + cleanup: sinon.spy() + }; + var dependencies = { + properties: [ + { + name: 'p1', + fileName: 'file1.xml', + nameTemplate: '{{bar}}', + isHostsList: true, + isHostsArray: false + } + ], + initializer: { + name: 'i1', + setupKeys: ['bar'] + } + }; + var context = Em.Object.create({ + controller: { + selectedService: { + serviceName: 'S1' + } + } + }); + var serviceConfigs = [ + Em.Object.create({ + name: 'foo', + filename: 'file1.xml', + value: 'val1' + }) + ]; + + beforeEach(function() { + sinon.stub(view, 'getDependenciesForeignKeys').returns({ + bar: 'foo' + }); + sinon.stub(App, 'get').returns(initializer); + sinon.stub(view, 'getMasterComponents'); + sinon.stub(view, 'saveRecommendations'); + sinon.stub(App.config, 'updateHostsListValue'); + sinon.stub(App.config, 'get').returns({ + 'file1.xml': Em.Object.create({ + serviceName: 'S1' + }) + }); + view.resolveDependencies(dependencies, serviceConfigs, context); + }); + afterEach(function() { + App.config.get.restore(); + view.getDependenciesForeignKeys.restore(); + App.get.restore(); + view.getMasterComponents.restore(); + view.saveRecommendations.restore(); + App.config.updateHostsListValue.restore(); + }); + + it('initializer.setup should be called', function() { + expect(initializer.setup.calledWith({bar: 'foo'})).to.be.true; + }); + it('initializer.setup initialValue be called', function() { + expect(initializer.initialValue.calledWith({ + name: 'foo', + fileName: 'file1.xml' + })).to.be.true; + }); + it('initializer.cleanup should be called', function() { + expect(initializer.cleanup.called).to.be.true; }); + it('saveRecommendations should be called', function() { + expect(view.saveRecommendations.calledWith(context)).to.be.true; + }); + it('App.config.updateHostsListValue should be called', function() { + expect(App.config.updateHostsListValue.getCall(0).args).to.be.eql([ + { + foo: 'val1' + }, + 'file1.xml', + 'foo', + undefined, + false + ]); + }); + }); + describe('#saveMasterComponentHosts', function() { + var mockCtrl = { + saveMasterComponentHosts: sinon.spy(), + loadMasterComponentHosts: sinon.spy() + }; + beforeEach(function() { + sinon.stub(App.router, 'get').returns(mockCtrl); + view.reopen({ + content: Em.Object.create({ + componentsFromConfigs: [] + }) + }); + view.set('mastersToCreate', [ + {} + ]); + }); afterEach(function() { App.router.get.restore(); - popup.hide.restore(); - mock.saveMasterComponentHosts.restore(); - mock.loadMasterComponentHosts.restore(); - mock.setDBProperty.restore(); - App.config.getConfigTagFromFileName.restore(); }); - it("saveMasterComponentHosts should be called", function() { - expect(mock.saveMasterComponentHosts.calledOnce).to.be.true; + it('saveMasterComponentHosts should be called', function() { + view.saveMasterComponentHosts(); + expect(mockCtrl.saveMasterComponentHosts.calledWith(view, true)).to.be.true; + }); + it('loadMasterComponentHosts should be called', function() { + view.saveMasterComponentHosts(); + expect(mockCtrl.loadMasterComponentHosts.calledWith(true)).to.be.true; }); + it('componentsFromConfigs should be set', function() { + view.saveMasterComponentHosts(); + expect(view.get('content.componentsFromConfigs')).to.be.eql([{}]); + }); + }); - it("loadMasterComponentHosts should be called", function() { - expect(mock.loadMasterComponentHosts.calledOnce).to.be.true; + describe('#getSelectedHostName', function() { + + it('should return host of component', function() { + view.set('selectedServicesMasters', [ + { + component_name: 'C1', + selectedHost: 'host1' + } + ]); + expect(view.getSelectedHostName('C1')).to.be.equal('host1'); }); + }); - it("configActionComponent should be set", function() { - expect(view.get('configWidgetContext.config.configActionComponent')).to.be.eql({ - componentName: 'C1', - hostName: 'host1' + describe('#saveRecommendations', function() { + var mockCtrl = { + loadRecommendationsSuccess: sinon.spy(), + wizardController: { + name: 'installerController' + } + }; + var context = Em.Object.create({ + controller: mockCtrl + }); + it('loadRecommendationsSuccess should be called', function() { + view.set('configWidgetContext', { + config: Em.Object.create({ + fileName: 'foo.xml', + name: 'bar', + initialValue: 'iv1' + }) + }); + view.saveRecommendations(context, {}); + expect(mockCtrl.loadRecommendationsSuccess.getCall(0).args).to.be.eql([ + { + resources: [ + { + recommendations: { + blueprint: { + configurations: {} + } + } + } + ] + }, null, { + dataToSend: { + changed_configurations: [{ + type: 'foo', + name: 'bar', + old_value: 'iv1' + }] + } + } + ]); + }); + }); + + describe('#getDependenciesForeignKeys', function() { + var dependencies = { + foreignKeys: [ + { + fileName: 'foo.xml', + propertyName: 'c1', + key: 'k1' + } + ] + }; + var serviceConfigs = [ + Em.Object.create({ + filename: 'foo.xml', + name: 'c1', + value: 'val1' + }) + ]; + + it('should return foreignKeys map', function() { + expect(view.getDependenciesForeignKeys(dependencies, serviceConfigs)).to.be.eql({ + k1: 'val1' + }); + }); + }); + + describe('#getMasterComponents', function() { + var dependencies = { + initializer: { + componentNames: ['C1'] + } + }; + var context = Em.Object.create({ + controller: { + content: { + masterComponentHosts: [ + { + component: 'C1', + hostName: 'host2' + } + ] + } + } + }); + beforeEach(function() { + sinon.stub(blueprintUtils, 'getComponentForHosts').returns({ + host1: ['C1'] }); }); + afterEach(function() { + blueprintUtils.getComponentForHosts.restore(); + }); + + it('should return master components when controllerName undefined', function() { + view.set('content.controllerName', undefined); + expect(view.getMasterComponents(dependencies, context)).to.be.eql([ + { + component: 'C1', + hostName: 'host1', + isInstalled: true + } + ]); + }); + + it('should return master components when controllerName valid', function() { + view.set('content.controllerName', 'ctrl1'); + expect(view.getMasterComponents(dependencies, context)).to.be.eql([ + { + component: 'C1', + hostName: 'host2', + isInstalled: true + } + ]); + }); }); }); \ No newline at end of file