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 2016/12/22 14:54:00 UTC

ambari git commit: AMBARI-19280 Cover global controllers with unit tests. (atkach)

Repository: ambari
Updated Branches:
  refs/heads/trunk 633ac3bd5 -> 98a83c5f9


AMBARI-19280 Cover global controllers with unit tests. (atkach)


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

Branch: refs/heads/trunk
Commit: 98a83c5f909b5fe5b8debe249496978bd3c6c7d2
Parents: 633ac3b
Author: Andrii Tkach <at...@apache.org>
Authored: Thu Dec 22 13:16:46 2016 +0200
Committer: Andrii Tkach <at...@apache.org>
Committed: Thu Dec 22 16:50:55 2016 +0200

----------------------------------------------------------------------
 .../global/background_operations_controller.js  |  60 +-
 .../controllers/global/cluster_controller.js    | 179 +++---
 .../global/configuration_controller.js          |  14 +-
 .../app/controllers/global/update_controller.js |   5 +-
 .../global/user_settings_controller.js          |  67 ++-
 .../global/background_operations_test.js        | 241 +++++++-
 .../global/cluster_controller_test.js           | 592 +++++++++++++++++++
 .../global/configuration_controller_test.js     | 163 +++++
 .../global/errors_handler_controller_test.js    |  10 +
 .../global/update_controller_test.js            | 122 ++++
 .../global/user_settings_controller_test.js     | 300 ++++++++++
 11 files changed, 1607 insertions(+), 146 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/98a83c5f/ambari-web/app/controllers/global/background_operations_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/global/background_operations_controller.js b/ambari-web/app/controllers/global/background_operations_controller.js
index 9612141..3a011f5 100644
--- a/ambari-web/app/controllers/global/background_operations_controller.js
+++ b/ambari-web/app/controllers/global/background_operations_controller.js
@@ -320,36 +320,46 @@ App.BackgroundOperationsController = Em.Controller.extend({
 
   /**
    * parse request context and if keyword "_PARSE_" is present then format it
-   * @param requestContext
+   * @param {string} requestContext
    * @return {Object}
    */
   parseRequestContext: function (requestContext) {
-    var parsedRequestContext;
-    var service;
-    var contextCommand;
+    var context = {};
     if (requestContext) {
       if (requestContext.indexOf(App.BackgroundOperationsController.CommandContexts.PREFIX) !== -1) {
-        var contextSplits = requestContext.split('.');
-        contextCommand = contextSplits[1];
-        service = contextSplits[2];
-        switch(contextCommand){
-        case "STOP":
-        case "START":
-          if (service === 'ALL_SERVICES') {
-            parsedRequestContext = Em.I18n.t("requestInfo." + contextCommand.toLowerCase()).format(Em.I18n.t('common.allServices'));
-          } else {
-            parsedRequestContext = Em.I18n.t("requestInfo." + contextCommand.toLowerCase()).format(App.format.role(service, true));
-          }
-          break;
-        case "ROLLING-RESTART":
-          parsedRequestContext = Em.I18n.t("rollingrestart.rest.context").format(App.format.role(service, true), contextSplits[3], contextSplits[4]);
-          break;
-        }
+        context = this.getRequestContextWithPrefix(requestContext);
       } else {
-        parsedRequestContext = requestContext;
+        context.parsedRequestContext = requestContext;
       }
     } else {
-      parsedRequestContext = Em.I18n.t('requestInfo.unspecified');
+      context.parsedRequestContext = Em.I18n.t('requestInfo.unspecified');
+    }
+    return context;
+  },
+
+  /**
+   *
+   * @param {string} requestContext
+   * @returns {{requestContext: *, dependentService: *, contextCommand: *}}
+   */
+  getRequestContextWithPrefix: function (requestContext) {
+    var contextSplits = requestContext.split('.'),
+        parsedRequestContext,
+        contextCommand = contextSplits[1],
+        service = contextSplits[2];
+
+    switch (contextCommand) {
+      case "STOP":
+      case "START":
+        if (service === 'ALL_SERVICES') {
+          parsedRequestContext = Em.I18n.t("requestInfo." + contextCommand.toLowerCase()).format(Em.I18n.t('common.allServices'));
+        } else {
+          parsedRequestContext = Em.I18n.t("requestInfo." + contextCommand.toLowerCase()).format(App.format.role(service, true));
+        }
+        break;
+      case "ROLLING-RESTART":
+        parsedRequestContext = Em.I18n.t("rollingrestart.rest.context").format(App.format.role(service, true), contextSplits[3], contextSplits[4]);
+        break;
     }
     return {
       requestContext: parsedRequestContext,
@@ -363,13 +373,13 @@ App.BackgroundOperationsController = Em.Controller.extend({
   /**
    * Onclick handler for background operations number located right to logo
    */
-  showPopup: function(){
+  showPopup: function () {
     // load the checkbox on footer first, then show popup.
     var self = this;
     App.router.get('userSettingsController').dataLoading('show_bg').done(function (initValue) {
       App.updater.immediateRun('requestMostRecent');
-      if(self.get('popupView') && App.HostPopup.get('isBackgroundOperations')){
-        self.set ('popupView.isNotShowBgChecked', !initValue);
+      if (self.get('popupView') && App.HostPopup.get('isBackgroundOperations')) {
+        self.set('popupView.isNotShowBgChecked', !initValue);
         self.set('popupView.isOpen', true);
         var el = $(self.get('popupView.element'));
         el.appendTo('#wrapper');

http://git-wip-us.apache.org/repos/asf/ambari/blob/98a83c5f/ambari-web/app/controllers/global/cluster_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/global/cluster_controller.js b/ambari-web/app/controllers/global/cluster_controller.js
index d7cedd3..21508ab 100644
--- a/ambari-web/app/controllers/global/cluster_controller.js
+++ b/ambari-web/app/controllers/global/cluster_controller.js
@@ -164,6 +164,7 @@ App.ClusterController = Em.Controller.extend(App.ReloadPopupMixin, {
       error: 'getServerClockErrorCallback'
     });
   },
+
   getServerClockSuccessCallback: function (data) {
     var clientClock = new Date().getTime();
     var serverClock = (data.RootServiceComponents.server_clock).toString();
@@ -171,8 +172,8 @@ App.ClusterController = Em.Controller.extend(App.ReloadPopupMixin, {
     App.set('clockDistance', serverClock - clientClock);
     App.set('currentServerTime', parseInt(serverClock));
   },
-  getServerClockErrorCallback: function () {
-  },
+
+  getServerClockErrorCallback: Em.K,
 
   getUrl: function (testUrl, url) {
     return (App.get('testMode')) ? testUrl : App.get('apiPrefix') + '/clusters/' + App.get('clusterName') + url;
@@ -182,10 +183,10 @@ App.ClusterController = Em.Controller.extend(App.ReloadPopupMixin, {
    *  load all data and update load status
    */
   loadClusterData: function () {
-    var self = this;
     this.loadAuthorizations();
     this.getAllHostNames();
     this.loadAmbariProperties();
+
     if (!App.get('clusterName')) {
       return;
     }
@@ -196,38 +197,49 @@ App.ClusterController = Em.Controller.extend(App.ReloadPopupMixin, {
     }
     App.router.get('userSettingsController').getAllUserSettings();
     App.router.get('errorsHandlerController').loadErrorLogs();
-    var clusterUrl = this.getUrl('/data/clusters/cluster.json', '?fields=Clusters');
     var hostsController = App.router.get('mainHostController');
     hostsController.set('isCountersUpdating', true);
     hostsController.updateStatusCounters();
 
+    this.loadClusterInfo();
+    this.restoreUpgradeState();
+    App.router.get('wizardWatcherController').getUser();
+
+    this.loadClusterDataToModel();
+
+    //force clear filters  for hosts page to load all data
+    App.db.setFilterConditions('mainHostController', null);
+
+    //load cluster-env, used by alert check tolerance
+    // TODO services auto-start
+    App.router.get('updateController').updateClusterEnv();
+  },
+
+  loadClusterInfo: function() {
+    var clusterUrl = this.getUrl('/data/clusters/cluster.json', '?fields=Clusters');
     App.HttpClient.get(clusterUrl, App.clusterMapper, {
       complete: function (jqXHR, textStatus) {
         App.set('isCredentialStorePersistent', Em.getWithDefault(App.Cluster.find().findProperty('clusterName', App.get('clusterName')), 'isCredentialStorePersistent', false));
       }
-    }, function (jqXHR, textStatus) {
-    });
-
-
-    self.restoreUpgradeState();
-
-    App.router.get('wizardWatcherController').getUser();
+    }, Em.K);
+  },
 
-    var updater = App.router.get('updateController');
+  /**
+   * Order of loading:
+   * 1. load all created service components
+   * 2. request for service components supported by stack
+   * 3. load stack components to model
+   * 4. request for services
+   * 5. put services in cache
+   * 6. request for hosts and host-components (single call)
+   * 7. request for service metrics
+   * 8. load host-components to model
+   * 9. load services from cache with metrics to model
+   */
+  loadClusterDataToModel: function() {
+    var self = this;
 
-    /**
-     * Order of loading:
-     * 1. load all created service components
-     * 2. request for service components supported by stack
-     * 3. load stack components to model
-     * 4. request for services
-     * 5. put services in cache
-     * 6. request for hosts and host-components (single call)
-     * 7. request for service metrics
-     * 8. load host-components to model
-     * 9. load services from cache with metrics to model
-     */
-    self.loadStackServiceComponents(function (data) {
+    this.loadStackServiceComponents(function (data) {
       data.items.forEach(function (service) {
         service.StackServices.is_selected = true;
         service.StackServices.is_installed = false;
@@ -235,64 +247,68 @@ App.ClusterController = Em.Controller.extend(App.ReloadPopupMixin, {
       App.stackServiceMapper.mapStackServices(data);
       App.config.setPreDefinedServiceConfigs(true);
       self.updateLoadStatus('stackComponents');
-      updater.updateServices(function () {
-        self.updateLoadStatus('services');
-
-        //hosts should be loaded after services in order to properly populate host-component relation in App.cache.services
-        updater.updateHost(function () {
-          self.set('isHostsLoaded', true);
-          console.time('Overall alerts loading time');
-          updater.updateAlertGroups(function () {
-            updater.updateAlertDefinitions(function () {
-              updater.updateAlertDefinitionSummary(function () {
-                updater.updateUnhealthyAlertInstances(function () {
-                  console.timeEnd('Overall alerts loading time');
-                  self.set('isAlertsLoaded', true);
-                });
-              });
-            });
-          });
-        });
-        App.config.loadConfigsFromStack(App.Service.find().mapProperty('serviceName')).complete(function () {
-          App.config.loadClusterConfigsFromStack().complete(function () {
-            self.set('isConfigsPropertiesLoaded', true);
+      self.loadServicesAndComponents();
+    });
+  },
+
+  loadServicesAndComponents: function() {
+    var updater = App.router.get('updateController');
+    var self = this;
+
+    updater.updateServices(function () {
+      self.updateLoadStatus('services');
+
+      //hosts should be loaded after services in order to properly populate host-component relation in App.cache.services
+      updater.updateHost(function () {
+        self.set('isHostsLoaded', true);
+        self.loadAlerts();
+      });
+      self.loadConfigProperties();
+      // components state loading doesn't affect overall progress
+      updater.updateComponentsState(function () {
+        self.set('isComponentsStateLoaded', true);
+        // service metrics should be loaded after components state for mapping service components to service in the DS model
+        // service metrics loading doesn't affect overall progress
+        updater.updateServiceMetric(function () {
+          self.set('isServiceMetricsLoaded', true);
+          // make second call, because first is light since it doesn't request host-component metrics
+          updater.updateServiceMetric(function() {
+            self.set('isHostComponentMetricsLoaded', true);
           });
-        });
-        // components state loading doesn't affect overall progress
-        updater.updateComponentsState(function () {
-          self.set('isComponentsStateLoaded', true);
-          // service metrics should be loaded after components state for mapping service components to service in the DS model
-          // service metrics loading doesn't affect overall progress
-          updater.updateServiceMetric(function () {
-            self.set('isServiceMetricsLoaded', true);
-            // make second call, because first is light since it doesn't request host-component metrics
-            updater.updateServiceMetric(function() {
-              self.set('isHostComponentMetricsLoaded', true);
-            });
-            // components config loading doesn't affect overall progress
-            updater.updateComponentConfig(function () {
-              self.set('isComponentsConfigLoaded', true);
-            });
+          // components config loading doesn't affect overall progress
+          updater.updateComponentConfig(function () {
+            self.set('isComponentsConfigLoaded', true);
           });
         });
       });
     });
+  },
 
-    //force clear filters  for hosts page to load all data
-    App.db.setFilterConditions('mainHostController', null);
-
-    //load cluster-env, used by alert check tolerance // TODO services auto-start
-    updater.updateClusterEnv();
+  loadConfigProperties: function() {
+    var self = this;
 
-    /*  Root service mapper maps all the data exposed under Ambari root service which includes ambari configurations i.e ambari-properties
-     ** This is useful information but its not being used in the code anywhere as of now
+    App.config.loadConfigsFromStack(App.Service.find().mapProperty('serviceName')).complete(function () {
+      App.config.loadClusterConfigsFromStack().complete(function () {
+        self.set('isConfigsPropertiesLoaded', true);
+      });
+    });
+  },
 
-     self.loadRootService().done(function (data) {
-     App.rootServiceMapper.map(data);
-     self.updateLoadStatus('rootService');
-     });
+  loadAlerts: function() {
+    var updater = App.router.get('updateController');
+    var self = this;
 
-     */
+    console.time('Overall alerts loading time');
+    updater.updateAlertGroups(function () {
+      updater.updateAlertDefinitions(function () {
+        updater.updateAlertDefinitionSummary(function () {
+          updater.updateUnhealthyAlertInstances(function () {
+            console.timeEnd('Overall alerts loading time');
+            self.set('isAlertsLoaded', true);
+          });
+        });
+      });
+    });
   },
 
   /**
@@ -353,7 +369,7 @@ App.ClusterController = Em.Controller.extend(App.ReloadPopupMixin, {
 
   isRunningState: function(status){
     if (status) {
-      return "IN_PROGRESS" == status || "PENDING" == status || status.contains("HOLDING");
+      return "IN_PROGRESS" === status || "PENDING" === status || status.contains("HOLDING");
     } else {
       //init state
       return true;
@@ -364,7 +380,7 @@ App.ClusterController = Em.Controller.extend(App.ReloadPopupMixin, {
    * ABORTED should be handled as SUSPENDED for the lastUpgradeItem
    * */
   isSuspendedState: function(status){
-    return "ABORTED" == status;
+    return "ABORTED" === status;
   },
 
   loadRootService: function () {
@@ -385,12 +401,13 @@ App.ClusterController = Em.Controller.extend(App.ReloadPopupMixin, {
   /**
    *
    * @param callback
+   * @returns {?object}
    */
   loadStackServiceComponents: function (callback) {
     var callbackObj = {
       loadStackServiceComponentsSuccess: callback
     };
-    App.ajax.send({
+    return App.ajax.send({
       name: 'wizard.service_components',
       data: {
         stackUrl: App.get('stackVersionURL'),
@@ -433,9 +450,7 @@ App.ClusterController = Em.Controller.extend(App.ReloadPopupMixin, {
     App.router.get('mainController').monitorInactivity();
   },
 
-  loadAmbariPropertiesError: function () {
-
-  },
+  loadAmbariPropertiesError: Em.K,
 
   updateClusterData: function () {
     var testUrl = '/data/clusters/HDP2/cluster.json';
@@ -463,9 +478,7 @@ App.ClusterController = Em.Controller.extend(App.ReloadPopupMixin, {
     App.set("allHostNames", data.items.mapProperty("Hosts.host_name"));
   },
 
-  getHostNamesError: function () {
-
-  },
+  getHostNamesError: Em.K,
 
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/98a83c5f/ambari-web/app/controllers/global/configuration_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/global/configuration_controller.js b/ambari-web/app/controllers/global/configuration_controller.js
index 43afc0f..806064a 100644
--- a/ambari-web/app/controllers/global/configuration_controller.js
+++ b/ambari-web/app/controllers/global/configuration_controller.js
@@ -61,6 +61,12 @@ App.ConfigurationController = Em.Controller.extend({
     }
     return isDifferent;
   },
+
+  /**
+   *
+   * @param {Array} siteNames
+   * @returns {*}
+   */
   loadFromDB: function (siteNames) {
     var dfd = $.Deferred();
     var configs = App.db.getConfigs().filter(function (site) {
@@ -80,7 +86,7 @@ App.ConfigurationController = Em.Controller.extend({
     var dfd = $.Deferred();
     if (!tags.everyProperty('tagName')) {
       var configTags;
-      var jqXhr =  this.loadConfigTags();
+      var jqXhr = this.loadConfigTags();
       jqXhr.done(function (data) {
         configTags = data.Clusters.desired_configs;
         tags.forEach(function (_tag) {
@@ -88,10 +94,10 @@ App.ConfigurationController = Em.Controller.extend({
             _tag.tagName = configTags[_tag.siteName].tag;
           }
         }, self);
-        self.loadConfigsByTags(tags,dfd);
+        self.loadConfigsByTags(tags, dfd);
       });
     } else {
-      self.loadConfigsByTags(tags,dfd);
+      self.loadConfigsByTags(tags, dfd);
     }
     return dfd.promise();
   },
@@ -101,7 +107,7 @@ App.ConfigurationController = Em.Controller.extend({
    *  @params tags
    *  @params dfd jqXhr promise
    */
-  loadConfigsByTags: function (tags,dfd) {
+  loadConfigsByTags: function (tags, dfd) {
     var self = this;
     var loadedConfigs = [];
     App.config.loadConfigsByTags(tags).done(function (data) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/98a83c5f/ambari-web/app/controllers/global/update_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/global/update_controller.js b/ambari-web/app/controllers/global/update_controller.js
index ce93b34..a3aee37 100644
--- a/ambari-web/app/controllers/global/update_controller.js
+++ b/ambari-web/app/controllers/global/update_controller.js
@@ -410,10 +410,10 @@ App.UpdateController = Em.Controller.extend({
       params.callback(skipCall, queryParams);
     }
   },
-  getHostByHostComponentsErrorCallback: function () {
+  getHostByHostComponentsErrorCallback: Em.K,
 
-  },
   graphs: [],
+
   graphsUpdate: function (callback) {
     var existedGraphs = [];
     this.get('graphs').forEach(function (_graph) {
@@ -524,6 +524,7 @@ App.UpdateController = Em.Controller.extend({
       complete: callback
     });
   },
+
   updateComponentConfig: function (callback) {
     var testUrl = '/data/services/host_component_stale_configs.json';
     var componentConfigUrl = this.getUrl(testUrl, '/components?host_components/HostRoles/stale_configs=true&fields=host_components/HostRoles/display_name,host_components/HostRoles/service_name,host_components/HostRoles/state,host_components/HostRoles/maintenance_state,host_components/HostRoles/host_name,host_components/HostRoles/public_host_name,host_components/HostRoles/stale_configs,host_components/HostRoles/desired_admin_state&minimal_response=true');

http://git-wip-us.apache.org/repos/asf/ambari/blob/98a83c5f/ambari-web/app/controllers/global/user_settings_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/global/user_settings_controller.js b/ambari-web/app/controllers/global/user_settings_controller.js
index 9580400..e971cba 100644
--- a/ambari-web/app/controllers/global/user_settings_controller.js
+++ b/ambari-web/app/controllers/global/user_settings_controller.js
@@ -169,10 +169,10 @@ App.UserSettingsController = Em.Controller.extend(App.UserPref, {
    * @returns {*}
    */
   postUserPref: function (key, value) {
-    var k = key.startsWith('userSettingsKeys.') ? key : 'userSettingsKeys.' + key + '.name';
-    var kk = k.replace('userSettingsKeys.', '').replace('.name', '');
-    this.set('userSettings.' + kk, value);
-    return this._super(this.get(k), value);
+    var normalizedKey = key.startsWith('userSettingsKeys.') ? key : 'userSettingsKeys.' + key + '.name';
+    var shortKey = normalizedKey.replace('userSettingsKeys.', '').replace('.name', '');
+    this.set('userSettings.' + shortKey, value);
+    return this._super(this.get(normalizedKey), value);
   },
 
   /**
@@ -187,8 +187,7 @@ App.UserSettingsController = Em.Controller.extend(App.UserPref, {
       return;
     }
 
-    this.dataLoading()
-    .done(function(response) {
+    this.dataLoading().done(function(response) {
       self.loadPrivileges().complete(function() {
         self._showSettingsPopup(response);
       });
@@ -207,27 +206,11 @@ App.UserSettingsController = Em.Controller.extend(App.UserPref, {
   },
 
   loadPrivilegesSuccessCallback: function(data) {
-    var key;
-    var privileges = {
-      clusters: {},
-      views: {}
-    };
-    data.items.forEach(function(privilege) {
-      privilege = privilege.PrivilegeInfo;
-      if(privilege.type === 'CLUSTER'){
-        // This is cluster
-        privileges.clusters[privilege.cluster_name] = privileges.clusters[privilege.cluster_name] || [];
-        privileges.clusters[privilege.cluster_name].push(privilege.permission_label);
-      } else if ( privilege.type === 'VIEW'){
-        privileges.views[privilege.instance_name] = privileges.views[privilege.instance_name] || { privileges:[]};
-        privileges.views[privilege.instance_name].version = privilege.version;
-        privileges.views[privilege.instance_name].view_name = privilege.view_name;
-        privileges.views[privilege.instance_name].privileges.push(privilege.permission_label);
-      }
-    });
-    // restructure data for view
-    var clusters = [];
-    var views = [];
+    var key,
+        privileges = this.parsePrivileges(data),
+        clusters = [],
+        views = [];
+
     for (key in privileges.clusters) {
       clusters.push({
         name: key,
@@ -245,12 +228,38 @@ App.UserSettingsController = Em.Controller.extend(App.UserPref, {
     privileges.clusters = clusters;
     privileges.views = views;
     this.set('privileges', data.items.length ? privileges : null);
-    this.set('noClusterPriv', $.isEmptyObject(privileges.clusters));
-    this.set('noViewPriv', $.isEmptyObject(privileges.views));
+    this.set('noClusterPriv', Em.isEmpty(clusters));
+    this.set('noViewPriv', Em.isEmpty(views));
     this.set('hidePrivileges', this.get('noClusterPriv') && this.get('noViewPriv'));
   },
 
   /**
+   *
+   * @param {?object} data
+   * @returns {{clusters: {}, views: {}}}
+   */
+  parsePrivileges: function (data) {
+    var privileges = {
+      clusters: {},
+      views: {}
+    };
+    data.items.forEach(function (privilege) {
+      privilege = privilege.PrivilegeInfo;
+      if (privilege.type === 'CLUSTER') {
+        // This is cluster
+        privileges.clusters[privilege.cluster_name] = privileges.clusters[privilege.cluster_name] || [];
+        privileges.clusters[privilege.cluster_name].push(privilege.permission_label);
+      } else if (privilege.type === 'VIEW') {
+        privileges.views[privilege.instance_name] = privileges.views[privilege.instance_name] || {privileges: []};
+        privileges.views[privilege.instance_name].version = privilege.version;
+        privileges.views[privilege.instance_name].view_name = privilege.view_name;
+        privileges.views[privilege.instance_name].privileges.push(privilege.permission_label);
+      }
+    });
+    return privileges;
+  },
+
+  /**
    * Show popup with settings for user
    * Don't call this method directly! Use <code>showSettingsPopup</code>
    *

http://git-wip-us.apache.org/repos/asf/ambari/blob/98a83c5f/ambari-web/test/controllers/global/background_operations_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/global/background_operations_test.js b/ambari-web/test/controllers/global/background_operations_test.js
index b22c105..323f090 100644
--- a/ambari-web/test/controllers/global/background_operations_test.js
+++ b/ambari-web/test/controllers/global/background_operations_test.js
@@ -31,9 +31,7 @@ require('utils/host_progress_popup');
 
 describe('App.BackgroundOperationsController', function () {
 
-  var controller = App.BackgroundOperationsController.create({
-    isInitLoading: Em.K
-  });
+  var controller = App.BackgroundOperationsController.create();
 
   describe('#getQueryParams', function () {
     /**
@@ -713,4 +711,241 @@ describe('App.BackgroundOperationsController', function () {
       expect(request.get('isRunning')).to.equal(true);
     });
   });
+
+  describe("#isInitLoading()", function () {
+
+    it("should return false when not on HOSTS_LIST level", function() {
+      controller.set('levelInfo', Em.Object.create({
+        name: 'SERVICES_LIST'
+      }));
+      expect(controller.isInitLoading()).to.be.false;
+    });
+
+    it("should return false when no request found", function() {
+      controller.set('levelInfo', Em.Object.create({
+        name: 'HOSTS_LIST',
+        requestId: 1
+      }));
+      controller.set('services', []);
+      expect(controller.isInitLoading()).to.be.false;
+    });
+
+    it("should return false when no request found", function() {
+      controller.set('levelInfo', Em.Object.create({
+        name: 'HOSTS_LIST',
+        requestId: 1
+      }));
+      controller.set('services', []);
+      expect(controller.isInitLoading()).to.be.false;
+    });
+
+    it("should return false when request has hosts", function() {
+      controller.set('levelInfo', Em.Object.create({
+        name: 'HOSTS_LIST',
+        requestId: 1
+      }));
+      controller.set('services', [Em.Object.create({
+        id: 1,
+        hostsMap: {
+          'host1': {}
+        }
+      })]);
+      expect(controller.isInitLoading()).to.be.false;
+    });
+
+    it("should return true when no request has no hosts", function() {
+      controller.set('levelInfo', Em.Object.create({
+        name: 'HOSTS_LIST',
+        requestId: 1
+      }));
+      controller.set('services', [Em.Object.create({
+        id: 1,
+        hostsMap: {}
+      })]);
+      expect(controller.isInitLoading()).to.be.true;
+    });
+  });
+
+  describe("#callBackFilteredByTask()", function () {
+    var data = {
+      Tasks: {
+        request_id: 1,
+        host_name: 'host1',
+        id: 2,
+        status: 'foo',
+        stdout: 'bar',
+        stderr: 'barfoo',
+        command: 'cmd',
+        custom_command_name: 'custom-cmd',
+        structured_out: 'str-out',
+        output_log: 'out-log',
+        error_log: 'err-log'
+      }
+    };
+
+    beforeEach(function() {
+      sinon.stub(App, 'dateTime').returns(1);
+    });
+
+    afterEach(function() {
+      App.dateTime.restore();
+    });
+
+    it("should set task info", function() {
+      var task = {
+        Tasks: {
+          id: 2
+        }
+      };
+      controller.set('services', [
+        Em.Object.create({
+          id: 1,
+          hostsMap: {
+            host1: {
+              logTasks: [task]
+            }
+          }
+        })
+      ]);
+
+      controller.callBackFilteredByTask(data);
+      expect(task).to.be.eql({
+        "Tasks": {
+          "id": 2,
+          "status": "foo",
+          "stdout": "bar",
+          "stderr": "barfoo",
+          "command": "cmd",
+          "custom_command_name": "custom-cmd",
+          "structured_out": "str-out",
+          "output_log": "out-log",
+          "error_log": "err-log"
+        }
+      });
+      expect(controller.get('serviceTimestamp')).to.be.equal(1);
+    });
+  });
+
+  describe("#parseRequestContext()", function () {
+
+    beforeEach(function() {
+      sinon.stub(controller, 'getRequestContextWithPrefix').returns({
+        parsedRequestContext: 'CTX_WITH_PREFIX'
+      });
+    });
+
+    afterEach(function() {
+      controller.getRequestContextWithPrefix.restore();
+    });
+
+    it("no requestContext specified", function() {
+      expect(controller.parseRequestContext()).to.be.eql({
+        parsedRequestContext: Em.I18n.t('requestInfo.unspecified')
+      });
+    });
+
+    it("requestContext specified", function() {
+      expect(controller.parseRequestContext('CTX')).to.be.eql({
+        parsedRequestContext: 'CTX'
+      });
+    });
+
+    it("requestContext specified with prefix", function() {
+      expect(controller.parseRequestContext(App.BackgroundOperationsController.CommandContexts.PREFIX)).to.be.eql({
+        parsedRequestContext: 'CTX_WITH_PREFIX'
+      });
+    });
+  });
+
+  describe("#getRequestContextWithPrefix()", function () {
+
+    beforeEach(function() {
+      sinon.stub(App.format, 'role', function (arg) {
+        return arg;
+      })
+    });
+
+    afterEach(function() {
+      App.format.role.restore();
+    });
+
+    it("custom command", function() {
+      expect(controller.getRequestContextWithPrefix('prefix.foo.bar')).to.be.eql({
+        requestContext: undefined,
+        dependentService: 'bar',
+        contextCommand: 'foo'
+      });
+    });
+    it("STOP all services command", function() {
+      expect(controller.getRequestContextWithPrefix('prefix.STOP.ALL_SERVICES')).to.be.eql({
+        requestContext: Em.I18n.t("requestInfo.stop").format(Em.I18n.t('common.allServices')),
+        dependentService: 'ALL_SERVICES',
+        contextCommand: 'STOP'
+      });
+    });
+    it("STOP one service command", function() {
+      expect(controller.getRequestContextWithPrefix('prefix.STOP.S1')).to.be.eql({
+        requestContext: Em.I18n.t("requestInfo.stop").format('S1'),
+        dependentService: 'S1',
+        contextCommand: 'STOP'
+      });
+    });
+    it("ROLLING-RESTART service command", function() {
+      expect(controller.getRequestContextWithPrefix('prefix.ROLLING-RESTART.S1.foo.bar')).to.be.eql({
+        requestContext: Em.I18n.t("rollingrestart.rest.context").format('S1', 'foo', 'bar'),
+        dependentService: 'S1',
+        contextCommand: 'ROLLING-RESTART'
+      });
+    });
+  });
+
+  describe("#showPopup()", function () {
+
+    beforeEach(function() {
+      sinon.stub(App.router, 'get').returns({
+        dataLoading: function() {
+          return {
+            done: Em.clb
+          }
+        }
+      });
+      sinon.stub(App.HostPopup, 'initPopup').returns(Em.Object.create());
+      App.HostPopup.set('isBackgroundOperations', true);
+    });
+
+    afterEach(function() {
+      App.router.get.restore();
+      App.HostPopup.initPopup.restore();
+    });
+
+    it("App.updater.immediateRun should be called", function() {
+      controller.showPopup();
+      expect(App.updater.immediateRun.calledWith('requestMostRecent')).to.be.true;
+    });
+
+    it("popupView should be created and opened", function() {
+      controller.set('popupView', null);
+      controller.showPopup();
+      expect(controller.get('popupView')).to.be.eql(Em.Object.create({
+        isNotShowBgChecked: true
+      }));
+    });
+
+    it("popupView should be restored and opened", function() {
+      controller.set('popupView', Em.Object.create());
+      controller.showPopup();
+      expect(controller.get('popupView')).to.be.eql(Em.Object.create({
+        isNotShowBgChecked: true,
+        isOpen: true
+      }));
+    });
+  });
+
+  describe("#clear()", function () {
+
+    it("operationsCount should be 10", function() {
+      controller.clear();
+      expect(controller.get('operationsCount')).to.be.equal(10);
+    });
+  });
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/98a83c5f/ambari-web/test/controllers/global/cluster_controller_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/global/cluster_controller_test.js b/ambari-web/test/controllers/global/cluster_controller_test.js
index 47708ac..ad6e6f9 100644
--- a/ambari-web/test/controllers/global/cluster_controller_test.js
+++ b/ambari-web/test/controllers/global/cluster_controller_test.js
@@ -571,4 +571,596 @@ describe('App.clusterController', function () {
 
     });
   });
+
+  describe('#loadClientServerClockDistance()', function() {
+
+    beforeEach(function() {
+      sinon.stub(controller, 'getServerClock').returns({
+        done: Em.clb
+      });
+    });
+
+    afterEach(function() {
+      controller.getServerClock.restore();
+    });
+
+    it('getServerClock should be called', function() {
+      expect(controller.loadClientServerClockDistance()).to.be.an.object;
+      expect(controller.getServerClock).to.be.calledOnce;
+    });
+  });
+
+  describe('#getServerClock()', function() {
+
+    it('App.ajax.send should be called', function() {
+      controller.getServerClock();
+      var args = testHelpers.findAjaxRequest('name', 'ambari.service');
+      expect(args[0]).to.eql({
+        name: 'ambari.service',
+        sender: controller,
+        data: {
+          fields: '?fields=RootServiceComponents/server_clock'
+        },
+        success: 'getServerClockSuccessCallback',
+        error: 'getServerClockErrorCallback'
+      });
+    });
+  });
+
+  describe('#isRunningState()', function() {
+    var testCases = [
+      {
+        status: '',
+        expected: true
+      },
+      {
+        status: 'IN_PROGRESS',
+        expected: true
+      },
+      {
+        status: 'PENDING',
+        expected: true
+      },
+      {
+        status: 'FAILED_HOLDING',
+        expected: true
+      },
+      {
+        status: 'ABORTED',
+        expected: false
+      }
+    ];
+
+    testCases.forEach(function(test) {
+      it('status = ' + test.status, function() {
+        expect(controller.isRunningState(test.status)).to.be.equal(test.expected);
+      });
+    });
+  });
+
+  describe('#isSuspendedState()', function() {
+
+    it('should return true when status is ABORTED', function() {
+      expect(controller.isSuspendedState('ABORTED')).to.be.true;
+    });
+  });
+
+  describe('#loadRootService()', function() {
+
+    it('App.ajax.send should be called', function() {
+      controller.loadRootService();
+      var args = testHelpers.findAjaxRequest('name', 'service.ambari');
+      expect(args).to.exist;
+    });
+  });
+
+  describe('#requestHosts()', function() {
+
+    beforeEach(function() {
+      sinon.stub(App.HttpClient, 'get');
+    });
+
+    afterEach(function() {
+      App.HttpClient.get.restore();
+    });
+
+    it('App.HttpClient.get should be called', function() {
+      controller.requestHosts();
+      expect(App.HttpClient.get).to.be.calledOnce;
+    });
+  });
+
+  describe('#loadStackServiceComponents()', function() {
+
+    it('App.ajax.send should be called', function() {
+      controller.loadStackServiceComponents();
+      var args = testHelpers.findAjaxRequest('name', 'wizard.service_components');
+      expect(args).to.exist;
+    });
+  });
+
+  describe('#loadAmbariProperties()', function() {
+
+    it('App.ajax.send should be called', function() {
+      controller.loadAmbariProperties();
+      var args = testHelpers.findAjaxRequest('name', 'ambari.service');
+      expect(args).to.exist;
+    });
+  });
+
+  describe('#loadAuthorizations()', function() {
+
+    it('App.ajax.send should be called', function() {
+      controller.loadAuthorizations();
+      var args = testHelpers.findAjaxRequest('name', 'router.user.authorizations');
+      expect(args).to.exist;
+    });
+  });
+
+  describe('#loadAuthorizationsSuccessCallback()', function() {
+    var auth = App.get('auth');
+
+    beforeEach(function() {
+      sinon.stub(App.db, 'setAuth');
+    });
+
+    afterEach(function() {
+      App.db.setAuth.restore();
+      App.set('auth', auth);
+    });
+
+    it('App.db.setAuth should not be called when response is null', function() {
+      controller.loadAuthorizationsSuccessCallback(null);
+      expect(App.db.setAuth).to.not.be.called;
+    });
+
+    it('App.db.setAuth should not be called when response has no items', function() {
+      controller.loadAuthorizationsSuccessCallback({items: null});
+      expect(App.db.setAuth).to.not.be.called;
+    });
+
+    it('App.db.setAuth should be called when response correct', function() {
+      controller.loadAuthorizationsSuccessCallback({items: [
+        {
+          AuthorizationInfo: {
+            authorization_id: 'admin'
+          }
+        },
+        {
+          AuthorizationInfo: {
+            authorization_id: 'admin'
+          }
+        }
+      ]});
+      expect(App.get('auth')).to.be.eql(['admin']);
+      expect(App.db.setAuth.calledWith(['admin'])).to.be.true;
+    });
+  });
+
+  describe('#loadAmbariPropertiesSuccess()', function() {
+
+    beforeEach(function() {
+      sinon.stub(App.router.get('mainController'), 'monitorInactivity');
+      controller.loadAmbariPropertiesSuccess({
+        RootServiceComponents: {
+          properties: {
+            p1: '1'
+          }
+        }
+      });
+    });
+
+    afterEach(function() {
+      App.router.get('mainController').monitorInactivity.restore();
+    });
+
+    it('should set ambariProperties', function() {
+      expect(controller.get('ambariProperties')).to.be.eql({p1: '1'});
+    });
+
+    it('should set isCustomJDK', function() {
+      expect(controller.get('isCustomJDK')).to.be.true;
+    });
+
+    it('monitorInactivity should be called', function() {
+      expect(App.router.get('mainController').monitorInactivity).to.be.calledOnce;
+    });
+  });
+
+  describe('#updateClusterData()', function() {
+
+    beforeEach(function() {
+      sinon.stub(App.HttpClient, 'get');
+    });
+
+    afterEach(function() {
+      App.HttpClient.get.restore();
+    });
+
+    it('App.HttpClient.get should be called', function() {
+      controller.updateClusterData();
+      expect(App.HttpClient.get).to.be.calledOnce;
+    });
+  });
+
+  describe('#getAllHostNames()', function() {
+
+    it('App.ajax.send should be called', function() {
+      controller.getAllHostNames();
+      var args = testHelpers.findAjaxRequest('name', 'hosts.all');
+      expect(args).to.exist;
+    });
+  });
+
+  describe('#getHostNamesSuccess()', function() {
+
+    it('should set allHostNames', function() {
+      controller.getHostNamesSuccess({
+        items: [
+          {
+            Hosts: {
+              host_name: 'host1'
+            }
+          }
+        ]
+      });
+      expect(App.get('allHostNames')).to.be.eql(['host1']);
+    });
+  });
+
+  describe('#createKerberosAdminSession()', function() {
+
+    beforeEach(function() {
+      sinon.stub(credentialUtils, 'createOrUpdateCredentials').returns({
+        then: Em.clb
+      });
+    });
+
+    afterEach(function() {
+      credentialUtils.createOrUpdateCredentials.restore();
+    });
+
+    it('credentialUtils.createOrUpdateCredentials should be called', function() {
+      controller.createKerberosAdminSession({}, {});
+      expect(credentialUtils.createOrUpdateCredentials).to.be.calledOnce;
+    });
+  });
+
+  describe('#getAllUpgrades()', function() {
+
+    it('App.ajax.send should be called', function() {
+      controller.getAllUpgrades();
+      var args = testHelpers.findAjaxRequest('name', 'cluster.load_last_upgrade');
+      expect(args).to.exist;
+    });
+  });
+
+  describe('#triggerQuickLinksUpdate()', function() {
+
+    it('should increment quickLinksUpdateCounter', function() {
+      controller.set('quickLinksUpdateCounter', 0);
+      controller.triggerQuickLinksUpdate();
+      expect(controller.get('quickLinksUpdateCounter')).to.be.equal(1);
+    });
+  });
+
+  describe('#loadClusterData()', function() {
+
+    beforeEach(function() {
+      sinon.stub(controller, 'loadAuthorizations');
+      sinon.stub(controller, 'getAllHostNames');
+      sinon.stub(controller, 'loadAmbariProperties');
+      sinon.stub(controller, 'loadClusterInfo');
+      sinon.stub(controller, 'restoreUpgradeState');
+      sinon.stub(controller, 'loadClusterDataToModel');
+      sinon.stub(App.router.get('mainController'), 'startPolling');
+      sinon.stub(App.router.get('userSettingsController'), 'getAllUserSettings');
+      sinon.stub(App.router.get('errorsHandlerController'), 'loadErrorLogs');
+      sinon.stub(App.router.get('mainHostController'), 'updateStatusCounters');
+      sinon.stub(App.router.get('wizardWatcherController'), 'getUser');
+      sinon.stub(App.db, 'setFilterConditions');
+      sinon.stub(App.router.get('updateController'), 'updateClusterEnv');
+      controller.set('isLoaded', false);
+    });
+
+    afterEach(function() {
+      App.router.get('updateController').updateClusterEnv.restore();
+      App.db.setFilterConditions.restore();
+      App.router.get('wizardWatcherController').getUser.restore();
+      App.router.get('mainHostController').updateStatusCounters.restore();
+      App.router.get('errorsHandlerController').loadErrorLogs.restore();
+      App.router.get('userSettingsController').getAllUserSettings.restore();
+      App.router.get('mainController').startPolling.restore();
+      controller.loadAuthorizations.restore();
+      controller.getAllHostNames.restore();
+      controller.loadAmbariProperties.restore();
+      controller.loadClusterInfo.restore();
+      controller.restoreUpgradeState.restore();
+      controller.loadClusterDataToModel.restore();
+    });
+
+    it('loadAuthorizations should be called', function() {
+      controller.loadClusterData();
+      expect(controller.loadAuthorizations.calledOnce).to.be.true;
+    });
+
+    it('getAllHostNames should be called', function() {
+      controller.loadClusterData();
+      expect(controller.getAllHostNames.calledOnce).to.be.true;
+    });
+
+    it('loadAmbariProperties should be called', function() {
+      controller.loadClusterData();
+      expect(controller.loadAmbariProperties.calledOnce).to.be.true;
+    });
+
+    it('getAllUserSettings should be called', function() {
+      controller.loadClusterData();
+      expect(App.router.get('userSettingsController').getAllUserSettings.calledOnce).to.be.true;
+    });
+
+    it('loadErrorLogs should be called', function() {
+      controller.loadClusterData();
+      expect(App.router.get('errorsHandlerController').loadErrorLogs.calledOnce).to.be.true;
+    });
+
+    it('updateStatusCounters should be called', function() {
+      controller.loadClusterData();
+      expect(App.router.get('mainHostController').updateStatusCounters.calledOnce).to.be.true;
+    });
+
+    it('loadClusterInfo should be called', function() {
+      controller.loadClusterData();
+      expect(controller.loadClusterInfo.calledOnce).to.be.true;
+    });
+
+    it('restoreUpgradeState should be called', function() {
+      controller.loadClusterData();
+      expect(controller.restoreUpgradeState.calledOnce).to.be.true;
+    });
+
+    it('getUser should be called', function() {
+      controller.loadClusterData();
+      expect(App.router.get('wizardWatcherController').getUser.calledOnce).to.be.true;
+    });
+
+    it('App.db.setFilterConditions should be called', function() {
+      controller.loadClusterData();
+      expect(App.db.setFilterConditions.calledOnce).to.be.true;
+    });
+
+    it('loadClusterDataToModel should be called', function() {
+      controller.loadClusterData();
+      expect(controller.loadClusterDataToModel.calledOnce).to.be.true;
+    });
+
+    it('updateClusterEnv should be called', function() {
+      controller.loadClusterData();
+      expect(App.router.get('updateController').updateClusterEnv.calledOnce).to.be.true;
+    });
+
+    it('startPolling should be called', function() {
+      controller.set('isLoaded', true);
+      controller.loadClusterData();
+      expect(App.router.get('mainController').startPolling.calledOnce).to.be.true;
+    });
+  });
+
+  describe('#loadClusterInfo()', function() {
+
+    beforeEach(function() {
+      sinon.stub(App.HttpClient, 'get');
+    });
+
+    afterEach(function() {
+      App.HttpClient.get.restore();
+    });
+
+    it('App.HttpClient.get should be called', function() {
+      controller.loadClusterInfo();
+      expect(App.HttpClient.get.calledOnce).to.be.true;
+    });
+  });
+
+  describe('#loadClusterDataToModel()', function() {
+
+    beforeEach(function() {
+      sinon.stub(controller, 'loadStackServiceComponents', function(callback) {
+        callback({items: [{
+          StackServices: {}
+        }]});
+      });
+      sinon.stub(App.stackServiceMapper, 'mapStackServices');
+      sinon.stub(App.config, 'setPreDefinedServiceConfigs');
+      sinon.stub(controller, 'updateLoadStatus');
+      sinon.stub(controller, 'loadServicesAndComponents');
+      controller.loadClusterDataToModel();
+    });
+
+    afterEach(function() {
+      controller.loadServicesAndComponents.restore();
+      controller.updateLoadStatus.restore();
+      controller.loadStackServiceComponents.restore();
+      App.stackServiceMapper.mapStackServices.restore();
+      App.config.setPreDefinedServiceConfigs.restore();
+    });
+
+    it('loadStackServiceComponents should be called', function() {
+      expect(controller.loadStackServiceComponents.calledOnce).to.be.true;
+    });
+
+    it('App.stackServiceMapper.mapStackServices should be called', function() {
+      expect(App.stackServiceMapper.mapStackServices.calledWith({items: [
+        {
+          StackServices: {
+            is_selected: true,
+            is_installed: false
+          }
+        }
+      ]})).to.be.true;
+    });
+
+    it('App.config.setPreDefinedServiceConfigs should be called', function() {
+      expect(App.config.setPreDefinedServiceConfigs.calledWith(true)).to.be.true;
+    });
+
+    it('updateLoadStatus should be called', function() {
+      expect(controller.updateLoadStatus.calledWith('stackComponents')).to.be.true;
+    });
+
+    it('loadServicesAndComponents should be called', function() {
+      expect(controller.loadServicesAndComponents.calledOnce).to.be.true;
+    });
+  });
+
+  describe('#loadAlerts()', function() {
+    var updater = App.router.get('updateController');
+
+    beforeEach(function() {
+      sinon.stub(updater, 'updateAlertGroups', Em.clb);
+      sinon.stub(updater, 'updateAlertDefinitions', Em.clb);
+      sinon.stub(updater, 'updateAlertDefinitionSummary', Em.clb);
+      sinon.stub(updater, 'updateUnhealthyAlertInstances', Em.clb);
+      controller.loadAlerts();
+    });
+
+    afterEach(function() {
+      updater.updateUnhealthyAlertInstances.restore();
+      updater.updateAlertDefinitionSummary.restore();
+      updater.updateAlertDefinitions.restore();
+      updater.updateAlertGroups.restore();
+    });
+
+    it('updateAlertGroups should be called', function() {
+      expect(updater.updateAlertGroups.calledOnce).to.be.true;
+    });
+
+    it('updateAlertDefinitions should be called', function() {
+      expect(updater.updateAlertDefinitions.calledOnce).to.be.true;
+    });
+
+    it('updateAlertDefinitionSummary should be called', function() {
+      expect(updater.updateAlertDefinitionSummary.calledOnce).to.be.true;
+    });
+
+    it('updateUnhealthyAlertInstances should be called', function() {
+      expect(updater.updateUnhealthyAlertInstances.calledOnce).to.be.true;
+    });
+
+    it('should set isAlertsLoaded to true', function() {
+      expect(controller.get('isAlertsLoaded')).to.be.true;
+    });
+  });
+
+  describe('#loadConfigProperties()', function() {
+
+    beforeEach(function() {
+      sinon.stub(App.config, 'loadConfigsFromStack').returns({
+        complete: Em.clb
+      });
+      sinon.stub(App.config, 'loadClusterConfigsFromStack').returns({
+        complete: Em.clb
+      });
+    });
+
+    afterEach(function() {
+      App.config.loadClusterConfigsFromStack.restore();
+      App.config.loadConfigsFromStack.restore();
+    });
+
+    it('App.config.loadConfigsFromStack should be called', function() {
+      controller.loadConfigProperties();
+      expect(App.config.loadConfigsFromStack.calledOnce).to.be.true;
+    });
+
+    it('App.config.loadClusterConfigsFromStack should be called', function() {
+      controller.loadConfigProperties();
+      expect(App.config.loadClusterConfigsFromStack.calledOnce).to.be.true;
+    });
+
+    it('isConfigsPropertiesLoaded should be true', function() {
+      controller.loadConfigProperties();
+      expect(controller.get('isConfigsPropertiesLoaded')).to.be.true;
+    });
+  });
+
+  describe('#loadServicesAndComponents()', function() {
+    var updater = App.router.get('updateController');
+
+    beforeEach(function() {
+      sinon.stub(updater, 'updateServices', Em.clb);
+      sinon.stub(controller, 'updateLoadStatus');
+      sinon.stub(updater, 'updateHost', Em.clb);
+      sinon.stub(controller, 'loadAlerts');
+      sinon.stub(controller, 'loadConfigProperties');
+      sinon.stub(updater, 'updateComponentsState', Em.clb);
+      sinon.stub(updater, 'updateServiceMetric', Em.clb);
+      sinon.stub(updater, 'updateComponentConfig', Em.clb);
+
+      controller.loadServicesAndComponents();
+    });
+
+    afterEach(function() {
+      controller.loadConfigProperties.restore();
+      controller.loadAlerts.restore();
+      updater.updateHost.restore();
+      updater.updateServices.restore();
+      controller.updateLoadStatus.restore();
+      updater.updateComponentsState.restore();
+      updater.updateServiceMetric.restore();
+      updater.updateComponentConfig.restore();
+    });
+
+    it('updateServices should be called', function() {
+      expect(updater.updateServices.calledOnce).to.be.true;
+    });
+
+    it('updateLoadStatus should be called', function() {
+      expect(controller.updateLoadStatus.calledWith('services')).to.be.true;
+    });
+
+    it('updateHost should be called', function() {
+      expect(updater.updateHost.calledOnce).to.be.true;
+    });
+
+    it('isHostsLoaded should be true', function() {
+      expect(controller.get('isHostsLoaded')).to.be.true;
+    });
+
+    it('loadAlerts should be called', function() {
+      expect(controller.loadAlerts.calledOnce).to.be.true;
+    });
+
+    it('loadConfigProperties should be called', function() {
+      expect(controller.loadConfigProperties.calledOnce).to.be.true;
+    });
+
+    it('updateComponentsState should be called', function() {
+      expect(updater.updateComponentsState.calledOnce).to.be.true;
+    });
+
+    it('isComponentsStateLoaded should be true', function() {
+      expect(controller.get('isComponentsStateLoaded')).to.be.true;
+    });
+
+    it('updateServiceMetric should be called', function() {
+      expect(updater.updateServiceMetric.calledTwice).to.be.true;
+    });
+
+    it('isServiceMetricsLoaded should be true', function() {
+      expect(controller.get('isServiceMetricsLoaded')).to.be.true;
+    });
+
+    it('isHostComponentMetricsLoaded should be true', function() {
+      expect(controller.get('isHostComponentMetricsLoaded')).to.be.true;
+    });
+
+    it('updateComponentConfig should be called', function() {
+      expect(updater.updateComponentConfig.calledOnce).to.be.true;
+    });
+
+    it('isComponentsConfigLoaded should be true', function() {
+      expect(controller.get('isComponentsConfigLoaded')).to.be.true;
+    });
+  });
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/98a83c5f/ambari-web/test/controllers/global/configuration_controller_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/global/configuration_controller_test.js b/ambari-web/test/controllers/global/configuration_controller_test.js
index 5baac0e..11dfe0d 100644
--- a/ambari-web/test/controllers/global/configuration_controller_test.js
+++ b/ambari-web/test/controllers/global/configuration_controller_test.js
@@ -19,6 +19,7 @@
 
 var App = require('app');
 require('controllers/global/configuration_controller');
+var testHelpers = require('test/helpers');
 
 
 describe('App.ConfigurationController', function () {
@@ -131,4 +132,166 @@ describe('App.ConfigurationController', function () {
       });
     });
   });
+
+  describe('#getConfigsByTags()', function() {
+
+    beforeEach(function() {
+      sinon.stub(App.db, 'getConfigs').returns([
+        {
+          type: 't1',
+          tag: 'tag1'
+        }
+      ]);
+      this.mockCheck = sinon.stub(controller, 'checkTagsChanges');
+      sinon.stub(controller, 'loadFromServer');
+      sinon.stub(controller, 'loadFromDB');
+    });
+
+    afterEach(function() {
+      App.db.getConfigs.restore();
+      this.mockCheck.restore();
+      controller.loadFromServer.restore();
+      controller.loadFromDB.restore();
+    });
+
+    it('checkTagsChanges should be called', function() {
+      controller.getConfigsByTags([]);
+      expect(controller.checkTagsChanges.calledWith([], [{
+        siteName: 't1',
+        tagName: 'tag1'
+      }])).to.be.true;
+    });
+
+    it('loadFromServer should be called', function() {
+      this.mockCheck.returns(true);
+      controller.getConfigsByTags([]);
+      expect(controller.loadFromServer.calledWith([])).to.be.true;
+    });
+
+    it('loadFromDB should be called', function() {
+      this.mockCheck.returns(false);
+      controller.getConfigsByTags([{siteName: 'site1'}]);
+      expect(controller.loadFromDB.calledWith(['site1'])).to.be.true;
+    });
+  });
+
+  describe('#loadFromServer()', function() {
+
+    beforeEach(function() {
+      sinon.stub(controller, 'loadConfigTags').returns({
+        done: function(callback) {
+          callback({
+            Clusters: {
+              desired_configs: {
+                's1': {
+                  siteName: 's1',
+                  tag: 'tag2'
+                }
+              }
+            }
+          });
+        }
+      });
+      sinon.stub(controller, 'loadConfigsByTags');
+    });
+
+    afterEach(function() {
+      controller.loadConfigTags.restore();
+      controller.loadConfigsByTags.restore();
+    });
+
+    it('tags data is correct', function() {
+      expect(controller.loadFromServer([{tagName: 'tag1', siteName: 's1'}])).to.be.an.object;
+      expect(controller.loadConfigsByTags.calledWith([{tagName: 'tag1', siteName: 's1'}])).to.be.true;
+    });
+
+    it('tags data is corrupted', function() {
+      expect(controller.loadFromServer([{siteName: 's1'}])).to.be.an.object;
+      expect(controller.loadConfigsByTags.calledWith([{tagName: 'tag2', siteName: 's1'}])).to.be.true;
+    });
+  });
+
+  describe('#loadConfigsByTags()', function() {
+    var dfd = {
+      resolve: Em.K
+    };
+
+    beforeEach(function() {
+      sinon.stub(App.config, 'loadConfigsByTags').returns({
+        done: function(callback) {
+          callback({items: [{}]});
+          return {
+            complete: Em.clb
+          }
+        }
+      });
+      sinon.stub(controller, 'saveToDB');
+      sinon.spy(dfd, 'resolve');
+      controller.loadConfigsByTags([], dfd);
+    });
+
+    afterEach(function() {
+      App.config.loadConfigsByTags.restore();
+      controller.saveToDB.restore();
+      dfd.resolve.restore();
+    });
+
+    it('saveToDB should be called', function() {
+      expect(controller.saveToDB.calledWith([{}])).to.be.true;
+    });
+
+    it('Deferred should be resolved', function() {
+      expect(dfd.resolve.calledWith([{}])).to.be.true;
+    });
+  });
+
+  describe('#loadConfigTags()', function() {
+
+    it('App.ajax.send should be called', function() {
+      controller.loadConfigTags();
+      var args = testHelpers.findAjaxRequest('name', 'config.tags');
+      expect(args).to.exist;
+    });
+  });
+
+  describe('#saveToDB()', function() {
+
+    beforeEach(function() {
+      sinon.stub(App.db, 'getConfigs').returns([{
+        type: 't1'
+      }]);
+      sinon.stub(App.db, 'setConfigs');
+    });
+
+    afterEach(function() {
+      App.db.getConfigs.restore();
+      App.db.setConfigs.restore();
+    });
+
+    it('App.db.setConfigs should be called', function() {
+      var loadedConfigs = [
+        {
+          type: 't1',
+          tag: 'tag1',
+          properties: {},
+          properties_attributes: {}
+        },
+        {
+          type: 't2'
+        }
+      ];
+      controller.saveToDB(loadedConfigs);
+      expect(JSON.stringify(App.db.setConfigs.getCall(0).args[0])).to.be.equal(JSON.stringify([
+        {
+          type: 't1',
+          tag: 'tag1',
+          properties: {},
+          properties_attributes: {}
+        },
+        {
+          type: 't2'
+        }
+      ]));
+    });
+  });
 });
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/98a83c5f/ambari-web/test/controllers/global/errors_handler_controller_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/global/errors_handler_controller_test.js b/ambari-web/test/controllers/global/errors_handler_controller_test.js
index 2a726ee..aa98d09 100644
--- a/ambari-web/test/controllers/global/errors_handler_controller_test.js
+++ b/ambari-web/test/controllers/global/errors_handler_controller_test.js
@@ -67,4 +67,14 @@ describe('App.ErrorsHandlerController', function () {
       expect(args[0]).to.be.equal('errors');
     });
   });
+
+  describe("#getUserPrefSuccessCallback()", function () {
+
+    it("should set errors to localStorage", function() {
+      controller.getUserPrefSuccessCallback({data: {}});
+      expect(localStorage.getObject('errors')).to.be.eql({
+        data: {}
+      })
+    });
+  });
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/98a83c5f/ambari-web/test/controllers/global/update_controller_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/global/update_controller_test.js b/ambari-web/test/controllers/global/update_controller_test.js
index dc57a57..2a9d020 100644
--- a/ambari-web/test/controllers/global/update_controller_test.js
+++ b/ambari-web/test/controllers/global/update_controller_test.js
@@ -32,6 +32,11 @@ describe('App.UpdateController', function () {
 
   beforeEach(function () {
     c = App.UpdateController.create();
+    sinon.stub(App.HttpClient, 'get');
+  });
+
+  afterEach(function() {
+    App.HttpClient.get.restore();
   });
 
   App.TestAliases.testAsComputedAlias(App.UpdateController.create(), 'clusterName', 'App.router.clusterController.clusterName', 'string');
@@ -443,6 +448,14 @@ describe('App.UpdateController', function () {
 
   describe('#computeParameters', function () {
 
+    beforeEach(function() {
+      sinon.stub(App.router.get('mainHostComboSearchBoxController'), 'generateQueryParam').returns('combo');
+    });
+
+    afterEach(function() {
+      App.router.get('mainHostComboSearchBoxController').generateQueryParam.restore();
+    });
+
     Em.A([
       {
         q: [{
@@ -454,6 +467,22 @@ describe('App.UpdateController', function () {
       },
       {
         q: [{
+          type: 'CUSTOM',
+          key: '{0} - {1}',
+          value: [1, 2]
+        }],
+        result: '1 - 2'
+      },
+      {
+        q: [{
+          type: 'COMBO',
+          key: '',
+          value: []
+        }],
+        result: 'combo'
+      },
+      {
+        q: [{
           type: 'MULTIPLE',
           key: 'k',
           value: [1, 2]
@@ -534,9 +563,102 @@ describe('App.UpdateController', function () {
         var result = c.computeParameters(test.q);
         expect(result).to.be.equal(test.result);
       });
+    });
+  });
+
+  describe('#preLoadHosts()', function() {
+
+    beforeEach(function() {
+      sinon.stub(c, 'getHostByHostComponents');
+    });
+
+    afterEach(function() {
+      c.getHostByHostComponents.restore();
+    });
+
+    it('getHostByHostComponents should be called', function() {
+      c.set('queryParams.Hosts', [{isComponentRelatedFilter: true}]);
+      expect(c.preLoadHosts(Em.K)).to.be.true;
+      expect(c.getHostByHostComponents.calledOnce).to.be.true;
+    });
+
+    it('getHostByHostComponents should not be called', function() {
+      c.set('queryParams.Hosts', []);
+      expect(c.preLoadHosts(Em.K)).to.be.false;
+      expect(c.getHostByHostComponents.calledOnce).to.be.false;
+    });
+  });
+
+  describe('#getHostByHostComponents', function() {
 
+    it('App.ajax.send should be called', function() {
+      var args = testHelpers.findAjaxRequest('name', 'hosts.host_components.pre_load');
+      expect(args).to.exists;
+    });
+  });
+
+  describe('#updateServices()', function() {
+    it('App.HttpClient.get should be called', function() {
+      c.updateServices();
+      expect(App.HttpClient.get.calledOnce).to.be.true;
+    });
+  });
+
+  describe('#updateComponentConfig()', function() {
+    it('App.HttpClient.get should be called', function() {
+      c.updateComponentConfig();
+      expect(App.HttpClient.get.calledOnce).to.be.true;
+    });
+  });
+
+  describe('#updateComponentsState()', function() {
+    it('App.HttpClient.get should be called', function() {
+      c.updateComponentsState();
+      expect(App.HttpClient.get.calledOnce).to.be.true;
+    });
+  });
+
+  describe('#updateAlertDefinitions()', function() {
+    it('App.HttpClient.get should be called', function() {
+      c.updateAlertDefinitions();
+      expect(App.HttpClient.get.calledOnce).to.be.true;
+    });
+  });
+
+  describe('#updateUnhealthyAlertInstances()', function() {
+    it('App.HttpClient.get should be called', function() {
+      c.updateUnhealthyAlertInstances();
+      expect(App.HttpClient.get.calledOnce).to.be.true;
+    });
+  });
+
+  describe('#updateAlertDefinitionSummary()', function() {
+    it('App.HttpClient.get should be called', function() {
+      c.updateAlertDefinitionSummary();
+      expect(App.HttpClient.get.calledOnce).to.be.true;
+    });
+  });
+
+  describe('#updateAlertGroups()', function() {
+    it('App.HttpClient.get should be called', function() {
+      c.updateAlertGroups();
+      expect(App.HttpClient.get.calledOnce).to.be.true;
     });
+  });
 
+  describe('#updateAlertNotifications()', function() {
+    it('App.HttpClient.get should be called', function() {
+      c.updateAlertNotifications();
+      expect(App.HttpClient.get.calledOnce).to.be.true;
+    });
   });
 
+  describe('#loadClusterConfig()', function() {
+
+    it('App.ajax.send should be called', function() {
+      c.loadClusterConfig();
+      var args = testHelpers.findAjaxRequest('name', 'config.tags.site');
+      expect(args).to.exists;
+    });
+  });
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/98a83c5f/ambari-web/test/controllers/global/user_settings_controller_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/global/user_settings_controller_test.js b/ambari-web/test/controllers/global/user_settings_controller_test.js
index 5ae17f8..f68c109 100644
--- a/ambari-web/test/controllers/global/user_settings_controller_test.js
+++ b/ambari-web/test/controllers/global/user_settings_controller_test.js
@@ -17,6 +17,7 @@
  */
 
 var App = require('app');
+var testHelpers = require('test/helpers');
 
 describe('App.UserSettingsController', function () {
   var controller;
@@ -58,4 +59,303 @@ describe('App.UserSettingsController', function () {
     });
   });
 
+  describe("#dataLoading()", function () {
+
+    beforeEach(function() {
+      sinon.stub(controller, 'getUserPref').returns({
+        complete: Em.clb
+      });
+    });
+
+    afterEach(function() {
+      controller.getUserPref.restore();
+    });
+
+    it("should return promise with preferences", function() {
+      controller.set('currentPrefObject', {data: {}});
+      var promise = controller.dataLoading();
+      promise.done(function(result) {
+        expect(result).to.be.eql({data: {}});
+      });
+      expect(controller.get('currentPrefObject')).to.be.null;
+    });
+  });
+
+  describe("#getUserPrefErrorCallback()", function () {
+
+    beforeEach(function() {
+      sinon.stub(controller, 'updateUserPrefWithDefaultValues');
+    });
+
+    afterEach(function() {
+      controller.updateUserPrefWithDefaultValues.restore();
+    });
+
+    it("updateUserPrefWithDefaultValues should be called", function() {
+      controller.getUserPrefErrorCallback({status: 404});
+      expect(controller.updateUserPrefWithDefaultValues.calledOnce).to.be.true;
+    });
+
+    it("updateUserPrefWithDefaultValues should not be called", function() {
+      controller.getUserPrefErrorCallback({status: 200});
+      expect(controller.updateUserPrefWithDefaultValues.called).to.be.false;
+    });
+  });
+
+  describe("#getAllUserSettings()", function () {
+
+    beforeEach(function() {
+      sinon.stub(controller, 'dataLoading').returns({
+        done: function(callback) {
+          callback({});
+        }
+      });
+      sinon.stub(controller, 'postUserPref');
+      controller.reopen({
+        userSettingsKeys: {
+          key1: {
+            defaultValue: 'val'
+          }
+        }
+      });
+      controller.getAllUserSettings();
+    });
+
+    afterEach(function() {
+      controller.dataLoading.restore();
+      controller.postUserPref.restore();
+    });
+
+    it("postUserPref should be called", function() {
+      expect(controller.postUserPref.calledWith('key1', 'val')).to.be.true;
+    });
+
+    it("userSettings should be set", function() {
+      expect(controller.get('userSettings')).to.be.eql({key1: 'val'});
+    });
+  });
+
+  describe('#updateUserPrefWithDefaultValues()', function() {
+
+    beforeEach(function() {
+      sinon.stub(controller, 'postUserPref');
+      controller.reopen({
+        userSettingsKeys: {
+          key1: {
+            name: 'n1',
+            defaultValue: 'val'
+          }
+        }
+      });
+    });
+
+    afterEach(function() {
+      controller.postUserPref.restore();
+    });
+
+    it('postUserPref should be called', function() {
+      controller.updateUserPrefWithDefaultValues({}, true);
+      expect(controller.postUserPref.calledWith('key1', 'val')).to.be.true;
+    });
+  });
+
+  describe('#showSettingsPopup()', function() {
+
+    beforeEach(function() {
+      this.mockAuthorized = sinon.stub(App, 'isAuthorized');
+      sinon.stub(controller, 'dataLoading').returns({
+        done: Em.clb
+      });
+      sinon.stub(controller, 'loadPrivileges').returns({
+        complete: Em.clb
+      });
+      sinon.stub(controller, '_showSettingsPopup');
+    });
+
+    afterEach(function() {
+      controller.dataLoading.restore();
+      this.mockAuthorized.restore();
+      controller.loadPrivileges.restore();
+      controller._showSettingsPopup.restore();
+    });
+
+    it('dataLoading should not be called', function() {
+      this.mockAuthorized.returns(false);
+      controller.showSettingsPopup();
+      expect(controller.dataLoading).to.not.be.called;
+    });
+
+    it('_showSettingsPopup should be called', function() {
+      this.mockAuthorized.returns(true);
+      controller.showSettingsPopup();
+      expect(controller.dataLoading).to.be.calledOnce;
+      expect(controller.loadPrivileges).to.be.calledOnce;
+      expect(controller._showSettingsPopup).to.be.calledonce;
+    });
+  });
+
+  describe('#loadPrivileges()', function() {
+
+    beforeEach(function() {
+      sinon.stub(App.db, 'getLoginName').returns('user');
+    });
+
+    afterEach(function() {
+      App.db.getLoginName.restore();
+    });
+
+    it('App.ajax.send should be called', function() {
+      controller.loadPrivileges();
+      var args = testHelpers.findAjaxRequest('name', 'router.user.privileges');
+      expect(args[0]).to.be.eql({
+        name: 'router.user.privileges',
+        sender: controller,
+        data: {
+          userName: 'user'
+        },
+        success: 'loadPrivilegesSuccessCallback'
+      });
+    });
+  });
+
+  describe('#postUserPref()', function() {
+
+    it('short key', function() {
+      controller.postUserPref('key1', 'val1');
+      expect(controller.get('userSettings.key1')).to.be.equal('val1');
+    });
+
+    it('key with prefix', function() {
+      controller.postUserPref('userSettingsKeys.key2', 'val2');
+      expect(controller.get('userSettings.key2')).to.be.equal('val2');
+    });
+  });
+
+  describe('#loadPrivilegesSuccessCallback()', function() {
+
+    beforeEach(function() {
+      this.mock = sinon.stub(controller, 'parsePrivileges');
+    });
+
+    afterEach(function() {
+      this.mock.restore();
+    });
+
+    it('should set privilege info when data present', function() {
+      this.mock.returns({
+        clusters: {
+          'c1': {}
+        },
+        views: {
+          'v1': {
+            privileges: {},
+            version: 'ver1',
+            view_name: 'view1'
+          }
+        }
+      });
+      controller.loadPrivilegesSuccessCallback({items: [{}]});
+      expect(JSON.stringify(controller.get('privileges'))).to.be.equal(JSON.stringify({
+        clusters: [
+          {
+            name: 'c1',
+            privileges: {}
+          }
+        ],
+        views: [
+          {
+            instance_name: 'v1',
+            privileges: {},
+            version: 'ver1',
+            view_name: 'view1'
+          }
+        ]
+      }));
+      expect(controller.get('noClusterPriv')).to.be.false;
+      expect(controller.get('noViewPriv')).to.be.false;
+      expect(controller.get('hidePrivileges')).to.be.false;
+    });
+
+    it('should set privilege info when data is empty', function() {
+      this.mock.returns({
+        clusters: {},
+        views: {}
+      });
+      controller.loadPrivilegesSuccessCallback({items: []});
+      expect(controller.get('privileges')).to.be.null;
+      expect(controller.get('noClusterPriv')).to.be.true;
+      expect(controller.get('noViewPriv')).to.be.true;
+      expect(controller.get('hidePrivileges')).to.be.true;
+    });
+  });
+
+  describe('#parsePrivileges()', function() {
+
+    it('should parse privileges from data', function() {
+      var data = {
+        items: [
+          {
+            PrivilegeInfo: {
+              type: 'CLUSTER',
+              cluster_name: 'c1',
+              clusters: {},
+              permission_label: 'perm1'
+            }
+          },
+          {
+            PrivilegeInfo: {
+              type: 'VIEW',
+              instance_name: 'c1',
+              view_name: 'v1',
+              version: 'ver1',
+              views: {},
+              permission_label: 'perm1'
+            }
+          }
+        ]
+      };
+      expect(controller.parsePrivileges(data)).to.be.eql({
+        "clusters": {
+          "c1": [
+            "perm1"
+          ]
+        },
+        "views": {
+          "c1": {
+            "privileges": [
+              "perm1"
+            ],
+            "version": "ver1",
+            "view_name": "v1"
+          }
+        }
+      })
+    });
+  });
+
+  describe('#_showSettingsPopup()', function() {
+
+    beforeEach(function() {
+      sinon.stub(App.ModalPopup, 'show');
+      sinon.stub(App, 'showAlertPopup');
+    });
+
+    afterEach(function() {
+      App.ModalPopup.show.restore();
+      App.showAlertPopup.restore();
+    });
+
+    it('App.ModalPopup.show should be called', function() {
+      controller.set('userSettingsKeys', {show_bg: {name: 'n1'}});
+      controller._showSettingsPopup({n1: {}});
+      expect(App.ModalPopup.show).to.be.calledOnce;
+    });
+
+    it('App.showAlertPopup should be called', function() {
+      controller.set('userSettingsKeys', {show_bg: {name: 'n1'}});
+      controller._showSettingsPopup({});
+      expect(App.showAlertPopup).to.be.calledOnce;
+    });
+  });
+
 });
\ No newline at end of file