Repository: ambari Updated Branches: refs/heads/trunk ba99a2944 -> 67d17f060
AMBARI-19445. Add macros `existsInByKey` and `notExistsInByKey` (onechiporenko) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/67d17f06 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/67d17f06 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/67d17f06 Branch: refs/heads/trunk Commit: 67d17f060e87530b1ad7ffe47bee9eba8ce43652 Parents: ba99a29 Author: Oleg Nechiporenko <onechipore...@apache.org> Authored: Tue Jan 10 15:32:49 2017 +0200 Committer: Oleg Nechiporenko <onechipore...@apache.org> Committed: Tue Jan 10 16:38:12 2017 +0200 ---------------------------------------------------------------------- ambari-web/app/utils/ember_computed.js | 52 ++++++++++++++ .../main/alerts/definition_details_view.js | 4 +- .../main/host/details/host_component_view.js | 12 +--- ambari-web/app/views/main/service/menu.js | 4 +- .../test/aliases/computed/existsInByKey.js | 59 ++++++++++++++++ .../test/aliases/computed/notExistsInByKey.js | 59 ++++++++++++++++ ambari-web/test/app_test.js | 8 ++- ambari-web/test/init_computed_aliases.js | 2 + ambari-web/test/utils/ember_computed_test.js | 72 ++++++++++++++++++++ .../main/alerts/definition_details_view_test.js | 32 +-------- .../host/details/host_component_view_test.js | 40 ++--------- ambari-web/test/views/main/service/menu_test.js | 15 ++++ 12 files changed, 274 insertions(+), 85 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/67d17f06/ambari-web/app/utils/ember_computed.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/utils/ember_computed.js b/ambari-web/app/utils/ember_computed.js index e21f4d3..b64d4a9 100644 --- a/ambari-web/app/utils/ember_computed.js +++ b/ambari-web/app/utils/ember_computed.js @@ -966,6 +966,32 @@ computed.existsIn = function (dependentKey, neededValues) { }; /** + * A computed property that returns true if dependent property exists in the property with needed values + * <pre> + * var o = Em.Object.create({ + * p1: 2, + * p2: Em.computed.existsInByKey('p1', 'p3'), + * p3: [1, 2, 3] + * }); + * console.log(o.get('p2')); // true + * o.set('p1', 4); + * console.log(o.get('p2')); // false + * </pre> + * + * @method existsIn + * @param {string} dependentKey + * @param {string} neededValuesKey + * @returns {Ember.ComputedProperty} + */ +computed.existsInByKey = function (dependentKey, neededValuesKey) { + return computed(dependentKey, `${neededValuesKey}.[]`, function () { + var value = smartGet(this, dependentKey); + var neededValues = smartGet(this, neededValuesKey); + return makeArray(neededValues).contains(value); + }); +}; + +/** * A computed property that returns true if dependent property doesn't exist in the needed values * <pre> * var o = Em.Object.create({ @@ -990,6 +1016,32 @@ computed.notExistsIn = function (dependentKey, neededValues) { }; /** + * A computed property that returns true if dependent property doesn't exist in the property with needed values + * <pre> + * var o = Em.Object.create({ + * p1: 2, + * p2: Em.computed.notExistsInByKey('p1', 'p3'), + * p3: [1, 2, 3] + * }); + * console.log(o.get('p2')); // false + * o.set('p1', 4); + * console.log(o.get('p2')); // true + * </pre> + * + * @method notExistsInByKey + * @param {string} dependentKey + * @param {string} neededValuesKey + * @returns {Ember.ComputedProperty} + */ +computed.notExistsInByKey = function (dependentKey, neededValuesKey) { + return computed(dependentKey, `${neededValuesKey}.[]`, function () { + var value = smartGet(this, dependentKey); + var neededValues = smartGet(this, neededValuesKey); + return !makeArray(neededValues).contains(value); + }); +}; + +/** * A computed property that returns result of calculation <code>(dependentProperty1/dependentProperty2 * 100)</code> * If accuracy is 0 (by default), result is rounded to integer * Otherwise - result is float with provided accuracy http://git-wip-us.apache.org/repos/asf/ambari/blob/67d17f06/ambari-web/app/views/main/alerts/definition_details_view.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/main/alerts/definition_details_view.js b/ambari-web/app/views/main/alerts/definition_details_view.js index fc80c89..5c8efff 100644 --- a/ambari-web/app/views/main/alerts/definition_details_view.js +++ b/ambari-web/app/views/main/alerts/definition_details_view.js @@ -326,9 +326,7 @@ App.AlertInstanceServiceHostView = Em.View.extend({ /** * Define whether show link for transition to service page */ - serviceIsLink: function () { - return App.get('services.all').contains(this.get('instance.service.serviceName')); - }.property('instance.service.serviceName'), + serviceIsLink: Em.computed.existsInByKey('instance.service.serviceName', 'App.services.all'), /** * Define whether show separator between service and hosts labels http://git-wip-us.apache.org/repos/asf/ambari/blob/67d17f06/ambari-web/app/views/main/host/details/host_component_view.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/main/host/details/host_component_view.js b/ambari-web/app/views/main/host/details/host_component_view.js index b5ea711..92cf0c6 100644 --- a/ambari-web/app/views/main/host/details/host_component_view.js +++ b/ambari-web/app/views/main/host/details/host_component_view.js @@ -173,9 +173,7 @@ App.HostComponentView = Em.View.extend({ * Shows whether we need to show Delete button * @type {bool} */ - isDeletableComponent: function () { - return App.get('components.deletable').contains(this.get('content.componentName')); - }.property('content'), + isDeletableComponent: Em.computed.existsInByKey('content.componentName', 'App.components.deletable'), /** * Host component with some <code>workStatus</code> can't be moved (so, disable such action in the dropdown list) @@ -230,9 +228,7 @@ App.HostComponentView = Em.View.extend({ * Check if component is restartable * @type {bool} */ - isRestartableComponent: function() { - return App.get('components.restartable').contains(this.get('content.componentName')); - }.property('content'), + isRestartableComponent: Em.computed.existsInByKey('content.componentName', 'App.components.restartable'), /** * Host component with some <code>workStatus</code> can't be restarted (so, disable such action in the dropdown list) @@ -244,9 +240,7 @@ App.HostComponentView = Em.View.extend({ * Check if component configs can be refreshed * @type {bool} */ - isRefreshConfigsAllowed: function() { - return App.get('components.refreshConfigsAllowed').contains(this.get('content.componentName')); - }.property('content'), + isRefreshConfigsAllowed: Em.computed.existsInByKey('content.componentName', 'App.components.refreshConfigsAllowed'), willInsertElement: function() { //make link to view instance to get decommission state http://git-wip-us.apache.org/repos/asf/ambari/blob/67d17f06/ambari-web/app/views/main/service/menu.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/main/service/menu.js b/ambari-web/app/views/main/service/menu.js index 2c9ac5c..aad718d 100644 --- a/ambari-web/app/views/main/service/menu.js +++ b/ambari-web/app/views/main/service/menu.js @@ -75,9 +75,7 @@ App.MainServiceMenuView = Em.CollectionView.extend({ hasCriticalAlerts: Em.computed.alias('content.hasCriticalAlerts'), - isConfigurable: function () { - return !App.get('services.noConfigTypes').contains(this.get('content.serviceName')); - }.property('App.services.noConfigTypes','content.serviceName'), + isConfigurable: Em.computed.notExistsInByKey('content.serviceName', 'App.services.noConfigTypes'), link: function() { var stateName = (['summary','configs'].contains(App.router.get('currentState.name'))) http://git-wip-us.apache.org/repos/asf/ambari/blob/67d17f06/ambari-web/test/aliases/computed/existsInByKey.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/aliases/computed/existsInByKey.js b/ambari-web/test/aliases/computed/existsInByKey.js new file mode 100644 index 0000000..6086c6a --- /dev/null +++ b/ambari-web/test/aliases/computed/existsInByKey.js @@ -0,0 +1,59 @@ +/** + * 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 helpers = App.TestAliases.helpers; + +/** + * + * @param {Em.Object} context + * @param {string} propertyName + * @param {string} dependentKey + * @param {string} neededValuesKey + * @params {array} listOfValues + */ +App.TestAliases.testAsComputedExistsInByKey = function (context, propertyName, dependentKey, neededValuesKey, listOfValues) { + + Ember.assert('`listOfValues` should be an array', Ember.isArray(listOfValues)); + + describe('#' + propertyName + ' as Em.computed.existsInByKey', function () { + + afterEach(function () { + helpers.smartRestoreGet(context); + }); + + it('has valid dependent keys', function () { + expect(Em.meta(context).descs[propertyName]._dependentKeys).to.eql([dependentKey, neededValuesKey + '.[]']); + }); + + listOfValues.forEach(function (neededValue) { + + it('should be `true` if ' + JSON.stringify(dependentKey) + ' is equal to ' + JSON.stringify(neededValue), function () { + var hash = {}; + hash[dependentKey] = neededValue; + hash[neededValuesKey] = listOfValues; + helpers.smartStubGet(context, hash) + .propertyDidChange(context, propertyName); + var value = helpers.smartGet(context, propertyName); + expect(value).to.be.true; + }); + + }); + + }); + +}; \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/67d17f06/ambari-web/test/aliases/computed/notExistsInByKey.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/aliases/computed/notExistsInByKey.js b/ambari-web/test/aliases/computed/notExistsInByKey.js new file mode 100644 index 0000000..6d1b195 --- /dev/null +++ b/ambari-web/test/aliases/computed/notExistsInByKey.js @@ -0,0 +1,59 @@ +/** + * 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 helpers = App.TestAliases.helpers; + +/** + * + * @param {Em.Object} context + * @param {string} propertyName + * @param {string} dependentKey + * @param {string} neededValuesKey + * @params {array} listOfValues + */ +App.TestAliases.testAsComputedNotExistsInByKey = function (context, propertyName, dependentKey, neededValuesKey, listOfValues) { + + Ember.assert('`listOfValues` should be an array', Ember.isArray(listOfValues)); + + describe('#' + propertyName + ' as Em.computed.notExistsInByKey', function () { + + afterEach(function () { + helpers.smartRestoreGet(context); + }); + + it('has valid dependent keys', function () { + expect(Em.meta(context).descs[propertyName]._dependentKeys).to.eql([dependentKey, neededValuesKey + '.[]']); + }); + + listOfValues.forEach(function (neededValue) { + + it('should be `false` if ' + JSON.stringify(dependentKey) + ' is equal to ' + JSON.stringify(neededValue), function () { + var hash = {}; + hash[dependentKey] = neededValue; + hash[neededValuesKey] = listOfValues; + helpers.smartStubGet(context, hash) + .propertyDidChange(context, propertyName); + var value = helpers.smartGet(context, propertyName); + expect(value).to.be.false; + }); + + }); + + }); + +}; \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/67d17f06/ambari-web/test/app_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/app_test.js b/ambari-web/test/app_test.js index 42789d5..c87215f 100644 --- a/ambari-web/test/app_test.js +++ b/ambari-web/test/app_test.js @@ -406,9 +406,11 @@ describe('App', function () { testCases.forEach(function (test) { it(test.key + ' should contain ' + test.result, function () { - expect(App.get('components.' + test.key)).to.eql(test.result); - }) - }) + var key = 'components.' + test.key; + App.components.propertyDidChange(test.key); + expect(App.get(key)).to.eql(test.result); + }); + }); }); describe('#upgradeIsRunning', function () { http://git-wip-us.apache.org/repos/asf/ambari/blob/67d17f06/ambari-web/test/init_computed_aliases.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/init_computed_aliases.js b/ambari-web/test/init_computed_aliases.js index 612d831..477d034 100644 --- a/ambari-web/test/init_computed_aliases.js +++ b/ambari-web/test/init_computed_aliases.js @@ -193,7 +193,9 @@ require('test/aliases/computed/countBasedMessage'); require('test/aliases/computed/firstNotBlank'); require('test/aliases/computed/percents'); require('test/aliases/computed/existsIn'); +require('test/aliases/computed/existsInByKey'); require('test/aliases/computed/notExistsIn'); +require('test/aliases/computed/notExistsInByKey'); require('test/aliases/computed/alias'); require('test/aliases/computed/gte'); require('test/aliases/computed/gt'); http://git-wip-us.apache.org/repos/asf/ambari/blob/67d17f06/ambari-web/test/utils/ember_computed_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/utils/ember_computed_test.js b/ambari-web/test/utils/ember_computed_test.js index e5754f5..a3569b8 100644 --- a/ambari-web/test/utils/ember_computed_test.js +++ b/ambari-web/test/utils/ember_computed_test.js @@ -1235,6 +1235,42 @@ describe('Ember.computed macros', function () { }); + describe('#existsInByKey', function () { + + beforeEach(function () { + this.obj = Em.Object.create({ + prop1: 'v1', + prop2: Em.computed.existsInByKey('prop1', 'prop3'), + prop3: ['v1', 'v2'] + }); + }); + + it('`true` if dependent value is in the array', function () { + expect(this.obj.get('prop2')).to.be.true; + }); + + it('`true` if dependent value is in the array (2)', function () { + this.obj.set('prop1', 'v2'); + expect(this.obj.get('prop2')).to.be.true; + }); + + it('`false` if dependent value is not in the array', function () { + this.obj.set('prop1', 'v3'); + expect(this.obj.get('prop2')).to.be.false; + }); + + it('`false` if dependent value is not in the array (2)', function () { + this.obj.set('prop1', 'v1'); + this.obj.set('prop3', ['v2', 'v3']); + expect(this.obj.get('prop2')).to.be.false; + }); + + it('prop2 dependent keys are valid', function () { + expect(Em.meta(this.obj).descs.prop2._dependentKeys).to.eql(['prop1', 'prop3.[]']); + }); + + }); + describe('#percents', function () { beforeEach(function () { @@ -1492,6 +1528,42 @@ describe('Ember.computed macros', function () { }); + describe('#notExistsInByKey', function () { + + beforeEach(function () { + this.obj = Em.Object.create({ + prop1: 'v1', + prop2: Em.computed.notExistsInByKey('prop1', 'prop3'), + prop3: ['v1', 'v2'] + }); + }); + + it('`false` if dependent value is in the array', function () { + expect(this.obj.get('prop2')).to.be.false; + }); + + it('`false` if dependent value is in the array (2)', function () { + this.obj.set('prop1', 'v2'); + expect(this.obj.get('prop2')).to.be.false; + }); + + it('`true` if dependent value is not in the array', function () { + this.obj.set('prop1', 'v3'); + expect(this.obj.get('prop2')).to.be.true; + }); + + it('`true` if dependent value is not in the array (2)', function () { + this.obj.set('prop1', 'v1'); + this.obj.set('prop3', ['v2', 'v3']); + expect(this.obj.get('prop2')).to.be.true; + }); + + it('prop2 dependent keys are valid', function () { + expect(Em.meta(this.obj).descs.prop2._dependentKeys).to.eql(['prop1', 'prop3.[]']); + }); + + }); + describe('#firstNotBlank', function () { beforeEach(function () { http://git-wip-us.apache.org/repos/asf/ambari/blob/67d17f06/ambari-web/test/views/main/alerts/definition_details_view_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/views/main/alerts/definition_details_view_test.js b/ambari-web/test/views/main/alerts/definition_details_view_test.js index e468968..b3c4712 100644 --- a/ambari-web/test/views/main/alerts/definition_details_view_test.js +++ b/ambari-web/test/views/main/alerts/definition_details_view_test.js @@ -376,38 +376,8 @@ function getInstanceView() { describe('App.AlertInstanceServiceHostView', function () { - var instanceView; - - beforeEach(function() { - instanceView = getInstanceView(); - }); - App.TestAliases.testAsComputedAnd(getInstanceView(), 'showSeparator', ['instance.serviceDisplayName', 'instance.hostName']); - describe("#serviceIsLink", function() { + App.TestAliases.testAsComputedExistsInByKey(getInstanceView(), 'serviceIsLink', 'instance.service.serviceName', 'App.services.all', ['HDFS', 'ZOOKEEPER']); - beforeEach(function() { - sinon.stub(App, 'get').returns(['S1']); - }); - afterEach(function() { - App.get.restore(); - }); - - it("service belongs to all", function() { - instanceView.set('instance', Em.Object.create({ - service: Em.Object.create({ - serviceName: 'S1' - }) - })); - expect(instanceView.get('serviceIsLink')).to.be.true; - }); - it("service does not belong to all", function() { - instanceView.set('instance', Em.Object.create({ - service: Em.Object.create({ - serviceName: 'S2' - }) - })); - expect(instanceView.get('serviceIsLink')).to.be.false; - }); - }); }); http://git-wip-us.apache.org/repos/asf/ambari/blob/67d17f06/ambari-web/test/views/main/host/details/host_component_view_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/views/main/host/details/host_component_view_test.js b/ambari-web/test/views/main/host/details/host_component_view_test.js index 50197bc..f78c71e 100644 --- a/ambari-web/test/views/main/host/details/host_component_view_test.js +++ b/ambari-web/test/views/main/host/details/host_component_view_test.js @@ -384,24 +384,7 @@ describe('App.HostComponentView', function() { }); }); - describe("#isDeletableComponent", function() { - beforeEach(function(){ - sinon.stub(App, 'get').returns(['C1']); - }); - afterEach(function(){ - App.get.restore(); - }); - it("component deletable", function() { - hostComponentView.set('content.componentName', 'C1'); - hostComponentView.propertyDidChange('isDeletableComponent'); - expect(hostComponentView.get('isDeletableComponent')).to.be.true; - }); - it("component is not deletable", function() { - hostComponentView.set('content.componentName', 'C2'); - hostComponentView.propertyDidChange('isDeletableComponent'); - expect(hostComponentView.get('isDeletableComponent')).to.be.false; - }); - }); + App.TestAliases.testAsComputedExistsInByKey(getView(), 'isDeletableComponent', 'content.componentName', 'App.components.deletable', ['DATANODE', 'HDFS_CLIENT', 'NFS_GATEWAY']) describe("#isMoveComponentDisabled", function() { beforeEach(function(){ @@ -476,24 +459,9 @@ describe('App.HostComponentView', function() { }); }); - describe("#isRestartableComponent", function() { - beforeEach(function(){ - sinon.stub(App, 'get').returns(['C1']); - }); - afterEach(function(){ - App.get.restore(); - }); - it("component deletable", function() { - hostComponentView.set('content.componentName', 'C1'); - hostComponentView.propertyDidChange('isRestartableComponent'); - expect(hostComponentView.get('isRestartableComponent')).to.be.true; - }); - it("component is not deletable", function() { - hostComponentView.set('content.componentName', 'C2'); - hostComponentView.propertyDidChange('isRestartableComponent'); - expect(hostComponentView.get('isRestartableComponent')).to.be.false; - }); - }); + App.TestAliases.testAsComputedExistsInByKey(getView(), 'isRestartableComponent', 'content.componentName', 'App.components.restartable', ['DATANODE', 'JOURNALNODE', 'NAMENODE']); + + App.TestAliases.testAsComputedExistsInByKey(getView(), 'isRefreshConfigsAllowed', 'content.componentName', 'App.components.refreshConfigsAllowed', ['FLUME_HANDLER']); describe("#isRefreshConfigsAllowed", function() { beforeEach(function(){ http://git-wip-us.apache.org/repos/asf/ambari/blob/67d17f06/ambari-web/test/views/main/service/menu_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/views/main/service/menu_test.js b/ambari-web/test/views/main/service/menu_test.js index 15f0c15..275006a 100644 --- a/ambari-web/test/views/main/service/menu_test.js +++ b/ambari-web/test/views/main/service/menu_test.js @@ -19,6 +19,10 @@ var App = require('app'); require('views/main/service/menu'); +function getView() { + return App.MainServiceMenuView.create(); +} + describe('App.MainServiceMenuView', function () { var mainServiceMenuView; @@ -64,4 +68,15 @@ describe('App.MainServiceMenuView', function () { expect(mainServiceMenuView.get('itemViewClass.alertsCount')).to.equal(item.result); }); }); + + describe('#itemViewClass', function () { + + function getItemViewClass() { + return getView().get('itemViewClass').create(); + } + + App.TestAliases.testAsComputedNotExistsInByKey(getItemViewClass(), 'isConfigurable', 'content.serviceName', 'App.services.noConfigTypes', ['HDFS', 'ZOOKEEPER']); + + }); + });