AMBARI-7447 Remove xml escaping logic present in the web-ui code. (ababiichuk)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/03a1ff97 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/03a1ff97 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/03a1ff97 Branch: refs/heads/branch-alerts-dev Commit: 03a1ff97384fee8cfe248278fd995c4640569b89 Parents: 10b0038 Author: ababiichuk <[email protected]> Authored: Wed Sep 24 17:52:08 2014 +0300 Committer: ababiichuk <[email protected]> Committed: Wed Sep 24 17:52:08 2014 +0300 ---------------------------------------------------------------------- .../security/security_progress_controller.js | 27 -------- .../main/mirroring/jobs_controller.js | 2 +- .../controllers/main/service/info/configs.js | 9 +-- .../app/controllers/wizard/step8_controller.js | 22 +++--- ambari-web/app/utils/config.js | 47 ------------- ambari-web/app/views/wizard/controls_view.js | 21 +++++- .../security_progress_controller_test.js | 71 -------------------- .../main/service/info/config_test.js | 9 +-- .../test/controllers/wizard/step8_test.js | 34 ++-------- ambari-web/test/utils/config_test.js | 38 +---------- 10 files changed, 40 insertions(+), 240 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/03a1ff97/ambari-web/app/controllers/main/admin/security/security_progress_controller.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers/main/admin/security/security_progress_controller.js b/ambari-web/app/controllers/main/admin/security/security_progress_controller.js index 5aacb56..a17c5f6 100644 --- a/ambari-web/app/controllers/main/admin/security/security_progress_controller.js +++ b/ambari-web/app/controllers/main/admin/security/security_progress_controller.js @@ -379,7 +379,6 @@ App.MainAdminSecurityProgressController = Em.Controller.extend({ } }, this); if (this.manageSecureConfigs()) { - this.escapeXMLCharacters(this.get('serviceConfigTags')); this.applyConfigurationsToCluster(); } }, @@ -392,32 +391,6 @@ App.MainAdminSecurityProgressController = Em.Controller.extend({ console.log("TRACE: error code status is: " + request.status); }, - /* - Iterate over keys of all configurations and escape xml characters in their values - */ - escapeXMLCharacters: function (serviceConfigTags) { - serviceConfigTags.forEach(function (_serviceConfigTags) { - var configs = _serviceConfigTags.configs; - for (var key in configs) { - configs[key] = this.setServerConfigValue(key, configs[key]); - } - }, this); - }, - - /** - * set specific server values to config - * @param configName - * @param value - * @return {*} - */ - setServerConfigValue: function (configName, value) { - switch (configName) { - case 'storm.zookeeper.servers': - return value; - default: - return App.config.escapeXMLCharacters(value); - } - }, /** * save commands to server and local storage */ http://git-wip-us.apache.org/repos/asf/ambari/blob/03a1ff97/ambari-web/app/controllers/main/mirroring/jobs_controller.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers/main/mirroring/jobs_controller.js b/ambari-web/app/controllers/main/mirroring/jobs_controller.js index ac36890..dded921 100644 --- a/ambari-web/app/controllers/main/mirroring/jobs_controller.js +++ b/ambari-web/app/controllers/main/mirroring/jobs_controller.js @@ -183,7 +183,7 @@ App.MainDatasetJobsController = Em.Controller.extend({ openInfoInNewTab: function (xml) { var newWindow = window.open(''); var newDocument = newWindow.document; - newDocument.write('<pre>' + App.config.escapeXMLCharacters(xml, true) + '</pre>'); + newDocument.write('<pre>' + xml + '</pre>'); newWindow.focus(); }, http://git-wip-us.apache.org/repos/asf/ambari/blob/03a1ff97/ambari-web/app/controllers/main/service/info/configs.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers/main/service/info/configs.js b/ambari-web/app/controllers/main/service/info/configs.js index a05f5ac..718ebf8 100644 --- a/ambari-web/app/controllers/main/service/info/configs.js +++ b/ambari-web/app/controllers/main/service/info/configs.js @@ -2153,7 +2153,7 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM var coreSiteObj = this.get('uiConfigs').filterProperty('filename', 'core-site.xml'); var coreSiteProperties = {}; coreSiteObj.forEach(function (_coreSiteObj) { - coreSiteProperties[_coreSiteObj.name] = App.config.escapeXMLCharacters(_coreSiteObj.value); + coreSiteProperties[_coreSiteObj.name] = _coreSiteObj.value; //this.recordHostOverride(_coreSiteObj, 'core-site', tagName, this); }, this); var result = {"type": "core-site", "tag": tagName, "properties": coreSiteProperties}; @@ -2181,7 +2181,7 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM if (heapsizeRegExp.test(_siteObj.name) && !heapsizeException.contains(_siteObj.name)) { value += "m"; } - siteProperties[_siteObj.name] = App.config.escapeXMLCharacters(value); + siteProperties[_siteObj.name] = value; switch (siteName) { case 'falcon-startup.properties': case 'falcon-runtime.properties': @@ -2219,11 +2219,8 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM return value; } break; - case 'content': - return value; - break; default: - return App.config.escapeXMLCharacters(value); + return value; } }, http://git-wip-us.apache.org/repos/asf/ambari/blob/03a1ff97/ambari-web/app/controllers/wizard/step8_controller.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers/wizard/step8_controller.js b/ambari-web/app/controllers/wizard/step8_controller.js index 9f07df4..1fd0b0a 100644 --- a/ambari-web/app/controllers/wizard/step8_controller.js +++ b/ambari-web/app/controllers/wizard/step8_controller.js @@ -1404,7 +1404,7 @@ App.WizardStep8Controller = Em.Controller.extend(App.AddSecurityConfigs, { var selectedServices = this.get('selectedServices'); var coreSiteObject = this.createCoreSiteObj(); var tag = 'version1'; - var clusterSiteObj = this.createSiteObj('cluster-env', true, tag); + var clusterSiteObj = this.createSiteObj('cluster-env', tag); if (this.get('content.controllerName') == 'installerController') { this.get('serviceConfigTags').pushObject(clusterSiteObj); @@ -1436,8 +1436,7 @@ App.WizardStep8Controller = Em.Controller.extend(App.AddSecurityConfigs, { obj.service_config_version_note = serviceVersionNotes; this.get('serviceConfigTags').pushObject(obj); } else { - var isNonXmlFile = type.endsWith('log4j') || type.endsWith('env') || type.endsWith('properties') || type.endsWith('conf'); - var obj = this.createSiteObj(type, isNonXmlFile, tag); + var obj = this.createSiteObj(type, tag); obj.service_config_version_note = serviceVersionNotes; this.get('serviceConfigTags').pushObject(obj); } @@ -1610,17 +1609,17 @@ App.WizardStep8Controller = Em.Controller.extend(App.AddSecurityConfigs, { (isOozieSelected || (_coreSiteObj.name != 'hadoop.proxyuser.' + oozieUser + '.hosts' && _coreSiteObj.name != 'hadoop.proxyuser.' + oozieUser + '.groups')) && (isHiveSelected || (_coreSiteObj.name != 'hadoop.proxyuser.' + hiveUser + '.hosts' && _coreSiteObj.name != 'hadoop.proxyuser.' + hiveUser + '.groups')) && (isHiveSelected || (_coreSiteObj.name != 'hadoop.proxyuser.' + hcatUser + '.hosts' && _coreSiteObj.name != 'hadoop.proxyuser.' + hcatUser + '.groups'))) { - coreSiteProperties[_coreSiteObj.name] = App.config.escapeXMLCharacters(_coreSiteObj.value); + coreSiteProperties[_coreSiteObj.name] = _coreSiteObj.value; } if (isGLUSTERFSSelected && _coreSiteObj.name == "fs.default.name") { coreSiteProperties[_coreSiteObj.name] = this.get('configs').someProperty('name', 'fs_glusterfs_default_name') ? - App.config.escapeXMLCharacters(this.get('configs').findProperty('name', 'fs_glusterfs_default_name').value) : null; + this.get('configs').findProperty('name', 'fs_glusterfs_default_name').value : null; } if (isGLUSTERFSSelected && _coreSiteObj.name == "fs.defaultFS") { coreSiteProperties[_coreSiteObj.name] = this.get('configs').someProperty('name', 'glusterfs_defaultFS_name') ? - App.config.escapeXMLCharacters(this.get('configs').findProperty('name', 'glusterfs_defaultFS_name').value) : null; + this.get('configs').findProperty('name', 'glusterfs_defaultFS_name').value : null; } }, this); var attributes = App.router.get('mainServiceInfoConfigsController').getConfigAttributes(coreSiteObj); @@ -1634,17 +1633,15 @@ App.WizardStep8Controller = Em.Controller.extend(App.AddSecurityConfigs, { /** * Create siteObj for custom service with it own configs * @param {string} site - * @param {boolean} isNonXmlFile * @param tag * @returns {{type: string, tag: string, properties: {}}} * @method createSiteObj */ - createSiteObj: function (site, isNonXmlFile, tag) { + createSiteObj: function (site, tag) { var properties = {}; var configs = this.get('configs').filterProperty('filename', site + '.xml'); var attributes = App.router.get('mainServiceInfoConfigsController').getConfigAttributes(configs); configs.forEach(function (_configProperty) { - if (isNonXmlFile) { var heapsizeExceptions = ['hadoop_heapsize', 'yarn_heapsize', 'nodemanager_heapsize', 'resourcemanager_heapsize', 'apptimelineserver_heapsize', 'jobhistory_heapsize']; // do not pass any globals whose name ends with _host or _hosts if (_configProperty.isRequiredByAgent !== false) { @@ -1655,9 +1652,6 @@ App.WizardStep8Controller = Em.Controller.extend(App.AddSecurityConfigs, { properties[_configProperty.name] = _configProperty.value; } } - } else { - properties[_configProperty.name] = App.config.escapeXMLCharacters(_configProperty.value); - } }, this); var configObj = {"type": site, "tag": tag, "properties": properties }; if (attributes) { @@ -1676,7 +1670,7 @@ App.WizardStep8Controller = Em.Controller.extend(App.AddSecurityConfigs, { var configs = this.get('configs').filterProperty('filename', 'zoo.cfg'); var csProperties = {}; configs.forEach(function (_configProperty) { - csProperties[_configProperty.name] = App.config.escapeXMLCharacters(_configProperty.value); + csProperties[_configProperty.name] = _configProperty.value; }, this); return {type: 'zoo.cfg', tag: tag, properties: csProperties}; }, @@ -1699,7 +1693,7 @@ App.WizardStep8Controller = Em.Controller.extend(App.AddSecurityConfigs, { stormProperties[_configProperty.name] = JSON.stringify(_configProperty.value).replace(/"/g, ""); } } else { - stormProperties[_configProperty.name] = App.config.escapeXMLCharacters(_configProperty.value); + stormProperties[_configProperty.name] = _configProperty.value; } }, this); return {type: 'storm-site', tag: tag, properties: stormProperties}; http://git-wip-us.apache.org/repos/asf/ambari/blob/03a1ff97/ambari-web/app/utils/config.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/utils/config.js b/ambari-web/app/utils/config.js index 52f918d..2d1004d 100644 --- a/ambari-web/app/utils/config.js +++ b/ambari-web/app/utils/config.js @@ -22,24 +22,6 @@ var stringUtils = require('utils/string_utils'); var configGroupsByTag = []; App.config = Em.Object.create({ - /** - * XML characters which should be escaped in values - * http://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references#Predefined_entities_in_XML - */ - xmlEscapeMap: { - "&": "&", - "<": "<", - ">": ">", - '"': '"', - "'": ''' - }, - xmlUnEscapeMap: { - "&": "&", - "<": "<", - ">": ">", - """: '"', - "'": "'" - }, CONFIG_GROUP_NAME_MAX_LENGTH: 18, @@ -48,35 +30,6 @@ App.config = Em.Object.create({ */ filenameExceptions: ['zoo.cfg'], - /** - * Since values end up in XML files (core-sit.xml, etc.), certain - * XML sensitive characters should be escaped. If not we will have - * an invalid XML document, and services will fail to start. - * - * 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; - // To prevent double/triple replacing '>' to '&gt;' to '&amp;gt;', we need - // to first unescape all XML chars, and then escape them again. - var newValue = String(value).replace(/(&|<|>|"|')/g, function (s) { - return self.xmlUnEscapeMap[s]; - }); - if (toXML) { - return String(newValue).replace(/[&<>"']/g, function (s) { - return self.xmlEscapeMap[s]; - }); - } else { - return newValue; - } - }, - preDefinedServiceConfigs: [], /** * http://git-wip-us.apache.org/repos/asf/ambari/blob/03a1ff97/ambari-web/app/views/wizard/controls_view.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/wizard/controls_view.js b/ambari-web/app/views/wizard/controls_view.js index 6619179..198e4a8 100644 --- a/ambari-web/app/views/wizard/controls_view.js +++ b/ambari-web/app/views/wizard/controls_view.js @@ -60,10 +60,25 @@ App.ServiceConfigPopoverSupport = Ember.Mixin.create({ }); /** + * if config value contains &|<|>|"|' + * input field converts it to &|<|>|"|' + * this mixin helps to aviod such convertation and show values as is. + */ +App.SkipXmlEscapingSupport = Ember.Mixin.create({ + didInsertElement: function() { + this._super(); + if (this.get('serviceConfig.value').match(/(&|<|>|"|')/g)) { + this.set('value', this.get('serviceConfig.value').replace('&','&')); + this.set('value', this.get('value').replace('&','&')); + } + } +}); + +/** * Default input control * @type {*} */ -App.ServiceConfigTextField = Ember.TextField.extend(App.ServiceConfigPopoverSupport, { +App.ServiceConfigTextField = Ember.TextField.extend(App.ServiceConfigPopoverSupport, App.SkipXmlEscapingSupport, { valueBinding: 'serviceConfig.value', classNameBindings: 'textFieldClassName', @@ -156,7 +171,7 @@ App.ServiceConfigPasswordField = Ember.TextField.extend({ * Textarea control * @type {*} */ -App.ServiceConfigTextArea = Ember.TextArea.extend(App.ServiceConfigPopoverSupport, { +App.ServiceConfigTextArea = Ember.TextArea.extend(App.ServiceConfigPopoverSupport, App.SkipXmlEscapingSupport, { valueBinding: 'serviceConfig.value', rows: 4, @@ -167,7 +182,7 @@ App.ServiceConfigTextArea = Ember.TextArea.extend(App.ServiceConfigPopoverSuppor * Textarea control for content type * @type {*} */ -App.ServiceConfigTextAreaContent = Ember.TextArea.extend(App.ServiceConfigPopoverSupport, { +App.ServiceConfigTextAreaContent = Ember.TextArea.extend(App.ServiceConfigPopoverSupport, App.SkipXmlEscapingSupport, { valueBinding: 'serviceConfig.value', rows: 20, http://git-wip-us.apache.org/repos/asf/ambari/blob/03a1ff97/ambari-web/test/controllers/main/admin/security/security_progress_controller_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/controllers/main/admin/security/security_progress_controller_test.js b/ambari-web/test/controllers/main/admin/security/security_progress_controller_test.js index 2d96150..26cfbab 100644 --- a/ambari-web/test/controllers/main/admin/security/security_progress_controller_test.js +++ b/ambari-web/test/controllers/main/admin/security/security_progress_controller_test.js @@ -408,75 +408,4 @@ describe('App.MainAdminSecurityProgressController', function () { }); }); }); - - describe('#setServerConfigValue()', function () { - - beforeEach(function () { - sinon.spy(App.config, "escapeXMLCharacters"); - }); - afterEach(function () { - App.config.escapeXMLCharacters.restore(); - }); - - it('Empty config', function () { - expect(controller.setServerConfigValue('', '')).to.equal(''); - expect(App.config.escapeXMLCharacters.calledWith('')).to.be.true; - }); - it('Config1, value = "value1"', function () { - expect(controller.setServerConfigValue('config1', 'value1')).to.equal('value1'); - expect(App.config.escapeXMLCharacters.calledWith('value1')).to.be.true; - }); - it('config = "storm.zookeeper.servers", value = "value1"', function () { - expect(controller.setServerConfigValue('storm.zookeeper.servers', 'value1')).to.equal('value1'); - expect(App.config.escapeXMLCharacters.called).to.be.false; - }); - }); - - describe('#escapeXMLCharacters()', function () { - - beforeEach(function () { - sinon.spy(controller, "setServerConfigValue"); - }); - afterEach(function () { - controller.setServerConfigValue.restore(); - }); - - it('serviceConfigTags is empty', function () { - var serviceConfigTags = []; - controller.escapeXMLCharacters(serviceConfigTags); - expect(controller.setServerConfigValue.called).to.be.false; - }); - it('configs is empty', function () { - var serviceConfigTags = [ - { - configs: {} - } - ]; - controller.escapeXMLCharacters(serviceConfigTags); - expect(controller.setServerConfigValue.called).to.be.false; - }); - it('serviceConfigTags has property', function () { - var serviceConfigTags = [ - { - configs: { - 'p1': 'value1' - } - } - ]; - controller.escapeXMLCharacters(serviceConfigTags); - expect(controller.setServerConfigValue.withArgs('p1', 'value1').calledOnce).to.be.true; - }); - it('serviceConfigTags has multiple properties', function () { - var serviceConfigTags = [ - { - configs: { - 'p1': 'value1', - 'p2': 'value2' - } - } - ]; - controller.escapeXMLCharacters(serviceConfigTags); - expect(controller.setServerConfigValue.callCount).to.equal(2); - }); - }); }); http://git-wip-us.apache.org/repos/asf/ambari/blob/03a1ff97/ambari-web/test/controllers/main/service/info/config_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/controllers/main/service/info/config_test.js b/ambari-web/test/controllers/main/service/info/config_test.js index afb2a08..8926cf2 100644 --- a/ambari-web/test/controllers/main/service/info/config_test.js +++ b/ambari-web/test/controllers/main/service/info/config_test.js @@ -482,11 +482,8 @@ describe("App.MainServiceInfoConfigsController", function () { it("parsing storm.zookeeper.servers property in non standart method", function () { expect(mainServiceInfoConfigsController.setServerConfigValue("storm.zookeeper.servers", ["a", "b"])).to.equal('[\'a\',\'b\']'); }); - it("parsing content property in non standart method", function () { - expect(mainServiceInfoConfigsController.setServerConfigValue("content", "value")).to.equal("value"); - }); it("parsing default properties", function () { - expect(mainServiceInfoConfigsController.setServerConfigValue("any.other.property", "value<")).to.equal("value<"); + expect(mainServiceInfoConfigsController.setServerConfigValue("any.other.property", "value")).to.equal("value"); }); }); @@ -511,7 +508,7 @@ describe("App.MainServiceInfoConfigsController", function () { "tag": "version1", "properties": { "property1": "value1", - "property2": "value2<" + "property2": "value2<" } }, m: "default" @@ -570,7 +567,7 @@ describe("App.MainServiceInfoConfigsController", function () { "tag": "version1", "properties": { "property1": "value1", - "property2": "value2<" + "property2": "value2<" } } } http://git-wip-us.apache.org/repos/asf/ambari/blob/03a1ff97/ambari-web/test/controllers/wizard/step8_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/controllers/wizard/step8_test.js b/ambari-web/test/controllers/wizard/step8_test.js index b6488a9..3a7774b 100644 --- a/ambari-web/test/controllers/wizard/step8_test.js +++ b/ambari-web/test/controllers/wizard/step8_test.js @@ -85,7 +85,7 @@ describe('App.WizardStep8Controller', function () { it(test.name, function () { - var siteObj = installerStep8Controller.createSiteObj(test.e.type,false,test.e.tag); + var siteObj = installerStep8Controller.createSiteObj(test.e.type, test.e.tag); expect(siteObj.tag).to.equal(test.e.tag); expect(Em.keys(siteObj.properties).length).to.equal(test.e.l); }); @@ -911,11 +911,11 @@ describe('App.WizardStep8Controller', function () { type: 'zoo.cfg', tag: 'version1', properties: { - p1: 'a&b', - p2: 'a<b', - p3: 'a>b', - p4: 'a"b', - p5: 'a\'b' + p1: 'a&b', + p2: 'a<b', + p3: 'a>b', + p4: 'a"b', + p5: 'a'b' } }; installerStep8Controller.reopen({configs: configs}); @@ -956,28 +956,6 @@ describe('App.WizardStep8Controller', function () { installerStep8Controller.reopen({configs: configs}); expect(installerStep8Controller.createStormSiteObj('version1')).to.eql(expected); }); - it('should affect storm-site.xml properties', function() { - var configs = [ - {filename: 'storm-site.xml', value: 'a&b', name: 'p1'}, - {filename: 'storm-site.xml', value: 'a<b', name: 'p2'}, - {filename: 'storm-site.xml', value: 'a>b', name: 'p3'}, - {filename: 'storm-site.xml', value: 'a"b', name: 'p4'}, - {filename: 'storm-site.xml', value: 'a'b', name: 'p5'} - ], - expected = { - type: 'storm-site', - tag: 'version1', - properties: { - p1: 'a&b', - p2: 'a<b', - p3: 'a>b', - p4: 'a"b', - p5: 'a\'b' - } - }; - installerStep8Controller.reopen({configs: configs}); - expect(installerStep8Controller.createStormSiteObj('version1')).to.eql(expected); - }); }); describe('#ajaxQueueFinished', function() { http://git-wip-us.apache.org/repos/asf/ambari/blob/03a1ff97/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 451f748..528be46 100644 --- a/ambari-web/test/utils/config_test.js +++ b/ambari-web/test/utils/config_test.js @@ -288,42 +288,6 @@ describe('App.config', function () { }); }); - describe('#escapeXMLCharacters', function () { - - var testConfigs = [ - { - html: '&>"', - json: '&>"' - }, - { - html: '&>"'', - json: '&>"\'' - }, - { - html: '&>', - json: '&>' - }, - { - html: '&&&', - json: '&&&' - }, - { - html: '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`', - 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: '&&&', - json: '&&&', - toXml: true - } - ]; - testConfigs.forEach(function(t){ - it('parsing html ' + t.html + ' `toXml` param passed ' + !!t.toXml, function () { - expect(t.json).to.equal(App.config.escapeXMLCharacters(t.html, t.toXml)); - }); - }); - }); - describe('#addAvancedConfigs()', function() { before(function() { this.storedConfigs = modelSetup.setupStoredConfigsObject(); @@ -457,4 +421,4 @@ describe('App.config', function () { expect(ServiceConfig.get('configCategories.length')).to.eql(1); }); }); -}); \ No newline at end of file +});
