You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by nc...@apache.org on 2016/02/18 14:33:50 UTC

[31/33] ambari git commit: AMBARI-15084 Cover service's views with unit tests. (atkach)

AMBARI-15084 Cover service's views 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/1bd4c232
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/1bd4c232
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/1bd4c232

Branch: refs/heads/branch-dev-patch-upgrade
Commit: 1bd4c2329192157f0977bb7e1941485202b04837
Parents: 84ca6a8
Author: Andrii Tkach <at...@hortonworks.com>
Authored: Thu Feb 18 09:51:59 2016 +0200
Committer: Andrii Tkach <at...@hortonworks.com>
Committed: Thu Feb 18 09:51:59 2016 +0200

----------------------------------------------------------------------
 ambari-web/app/assets/test/tests.js             |   2 +
 ambari-web/app/models/service.js                |   2 +-
 .../app/views/common/chart/linear_time.js       |   4 +
 ambari-web/app/views/main/service/info/menu.js  |  45 +-
 .../app/views/main/service/info/summary.js      | 154 ++--
 .../service/reassign/step4_controller_test.js   |   5 +-
 .../test/views/common/chart/linear_time_test.js |   3 +-
 .../stack_upgrade/upgrade_wizard_view_test.js   |   5 -
 .../service/info/component_list_view_test.js    | 153 ++++
 .../test/views/main/service/info/config_test.js |  99 ++-
 .../test/views/main/service/info/menu_test.js   |  93 ++
 .../views/main/service/info/summary_test.js     | 852 +++++++++++++------
 12 files changed, 1040 insertions(+), 377 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/1bd4c232/ambari-web/app/assets/test/tests.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/assets/test/tests.js b/ambari-web/app/assets/test/tests.js
index 0695d06..06c4c31 100644
--- a/ambari-web/app/assets/test/tests.js
+++ b/ambari-web/app/assets/test/tests.js
@@ -270,6 +270,8 @@ var files = [
   'test/views/main/service/item_test',
   'test/views/main/service/info/config_test',
   'test/views/main/service/info/summary_test',
+  'test/views/main/service/info/menu_test',
+  'test/views/main/service/info/component_list_view_test',
   'test/views/main/service/info/metrics/ambari_metrics/regionserver_base_test',
   'test/views/main/service/info/metrics/flume/flume_agent_metrics_section_test',
   'test/views/main/service/services/ranger_test',

http://git-wip-us.apache.org/repos/asf/ambari/blob/1bd4c232/ambari-web/app/models/service.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/service.js b/ambari-web/app/models/service.js
index 39a6b1c..c1ed776 100644
--- a/ambari-web/app/models/service.js
+++ b/ambari-web/app/models/service.js
@@ -229,7 +229,7 @@ App.Service.Health = {
  * association between service and extended model name
  * @type {Object}
  */
-  App.Service.extendedModel = {
+App.Service.extendedModel = {
   'HDFS': 'HDFSService',
   'HBASE': 'HBaseService',
   'YARN': 'YARNService',

http://git-wip-us.apache.org/repos/asf/ambari/blob/1bd4c232/ambari-web/app/views/common/chart/linear_time.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/chart/linear_time.js b/ambari-web/app/views/common/chart/linear_time.js
index 064bec3..864203d 100644
--- a/ambari-web/app/views/common/chart/linear_time.js
+++ b/ambari-web/app/views/common/chart/linear_time.js
@@ -199,6 +199,10 @@ App.ChartLinearTimeView = Ember.View.extend(App.ExportMetricsMixin, {
     });
   },
 
+  setCurrentTimeIndex: function () {
+    this.set('currentTimeIndex', this.get('parentView.currentTimeRangeIndex'));
+  }.observes('parentView.currentTimeRangeIndex'),
+
   /**
    * Maps server data into series format ready for export to graph and JSON formats
    * @param jsonData

http://git-wip-us.apache.org/repos/asf/ambari/blob/1bd4c232/ambari-web/app/views/main/service/info/menu.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/service/info/menu.js b/ambari-web/app/views/main/service/info/menu.js
index 3de23fd..3533a72 100644
--- a/ambari-web/app/views/main/service/info/menu.js
+++ b/ambari-web/app/views/main/service/info/menu.js
@@ -21,29 +21,46 @@ var App = require('app');
 App.MainServiceInfoMenuView = Em.CollectionView.extend({
   tagName: 'ul',
   classNames: ["nav", "nav-tabs", "background-text"],
-  content:function(){
+  content: function () {
     var menuItems = [
-      { label: Em.I18n.t('services.service.info.menu.summary'), id: 'summary-service-tab',routing:'summary', active:"active"}
-      //{ label:'Audit', routing:'audit'}
+      {
+        label: Em.I18n.t('services.service.info.menu.summary'),
+        id: 'summary-service-tab',
+        routing: 'summary',
+        active: "active"
+      }
     ];
 
-    if(this.get('heatmapTab')) menuItems.push({ label: Em.I18n.t('services.service.info.menu.heatmaps'), id: 'heatmap-service-tab', routing:'heatmaps'});
-    if(this.get('configTab')) menuItems.push({ label: Em.I18n.t('services.service.info.menu.configs'), id: 'configs-service-tab', routing:'configs'});
+    if (this.get('heatmapTab')) {
+      menuItems.push({
+        label: Em.I18n.t('services.service.info.menu.heatmaps'),
+        id: 'heatmap-service-tab',
+        routing: 'heatmaps'
+      });
+    }
+    if (this.get('configTab')) {
+      menuItems.push({
+        label: Em.I18n.t('services.service.info.menu.configs'),
+        id: 'configs-service-tab',
+        routing: 'configs'
+      });
+    }
     return menuItems;
   }.property(),
 
-  init: function(){ this._super(); this.activateView(); },
+  init: function () {
+    this._super();
+    this.activateView();
+  },
 
-  activateView:function () {
-    $.each(this._childViews, function () {
-      this.set('active', (document.URL.endsWith(this.get('content.routing')) ? "active" : ""));
-    });
+  activateView: function () {
+    this.get('_childViews').forEach(function(view) {
+      view.set('active', (document.URL.endsWith(view.get('content.routing')) ? "active" : ""));
+    }, this);
   }.observes('App.router.location.lastSetURL'),
 
-  deactivateChildViews: function() {
-    $.each(this._childViews, function(){
-      this.set('active', "");
-    });
+  deactivateChildViews: function () {
+    this.get('_childViews').setEach('active', '');
   },
 
   itemViewClass: Em.View.extend({

http://git-wip-us.apache.org/repos/asf/ambari/blob/1bd4c232/ambari-web/app/views/main/service/info/summary.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/service/info/summary.js b/ambari-web/app/views/main/service/info/summary.js
index d0aadc0..2482913 100644
--- a/ambari-web/app/views/main/service/info/summary.js
+++ b/ambari-web/app/views/main/service/info/summary.js
@@ -89,7 +89,7 @@ App.MainServiceInfoSummaryView = Em.View.extend(App.UserPref, App.TimeRangeMixin
   hasManyServers: Em.computed.gt('servers.length', 1),
 
   clientsHostText: function () {
-    if (this.get('controller.content.installedClients').length == 0) {
+    if (this.get('controller.content.installedClients').length === 0) {
       return '';
     } else if (this.get("hasManyClients")) {
       return Em.I18n.t('services.service.summary.viewHosts');
@@ -134,9 +134,11 @@ App.MainServiceInfoSummaryView = Em.View.extend(App.UserPref, App.TimeRangeMixin
     return result;
   }.property('controller.content'),
 
-  historyServerUI: function(){
-    var service=this.get('controller.content');
-    return (App.singleNodeInstall ? "http://" + App.singleNodeAlias + ":19888" : "http://" + service.get("hostComponents").findProperty('isMaster', true).get("host").get("publicHostName")+":19888");
+  historyServerUI: function () {
+    var master = this.get('controller.content.hostComponents').findProperty('isMaster');
+    return (App.singleNodeInstall
+      ? "http://" + App.singleNodeAlias + ":19888"
+      : "http://" + master.get("host.publicHostName") + ":19888");
   }.property('controller.content'),
 
   /**
@@ -189,7 +191,7 @@ App.MainServiceInfoSummaryView = Em.View.extend(App.UserPref, App.TimeRangeMixin
   updateComponentList: function(source, data) {
     var sourceIds = source.mapProperty('id');
     var dataIds = data.mapProperty('id');
-    if (sourceIds.length == 0) {
+    if (sourceIds.length === 0) {
       source.pushObjects(data);
     }
     if (source.length > data.length) {
@@ -216,13 +218,14 @@ App.MainServiceInfoSummaryView = Em.View.extend(App.UserPref, App.TimeRangeMixin
   },
 
   /**
+   * @type {Em.View}
    * Wrapper for displayName. used to render correct display name for mysql_server
    */
   componentNameView: Ember.View.extend({
     template: Ember.Handlebars.compile('{{view.displayName}}'),
     comp : null,
-    displayName: function(){
-      if(this.get('comp.componentName') == 'MYSQL_SERVER'){
+    displayName: function () {
+      if (this.get('comp.componentName') === 'MYSQL_SERVER') {
         return this.t('services.hive.databaseComponent');
       }
       return this.get('comp.displayName');
@@ -232,43 +235,32 @@ App.MainServiceInfoSummaryView = Em.View.extend(App.UserPref, App.TimeRangeMixin
   service: null,
 
   getServiceModel: function (serviceName) {
-    var svc = App.Service.find(serviceName);
-    var svcName = svc.get('serviceName');
-    if (svcName) {
-      switch (svcName.toLowerCase()) {
-        case 'hdfs':
-          svc = App.HDFSService.find().objectAt(0);
-          break;
-        case 'yarn':
-          svc = App.YARNService.find().objectAt(0);
-          break;
-        case 'hbase':
-          svc = App.HBaseService.find().objectAt(0);
-          break;
-        case 'flume':
-          svc = App.FlumeService.find().objectAt(0);
-          break;
-        case 'storm':
-          svc = App.StormService.find().objectAt(0);
-          break;
-        default:
-          break;
-      }
+    var extended = App.Service.extendedModel[serviceName];
+    if (extended) {
+      return App[extended].find().objectAt(0);
     }
-    return svc;
+    return App.Service.find(serviceName);
   },
 
-  isHide:true,
-  moreStatsView:Em.View.extend({
-    tagName:"a",
-    template:Ember.Handlebars.compile('{{t services.service.summary.moreStats}}'),
-    attributeBindings:[ 'href' ],
-    classNames:[ 'more-stats' ],
-    click:function (event) {
+  /**
+   * @type {boolean}
+   * @default true
+   */
+  isHide: true,
+
+  /**
+   * @type {Em.View}
+   */
+  moreStatsView: Em.View.extend({
+    tagName: "a",
+    template: Ember.Handlebars.compile('{{t services.service.summary.moreStats}}'),
+    attributeBindings: ['href'],
+    classNames: ['more-stats'],
+    click: function (event) {
       this._parentView._parentView.set('isHide', false);
       this.remove();
     },
-    href:'javascript:void(null)'
+    href: 'javascript:void(null)'
   }),
 
   serviceName: Em.computed.alias('service.serviceName'),
@@ -293,7 +285,7 @@ App.MainServiceInfoSummaryView = Em.View.extend(App.UserPref, App.TimeRangeMixin
     return App.AlertDefinition.find().someProperty('serviceName', this.get('controller.content.serviceName'));
   }.property('controller.content.serviceName'),
 
-  updateComponentInformation: function() {
+  updateComponentInformation: function () {
     var hc = this.get('controller.content.restartRequiredHostsAndComponents');
     var hostsCount = 0;
     var componentsCount = 0;
@@ -305,10 +297,11 @@ App.MainServiceInfoSummaryView = Em.View.extend(App.UserPref, App.TimeRangeMixin
     this.set('hostsCount', hostsCount);
   }.observes('controller.content.restartRequiredHostsAndComponents'),
 
-  rollingRestartSlaveComponentName : function() {
+  rollingRestartSlaveComponentName: function() {
     return batchUtils.getRollingRestartComponentName(this.get('serviceName'));
   }.property('serviceName'),
-  rollingRestartActionName : function() {
+
+  rollingRestartActionName: function() {
     var label = null;
     var componentName = this.get('rollingRestartSlaveComponentName');
     if (componentName) {
@@ -349,6 +342,7 @@ App.MainServiceInfoSummaryView = Em.View.extend(App.UserPref, App.TimeRangeMixin
       }, bodyMessage);
     }
   },
+
   rollingRestartStaleConfigSlaveComponents: function (componentName) {
     batchUtils.launchHostComponentRollingRestart(componentName.context, this.get('service.displayName'), this.get('service.passiveState') === "ON", true);
   },
@@ -358,31 +352,25 @@ App.MainServiceInfoSummaryView = Em.View.extend(App.UserPref, App.TimeRangeMixin
    * the array into sections of 5 for displaying on the page
    * (will only display rows with 5 items)
    */
-  constructGraphObjects: function(graphNames) {
-    var result = [], graphObjects = [], chunkSize = this.get('chunkSize');
-    var self = this;
-    var serviceName = this.get('controller.content.serviceName');
-    var stackService = App.StackService.find().findProperty('serviceName', serviceName);
+  constructGraphObjects: function (graphNames) {
+    var self = this,
+        stackService = App.StackService.find(this.get('controller.content.serviceName'));
 
     if (!graphNames && !stackService.get('isServiceWithWidgets')) {
-      self.get('serviceMetricGraphs').clear();
-      self.set('isServiceMetricLoaded', false);
+      this.get('serviceMetricGraphs').clear();
+      this.set('isServiceMetricLoaded', false);
       return;
     }
 
-    // load time range for current service from server
-    self.getUserPref(self.get('persistKey')).complete(function () {
-      var index = self.get('currentTimeRangeIndex');
+    // load time range(currentTimeRangeIndex) for current service from server
+    this.getUserPref(self.get('persistKey')).complete(function () {
+      var result = [], graphObjects = [], chunkSize = self.get('chunkSize');
       if (graphNames) {
-        graphNames.forEach(function(graphName) {
-          graphObjects.push(App["ChartServiceMetrics" + graphName].extend({
-            setCurrentTimeIndex: function () {
-              this.set('currentTimeIndex', this.get('parentView.currentTimeRangeIndex'));
-            }.observes('parentView.currentTimeRangeIndex')
-          }));
+        graphNames.forEach(function (graphName) {
+          graphObjects.push(App["ChartServiceMetrics" + graphName].extend());
         });
       }
-      while(graphObjects.length) {
+      while (graphObjects.length) {
         result.push(graphObjects.splice(0, chunkSize));
       }
       self.set('serviceMetricGraphs', result);
@@ -394,6 +382,11 @@ App.MainServiceInfoSummaryView = Em.View.extend(App.UserPref, App.TimeRangeMixin
    * Contains graphs for this particular service
    */
   serviceMetricGraphs: [],
+
+  /**
+   * @type {boolean}
+   * @default false
+   */
   isServiceMetricLoaded: false,
 
   /**
@@ -409,7 +402,7 @@ App.MainServiceInfoSummaryView = Em.View.extend(App.UserPref, App.TimeRangeMixin
   },
 
   getUserPrefErrorCallback: function (request) {
-    if (request.status == 404) {
+    if (request.status === 404) {
       this.postUserPref(this.get('persistKey'), 0);
       this.set('currentTimeRangeIndex', 0);
     }
@@ -543,7 +536,7 @@ App.MainServiceInfoSummaryView = Em.View.extend(App.UserPref, App.TimeRangeMixin
     this._super();
     var svcName = this.get('controller.content.serviceName');
     this.set('service', this.getServiceModel(svcName));
-    var isMetricsSupported = svcName != 'STORM' || App.get('isStormMetricsSupported');
+    var isMetricsSupported = svcName !== 'STORM' || App.get('isStormMetricsSupported');
 
     this.get('controller').getActiveWidgetLayout();
     if (App.get('supports.customizedWidgetLayout')) {
@@ -551,11 +544,35 @@ App.MainServiceInfoSummaryView = Em.View.extend(App.UserPref, App.TimeRangeMixin
     }
 
     if (svcName && isMetricsSupported) {
-      var allServices =  require('data/service_graph_config');
+      var allServices = require('data/service_graph_config');
       this.constructGraphObjects(allServices[svcName.toLowerCase()]);
     }
-    // adjust the summary table height
+    this.adjustSummaryHeight();
+    this.makeSortable();
+    this.addWidgetTooltip();
+    App.loadTimer.finish('Service Summary Page');
+  },
+
+  addWidgetTooltip: function() {
+    Em.run.later(this, function () {
+      App.tooltip($("[rel='add-widget-tooltip']"));
+      // enable description show up on hover
+      $('.thumbnail').hoverIntent(function() {
+        if ($(this).is(':hover')) {
+          $(this).find('.hidden-description').delay(1000).fadeIn(200).end();
+        }
+      }, function() {
+        $(this).find('.hidden-description').stop().hide().end();
+      });
+    }, 1000);
+  },
+
+  /**
+   * adjust the summary table height
+   */
+  adjustSummaryHeight: function() {
     var summaryTable = document.getElementById('summary-info');
+
     if (summaryTable) {
       var rows = $(summaryTable).find('tr');
       if (rows != null && rows.length > 0) {
@@ -567,19 +584,6 @@ App.MainServiceInfoSummaryView = Em.View.extend(App.UserPref, App.TimeRangeMixin
         }
       }
     }
-    this.makeSortable();
-    Em.run.later(this, function () {
-      App.tooltip($("[rel='add-widget-tooltip']"));
-      // enalble description show up on hover
-      $('.thumbnail').hoverIntent(function() {
-        if ($(this).is(':hover')) {
-          $(this).find('.hidden-description').delay(1000).fadeIn(200).end();
-        }
-      }, function() {
-        $(this).find('.hidden-description').stop().hide().end();
-      });
-    }, 1000);
-    App.loadTimer.finish('Service Summary Page');
   },
 
   willDestroyElement: function() {

http://git-wip-us.apache.org/repos/asf/ambari/blob/1bd4c232/ambari-web/test/controllers/main/service/reassign/step4_controller_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/service/reassign/step4_controller_test.js b/ambari-web/test/controllers/main/service/reassign/step4_controller_test.js
index 945718f..4406bb0 100644
--- a/ambari-web/test/controllers/main/service/reassign/step4_controller_test.js
+++ b/ambari-web/test/controllers/main/service/reassign/step4_controller_test.js
@@ -952,7 +952,10 @@ describe('App.ReassignMasterWizardStep4Controller', function () {
     it('reassign host does not match current', function () {
       controller.set('content.reassignHosts.source', 'host2');
       controller.startNameNode();
-      expect(controller.updateComponent.calledWith('NAMENODE', ['host1'], 'HDFS', 'Start')).to.be.true;
+      expect(controller.updateComponent.getCall(0).args[0]).to.be.equal('NAMENODE');
+      expect(controller.updateComponent.getCall(0).args[1][0]).to.be.equal('host1');
+      expect(controller.updateComponent.getCall(0).args[2]).to.be.equal('HDFS');
+      expect(controller.updateComponent.getCall(0).args[3]).to.be.equal('Start');
     });
 
     it('reassign host matches current', function () {

http://git-wip-us.apache.org/repos/asf/ambari/blob/1bd4c232/ambari-web/test/views/common/chart/linear_time_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/common/chart/linear_time_test.js b/ambari-web/test/views/common/chart/linear_time_test.js
index c547249..0484fd1 100644
--- a/ambari-web/test/views/common/chart/linear_time_test.js
+++ b/ambari-web/test/views/common/chart/linear_time_test.js
@@ -302,7 +302,8 @@ describe('App.ChartLinearTimeView', function () {
           parentView: Em.Object.create({
             currentTimeRangeIndex: 2
           })
-        })
+        }),
+        timeUnitSecondsSetter: Em.K
       });
     });
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/1bd4c232/ambari-web/test/views/main/admin/stack_upgrade/upgrade_wizard_view_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/main/admin/stack_upgrade/upgrade_wizard_view_test.js b/ambari-web/test/views/main/admin/stack_upgrade/upgrade_wizard_view_test.js
index 6349dfe..5630a8c 100644
--- a/ambari-web/test/views/main/admin/stack_upgrade/upgrade_wizard_view_test.js
+++ b/ambari-web/test/views/main/admin/stack_upgrade/upgrade_wizard_view_test.js
@@ -74,11 +74,6 @@ describe('App.upgradeWizardView', function () {
   });
 
   describe("#activeGroup", function () {
-    after(function () {
-      view.reopen({
-        activeGroup: Em.Object.create()
-      });
-    });
     it("status is updated", function () {
       view.reopen({
         activeStatuses: ['IN_PROGRESS'],

http://git-wip-us.apache.org/repos/asf/ambari/blob/1bd4c232/ambari-web/test/views/main/service/info/component_list_view_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/main/service/info/component_list_view_test.js b/ambari-web/test/views/main/service/info/component_list_view_test.js
new file mode 100644
index 0000000..1537f2b
--- /dev/null
+++ b/ambari-web/test/views/main/service/info/component_list_view_test.js
@@ -0,0 +1,153 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+var App = require('app');
+require('views/main/service/info/menu');
+
+
+describe('App.SummaryMasterComponentsView', function () {
+  var view;
+
+  beforeEach(function () {
+    view = App.SummaryMasterComponentsView.create({
+      controller: Em.Object.create()
+    });
+  });
+
+  describe("#mastersCompWillChange", function() {
+
+    beforeEach(function() {
+      sinon.stub(view, 'removeTooltips');
+    });
+    afterEach(function() {
+      view.removeTooltips.restore();
+    });
+
+    it("removeTooltips should be called", function() {
+      view.mastersCompWillChange();
+      expect(view.removeTooltips.calledOnce).to.be.true;
+    });
+  });
+
+  describe("#mastersCompDidChange", function() {
+
+    beforeEach(function() {
+      sinon.stub(view, 'attachTooltip');
+    });
+    afterEach(function() {
+      view.attachTooltip.restore();
+    });
+
+    it("attachTooltip should be called", function() {
+      view.mastersCompDidChange();
+      expect(view.attachTooltip.calledOnce).to.be.true;
+    });
+  });
+
+  describe("#didInsertElement", function() {
+
+    beforeEach(function() {
+      sinon.stub(view, 'attachTooltip');
+    });
+    afterEach(function() {
+      view.attachTooltip.restore();
+    });
+
+    it("attachTooltip should be called", function() {
+      view.didInsertElement();
+      expect(view.attachTooltip.calledOnce).to.be.true;
+    });
+  });
+
+  describe("#willDestroyElement", function() {
+    var mock = {tooltip: Em.K};
+
+    beforeEach(function() {
+      sinon.spy(mock, 'tooltip');
+      sinon.stub(window, '$').returns(mock);
+    });
+    afterEach(function() {
+      mock.tooltip.restore();
+      window.$.restore();
+    });
+
+    it("tooltip should be called", function() {
+      view.willDestroyElement();
+      expect(mock.tooltip.calledWith('destroy')).to.be.true;
+    });
+  });
+
+  describe("#removeTooltips", function() {
+    var mock = {
+      tooltip: Em.K
+    };
+
+    beforeEach(function() {
+      sinon.spy(mock, 'tooltip');
+      sinon.stub(window, '$').returns(mock);
+    });
+    afterEach(function() {
+      mock.tooltip.restore();
+      window.$.restore();
+    });
+
+    it("tooltip should be called", function() {
+      mock.length = 1;
+      view.removeTooltips();
+      expect(mock.tooltip.calledWith('destroy')).to.be.true;
+    });
+
+    it("tooltip should not be called", function() {
+      mock.length = 0;
+      view.removeTooltips();
+      expect(mock.tooltip.called).to.be.false;
+    });
+  });
+
+  describe("#attachTooltip", function() {
+    var mock = {
+      tooltip: Em.K
+    };
+
+    beforeEach(function() {
+      sinon.stub(App, 'tooltip');
+      sinon.stub(window, '$').returns(mock);
+    });
+    afterEach(function() {
+      App.tooltip.restore();
+      window.$.restore();
+    });
+
+    it("tooltip should be called", function() {
+      mock.length = 1;
+      view.attachTooltip();
+      expect(App.tooltip.calledOnce).to.be.true;
+    });
+
+    it("tooltip should not be called", function() {
+      mock.length = 0;
+      view.attachTooltip();
+      expect(App.tooltip.called).to.be.false;
+    });
+  });
+
+
+
+
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/1bd4c232/ambari-web/test/views/main/service/info/config_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/main/service/info/config_test.js b/ambari-web/test/views/main/service/info/config_test.js
index 4e369ea..fb66243 100644
--- a/ambari-web/test/views/main/service/info/config_test.js
+++ b/ambari-web/test/views/main/service/info/config_test.js
@@ -19,6 +19,7 @@
 
 var App = require('app');
 require('views/main/service/info/configs');
+var batchUtils = require('utils/batch_scheduled_requests');
 
 describe('App.MainServiceInfoConfigsView', function () {
 
@@ -26,7 +27,11 @@ describe('App.MainServiceInfoConfigsView', function () {
 
   beforeEach(function () {
     view = App.MainServiceInfoConfigsView.create({
-      controller: Em.Object.create()
+      controller: Em.Object.create({
+        loadStep: Em.K,
+        clearStep: Em.K,
+        content: Em.Object.create()
+      })
     });
   });
 
@@ -101,4 +106,96 @@ describe('App.MainServiceInfoConfigsView', function () {
     });
   });
 
+  describe("#didInsertElement()", function() {
+    var mock = {
+      isLoading: function () {
+        return {
+          done: function (callback) {
+            callback();
+          }
+        }
+      }
+    };
+
+    beforeEach(function() {
+      sinon.stub(App.router, 'get').returns(mock);
+      sinon.stub(view.get('controller'), 'loadStep');
+      sinon.stub(view, 'resetConfigTabSelection');
+      view.didInsertElement();
+    });
+    afterEach(function() {
+      App.router.get.restore();
+      view.get('controller').loadStep.restore();
+      view.resetConfigTabSelection.restore();
+    });
+
+    it("loadStep should be called", function() {
+      expect(view.get('controller').loadStep.calledOnce).to.be.true;
+    });
+
+    it("resetConfigTabSelection should be called", function() {
+      expect(view.resetConfigTabSelection.calledOnce).to.be.true;
+    });
+  });
+
+  describe("#willDestroyElement()", function() {
+
+    beforeEach(function() {
+      sinon.stub(view.get('controller'), 'clearStep');
+    });
+    afterEach(function() {
+      view.get('controller').clearStep.restore();
+    });
+
+    it("resetConfigTabSelection should be called", function() {
+      view.willDestroyElement();
+      expect(view.get('controller').clearStep.calledOnce).to.be.true;
+    });
+  });
+
+  describe("#rollingRestartSlaveComponentName", function() {
+
+    beforeEach(function() {
+      sinon.stub(batchUtils, 'getRollingRestartComponentName', function(input) {
+        return input;
+      });
+    });
+    afterEach(function() {
+      batchUtils.getRollingRestartComponentName.restore();
+    });
+
+    it("should return service name", function() {
+      view.set('controller.content.serviceName', 'S1');
+      view.propertyDidChange('rollingRestartSlaveComponentName');
+      expect(view.get('rollingRestartSlaveComponentName')).to.equal('S1');
+    });
+  });
+
+  describe("#rollingRestartActionName", function() {
+
+    beforeEach(function() {
+      sinon.stub(App.format, 'role', function(input) {
+        return input;
+      });
+    });
+    afterEach(function() {
+      App.format.role.restore();
+    });
+
+    it("should return action name", function() {
+      view.reopen({
+        rollingRestartSlaveComponentName: 'C1'
+      });
+      view.propertyDidChange('rollingRestartActionName');
+      expect(view.get('rollingRestartActionName')).to.equal(Em.I18n.t('rollingrestart.dialog.title').format('C1'));
+    });
+
+    it("should return empty", function() {
+      view.reopen({
+        rollingRestartSlaveComponentName: null
+      });
+      view.propertyDidChange('rollingRestartActionName');
+      expect(view.get('rollingRestartActionName')).to.be.empty;
+    });
+  });
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/1bd4c232/ambari-web/test/views/main/service/info/menu_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/main/service/info/menu_test.js b/ambari-web/test/views/main/service/info/menu_test.js
new file mode 100644
index 0000000..5caa5b0
--- /dev/null
+++ b/ambari-web/test/views/main/service/info/menu_test.js
@@ -0,0 +1,93 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+var App = require('app');
+require('views/main/service/info/menu');
+
+
+describe('App.MainServiceInfoMenuView', function () {
+  var view;
+
+  beforeEach(function () {
+    view = App.MainServiceInfoMenuView.create({
+      controller: Em.Object.create()
+    });
+  });
+
+  describe("#content", function() {
+
+    it("heatmapTab and configTab are false", function() {
+      view.setProperties({
+        configTab: false,
+        heatmapTab: false
+      });
+      view.propertyDidChange('content');
+      expect(view.get('content').mapProperty('id')).to.eql(['summary-service-tab']);
+    });
+
+    it("heatmapTab - false, configTab - true", function() {
+      view.setProperties({
+        configTab: true,
+        heatmapTab: false
+      });
+      view.propertyDidChange('content');
+      expect(view.get('content').mapProperty('id')).to.eql(['summary-service-tab', 'configs-service-tab']);
+    });
+
+    it("heatmapTab - true, configTab - false", function() {
+      view.setProperties({
+        configTab: false,
+        heatmapTab: true
+      });
+      view.propertyDidChange('content');
+      expect(view.get('content').mapProperty('id')).to.eql(['summary-service-tab', 'heatmap-service-tab']);
+    });
+
+    it("heatmapTab - true, configTab - true", function() {
+      view.setProperties({
+        configTab: true,
+        heatmapTab: true
+      });
+      view.propertyDidChange('content');
+      expect(view.get('content').mapProperty('id')).to.eql(['summary-service-tab', 'heatmap-service-tab', 'configs-service-tab']);
+    });
+  });
+
+  describe("#activateView()", function() {
+    it("_childViews should be active", function() {
+      view.set('_childViews', [
+        Em.Object.create({active: '', content: {routing: 'login'}})
+      ]);
+      view.activateView();
+      expect(view.get('_childViews')[0].get('active')).to.equal('active');
+    });
+  });
+
+  describe("#deactivateChildViews()", function() {
+    it("_childViews should be deactivated", function() {
+      view.set('_childViews', [
+        Em.Object.create({active: 'active'}),
+        Em.Object.create({active: 'active'})
+      ]);
+      view.deactivateChildViews();
+      expect(view.get('_childViews')[0].get('active')).to.be.empty;
+      expect(view.get('_childViews')[1].get('active')).to.be.empty;
+    });
+  });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/1bd4c232/ambari-web/test/views/main/service/info/summary_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/main/service/info/summary_test.js b/ambari-web/test/views/main/service/info/summary_test.js
index 5e24490..6a84bb6 100644
--- a/ambari-web/test/views/main/service/info/summary_test.js
+++ b/ambari-web/test/views/main/service/info/summary_test.js
@@ -31,7 +31,8 @@ describe('App.MainServiceInfoSummaryView', function() {
         serviceName: 'HDFS',
         hostComponents: []
       }),
-      getActiveWidgetLayout: Em.K
+      getActiveWidgetLayout: Em.K,
+      loadWidgetLayouts: Em.K
     }),
     alertsController: Em.Object.create(),
     service: Em.Object.create()
@@ -196,270 +197,17 @@ describe('App.MainServiceInfoSummaryView', function() {
 
   });
 
-  describe('#didInsertElement', function () {
-
-    var cases = [
-      {
-        serviceName: 'STORM',
-        isStormMetricsSupported: false,
-        isConstructGraphObjectsCalled: false,
-        title: 'Storm, metrics not supported'
-      },
-      {
-        serviceName: 'STORM',
-        isStormMetricsSupported: true,
-        isConstructGraphObjectsCalled: true,
-        title: 'Storm, metrics supported'
-      },
-      {
-        serviceName: 'HDFS',
-        isConstructGraphObjectsCalled: true,
-        title: 'not Storm'
-      }
-    ];
-
-    beforeEach(function () {
-      sinon.stub(view, 'constructGraphObjects', Em.K);
-      this.mock = sinon.stub(App, 'get');
-    });
-
-    afterEach(function () {
-      view.constructGraphObjects.restore();
-      this.mock.restore();
-    });
-
-    cases.forEach(function (item) {
-      it(item.title, function () {
-        view.set('controller.content.serviceName', item.serviceName);
-        this.mock.withArgs('isStormMetricsSupported').returns(item.isStormMetricsSupported);
-        view.didInsertElement();
-        expect(view.constructGraphObjects.calledOnce).to.equal(item.isConstructGraphObjectsCalled);
-      });
-    });
-
-  });
-
-  describe.skip('#setTimeRange', function () {
-
-    var cases = [
-      {
-        currentTimeRangeIndex: 0,
-        isServiceMetricLoaded: false,
-        graphIds: [],
-        title: 'no event passed'
-      },
-      {
-        event: {},
-        currentTimeRangeIndex: 0,
-        isServiceMetricLoaded: false,
-        graphIds: [],
-        title: 'no event context passed'
-      },
-      {
-        event: {
-          context: {
-            index: 1
-          }
-        },
-        currentTimeRangeIndex: 1,
-        isServiceMetricLoaded: false,
-        graphIds: [],
-        title: 'no service name set'
-      },
-      {
-        event: {
-          context: {
-            index: 2
-          }
-        },
-        serviceName: 'HDFS',
-        currentTimeRangeIndex: 2,
-        isServiceMetricLoaded: true,
-        graphIds: [
-          [
-            'service-metrics-hdfs-space-utilization', 'service-metrics-hdfs-file-operations',
-            'service-metrics-hdfs-block-status', 'service-metrics-hdfs-io', 'service-metrics-hdfs-rpc'
-          ],
-          [
-            'service-metrics-hdfs-gc', 'service-metrics-hdfs-jvm-heap', 'service-metrics-hdfs-jvm-threads'
-          ]
-        ]
-      },
-      {
-        event: {
-          context: {
-            index: 3
-          }
-        },
-        serviceName: 'YARN',
-        currentTimeRangeIndex: 3,
-        isServiceMetricLoaded: true,
-        graphIds: [
-          [
-            'service-metrics-yarn-queue-allocated', 'service-metrics-yarn-queue-memory-resource',
-            'service-metrics-yarn-queue-allocated-container', 'service-metrics-yarn-node-manager-statuses',
-            'service-metrics-yarn-apps-current-states'
-          ],
-          [
-            'service-metrics-yarn-apps-finished-states', 'service-metrics-yarn-rpc', 'service-metrics-yarn-gc',
-            'service-metrics-yarn-jvm-threads', 'service-metrics-yarn-jvm-heap'
-          ]
-        ]
-      },
-      {
-        event: {
-          context: {
-            index: 4
-          }
-        },
-        serviceName: 'HBASE',
-        currentTimeRangeIndex: 4,
-        isServiceMetricLoaded: true,
-        graphIds: [
-          [
-            'service-metrics-hbase-cluster-requests', 'service-metrics-hbase-regionserver-rw-requests',
-            'service-metrics-hbase-regionserver-regions', 'service-metrics-hbase-regionserver-queuesize',
-            'service-metrics-hbase-hlog-split-time'
-          ],
-          [
-            'service-metrics-hbase-hlog-split-size'
-          ]
-        ]
-      },
-      {
-        event: {
-          context: {
-            index: 5
-          }
-        },
-        serviceName: 'AMBARI_METRICS',
-        currentTimeRangeIndex: 5,
-        isServiceMetricLoaded: true,
-        graphIds: [
-          [
-            'service-metrics-ambari-metrics-master-average-load',
-            'service-metrics-ambari-metrics-region-server-store-files',
-            'service-metrics-ambari-metrics-region-server-regions',
-            'service-metrics-ambari-metrics-region-server-requests',
-            'service-metrics-ambari-metrics-region-server-block-cache-hit-percent'
-          ],
-          [
-            'service-metrics-ambari-metrics-region-server-compaction-queue-size'
-          ]
-        ]
-      },
-      {
-        event: {
-          context: {
-            index: 6
-          }
-        },
-        serviceName: 'FLUME',
-        currentTimeRangeIndex: 6,
-        isServiceMetricLoaded: true,
-        graphIds: [
-          [
-            'service-metrics-flume-channel-size-mma', 'service-metrics-flume-channel-size-sum',
-            'service-metrics-flume-incoming_mma', 'service-metrics-flume-incoming_sum',
-            'service-metrics-flume-outgoing_mma'
-          ],
-          [
-            'service-metrics-flume-outgoing_sum'
-          ]
-        ]
-      },
-      {
-        event: {
-          context: {
-            index: 7
-          }
-        },
-        serviceName: 'STORM',
-        currentTimeRangeIndex: 7,
-        isServiceMetricLoaded: true,
-        graphIds: [
-          [
-            'service-metrics-storm-supervisor-allocated', 'service-metrics-storm-executors',
-            'service-metrics-storm-topologies', 'service-metrics-storm-tasks'
-          ]
-        ]
-      },
-      {
-        event: {
-          context: {
-            index: 8
-          }
-        },
-        serviceName: 'KAFKA',
-        chunkSize: 4,
-        currentTimeRangeIndex: 8,
-        isServiceMetricLoaded: true,
-        graphIds: [
-          [
-            'service-metrics-kafka-broker-topic-metrics', 'service-metrics-kafka-controller-metrics',
-            'service-metrics-kafka-controler-status-metrics', 'service-metrics-kafka-replica-manager-metrics'
-          ],
-          [
-            'service-metrics-kafka-log-metrics', 'service-metrics-kafka-replica-fetcher-metrics'
-          ]
-        ]
-      }
-    ];
-
-    beforeEach(function () {
-      sinon.stub(view, 'postUserPref', Em.K);
-      view.setProperties({
-        chunkSize: 5,
-        currentTimeRangeIndex: 0,
-        isServiceMetricLoaded: false,
-        serviceMetricGraphs: []
-      });
-    });
-
-    afterEach(function () {
-      view.postUserPref.restore();
-    });
-
-    cases.forEach(function (item) {
-      it(item.serviceName || item.title, function () {
-        view.set('chunkSize', Em.isNone(item.chunkSize) ? 5 : item.chunkSize);
-        view.set('service.serviceName', item.serviceName);
-        view.setTimeRange(item.event);
-        var graphIndices = [],
-          graphIds = view.get('serviceMetricGraphs').map(function (graphs) {
-          return graphs.map(function (graph) {
-            var graphView = graph.create();
-            graphIndices.push(graphView.get('currentTimeIndex'));
-            return graphView.get('id');
-          });
-        });
-        expect(view.get('currentTimeRangeIndex')).to.equal(item.currentTimeRangeIndex);
-        expect(view.get('isServiceMetricLoaded')).to.equal(item.isServiceMetricLoaded);
-        if (item.event && item.event.context && item.serviceName) {
-          expect(graphIndices.uniq()).to.eql([item.currentTimeRangeIndex]);
-        }
-        expect(graphIds).to.eql(item.graphIds);
-      });
-    });
-
-  });
-
   describe("#restartAllStaleConfigComponents", function () {
 
     describe('trigger restartAllServiceHostComponents', function () {
 
       beforeEach(function () {
-        view = App.MainServiceInfoSummaryView.create({
-          controller: Em.Object.create({
-            content: {
-              serviceName: "HDFS"
-            },
-            getActiveWidgetLayout: Em.K
-          }),
-          service: Em.Object.create({
-            displayName: 'HDFS'
-          })
-        });
+        view.set('controller.content', Em.Object.create({
+          serviceName: "HDFS"
+        }));
+        view.set('service', Em.Object.create({
+          displayName: 'HDFS'
+        }));
         sinon.stub(batchUtils, "restartAllServiceHostComponents", Em.K);
       });
 
@@ -479,25 +227,20 @@ describe('App.MainServiceInfoSummaryView', function() {
       var mainServiceItemController;
 
       beforeEach(function () {
-        view = App.MainServiceInfoSummaryView.create({
-          controller: Em.Object.create({
-            content: {
-              serviceName: "HDFS",
-              hostComponents: [{
-                componentName: 'NAMENODE',
-                workStatus: 'STARTED'
-              }],
-              restartRequiredHostsAndComponents: {
-                "host1": ['NameNode'],
-                "host2": ['DataNode', 'ZooKeeper']
-              }
-            },
-            getActiveWidgetLayout: Em.K
-          }),
-          service: Em.Object.create({
-            displayName: 'HDFS'
-          })
-        });
+        view.set('controller.content', Em.Object.create({
+          serviceName: "HDFS",
+          hostComponents: [{
+            componentName: 'NAMENODE',
+            workStatus: 'STARTED'
+          }],
+          restartRequiredHostsAndComponents: {
+            "host1": ['NameNode'],
+            "host2": ['DataNode', 'ZooKeeper']
+          }
+        }));
+        view.set('service', Em.Object.create({
+          displayName: 'HDFS'
+        }));
         mainServiceItemController = App.MainServiceItemController.create({});
         sinon.stub(mainServiceItemController, 'checkNnLastCheckpointTime', function() {
           return true;
@@ -580,4 +323,555 @@ describe('App.MainServiceInfoSummaryView', function() {
     });
   });
 
+  describe("#clientsHostText", function() {
+
+    it("no installed clients", function() {
+      view.set('controller.content.installedClients', []);
+      view.propertyDidChange('clientsHostText');
+      expect(view.get('clientsHostText')).to.be.empty;
+    });
+
+    it("has many clients", function() {
+      view.set('controller.content.installedClients', [1]);
+      view.reopen({
+        hasManyClients: true
+      });
+      view.propertyDidChange('clientsHostText');
+      expect(view.get('clientsHostText')).to.be.equal(Em.I18n.t('services.service.summary.viewHosts'));
+    });
+
+    it("otherwise", function() {
+      view.set('controller.content.installedClients', [1]);
+      view.reopen({
+        hasManyClients: false
+      });
+      view.propertyDidChange('clientsHostText');
+      expect(view.get('clientsHostText')).to.be.equal(Em.I18n.t('services.service.summary.viewHost'));
+    });
+  });
+
+  describe("#historyServerUI", function() {
+
+    it("singleNodeInstall is true", function() {
+      App.set('singleNodeInstall', true);
+      App.set('singleNodeAlias', 'alias');
+      view.propertyDidChange('historyServerUI');
+      expect(view.get('historyServerUI')).to.equal("http://alias:19888");
+    });
+
+    it("singleNodeInstall is false", function () {
+      App.set('singleNodeInstall', false);
+      view.set('controller.content', Em.Object.create({
+        hostComponents: [
+          Em.Object.create({
+            isMaster: true,
+            host: Em.Object.create({
+              publicHostName: 'host1'
+            })
+          })
+        ]
+      }));
+      view.propertyDidChange('historyServerUI');
+      expect(view.get('historyServerUI')).to.equal("http://host1:19888");
+    });
+  });
+
+  describe("#serversHost", function() {
+
+    it("should return empty object", function() {
+      view.set('controller.content', Em.Object.create({
+        id: 'S1',
+        hostComponents: []
+      }));
+      view.propertyDidChange('serversHost');
+      expect(view.get('serversHost')).to.be.empty;
+    });
+
+    it("should return server object", function() {
+      view.set('controller.content', Em.Object.create({
+        id: 'ZOOKEEPER',
+        hostComponents: [
+          Em.Object.create({
+            isMaster: true
+          })
+        ]
+      }));
+      view.propertyDidChange('serversHost');
+      expect(view.get('serversHost')).to.eql(Em.Object.create({
+        isMaster: true
+      }));
+    });
+  });
+
+  describe("#updateComponentList()", function() {
+
+    it("add components to empty source", function() {
+      var source = [],
+          data = [{id: 1}];
+      view.updateComponentList(source, data);
+      expect(source.mapProperty('id')).to.eql([1]);
+    });
+
+    it("add components to exist source", function() {
+      var source = [{id: 1}],
+        data = [{id: 1}, {id: 2}];
+      view.updateComponentList(source, data);
+      expect(source.mapProperty('id')).to.eql([1, 2]);
+    });
+
+    it("remove components from exist source", function() {
+      var source = [{id: 1}, {id: 2}],
+        data = [{id: 1}];
+      view.updateComponentList(source, data);
+      expect(source.mapProperty('id')).to.eql([1]);
+    });
+  });
+
+  describe("#componentNameView", function () {
+    var componentNameView;
+
+    beforeEach(function () {
+      componentNameView = view.get('componentNameView').create();
+    });
+
+    describe("#displayName", function () {
+
+      it("component is MYSQL_SERVER", function () {
+        componentNameView.set('comp', Em.Object.create({
+          componentName: 'MYSQL_SERVER'
+        }));
+        componentNameView.propertyDidChange('displayName');
+        expect(componentNameView.get('displayName')).to.equal(Em.I18n.t('services.hive.databaseComponent'));
+      });
+
+      it("any component", function () {
+        componentNameView.set('comp', Em.Object.create({
+          componentName: 'C1',
+          displayName: 'c1'
+        }));
+        componentNameView.propertyDidChange('displayName');
+        expect(componentNameView.get('displayName')).to.equal('c1');
+      });
+    });
+  });
+
+
+  describe("#getServiceModel()", function() {
+
+    beforeEach(function() {
+      sinon.stub(App.Service, 'find').returns({serviceName: 'S1'});
+      sinon.stub(App.HDFSService, 'find').returns([{serviceName: 'HDFS'}]);
+    });
+    afterEach(function() {
+      App.Service.find.restore();
+      App.HDFSService.find.restore();
+    });
+
+    it("HDFS service", function() {
+      expect(view.getServiceModel('HDFS')).to.eql({serviceName: 'HDFS'});
+    });
+
+    it("Simple model service", function() {
+      expect(view.getServiceModel('S1')).to.eql({serviceName: 'S1'});
+    });
+  });
+
+  describe("#updateComponentInformation()", function () {
+    it("should count hosts and components", function () {
+      view.set('controller.content.restartRequiredHostsAndComponents', {
+        'host1': ['c1', 'c2']
+      });
+      view.updateComponentInformation();
+      expect(view.get('componentsCount')).to.equal(2);
+      expect(view.get('hostsCount')).to.equal(1);
+    });
+  });
+
+  describe("#rollingRestartSlaveComponentName ", function() {
+
+    beforeEach(function() {
+      sinon.stub(batchUtils, 'getRollingRestartComponentName').returns('C1');
+    });
+    afterEach(function() {
+      batchUtils.getRollingRestartComponentName.restore();
+    });
+
+    it("should returns component name", function() {
+      view.set('serviceName', 'S1');
+      view.propertyDidChange('rollingRestartSlaveComponentName');
+      expect(view.get('rollingRestartSlaveComponentName')).to.equal('C1');
+    });
+  });
+
+  describe("#rollingRestartActionName ", function() {
+
+    beforeEach(function() {
+      sinon.stub(App.format, 'role').returns('C1');
+    });
+    afterEach(function() {
+      App.format.role.restore();
+    });
+
+    it("rollingRestartSlaveComponentName is set", function() {
+      view.reopen({
+        rollingRestartSlaveComponentName: 'C1'
+      });
+      view.propertyDidChange('rollingRestartActionName');
+      expect(view.get('rollingRestartActionName')).to.equal(Em.I18n.t('rollingrestart.dialog.title').format('C1'));
+    });
+
+    it("rollingRestartSlaveComponentName is null", function() {
+      view.reopen({
+        rollingRestartSlaveComponentName: null
+      });
+      view.propertyDidChange('rollingRestartActionName');
+      expect(view.get('rollingRestartActionName')).to.be.null;
+    });
+  });
+
+  describe("#rollingRestartStaleConfigSlaveComponents() ", function() {
+
+    beforeEach(function() {
+      sinon.stub(batchUtils, 'launchHostComponentRollingRestart');
+    });
+    afterEach(function() {
+      batchUtils.launchHostComponentRollingRestart.restore();
+    });
+
+    it("launchHostComponentRollingRestart should be called", function() {
+      view.get('service').setProperties({
+        displayName: 's1',
+        passiveState: 'ON'
+      });
+      view.rollingRestartStaleConfigSlaveComponents({context: 'C1'});
+      expect(batchUtils.launchHostComponentRollingRestart.calledWith(
+        'C1', 's1', true, true
+      )).to.be.true;
+    });
+  });
+
+  describe("#constructGraphObjects()", function() {
+    var mock = Em.Object.create({
+      isServiceWithWidgets: false
+    });
+
+    beforeEach(function() {
+      sinon.stub(App.StackService, 'find').returns(mock);
+      sinon.stub(view, 'getUserPref').returns({
+        complete: function(callback){callback();}
+      })
+    });
+    afterEach(function() {
+      App.StackService.find.restore();
+      view.getUserPref.restore();
+    });
+
+    it("metrics not loaded", function() {
+      mock.set('isServiceWithWidgets', false);
+      view.constructGraphObjects(null);
+      expect(view.get('isServiceMetricLoaded')).to.be.false;
+      expect(view.getUserPref.called).to.be.false;
+    });
+
+    it("metrics loaded", function() {
+      App.ChartServiceMetricsG1 = Em.Object.extend();
+      mock.set('isServiceWithWidgets', true);
+      view.constructGraphObjects(['G1']);
+      expect(view.get('isServiceMetricLoaded')).to.be.true;
+      expect(view.getUserPref.calledOnce).to.be.true;
+      expect(view.get('serviceMetricGraphs')).to.not.be.empty;
+    });
+  });
+
+  describe("#getUserPrefSuccessCallback()", function() {
+
+    it("currentTimeRangeIndex should be set", function() {
+      view.getUserPrefSuccessCallback(1);
+      expect(view.get('currentTimeRangeIndex')).to.equal(1);
+    });
+  });
+
+  describe("#getUserPrefErrorCallback()", function() {
+
+    beforeEach(function() {
+      sinon.stub(view, 'postUserPref');
+    });
+    afterEach(function() {
+      view.postUserPref.restore();
+    });
+
+    it("request.status = 404", function() {
+      view.getUserPrefErrorCallback({status: 404});
+      expect(view.get('currentTimeRangeIndex')).to.equal(0);
+      expect(view.postUserPref.calledOnce).to.be.true;
+    });
+
+    it("request.status = 403", function() {
+      view.getUserPrefErrorCallback({status: 403});
+      expect(view.postUserPref.called).to.be.false;
+    });
+  });
+
+  describe("#widgetActions", function() {
+
+    beforeEach(function() {
+      this.mock = sinon.stub(App, 'isAuthorized');
+      view.setProperties({
+        staticWidgetLayoutActions: [{id: 1}],
+        staticAdminPrivelegeWidgetActions: [{id: 2}],
+        staticGeneralWidgetActions: [{id: 3}]
+      });
+    });
+    afterEach(function() {
+      this.mock.restore();
+    });
+
+    it("not authorized", function() {
+      this.mock.returns(false);
+      view.propertyDidChange('widgetActions');
+      expect(view.get('widgetActions').mapProperty('id')).to.eql([3]);
+    });
+
+    it("is authorized", function() {
+      this.mock.returns(true);
+      App.supports.customizedWidgetLayout = true;
+      view.propertyDidChange('widgetActions');
+      expect(view.get('widgetActions').mapProperty('id')).to.eql([1, 2, 3]);
+    });
+  });
+
+  describe("#doWidgetAction()", function() {
+
+    beforeEach(function() {
+      view.set('controller.action1', Em.K);
+      sinon.stub(view.get('controller'), 'action1');
+    });
+    afterEach(function() {
+      view.get('controller').action1.restore();
+    });
+
+    it("action exist", function() {
+      view.doWidgetAction({context: 'action1'});
+      expect(view.get('controller').action1.calledOnce).to.be.true;
+    });
+  });
+
+  describe("#setTimeRange", function() {
+
+    it("range = 0", function() {
+      var widget = Em.Object.create({
+        widgetType: 'GRAPH',
+        properties: {
+          time_range: '0'
+        }
+      });
+      view.set('controller.widgets', [widget]);
+      view.setTimeRange({context: {value: '0'}});
+      expect(widget.get('properties')['time_range']).to.equal('0')
+    });
+
+    it("range = 1", function() {
+      var widget = Em.Object.create({
+        widgetType: 'GRAPH',
+        properties: {
+          time_range: 0
+        }
+      });
+      view.set('controller.widgets', [widget]);
+      view.setTimeRange({context: {value: '1'}});
+      expect(widget.get('properties')['time_range']).to.equal('1')
+    });
+  });
+
+  describe("#makeSortable()", function() {
+    var mock = {
+      on: function(arg1, arg2, callback) {
+        callback();
+      },
+      off: Em.K,
+      sortable: function() {
+        return {
+          disableSelection: Em.K
+        }
+      }
+    };
+
+    beforeEach(function() {
+      sinon.stub(window, '$').returns(mock);
+      sinon.spy(mock, 'on');
+      sinon.spy(mock, 'off');
+      sinon.spy(mock, 'sortable');
+      view.makeSortable();
+    });
+    afterEach(function() {
+      window.$.restore();
+      mock.on.restore();
+      mock.off.restore();
+      mock.sortable.restore();
+    });
+
+    it("on() should be called", function() {
+      expect(mock.on.calledWith('DOMNodeInserted', '#widget_layout')).to.be.true;
+    });
+
+    it("sortable() should be called", function() {
+      expect(mock.sortable.calledOnce).to.be.true;
+    });
+
+    it("off() should be called", function() {
+      expect(mock.off.calledWith('DOMNodeInserted', '#widget_layout')).to.be.true;
+    });
+  });
+
+  describe('#didInsertElement', function () {
+
+    beforeEach(function () {
+      sinon.stub(view, 'constructGraphObjects', Em.K);
+      this.mock = sinon.stub(App, 'get');
+      sinon.stub(view, 'getServiceModel');
+      sinon.stub(view.get('controller'), 'getActiveWidgetLayout');
+      sinon.stub(view.get('controller'), 'loadWidgetLayouts');
+      sinon.stub(view, 'adjustSummaryHeight');
+      sinon.stub(view, 'makeSortable');
+      sinon.stub(view, 'addWidgetTooltip');
+
+    });
+
+    afterEach(function () {
+      view.constructGraphObjects.restore();
+      this.mock.restore();
+      view.getServiceModel.restore();
+      view.get('controller').getActiveWidgetLayout.restore();
+      view.get('controller').loadWidgetLayouts.restore();
+      view.adjustSummaryHeight.restore();
+      view.makeSortable.restore();
+      view.addWidgetTooltip.restore();
+    });
+
+    it("getServiceModel should be called", function() {
+      view.didInsertElement();
+      expect(view.getServiceModel.calledOnce).to.be.true;
+    });
+    it("adjustSummaryHeight should be called", function() {
+      view.didInsertElement();
+      expect(view.adjustSummaryHeight.calledOnce).to.be.true;
+    });
+    it("addWidgetTooltip should be called", function() {
+      view.didInsertElement();
+      expect(view.addWidgetTooltip.calledOnce).to.be.true;
+    });
+    it("makeSortable should be called", function() {
+      view.didInsertElement();
+      expect(view.makeSortable.calledOnce).to.be.true;
+    });
+    it("getActiveWidgetLayout should be called", function() {
+      view.didInsertElement();
+      expect(view.get('controller').getActiveWidgetLayout.calledOnce).to.be.true;
+    });
+
+    describe("serviceName is null, metrics not supported, widgets not supported", function() {
+      beforeEach(function () {
+        view.set('controller.content.serviceName', null);
+        this.mock.returns(false);
+        view.didInsertElement();
+      });
+
+      it("loadWidgetLayouts should not be called", function() {
+        expect(view.get('controller').loadWidgetLayouts.called).to.be.false;
+      });
+      it("constructGraphObjects should not be called", function() {
+        expect(view.constructGraphObjects.called).to.be.false;
+      });
+    });
+
+    describe("serviceName is set, metrics is supported, widgets is supported", function() {
+      beforeEach(function () {
+        view.set('controller.content.serviceName', 'S1');
+        this.mock.returns(true);
+        view.didInsertElement();
+      });
+
+      it("loadWidgetLayouts should be called", function() {
+        expect(view.get('controller').loadWidgetLayouts.calledOnce).to.be.true;
+      });
+      it("constructGraphObjects should be called", function() {
+        expect(view.constructGraphObjects.calledOnce).to.be.true;
+      });
+    });
+  });
+
+  describe("#addWidgetTooltip()", function() {
+    var mock = {
+      hoverIntent: Em.K
+    };
+
+    beforeEach(function() {
+      sinon.stub(Em.run, 'later', function(arg1, callback) {
+        callback();
+      });
+      sinon.stub(App, 'tooltip');
+      sinon.stub(window, '$').returns(mock);
+      sinon.spy(mock, 'hoverIntent');
+      view.addWidgetTooltip();
+    });
+    afterEach(function() {
+      Em.run.later.restore();
+      App.tooltip.restore();
+      window.$.restore();
+      mock.hoverIntent.restore();
+    });
+
+    it("Em.run.later should be called", function() {
+      expect(Em.run.later.calledOnce).to.be.true;
+    });
+    it("App.tooltip should be called", function() {
+      expect(App.tooltip.calledOnce).to.be.true;
+    });
+    it("hoverIntent should be called", function() {
+      expect(mock.hoverIntent.calledOnce).to.be.true;
+    });
+  });
+
+  describe("#adjustSummaryHeight()", function() {
+    var jQueryMock = {
+      find: Em.K,
+      attr: Em.K
+    };
+
+    beforeEach(function() {
+      sinon.stub(window, '$').returns(jQueryMock);
+      this.mockFind = sinon.stub(jQueryMock, 'find');
+      sinon.spy(jQueryMock, 'attr');
+      this.mockGetElementById = sinon.stub(document, 'getElementById');
+    });
+    afterEach(function() {
+      this.mockGetElementById.restore();
+      window.$.restore();
+      this.mockFind.restore();
+      jQueryMock.attr.restore();
+    });
+
+    it("summary-info not in DOM", function() {
+      this.mockGetElementById.returns(null);
+      view.adjustSummaryHeight();
+      expect(jQueryMock.find.called).to.be.false;
+    });
+
+    it("summary-info has no rows", function() {
+      this.mockGetElementById.returns({});
+      this.mockFind.returns(null);
+      view.adjustSummaryHeight();
+      expect(jQueryMock.find.calledOnce).to.be.true;
+      expect(jQueryMock.attr.called).to.be.false;
+    });
+
+    it("summary-info has rows", function() {
+      this.mockGetElementById.returns({
+        clientHeight: 10
+      });
+      this.mockFind.returns([{}]);
+      view.adjustSummaryHeight();
+      expect(jQueryMock.attr.calledWith('style', "height:20px;")).to.be.true;
+    });
+  });
 });
\ No newline at end of file