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 <[email protected]>
Authored: Wed Jan 13 16:02:30 2016 +0200
Committer: ababiichuk <[email protected]>
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,

Reply via email to