You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by on...@apache.org on 2014/05/07 11:26:39 UTC

git commit: AMBARI-5692. Unit tests for utils/config.js part 1. (Buzhor Denys via onechiporenko)

Repository: ambari
Updated Branches:
  refs/heads/trunk 32e68f41b -> 5c11ca71b


AMBARI-5692. Unit tests for utils/config.js part 1. (Buzhor Denys via onechiporenko)


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

Branch: refs/heads/trunk
Commit: 5c11ca71bd3de74cb4580a7eeb44ac49757a7017
Parents: 32e68f4
Author: Oleg Nechiporenko <on...@apache.org>
Authored: Wed May 7 12:22:32 2014 +0300
Committer: Oleg Nechiporenko <on...@apache.org>
Committed: Wed May 7 12:22:32 2014 +0300

----------------------------------------------------------------------
 ambari-web/app/utils/config.js                  |  20 +-
 ambari-web/test/init_model_test.js              |  10 +-
 .../test/mock_data_setup/configs_mock_data.js   | 354 +++++++++++++
 ambari-web/test/utils/config_test.js            | 496 ++++++++++++++++++-
 4 files changed, 874 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/5c11ca71/ambari-web/app/utils/config.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/config.js b/ambari-web/app/utils/config.js
index 8ab5337..eb6febc 100644
--- a/ambari-web/app/utils/config.js
+++ b/ambari-web/app/utils/config.js
@@ -56,6 +56,11 @@ App.config = Em.Object.create({
    * 
    * Special characters in XML are defined at
    * http://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references#Predefined_entities_in_XML
+   *
+   * @method escapeXMLCharacters
+   * @param {*} value
+   * @param toXml {Boolean}
+   * @return {String}
    */
   escapeXMLCharacters: function(value, toXML) {
     var self = this;
@@ -72,6 +77,7 @@ App.config = Em.Object.create({
       return newValue;
     }
   },
+
   preDefinedServiceConfigs: function () {
     var configs = this.get('preDefinedGlobalProperties');
     var services = [];
@@ -81,32 +87,38 @@ App.config = Em.Object.create({
     });
     return services;
   }.property('preDefinedGlobalProperties'),
+
   configMapping: function () {
     if (App.get('isHadoop2Stack')) {
       return $.extend(true, [], require('data/HDP2/config_mapping'));
     }
     return $.extend(true, [], require('data/config_mapping'));
   }.property('App.isHadoop2Stack'),
+
   preDefinedGlobalProperties: function () {
     if (App.get('isHadoop2Stack')) {
       return $.extend(true, [], require('data/HDP2/global_properties').configProperties);
     }
     return $.extend(true, [], require('data/global_properties').configProperties);
   }.property('App.isHadoop2Stack'),
+
   preDefinedSiteProperties: function () {
     if (App.get('isHadoop2Stack')) {
       return $.extend(true, [], require('data/HDP2/site_properties').configProperties);
     }
     return $.extend(true, [], require('data/site_properties').configProperties);
   }.property('App.isHadoop2Stack'),
+
   preDefinedCustomConfigs: function () {
     if (App.get('isHadoop2Stack')) {
       return $.extend(true, [], require('data/HDP2/custom_configs'));
     }
     return $.extend(true, [], require('data/custom_configs'));
   }.property('App.isHadoop2Stack'),
+
   //categories which contain custom configs
   categoriesWithCustom: ['CapacityScheduler'],
+
   //configs with these filenames go to appropriate category not in Advanced
   customFileNames: function () {
     var customFiles = ['flume-conf.xml'];
@@ -121,7 +133,7 @@ App.config = Em.Object.create({
 
   /**
    * Function should be used post-install as precondition check should not be done only after installer wizard
-   * @param siteNames
+   * @param siteNames {string|array}
    * @returns {Array}
    */
   getBySitename: function (siteNames) {
@@ -137,7 +149,6 @@ App.config = Em.Object.create({
     return siteProperties;
   },
 
-
   /**
    * Cache of loaded configurations. This is useful in not loading
    * same configuration multiple times. It is populated in multiple
@@ -206,6 +217,7 @@ App.config = Em.Object.create({
       config.isRequired = true;
     }
   },
+
   capacitySchedulerFilter: function () {
     var yarnRegex = /^yarn\.scheduler\.capacity\.root\.(?!unfunded)([a-z]([\_\-a-z0-9]{0,50}))\.(acl_administer_jobs|acl_submit_jobs|state|user-limit-factor|maximum-capacity|capacity)$/i;
     var self = this;
@@ -358,7 +370,9 @@ App.config = Em.Object.create({
 
   /**
    * synchronize order of config properties with order, that on UI side
-   * @param configSet
+   *
+   * @method syncOrderWithPredefined
+   * @param configSet {object}
    * @return {Object}
    */
   syncOrderWithPredefined: function (configSet) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/5c11ca71/ambari-web/test/init_model_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/init_model_test.js b/ambari-web/test/init_model_test.js
index 8fbfe6e..bb36034 100644
--- a/ambari-web/test/init_model_test.js
+++ b/ambari-web/test/init_model_test.js
@@ -37,5 +37,13 @@ module.exports = {
   },
   cleanStackServiceComponent: function(){
     App.StackServiceComponent.find().set('content',[]);
-  }
+  },
+  setupStackVersion: function(context, version) {
+    context.prevStackVersion = App.get('currentStackVersion');
+    App.set('currentStackVersion', version);
+  },
+  restoreStackVersion: function(context) {
+    App.set('currentStackVersion', context.prevStackVersion);
+  },
+  configs: require('test/mock_data_setup/configs_mock_data')
 };
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/5c11ca71/ambari-web/test/mock_data_setup/configs_mock_data.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/mock_data_setup/configs_mock_data.js b/ambari-web/test/mock_data_setup/configs_mock_data.js
new file mode 100644
index 0000000..64cc619
--- /dev/null
+++ b/ambari-web/test/mock_data_setup/configs_mock_data.js
@@ -0,0 +1,354 @@
+/**
+ * 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.
+ */
+
+module.exports = {
+  setupConfigGroupsObject: function(serviceName) {
+    var serviceGroups = this.setupServiceConfigTagsObject(serviceName).mapProperty('siteName');
+    var configGroups = [
+      {
+        "tag":"version1",
+        "type":"core-site",
+        "properties": {
+          "fs.defaultFS" : "hdfs://c6401.ambari.apache.org:8020",
+          "fs.trash.interval" : "360"
+        }
+      },
+      {
+        "tag":"version1",
+        "type":"global",
+        "properties":{
+          "hadoop_heapsize":"1024",
+          "storm_log_dir": "/var/log/storm",
+          "stormuiserver_host": "c6401.ambari.apache.org",
+          "nonexistent_property": "some value"
+        }
+      },
+      {
+        "tag":"version1",
+        "type":"hdfs-site",
+        "properties": {
+          "dfs.datanode.data.dir": "/b,/a",
+          "dfs.namenode.name.dir": "/b,/a,/c",
+          "dfs.namenode.checkpoint.dir": "/b,/d,/a,/c",
+          "dfs.datanode.failed.volumes.tolerated": "2",
+          "content": "custom mock property"
+        }
+      },
+      {
+        "tag":"version1",
+        "type":"hdfs-log4j",
+        "properties": {
+          "content": "hdfs log4j content"
+        }
+      },
+      {
+        "tag":"version1",
+        "type":"zoo.cfg",
+        "properties": {
+          "custom.zoo.cfg": "zoo cfg content"
+        }
+      },
+      {
+        "tag":"version1",
+        "type":"storm-site",
+        "properties": {
+          "storm.zookeeper.servers": "['c6401.ambari.apache.org','c6402.ambari.apache.org']",
+          "single_line_property": "value",
+          "multi_line_property": "value \n value"
+        }
+      },
+      {
+        "tag":"version1",
+        "type":"zoo.cfg",
+        "properties": {
+          "custom.zoo.cfg": "value"
+        }
+      }
+    ];
+    return configGroups.filter(function(configGroup) {
+      return serviceGroups.contains(configGroup.type);
+    });
+  },
+  setupServiceConfigTagsObject: function(serviceName) {
+    var configTags = {
+      STORM: ['global','storm-site'],
+      HDFS: ['global','hdfs-site','core-site','hdfs-log4j'],
+      ZOOKEEPER: ['global', 'zoo.cfg']
+    };
+    var configTagsObject = [];
+    if (serviceName) {
+      configTags[serviceName].forEach(function(tag) {
+        configTagsObject.push({
+          siteName: tag,
+          tagName: "version1",
+          newTagName: null
+        });
+      });
+    } else {
+      for (var serviceName in configTags) {
+        configTags[serviceName].forEach(function(tag) {
+          configTagsObject.push({
+            siteName: tag,
+            tagName: "version1",
+            newTagName: null
+          });
+        });
+      }
+    }
+    return configTagsObject.uniq();
+  },
+  setupAdvancedConfigsObject: function() {
+    return [
+      {
+        "serviceName": "HDFS",
+        "name": "fs.defaultFS",
+        "value": "hdfs://c6401.ambari.apache.org:8020",
+        "description": "fs.defaultFS",
+        "filename": "core-site.xml"
+      },
+      {
+        "serviceName": "STORM",
+        "name": "storm.zookeeper.servers",
+        "value": "['localhost']",
+        "description": "desc",
+        "filename": "storm-site.xml"
+      },
+      {
+        "serviceName": "HDFS",
+        "name": "dfs.datanode.data.dir",
+        "value": "/hadoop/hdfs/data",
+        "description": "desc",
+        "filename": "hdfs-site.xml"
+      },
+      {
+        "serviceName": "HDFS",
+        "name": "dfs.namenode.name.dir",
+        "value": "/hadoop/hdfs/namenode",
+        "description": "desc",
+        "filename": "hdfs-site.xml"
+      },
+      {
+        "serviceName": "HDFS",
+        "name": "dfs.namenode.checkpoint.dir",
+        "value": "/hadoop/hdfs/namesecondary",
+        "description": "desc",
+        "filename": "hdfs-site.xml"
+      },
+      {
+        "serviceName": "HDFS",
+        "name": "dfs.datanode.failed.volumes.tolerated",
+        "value": "2",
+        "description": "desc",
+        "filename": "hdfs-site.xml"
+      },
+      {
+        "serviceName": "HDFS",
+        "name": "content",
+        "value": "custom mock property",
+        "description": "desc",
+        "filename": "hdfs-site.xml"
+      },
+      {
+        "serviceName": "HDFS",
+        "name": "content",
+        "value": "hdfs log4j content",
+        "description": "desc",
+        "filename": "hdfs-log4j.xml"
+      },
+      {
+        "serviceName": "HDFS",
+        "name": "content",
+        "value": "custom hdfs log4j content",
+        "description": "desc",
+        "filename": "custom-hdfs-log4j.xml"
+      },
+      {
+        "serviceName": "ZOOKEEPER",
+        "name": "content",
+        "value": "zookeeper log4j.xml content",
+        "description": "desc",
+        "filename": "zookeeper-log4j.xml"
+      },
+      {
+        "serviceName": "ZOOKEEPER",
+        "name": "custom.zoo.cfg",
+        "value": "zoo cfg content",
+        "description": "zoo.cfg config",
+        "filename": "zoo.cfg"
+      },
+      {
+        "serviceName": "YARN",
+        "name": "content",
+        "value": " value \n value",
+        "filename": "capacity-scheduler.xml"
+      },
+      {
+        "serviceName": "YARN",
+        "name": "yarn.scheduler.capacity.root.default.capacity",
+        "value": "100",
+        "filename": "capacity-scheduler.xml"
+      }
+    ];
+  },
+  setupStoredConfigsObject: function() {
+    return [
+      {
+        "name":"storm.zookeeper.servers",
+        "value":[
+          "c6401.ambari.apache.org",
+          "c6402.ambari.apache.org"
+        ],
+        "defaultValue":"['c6401.ambari.apache.org','c6402.ambari.apache.org']",
+        "filename":"storm-site.xml",
+        "isUserProperty":false,
+        "isOverridable":false,
+        "showLabel":true,
+        "serviceName":"STORM",
+        "displayType":"masterHosts",
+        "isVisible":true,
+        "description":"desc",
+        "isSecureConfig":false,
+        "category":"General",
+        "id":"site property",
+        "displayName":"storm.zookeeper.servers"
+      },
+      {
+        "name":"single_line_property",
+        "value":"value",
+        "defaultValue":"value",
+        "filename":"storm-site.xml",
+        "isUserProperty":true,
+        "isOverridable":true,
+        "showLabel":true,
+        "serviceName":"STORM",
+        "id":"site property",
+        "displayType":"advanced",
+        "displayName":"single_line_property",
+        "category":"AdvancedStormSite"
+      },
+      {
+        "name":"multi_line_property",
+        "value":"value \n value",
+        "defaultValue":"value \n value",
+        "filename":"storm-site.xml",
+        "isUserProperty":true,
+        "isOverridable":true,
+        "showLabel":true,
+        "serviceName":"STORM",
+        "id":"site property",
+        "displayType":"multiLine",
+        "displayName":"multi_line_property",
+        "category":"AdvancedStormSite"
+      },
+      {
+        "name":"nonexistent_property",
+        "value":"some value",
+        "defaultValue":"some value",
+        "filename":"global.xml",
+        "isUserProperty":false,
+        "isOverridable":true,
+        "showLabel":true,
+        "serviceName":"STORM",
+        "isVisible":false,
+        "id":"puppet var",
+        "displayName":null,
+        "options":null
+      },
+      {
+        "name":"dfs.datanode.data.dir",
+        "value":"/a,/b",
+        "defaultValue":"/a,/b",
+        "filename":"hdfs-site.xml",
+        "isUserProperty":false,
+        "isOverridable":true,
+        "showLabel":true,
+        "serviceName":"HDFS",
+        "displayType":"directories",
+        "isRequired":true,
+        "isReconfigurable":true,
+        "isVisible":true,
+        "description":"desc",
+        "index":1,
+        "isSecureConfig":false,
+        "category":"DataNode",
+        "id":"site property",
+        "displayName":"DataNode directories"
+      },
+      {
+        "name":"content",
+        "value":"custom mock property",
+        "defaultValue":"custom mock property",
+        "filename":"hdfs-site.xml",
+        "isUserProperty":false,
+        "isOverridable":true,
+        "showLabel":false,
+        "serviceName":"HDFS",
+        "displayType":"content",
+        "isRequired":true,
+        "isRequiredByAgent":true,
+        "isReconfigurable":true,
+        "isVisible":true,
+        "description":"desc",
+        "isSecureConfig":false,
+        "category":"AdvancedHDFSLog4j",
+        "id":"site property",
+        "displayName":"content"
+      },
+      {
+        "name":"content",
+        "value":"hdfs log4j content",
+        "defaultValue":"hdfs log4j content",
+        "filename":"hdfs-log4j.xml",
+        "isUserProperty":false,
+        "isOverridable":true,
+        "showLabel":false,
+        "serviceName":"HDFS",
+        "displayType":"content",
+        "isRequired":true,
+        "isRequiredByAgent":true,
+        "isReconfigurable":true,
+        "isVisible":true,
+        "description":"desc",
+        "isSecureConfig":false,
+        "category":"AdvancedHDFSLog4j",
+        "id":"site property",
+        "displayName":"content"
+      },
+      {
+        "name":"storm_log_dir",
+        "value":"/var/log/storm",
+        "defaultValue":"/var/log/storm",
+        "filename":"global.xml",
+        "isUserProperty":false,
+        "isOverridable":true,
+        "showLabel":true,
+        "serviceName":"STORM",
+        "displayType":"directory",
+        "isRequired":true,
+        "isRequiredByAgent":true,
+        "isReconfigurable":true,
+        "isVisible":true,
+        "description":"Storm log directory",
+        "isSecureConfig":false,
+        "category":"General",
+        "id":"puppet var",
+        "displayName":"storm_log_dir"
+      }
+    ];
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/5c11ca71/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 56551ca..388985c 100644
--- a/ambari-web/test/utils/config_test.js
+++ b/ambari-web/test/utils/config_test.js
@@ -19,11 +19,49 @@
 var App = require('app');
 require('config');
 require('utils/config');
+require('models/service/hdfs');
+var setups = require('test/init_model_test');
+var modelSetup = setups.configs;
 
 describe('App.config', function () {
 
   App.supports.capacitySchedulerUi = true;
 
+  var loadServiceSpecificConfigs = function(context, serviceName) {
+    context.configGroups = modelSetup.setupConfigGroupsObject(serviceName);
+    context.advancedConfigs = modelSetup.setupAdvancedConfigsObject();
+    context.tags = modelSetup.setupServiceConfigTagsObject(serviceName);
+    context.result = App.config.mergePreDefinedWithLoaded(context.configGroups, context.advancedConfigs, context.tags, App.Service.find().findProperty('id', serviceName).get('serviceName'));
+  };
+
+  var loadAllServicesConfigs = function(context, serviceNames) {
+    context.configGroups = modelSetup.setupConfigGroupsObject();
+  }
+
+  var loadServiceModelsData = function(serviceNames) {
+    serviceNames.forEach(function(serviceName) {
+      App.store.load(App.Service, {
+        id: serviceName,
+        service_name: serviceName
+      });
+    });
+  };
+
+  var setupContentForMergeWithStored = function(context) {
+    loadServiceModelsData(context.installedServiceNames);
+    loadAllServicesConfigs(context);
+    setups.setupStackVersion(this, 'HDP-2.1');
+    context.result = App.config.mergePreDefinedWithStored(context.storedConfigs, modelSetup.setupAdvancedConfigsObject(), context.installedServiceNames);
+  };
+
+  var removeServiceModelData = function(serviceIds) {
+    serviceIds.forEach(function(serviceId) {
+      var record = App.Service.find(serviceId);
+      record.deleteRecord();
+      record.get('stateManager').transitionTo('loading');
+    });
+  };
+
   describe('#identifyCategory', function () {
     var data = {};
     it('should return null if config doesn\'t have category', function () {
@@ -119,6 +157,86 @@ describe('App.config', function () {
     });
   });
 
+  describe('#capacitySchedulerFilter', function() {
+    var testMessage = 'filter should {0} detect `{1}` property';
+    describe('Stack version >= 2.0', function() {
+      before(function() {
+        setups.setupStackVersion(this, 'HDP-2.1');
+      });
+      var tests = [
+        {
+          config: {
+            name: 'yarn.scheduler.capacity.maximum-am-resource-percent'
+          },
+          e: false
+        },
+        {
+          config: {
+            name: 'yarn.scheduler.capacity.root.capacity'
+          },
+          e: false
+        },
+        {
+          config: {
+            name: 'yarn.scheduler.capacity.root.default.capacity'
+          },
+          e: true
+        }
+      ];
+
+      tests.forEach(function(test){
+        it(testMessage.format( !!test.e ? '' : 'not', test.config.name), function() {
+          expect(App.config.get('capacitySchedulerFilter')(test.config)).to.eql(test.e);
+        });
+      });
+      after(function() {
+        setups.restoreStackVersion(this);
+      })
+    });
+
+    describe('Stack version < 2.0', function() {
+      before(function() {
+        setups.setupStackVersion(this, 'HDP-1.3');
+      });
+      var tests = [
+        {
+          config: {
+            name: 'mapred.capacity-scheduler.maximum-system-jobs'
+          },
+          e: false
+        },
+        {
+          config: {
+            name: 'yarn.scheduler.capacity.root.capacity'
+          },
+          e: false
+        },
+        {
+          config: {
+            name: 'mapred.capacity-scheduler.queue.default.capacity'
+          },
+          e: true
+        },
+        {
+          config: {
+            name: 'mapred.queue.default.acl-administer-jobs'
+          },
+          e: true
+        }
+      ];
+
+      tests.forEach(function(test){
+        it(testMessage.format( !!test.e ? '' : 'not', test.config.name), function() {
+          expect(App.config.get('capacitySchedulerFilter')(test.config)).to.eql(test.e);
+        });
+      });
+
+      after(function() {
+        setups.restoreStackVersion(this);
+      });
+    });
+  });
+
   describe('#fileConfigsIntoTextarea', function () {
     var filename = 'capacity-scheduler.xml';
     var configs = [
@@ -253,13 +371,387 @@ describe('App.config', function () {
       {
         html: 'LD_LIBRARY_PATH=/usr/lib/hadoop/lib/native:/usr/lib/hadoop/lib/native/`$JAVA_HOME/bin/java -d32 -version &amp;&gt; /dev/null;if [ $? -eq 0 ]; then echo Linux-i386-32; else echo Linux-amd64-64;fi`',
         json: 'LD_LIBRARY_PATH=/usr/lib/hadoop/lib/native:/usr/lib/hadoop/lib/native/`$JAVA_HOME/bin/java -d32 -version &> /dev/null;if [ $? -eq 0 ]; then echo Linux-i386-32; else echo Linux-amd64-64;fi`'
+      },
+      {
+        html: '&&&amp;',
+        json: '&amp;&amp;&amp;',
+        toXml: true
       }
     ];
     testConfigs.forEach(function(t){
-      it('parsing html ' + t.html, function () {
-        expect(t.json).to.equal(App.config.escapeXMLCharacters(t.html));
+      it('parsing html ' + t.html + ' `toXml` param passed ' + !!t.toXml, function () {
+        expect(t.json).to.equal(App.config.escapeXMLCharacters(t.html, t.toXml));
+      });
+    });
+  });
+
+  describe('#mergePreDefinedWithLoaded()', function() {
+    before(function() {
+      loadServiceModelsData(['HDFS','STORM','ZOOKEEPER']);
+      setups.setupStackVersion(this, 'HDP-2.1');
+    });
+
+    describe('Load STORM configs: global, storm-site', function() {
+      before(function() {
+        loadServiceSpecificConfigs(this, "STORM");
+      });
+
+      it('site property with `masterHosts` display type should pass value validation', function() {
+        var property = this.result.configs.findProperty('name', 'storm.zookeeper.servers');
+        expect(property).to.be.ok;
+        expect(property.displayType).to.eql('masterHosts');
+        expect(property.value).to.eql(["c6401.ambari.apache.org", "c6402.ambari.apache.org"]);
+        expect(property.category).to.eql('General')
+      });
+      it('non-predefined global properties should not be displayed on UI', function() {
+        var property = this.result.globalConfigs.findProperty('name', 'nonexistent_property');
+        expect(property).to.be.a('object');
+        expect(property.isVisible).to.be.false;
+      });
+      it('non-predefined site properties should have displayType advanced/multiLine', function() {
+        var tests = [
+          {
+            property: 'single_line_property',
+            e: 'advanced'
+          },
+          {
+            property: 'multi_line_property',
+            e: 'multiLine'
+          }
+        ];
+        tests.forEach(function(test) {
+          var property = this.result.configs.findProperty('name', test.property);
+          expect(property).to.be.ok;
+          expect(property.displayType).to.eql(test.e);
+        }, this);
+
+      });
+    });
+
+    describe('Load HDFS configs: global, hdfs-site, core-site', function() {
+      before(function() {
+        loadServiceSpecificConfigs(this, "HDFS");
+      });
+
+      it('Data Node, Name Node, SName Node directory properties should have sorted values', function() {
+        var tests = [
+          {
+            property: "dfs.datanode.data.dir",
+            e: '/a,/b'
+          },
+          {
+            property: "dfs.namenode.name.dir",
+            e: '/a,/b,/c'
+          },
+          {
+            property: "dfs.namenode.checkpoint.dir",
+            e: '/a'
+          }
+        ];
+        tests.forEach(function(test) {
+          var property = this.result.configs.findProperty('name', test.property);
+          expect(property).to.be.ok;
+          expect(property.value).to.eql(test.e);
+        }, this);
+      });
+    });
+
+    describe('Load ZOOKEEPER configs: global, zoo.cfg', function() {
+      before(function() {
+        loadServiceSpecificConfigs(this, "ZOOKEEPER");
+      });
+
+      it('zoo.cfg configs should have non xml filename', function() {
+        expect(this.result.configs.findProperty('name', 'custom.zoo.cfg').filename).to.eql('zoo.cfg');
+      });
+    });
+
+    after(function() {
+      removeServiceModelData(['HDFS','STORM','ZOOKEEPER']);
+      setups.restoreStackVersion(this);
+    });
+  });
+
+  describe('#syncOrderWithPredefined()', function() {
+    before(function() {
+      setups.setupStackVersion(this, 'HDP-2.1');
+      loadServiceModelsData(['HDFS','STORM','ZOOKEEPER']);
+      loadServiceSpecificConfigs(this, 'HDFS');
+    });
+    it('properties should be ordered according to position in predefined data', function() {
+      var result = App.config.syncOrderWithPredefined(this.result);
+      expect(result).to.be.a('object');
+      expect(result.configs.filterProperty('category','DataNode').mapProperty('name')).to.eql(['dfs.datanode.failed.volumes.tolerated', 'dfs.datanode.data.dir']);
+    });
+    after(function() {
+      removeServiceModelData(['HDFS','STORM','ZOOKEEPER']);
+    });
+  });
+
+  describe('#mergePreDefinedWithStored()', function() {
+    describe('without `storedConfigs` parameter', function() {
+      before(function() {
+        this.installedServiceNames = ['HDFS','STORM', 'ZOOKEEPER'];
+        setupContentForMergeWithStored(this);
+      });
+
+      var tests = [
+        {
+          property: 'dfs.datanode.data.dir',
+          e: '/hadoop/hdfs/data'
+        },
+        {
+          property: 'dfs.datanode.failed.volumes.tolerated',
+          e: '2'
+        }
+      ];
+
+      tests.forEach(function(test) {
+        it('should set value and defaultValue to ' + test.e + ' for `' + test.property + '`', function() {
+          expect(this.result.findProperty('name', test.property).value).to.eql(test.e);
+          expect(this.result.findProperty('name', test.property).defaultValue).to.eql(test.e);
+        });
+      });
+
+      after(function() {
+        removeServiceModelData(this.installedServiceNames);
+        setups.restoreStackVersion(this);
+      });
+    });
+
+    describe('with `storedConfigs` parameter', function() {
+      before(function() {
+        this.installedServiceNames = ['HDFS','STORM','ZOOKEEPER'];
+        this.storedConfigs = modelSetup.setupStoredConfigsObject();
+        setupContentForMergeWithStored(this);
+      });
+
+      var tests = [
+        {
+          property: 'nonexistent_property',
+          stored: true,
+          e: {
+            value: 'some value',
+            isVisible: false,
+            category: 'Advanced',
+            displayType: 'advanced',
+            isRequired: true,
+            isOverridable: true
+          }
+        },
+        {
+          property: 'content',
+          filename: 'hdfs-log4j.xml',
+          stored: true,
+          predefined: true,
+          e: {
+            value: 'hdfs log4j content',
+            defaultValue: 'hdfs log4j content',
+            displayType: 'content'
+          }
+        },
+        {
+          property: 'content',
+          filename: 'zookeeper-log4j.xml',
+          stored: false,
+          predefined: true,
+          e: {
+            value: 'zookeeper log4j.xml content',
+            defaultValue: 'zookeeper log4j.xml content',
+            displayType: 'content'
+          }
+        }
+      ];
+
+      tests.forEach(function(test) {
+        it('`{0}` should pass validation. stored/predefined: {1}/{2}'.format(test.property, !!test.stored, !!test.predefined), function() {
+          var property = test.property == 'content' ? this.result.filterProperty('name', 'content').findProperty('filename', test.filename) : this.result.findProperty('name', test.property);
+          for (var key in test.e) {
+            expect(property[key]).to.be.eql(test.e[key]);
+          }
+        });
+      });
+
+      after(function(){
+        removeServiceModelData(this.installedServiceNames);
+        setups.restoreStackVersion(this);
+      });
+    });
+  });
+
+  describe('#addAvancedConfigs()', function() {
+    before(function() {
+      this.storedConfigs = modelSetup.setupStoredConfigsObject();
+    });
+
+    it('`custom.zoo.cfg` absent in stored configs', function() {
+      expect(this.storedConfigs.findProperty('name', 'custom.zoo.cfg')).to.be.undefined;
+    });
+
+    it('`custom.zoo.cfg.` from advanced configs should be added to stored configs', function() {
+      App.config.addAdvancedConfigs(this.storedConfigs, modelSetup.setupAdvancedConfigsObject(), 'ZOOKEEPER');
+      var property = this.storedConfigs.findProperty('name', 'custom.zoo.cfg');
+      expect(property).to.be.ok;
+      expect(property.category).to.eql('Advanced');
+    });
+
+    it('`capacity-scheduler.xml` configs related to `YARN` service should have category `CapacityScheduler`', function() {
+      App.config.addAdvancedConfigs(this.storedConfigs, modelSetup.setupAdvancedConfigsObject(), 'YARN');
+      expect(this.storedConfigs.filterProperty('filename', 'capacity-scheduler.xml').mapProperty('category').uniq()).to.eql(['CapacityScheduler']);
+    });
+    it('`capacity-scheduler.xml` property with name `content` should have `displayType` `multiLine`', function() {
+      expect(this.storedConfigs.filterProperty('filename', 'capacity-scheduler.xml').findProperty('name','content').displayType).to.eql('multiLine');
+    });
+  });
+
+  describe('#addCustomConfigs()', function() {
+    before(function() {
+      setups.setupStackVersion(this, 'HDP-2.1');
+      this.storedConfigs = modelSetup.setupStoredConfigsObject();
+      App.config.addAdvancedConfigs(this.storedConfigs, modelSetup.setupAdvancedConfigsObject(), 'ZOOKEEPER');
+      App.config.addAdvancedConfigs(this.storedConfigs, modelSetup.setupAdvancedConfigsObject(), 'YARN');
+    });
+
+    it('`yarn.scheduler.capacity.root.default.capacity` should have `isQueue` flag on', function() {
+      App.config.addCustomConfigs(this.storedConfigs);
+      expect(this.storedConfigs.findProperty('name','yarn.scheduler.capacity.root.default.capacity').isQueue).to.be.ok;
+    });
+
+    after(function() {
+      setups.restoreStackVersion(this);
+    });
+  });
+
+  describe('#createServiceConfig()', function() {
+    it('should create valid object for `HDFS`', function() {
+      var ServiceConfig = App.config.createServiceConfig('HDFS');
+      expect(ServiceConfig.configCategories.mapProperty('name')).to.include.members(["NameNode","SNameNode","DataNode"]);
+    });
+    it('should create valid object for `YARN` with capacity scheduler flag `on`', function() {
+      var ServiceConfig = App.config.createServiceConfig('YARN');
+      expect(ServiceConfig.configCategories.mapProperty('name')).to.include.members(["ResourceManager","NodeManager"]);
+      expect(ServiceConfig.configCategories.findProperty('name', 'CapacityScheduler').customView).to.be.a('Function');
+      expect(ServiceConfig.configCategories.findProperty('name', 'CapacityScheduler').isCustomView).to.true;
+    });
+    it('should create valid object for `YARN` with capacity scheduler flag `off`', function() {
+      App.supports.capacitySchedulerUi = false;
+      var ServiceConfig = App.config.createServiceConfig('YARN');
+      expect(ServiceConfig.configCategories.mapProperty('name')).to.include.members(["ResourceManager","NodeManager"]);
+      expect(ServiceConfig.configCategories.findProperty('name', 'CapacityScheduler').isCustomView).to.false;
+      App.supports.capacitySchedulerUi = true;
+    });
+  });
+
+  describe('#trimProperty',function() {
+    var testMessage = 'displayType `{0}`, value `{1}`{3} should return `{2}`';
+    var tests = [
+      {
+        config: {
+          displayType: 'directory',
+          value: ' /a /b /c'
+        },
+        e: '/a,/b,/c'
+      },
+      {
+        config: {
+          displayType: 'directories',
+          value: ' /a /b '
+        },
+        e: '/a,/b'
+      },
+      {
+        config: {
+          displayType: 'host',
+          value: ' localhost '
+        },
+        e: 'localhost'
+      },
+      {
+        config: {
+          displayType: 'password',
+          value: ' passw ord '
+        },
+        e: ' passw ord '
+      },
+      {
+        config: {
+          displayType: 'advanced',
+          value: ' value'
+        },
+        e: ' value'
+      },
+      {
+        config: {
+          displayType: 'advanced',
+          value: ' value'
+        },
+        e: ' value'
+      },
+      {
+        config: {
+          displayType: 'advanced',
+          value: 'http://localhost ',
+          name: 'javax.jdo.option.ConnectionURL'
+        },
+        e: 'http://localhost'
+      },
+      {
+        config: {
+          displayType: 'advanced',
+          value: 'http://localhost    ',
+          name: 'oozie.service.JPAService.jdbc.url'
+        },
+        e: 'http://localhost'
+      },
+      {
+        config: {
+          displayType: 'custom',
+          value: ' custom value '
+        },
+        e: ' custom value'
+      },
+      {
+        config: {
+          displayType: 'masterHosts',
+          value: ['host1.com', 'host2.com']
+        },
+        e: ['host1.com', 'host2.com']
+      }
+    ];
+
+    tests.forEach(function(test) {
+      it(testMessage.format(test.config.displayType, test.config.value, test.e, !!test.config.name ? ', name `' + test.config.name + '`' : ''), function() {
+        expect(App.config.trimProperty(test.config)).to.eql(test.e);
+        expect(App.config.trimProperty(Em.Object.create(test.config), true)).to.eql(test.e);
       });
     });
+  });
 
+  describe('#OnNnHAHideSnn()', function() {
+    it('`SNameNode` category present in `ServiceConfig`. It should be removed.', function() {
+      App.store.load(App.HDFSService, {
+        'id': 'HDFS'
+      });
+      var ServiceConfig = Em.Object.create({
+        configCategories: [ { name: 'SNameNode' } ]
+      });
+      expect(ServiceConfig.get('configCategories').findProperty('name','SNameNode')).to.ok;
+      App.config.OnNnHAHideSnn(ServiceConfig);
+      expect(ServiceConfig.get('configCategories').findProperty('name','SNameNode')).to.undefined;
+      var record = App.HDFSService.find('HDFS');
+      record.deleteRecord();
+      record.get('stateManager').transitionTo('loading');
+    });
+    it('`SNameNode` category absent in `ServiceConfig`. Nothing to do.', function() {
+      App.store.load(App.HDFSService, {
+        'id': 'HDFS'
+      });
+      var ServiceConfig = Em.Object.create({
+        configCategories: [ { name: 'DataNode' } ]
+      });
+      App.config.OnNnHAHideSnn(ServiceConfig);
+      expect(ServiceConfig.get('configCategories').findProperty('name','DataNode')).to.ok;
+      expect(ServiceConfig.get('configCategories.length')).to.eql(1);
+    });
   });
 });
\ No newline at end of file