AMBARI-18379 Cover host views 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/2ad42074 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/2ad42074 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/2ad42074 Branch: refs/heads/branch-dev-patch-upgrade Commit: 2ad42074f1633c5c6f56cf979bdaa49440457566 Parents: 5beed88 Author: Andrii Tkach <[email protected]> Authored: Tue Sep 13 20:28:41 2016 +0300 Committer: Andrii Tkach <[email protected]> Committed: Wed Sep 14 16:22:17 2016 +0300 ---------------------------------------------------------------------- ambari-web/app/assets/test/tests.js | 3 + .../app/views/main/host/combo_search_box.js | 294 ++++-- .../views/main/host/hosts_table_menu_view.js | 14 +- ambari-web/app/views/main/host/log_metrics.js | 2 +- .../views/main/host/combo_search_box_test.js | 957 ++++++++++++++++++- .../views/main/host/host_alerts_view_test.js | 23 +- .../main/host/hosts_table_menu_view_test.js | 304 ++++++ .../test/views/main/host/log_metrics_test.js | 116 +++ .../test/views/main/host/logs_view_test.js | 178 ++++ .../views/main/host/stack_versions_view_test.js | 66 ++ ambari-web/test/views/main/host/summary_test.js | 91 ++ 11 files changed, 1942 insertions(+), 106 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/2ad42074/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 d2f3637..d918900 100644 --- a/ambari-web/app/assets/test/tests.js +++ b/ambari-web/app/assets/test/tests.js @@ -296,6 +296,9 @@ var files = [ 'test/views/main/host/combo_search_box_test', 'test/views/main/host/config_service_test', 'test/views/main/host/add_view_test', + 'test/views/main/host/logs_view_test', + 'test/views/main/host/hosts_table_menu_view_test', + 'test/views/main/host/log_metrics_test', 'test/views/main/host/config_service_menu_test', 'test/views/main/host/details/host_component_view_test', 'test/views/main/host/details/host_component_views/decommissionable_test', http://git-wip-us.apache.org/repos/asf/ambari/blob/2ad42074/ambari-web/app/views/main/host/combo_search_box.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/main/host/combo_search_box.js b/ambari-web/app/views/main/host/combo_search_box.js index f417cc6..2f9900a 100644 --- a/ambari-web/app/views/main/host/combo_search_box.js +++ b/ambari-web/app/views/main/host/combo_search_box.js @@ -60,7 +60,7 @@ App.MainHostComboSearchBoxView = Em.View.extend({ if (invalidFacet) { this.showErrMsg(invalidFacet); } - var tableView = this.get('parentView').get('parentView'); + var tableView = this.get('parentView.parentView'); App.db.setComboSearchQuery(tableView.get('controller.name'), query); var filterConditions = this.createFilterConditions(searchCollection); tableView.updateComboFilter(filterConditions); @@ -87,7 +87,7 @@ App.MainHostComboSearchBoxView = Em.View.extend({ // Add host component facets only when there isn't any component filter // with value other than ALL yet var currentComponentFacets = this.getComponentStateFacets(hostComponentList, false); - if (currentComponentFacets.length == 0) { + if (currentComponentFacets.length === 0) { list = list.concat(hostComponentList); } list = this.filterOutOneFacetOnlyOptions(list); @@ -105,7 +105,6 @@ App.MainHostComboSearchBoxView = Em.View.extend({ var controller = App.router.get('mainHostComboSearchBoxController'); this.showHideClearButton(); var map = App.router.get('mainHostController.labelValueMap'); - var serviceMap = this.get('serviceMap') var facetValue = map[facet] || facet; if (controller.isComponentStateFacet(facetValue)) { facetValue = 'componentState' @@ -113,76 +112,153 @@ App.MainHostComboSearchBoxView = Em.View.extend({ switch (facetValue) { case 'hostName': case 'ip': - controller.getPropertySuggestions(facetValue, searchTerm).done(function() { - callback(controller.get('currentSuggestion').reject(function (item) { - return visualSearch.searchQuery.values(facet).indexOf(item) >= 0; // reject the ones already in search - }), {preserveMatches: true}); - }); + this.searchByHostname(facetValue, searchTerm, facet, callback); break; case 'rack': - callback(App.Host.find().toArray().mapProperty('rack').uniq().reject(function (item) { - return visualSearch.searchQuery.values(facet).indexOf(item) >= 0; - })); + this.searchByRack(facet, callback); break; case 'version': - callback(App.HostStackVersion.find().toArray() - .filterProperty('isVisible', true).mapProperty('displayName').uniq().reject(function (item) { - return visualSearch.searchQuery.values(facet).indexOf(item) >= 0; - })); + this.searchByVersion(facet, callback); break; case 'versionState': - callback(App.HostStackVersion.statusDefinition.map(function (status) { - map[App.HostStackVersion.formatStatus(status)] = status; - return App.HostStackVersion.formatStatus(status); - }).reject(function (item) { - return visualSearch.searchQuery.values(facet).indexOf(item) >= 0; - })); + this.searchByVersionState(facet, callback, map); break; case 'healthClass': - var category_mocks = this.healthStatusCategories; - callback(category_mocks.slice(1).map(function (category) { - map[category.value] = category.healthStatus; - return category.value; - }).reject(function (item) { - return visualSearch.searchQuery.values(facet).indexOf(item) >= 0; - }), {preserveOrder: true}); + this.searchByHealthClass(facet, callback, map); break; case 'services': - callback(App.Service.find().toArray().map(function (service) { - serviceMap[App.format.role(service.get('serviceName'), true)] = service.get('serviceName'); - return App.format.role(service.get('serviceName'), true); - }).reject(function (item) { - return visualSearch.searchQuery.values(facet).indexOf(item) >= 0; - }), {preserveOrder: true}); + this.searchByServices(facet, callback); break; case 'componentState': - var list = [ "All" ]; - // client only have "ALL" state - if (facet.toLowerCase().indexOf("client") == -1) - { - var currentComponentFacets = this.getComponentStateFacets(null, true); - if (currentComponentFacets.length == 0) { - list = list.concat(App.HostComponentStatus.getStatusesList() - .reject(function(status){return status == "UPGRADE_FAILED"}) // take out 'UPGRADE_FAILED' - .map(function (status) { - map[App.HostComponentStatus.getTextStatus(status)] = status; - return App.HostComponentStatus.getTextStatus(status); - })) - .concat([ - "Inservice", - "Decommissioned", - "Decommissioning", - "RS Decommissioned", - "Maintenance Mode On", - "Maintenance Mode Off" - ]); - } - } - callback(list, {preserveOrder: true}); + this.searchByComponentState(facet, callback, map); break; } }, + /** + * + * @param {string} facetValue + * @param {string} searchTerm + * @param {string} facet + * @param {Function} callback + */ + searchByHostname: function(facetValue, searchTerm, facet, callback) { + var controller = App.router.get('mainHostComboSearchBoxController'); + + controller.getPropertySuggestions(facetValue, searchTerm).done(function() { + callback(controller.get('currentSuggestion').reject(function (item) { + return visualSearch.searchQuery.values(facet).indexOf(item) >= 0; // reject the ones already in search + }), {preserveMatches: true}); + }); + }, + + /** + * + * @param {string} facet + * @param {Function} callback + */ + searchByRack: function(facet, callback) { + callback(App.Host.find().toArray().mapProperty('rack').uniq().reject(function (item) { + return visualSearch.searchQuery.values(facet).indexOf(item) >= 0; + })); + }, + + /** + * + * @param {string} facet + * @param {Function} callback + */ + searchByVersion: function(facet, callback) { + callback(App.HostStackVersion.find().toArray() + .filterProperty('isVisible', true).mapProperty('displayName').uniq().reject(function (item) { + return visualSearch.searchQuery.values(facet).indexOf(item) >= 0; + })); + }, + + /** + * + * @param {string} facet + * @param {Function} callback + * @param {object} map + */ + searchByVersionState: function(facet, callback, map) { + callback(App.HostStackVersion.statusDefinition.map(function (status) { + map[App.HostStackVersion.formatStatus(status)] = status; + return App.HostStackVersion.formatStatus(status); + }).reject(function (item) { + return visualSearch.searchQuery.values(facet).indexOf(item) >= 0; + })); + }, + + /** + * + * @param {string} facet + * @param {Function} callback + * @param {object} map + */ + searchByHealthClass: function(facet, callback, map) { + //exclude "All" category + var category_mocks = this.get('healthStatusCategories').slice(1); + + callback(category_mocks.map(function (category) { + map[category.value] = category.healthStatus; + return category.value; + }).reject(function (item) { + return visualSearch.searchQuery.values(facet).indexOf(item) >= 0; + }), {preserveOrder: true}); + }, + + /** + * + * @param {string} facet + * @param {Function} callback + */ + searchByServices: function(facet, callback) { + var serviceMap = this.get('serviceMap'); + + callback(App.Service.find().toArray().map(function (service) { + serviceMap[App.format.role(service.get('serviceName'), true)] = service.get('serviceName'); + return App.format.role(service.get('serviceName'), true); + }).reject(function (item) { + return visualSearch.searchQuery.values(facet).indexOf(item) >= 0; + }), {preserveOrder: true}); + }, + + /** + * + * @param {string} facet + * @param {Function} callback + * @param {object} map + */ + searchByComponentState: function (facet, callback, map) { + var list = ["All"]; + // client only have "ALL" state + if (facet.toLowerCase().indexOf("client") === -1) { + var currentComponentFacets = this.getComponentStateFacets(null, true); + if (currentComponentFacets.length === 0) { + list = list.concat( + App.HostComponentStatus.getStatusesList() + .reject(function (status) { + return status === "UPGRADE_FAILED" + }) // take out 'UPGRADE_FAILED' + .map(function (status) { + map[App.HostComponentStatus.getTextStatus(status)] = status; + return App.HostComponentStatus.getTextStatus(status); + }) + ) + .concat([ + "Inservice", + "Decommissioned", + "Decommissioning", + "RS Decommissioned", + "Maintenance Mode On", + "Maintenance Mode Off" + ]); + } + } + callback(list, {preserveOrder: true}); + }, + findInvalidFacet: function(searchCollection) { var result = null; var map = App.router.get('mainHostController.labelValueMap'); @@ -204,8 +280,8 @@ App.MainHostComboSearchBoxView = Em.View.extend({ this.set('errMsg', '') }, - showHideClearButton: function() { - if(visualSearch.searchQuery.toJSON().length > 0) { + showHideClearButton: function () { + if (visualSearch.searchQuery.toJSON().length > 0) { $('.VS-cancel-search-box').removeClass('hide'); } else { $('.VS-cancel-search-box').addClass('hide'); @@ -234,25 +310,34 @@ App.MainHostComboSearchBoxView = Em.View.extend({ return hostComponentList; }, - getComponentStateFacets: function(hostComponentList, includeAllValue) { + /** + * + * @param {Array} hostComponentList + * @param {boolean} includeAllValue + * @returns {Array} + */ + getComponentStateFacets: function (hostComponentList, includeAllValue) { if (!hostComponentList) { hostComponentList = this.getHostComponentList(); } - var currentComponentFacets = visualSearch.searchQuery.toJSON().filter(function (facet) { - var result = !!(hostComponentList.findProperty('label', facet.category) && facet.value); + return visualSearch.searchQuery.toJSON().filter(function (facet) { + var result = Boolean(hostComponentList.findProperty('label', facet.category) && facet.value); if (!includeAllValue) { - result &= (facet.value != 'All'); + result &= (facet.value !== 'All'); } return result; }); - return currentComponentFacets; }, + /** + * + * @param {string} name + * @returns {Array} + */ getFacetsByName: function(name) { - var facets = visualSearch.searchQuery.toJSON().filter(function(facet) { + return visualSearch.searchQuery.toJSON().filter(function(facet) { return facet.category === name; }); - return facets; }, filterOutOneFacetOnlyOptions: function(options) { @@ -288,59 +373,80 @@ App.MainHostComboSearchBoxView = Em.View.extend({ map['Maintenance Mode Off'] = 'OFF'; }, - createFilterConditions: function(searchCollection) { - var self = this; - var mainHostController = App.router.get('mainHostController'); - var map = mainHostController.get('labelValueMap'); + createFilterConditions: function (searchCollection) { + var map = App.router.get('mainHostController.labelValueMap'); var serviceMap = this.get('serviceMap'); var filterConditions = Em.A(); + searchCollection.models.forEach(function (model) { var tag = model.attributes; var category = map[tag.category] || tag.category; - var value = (category == 'services')? (serviceMap[tag.value] || tag.value) : (map[tag.value] || tag.value); - - var iColumn = self.getFilterColumn(category, value); - var filterValue = self.getFilterValue(category, value); + var value = (category === 'services') ? (serviceMap[tag.value] || tag.value) : (map[tag.value] || tag.value); + var iColumn = this.getFilterColumn(category, value); + var filterValue = this.getFilterValue(category, value); var condition = filterConditions.findProperty('iColumn', iColumn); + if (condition) { // handle multiple facets with same category - if (typeof condition.value == 'string') { + if (typeof condition.value === 'string') { condition.value = [condition.value, filterValue]; - } else if (Em.isArray(condition.value) && condition.value.indexOf(filterValue) == -1) { + } else if (Em.isArray(condition.value) && condition.value.indexOf(filterValue) === -1) { condition.value.push(filterValue); } } else { - var type = 'string'; - if (category === 'cpu') { - type = 'number'; - } - if (category === 'memoryFormatted') { - type = 'ambari-bandwidth'; - } - condition = { - skipFilter: false, - iColumn: iColumn, - value: filterValue, - type: type - }; - filterConditions.push(condition); + filterConditions.push(this.createCondition(category, iColumn, filterValue)); } - }); + }, this); return filterConditions; }, + /** + * + * @param {string} category + * @param {number} iColumn + * @param {string} filterValue + * @returns {{skipFilter: boolean, iColumn: number, value: string, type: string}} + */ + createCondition: function(category, iColumn, filterValue) { + var type = 'string'; + if (category === 'cpu') { + type = 'number'; + } + if (category === 'memoryFormatted') { + type = 'ambari-bandwidth'; + } + return { + skipFilter: false, + iColumn: iColumn, + value: filterValue, + type: type + }; + }, + + /** + * + * @param {string} category + * @param {string} value + * @returns {number} + */ getFilterColumn: function(category, value) { - var iColumn = -1; + var iColumn; if (this.get('controller').isComponentStateFacet(category)) { - iColumn = App.router.get('mainHostController').get('colPropAssoc').indexOf('componentState'); + iColumn = App.router.get('mainHostController.colPropAssoc').indexOf('componentState'); } else if (this.get('controller').isComplexHealthStatusFacet(value)) { iColumn = this.get('healthStatusCategories').findProperty('healthStatus', value).column; } else { - iColumn = App.router.get('mainHostController').get('colPropAssoc').indexOf(category); + iColumn = App.router.get('mainHostController.colPropAssoc').indexOf(category); } return iColumn; }, + /** + * + * @param {string} category + * @param {string} value + * @returns {string} + */ getFilterValue: function(category, value) { var filterValue = value; if (this.get('controller').isComponentStateFacet(category)) { http://git-wip-us.apache.org/repos/asf/ambari/blob/2ad42074/ambari-web/app/views/main/host/hosts_table_menu_view.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/main/host/hosts_table_menu_view.js b/ambari-web/app/views/main/host/hosts_table_menu_view.js index 8849244..f820c70 100644 --- a/ambari-web/app/views/main/host/hosts_table_menu_view.js +++ b/ambari-web/app/views/main/host/hosts_table_menu_view.js @@ -44,10 +44,10 @@ App.HostTableMenuView = Em.View.extend({ }); }.property(), - getBulkMenuItemsPerServiceComponent: function(){ + getBulkMenuItemsPerServiceComponent: function () { var menuItems = []; App.StackServiceComponent.find().forEach(function (stackComponent) { - if(stackComponent.get('hasBulkCommandsDefinition')){ + if (stackComponent.get('hasBulkCommandsDefinition')) { var menuItem = O.create({ serviceName: stackComponent.get('serviceName'), componentName: stackComponent.get('componentName'), @@ -208,16 +208,18 @@ App.HostTableMenuView = Em.View.extend({ }.property('App.router.mainServiceController.content.@each', 'content'), tooltipMsg: function () { - return (this.get('disabledElement') == 'disabled') ? - Em.I18n.t('hosts.decommission.tooltip.warning').format(this.get('content.message'), App.format.role(this.get('content.componentName'), false)) : ''; + var displayName = App.format.role(this.get('content.componentName'), false); + return (this.get('disabledElement') === 'disabled') + ? Em.I18n.t('hosts.decommission.tooltip.warning').format(this.get('content.message'), displayName) + : ''; }.property('disabledElement', 'content.componentName'), disabledElement: function () { - return this.get('service.workStatus') == 'STARTED' ? '' : 'disabled'; + return this.get('service.workStatus') === 'STARTED' ? '' : 'disabled'; }.property('service.workStatus'), click: function () { - if (this.get('disabledElement') == 'disabled') { + if (this.get('disabledElement') === 'disabled') { return; } this.get('controller').bulkOperationConfirm(this.get('content'), this.get('selection')); http://git-wip-us.apache.org/repos/asf/ambari/blob/2ad42074/ambari-web/app/views/main/host/log_metrics.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/main/host/log_metrics.js b/ambari-web/app/views/main/host/log_metrics.js index 20f5ec6..92bd86e 100644 --- a/ambari-web/app/views/main/host/log_metrics.js +++ b/ambari-web/app/views/main/host/log_metrics.js @@ -36,7 +36,7 @@ App.MainHostLogMetrics = Em.View.extend({ * @type {ServiceLogMetricsObject[]} */ logsData: function() { - var services = this.get('content').get('hostComponents').mapProperty('service').uniq(); + var services = this.get('content.hostComponents').mapProperty('service').uniq(); var logLevels = ['fatal', 'critical', 'error', 'warning', 'info', 'debug']; return services.map(function(service) { var levels = logLevels.map(function(level) { http://git-wip-us.apache.org/repos/asf/ambari/blob/2ad42074/ambari-web/test/views/main/host/combo_search_box_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/views/main/host/combo_search_box_test.js b/ambari-web/test/views/main/host/combo_search_box_test.js index f6ff040..c82167c 100644 --- a/ambari-web/test/views/main/host/combo_search_box_test.js +++ b/ambari-web/test/views/main/host/combo_search_box_test.js @@ -22,7 +22,24 @@ var view; describe('App.MainHostComboSearchBoxView', function () { beforeEach(function () { - view = App.MainHostComboSearchBoxView.create(); + view = App.MainHostComboSearchBoxView.create({ + parentView: Em.Object.create(), + controller: Em.Object.create({ + isComponentStateFacet: Em.K, + isComplexHealthStatusFacet: Em.K + }) + }); + window.visualSearch = { + searchQuery: { + values: function() { + return []; + }, + toJSON: Em.K + }, + searchBox: { + setQuery: Em.K + } + } }); describe("#didInsertElement()", function() { @@ -30,14 +47,950 @@ describe('App.MainHostComboSearchBoxView', function () { beforeEach(function() { sinon.stub(view, 'initVS'); sinon.stub(view, 'showHideClearButton'); + sinon.stub(view, 'restoreComboFilterQuery'); + view.didInsertElement(); }); afterEach(function() { view.initVS.restore(); + view.showHideClearButton.restore(); + view.restoreComboFilterQuery.restore(); }); it("initVS should be called", function() { - view.didInsertElement(); expect(view.initVS.calledOnce).to.be.true; }); + + it("showHideClearButton should be called", function() { + expect(view.showHideClearButton.calledOnce).to.be.true; + }); + + it("restoreComboFilterQuery should be called", function() { + expect(view.restoreComboFilterQuery.calledOnce).to.be.true; + }); + }); + + describe("#setupLabelMap", function () { + + beforeEach(function() { + sinon.stub(view, 'setupLabelMap'); + sinon.stub(VS, 'init').returns({init: 'init'}); + view.initVS(); + }); + + afterEach(function() { + view.setupLabelMap.restore(); + VS.init.restore(); + }); + + it("setupLabelMap should be called", function() { + expect(view.setupLabelMap.calledOnce).to.be.true; + }); + + it("window.visualSearch should be set", function() { + expect(window.visualSearch).to.be.eql({init: 'init'}); + }); + }); + + describe("#search()", function () { + + beforeEach(function() { + view.set('parentView.parentView', Em.Object.create({ + updateComboFilter: Em.K, + controller: {name: 'ctrl1'} + })); + sinon.stub(view.get('parentView.parentView'), 'updateComboFilter'); + sinon.stub(view, 'createFilterConditions').returns([{}]); + sinon.stub(view, 'clearErrMsg'); + sinon.stub(view, 'showErrMsg'); + sinon.stub(App.db, 'setComboSearchQuery'); + this.mockFacet = sinon.stub(view, 'findInvalidFacet'); + }); + + afterEach(function() { + App.db.setComboSearchQuery.restore(); + view.clearErrMsg.restore(); + view.showErrMsg.restore(); + this.mockFacet.restore(); + view.createFilterConditions.restore(); + view.get('parentView.parentView').updateComboFilter.restore(); + }); + + it("clearErrMsg should be called", function() { + view.search('query', {}); + expect(view.clearErrMsg.calledOnce).to.be.true; + }); + + it("showErrMsg should be called", function() { + this.mockFacet.returns({}); + view.search('query', {}); + expect(view.showErrMsg.calledWith({})).to.be.true; + }); + + it("App.db.setComboSearchQuery should be called", function() { + view.search('query', {}); + expect(App.db.setComboSearchQuery.calledWith('ctrl1', 'query')).to.be.true; + }); + + it("updateComboFilter should be called", function() { + view.search('query', {}); + expect(view.get('parentView.parentView').updateComboFilter.calledWith([{}])).to.be.true; + }); + }); + + describe("#facetMatches()", function () { + var container = { + callback: Em.K + }; + + beforeEach(function() { + sinon.stub(view, 'showHideClearButton'); + sinon.stub(view, 'getHostComponentList').returns([ + Em.Object.create({componentName: 'C1'}) + ]); + this.mock = sinon.stub(view, 'getComponentStateFacets').returns([]); + sinon.stub(view, 'filterOutOneFacetOnlyOptions', function(list) { + return list; + }); + sinon.stub(container, 'callback'); + }); + + afterEach(function() { + view.showHideClearButton.restore(); + view.getHostComponentList.restore(); + this.mock.restore(); + view.filterOutOneFacetOnlyOptions.restore(); + container.callback.restore(); + }); + + it("showHideClearButton should be called", function() { + view.facetMatches(container.callback); + expect(view.showHideClearButton.calledOnce).to.be.true; + }); + + it("callback should be called", function() { + view.facetMatches(container.callback); + expect(container.callback.calledWith( + [ + {label: 'Host Name', category: 'Host'}, + {label: 'IP', category: 'Host'}, + {label: 'Host Status', category: 'Host'}, + {label: 'Cores', category: 'Host'}, + {label: 'RAM', category: 'Host'}, + {label: 'Stack Version', category: 'Host'}, + {label: 'Version State', category: 'Host'}, + {label: 'Rack', category: 'Host'}, + {label: 'Service', category: 'Service'}, + Em.Object.create({componentName: 'C1'}) + ], + {preserveOrder: true} + )).to.be.true; + }); + + it("callback should be called, facets not empty", function() { + this.mock.returns([{}]); + view.facetMatches(container.callback); + expect(container.callback.calledWith( + [ + {label: 'Host Name', category: 'Host'}, + {label: 'IP', category: 'Host'}, + {label: 'Host Status', category: 'Host'}, + {label: 'Cores', category: 'Host'}, + {label: 'RAM', category: 'Host'}, + {label: 'Stack Version', category: 'Host'}, + {label: 'Version State', category: 'Host'}, + {label: 'Rack', category: 'Host'}, + {label: 'Service', category: 'Service'} + ], + {preserveOrder: true} + )).to.be.true; + }); + }); + + describe("#valueMatches()", function () { + var controller = { + isComponentStateFacet: Em.K + }; + var container = { + callback: Em.K + }; + + beforeEach(function() { + sinon.stub(view, 'showHideClearButton'); + this.mockRouter = sinon.stub(App.router, 'get'); + this.mockRouter.withArgs('mainHostComboSearchBoxController').returns(controller); + this.mockRouter.withArgs('mainHostController.labelValueMap').returns({ + key1: 'hostName' + }); + this.mockIsComp = sinon.stub(controller, 'isComponentStateFacet').returns(false); + sinon.stub(container, 'callback'); + sinon.stub(view, 'searchByHostname'); + sinon.stub(view, 'searchByRack'); + sinon.stub(view, 'searchByVersion'); + sinon.stub(view, 'searchByVersionState'); + sinon.stub(view, 'searchByHealthClass'); + sinon.stub(view, 'searchByServices'); + sinon.stub(view, 'searchByComponentState'); + }); + + afterEach(function() { + view.showHideClearButton.restore(); + this.mockRouter.restore(); + this.mockIsComp.restore(); + container.callback.restore(); + view.searchByHostname.restore(); + view.searchByRack.restore(); + view.searchByVersion.restore(); + view.searchByVersionState.restore(); + view.searchByHealthClass.restore(); + view.searchByServices.restore(); + view.searchByComponentState.restore(); + }); + + it("showHideClearButton should be called", function() { + view.valueMatches('', '', container.callback); + expect(view.showHideClearButton.calledOnce).to.be.true; + }); + + it("searchByHostname should be called", function() { + view.valueMatches('key1', 'term1', container.callback); + expect(view.searchByHostname.calledWith( + 'hostName', 'term1', 'key1', container.callback + )).to.be.true; + }); + + it("searchByRack should be called", function() { + view.valueMatches('rack', 'term1', container.callback); + expect(view.searchByRack.calledWith('rack', container.callback)).to.be.true; + }); + + it("searchByVersion should be called", function() { + view.valueMatches('version', 'term1', container.callback); + expect(view.searchByVersion.calledWith('version', container.callback)).to.be.true; + }); + + it("searchByVersionState should be called", function() { + view.valueMatches('versionState', 'term1', container.callback); + expect(view.searchByVersionState.calledWith('versionState', container.callback, { + key1: 'hostName' + })).to.be.true; + }); + + it("searchByHealthClass should be called", function() { + view.valueMatches('healthClass', 'term1', container.callback); + expect(view.searchByHealthClass.calledWith('healthClass', container.callback, { + key1: 'hostName' + })).to.be.true; + }); + + it("searchByServices should be called", function() { + view.valueMatches('services', 'term1', container.callback); + expect(view.searchByServices.calledWith('services', container.callback)).to.be.true; + }); + + it("searchByComponentState should be called", function() { + this.mockIsComp.returns(true); + view.valueMatches('componentState', 'term1', container.callback); + expect(view.searchByComponentState.calledWith('componentState', container.callback, { + key1: 'hostName' + })).to.be.true; + }); + }); + + describe("#searchByHostname()", function () { + var controller = Em.Object.create({ + getPropertySuggestions: Em.K, + currentSuggestion: ['sg1', 'sg2'] + }); + var container = { + callback: Em.K + }; + + + beforeEach(function() { + sinon.stub(App.router, 'get').returns(controller); + sinon.stub(controller, 'getPropertySuggestions').returns({ + done: function(callback) { + callback(); + } + }); + sinon.stub(container, 'callback'); + sinon.stub(visualSearch.searchQuery, 'values').returns(['sg1']); + }); + + afterEach(function() { + App.router.get.restore(); + controller.getPropertySuggestions.restore(); + container.callback.restore(); + visualSearch.searchQuery.values.restore(); + }); + + it("callback should be called", function() { + view.searchByHostname('fv1', 'term1', 'f1', container.callback); + expect(container.callback.calledWith(['sg2'], {preserveMatches: true})).to.be.true; + }); + }); + + describe("#searchByRack()", function () { + var container = { + callback: Em.K + }; + + beforeEach(function() { + sinon.stub(container, 'callback'); + sinon.stub(visualSearch.searchQuery, 'values').returns(['r1']); + sinon.stub(App.Host, 'find').returns([{rack: 'r1'}, {rack: 'r2'}]); + }); + + afterEach(function() { + container.callback.restore(); + visualSearch.searchQuery.values.restore(); + App.Host.find.restore(); + }); + + it("callback should be called", function() { + view.searchByRack('f1', container.callback); + expect(container.callback.calledWith(['r2'])).to.be.true; + }); + }); + + describe("#searchByVersion()", function () { + var container = { + callback: Em.K + }; + + beforeEach(function() { + sinon.stub(container, 'callback'); + sinon.stub(visualSearch.searchQuery, 'values').returns(['v1']); + sinon.stub(App.HostStackVersion, 'find').returns([ + { + isVisible: true, + displayName: 'v1' + }, + { + isVisible: true, + displayName: 'v2' + }, + { + isVisible: false, + displayName: 'v3' + } + ]); + }); + + afterEach(function() { + container.callback.restore(); + visualSearch.searchQuery.values.restore(); + App.HostStackVersion.find.restore(); + }); + + it("callback should be called", function() { + view.searchByVersion('f1', container.callback); + expect(container.callback.calledWith(['v2'])).to.be.true; + }); + }); + + describe("#searchByVersionState()", function () { + var container = { + callback: Em.K + }; + + beforeEach(function() { + sinon.stub(container, 'callback'); + sinon.stub(visualSearch.searchQuery, 'values').returns(['INSTALLED']); + sinon.stub(App.HostStackVersion, 'formatStatus', function(status) { + return status; + }); + }); + + afterEach(function() { + container.callback.restore(); + visualSearch.searchQuery.values.restore(); + App.HostStackVersion.formatStatus.restore(); + }); + + it("callback should be called", function() { + view.searchByVersionState('f1', container.callback, {}); + expect(container.callback.getCall(0).args[0]).to.be.eql([ + "INSTALLING", + "INSTALL_FAILED", + "OUT_OF_SYNC", + "CURRENT", + "UPGRADING", + "UPGRADE_FAILED" + ]); + }); + }); + + describe("#searchByHealthClass()", function () { + var container = { + callback: Em.K + }; + + beforeEach(function() { + sinon.stub(container, 'callback'); + sinon.stub(visualSearch.searchQuery, 'values').returns(['c1']); + view.set('healthStatusCategories', [ + {value: 'All'}, + {value: 'c1'}, + {value: 'c2'} + ]); + }); + + afterEach(function() { + container.callback.restore(); + visualSearch.searchQuery.values.restore(); + }); + + it("callback should be called", function() { + view.searchByHealthClass('f1', container.callback, {}); + expect(container.callback.getCall(0).args).to.be.eql([ + ['c2'], {preserveOrder: true} + ]); + }); + }); + + describe("#searchByServices()", function () { + var container = { + callback: Em.K + }; + + beforeEach(function() { + sinon.stub(container, 'callback'); + sinon.stub(visualSearch.searchQuery, 'values').returns(['s1']); + sinon.stub(App.Service, 'find').returns([ + Em.Object.create({serviceName: 'S1'}), + Em.Object.create({serviceName: 'S2'}) + ]); + }); + + afterEach(function() { + container.callback.restore(); + visualSearch.searchQuery.values.restore(); + App.Service.find.restore(); + }); + + it("callback should be called", function() { + view.searchByServices('f1', container.callback); + expect(container.callback.getCall(0).args).to.be.eql([ + ['S2'], {preserveOrder: true} + ]); + }); + }); + + + describe("#searchByComponentState()", function () { + var container = { + callback: Em.K + }; + + beforeEach(function() { + sinon.stub(container, 'callback'); + this.mock = sinon.stub(view, 'getComponentStateFacets').returns(['cf1']); + sinon.stub(App.HostComponentStatus, 'getStatusesList').returns([ + 'UPGRADE_FAILED', 'ST1' + ]); + sinon.stub(App.HostComponentStatus, 'getTextStatus', function(status) { + return status; + }); + }); + + afterEach(function() { + container.callback.restore(); + this.mock.restore(); + App.HostComponentStatus.getStatusesList.restore(); + App.HostComponentStatus.getTextStatus.restore(); + }); + + it("callback should be called, client", function() { + view.searchByComponentState('client', container.callback, {}); + expect(container.callback.getCall(0).args).to.be.eql([ + ['All'], {preserveOrder: true} + ]); + }); + + it("callback should be called", function() { + view.searchByComponentState('f1', container.callback, {}); + expect(container.callback.getCall(0).args).to.be.eql([ + ['All'], {preserveOrder: true} + ]); + }); + + it("callback should be called, empty state facets", function() { + this.mock.returns([]); + view.searchByComponentState('f1', container.callback, {}); + expect(container.callback.getCall(0).args).to.be.eql([ + [ + "All", + "ST1", + "Inservice", + "Decommissioned", + "Decommissioning", + "RS Decommissioned", + "Maintenance Mode On", + "Maintenance Mode Off" + ], {preserveOrder: true} + ]); + }); + }); + + describe("#findInvalidFacet()", function () { + + beforeEach(function() { + sinon.stub(App.router, 'get').returns({}); + }); + + afterEach(function() { + App.router.get.restore(); + }); + + it("empty searchCollection", function() { + expect(view.findInvalidFacet({models: []})).to.be.null; + }); + + it("searchCollection has values", function() { + expect(view.findInvalidFacet({models: [{ + attributes: { + category: 'cat1' + } + }]})).to.be.eql({ + attributes: { + category: 'cat1' + } + }); + }); + }); + + describe("#showErrMsg()", function () { + + it("errMsg should be set", function() { + view.showErrMsg({attributes: {value: 'val1'}}); + expect(view.get('errMsg')).to.be.equal('val1 ' + Em.I18n.t('hosts.combo.search.invalidCategory')); + }); + }); + + describe("#clearErrMsg()", function () { + + it("errMsg should be empty", function() { + view.clearErrMsg(); + expect(view.get('errMsg')).to.be.empty; + }); + }); + + describe("#showHideClearButton()", function () { + var container = { + removeClass: Em.K, + addClass: Em.K + }; + + beforeEach(function() { + sinon.stub(window, '$').returns(container); + sinon.spy(container, 'removeClass'); + sinon.spy(container, 'addClass'); + this.mock = sinon.stub(visualSearch.searchQuery, 'toJSON'); + }); + + afterEach(function() { + window.$.restore(); + container.removeClass.restore(); + container.addClass.restore(); + visualSearch.searchQuery.toJSON.restore(); + }); + + it("class should be added", function() { + this.mock.returns([]); + view.showHideClearButton(); + expect(container.addClass.calledWith('hide')).to.be.true; + }); + + it("class should be removed", function() { + this.mock.returns(['f']); + view.showHideClearButton(); + expect(container.removeClass.calledWith('hide')).to.be.true; + }); + }); + + describe("#restoreComboFilterQuery()", function () { + + beforeEach(function() { + this.mockQuery = sinon.stub(App.db, 'getComboSearchQuery'); + sinon.stub(visualSearch.searchBox, 'setQuery'); + }); + + afterEach(function() { + this.mockQuery.restore(); + visualSearch.searchBox.setQuery.restore(); + }); + + it("query is empty", function() { + this.mockQuery.returns(''); + view.restoreComboFilterQuery(); + expect(visualSearch.searchBox.setQuery.called).to.be.false; + }); + + it("query has value", function() { + this.mockQuery.returns('query'); + view.restoreComboFilterQuery(); + expect(visualSearch.searchBox.setQuery.calledWith('query')).to.be.true; + }); + }); + + describe("#getHostComponentList()", function () { + var labelValueMap = {}; + + beforeEach(function() { + sinon.stub(App.MasterComponent, 'find').returns([ + Em.Object.create({totalCount: 0}), + Em.Object.create({totalCount: 1}), + Em.Object.create({totalCount: 1, displayName: 'mc1', componentName: 'MC1'}) + ]); + sinon.stub(App.SlaveComponent, 'find').returns([ + Em.Object.create({totalCount: 0}), + Em.Object.create({totalCount: 1}), + Em.Object.create({totalCount: 1, displayName: 'sc1', componentName: 'SC1'}) + ]); + sinon.stub(App.ClientComponent, 'find').returns([ + Em.Object.create({totalCount: 0}), + Em.Object.create({totalCount: 1}), + Em.Object.create({totalCount: 1, displayName: 'cc1', componentName: 'CC1'}) + ]); + sinon.stub(App.router, 'get').returns(labelValueMap); + }); + + afterEach(function() { + App.MasterComponent.find.restore(); + App.SlaveComponent.find.restore(); + App.ClientComponent.find.restore(); + App.router.get.restore(); + }); + + it("should return host-component list", function() { + expect(view.getHostComponentList()).to.be.eql([ + {label: 'mc1', category: 'Component'}, + {label: 'sc1', category: 'Component'}, + {label: 'cc1', category: 'Component'} + ]); + expect(labelValueMap).to.be.eql({ + mc1: 'MC1', + sc1: 'SC1', + cc1: 'CC1' + }); + }); + }); + + describe("#getComponentStateFacets()", function () { + + beforeEach(function() { + sinon.stub(visualSearch.searchQuery, 'toJSON').returns([ + {category: 'cat1', value: 'val'}, + {category: 'cat2', value: null}, + {category: 'cat3', value: 'All'} + ]); + sinon.stub(view, 'getHostComponentList').returns([{label: ''}]); + }); + + afterEach(function() { + visualSearch.searchQuery.toJSON.restore(); + view.getHostComponentList.restore(); + }); + + it("label='', includeAllValue=true", function() { + expect(view.getComponentStateFacets(null, true)).to.be.empty; + }); + + it("label=cat2, includeAllValue=true", function() { + expect(view.getComponentStateFacets([{label: 'cat2'}], true)).to.be.empty; + }); + + it("label=cat1, includeAllValue=true", function() { + expect(view.getComponentStateFacets([{label: 'cat1'}], true)).to.be.eql([ + {category: 'cat1', value: 'val'} + ]); + }); + + it("label=cat1, includeAllValue=false", function() { + expect(view.getComponentStateFacets([{label: 'cat1'}], false)).to.be.eql([ + {category: 'cat1', value: 'val'} + ]); + }); + + it("label=cat3, includeAllValue=false", function() { + expect(view.getComponentStateFacets([{label: 'cat3'}], false)).to.be.empty; + }); + }); + + describe("#getFacetsByName()", function () { + + beforeEach(function() { + sinon.stub(visualSearch.searchQuery, 'toJSON').returns([ + {category: 'f1'}, + {category: 'f2'} + ]); + }); + + afterEach(function() { + visualSearch.searchQuery.toJSON.restore(); + }); + + it("should return facets", function() { + expect(view.getFacetsByName('f1')).to.be.eql([{category: 'f1'}]); + }); + }); + + describe("#filterOutOneFacetOnlyOptions()", function () { + + beforeEach(function() { + this.mock = sinon.stub(view, 'getFacetsByName'); + }); + + afterEach(function() { + view.getFacetsByName.restore(); + }); + + it("should return empty, no facets", function() { + this.mock.returns([]); + expect(view.filterOutOneFacetOnlyOptions([])).to.be.empty; + }); + + it("should return empty", function() { + this.mock.returns([{}]); + expect(view.filterOutOneFacetOnlyOptions([{label: 'Cores'}])).to.be.empty; + }); + + it("should return options", function() { + this.mock.returns([{}]); + expect(view.filterOutOneFacetOnlyOptions([{label: 'f1'}])).to.be.eql([{label: 'f1'}]); + }); + }); + + describe("#setupLabelMap()", function () { + var map = { + 'init': 'init' + }; + + beforeEach(function() { + sinon.stub(App.router, 'get').returns(map); + }); + + afterEach(function() { + App.router.get.restore(); + }); + + it("should set map", function() { + view.setupLabelMap(); + expect(map).to.be.eql({ + 'init': 'init', + 'All': 'ALL', + 'Host Name': 'hostName', + 'IP': 'ip', + 'Host Status': 'healthClass', + 'Cores': 'cpu', + 'RAM': 'memoryFormatted', + 'Stack Version': 'version', + 'Version State': 'versionState', + 'Rack': 'rack', + 'Service': 'services', + 'Inservice': 'INSERVICE', + 'Decommissioned': 'DECOMMISSIONED', + 'Decommissioning': 'DECOMMISSIONING', + 'RS Decommissioned': 'RS_DECOMMISSIONED', + 'Maintenance Mode On': 'ON', + 'Maintenance Mode Off': 'OFF' + }); + }); + }); + + describe("#createFilterConditions()", function () { + + beforeEach(function() { + sinon.stub(view, 'getFilterColumn').returns(1); + sinon.stub(view, 'getFilterValue').returns('filterValue'); + sinon.stub(App.router, 'get').returns({'k1': 'services'}); + sinon.stub(view, 'createCondition').returns({ + skipFilter: false, + iColumn: 1, + value: 'val1', + type: 't1' + }); + view.set('serviceMap', {k2: 'val2'}); + }); + + afterEach(function() { + view.getFilterColumn.restore(); + view.getFilterValue.restore(); + App.router.get.restore(); + view.createCondition.restore(); + }); + + it("empty models", function() { + var searchCollection = { + models: [] + }; + expect(view.createFilterConditions(searchCollection)).to.be.empty; + }); + + it("should return conditions, string value", function() { + var searchCollection = { + models: [ + { + attributes: { + category: 'k1', + value: 'k2' + } + }, + { + attributes: { + category: 'k1', + value: 'k2' + } + } + ] + }; + expect(JSON.stringify(view.createFilterConditions(searchCollection))).to.be.equal(JSON.stringify([ + { + "skipFilter": false, + "iColumn": 1, + "value": [ + "val1", + "filterValue" + ], + "type": "t1" + } + ])); + }); + + + it("should return conditions, array value", function() { + var searchCollection = { + models: [ + { + attributes: { + category: 'cat1', + value: ['val1'] + } + }, + { + attributes: { + category: 'cat2', + value: 'val2' + } + } + ] + }; + expect(JSON.stringify(view.createFilterConditions(searchCollection))).to.be.equal(JSON.stringify([ + { + "skipFilter": false, + "iColumn": 1, + "value": [ + "val1", + "filterValue" + ], + "type": "t1" + } + ])); + }); + }); + + describe("#createCondition()", function () { + var testCases = [ + { + category: 'cpu', + iColumn: 1, + filterValue: 'val1', + expected: { + skipFilter: false, + iColumn: 1, + value: 'val1', + type: 'number' + } + }, + { + category: 'memoryFormatted', + iColumn: 2, + filterValue: 'val2', + expected: { + skipFilter: false, + iColumn: 2, + value: 'val2', + type: 'ambari-bandwidth' + } + }, + { + category: 'cat1', + iColumn: 3, + filterValue: ['val2'], + expected: { + skipFilter: false, + iColumn: 3, + value: ['val2'], + type: 'string' + } + } + ]; + + testCases.forEach(function(test) { + it("category = " + test.category + + " iColumn = " + test.iColumn + + " filterValue = " + test.filterValue, function() { + expect(view.createCondition(test.category, test.iColumn, test.filterValue)).to.be.eql(test.expected); + }); + }); + }); + + describe("#getFilterColumn()", function () { + + beforeEach(function() { + this.mockComponentState = sinon.stub(view.get('controller'), 'isComponentStateFacet'); + this.mockComplexHealth = sinon.stub(view.get('controller'), 'isComplexHealthStatusFacet'); + sinon.stub(App.router, 'get').returns(['componentState', 'cat1']); + view.set('healthStatusCategories', [{healthStatus: 'val1', column: 2}]); + }); + + afterEach(function() { + this.mockComponentState.restore(); + this.mockComplexHealth.restore(); + App.router.get.restore(); + }); + + it("should return componentState column", function() { + this.mockComponentState.returns(true); + expect(view.getFilterColumn('cat1', 'val1')).to.be.equal(0); + }); + + it("should return healthStatus column", function() { + this.mockComplexHealth.returns(true); + expect(view.getFilterColumn('cat1', 'val1')).to.be.equal(2); + }); + + it("should return custom column", function() { + expect(view.getFilterColumn('cat1', 'val1')).to.be.equal(1); + }); + }); + + describe("#getFilterValue()", function () { + + beforeEach(function() { + this.mockComponentState = sinon.stub(view.get('controller'), 'isComponentStateFacet'); + this.mockComplexHealth = sinon.stub(view.get('controller'), 'isComplexHealthStatusFacet'); + view.set('healthStatusCategories', [{healthStatus: 'val1', filterValue: 'filterValue'}]); + }); + + afterEach(function() { + this.mockComponentState.restore(); + this.mockComplexHealth.restore(); + }); + + it("should return componentState filter value", function() { + this.mockComponentState.returns(true); + expect(view.getFilterValue('cat1', 'val1')).to.be.equal('cat1:val1'); + }); + + it("should return health filter value", function() { + this.mockComplexHealth.returns(true); + expect(view.getFilterValue('cat1', 'val1')).to.be.equal('filterValue'); + }); + + it("should return other filter value", function() { + expect(view.getFilterValue('cat1', 'val1')).to.be.equal('val1'); + }); }); }); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/2ad42074/ambari-web/test/views/main/host/host_alerts_view_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/views/main/host/host_alerts_view_test.js b/ambari-web/test/views/main/host/host_alerts_view_test.js index 38af1bd..2c0d59a 100644 --- a/ambari-web/test/views/main/host/host_alerts_view_test.js +++ b/ambari-web/test/views/main/host/host_alerts_view_test.js @@ -132,26 +132,43 @@ describe('App.MainHostAlertsView', function () { sinon.stub(App.db, 'getSortingStatuses').returns([ { name: "state", - status: "sorting_asc" + status: "sorting" } ]); + sinon.stub(App.db, 'setSortingStatuses'); }); afterEach(function() { mock.loadAlertInstancesByHost.restore(); App.router.get.restore(); App.router.set.restore(); App.db.getSortingStatuses.restore(); + App.db.setSortingStatuses.restore(); }); it("loadAlertInstancesByHost should be called", function() { view.willInsertElement(); - expect(App.router.set.calledWith('mainAlertInstancesController.isUpdating', true)).to.be.true; + expect(mock.loadAlertInstancesByHost.calledWith('host1')).to.be.true; }); - it("App.router.set should be called", function() { + it("isUpdating should be true", function() { view.willInsertElement(); expect(App.router.set.calledWith('mainAlertInstancesController.isUpdating', true)).to.be.true; }); + + it("App.db.setSortingStatuses should be called", function() { + view.set('controller.name', 'ctrl1'); + view.willInsertElement(); + expect(App.db.setSortingStatuses.calledWith('ctrl1', [ + { + name: "state", + status: "sorting" + }, + { + name: "state", + status: "sorting_asc" + } + ])).to.be.true; + }); }); describe("#didInsertElement()", function() { http://git-wip-us.apache.org/repos/asf/ambari/blob/2ad42074/ambari-web/test/views/main/host/hosts_table_menu_view_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/views/main/host/hosts_table_menu_view_test.js b/ambari-web/test/views/main/host/hosts_table_menu_view_test.js new file mode 100644 index 0000000..0536c8c --- /dev/null +++ b/ambari-web/test/views/main/host/hosts_table_menu_view_test.js @@ -0,0 +1,304 @@ +/** + * 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'); + +describe('App.HostTableMenuView', function() { + var view; + + beforeEach(function() { + view = App.HostTableMenuView.create(); + }); + + describe("#components", function () { + + beforeEach(function() { + sinon.stub(App.Service, 'find').returns([Em.Object.create({serviceName: 'S1'})]); + this.mockMenu = sinon.stub(view, 'getBulkMenuItemsPerServiceComponent'); + }); + + afterEach(function() { + App.Service.find.restore(); + this.mockMenu.restore(); + }); + + it("should return components", function() { + this.mockMenu.returns([ + {serviceName: 'S1'}, + {serviceName: 'S2'} + ]); + view.propertyDidChange('components'); + expect(view.get('components')).to.be.eql([ + {serviceName: 'S1'} + ]); + }); + }); + + describe("#getBulkMenuItemsPerServiceComponent()", function () { + + beforeEach(function() { + sinon.stub(App.StackServiceComponent, 'find').returns([ + Em.Object.create({ + serviceName: 'S1', + componentName: 'C1', + bulkCommandsMasterComponentName: 'm1', + bulkCommandsDisplayName: 'c1', + hasBulkCommandsDefinition: {} + }), + Em.Object.create({ + serviceName: 'S2', + componentName: 'C2', + bulkCommandsMasterComponentName: 'm2', + bulkCommandsDisplayName: 'c2', + hasBulkCommandsDefinition: null + }) + ]); + }); + + afterEach(function() { + App.StackServiceComponent.find.restore(); + }); + + it("should return bulk menu items", function() { + expect(view.getBulkMenuItemsPerServiceComponent()).to.be.eql([ + Em.Object.create({ + serviceName: 'S1', + componentName: 'C1', + masterComponentName: 'm1', + componentNameFormatted: 'c1' + }) + ]); + }); + }); + + describe("#slaveItemView", function () { + var slaveItemView; + + beforeEach(function () { + slaveItemView = view.get('slaveItemView').create(); + }); + + + describe("#commonOperationView", function () { + var commonOperationView; + + beforeEach(function () { + commonOperationView = slaveItemView.get('commonOperationView').create({ + controller: Em.Object.create({ + bulkOperationConfirm: Em.K + }) + }); + }); + + describe("#click()", function () { + + beforeEach(function () { + sinon.spy(commonOperationView.get('controller'), 'bulkOperationConfirm'); + }); + + afterEach(function () { + commonOperationView.get('controller').bulkOperationConfirm.restore(); + }); + + it("bulkOperationConfirm should be called", function () { + commonOperationView.setProperties({ + content: {}, + selection: 'selection' + }); + commonOperationView.click(); + expect(commonOperationView.get('controller').bulkOperationConfirm.calledWith( + {}, 'selection' + )).to.be.true; + }); + }); + }); + + describe("#advancedOperationView", function () { + var advancedOperationView; + + beforeEach(function() { + advancedOperationView = slaveItemView.get('advancedOperationView').create({ + content: Em.Object.create(), + controller: Em.Object.create({ + bulkOperationConfirm: Em.K + }) + }); + }); + + describe("#service", function () { + + beforeEach(function() { + sinon.stub(App.router, 'get').returns([ + {serviceName: 'S1'} + ]); + }); + + afterEach(function() { + App.router.get.restore(); + }); + + it("should return service", function() { + advancedOperationView.set('content.serviceName', 'S1'); + advancedOperationView.propertyDidChange('service'); + expect(advancedOperationView.get('service')).to.be.eql({serviceName: 'S1'}); + }); + }); + + describe("#tooltipMsg", function () { + + it("disabled", function() { + advancedOperationView.reopen({ + disabledElement: 'disabled' + }); + advancedOperationView.set('content.componentName', 'C1'); + advancedOperationView.set('content.message', 'msg'); + expect(advancedOperationView.get('tooltipMsg')).to.be.equal( + Em.I18n.t('hosts.decommission.tooltip.warning').format('msg', 'c1') + ); + }); + + it("not disabled", function() { + advancedOperationView.reopen({ + disabledElement: '' + }); + advancedOperationView.set('content.componentName', 'C1'); + expect(advancedOperationView.get('tooltipMsg')).to.be.empty; + }); + }); + + describe("#disabledElement", function () { + + it("workStatus=STARTED", function() { + advancedOperationView.reopen({ + service: Em.Object.create({ + workStatus: 'STARTED' + }) + }); + advancedOperationView.propertyDidChange('disabledElement'); + expect(advancedOperationView.get('disabledElement')).to.be.empty; + }); + + it("workStatus=INSTALLED", function() { + advancedOperationView.reopen({ + service: Em.Object.create({ + workStatus: 'INSTALLED' + }) + }); + advancedOperationView.propertyDidChange('disabledElement'); + expect(advancedOperationView.get('disabledElement')).to.be.equal('disabled'); + }); + }); + + describe("#click()", function () { + + beforeEach(function () { + sinon.spy(advancedOperationView.get('controller'), 'bulkOperationConfirm'); + }); + + afterEach(function () { + advancedOperationView.get('controller').bulkOperationConfirm.restore(); + }); + + it("bulkOperationConfirm should be called", function () { + advancedOperationView.setProperties({ + content: {}, + selection: 'selection' + }); + advancedOperationView.reopen({ + disabledElement: '' + }); + advancedOperationView.click(); + expect(advancedOperationView.get('controller').bulkOperationConfirm.calledWith( + {}, 'selection' + )).to.be.true; + }); + + it("bulkOperationConfirm should not be called", function () { + advancedOperationView.setProperties({ + content: {}, + selection: 'selection' + }); + advancedOperationView.reopen({ + disabledElement: 'disabled' + }); + advancedOperationView.click(); + expect(advancedOperationView.get('controller').bulkOperationConfirm.called).to.be.false; + }); + }); + + describe("#didInsertElement()", function () { + + beforeEach(function() { + sinon.stub(App, 'tooltip'); + }); + + afterEach(function() { + App.tooltip.restore(); + }); + + it("App.tooltip should be called", function() { + advancedOperationView.didInsertElement(); + expect(App.tooltip.calledOnce).to.be.true; + }); + }); + }); + }); + + describe("#hostItemView", function () { + var hostItemView; + + beforeEach(function () { + hostItemView = view.get('hostItemView').create(); + }); + + describe("#operationView", function () { + var operationView; + + beforeEach(function () { + operationView = hostItemView.get('operationView').create({ + controller: Em.Object.create({ + bulkOperationConfirm: Em.K + }) + }); + }); + + describe("#click()", function () { + + beforeEach(function () { + sinon.spy(operationView.get('controller'), 'bulkOperationConfirm'); + }); + + afterEach(function () { + operationView.get('controller').bulkOperationConfirm.restore(); + }); + + it("bulkOperationConfirm should be called", function () { + operationView.setProperties({ + content: {}, + selection: 'selection' + }); + operationView.click(); + expect(operationView.get('controller').bulkOperationConfirm.calledWith( + {}, 'selection' + )).to.be.true; + }); + }); + }); + }); + +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/2ad42074/ambari-web/test/views/main/host/log_metrics_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/views/main/host/log_metrics_test.js b/ambari-web/test/views/main/host/log_metrics_test.js new file mode 100644 index 0000000..a0a3c6c --- /dev/null +++ b/ambari-web/test/views/main/host/log_metrics_test.js @@ -0,0 +1,116 @@ +/** + * 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 fileUtils = require('utils/file_utils'); + +describe('App.MainHostLogMetrics', function() { + var view; + + beforeEach(function() { + view = App.MainHostLogMetrics.create({ + content: Em.Object.create() + }); + }); + + describe("#logsData", function () { + + it("should return logsData", function() { + view.set('content.hostComponents', [{service: 'S1'}]); + view.propertyDidChange('logsData'); + expect(view.get('logsData').mapProperty('service')).to.be.eql(['S1']); + expect(view.get('logsData')[0].get('logs').mapProperty('level')).to.be.eql([ + 'fatal', 'critical', 'error', 'warning', 'info', 'debug' + ]); + }); + }); + + describe("#chartView", function () { + var chartView; + + beforeEach(function () { + chartView = view.get('chartView').create({ + donut: Em.K + }); + }); + + describe("#prepareChartData()", function () { + + it("data should be set", function () { + chartView.prepareChartData(Em.Object.create({logs: [Em.Object.create()]})); + expect(chartView.get('data')).to.be.eql([Em.Object.create()]); + }); + }); + + describe("#didInsertElement()", function () { + + beforeEach(function() { + sinon.stub(chartView, 'prepareChartData'); + sinon.stub(chartView, 'appendLabels'); + sinon.stub(chartView, 'formatCenterText'); + sinon.stub(chartView, 'attachArcEvents'); + sinon.stub(chartView, 'colorizeArcs'); + chartView.didInsertElement(); + }); + + afterEach(function() { + chartView.prepareChartData.restore(); + chartView.appendLabels.restore(); + chartView.formatCenterText.restore(); + chartView.attachArcEvents.restore(); + chartView.colorizeArcs.restore(); + }); + + it("prepareChartData should be called", function() { + expect(chartView.prepareChartData.calledOnce).to.be.true; + }); + + it("appendLabels should be called", function() { + expect(chartView.appendLabels.calledOnce).to.be.true; + }); + + it("formatCenterText should be called", function() { + expect(chartView.formatCenterText.calledOnce).to.be.true; + }); + + it("attachArcEvents should be called", function() { + expect(chartView.attachArcEvents.calledOnce).to.be.true; + }); + + it("colorizeArcs should be called", function() { + expect(chartView.colorizeArcs.calledOnce).to.be.true; + }); + }); + }); + + describe("#transitionByService()", function () { + + beforeEach(function() { + sinon.stub(App.router, 'transitionTo'); + }); + + afterEach(function() { + App.router.transitionTo.restore() + }); + + it("App.router.transitionTo should be called", function() { + view.transitionByService({context: Em.Object.create({service: {serviceName: 'S1'}})}); + expect(App.router.transitionTo.calledWith('logs', {query: '?service_name=S1'})).to.be.true; + }); + }); +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/2ad42074/ambari-web/test/views/main/host/logs_view_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/views/main/host/logs_view_test.js b/ambari-web/test/views/main/host/logs_view_test.js new file mode 100644 index 0000000..38159df --- /dev/null +++ b/ambari-web/test/views/main/host/logs_view_test.js @@ -0,0 +1,178 @@ +/** + * 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 fileUtils = require('utils/file_utils'); + +describe('App.MainHostLogsView', function() { + var view; + + beforeEach(function() { + view = App.MainHostLogsView.create({ + host: Em.Object.create() + }); + }); + + describe("#hostLogs", function () { + + beforeEach(function() { + sinon.stub(App.HostComponentLog, 'find').returns([Em.Object.create({ + hostName: 'host1', + logFileNames: [] + })]); + }); + + afterEach(function() { + App.HostComponentLog.find.restore(); + }); + + it("should return host logs", function() { + view.set('host.hostName', 'host1'); + view.propertyDidChange('hostLogs'); + expect(view.get('hostLogs')).to.be.eql([Em.Object.create({ + hostName: 'host1', + logFileNames: [] + })]); + }); + }); + + describe("#content", function () { + + beforeEach(function() { + sinon.stub(fileUtils, 'fileNameFromPath').returns('file1'); + }); + + afterEach(function() { + fileUtils.fileNameFromPath.restore(); + }); + + it("should return content", function() { + view.reopen({ + host: Em.Object.create({hostName: 'host1'}), + hostLogs: [Em.Object.create({ + hostComponent: { + service: { + displayName: 's1', + serviceName: 'S1' + }, + componentName: 'C1', + displayName: 'c1' + }, + hostName: 'host1', + name: 'l1', + logFileNames: ['f1', 'f2'] + })] + }); + view.propertyDidChange('content'); + expect(view.get('content')).to.be.eql([Em.Object.create({ + serviceName: 'S1', + serviceDisplayName: 's1', + componentName: 'C1', + componentDisplayName: 'c1', + hostName: 'host1', + logComponentName: 'l1', + fileNamesObject: [ + { + fileName: 'file1', + filePath: 'f1', + linkTail: '?host_name=host1&file_name=f1&component_name=l1' + }, + { + fileName: 'file1', + filePath: 'f2', + linkTail: '?host_name=host1&file_name=f2&component_name=l1' + } + ], + fileNamesFilterValue: 'f1,f2' + })]); + }); + }); + + describe("#logFileRowView", function () { + var logFileRowView; + + beforeEach(function() { + logFileRowView = view.get('logFileRowView').create() + }); + + describe("#didInsertElement()", function () { + + beforeEach(function() { + sinon.stub(App, 'tooltip'); + }); + + afterEach(function() { + App.tooltip.restore(); + }); + + it("App.tooltip should be called", function() { + logFileRowView.didInsertElement(); + expect(App.tooltip.calledOnce).to.be.true; + }); + }); + + describe("#willDestroyElement()", function () { + var mock = { + tooltip: Em.K + }; + + beforeEach(function() { + sinon.stub(logFileRowView, '$').returns(mock); + sinon.spy(mock, 'tooltip'); + }); + + afterEach(function() { + logFileRowView.$.restore(); + mock.tooltip.restore(); + }); + + it("tooltip should be destroyed", function() { + logFileRowView.willDestroyElement(); + expect(mock.tooltip.calledWith('destroy')).to.be.true; + }); + }); + }); + + describe("#openLogFile()", function () { + + beforeEach(function() { + sinon.stub(App, 'showLogTailPopup'); + }); + + afterEach(function() { + App.showLogTailPopup.restore(); + }); + + it("contexts is empty", function() { + view.openLogFile({contexts: []}); + expect(App.showLogTailPopup.called).to.be.false; + }); + + it("App.showLogTailPopup should be called", function() { + view.openLogFile({contexts: [Em.Object.create({ + logComponentName: 'lc1', + hostName: 'host1' + }), 'f1']}); + expect(App.showLogTailPopup.calledWith(Em.Object.create({ + logComponentName: 'lc1', + hostName: 'host1', + filePath: 'f1' + }))).to.be.true; + }); + }); +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/2ad42074/ambari-web/test/views/main/host/stack_versions_view_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/views/main/host/stack_versions_view_test.js b/ambari-web/test/views/main/host/stack_versions_view_test.js index 0d1d6ff..c92c404 100644 --- a/ambari-web/test/views/main/host/stack_versions_view_test.js +++ b/ambari-web/test/views/main/host/stack_versions_view_test.js @@ -43,4 +43,70 @@ describe('App.MainHostStackVersionsView', function() { expect(view.get('filteredContentInfo')).to.eql(Em.I18n.t('hosts.host.stackVersions.table.filteredInfo').format(1, 2)); }); }); + + describe("#showInstallProgress()", function () { + var mock = { + showProgressPopup: Em.K + }; + + beforeEach(function() { + sinon.stub(App.router, 'get').returns(mock); + sinon.stub(mock, 'showProgressPopup'); + }); + + afterEach(function() { + App.router.get.restore(); + mock.showProgressPopup.restore(); + }); + + it("showProgressPopup should be called", function() { + view.showInstallProgress({context: {}}); + expect(mock.showProgressPopup.calledWith({})).to.be.true; + }); + }); + + describe("#outOfSyncInfo", function () { + var outOfSyncInfo; + + beforeEach(function() { + outOfSyncInfo = view.get('outOfSyncInfo').create() + }); + + describe("#didInsertElement()", function () { + + beforeEach(function() { + sinon.stub(App, 'tooltip'); + }); + + afterEach(function() { + App.tooltip.restore(); + }); + + it("App.tooltip should be called", function() { + outOfSyncInfo.didInsertElement(); + expect(App.tooltip.calledOnce).to.be.true; + }); + }); + + describe("#willDestroyElement()", function () { + var mock = { + tooltip: Em.K + }; + + beforeEach(function() { + sinon.stub(window, '$').returns(mock); + sinon.spy(mock, 'tooltip'); + }); + + afterEach(function() { + window.$.restore(); + mock.tooltip.restore(); + }); + + it("tooltip should be destroyed", function() { + outOfSyncInfo.willDestroyElement(); + expect(mock.tooltip.calledWith('destroy')).to.be.true; + }); + }); + }); }); http://git-wip-us.apache.org/repos/asf/ambari/blob/2ad42074/ambari-web/test/views/main/host/summary_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/views/main/host/summary_test.js b/ambari-web/test/views/main/host/summary_test.js index 31b6d94..f1c9d06 100644 --- a/ambari-web/test/views/main/host/summary_test.js +++ b/ambari-web/test/views/main/host/summary_test.js @@ -694,4 +694,95 @@ describe('App.MainHostSummaryView', function() { expect(mainHostSummaryView.get('controller.installClients').calledWith([1,2,3])).to.be.true; }); }); + + describe("#timeSinceHeartBeat", function () { + + beforeEach(function() { + sinon.stub($, 'timeago').returns('1'); + }); + + afterEach(function() { + $.timeago.restore(); + }); + + it("rawLastHeartBeatTime = null", function() { + mainHostSummaryView.set('content.rawLastHeartBeatTime', null); + mainHostSummaryView.propertyDidChange('timeSinceHeartBeat'); + expect(mainHostSummaryView.get('timeSinceHeartBeat')).to.be.empty; + }); + + it("rawLastHeartBeatTime = 1", function() { + mainHostSummaryView.set('content.rawLastHeartBeatTime', '1'); + mainHostSummaryView.propertyDidChange('timeSinceHeartBeat'); + expect(mainHostSummaryView.get('timeSinceHeartBeat')).to.be.equal('1'); + }); + }); + + describe("#clientsWithCustomCommands", function () { + + beforeEach(function() { + this.mockComponents = sinon.stub(App.StackServiceComponent, 'find'); + }); + + afterEach(function() { + this.mockComponents.restore(); + }); + + var testCases = [ + { + component: Em.Object.create(), + clients: [], + expected: [] + }, + { + component: Em.Object.create(), + clients: [ + Em.Object.create({componentName: 'KERBEROS_CLIENT'}) + ], + expected: [] + }, + { + component: Em.Object.create({customCommands: []}), + clients: [ + Em.Object.create({componentName: 'C1'}) + ], + expected: [] + }, + { + component: Em.Object.create({customCommands: ['cmd1']}), + clients: [ + Em.Object.create({ + hostName: 'host1', + displayName: 'dn1', + componentName: 'C1', + service: Em.Object.create({serviceName: 'S1'}) + }) + ], + expected: [{ + label: 'dn1', + commands: [ + { + label: Em.I18n.t('services.service.actions.run.executeCustomCommand.menu').format('cmd1'), + service: "S1", + hosts: 'host1', + component: 'C1', + command: 'cmd1' + } + ] + }] + } + ]; + + testCases.forEach(function(test) { + it("component = " + JSON.stringify(test.component) + + " clients = " + JSON.stringify(test.clients), function() { + this.mockComponents.returns(test.component); + mainHostSummaryView.reopen({ + clients: test.clients + }); + mainHostSummaryView.propertyDidChange('clientsWithCustomCommands'); + expect(mainHostSummaryView.get('clientsWithCustomCommands')).to.be.eql(test.expected); + }); + }); + }); });
