ambari-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From nc...@apache.org
Subject [12/50] ambari git commit: AMBARI-14648 Cover with unit tests recommendations flow 2. (ababiichuk)
Date Fri, 15 Jan 2016 18:52:07 GMT
AMBARI-14648 Cover with unit tests recommendations flow 2. (ababiichuk)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/ac1fbc23
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/ac1fbc23
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/ac1fbc23

Branch: refs/heads/branch-dev-patch-upgrade
Commit: ac1fbc23d2d9d759cf24e61ba7c5fdf0be434ea4
Parents: a717275
Author: ababiichuk <ababiichuk@hortonworks.com>
Authored: Wed Jan 13 16:02:30 2016 +0200
Committer: ababiichuk <ababiichuk@hortonworks.com>
Committed: Wed Jan 13 17:07:37 2016 +0200

----------------------------------------------------------------------
 ambari-web/app/assets/test/tests.js             |   1 +
 .../configs/config_recommendation_parser.js     | 153 ++++---
 ambari-web/app/utils/config.js                  |  25 +-
 .../config_recommendation_parser_test.js        | 458 +++++++++++++++++++
 ambari-web/test/utils/config_test.js            |   2 +-
 5 files changed, 583 insertions(+), 56 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/ac1fbc23/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 031a939..d6b0de8 100644
--- a/ambari-web/app/assets/test/tests.js
+++ b/ambari-web/app/assets/test/tests.js
@@ -137,6 +137,7 @@ var files = [
   'test/mappers/configs/themes_mapper_test',
   'test/mixins/common/configs/enhanced_configs_test',
   'test/mixins/common/configs/config_recommendations_test',
+  'test/mixins/common/configs/config_recommendation_parser_test',
   'test/mixins/common/configs/configs_saver_test',
   'test/mixins/common/configs/toggle_isrequired_test',
   'test/mixins/common/chart/storm_linear_time_test',

http://git-wip-us.apache.org/repos/asf/ambari/blob/ac1fbc23/ambari-web/app/mixins/common/configs/config_recommendation_parser.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins/common/configs/config_recommendation_parser.js b/ambari-web/app/mixins/common/configs/config_recommendation_parser.js
index 800e145..51d0b44 100644
--- a/ambari-web/app/mixins/common/configs/config_recommendation_parser.js
+++ b/ambari-web/app/mixins/common/configs/config_recommendation_parser.js
@@ -37,33 +37,43 @@ App.ConfigRecommendationParser = Em.Mixin.create(App.ConfigRecommendations,
{
 	 */
 	parseRecommendations: function(recommendationObject, configs, parentProperties, configGroup,
 	                               updateCallback, removeCallback, updateBoundariesCallback)
{
+
+    App.assertObject(recommendationObject);
+    App.assertArray(configs);
+    App.assertFunction(updateCallback);
+    App.assertFunction(removeCallback);
+    App.assertFunction(updateBoundariesCallback);
+
 		var propertiesToDelete = [];
 		configs.forEach(function (config) {
 			var name = Em.get(config, 'name'), fileName = Em.get(config, 'filename'),
-				site = App.config.getConfigTagFromFileName(fileName);
-			if (recommendationObject[site]) {
-				var properties = recommendationObject[site].properties,
-					property_attributes = recommendationObject[site].property_attributes;
-				if (properties) {
-					var recommendedValue = App.config.formatValue(properties[name]);
+				recommendations = recommendationObject[App.config.getConfigTagFromFileName(fileName)];
+
+			if (recommendations) {
+
+				if (recommendations.properties) {
+					var recommendedValue = App.config.formatValue(recommendations.properties[name]);
 					if (!Em.isNone(recommendedValue)) {
 						/** update config **/
 						updateCallback(config, recommendedValue, parentProperties, configGroup);
 
-						delete recommendationObject[site].properties[name];
+						delete recommendations.properties[name];
 					}
 				}
-				if (property_attributes) {
-					var propertyAttributes = property_attributes[name];
-					var stackProperty = App.configsCollection.getConfigByName(name, fileName);
-					for (var attr in propertyAttributes) {
-						if (attr == 'delete' && this.allowUpdateProperty(parentProperties, name, fileName))
{
-							propertiesToDelete.push(config);
-						} else if (stackProperty) {
-							/** update config boundaries **/
-							updateBoundariesCallback(stackProperty, attr, propertyAttributes[attr], configGroup);
-						}
-					}
+
+				if (recommendations.property_attributes) {
+					var propertyAttributes = recommendations.property_attributes[name];
+          if (propertyAttributes) {
+            var stackProperty = App.configsCollection.getConfigByName(name, fileName);
+            for (var attr in propertyAttributes) {
+              if (attr == 'delete' && this.allowUpdateProperty(parentProperties,
name, fileName)) {
+                propertiesToDelete.push(config);
+              } else if (stackProperty) {
+                /** update config boundaries **/
+                updateBoundariesCallback(stackProperty, attr, propertyAttributes[attr], configGroup);
+              }
+            }
+          }
 				}
 			}
 		}, this);
@@ -98,6 +108,8 @@ App.ConfigRecommendationParser = Em.Mixin.create(App.ConfigRecommendations,
{
 	 * @param {Object[]} parentProperties
 	 */
 	addByRecommendations: function (recommendationObject, parentProperties) {
+    App.assertObject(recommendationObject);
+
 		for (var site in recommendationObject) {
 			var properties = recommendationObject[site].properties;
 			if (properties && Object.keys(properties).length) {
@@ -105,11 +117,13 @@ App.ConfigRecommendationParser = Em.Mixin.create(App.ConfigRecommendations,
{
 				if (stepConfig) {
 					for (var propertyName in properties) {
 						if (this.allowUpdateProperty(parentProperties, propertyName, site)) {
-							this._addConfigByRecommendation(configs, propertyName, site, properties[propertyName],
parentProperties);
+              configs.pushObject(this._createNewProperty(propertyName, site, stepConfig.get('serviceName'),
properties[propertyName], parentProperties));
 						}
 					}
-					var mergedConfigs = configs.concat(stepConfig.get('configs'));
-					stepConfig.set('configs', mergedConfigs);
+          if (configs.length) {
+            var mergedConfigs = configs.concat(stepConfig.get('configs'));
+            stepConfig.set('configs', mergedConfigs);
+          }
 				}
 			}
 		}
@@ -118,13 +132,15 @@ App.ConfigRecommendationParser = Em.Mixin.create(App.ConfigRecommendations,
{
 	/**
 	 * Update config based on recommendations
 	 *
-	 * @param config
-	 * @param recommendedValue
-	 * @param parentProperties
+	 * @param {recommendation} config
+	 * @param {String} recommendedValue
+	 * @param {String[]} [parentProperties]
+   * @returns {recommendation}
 	 * @protected
 	 */
 	_updateConfigByRecommendation: function (config, recommendedValue, parentProperties) {
-		Em.assert('config should be defined', config);
+    App.assertObject(config);
+
 		Em.set(config, 'recommendedValue', recommendedValue);
 		if (this.allowUpdateProperty(parentProperties, Em.get(config, 'name'), Em.get(config, 'filename')))
{
 			Em.set(config, 'value', recommendedValue);
@@ -133,43 +149,53 @@ App.ConfigRecommendationParser = Em.Mixin.create(App.ConfigRecommendations,
{
 		if (this.updateInitialOnRecommendations(Em.get(config, 'serviceName'))) {
 			Em.set(config, 'initialValue', recommendedValue);
 		}
+    return config;
 	},
 
 	/**
 	 * Add config based on recommendations
 	 *
-	 * @param configs
 	 * @param name
 	 * @param fileName
+   * @param serviceName
 	 * @param recommendedValue
 	 * @param parentProperties
 	 * @protected
 	 */
-	_addConfigByRecommendation: function (configs, name, fileName, recommendedValue, parentProperties)
{
-		fileName = App.config.getOriginalFileName(fileName);
-		var stackConfig = App.configsCollection.getConfigByName(name, fileName),
-			service = App.config.get('serviceByConfigTypeMap')[App.config.getConfigTagFromFileName(fileName)];
-		if (service) {
-			var serviceName = stackConfig ? stackConfig.serviceName : service && service.get('serviceName'),
-				popupProperty = this.getRecommendation(name, fileName),
-				initialValue = popupProperty ? popupProperty.value : null;
-
-			var coreObject = {
-				"value": recommendedValue,
-				"recommendedValue": recommendedValue,
-				"initialValue": this.updateInitialOnRecommendations(serviceName) ? recommendedValue :
initialValue,
-				"savedValue": !this.useInitialValue(serviceName) && !Em.isNone(initialValue)
? initialValue : null
-			};
-			var addedProperty = stackConfig || App.config.createDefaultConfig(name, serviceName, fileName,
false);
-			Em.setProperties(addedProperty, coreObject);
-			var addedPropertyObject = App.ServiceConfigProperty.create(addedProperty);
-			configs.pushObject(addedPropertyObject);
-			addedPropertyObject.validate();
-
-			this.applyRecommendation(name, fileName, "Default",
-				recommendedValue, null, parentProperties);
-		}
-	},
+  _createNewProperty: function (name, fileName, serviceName, recommendedValue, parentProperties)
{
+    App.assertExists(name, 'name');
+    App.assertExists(fileName, 'fileName');
+    App.assertExists(serviceName, 'serviceName');
+
+    var coreObject = this._getCoreProperties(serviceName, recommendedValue, this._getInitialFromRecommendations(name,
fileName)),
+      newConfig = App.config.getDefaultConfig(name, fileName, serviceName, coreObject),
+      addedPropertyObject = App.ServiceConfigProperty.create(newConfig);
+
+    addedPropertyObject.validate();
+
+    this.applyRecommendation(name, fileName, "Default",
+      recommendedValue, null, parentProperties);
+
+    return addedPropertyObject;
+  },
+
+  /**
+   *
+   * @param serviceName
+   * @param recommendedValue
+   * @param initialValue
+   * @returns {{value: *, recommendedValue: *, initialValue: *, savedValue: *}}
+   * @private
+   */
+  _getCoreProperties: function(serviceName, recommendedValue, initialValue) {
+    return {
+      "value": recommendedValue,
+      "recommendedValue": recommendedValue,
+      "initialValue": this.updateInitialOnRecommendations(serviceName) ? recommendedValue
: initialValue,
+      "savedValue": !this.useInitialValue(serviceName) ? initialValue : null
+    }
+  },
+
 
 	/**
 	 * Remove config based on recommendations
@@ -180,7 +206,9 @@ App.ConfigRecommendationParser = Em.Mixin.create(App.ConfigRecommendations,
{
 	 * @protected
 	 */
 	_removeConfigByRecommendation: function (config, configsCollection, parentProperties) {
-		Em.assert('config and configsCollection should be defined', config && configsCollection);
+    App.assertObject(config);
+    App.assertArray(configsCollection);
+
 		configsCollection.removeObject(config);
 
 		this.applyRecommendation(Em.get(config, 'name'), Em.get(config, 'filename'), Em.get(config,
'group.name'),
@@ -196,9 +224,30 @@ App.ConfigRecommendationParser = Em.Mixin.create(App.ConfigRecommendations,
{
 	 * @protected
 	 */
 	_updateBoundaries: function(stackProperty, attr, value) {
+    App.assertObject(stackProperty);
+    if (!Em.get(stackProperty, 'valueAttributes')) {
+      stackProperty.valueAttributes = {};
+    }
 		Em.set(stackProperty.valueAttributes, attr, value);
+    return stackProperty;
 	},
 
+  /**
+   * Get initial config value that was before recommendations was applied
+   *
+   * @param name
+   * @param fileName
+   * @returns {*}
+   * @protected
+   */
+  _getInitialFromRecommendations: function(name, fileName) {
+    try {
+      return this.getRecommendation(name, fileName).initialValue;
+    } catch(e) {
+      return null;
+    }
+  },
+
 	/**
 	 * Get default config value
 	 * <code>savedValue<code> for installed services

http://git-wip-us.apache.org/repos/asf/ambari/blob/ac1fbc23/ambari-web/app/utils/config.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/config.js b/ambari-web/app/utils/config.js
index 263baa2..d18c937 100644
--- a/ambari-web/app/utils/config.js
+++ b/ambari-web/app/utils/config.js
@@ -245,8 +245,7 @@ App.config = Em.Object.create({
       var properties = siteConfig.properties || {};
 
       for (var index in properties) {
-        var advancedConfig = App.configsCollection.getConfigByName(index, siteConfig.type);
-        var serviceConfigObj = advancedConfig || this.createDefaultConfig(index, serviceName,
filename, false);
+        var serviceConfigObj = this.getDefaultConfig(index, serviceName, filename);
         this.restrictSecureProperties(serviceConfigObj);
 
         if (serviceConfigObj.isRequiredByAgent !== false) {
@@ -278,6 +277,26 @@ App.config = Em.Object.create({
   },
 
   /**
+   * Get config from configsCollections or
+   * generate new default config in collection does not contain
+   * such config
+   *
+   * @param name
+   * @param serviceName
+   * @param fileName
+   * @param coreObject
+   * @returns {*|Object}
+   */
+  getDefaultConfig: function(name, serviceName, fileName, coreObject) {
+    var cfg = App.configsCollection.getConfigByName(name, fileName) ||
+      App.config.createDefaultConfig(name, serviceName, fileName, false, coreObject);
+    if (Em.typeOf(coreObject) === 'object') {
+      Em.setProperties(cfg, coreObject);
+    }
+    return cfg;
+  },
+
+  /**
    * This method sets default values for config property
    * These property values has the lowest priority and can be overridden be stack/UI
    * config property but is used when such properties are absent in stack/UI configs
@@ -293,7 +312,7 @@ App.config = Em.Object.create({
       /** core properties **/
       id: this.configId(name, fileName),
       name: name,
-      filename: fileName,
+      filename: this.getOriginalFileName(fileName),
       value: '',
       savedValue: null,
       isFinal: false,

http://git-wip-us.apache.org/repos/asf/ambari/blob/ac1fbc23/ambari-web/test/mixins/common/configs/config_recommendation_parser_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/mixins/common/configs/config_recommendation_parser_test.js b/ambari-web/test/mixins/common/configs/config_recommendation_parser_test.js
new file mode 100644
index 0000000..f406336
--- /dev/null
+++ b/ambari-web/test/mixins/common/configs/config_recommendation_parser_test.js
@@ -0,0 +1,458 @@
+/**
+ * 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.ConfigRecommendationParser', function() {
+  var mixinObject =  Em.Controller.extend(App.ConfigRecommendationParser, {});
+  var instanceObject = mixinObject.create({});
+
+  var recommendationObject = {
+    'fileName1': {
+      'properties': {
+        'p1': 'v1'
+      },
+      'property_attributes': {
+        'p2': {
+          'delete': true
+        },
+        'p3': {
+          'maximum': 100,
+          'minimum': 1
+        }
+      }
+    }
+  };
+  var configs = [
+    Em.Object.create({
+      name: 'p1',
+      filename: 'fileName1'
+    }),
+    Em.Object.create({
+      name: 'p2',
+      filename: 'fileName1'
+    }),
+    Em.Object.create({
+      name: 'p3',
+      filename: 'fileName1'
+    })
+  ];
+
+  beforeEach(function() {
+    instanceObject.set('stepConfigs', []);
+  });
+
+
+  describe('#parseRecommendations', function() {
+
+    describe('#recommendartion parsed', function() {
+      beforeEach(function() {
+        instanceObject.reopen({
+          updateCallback: Em.K,
+          removeCallback: Em.K,
+          updateBoundariesCallback: Em.K
+        });
+
+        sinon.stub(App.configsCollection, 'getConfigByName', function(name, fileName) {
+          return { name: name, filename: fileName };
+        });
+
+        sinon.spy(instanceObject, 'updateCallback');
+        sinon.spy(instanceObject, 'removeCallback');
+        sinon.spy(instanceObject, 'updateBoundariesCallback');
+
+        instanceObject.parseRecommendations(recommendationObject, configs, null, null,
+          instanceObject.updateCallback, instanceObject.removeCallback, instanceObject.updateBoundariesCallback);
+      });
+
+      afterEach(function() {
+        App.configsCollection.getConfigByName.restore();
+
+        instanceObject.updateCallback.restore();
+        instanceObject.removeCallback.restore();
+        instanceObject.updateBoundariesCallback.restore();
+      });
+
+      it('updateCallback', function() {
+        expect(instanceObject.updateCallback.calledWith(configs[0], 'v1', null, null)).to.be.true;
+      });
+
+      it('removeCallback', function() {
+        expect(instanceObject.removeCallback.calledWith(configs[1], configs, null, null)).to.be.true;
+      });
+
+      it('updateBoundariesCallback maximum', function() {
+        expect(instanceObject.updateBoundariesCallback.calledWith({ name: 'p3',  filename:
'fileName1' },
+          'maximum', 100, null)).to.be.true;
+      });
+
+      it('updateBoundariesCallback minimum', function() {
+        expect(instanceObject.updateBoundariesCallback.calledWith({ name: 'p3',  filename:
'fileName1' },
+          'minimum', 1, null)).to.be.true;
+      });
+    });
+
+    it('#recommendation parsing failed', function() {
+      expect(instanceObject.parseRecommendations.bind(instanceObject, null)).to.throw(App.ObjectTypeError);
+    });
+
+    it('#recommendation parsing failed', function() {
+      expect(instanceObject.parseRecommendations.bind(instanceObject, {}, null)).to.throw(App.ArrayTypeError);
+    });
+
+    it('#recommendation parsing failed', function() {
+      expect(instanceObject.parseRecommendations.bind(instanceObject, {}, [Em.Object.create({name:
'cfg1'})])).to.throw(App.FunctionTypeError);
+    });
+  });
+
+  describe('#addByRecommendations', function(){
+    var recommendationObject = {
+      'file-name': {
+        'properties': {
+          'p1': 'v1'
+        }
+      }
+    };
+    var stepConfig = App.ServiceConfig.create({
+      serviceName: 'serviceName1',
+      configs: []
+    });
+    var cases = [
+      {
+        m: 'allowUpdateProperty true',
+        allowUpdateProperty: true
+      },
+      {
+        m: 'allowUpdateProperty false',
+        allowUpdateProperty: false
+      }
+    ];
+    cases.forEach(function (c) {
+      describe('non error case', function() {
+        beforeEach(function() {
+          sinon.stub(App.config, 'getStepConfigForProperty').returns(stepConfig);
+          sinon.stub(instanceObject, 'allowUpdateProperty').returns(c.allowUpdateProperty);
+          sinon.stub(instanceObject, '_createNewProperty').returns(App.ServiceConfigProperty.create({
+            'name': 'p1',
+            'filename': 'file-name'
+          }));
+          instanceObject.addByRecommendations(recommendationObject, []);
+        });
+
+        afterEach(function() {
+          App.config.getStepConfigForProperty.restore();
+          instanceObject.allowUpdateProperty.restore();
+          instanceObject._createNewProperty.restore();
+        });
+
+        if (c.allowUpdateProperty) {
+          it ('adds new property', function() {
+            expect(instanceObject._createNewProperty.calledWith('p1', 'file-name', 'serviceName1',
'v1', [])).to.be.true;
+
+            expect(stepConfig.get('configs.0')).to.eql(App.ServiceConfigProperty.create({
+              'name': 'p1',
+              'filename': 'file-name'
+            }));
+          });
+
+        } else {
+          it('does  not add property error', function() {
+            expect(instanceObject._createNewProperty.called).to.be.false;
+          });
+        }
+      });
+    });
+
+    it('throws error', function() {
+      expect(instanceObject.addByRecommendations.bind(instanceObject, null)).to.throw(App.ObjectTypeError);
+    });
+  });
+
+  describe('#_updateConfigByRecommendation', function() {
+    var cases = [
+      {
+        'allowUpdateProperty': true,
+        'updateInitialOnRecommendations': true,
+        'm': 'allowUpdateProperty and update init on recommendation',
+        'result': {
+          'recommendedValue': 'recommendedValue',
+          'value': 'recommendedValue',
+          'initialValue': 'recommendedValue'
+        }
+      },
+      {
+        'allowUpdateProperty': true,
+        'updateInitialOnRecommendations': false,
+        'm': 'allowUpdateProperty and do not update init on recommendation',
+        'result': {
+          'recommendedValue': 'recommendedValue',
+          'value': 'recommendedValue',
+          'initialValue': null
+        }
+      },
+      {
+        'allowUpdateProperty': false,
+        'updateInitialOnRecommendations': false,
+        'm': 'do not allowUpdateProperty and do not update init on recommendation',
+        'result': {
+          'recommendedValue': 'recommendedValue',
+          'value': null,
+          'initialValue': null
+        }
+      }
+    ];
+
+    cases.forEach(function(c) {
+      describe('update recommendation', function() {
+        beforeEach(function() {
+          sinon.spy(instanceObject, 'applyRecommendation');
+          sinon.stub(instanceObject, 'allowUpdateProperty').returns(c.allowUpdateProperty);
+          sinon.stub(instanceObject, 'updateInitialOnRecommendations').returns(c.updateInitialOnRecommendations);
+        });
+        afterEach(function() {
+          instanceObject.allowUpdateProperty.restore();
+          instanceObject.updateInitialOnRecommendations.restore();
+          instanceObject.applyRecommendation.restore();
+        });
+
+        it(c.m, function() {
+          expect(instanceObject._updateConfigByRecommendation({
+            'recommendedValue': null,
+            'value': null,
+            'initialValue': null
+          }, 'recommendedValue')).to.eql(c.result);
+        });
+
+        if(c.allowUpdateProperty) {
+          it('runs applyRecommendation', function() {
+            instanceObject._updateConfigByRecommendation({}, 'recommendedValue');
+            expect(instanceObject.applyRecommendation.calledOnce).to.be.true;
+          });
+        }
+      });
+    });
+
+    it('throws error for configs', function() {
+      expect(instanceObject._updateConfigByRecommendation.bind(instanceObject, null)).to.throw(App.ObjectTypeError);
+    });
+  });
+
+  describe('#_createNewProperty', function() {
+    beforeEach(function() {
+      sinon.spy(instanceObject, 'applyRecommendation');
+      sinon.stub(instanceObject, '_getCoreProperties').returns({
+        'value': 'recommendedValue',
+        'recommendedValue': 'recommendedValue',
+        'initialValue': 'initialValue',
+        'savedValue': null
+      });
+      sinon.stub(App.config, 'getDefaultConfig', function(name, serviceName, fileName, coreObject)
{
+        coreObject.name = name;
+        coreObject.filename = fileName;
+        coreObject.serviceName = serviceName;
+        return coreObject;
+      });
+    });
+    afterEach(function() {
+      instanceObject.applyRecommendation.restore();
+      instanceObject._getCoreProperties.restore();
+      App.config.getDefaultConfig.restore();
+    });
+    
+    it('adds new config', function() {
+      expect(instanceObject._createNewProperty('name', 'serviceName', 'fileName', 'recommendedValue',
null)).to.eql(App.ServiceConfigProperty.create({
+        'value': 'recommendedValue',
+        'recommendedValue': 'recommendedValue',
+        'initialValue': 'initialValue',
+        'savedValue': null,
+        'name': 'name',
+        'filename': 'fileName',
+        'serviceName': 'serviceName'
+      }));
+
+      expect(instanceObject.applyRecommendation.calledOnce).to.be.true;
+    });
+
+    it('throws error for name/fileName/serviceName', function() {
+      expect(instanceObject._createNewProperty.bind(instanceObject)).to.throw(App.NotNullTypeError);
+      expect(instanceObject._createNewProperty.bind(instanceObject, 'name')).to.throw(App.NotNullTypeError);
+    });
+  });
+
+  describe('#_removeConfigByRecommendation', function() {
+    beforeEach(function() {
+      sinon.spy(instanceObject, 'applyRecommendation');
+    });
+    afterEach(function() {
+      instanceObject.applyRecommendation.restore();
+    });
+    
+    it('removes config', function() {
+      var configCollection = [
+        {'name': 'cfg1'},
+        {'name': 'cfg2'}
+      ];
+      instanceObject._removeConfigByRecommendation(configCollection[0], configCollection);
+      expect(configCollection[0]).to.eql({'name': 'cfg2'});
+      expect(instanceObject.applyRecommendation.calledOnce).to.be.true;
+    });
+
+    it('throws error', function() {
+      expect(instanceObject._removeConfigByRecommendation.bind(instanceObject, null)).to.throw(App.ObjectTypeError);
+    });
+
+    it('throws error', function() {
+      expect(instanceObject._removeConfigByRecommendation.bind(instanceObject, {}, null)).to.throw(App.ArrayTypeError);
+    });
+  });
+
+  describe('#_updateBoundaries', function() {
+    it('sets appropriate attribute', function() {
+      expect(instanceObject._updateBoundaries({}, 'attr1', 'v1')).to.eql({ valueAttributes:
{'attr1': 'v1'}});
+    });
+
+    it('throws error', function() {
+      expect(instanceObject._updateBoundaries.bind(instanceObject, null, 'attr1', 'v1')).to.throw(App.ObjectTypeError);
+    });
+  });
+
+  describe('#_getCoreProperties', function() {
+    var cases = [
+      {
+        'useInitialValue': true,
+        'updateInitialOnRecommendations': true,
+        'm': 'use init and update init on recommendation',
+        'result': {
+          'value': 'recommendedValue',
+          'recommendedValue': 'recommendedValue',
+          'initialValue': 'recommendedValue',
+          'savedValue': null
+        }
+      },
+      {
+        'useInitialValue': true,
+        'updateInitialOnRecommendations': false,
+        'm': 'use init and do not update init on recommendation',
+        'result': {
+          'value': 'recommendedValue',
+          'recommendedValue': 'recommendedValue',
+          'initialValue': 'initValue',
+          'savedValue': null
+        }
+      },
+      {
+        'useInitialValue': false,
+        'updateInitialOnRecommendations': false,
+        'm': 'do not use init and do not update init on recommendation',
+        'result': {
+          'value': 'recommendedValue',
+          'recommendedValue': 'recommendedValue',
+          'initialValue': 'initValue',
+          'savedValue': 'initValue'
+        }
+      }
+    ];
+    cases.forEach(function(c) {
+      describe('get core object for different cases', function() {
+        beforeEach(function() {
+          sinon.stub(instanceObject, 'useInitialValue').returns(c.useInitialValue);
+          sinon.stub(instanceObject, 'updateInitialOnRecommendations').returns(c.updateInitialOnRecommendations);
+        });
+        afterEach(function() {
+          instanceObject.useInitialValue.restore();
+          instanceObject.updateInitialOnRecommendations.restore();
+        });
+        it(c.m, function() {
+          expect(instanceObject._getCoreProperties('serviceName', 'recommendedValue', 'initValue')).to.eql(c.result);
+        })
+      })
+    });
+  });
+
+  describe('#_getInitialFromRecommendations', function() {
+    beforeEach(function() {
+      instanceObject.set('recommendations', [
+        {
+          propertyName: 'p1',
+          propertyFileName: 'f1',
+          configGroup: 'Default',
+          initialValue: 'initValue'
+        }
+      ])
+    });
+
+    it('get init value from recommendations', function() {
+      expect(instanceObject._getInitialFromRecommendations('p1','f1')).to.equal('initValue');
+    });
+
+    it('recommendation does not exist', function() {
+      expect(instanceObject._getInitialFromRecommendations('p2','f2')).to.equal(null);
+    });
+  });
+
+  describe('#_getInitialValue', function() {
+    beforeEach(function() {
+      sinon.stub(instanceObject, 'useInitialValue', function(serviceName) {
+        return serviceName !== 'serviceNameInstalled'
+      })
+    });
+    afterEach(function() {
+      instanceObject.useInitialValue.restore();
+    });
+
+    it('use initialValue', function() {
+      expect(instanceObject._getInitialValue({
+        serviceName: 'serviceNameNotInstalled',
+        initialValue: 'initV',
+        savedValue: 'savedV'
+      })).to.equal('initV');
+    });
+
+    it('use savedValue', function() {
+      expect(instanceObject._getInitialValue({
+        serviceName: 'serviceNameInstalled',
+        initialValue: 'initV',
+        savedValue: 'savedV'
+      })).to.equal('savedV');
+    });
+
+    it('wrong params', function() {
+      expect(instanceObject._getInitialValue()).to.be.null;
+    });
+  });
+
+  describe('#updateInitialOnRecommendations', function() {
+    it('default value for updateInitialOnRecommendations is true', function() {
+      expect(instanceObject.updateInitialOnRecommendations()).to.be.false;
+    })
+  });
+
+  describe('#useInitialValue', function() {
+    it('default value for useInitialValue is false', function() {
+      expect(instanceObject.useInitialValue()).to.be.false;
+    })
+  });
+
+  describe('#allowUpdateProperty', function() {
+    it('default value for allowUpdateProperty is true', function() {
+      expect(instanceObject.allowUpdateProperty()).to.be.true;
+    })
+  });
+});
+
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/ac1fbc23/ambari-web/test/utils/config_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/utils/config_test.js b/ambari-web/test/utils/config_test.js
index 13e0fa5..b58bfa3 100644
--- a/ambari-web/test/utils/config_test.js
+++ b/ambari-web/test/utils/config_test.js
@@ -951,7 +951,7 @@ describe('App.config', function () {
       /** core properties **/
       id: "pName__pFileName",
       name: 'pName',
-      filename: 'pFileName',
+      filename: 'pFileName.xml',
       value: '',
       savedValue: null,
       isFinal: false,


Mime
View raw message