You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by at...@apache.org on 2014/05/14 16:45:22 UTC

git commit: AMBARI-5758 UI unit tests for Add Security step 4. (atkach)

Repository: ambari
Updated Branches:
  refs/heads/trunk 3d1171b06 -> 17a4e3e9c


AMBARI-5758 UI unit tests for Add Security step 4. (atkach)


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

Branch: refs/heads/trunk
Commit: 17a4e3e9ce7d7816645be0563da03d07ff27eece
Parents: 3d1171b
Author: atkach <at...@hortonworks.com>
Authored: Wed May 14 17:43:31 2014 +0300
Committer: atkach <at...@hortonworks.com>
Committed: Wed May 14 17:43:31 2014 +0300

----------------------------------------------------------------------
 .../main/admin/security/add/step4.js            |  463 +++++---
 .../templates/main/admin/security/add/step4.hbs |   10 +-
 .../main/admin/security/add/step4_test.js       | 1115 ++++++++++++++++--
 .../main/admin/security/disable_test.js         |   20 +-
 4 files changed, 1350 insertions(+), 258 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/17a4e3e9/ambari-web/app/controllers/main/admin/security/add/step4.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/admin/security/add/step4.js b/ambari-web/app/controllers/main/admin/security/add/step4.js
index b94f441..f7fba39 100644
--- a/ambari-web/app/controllers/main/admin/security/add/step4.js
+++ b/ambari-web/app/controllers/main/admin/security/add/step4.js
@@ -17,49 +17,108 @@
  */
 
 var App = require('app');
+
 App.MainAdminSecurityAddStep4Controller = App.MainAdminSecurityProgressController.extend({
 
   name: 'mainAdminSecurityAddStep4Controller',
 
   serviceUsersBinding: 'App.router.mainAdminSecurityController.serviceUsers',
 
+  /**
+   * component configs which should be added to global
+   */
+  componentsConfig: [
+    {
+      serviceName: 'OOZIE',
+      componentName: 'OOZIE_SERVER',
+      configName: 'oozieserver_host'
+    },
+    {
+      serviceName: 'HIVE',
+      componentName: 'HIVE_METASTORE',
+      configName: 'hivemetastore_host'
+    },
+    {
+      serviceName: 'WEBHCAT',
+      componentName: 'WEBHCAT_SERVER',
+      configName: 'webhcat_server'
+    }
+  ],
+
+  /**
+   * mock users used in testMode
+   */
+  testModeUsers: [
+    {
+      name: 'hdfs_user',
+      value: 'hdfs'
+    },
+    {
+      name: 'mapred_user',
+      value: 'mapred'
+    },
+    {
+      name: 'hbase_user',
+      value: 'hbase'
+    },
+    {
+      name: 'hive_user',
+      value: 'hive'
+    }
+  ],
+
+  /**
+   * security configs, which values should be modified after APPLY CONFIGURATIONS stage
+   */
+  secureConfigs: [
+    {
+      name: 'nagios_principal_name',
+      serviceName: 'NAGIOS'
+    },
+    {
+      name: 'zookeeper_principal_name',
+      serviceName: 'ZOOKEEPER'
+    },
+    {
+      name: 'storm_principal_name',
+      serviceName: 'STORM'
+    }
+  ],
+
   secureServices: function() {
     return  this.get('content.services');
   }.property('content.services'),
 
   isBackBtnDisabled: function () {
-    return !this.get('commands').someProperty('isError', true);
+    return !this.get('commands').someProperty('isError');
   }.property('commands.@each.isCompleted'),
 
-  isOozieSelected: function () {
-    return this.get('secureServices').someProperty('serviceName', 'OOZIE');
-  }.property('secureServices'),
-
-  isHiveSelected: function () {
-    return this.get('secureServices').someProperty('serviceName', 'HIVE');
-  }.property('secureServices'),
-
-  isNagiosSelected: function () {
-    return this.get('secureServices').someProperty('serviceName', 'NAGIOS');
-  }.property('secureServices'),
-
-  isZkSelected: function () {
-    return this.get('secureServices').someProperty('serviceName', 'ZOOKEEPER');
-  }.property('secureServices'),
-
-  isWebHcatSelected: function () {
-    var installedServices = App.Service.find().mapProperty('serviceName');
-    return installedServices.contains('WEBHCAT');
-  },
-
   isSecurityApplied: function () {
     return this.get('commands').someProperty('name', 'START_SERVICES') && this.get('commands').findProperty('name', 'START_SERVICES').get('isSuccess');
   }.property('commands.@each.isCompleted'),
 
+  /**
+   * control disabled property of completion button
+   */
+  enableSubmit: function () {
+    var addSecurityController = App.router.get('addSecurityController');
+    if (this.get('commands').someProperty('isError') || this.get('commands').everyProperty('isSuccess')) {
+      this.set('isSubmitDisabled', false);
+      if (this.get('commands').someProperty('isError')) {
+        addSecurityController.setStepsEnable();
+      }
+    } else {
+      this.set('isSubmitDisabled', true);
+      addSecurityController.setLowerStepsDisable(4);
+    }
+  }.observes('commands.@each.isCompleted'),
+
+  /**
+   * clear step info
+   */
   clearStep: function () {
-    this.set('commands',[]);
+    this.set('commands', []);
     this.set('isSubmitDisabled', true);
-    this.set('isBackBtnDisabled', true);
     this.get('serviceConfigTags').clear();
   },
 
@@ -71,54 +130,68 @@ App.MainAdminSecurityAddStep4Controller = App.MainAdminSecurityProgressControlle
     }
   },
 
+  /**
+   * load step info
+   */
   loadStep: function () {
-    this.set('secureMapping', require('data/secure_mapping').slice(0));
     this.clearStep();
-    var commands = App.db.getSecurityDeployCommands();
     this.prepareSecureConfigs();
-    if (commands && commands.length > 0) {
-      commands.forEach(function (_command, index) {
-        commands[index] = App.Poll.create(_command);
-      }, this);
-      if (commands.someProperty('isError', true)) {
-        this.get('commands').pushObjects(commands);
-        this.addObserverToCommands();
-        return;
-      } else if (commands.filterProperty('isStarted', true).someProperty('isCompleted', false)) {
-        var runningCommand = commands.filterProperty('isStarted', true).findProperty('isCompleted', false);
-        runningCommand.set('isStarted', false);
-        this.get('commands').pushObjects(commands);
-      } else {
-        this.get('commands').pushObjects(commands);
-      }
-    } else {
+
+    if (!this.resumeSavedCommands()) {
       this.loadCommands();
       this.addInfoToCommands();
-      var runningOperations = App.router.get('backgroundOperationsController.services').filterProperty('isRunning');
-      var stopAllOperation = runningOperations.findProperty('name', 'Stop All Services');
-      var stopCommand = this.get('commands').findProperty('name', 'STOP_SERVICES');
-      if (stopCommand.get('name') === 'STOP_SERVICES' && stopAllOperation) {
-        stopCommand.set('requestId', stopAllOperation.get('id'));
-      }
+      this.syncStopServicesOperation();
+      this.addObserverToCommands();
+      this.moveToNextCommand();
     }
-    this.addObserverToCommands();
-    this.moveToNextCommand();
   },
 
+  /**
+   * synchronize "STOP_SERVICES" operation from BO with command of step
+   * @return {Boolean}
+   */
+  syncStopServicesOperation: function () {
+    var runningOperations = App.router.get('backgroundOperationsController.services').filterProperty('isRunning');
+    var stopAllOperation = runningOperations.findProperty('name', 'Stop All Services');
+    var stopCommand = this.get('commands').findProperty('name', 'STOP_SERVICES');
+    if (stopCommand && stopAllOperation) {
+      stopCommand.set('requestId', stopAllOperation.get('id'));
+      return true;
+    }
+    return false;
+  },
 
-  enableSubmit: function () {
-    var addSecurityController = App.router.get('addSecurityController');
-    if (this.get('commands').someProperty('isError', true) || this.get('commands').everyProperty('isSuccess', true)) {
-      this.set('isSubmitDisabled', false);
-      if (this.get('commands').someProperty('isError', true)) {
-        addSecurityController.setStepsEnable();
-      }
+  /**
+   * resume previously saved commands
+   * @return {Boolean}
+   */
+  resumeSavedCommands: function () {
+    var commands = App.db.getSecurityDeployCommands();
+    if (Em.isNone(commands) || commands.length === 0) return false;
+
+    commands.forEach(function (_command, index) {
+      commands[index] = App.Poll.create(_command);
+    }, this);
+    if (commands.someProperty('isError')) {
+      this.get('commands').pushObjects(commands);
+      this.addObserverToCommands();
+      return true;
+    } else if (commands.filterProperty('isStarted').someProperty('isCompleted', false)) {
+      var runningCommand = commands.filterProperty('isStarted').findProperty('isCompleted', false);
+      runningCommand.set('isStarted', false);
+      this.get('commands').pushObjects(commands);
     } else {
-      this.set('isSubmitDisabled', true);
-      addSecurityController.setLowerStepsDisable(4);
+      this.get('commands').pushObjects(commands);
     }
-  }.observes('commands.@each.isCompleted'),
+    this.addObserverToCommands();
+    this.moveToNextCommand();
+    return true;
+  },
 
+  /**
+   * load configs from UI side
+   * @return {Array}
+   */
   loadUiSideConfigs: function () {
     var uiConfig = [];
     var configs = this.get('secureMapping').filterProperty('foreignKey', null);
@@ -127,8 +200,8 @@ App.MainAdminSecurityAddStep4Controller = App.MainAdminSecurityProgressControlle
       if (_config.hasOwnProperty('dependedServiceName')) {
         value = this.checkServiceForConfigValue(value, _config.dependedServiceName);
       }
-      value = this.getGlobConfigValue(_config.templateName, value, _config.name);
-      uiConfig.pushObject({
+      value = this.getGlobConfigValue(_config.templateName, value);
+      uiConfig.push({
         "id": "site property",
         "name": _config.name,
         "value": value,
@@ -138,8 +211,9 @@ App.MainAdminSecurityAddStep4Controller = App.MainAdminSecurityProgressControlle
     var dependentConfig = this.get('secureMapping').filterProperty('foreignKey');
     dependentConfig.forEach(function (_config) {
       if (App.Service.find().mapProperty('serviceName').contains(_config.serviceName)) {
-        this.setConfigValue(uiConfig, _config);
-        uiConfig.pushObject({
+        this.setConfigValue(_config);
+        this.formatConfigName(uiConfig, _config);
+        uiConfig.push({
           "id": "site property",
           "name": _config._name || _config.name,
           "value": _config.value,
@@ -150,57 +224,52 @@ App.MainAdminSecurityAddStep4Controller = App.MainAdminSecurityProgressControlle
     return uiConfig;
   },
 
-
-  checkServiceForConfigValue: function (value, serviceNames) {
-    serviceNames.forEach(function (_serviceName) {
-      if (!App.Service.find().mapProperty('serviceName').contains(_serviceName.name)) {
-        value = value.replace(_serviceName.replace, '');
+  /**
+   * erase template rules from config value if service is not loaded
+   * @param value
+   * @param services
+   * @return {*}
+   */
+  checkServiceForConfigValue: function (value, services) {
+    services.forEach(function (_service) {
+      if (!App.Service.find(_service.name).get('isLoaded')) {
+        value = value.replace(_service.replace, '');
       }
     }, this);
-
     return value;
   },
 
-
   /**
    * Set all site property that are derived from other puppet-variable
+   * @param templateName
+   * @param expression
+   * @return {String|null}
    */
+  getGlobConfigValue: function (templateName, expression) {
+    if (typeof expression !== 'string') return null;
 
-  getGlobConfigValue: function (templateName, expression, name) {
     var express = expression.match(/<(.*?)>/g);
-    var value = expression;
-    if (express == null) {
-      return expression;
-    }
+    var value = null;
+    if (Em.isNone(express)) return expression;
+
     express.forEach(function (_express) {
-      //console.log("The value of template is: " + _express);
       var index = parseInt(_express.match(/\[([\d]*)(?=\])/)[1]);
-      var globValue = this.get('globalProperties').findProperty('name', templateName[index]);
-      if (globValue) {
-        console.log('The template value of templateName ' + '[' + index + ']' + ': ' + templateName[index] + ' is: ' + globValue);
-        if (value !== null) {   // if the property depends on more than one template name like <templateName[0]>/<templateName[1]> then don't proceed to the next if the prior is null or not found in the global configs
-          value = value.replace(_express, globValue.value);
-        }
-      } else {
-        /*
-         console.log("ERROR: The variable name is: " + templateName[index]);
-         console.log("ERROR: mapped config from secureMapping file has no corresponding variable in " +
-         "content.serviceConfigProperties. Two possible reasons for the error could be: 1) The service is not selected. " +
-         "and/OR 2) The service_config metadata file has no corresponding global var for the site property variable");
-         */
-        value = null;
-      }
+      var globalConfig = this.get('globalProperties').findProperty('name', templateName[index]);
+
+      value = (globalConfig) ? expression.replace(_express, globalConfig.value) : null;
     }, this);
     return value;
   },
 
   /**
-   * Set all site property that are derived from other site-properties
+   * format name of config values of global configs which match foreignKey
+   * @param uiConfig
+   * @param config
+   * @return {Boolean}
    */
-  setConfigValue: function (uiConfig, config) {
-    if (config.value == null) {
-      return;
-    }
+  formatConfigName: function (uiConfig, config) {
+    if (Em.isNone(config.value)) return false;
+
     var fkValue = config.name.match(/<(foreignKey.*?)>/g);
     if (fkValue) {
       fkValue.forEach(function (_fkValue) {
@@ -214,23 +283,36 @@ App.MainAdminSecurityAddStep4Controller = App.MainAdminSecurityProgressControlle
           config._name = config.name.replace(_fkValue, globalValue);
         }
       }, this);
+      return true;
     }
-    //For properties in the configMapping file having foreignKey and templateName properties.
+    return false;
+  },
+
+  /**
+   * Set config value with values of global configs which match template
+   * @param config
+   * @return {Boolean}
+   */
+  setConfigValue: function (config) {
+    if (Em.isNone(config.value)) return false;
 
+    //For properties in the configMapping file having foreignKey and templateName properties.
     var templateValue = config.value.match(/<(templateName.*?)>/g);
     if (templateValue) {
       templateValue.forEach(function (_value) {
         var index = parseInt(_value.match(/\[([\d]*)(?=\])/)[1]);
         var globValue = this.get('globalProperties').findProperty('name', config.templateName[index]);
-        if (globValue) {
-          config.value = config.value.replace(_value, globValue.value);
-        } else {
-          config.value = null;
-        }
+
+        config.value = (globValue) ? config.value.replace(_value, globValue.value) : null;
       }, this);
+      return true;
     }
+    return false;
   },
 
+  /**
+   * prepare secure configs
+   */
   prepareSecureConfigs: function () {
     this.loadGlobals();
     var storedConfigs = this.get('content.serviceConfigProperties').filterProperty('id', 'site property');
@@ -238,6 +320,9 @@ App.MainAdminSecurityAddStep4Controller = App.MainAdminSecurityProgressControlle
     this.set('configs', storedConfigs.concat(uiConfigs));
   },
 
+  /**
+   * load global configs
+   */
   loadGlobals: function () {
     var globals = this.get('content.serviceConfigProperties').filterProperty('id', 'puppet var');
     this.set('globalProperties', globals);
@@ -247,8 +332,11 @@ App.MainAdminSecurityAddStep4Controller = App.MainAdminSecurityProgressControlle
     this.loadPrimaryNamesToGlobals();
   },
 
+  /**
+   * push users to global configs
+   */
   loadUsersToGlobal: function () {
-    if (!this.get('serviceUsers').length) {
+    if (!this.get('serviceUsers').length)  {
       this.loadUsersFromServer();
     }
     App.router.get('mainAdminSecurityController.serviceUsers').forEach(function (_user) {
@@ -256,38 +344,46 @@ App.MainAdminSecurityAddStep4Controller = App.MainAdminSecurityProgressControlle
     }, this);
   },
 
-  loadHostNamesToGlobal: function () {
-    var oozieHostComponent = App.Service.find('OOZIE').get('hostComponents').findProperty('componentName', 'OOZIE_SERVER');
-    if (this.get('isOozieSelected') && oozieHostComponent) {
-      var oozieHostName = oozieHostComponent.get('host.hostName');
-      this.get('globalProperties').pushObject({
-        id: 'puppet var',
-        name: 'oozieserver_host',
-        value: oozieHostName
-      });
-    }
-    var hiveHostComponent = App.Service.find('HIVE').get('hostComponents').findProperty('componentName', 'HIVE_METASTORE');
-    if (this.get('isHiveSelected') && hiveHostComponent) {
-      var hiveHostName = hiveHostComponent.get('host.hostName');
-      this.get('globalProperties').pushObject({
-        id: 'puppet var',
-        name: 'hivemetastore_host',
-        value: hiveHostName
-      });
-    }
-    var webHcatComponent = App.Service.find('WEBHCAT').get('hostComponents').findProperty('componentName', 'WEBHCAT_SERVER');
-    if (this.isWebHcatSelected() && webHcatComponent) {
-      var webHcatHostName = webHcatComponent.get('host.hostName');
-      this.get('globalProperties').pushObject({
-        id: 'puppet var',
-        name: 'webhcat_server',
-        value: webHcatHostName
-      });
+  /**
+   * add component config that contain host name as value
+   * @param serviceName
+   * @param componentName
+   * @param configName
+   * @return {Boolean}
+   */
+  addHostConfig: function(serviceName, componentName, configName) {
+    var service = App.Service.find(serviceName);
+    var isServiceSecure = this.get('secureServices').someProperty('serviceName', serviceName);
+
+    if (service.get('isLoaded') && isServiceSecure) {
+      var hostComponent = service.get('hostComponents').findProperty('componentName', componentName);
+      if (hostComponent) {
+        var hostName = hostComponent.get('host.hostName');
+        this.get('globalProperties').push({
+          id: 'puppet var',
+          name: configName,
+          value: hostName
+        });
+        return true;
+      }
     }
+    return false;
   },
 
+  /**
+   * add hosts' names to global configs
+   */
+  loadHostNamesToGlobal: function () {
+    var componentsConfig = this.get('componentsConfig');
+    componentsConfig.forEach(function (host) {
+      this.addHostConfig(host.serviceName, host.componentName, host.configName);
+    }, this);
+  },
+
+  /**
+   * load static global
+   */
   loadStaticGlobal: function () {
-    var globalProperties = this.get('globalProperties');
     this.get('globalProperties').forEach(function (_property) {
       switch (_property.name) {
         case 'security_enabled':
@@ -297,21 +393,27 @@ App.MainAdminSecurityAddStep4Controller = App.MainAdminSecurityProgressControlle
     }, this);
   },
 
+  /**
+   * add principals to global properties
+   */
   loadPrimaryNamesToGlobals: function () {
     var principalProperties = this.getPrincipalNames();
     principalProperties.forEach(function (_principalProperty) {
       var name = _principalProperty.name.replace('principal', 'primary');
       var value = _principalProperty.value.split('/')[0];
-      this.get('globalProperties').pushObject({name: name, value: value});
+      this.get('globalProperties').push({name: name, value: value});
     }, this);
   },
 
+  /**
+   * gather and return global properties with "principal_name"
+   * @return {Array}
+   */
   getPrincipalNames: function () {
     var principalNames = [];
-    var allPrincipalNames = [];
     this.get('globalProperties').forEach(function (_globalProperty) {
       if (/principal_name?$/.test(_globalProperty.name)) {
-        principalNames.pushObject(_globalProperty);
+        principalNames.push(_globalProperty);
       }
     }, this);
     this.get('secureProperties').forEach(function (_secureProperty) {
@@ -319,69 +421,90 @@ App.MainAdminSecurityAddStep4Controller = App.MainAdminSecurityProgressControlle
         var principalName = principalNames.findProperty('name', _secureProperty.name);
         if (!principalName) {
           _secureProperty.value = _secureProperty.defaultValue;
-          principalNames.pushObject(_secureProperty);
+          principalNames.push(_secureProperty);
         }
       }
     }, this);
     return principalNames;
   },
 
+  /**
+   * load users from server
+   */
   loadUsersFromServer: function () {
     if (App.testMode) {
       var serviceUsers = this.get('serviceUsers');
-      serviceUsers.pushObject({id: 'puppet var', name: 'hdfs_user', value: 'hdfs'});
-      serviceUsers.pushObject({id: 'puppet var', name: 'mapred_user', value: 'mapred'});
-      serviceUsers.pushObject({id: 'puppet var', name: 'hbase_user', value: 'hbase'});
-      serviceUsers.pushObject({id: 'puppet var', name: 'hive_user', value: 'hive'});
+      this.get('testModeUsers').forEach(function (user) {
+        user.id = 'puppet var';
+        serviceUsers.push(user);
+      }, this);
     } else {
       App.router.set('mainAdminSecurityController.serviceUsers', App.db.getSecureUserInfo());
     }
   },
 
-
+  /**
+   * manage secure configs
+   * @return {Boolean}
+   */
   manageSecureConfigs: function () {
-    try {
-      this.get('serviceConfigTags').forEach(function (_serviceConfigTags) {
+    var serviceConfigTags = this.get('serviceConfigTags');
+    var secureConfigs = this.get('secureConfigs');
+    var siteProperties = this.get('configs').filterProperty('id', 'site property');
+    var globalProperties = this.get('globalProperties');
+
+    if (serviceConfigTags) {
+      serviceConfigTags.forEach(function (_serviceConfigTags) {
         _serviceConfigTags.newTagName = 'version' + (new Date).getTime();
+
         if (_serviceConfigTags.siteName === 'global') {
-          var realmName = this.get('globalProperties').findProperty('name', 'kerberos_domain');
-          if (this.get('isNagiosSelected')) {
-            var nagiosPrincipalName = this.get('globalProperties').findProperty('name', 'nagios_principal_name');
-            nagiosPrincipalName.value = nagiosPrincipalName.value + '@' + realmName.value;
-          }
-          if (this.get('isZkSelected')) {
-            var zkPrincipalName = this.get('globalProperties').findProperty('name', 'zookeeper_principal_name');
-            zkPrincipalName.value = zkPrincipalName.value + '@' + realmName.value;
-          }
-          if (this.get('secureServices').someProperty('serviceName', 'STORM')) {
-            var stormPrincipalName = this.get('globalProperties').findProperty('name', 'storm_principal_name');
-            stormPrincipalName.value = stormPrincipalName.value + '@' + realmName.value;
-          }
-          this.get('globalProperties').forEach(function (_globalProperty) {
+          secureConfigs.forEach(function (config) {
+            this.setPrincipalValue(config.serviceName, config.name);
+          }, this);
+          globalProperties.forEach(function (_globalProperty) {
             if (!/_hosts?$/.test(_globalProperty.name)) {
               _serviceConfigTags.configs[_globalProperty.name] = _globalProperty.value;
             }
           }, this);
-        }
-        else {
-          this.get('configs').filterProperty('id', 'site property').filterProperty('filename', _serviceConfigTags.siteName + '.xml').forEach(function (_config) {
+        } else {
+          siteProperties.filterProperty('filename', _serviceConfigTags.siteName + '.xml').forEach(function (_config) {
             _serviceConfigTags.configs[_config.name] = _config.value;
           }, this);
         }
       }, this);
-    } catch (err) {
+      return true;
+    } else {
       var command = this.get('commands').findProperty('name', 'APPLY_CONFIGURATIONS');
       command.set('isSuccess', false);
       command.set('isError', true);
-      if (err) {
-        console.log("Error: Error occurred while applying secure configs to the server. Error message: " + err);
-      }
       this.onJsError();
       return false;
     }
-    return true;
   },
 
+  /**
+   * set value of principal property
+   * @param serviceName
+   * @param principalName
+   * @return {Boolean}
+   */
+  setPrincipalValue: function (serviceName, principalName) {
+    var globalProperties = this.get('globalProperties');
+    var realmName = globalProperties.findProperty('name', 'kerberos_domain');
+
+    if (this.get('secureServices').someProperty('serviceName', serviceName)) {
+      var principalProperty = globalProperties.findProperty('name', principalName);
+      principalProperty.value = principalProperty.value + '@' + realmName.value;
+      return true;
+    }
+    return false;
+  },
+
+  /**
+   * send DELETE command to server to delete component
+   * @param componentName
+   * @param hostName
+   */
   deleteComponents: function(componentName, hostName) {
     App.ajax.send({
       name: 'admin.delete_component',
@@ -395,6 +518,9 @@ App.MainAdminSecurityAddStep4Controller = App.MainAdminSecurityProgressControlle
     });
   },
 
+  /**
+   * callback on successful deletion of component
+   */
   onDeleteComplete: function () {
     var deleteAtsCommand = this.get('commands').findProperty('name', 'DELETE_ATS');
     console.warn('APP_TIMELINE_SERVER doesn\'t support security mode. It has been removed from YARN service ');
@@ -402,10 +528,16 @@ App.MainAdminSecurityAddStep4Controller = App.MainAdminSecurityProgressControlle
     deleteAtsCommand.set('isSuccess', true);
   },
 
+  /**
+   * callback on failed deletion of component
+   */
   onDeleteError: function () {
     console.warn('Error: Can\'t delete APP_TIMELINE_SERVER');
   },
 
+  /**
+   * show popup when js error occurred
+   */
   onJsError: function () {
     App.ModalPopup.show({
       header: Em.I18n.t('common.error'),
@@ -415,5 +547,4 @@ App.MainAdminSecurityAddStep4Controller = App.MainAdminSecurityProgressControlle
       })
     });
   }
-
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/17a4e3e9/ambari-web/app/templates/main/admin/security/add/step4.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/admin/security/add/step4.hbs b/ambari-web/app/templates/main/admin/security/add/step4.hbs
index bbd297c..7736c0b 100644
--- a/ambari-web/app/templates/main/admin/security/add/step4.hbs
+++ b/ambari-web/app/templates/main/admin/security/add/step4.hbs
@@ -19,14 +19,14 @@
 <h2>{{t admin.security.step4.header}}</h2>
 
 {{#if view.message}}
-  <p {{bindAttr class="view.msgColor :alert"}}>{{view.message}}</p>
+    <p {{bindAttr class="view.msgColor :alert"}}>{{view.message}}</p>
 {{/if}}
 
 {{view App.MainServiceReconfigureView}}
 
 <div class="btn-area">
-  <a class="btn" {{bindAttr disabled="isBackBtnDisabled"}}
-    {{action back}}>&larr; {{t common.back}}</a>
-  <a class="btn btn-success pull-right" {{bindAttr disabled="isSubmitDisabled"}}
-    {{action done}}>{{t common.done}} </a>
+    <a class="btn" {{bindAttr disabled="isBackBtnDisabled"}}
+      {{action back}}>&larr; {{t common.back}}</a>
+    <a class="btn btn-success pull-right" {{bindAttr disabled="isSubmitDisabled"}}
+      {{action done}}>{{t common.done}} </a>
 </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/17a4e3e9/ambari-web/test/controllers/main/admin/security/add/step4_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/admin/security/add/step4_test.js b/ambari-web/test/controllers/main/admin/security/add/step4_test.js
index 24e1da2..86b8297 100644
--- a/ambari-web/test/controllers/main/admin/security/add/step4_test.js
+++ b/ambari-web/test/controllers/main/admin/security/add/step4_test.js
@@ -26,108 +26,1057 @@ require('models/service');
 
 describe('App.MainAdminSecurityAddStep4Controller', function () {
 
-  /**
-   * Test object
-   */
-  var controller = App.MainAdminSecurityAddStep4Controller.create();
+  var controller = App.MainAdminSecurityAddStep4Controller.create({
+    content: {},
+    enableSubmit: function () {
+      this._super()
+    },
+    secureMapping: [],
+    secureProperties: []
+  });
+
+  describe('#secureServices', function() {
+    it('content.services is correct', function() {
+      controller.set('content.services', [{}]);
+      expect(controller.get('secureServices')).to.eql([{}]);
+      controller.reopen({
+        secureServices: []
+      })
+    });
+  });
 
-  describe('#moveToNextCommand()', function () {
-    controller.reopen({
-      saveCommands: function(){},
-      enableSubmit: function(){},
-      loadClusterConfigs: function(){}
+  describe('#isBackBtnDisabled', function() {
+    it('commands have error', function() {
+      controller.set('commands', [Em.Object.create({
+        isError: true
+      })]);
+      expect(controller.get('isBackBtnDisabled')).to.be.false;
     });
-    App.clusterStatus.reopen({
-      setClusterStatus: function(){}
+    it('commands do not have error', function() {
+      controller.set('commands', [Em.Object.create({
+        isError: false
+      })]);
+      expect(controller.get('isBackBtnDisabled')).to.be.true;
+    });
+  });
+
+  describe('#isSecurityApplied', function() {
+    var testCases = [
+      {
+        title: 'No START_SERVICES command',
+        commands: [],
+        result: false
+      },
+      {
+        title: 'START_SERVICES is not success',
+        commands: [Em.Object.create({
+          name: 'START_SERVICES',
+          isSuccess: false
+        })],
+        result: false
+      },
+      {
+        title: 'START_SERVICES is success',
+        commands: [Em.Object.create({
+          name: 'START_SERVICES',
+          isSuccess: true
+        })],
+        result: true
+      }
+    ];
+
+    testCases.forEach(function(test){
+      it(test.title, function() {
+        controller.set('commands', test.commands);
+        expect(controller.get('isSecurityApplied')).to.equal(test.result);
+      });
     });
+  });
 
-    controller.set('commands', [
-      App.Poll.create({name: 'STOP_SERVICES', isStarted: false, isPolling: true, isCompleted: false, start: function(){}}),
-      App.Poll.create({name: 'APPLY_CONFIGURATIONS', isStarted: false, isPolling: false, isCompleted: false, start: function(){}}),
-      App.Poll.create({name: 'START_SERVICES', isStarted: false, isPolling: true, isCompleted: false, start: function(){}})
-    ]);
+  describe('#enableSubmit()', function() {
+    var mock = {
+      setStepsEnable: Em.K,
+      setLowerStepsDisable: Em.K
+    };
 
-    it('STOP_SERVICES is started', function(){
-      controller.moveToNextCommand(controller.get('commands').findProperty('name', 'STOP_SERVICES'));
-      expect(controller.get('commands').findProperty('name', 'STOP_SERVICES').get('isStarted')).to.equal(true);
+    beforeEach(function () {
+      sinon.stub(App.router, 'get', function () {
+        return mock;
+      });
+      sinon.spy(mock, 'setStepsEnable');
+      sinon.spy(mock, 'setLowerStepsDisable');
+    });
+    afterEach(function () {
+      App.router.get.restore();
+      mock.setStepsEnable.restore();
+      mock.setLowerStepsDisable.restore();
     });
 
-    it('APPLY_CONFIGURATIONS is started', function(){
-      controller.moveToNextCommand(controller.get('commands').findProperty('name', 'APPLY_CONFIGURATIONS'));
-      expect(controller.get('commands').findProperty('name', 'APPLY_CONFIGURATIONS').get('isStarted')).to.equal(true);
+    it('Command has error', function() {
+      controller.set('commands', [Em.Object.create({
+        isError: true
+      })]);
+      controller.enableSubmit();
+      expect(controller.get('isSubmitDisabled')).to.be.false;
+      expect(mock.setStepsEnable.calledOnce).to.be.true;
     });
+    it('Command is successful', function() {
+      controller.set('commands', [Em.Object.create({
+        isSuccess: true
+      })]);
+      controller.enableSubmit();
+      expect(controller.get('isSubmitDisabled')).to.be.false;
+    });
+    it('Command is in progress', function() {
+      controller.set('commands', [Em.Object.create()]);
+      controller.enableSubmit();
+      expect(controller.get('isSubmitDisabled')).to.be.true;
+      expect(mock.setLowerStepsDisable.calledWith(4)).to.be.true;
+    });
+  });
 
-    it('START_SERVICES is started', function(){
-      controller.moveToNextCommand(controller.get('commands').findProperty('name', 'START_SERVICES'));
-      expect(controller.get('commands').findProperty('name', 'START_SERVICES').get('isStarted')).to.equal(true);
+  describe('#clearStep()', function() {
+    it('Clear step info', function() {
+      controller.set('commands', [Em.Object.create()]);
+      controller.set('isSubmitDisabled', false);
+      controller.set('serviceConfigTags', [{}]);
+      controller.clearStep();
+      expect(controller.get('isSubmitDisabled')).to.be.true;
+      expect(controller.get('commands')).to.be.empty;
+      expect(controller.get('serviceConfigTags')).to.be.empty;
     });
   });
 
   describe('#loadCommands()', function() {
-    describe('YARN installed with ATS', function() {
-      beforeEach(function(){
-        controller.reopen({
-          secureServices: function() {
-            return [
-              Em.Object.create({
-                serviceName: 'YARN'
-              })
-            ];
-          }.property()
+
+    beforeEach(function () {
+      controller.get('commands').clear();
+    });
+
+    it('No YARN in secureServices', function() {
+      controller.set('secureServices', []);
+      controller.loadCommands();
+      expect(controller.get('commands.length')).to.equal(3);
+      expect(controller.get('commands').someProperty('name', 'DELETE_ATS')).to.be.false;
+    });
+    it('YARN does not have APP_TIMELINE_SERVER', function() {
+      sinon.stub(App.Service, 'find', function () {
+        return Em.Object.create({
+          hostComponents: []
+        })
+      });
+      controller.set('secureServices', [{
+        serviceName: 'YARN'
+      }]);
+      controller.loadCommands();
+      expect(controller.get('commands.length')).to.equal(3);
+      expect(controller.get('commands').someProperty('name', 'DELETE_ATS')).to.be.false;
+      App.Service.find.restore();
+    });
+    it('YARN has APP_TIMELINE_SERVER', function() {
+      sinon.stub(App.Service, 'find', function () {
+        return Em.Object.create({
+          hostComponents: [Em.Object.create({
+            componentName: 'APP_TIMELINE_SERVER'
+          })]
+        })
+      });
+      controller.set('secureServices', [{
+        serviceName: 'YARN'
+      }]);
+      controller.loadCommands();
+      expect(controller.get('commands.length')).to.equal(4);
+      expect(controller.get('commands').someProperty('name', 'DELETE_ATS')).to.be.true;
+      App.Service.find.restore();
+    });
+  });
+
+  describe('#loadStep()', function() {
+
+    beforeEach(function () {
+      sinon.stub(controller, 'clearStep', Em.K);
+      sinon.stub(controller, 'prepareSecureConfigs', Em.K);
+    });
+    afterEach(function () {
+      controller.clearStep.restore();
+      controller.prepareSecureConfigs.restore();
+      controller.resumeSavedCommands.restore();
+    });
+
+    it('Resume saved commands', function() {
+      sinon.stub(controller, 'resumeSavedCommands', function(){
+        return true;
+      });
+
+      controller.loadStep();
+      expect(controller.clearStep.calledOnce).to.be.true;
+      expect(controller.prepareSecureConfigs.calledOnce).to.be.true;
+      expect(controller.resumeSavedCommands.calledOnce).to.be.true;
+    });
+    it('No saved commands', function() {
+      sinon.stub(controller, 'resumeSavedCommands', function(){
+        return false;
+      });
+      sinon.stub(controller, 'loadCommands', Em.K);
+      sinon.stub(controller, 'addInfoToCommands', Em.K);
+      sinon.stub(controller, 'syncStopServicesOperation', Em.K);
+      sinon.stub(controller, 'addObserverToCommands', Em.K);
+      sinon.stub(controller, 'moveToNextCommand', Em.K);
+
+      controller.loadStep();
+      expect(controller.clearStep.calledOnce).to.be.true;
+      expect(controller.prepareSecureConfigs.calledOnce).to.be.true;
+      expect(controller.resumeSavedCommands.calledOnce).to.be.true;
+
+      controller.loadCommands.restore();
+      controller.addInfoToCommands.restore();
+      controller.syncStopServicesOperation.restore();
+      controller.addObserverToCommands.restore();
+      controller.moveToNextCommand.restore();
+    });
+  });
+
+  describe('#syncStopServicesOperation()', function() {
+
+    afterEach(function () {
+      App.router.get.restore();
+    });
+
+    it('No running operations', function() {
+      sinon.stub(App.router, 'get', function(){
+        return [];
+      });
+
+      expect(controller.syncStopServicesOperation()).to.be.false;
+    });
+    it('Running operation is not Stop All Services', function() {
+      sinon.stub(App.router, 'get', function(){
+        return [Em.Object.create({isRunning: true})];
+      });
+
+      expect(controller.syncStopServicesOperation()).to.be.false;
+    });
+    it('No STOP_SERVICES in commands', function() {
+      sinon.stub(App.router, 'get', function(){
+        return [Em.Object.create({
+          isRunning: true,
+          name: 'Stop All Services'
+        })];
+      });
+      controller.set('commands', []);
+
+      expect(controller.syncStopServicesOperation()).to.be.false;
+    });
+    it('Sync stop services commands', function() {
+      sinon.stub(App.router, 'get', function(){
+        return [Em.Object.create({
+          isRunning: true,
+          name: 'Stop All Services',
+          id: 1
+        })];
+      });
+      controller.set('commands', [Em.Object.create({
+        name: 'STOP_SERVICES'
+      })]);
+
+      expect(controller.syncStopServicesOperation()).to.be.true;
+      expect(controller.get('commands').findProperty('name', 'STOP_SERVICES').get('requestId')).to.equal(1);
+    });
+  });
+
+  describe('#resumeSavedCommands()', function() {
+
+    beforeEach(function(){
+      sinon.stub(controller, 'addObserverToCommands', Em.K);
+      sinon.stub(controller, 'moveToNextCommand', Em.K);
+      controller.set('commands', []);
+    });
+    afterEach(function(){
+      controller.moveToNextCommand.restore();
+      controller.addObserverToCommands.restore();
+      App.db.getSecurityDeployCommands.restore();
+    });
+
+
+    it('Commands is null', function() {
+      sinon.stub(App.db, 'getSecurityDeployCommands', function(){
+        return null;
+      });
+      expect(controller.resumeSavedCommands()).to.be.false;
+    });
+    it('Commands is empty', function() {
+      sinon.stub(App.db, 'getSecurityDeployCommands', function(){
+        return [];
+      });
+      expect(controller.resumeSavedCommands()).to.be.false;
+    });
+    it('Command has error', function() {
+      sinon.stub(App.db, 'getSecurityDeployCommands', function(){
+        return [{
+          isError: true,
+          name: 'command1'
+        }];
+      });
+      expect(controller.resumeSavedCommands()).to.be.true;
+      expect(controller.get('commands').mapProperty('name')).to.eql(['command1']);
+      expect(controller.addObserverToCommands.calledOnce).to.be.true;
+    });
+    it('Command in progress', function() {
+      sinon.stub(App.db, 'getSecurityDeployCommands', function(){
+        return [{
+          isStarted: true,
+          isCompleted: false,
+          name: 'command1'
+        }];
+      });
+      expect(controller.resumeSavedCommands()).to.be.true;
+      expect(controller.get('commands').mapProperty('name')).to.eql(['command1']);
+      expect(controller.get('commands').findProperty('name', 'command1').get('isStarted')).to.be.false;
+      expect(controller.addObserverToCommands.calledOnce).to.be.true;
+      expect(controller.moveToNextCommand.calledOnce).to.be.true;
+    });
+    it('Command completed', function() {
+      sinon.stub(App.db, 'getSecurityDeployCommands', function(){
+        return [{
+          isCompleted: true,
+          name: 'command1'
+        }];
+      });
+      expect(controller.resumeSavedCommands()).to.be.true;
+      expect(controller.get('commands').mapProperty('name')).to.eql(['command1']);
+      expect(controller.addObserverToCommands.calledOnce).to.be.true;
+      expect(controller.moveToNextCommand.calledOnce).to.be.true;
+    });
+  });
+
+  describe('#loadUiSideConfigs()', function() {
+
+    beforeEach(function(){
+      sinon.stub(controller, 'getGlobConfigValue', function(arg1, arg2){
+        return arg2;
+      });
+      sinon.stub(controller, 'checkServiceForConfigValue', function() {
+        return 'value2';
+      });
+      sinon.stub(controller, 'setConfigValue', Em.K);
+      sinon.stub(controller, 'formatConfigName', Em.K);
+    });
+    afterEach(function(){
+      controller.getGlobConfigValue.restore();
+      controller.checkServiceForConfigValue.restore();
+      controller.setConfigValue.restore();
+      controller.formatConfigName.restore();
+    });
+
+    it('secureMapping is empty', function() {
+      controller.set('secureMapping', []);
+
+      expect(controller.loadUiSideConfigs()).to.be.empty;
+    });
+    it('Config does not have dependedServiceName', function() {
+      controller.set('secureMapping', [{
+        name: 'config1',
+        value: 'value1',
+        filename: 'file1',
+        foreignKey: null
+      }]);
+
+      expect(controller.loadUiSideConfigs()).to.eql([{
+        "id": "site property",
+        "name": 'config1',
+        "value": 'value1',
+        "filename": 'file1'
+      }]);
+    });
+    it('Config has dependedServiceName', function() {
+      controller.set('secureMapping', [{
+        name: 'config1',
+        value: 'value1',
+        filename: 'file1',
+        foreignKey: null,
+        dependedServiceName: 'service'
+      }]);
+
+      expect(controller.loadUiSideConfigs()).to.eql([{
+        "id": "site property",
+        "name": 'config1',
+        "value": 'value2',
+        "filename": 'file1'
+      }]);
+    });
+    it('Config has non-existent serviceName', function() {
+      controller.set('secureMapping', [{
+        name: 'config1',
+        value: 'value1',
+        filename: 'file1',
+        foreignKey: true,
+        serviceName: 'service'
+      }]);
+      sinon.stub(App.Service, 'find', function(){
+        return [];
+      });
+
+      expect(controller.loadUiSideConfigs()).to.be.empty;
+      App.Service.find.restore();
+    });
+    it('Config has correct serviceName', function() {
+      controller.set('secureMapping', [{
+        name: 'config1',
+        value: 'value1',
+        filename: 'file1',
+        foreignKey: true,
+        serviceName: 'HDFS'
+      }]);
+      sinon.stub(App.Service, 'find', function(){
+        return [{serviceName: 'HDFS'}];
+      });
+
+      expect(controller.loadUiSideConfigs()).to.eql([{
+        "id": "site property",
+        "name": 'config1',
+        "value": 'value1',
+        "filename": 'file1'
+      }]);
+      expect(controller.setConfigValue.calledOnce).to.be.true;
+      expect(controller.formatConfigName.calledOnce).to.be.true;
+      App.Service.find.restore();
+    });
+  });
+
+  describe('#checkServiceForConfigValue()', function() {
+    it('services is empty', function() {
+      var services = [];
+
+      expect(controller.checkServiceForConfigValue('value1', services)).to.equal('value1');
+    });
+    it('Service is loaded', function() {
+      var services = [{}];
+      sinon.stub(App.Service, 'find', function () {
+        return Em.Object.create({isLoaded: false});
+      });
+
+      expect(controller.checkServiceForConfigValue('value1', services)).to.equal('value1');
+
+      App.Service.find.restore();
+    });
+    it('Service is not loaded', function() {
+      var services = [{
+        replace: 'val'
+      }];
+      sinon.stub(App.Service, 'find', function () {
+        return Em.Object.create({isLoaded: false});
+      });
+
+      expect(controller.checkServiceForConfigValue('value1', services)).to.equal('ue1');
+
+      App.Service.find.restore();
+    });
+  });
+
+  describe('#getGlobConfigValue()', function() {
+    var testCases = [
+      {
+        title: 'Incorrect expression',
+        arguments: {
+          templateName: [],
+          expression: 'expression'
+        },
+        result: 'expression'
+      },
+      {
+        title: 'No such property in global configs',
+        arguments: {
+          templateName: ['config2'],
+          expression: '<[0]>'
+        },
+        result: null
+      },
+      {
+        title: 'Property in global configs',
+        arguments: {
+          templateName: ['config1'],
+          expression: '<[0]>'
+        },
+        result: 'value1'
+      }
+    ];
+
+    testCases.forEach(function(test){
+      it(test.title, function() {
+        controller.set('globalProperties', [{
+          name: 'config1',
+          value: 'value1'
+        }]);
+        expect(controller.getGlobConfigValue(test.arguments.templateName, test.arguments.expression)).to.equal(test.result);
+      });
+    });
+  });
+
+  describe('#formatConfigName()', function() {
+    it('config.value is null', function() {
+      var config = {
+        value: null
+      };
+
+      expect(controller.formatConfigName([], config)).to.be.false;
+    });
+    it('config.name does not contain foreignKey', function() {
+      var config = {
+        value: 'value1',
+        name: 'config1'
+      };
+
+      expect(controller.formatConfigName([], config)).to.be.false;
+    });
+    it('globalProperties is empty, use uiConfig', function() {
+      var config = {
+        value: 'value1',
+        name: '<foreignKey[0]>',
+        foreignKey: ['key1']
+      };
+      controller.set('globalProperties', []);
+      var uiConfig = [{
+        name: 'key1',
+        value: 'globalValue1'
+      }];
+
+      expect(controller.formatConfigName(uiConfig, config)).to.be.true;
+      expect(config._name).to.equal('globalValue1');
+    });
+    it('uiConfig is empty, use globalProperties', function() {
+      var config = {
+        value: 'value1',
+        name: '<foreignKey[0]>',
+        foreignKey: ['key1']
+      };
+      controller.set('globalProperties', [{
+        name: 'key1',
+        value: 'globalValue1'
+      }]);
+      var uiConfig = [];
+
+      expect(controller.formatConfigName(uiConfig, config)).to.be.true;
+      expect(config._name).to.equal('globalValue1');
+    });
+  });
+
+  describe('#setConfigValue()', function() {
+    it('config.value is null', function() {
+      var config = {
+        value: null
+      };
+
+      expect(controller.setConfigValue(config)).to.be.false;
+    });
+    it('config.value does not match "templateName"', function() {
+      var config = {
+        value: ''
+      };
+
+      expect(controller.setConfigValue(config)).to.be.false;
+    });
+    it('No such property in global configs', function() {
+      var config = {
+        value: '<templateName[0]>',
+        templateName: ['config1']
+      };
+      controller.set('globalProperties', []);
+
+      expect(controller.setConfigValue(config)).to.be.true;
+      expect(config.value).to.be.null;
+    });
+    it('Property in global configs', function() {
+      var config = {
+        value: '<templateName[0]>',
+        templateName: ['config1']
+      };
+      controller.set('globalProperties', [{
+        name: 'config1',
+        value: 'value1'
+      }]);
+
+      expect(controller.setConfigValue(config)).to.be.true;
+      expect(config.value).to.equal('value1');
+    });
+  });
+
+  describe('#prepareSecureConfigs()', function() {
+
+    beforeEach(function(){
+      sinon.stub(controller, 'loadGlobals', Em.K);
+      sinon.stub(controller, 'loadUiSideConfigs', function(){
+        return [{name: 'config1'}];
+      });
+    });
+    afterEach(function(){
+      controller.loadGlobals.restore();
+      controller.loadUiSideConfigs.restore();
+    });
+
+    it('content.serviceConfigProperties is empty', function() {
+      controller.set('content.serviceConfigProperties', []);
+
+      controller.prepareSecureConfigs();
+      expect(controller.loadGlobals.calledOnce).to.be.true;
+      expect(controller.loadUiSideConfigs.calledOnce).to.be.true;
+      expect(controller.get('configs')).to.eql([{name: 'config1'}]);
+    });
+    it('content.serviceConfigProperties is empty', function() {
+      controller.set('content.serviceConfigProperties', [{
+        id: 'site property',
+        name: 'config2'
+      }]);
+
+      controller.prepareSecureConfigs();
+      expect(controller.loadGlobals.calledOnce).to.be.true;
+      expect(controller.loadUiSideConfigs.calledOnce).to.be.true;
+      expect(controller.get('configs')).to.eql([
+        {
+          id: 'site property',
+          name: 'config2'
+        },
+        {name: 'config1'}
+      ]);
+    });
+  });
+
+  describe('#loadGlobals()', function() {
+
+    beforeEach(function(){
+      sinon.stub(controller, 'loadStaticGlobal', Em.K);
+      sinon.stub(controller, 'loadUsersToGlobal', Em.K);
+      sinon.stub(controller, 'loadHostNamesToGlobal', Em.K);
+      sinon.stub(controller, 'loadPrimaryNamesToGlobals', Em.K);
+    });
+    afterEach(function(){
+      controller.loadStaticGlobal.restore();
+      controller.loadUsersToGlobal.restore();
+      controller.loadHostNamesToGlobal.restore();
+      controller.loadPrimaryNamesToGlobals.restore();
+    });
+
+    it('content.serviceConfigProperties is empty', function() {
+      controller.set('content.serviceConfigProperties', []);
+
+      controller.loadGlobals();
+      expect(controller.loadStaticGlobal.calledOnce).to.be.true;
+      expect(controller.loadUsersToGlobal.calledOnce).to.be.true;
+      expect(controller.loadHostNamesToGlobal.calledOnce).to.be.true;
+      expect(controller.loadPrimaryNamesToGlobals.calledOnce).to.be.true;
+      expect(controller.get('globalProperties')).to.be.empty;
+    });
+    it('content.serviceConfigProperties is correct', function() {
+      controller.set('content.serviceConfigProperties', [{
+        id: 'puppet var',
+        name: 'config1'
+      }]);
+
+      controller.loadGlobals();
+      expect(controller.loadStaticGlobal.calledOnce).to.be.true;
+      expect(controller.loadUsersToGlobal.calledOnce).to.be.true;
+      expect(controller.loadHostNamesToGlobal.calledOnce).to.be.true;
+      expect(controller.loadPrimaryNamesToGlobals.calledOnce).to.be.true;
+      expect(controller.get('globalProperties')).to.eql([{
+        id: 'puppet var',
+        name: 'config1'
+      }]);
+    });
+  });
+
+  describe('#loadUsersToGlobal()', function() {
+
+    beforeEach(function(){
+      sinon.stub(controller, 'loadUsersFromServer', Em.K);
+    });
+    afterEach(function(){
+      controller.loadUsersFromServer.restore();
+      App.router.get.restore();
+    });
+
+    it('serviceUsers is empty', function() {
+      sinon.stub(App.router, 'get', function(){
+        return [];
+      });
+      controller.set('serviceUsers', []);
+      controller.set('globalProperties', []);
+
+      controller.loadUsersToGlobal();
+      expect(controller.loadUsersFromServer.calledOnce).to.be.true;
+      expect(controller.get('globalProperties')).to.be.empty;
+    });
+    it('serviceUsers is correct', function() {
+      sinon.stub(App.router, 'get', function(){
+        return [{name: 'user1'}];
+      });
+      controller.set('serviceUsers', [{}]);
+      controller.set('globalProperties', []);
+
+      controller.loadUsersToGlobal();
+      expect(controller.loadUsersFromServer.called).to.be.false;
+      expect(controller.get('globalProperties').mapProperty('name')).to.eql(['user1']);
+    });
+  });
+
+  describe('#addHostConfig()', function() {
+
+    afterEach(function () {
+      App.Service.find.restore();
+    });
+
+    it('No such service loaded', function() {
+      sinon.stub(App.Service, 'find', function(){
+        return Em.Object.create({isLoaded: false});
+      });
+
+      expect(controller.addHostConfig('service1', 'comp1', 'config1')).to.be.false;
+    });
+    it('No such service in secureServices', function() {
+      sinon.stub(App.Service, 'find', function(){
+        return Em.Object.create({isLoaded: true});
+      });
+      controller.set('secureServices', []);
+
+      expect(controller.addHostConfig('service1', 'comp1', 'config1')).to.be.false;
+    });
+    it('Service does not have such host-component', function() {
+      sinon.stub(App.Service, 'find', function(){
+        return Em.Object.create({
+          isLoaded: true,
+          hostComponents: []
         });
-        controller.set('commands', []);
-        controller.set('totalSteps', 3);
-        var service = {
-          id: 'YARN',
-          service_name: 'YARN',
-          host_components: ['APP_TIMLINE_SERVER_c6401.ambari.apache.org']
-        };
-        var hostComponent = {
-          component_name: 'APP_TIMELINE_SERVER',
-          id: 'APP_TIMLINE_SERVER_c6401.ambari.apache.org',
-          service_id: 'YARN'
-        };
-        App.store.load(App.HostComponent, hostComponent);
-        App.store.load(App.Service, service);
-        controller.loadCommands();
-      });
-
-      it('delete ATS component stage should be after APPLY_CONFIGURATIONS', function() {
-        expect(controller.get('commands').indexOf(controller.get('commands').findProperty('name','DELETE_ATS'))).to.eql(2);
-      });
-
-      it('commands length should be equal to 4', function() {
-        expect(controller.get('commands').length).to.eql(4);
-      });
-
-    });
-
-    describe('YARN installed without ATS', function() {
-      beforeEach(function(){
-        controller.reopen({
-          secureServices: function() {
-            return [
-              Em.Object.create({
-                serviceName: 'YARN'
-              })
-            ];
-          }.property()
+      });
+      controller.set('secureServices', [{
+        serviceName: 'service1'
+      }]);
+
+      expect(controller.addHostConfig('service1', 'comp1', 'config1')).to.be.false;
+    });
+    it('Push config to globalProperties', function() {
+      sinon.stub(App.Service, 'find', function(){
+        return Em.Object.create({
+          isLoaded: true,
+          hostComponents: [Em.Object.create({
+            componentName: 'comp1',
+            host: {hostName: 'host1'}
+          })]
         });
-        controller.set('commands', []);
-        controller.set('totalSteps', 3);
-        var service = {
-          id: 'YARN',
-          service_name: 'YARN',
-          host_components: []
-        };
-        App.store.load(App.Service, service);
-        controller.loadCommands();
       });
+      controller.set('secureServices', [{
+        serviceName: 'service1'
+      }]);
+
+      controller.set('globalProperties', []);
+
+      expect(controller.addHostConfig('service1', 'comp1', 'config1')).to.be.true;
+      expect(controller.get('globalProperties')).to.eql([{
+        id: 'puppet var',
+        name: 'config1',
+        value: 'host1'
+      }]);
+    });
+  });
+
+  describe('#loadHostNamesToGlobal()', function() {
+
+    beforeEach(function () {
+      sinon.stub(controller, 'addHostConfig', Em.K);
+    });
+    afterEach(function () {
+      controller.addHostConfig.restore();
+    });
+
+    it('componentsConfig is empty', function() {
+      controller.set('componentsConfig', []);
+
+      controller.loadHostNamesToGlobal();
+      expect(controller.addHostConfig.called).to.be.false;
+    });
+    it('componentsConfig is correct', function() {
+      controller.set('componentsConfig', [{
+        serviceName: 'service1',
+        componentName: 'comp1',
+        configName: 'config1'
+      }]);
+
+      controller.loadHostNamesToGlobal();
+      expect(controller.addHostConfig.calledWith('service1', 'comp1', 'config1')).to.be.true;
+    });
+  });
+
+  describe('#loadStaticGlobal()', function() {
+    it('globalProperties contains "security_enabled" property', function() {
+      controller.set('globalProperties', [{
+        name: 'security_enabled'
+      }]);
+
+      controller.loadStaticGlobal();
+      expect(controller.get('globalProperties').findProperty('name', 'security_enabled').value).to.equal('true');
+    });
+  });
+
+  describe('#loadPrimaryNamesToGlobals()', function() {
+
+    beforeEach(function(){
+      controller.set('globalProperties', []);
+    });
+    afterEach(function () {
+      controller.getPrincipalNames.restore();
+    });
+
+    it('No principal names', function() {
+      sinon.stub(controller, 'getPrincipalNames', function(){
+        return [];
+      });
+
+      controller.loadPrimaryNamesToGlobals();
+      expect(controller.get('globalProperties')).to.be.empty;
+    });
+    it('Principal name does not contain "principal"', function() {
+      sinon.stub(controller, 'getPrincipalNames', function(){
+        return [{
+          name: 'config1',
+          value: 'value2/value1'
+        }];
+      });
+
+      controller.loadPrimaryNamesToGlobals();
+      expect(controller.get('globalProperties')).to.eql([{name: 'config1', value: 'value2'}]);
+    });
+    it('Principal name contains "principal"', function() {
+      sinon.stub(controller, 'getPrincipalNames', function(){
+        return [{
+          name: 'principal1',
+          value: 'value1'
+        }];
+      });
+
+      controller.loadPrimaryNamesToGlobals();
+      expect(controller.get('globalProperties')).to.eql([{name: 'primary1', value: 'value1'}]);
+    });
+  });
+
+  describe('#getPrincipalNames()', function() {
 
-      it('commands length should be equal to 3', function() {
-        expect(controller.get('commands').length).to.eql(3);
+    beforeEach(function () {
+      controller.set('globalProperties', []);
+      controller.set('secureProperties', []);
+    });
+
+    it('globalProperties and secureProperties are empty', function() {
+      expect(controller.getPrincipalNames()).to.be.empty;
+    });
+    it('global property name does not match "principal_name"', function() {
+      controller.set('globalProperties', [{
+        name: 'config1'
+      }]);
+      expect(controller.getPrincipalNames()).to.be.empty;
+    });
+    it('secure property name does not match "principal_name"', function() {
+      controller.set('secureProperties', [{
+        name: 'config1'
+      }]);
+      expect(controller.getPrincipalNames()).to.be.empty;
+    });
+    it('global property name matches "principal_name"', function() {
+      controller.set('globalProperties', [{
+        name: 'principal_name'
+      }]);
+      expect(controller.getPrincipalNames()).to.eql([{
+        name: 'principal_name'
+      }]);
+    });
+    it('property with such name already exists', function() {
+      controller.set('globalProperties', [{
+        name: 'principal_name'
+      }]);
+      controller.set('secureProperties', [{
+        name: 'principal_name'
+      }]);
+      expect(controller.getPrincipalNames().mapProperty('name')).to.eql(['principal_name']);
+    });
+    it('global and secure property name matches "principal_name"', function() {
+      controller.set('globalProperties', [{
+        name: 'global_principal_name'
+      }]);
+      controller.set('secureProperties', [{
+        name: 'secure_principal_name',
+        defaultValue: 'value1'
+      }]);
+      expect(controller.getPrincipalNames().mapProperty('name')).to.eql(['global_principal_name', 'secure_principal_name']);
+      expect(controller.getPrincipalNames().findProperty('name', 'secure_principal_name').value).to.equal('value1');
+    });
+  });
+
+  describe('#loadUsersFromServer()', function() {
+    it('testMode = true', function() {
+      controller.set('testModeUsers', [{
+        name: 'user1',
+        value: 'value1'
+      }]);
+      controller.set('serviceUsers', []);
+      App.testMode = true;
+
+      controller.loadUsersFromServer();
+      expect(controller.get('serviceUsers')).to.eql([{
+        name: 'user1',
+        value: 'value1',
+        id: 'puppet var'
+      }]);
+    });
+    it('testMode = false', function() {
+      sinon.stub(App.router, 'set', Em.K);
+      sinon.stub(App.db, 'getSecureUserInfo', function(){
+        return [];
       });
+      App.testMode = false;
+
+      controller.loadUsersFromServer();
+      expect(App.db.getSecureUserInfo.calledOnce).to.be.true;
+      expect(App.router.set.calledWith('mainAdminSecurityController.serviceUsers', [])).to.be.true;
+
+      App.router.set.restore();
+      App.db.getSecureUserInfo.restore();
+    });
+  });
+
+  describe('#manageSecureConfigs()', function() {
+
+    beforeEach(function () {
+      sinon.stub(controller, 'setPrincipalValue', Em.K);
+    });
+    afterEach(function () {
+      controller.setPrincipalValue.restore();
+    });
+
+    it('serviceConfigTags is null', function() {
+      sinon.stub(controller, 'onJsError', Em.K);
+      controller.set('serviceConfigTags', null);
+      controller.set('configs', [{id: 'site property'}]);
+      controller.set('commands', [Em.Object.create({
+        name: 'APPLY_CONFIGURATIONS'
+      })]);
+
+      expect(controller.manageSecureConfigs()).to.be.false;
+      expect(controller.onJsError.calledOnce).to.be.true;
+      expect(controller.get('commands').findProperty('name', 'APPLY_CONFIGURATIONS').get('isSuccess')).to.be.false;
+      expect(controller.get('commands').findProperty('name', 'APPLY_CONFIGURATIONS').get('isError')).to.be.true;
+
+      controller.onJsError.restore();
+    });
+    it('Add configs from site-*.xml', function() {
+      controller.set('serviceConfigTags', [{
+        siteName: 'site1',
+        configs: {}
+      }]);
+      controller.set('configs', [{
+        id: 'site property',
+        name: 'config1',
+        value: "value1",
+        filename: 'site1.xml'
+      }]);
+
+      expect(controller.manageSecureConfigs()).to.be.true;
+      expect(controller.get('serviceConfigTags')[0].configs).to.eql({'config1': 'value1'});
+    });
+    it('Add configs from global.xml, config matches "_hosts"', function() {
+      controller.set('serviceConfigTags', [{
+        siteName: 'global',
+        configs: {}
+      }]);
+      controller.set('globalProperties', [{
+        id: 'site property',
+        name: 'config1_hosts',
+        value: "value1",
+        filename: 'site1.xml'
+      }]);
+      controller.set('secureConfigs', [{
+        serviceName: 'service1',
+        name: 'config1'
+      }]);
+
+      expect(controller.manageSecureConfigs()).to.be.true;
+      expect(controller.get('serviceConfigTags')[0].configs).to.eql({});
+      expect(controller.setPrincipalValue.calledWith('service1', 'config1')).to.be.true;
+    });
+    it('Add configs from global.xml, config does not match "_hosts"', function() {
+      controller.set('serviceConfigTags', [{
+        siteName: 'global',
+        configs: {}
+      }]);
+      controller.set('globalProperties', [{
+        id: 'site property',
+        name: 'config1',
+        value: "value1",
+        filename: 'site1.xml'
+      }]);
+      controller.set('secureConfigs', [{
+        serviceName: 'service1',
+        name: 'config1'
+      }]);
+
+      expect(controller.manageSecureConfigs()).to.be.true;
+      expect(controller.get('serviceConfigTags')[0].configs).to.eql({'config1': 'value1'});
+      expect(controller.setPrincipalValue.calledWith('service1', 'config1')).to.be.true;
+    });
+  });
+
+  describe('#setPrincipalValue()', function() {
+    it('secureServices does not contain such service', function() {
+      controller.set('secureServices', []);
+
+      expect(controller.setPrincipalValue('service1', 'principal1')).to.be.false;
+    });
+    it('secureServices contains such service', function() {
+      controller.set('secureServices', [{
+        serviceName: 'service1'
+      }]);
+      controller.set('globalProperties', [
+        {
+          name: 'kerberos_domain',
+          value: 'value1'
+        },
+        {
+          name: 'principal1',
+          value: 'value2'
+        }
+      ]);
+
+      expect(controller.setPrincipalValue('service1', 'principal1')).to.be.true;
+      expect(controller.get('globalProperties').findProperty('name', 'principal1').value).to.equal('value2@value1');
+    });
+  });
+
+  describe('#deleteComponents()', function() {
+    it('Send ajax', function() {
+      sinon.stub(App.ajax, 'send', Em.K);
+
+      controller.deleteComponents('comp1', 'host1');
+      expect(App.ajax.send.calledOnce).to.be.true;
+
+      App.ajax.send.restore();
     });
+  });
+
+  describe('#onDeleteComplete()', function() {
+    it('', function() {
+      controller.set('commands', [Em.Object.create({
+        name: 'DELETE_ATS'
+      })]);
+
+      controller.onDeleteComplete();
+      expect(controller.get('commands').findProperty('name', 'DELETE_ATS').get('isError')).to.be.false;
+      expect(controller.get('commands').findProperty('name', 'DELETE_ATS').get('isSuccess')).to.be.true;
+    });
+  });
+
+  describe('#onJsError()', function() {
+    it('Show popup', function() {
+      sinon.stub(App.ModalPopup, 'show', Em.K);
 
+      controller.onJsError();
+      expect(App.ModalPopup.show.calledOnce).to.be.true;
+
+      App.ModalPopup.show.restore();
+    });
   });
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/17a4e3e9/ambari-web/test/controllers/main/admin/security/disable_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/admin/security/disable_test.js b/ambari-web/test/controllers/main/admin/security/disable_test.js
index 9656734..c643e38 100644
--- a/ambari-web/test/controllers/main/admin/security/disable_test.js
+++ b/ambari-web/test/controllers/main/admin/security/disable_test.js
@@ -37,11 +37,20 @@ describe('App.MainAdminSecurityDisableController', function () {
       }
     };
 
+    var mock = {
+      setStepsEnable: Em.K,
+      setLowerStepsDisable: Em.K
+    };
+
     beforeEach(function () {
       sinon.stub(App.db, "getSecurityDeployCommands", context.getSecurityDeployCommands);
+      sinon.stub(App.router, 'get', function () {
+        return mock;
+      });
     });
     afterEach(function () {
       App.db.getSecurityDeployCommands.restore();
+      App.router.get.restore();
     });
 
     it('commands are absent in local storage', function () {
@@ -190,7 +199,7 @@ describe('App.MainAdminSecurityDisableController', function () {
 
     beforeEach(function () {
       sinon.spy(controller, "deleteDisabledGlobalConfigs");
-      sinon.spy(controller, "modifySiteConfigs");
+      sinon.stub(controller, "modifySiteConfigs", Em.K);
     });
     afterEach(function () {
       controller.deleteDisabledGlobalConfigs.restore();
@@ -373,7 +382,9 @@ describe('App.MainAdminSecurityDisableController', function () {
         title: 'secureMapping and _serviceConfigTags are empty',
         content: {
           secureMapping: [],
-          _serviceConfigTags: {}
+          _serviceConfigTags: {
+            configs: {}
+          }
         },
         result: true
       }
@@ -430,7 +441,8 @@ describe('App.MainAdminSecurityDisableController', function () {
       var secureMapping = [
         {
           filename: 'site1.xml',
-          name: 'config2'
+          name: 'config2',
+          nonSecureValue: 'nonSecureValue'
         }
       ];
       var _serviceConfigTags = {
@@ -443,7 +455,7 @@ describe('App.MainAdminSecurityDisableController', function () {
         'config2': 'value'
       });
       expect(controller.modifySiteConfigs(secureMapping, _serviceConfigTags)).to.be.true;
-      expect(_serviceConfigTags.configs.config2).to.equal('value');
+      expect(_serviceConfigTags.configs.config2).to.equal('nonSecureValue');
     });
   });
 });