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/02/12 11:09:57 UTC

ambari git commit: AMBARI-15016 Cover hosts views with unit tests. (atkach)

Repository: ambari
Updated Branches:
  refs/heads/trunk c47fff357 -> 30438e905


AMBARI-15016 Cover hosts 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/30438e90
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/30438e90
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/30438e90

Branch: refs/heads/trunk
Commit: 30438e9052d5782d8e2b5fe4b28c6adf9d78c5d7
Parents: c47fff3
Author: Andrii Tkach <at...@hortonworks.com>
Authored: Thu Feb 11 21:19:34 2016 +0200
Committer: Andrii Tkach <at...@hortonworks.com>
Committed: Fri Feb 12 12:09:23 2016 +0200

----------------------------------------------------------------------
 ambari-web/app/assets/test/tests.js             |   4 +
 .../app/controllers/wizard/step7_controller.js  |   4 +-
 .../utils/configs/rm_ha_config_initializer.js   |   2 +-
 .../admin/highAvailability/progress_view.js     |   4 +-
 ambari-web/app/views/main/host/add_view.js      |   3 +
 .../app/views/main/host/configs_service.js      |   3 +
 ambari-web/app/views/main/host/menu.js          |   6 +-
 ambari-web/app/views/main/host/summary.js       |   9 +-
 .../highAvailability/progress_view_test.js      |   4 +-
 .../test/views/main/host/add_view_test.js       | 141 ++++++++++
 .../views/main/host/combo_search_box_test.js    |  42 +++
 .../views/main/host/config_service_menu_test.js | 140 ++++++++++
 .../test/views/main/host/config_service_test.js |  46 +++
 .../views/main/host/host_alerts_view_test.js    | 140 +++++++++-
 ambari-web/test/views/main/host/menu_test.js    |  43 ++-
 ambari-web/test/views/main/host/summary_test.js | 277 +++++++++++++------
 16 files changed, 772 insertions(+), 96 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/30438e90/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 ecf55f7..44fb4f4 100644
--- a/ambari-web/app/assets/test/tests.js
+++ b/ambari-web/app/assets/test/tests.js
@@ -253,6 +253,10 @@ var files = [
   'test/views/main/host/menu_test',
   'test/views/main/host/stack_versions_view_test',
   'test/views/main/host/host_alerts_view_test',
+  'test/views/main/host/combo_search_box_test',
+  'test/views/main/host/config_service_test',
+  'test/views/main/host/add_view_test',
+  'test/views/main/host/config_service_menu_test',
   'test/views/main/host/details/host_component_view_test',
   'test/views/main/host/details/host_component_views/decommissionable_test',
   'test/views/main/host/details/host_component_views/datanode_view_test',

http://git-wip-us.apache.org/repos/asf/ambari/blob/30438e90/ambari-web/app/controllers/wizard/step7_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/wizard/step7_controller.js b/ambari-web/app/controllers/wizard/step7_controller.js
index c6f4689..7e96845 100644
--- a/ambari-web/app/controllers/wizard/step7_controller.js
+++ b/ambari-web/app/controllers/wizard/step7_controller.js
@@ -867,8 +867,8 @@ App.WizardStep7Controller = Em.Controller.extend(App.ServerValidatorMixin, App.E
    * @returns {Object[]} existing configs + additional config parameters in yarn-client.xml
    */
   addHawqConfigsOnRMHa: function(configs) {
-    rmHost1 = configs.findProperty('id', 'yarn.resourcemanager.hostname.rm1__yarn-site').value ;
-    rmHost2 = configs.findProperty('id', 'yarn.resourcemanager.hostname.rm2__yarn-site').value ;
+    var rmHost1 = configs.findProperty('id', 'yarn.resourcemanager.hostname.rm1__yarn-site').value ;
+    var rmHost2 = configs.findProperty('id', 'yarn.resourcemanager.hostname.rm2__yarn-site').value ;
     var yarnConfigToBeAdded = [
       {
         name: 'yarn.resourcemanager.ha',

http://git-wip-us.apache.org/repos/asf/ambari/blob/30438e90/ambari-web/app/utils/configs/rm_ha_config_initializer.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/configs/rm_ha_config_initializer.js b/ambari-web/app/utils/configs/rm_ha_config_initializer.js
index 9c36323..dac68d9 100644
--- a/ambari-web/app/utils/configs/rm_ha_config_initializer.js
+++ b/ambari-web/app/utils/configs/rm_ha_config_initializer.js
@@ -89,7 +89,7 @@ App.RmHaConfigInitializer = App.HaConfigInitializerClass.create(App.HostsBasedIn
    */
   _initRmHaHostsWithPort: function (configProperty, localDB, dependencies, initializer) {
     var rmHosts = localDB.masterComponentHosts.filterProperty('component', 'RESOURCEMANAGER').getEach('hostName');
-    for (rmHost in rmHosts) {
+    for (var rmHost in rmHosts) {
       rmHosts[rmHost] = rmHosts[rmHost] + ":" + initializer.port;
     }
     var value = rmHosts.join(',');

http://git-wip-us.apache.org/repos/asf/ambari/blob/30438e90/ambari-web/app/views/main/admin/highAvailability/progress_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/admin/highAvailability/progress_view.js b/ambari-web/app/views/main/admin/highAvailability/progress_view.js
index abe6685..fb793e2 100644
--- a/ambari-web/app/views/main/admin/highAvailability/progress_view.js
+++ b/ambari-web/app/views/main/admin/highAvailability/progress_view.js
@@ -43,7 +43,7 @@ App.HighAvailabilityProgressPageView = Em.View.extend(App.wizardProgressPageView
     if (currentStep === 1) {
       return  Em.I18n.t('admin.highAvailability.wizard.rollback.header.title');
     } else {
-      return  Em.I18n.t('admin.highAvailability.wizard.step' + currentStep + '.header.title');
+      return  Em.I18n.t('admin.highAvailability.wizard.step' + currentStep + '.header');
     }
   }.property(),
 
@@ -55,7 +55,7 @@ App.HighAvailabilityProgressPageView = Em.View.extend(App.wizardProgressPageView
     if (currentStep === 1) {
       return  Em.I18n.t('admin.highAvailability.rollback.notice.inProgress');
     } else {
-      return  Em.I18n.t('admin.highAvailability.wizard.step' + currentStep + '.notice.inProgress');
+      return  Em.I18n.t('admin.highAvailability.wizard.progressPage.notice.inProgress');
     }
   }.property(),
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/30438e90/ambari-web/app/views/main/host/add_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/host/add_view.js b/ambari-web/app/views/main/host/add_view.js
index 33fd123..2047f47 100644
--- a/ambari-web/app/views/main/host/add_view.js
+++ b/ambari-web/app/views/main/host/add_view.js
@@ -23,6 +23,9 @@ App.AddHostView = Em.View.extend(App.WizardMenuMixin, {
 
   templateName: require('templates/main/host/add'),
 
+  /**
+   * @type {boolean}
+   */
   isLoaded: false,
 
   willInsertElement: function () {

http://git-wip-us.apache.org/repos/asf/ambari/blob/30438e90/ambari-web/app/views/main/host/configs_service.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/host/configs_service.js b/ambari-web/app/views/main/host/configs_service.js
index eb3fc56..5bd1ef5 100644
--- a/ambari-web/app/views/main/host/configs_service.js
+++ b/ambari-web/app/views/main/host/configs_service.js
@@ -25,6 +25,9 @@ App.MainHostServiceConfigsView = Em.View.extend({
     this.get('controller').loadStep();
   },
 
+  /**
+   * @type {boolean}
+   */
   isConfigsEditable: false,
 
   content: Em.computed.alias('App.router.mainHostDetailsController.content')

http://git-wip-us.apache.org/repos/asf/ambari/blob/30438e90/ambari-web/app/views/main/host/menu.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/host/menu.js b/ambari-web/app/views/main/host/menu.js
index a53c21a..5540014 100644
--- a/ambari-web/app/views/main/host/menu.js
+++ b/ambari-web/app/views/main/host/menu.js
@@ -99,9 +99,7 @@ App.MainHostMenuView = Em.CollectionView.extend({
   },
 
   deactivateChildViews: function () {
-    $.each(this._childViews, function () {
-      this.set('active', "");
-    });
+    this.get('_childViews').setEach('active', '');
   },
 
   itemViewClass: Em.View.extend({
@@ -113,4 +111,4 @@ App.MainHostMenuView = Em.CollectionView.extend({
     '{{view.content.badgeText}}' +
     '</span>  {{/if}}</a>{{/unless}}')
   })
-});
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/30438e90/ambari-web/app/views/main/host/summary.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/host/summary.js b/ambari-web/app/views/main/host/summary.js
index 464d66f..aa12581 100644
--- a/ambari-web/app/views/main/host/summary.js
+++ b/ambari-web/app/views/main/host/summary.js
@@ -54,9 +54,7 @@ App.MainHostSummaryView = Em.View.extend(App.TimeRangeMixin, {
   /**
    * Host metrics panel not displayed when Metrics service (ex:Ganglia) is not in stack definition.
    */
-  isNoHostMetricsService: function() {
-    return !App.get('services.hostMetrics').length;
-  }.property('App.services.hostMetrics'),
+  isNoHostMetricsService: Em.computed.equal('App.services.hostMetrics.length', 0),
 
   /**
    * Message for "restart" block
@@ -242,11 +240,10 @@ App.MainHostSummaryView = Em.View.extend(App.TimeRangeMixin, {
     var clientComponents = App.StackServiceComponent.find().filterProperty('isClient');
     var installedServices = this.get('installedServices');
     var installedClients = this.get('clients').mapProperty('componentName');
-    var installableClients = clientComponents.filter(function(component) {
+    return clientComponents.filter(function(component) {
       // service for current client is installed but client isn't installed on current host
       return installedServices.contains(component.get('serviceName')) && !installedClients.contains(component.get('componentName'));
     });
-    return installableClients;
   }.property('content.hostComponents.length', 'installedServices.length'),
 
   notInstalledClientComponents: function () {
@@ -280,7 +277,7 @@ App.MainHostSummaryView = Em.View.extend(App.TimeRangeMixin, {
       });
     }
     return components;
-  }.property('content.hostComponents.length', 'installableClientComponents', 'App.components.addableToHost.@each'),
+  }.property('content.hostComponents.length', 'App.components.addableToHost.@each'),
 
   /**
    * Formatted with <code>$.timeago</code> value of host's last heartbeat

http://git-wip-us.apache.org/repos/asf/ambari/blob/30438e90/ambari-web/test/views/main/admin/highAvailability/progress_view_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/main/admin/highAvailability/progress_view_test.js b/ambari-web/test/views/main/admin/highAvailability/progress_view_test.js
index e68c2f1..76902f6 100644
--- a/ambari-web/test/views/main/admin/highAvailability/progress_view_test.js
+++ b/ambari-web/test/views/main/admin/highAvailability/progress_view_test.js
@@ -57,7 +57,7 @@ describe('App.HighAvailabilityProgressPageView', function () {
     it("currentStep is 2", function () {
       this.mock.returns(2);
       view.propertyDidChange('headerTitle');
-      expect(view.get('headerTitle')).to.equal(Em.I18n.t('admin.highAvailability.wizard.step2.header.title'));
+      expect(view.get('headerTitle')).to.equal(Em.I18n.t('admin.highAvailability.wizard.step2.header'));
     });
   });
 
@@ -76,7 +76,7 @@ describe('App.HighAvailabilityProgressPageView', function () {
     it("currentStep is 2", function () {
       this.mock.returns(2);
       view.propertyDidChange('noticeInProgress');
-      expect(view.get('noticeInProgress')).to.equal(Em.I18n.t('admin.highAvailability.wizard.step2.notice.inProgress'));
+      expect(view.get('noticeInProgress')).to.equal(Em.I18n.t('admin.highAvailability.wizard.progressPage.notice.inProgress'));
     });
   });
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/30438e90/ambari-web/test/views/main/host/add_view_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/main/host/add_view_test.js b/ambari-web/test/views/main/host/add_view_test.js
new file mode 100644
index 0000000..785eac4
--- /dev/null
+++ b/ambari-web/test/views/main/host/add_view_test.js
@@ -0,0 +1,141 @@
+/**
+ * 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');
+var testHelpers = require('test/helpers');
+var view;
+
+describe('App.AddHostView', function () {
+
+  beforeEach(function () {
+    view = App.AddHostView.create({
+      controller: Em.Object.create({
+        getDBProperty: Em.K,
+        setDBProperty: Em.K,
+        content: Em.Object.create()
+      })
+    });
+  });
+
+  describe("#willInsertElement()", function() {
+
+    beforeEach(function() {
+      sinon.stub(view, 'loadHosts');
+      this.mock = sinon.stub(view.get('controller'), 'getDBProperty');
+    });
+    afterEach(function() {
+      view.loadHosts.restore();
+      this.mock.restore();
+    });
+
+    it("hosts saved in DB", function() {
+      this.mock.returns(['host1']);
+      view.willInsertElement();
+      expect(view.get('isLoaded')).to.be.true;
+      expect(view.loadHosts.calledOnce).to.be.false;
+    });
+    it("hosts not saved in DB", function() {
+      this.mock.returns(null);
+      view.willInsertElement();
+      expect(view.get('isLoaded')).to.be.false;
+      expect(view.loadHosts.calledOnce).to.be.true;
+    });
+  });
+
+  describe("#loadHosts()", function() {
+
+    it("App.ajax.send should be called", function() {
+      view.loadHosts();
+      var args = testHelpers.filterAjaxRequests('name', 'hosts.confirmed');
+      expect(args[0][0]).to.eql({
+        name: 'hosts.confirmed',
+        sender: view,
+        data: {},
+        success: 'loadHostsSuccessCallback',
+        error: 'loadHostsErrorCallback'
+      });
+    });
+  });
+
+  describe("#loadHostsSuccessCallback()", function() {
+
+    beforeEach(function() {
+      sinon.stub(view.get('controller'), 'setDBProperty');
+    });
+    afterEach(function() {
+      view.get('controller').setDBProperty.restore();
+    });
+
+    it("should save hosts to DB", function() {
+      var response = {items: [
+        {
+          Hosts: {
+            host_name: 'host1',
+            cpu_count: 1,
+            total_mem: 1024,
+            disk_info: {}
+          },
+          host_components: [
+            {
+              component_name: 'C1'
+            }
+          ]
+        }
+      ]};
+      view.loadHostsSuccessCallback(response);
+      expect(view.get('isLoaded')).to.be.true;
+      expect(view.get('controller').setDBProperty.calledWith('hosts', {
+        host1: {
+          name: 'host1',
+          cpu: 1,
+          memory: 1024,
+          disk_info: {},
+          bootStatus: "REGISTERED",
+          isInstalled: true,
+          hostComponents: [
+            {
+              component_name: 'C1'
+            }
+          ]
+        }
+      })).to.be.true;
+      expect(view.get('controller.content.hosts')).to.eql({
+        host1: {
+          name: 'host1',
+          cpu: 1,
+          memory: 1024,
+          disk_info: {},
+          bootStatus: "REGISTERED",
+          isInstalled: true,
+          hostComponents: [
+            {
+              component_name: 'C1'
+            }
+          ]
+        }
+      });
+    });
+  });
+
+  describe("#loadHostsErrorCallback()", function() {
+    it("isLoaded should be set to true", function() {
+      view.loadHostsErrorCallback();
+      expect(view.get('isLoaded')).to.be.true;
+    });
+  });
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/30438e90/ambari-web/test/views/main/host/combo_search_box_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/main/host/combo_search_box_test.js b/ambari-web/test/views/main/host/combo_search_box_test.js
new file mode 100644
index 0000000..9c2e7b6
--- /dev/null
+++ b/ambari-web/test/views/main/host/combo_search_box_test.js
@@ -0,0 +1,42 @@
+/**
+ * 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');
+var view;
+
+describe('App.MainHostComboSearchBoxView', function () {
+
+  beforeEach(function () {
+    view = App.MainHostComboSearchBoxView.create();
+  });
+
+  describe("#didInsertElement()", function() {
+
+    beforeEach(function() {
+      sinon.stub(view, 'initVS');
+    });
+    afterEach(function() {
+      view.initVS.restore();
+    });
+
+    it("initVS should be called", function() {
+      view.didInsertElement();
+      expect(view.initVS.calledOnce).to.be.true;
+    });
+  });
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/30438e90/ambari-web/test/views/main/host/config_service_menu_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/main/host/config_service_menu_test.js b/ambari-web/test/views/main/host/config_service_menu_test.js
new file mode 100644
index 0000000..6d0481e
--- /dev/null
+++ b/ambari-web/test/views/main/host/config_service_menu_test.js
@@ -0,0 +1,140 @@
+/**
+ * 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');
+var misc = require('utils/misc');
+var view;
+
+describe('App.MainHostServiceMenuView', function () {
+
+  beforeEach(function () {
+    view = App.MainHostServiceMenuView.create({
+      host: Em.Object.create(),
+      controller: Em.Object.create({
+        connectOutlet: Em.K
+      })
+    });
+  });
+
+  describe("#content", function() {
+
+    beforeEach(function() {
+      sinon.stub(App, 'get').returns([]);
+      sinon.stub(App.StackService, 'find').returns([]);
+      sinon.stub(misc, 'sortByOrder', function(stackServices, services) {
+        return services;
+      });
+    });
+    afterEach(function() {
+      App.StackService.find.restore();
+      misc.sortByOrder.restore();
+      App.get.restore();
+    });
+
+    it("no hostComponents", function() {
+      view.set('host', Em.Object.create({
+        hostComponents: null
+      }));
+      view.propertyDidChange('content');
+      expect(view.get('content')).to.be.empty;
+    });
+
+    it("hostComponents without service", function() {
+      view.set('host', Em.Object.create({
+        hostComponents: [
+          Em.Object.create({
+            service: null
+          })
+        ]
+      }));
+      view.propertyDidChange('content');
+      expect(view.get('content')).to.be.empty;
+    });
+
+    it("hostComponents with service", function() {
+      view.set('host', Em.Object.create({
+        hostComponents: [
+          Em.Object.create({
+            service: Em.Object.create({
+              serviceName: 'S1'
+            })
+          })
+        ]
+      }));
+      view.propertyDidChange('content');
+      expect(view.get('content').mapProperty('serviceName')).to.eql(['S1']);
+    });
+
+    it("hostComponents with the same services", function() {
+      view.set('host', Em.Object.create({
+        hostComponents: [
+          Em.Object.create({
+            service: Em.Object.create({
+              serviceName: 'S1'
+            })
+          }),
+          Em.Object.create({
+            service: Em.Object.create({
+              serviceName: 'S1'
+            })
+          })
+        ]
+      }));
+      view.propertyDidChange('content');
+      expect(view.get('content').mapProperty('serviceName')).to.eql(['S1']);
+    });
+  });
+
+
+
+  describe("#showHostService()", function() {
+
+    beforeEach(function() {
+      sinon.stub(view.get('controller'), 'connectOutlet');
+    });
+    afterEach(function() {
+      view.get('controller').connectOutlet.restore()
+    });
+
+    it("service is absent", function() {
+      view.showHostService({contexts: []});
+      expect(view.get('controller').connectOutlet.called).to.be.false;
+    });
+
+    it("service is present", function() {
+      view.showHostService({contexts: [{serviceName: 'S1'}]});
+      expect(view.get('controller').connectOutlet.calledWith('service_config_outlet', 'mainHostServiceConfigs', {serviceName: 'S1', host: Em.Object.create()})).to.be.true;
+    });
+  });
+
+  describe("#didInsertElement()", function() {
+
+    beforeEach(function() {
+      sinon.stub(view, 'showHostService');
+    });
+    afterEach(function() {
+      view.showHostService.restore();
+    });
+
+    it("showHostService should be called", function() {
+      view.didInsertElement();
+      expect(view.showHostService.calledWith({contexts: [undefined]})).to.be.true;
+    });
+  });
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/30438e90/ambari-web/test/views/main/host/config_service_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/main/host/config_service_test.js b/ambari-web/test/views/main/host/config_service_test.js
new file mode 100644
index 0000000..bcd0660
--- /dev/null
+++ b/ambari-web/test/views/main/host/config_service_test.js
@@ -0,0 +1,46 @@
+/**
+ * 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');
+var view;
+
+describe('App.MainHostServiceConfigsView', function () {
+
+  beforeEach(function () {
+    view = App.MainHostServiceConfigsView.create({
+      controller: Em.Object.create({
+        loadStep: Em.K
+      })
+    });
+  });
+
+  describe("#didInsertElement()", function() {
+
+    beforeEach(function() {
+      sinon.stub(view.get('controller'), 'loadStep');
+    });
+    afterEach(function() {
+      view.get('controller').loadStep.restore();
+    });
+
+    it("loadStep should be called", function() {
+      view.didInsertElement();
+      expect(view.get('controller').loadStep.calledOnce).to.be.true;
+    });
+  });
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/30438e90/ambari-web/test/views/main/host/host_alerts_view_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/main/host/host_alerts_view_test.js b/ambari-web/test/views/main/host/host_alerts_view_test.js
index 6574309..cd38f49 100644
--- a/ambari-web/test/views/main/host/host_alerts_view_test.js
+++ b/ambari-web/test/views/main/host/host_alerts_view_test.js
@@ -25,7 +25,10 @@ describe('App.MainHostAlertsView', function () {
 
   beforeEach(function () {
     view = App.MainHostAlertsView.create({
-      controller: Em.Object.create()
+      controller: Em.Object.create(),
+      parentView: Em.Object.create({
+        controller: Em.Object.create()
+      })
     });
   });
 
@@ -114,4 +117,139 @@ describe('App.MainHostAlertsView', function () {
 
   });
 
+  describe("#willInsertElement()", function() {
+    var mock = {
+      loadAlertInstancesByHost: Em.K
+    };
+
+    beforeEach(function() {
+      sinon.stub(App.router, 'get').returns(mock);
+      sinon.spy(mock, 'loadAlertInstancesByHost');
+      sinon.stub(App.router, 'set');
+      view.set('parentView.controller.content', Em.Object.create({
+        hostName: 'host1'
+      }));
+    });
+    afterEach(function() {
+      mock.loadAlertInstancesByHost.restore();
+      App.router.get.restore();
+      App.router.set.restore();
+    });
+
+    it("loadAlertInstancesByHost should be called", function() {
+      view.willInsertElement();
+      expect(App.router.set.calledWith('mainAlertInstancesController.isUpdating', true)).to.be.true;
+    });
+
+    it("App.router.set should be called", function() {
+      view.willInsertElement();
+      expect(App.router.set.calledWith('mainAlertInstancesController.isUpdating', true)).to.be.true;
+    });
+  });
+
+  describe("#didInsertElement()", function() {
+
+    beforeEach(function() {
+      sinon.spy(view, 'tooltipsUpdater');
+    });
+    afterEach(function() {
+      view.tooltipsUpdater.restore();
+    });
+
+    it("tooltipsUpdater should be called", function() {
+      view.didInsertElement();
+      expect(view.tooltipsUpdater.calledOnce).to.be.true;
+    });
+  });
+
+
+  describe("#paginationLeftClass", function() {
+
+    it("startIndex is 2", function() {
+      view.set('startIndex', 2);
+      expect(view.get('paginationLeftClass')).to.equal('paginate_previous');
+    });
+
+    it("startIndex is 1", function() {
+      view.set('startIndex', 1);
+      expect(view.get('paginationLeftClass')).to.equal('paginate_disabled_previous');
+    });
+
+    it("startIndex is 0", function() {
+      view.set('startIndex', 0);
+      expect(view.get('paginationLeftClass')).to.equal('paginate_disabled_previous');
+    });
+  });
+
+  describe("#paginationRightClass", function() {
+
+    it("endIndex more than filteredCount", function() {
+      view.reopen({
+        endIndex: 4,
+        filteredCount: 3
+      });
+      expect(view.get('paginationRightClass')).to.equal('paginate_disabled_next');
+    });
+
+    it("endIndex equal to filteredCount", function() {
+      view.reopen({
+        endIndex: 4,
+        filteredCount: 4
+      });
+      expect(view.get('paginationRightClass')).to.equal('paginate_disabled_next');
+    });
+
+    it("endIndex less than filteredCount", function() {
+      view.reopen({
+        endIndex: 3,
+        filteredCount: 4
+      });
+      view.propertyDidChange('paginationRightClass');
+      expect(view.get('paginationRightClass')).to.equal('paginate_next');
+    });
+  });
+
+  describe("#clearFilters()", function() {
+    var mock = {
+      clearFilter: Em.K
+    };
+
+    beforeEach(function() {
+      sinon.spy(mock, 'clearFilter');
+    });
+    afterEach(function() {
+      mock.clearFilter.restore();
+    });
+
+    it("clearFilter should be called", function() {
+      view.reopen({
+        'childViews': [mock]
+      });
+      view.clearFilters();
+      expect(view.get('filterConditions')).to.be.empty;
+      expect(mock.clearFilter.calledOnce).to.be.true;
+    });
+  });
+
+  describe("#willDestroyElement()", function() {
+    var mock = {
+      tooltip: Em.K
+    };
+
+    beforeEach(function() {
+      sinon.stub(view, '$').returns(mock);
+      sinon.spy(mock, 'tooltip');
+    });
+    afterEach(function() {
+      view.$.restore();
+      mock.tooltip.restore();
+    });
+
+    it("tooltip should be called", function() {
+      view.willDestroyElement();
+      expect(view.$.calledWith(".enable-disable-button, .timeago, .alert-text")).to.be.true;
+      expect(mock.tooltip.calledWith('destroy')).to.be.true;
+    });
+  });
+
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/30438e90/ambari-web/test/views/main/host/menu_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/main/host/menu_test.js b/ambari-web/test/views/main/host/menu_test.js
index 59facf1..520314d 100644
--- a/ambari-web/test/views/main/host/menu_test.js
+++ b/ambari-web/test/views/main/host/menu_test.js
@@ -89,4 +89,45 @@ describe('App.MainHostMenuView', function () {
     });
   });
 
-});
+  describe("#updateAlertCounter()", function() {
+
+    it("CRITICAL alerts", function() {
+      view.setProperties({
+        host: Em.Object.create({
+          criticalWarningAlertsCount: 1,
+          alertsSummary: Em.Object.create({
+            CRITICAL: 1,
+            WARNING: 0
+          })
+        })
+      });
+      view.updateAlertCounter();
+      expect(view.get('content').findProperty('name', 'alerts').get('badgeText')).to.equal('1');
+      expect(view.get('content').findProperty('name', 'alerts').get('badgeClasses')).to.equal('label alerts-crit-count');
+    });
+
+    it("WARNING alerts", function() {
+      view.setProperties({
+        host: Em.Object.create({
+          criticalWarningAlertsCount: 1,
+          alertsSummary: Em.Object.create({
+            CRITICAL: 0,
+            WARNING: 1
+          })
+        })
+      });
+      view.updateAlertCounter();
+      expect(view.get('content').findProperty('name', 'alerts').get('badgeText')).to.equal('1');
+      expect(view.get('content').findProperty('name', 'alerts').get('badgeClasses')).to.equal('label alerts-warn-count');
+    });
+  });
+
+  describe("#deactivateChildViews()", function() {
+    it("active attr should be empty", function() {
+      view.set('_childViews', [Em.Object.create({active: 'active'})]);
+      view.deactivateChildViews();
+      expect(view.get('_childViews').mapProperty('active')).to.eql(['']);
+    });
+  });
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/30438e90/ambari-web/test/views/main/host/summary_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/main/host/summary_test.js b/ambari-web/test/views/main/host/summary_test.js
index 2add4d0..47dbf3d 100644
--- a/ambari-web/test/views/main/host/summary_test.js
+++ b/ambari-web/test/views/main/host/summary_test.js
@@ -24,21 +24,34 @@ require('mappers/server_data_mapper');
 require('views/main/host/summary');
 
 var mainHostSummaryView;
-var extendedMainHostSummaryView = App.MainHostSummaryView.extend({content: {}, addToolTip: function(){}, installedServices: []});
 var modelSetup = require('test/init_model_test');
 
 describe('App.MainHostSummaryView', function() {
 
   beforeEach(function() {
     modelSetup.setupStackServiceComponent();
-    mainHostSummaryView = extendedMainHostSummaryView.create({});
+    mainHostSummaryView = App.MainHostSummaryView.create({content: Em.Object.create()});
   });
 
   afterEach(function(){
     modelSetup.cleanStackServiceComponent();
   });
 
-  describe('#sortedComponents', function() {
+  describe("#installedServices", function() {
+
+    beforeEach(function() {
+      sinon.stub(App.Service, 'find').returns([Em.Object.create({serviceName: 'S1'})]);
+    });
+    afterEach(function() {
+      App.Service.find.restore();
+    });
+
+    it("should return installed services", function() {
+      expect(mainHostSummaryView.get('installedServices')).to.eql(['S1']);
+    });
+  });
+
+  describe('#sortedComponentsFormatter()', function() {
 
     var tests = Em.A([
       {
@@ -274,108 +287,70 @@ describe('App.MainHostSummaryView', function() {
 
   describe('#addableComponents', function() {
 
+    beforeEach(function() {
+      this.mock = sinon.stub(App.StackServiceComponent, 'find');
+    });
+    afterEach(function() {
+      App.StackServiceComponent.find.restore();
+    });
+
     var tests = Em.A([
       {
-        installableClientComponents: [{}, {}],
+        addableToHostComponents: [
+          Em.Object.create({
+            serviceName: 'HDFS',
+            componentName: 'DATANODE',
+            isAddableToHost: true
+          }),
+          Em.Object.create({
+            serviceName: 'HDFS',
+            componentName: 'HDFS_CLIENT',
+            isAddableToHost: true
+          })
+        ],
         content: Em.Object.create({
           hostComponents: Em.A([
             Em.Object.create({
               componentName: 'HDFS_CLIENT'
-            }),
-            Em.Object.create({
-              componentName: 'DATANODE'
             })
           ])
         }),
-        services: ['HDFS', 'YARN', 'MAPREDUCE2'],
-        e: ['NODEMANAGER', 'YARN_CLIENT', 'MAPREDUCE2_CLIENT'],
+        services: ['HDFS'],
+        e: ['DATANODE'],
         m: 'some components are already installed'
       },
       {
-        installableClientComponents: [],
+        addableToHostComponents: [
+          Em.Object.create({
+            serviceName: 'HDFS',
+            componentName: 'HDFS_CLIENT',
+            isAddableToHost: true
+          })
+        ],
         content: Em.Object.create({
           hostComponents: Em.A([
             Em.Object.create({
               componentName: 'HDFS_CLIENT'
-            }),
-            Em.Object.create({
-              componentName: 'YARN_CLIENT'
-            }),
-            Em.Object.create({
-              componentName: 'MAPREDUCE2_CLIENT'
-            }),
-            Em.Object.create({
-              componentName: 'NODEMANAGER'
             })
           ])
         }),
-        services: ['HDFS', 'YARN', 'MAPREDUCE2'],
-        e: ['DATANODE'],
-        m: 'all clients and some other components are already installed'
+        services: ['HDFS'],
+        e: [],
+        m: 'all components are already installed'
       }
     ]);
 
     tests.forEach(function(test) {
       it(test.m, function() {
-        mainHostSummaryView.reopen({installableClientComponents: test.installableClientComponents});
+        this.mock.returns(test.addableToHostComponents);
         mainHostSummaryView.set('content', test.content);
-        mainHostSummaryView.set('installedServices', test.services);
-        expect(mainHostSummaryView.get('addableComponents').mapProperty('componentName')).to.eql(test.e);
-      });
-    });
-
-  });
-
-  describe("#clientsWithCustomCommands", function() {
-    before(function() {
-      sinon.stub(App.StackServiceComponent, 'find', function(component) {
-        var customCommands = [];
-
-        if (component === 'WITH_CUSTOM_COMMANDS') {
-          customCommands = ['CUSTOMCOMMAND'];
-        }
-
-        var obj = Em.Object.create({
-          customCommands: customCommands,
-          filterProperty: function () {
-            return {
-              mapProperty: Em.K
-            };
-          }
+        mainHostSummaryView.reopen({
+          installedServices: test.services
         });
-        return obj;
+        mainHostSummaryView.propertyDidChange('addableComponents');
+        expect(mainHostSummaryView.get('addableComponents').mapProperty('componentName')).to.eql(test.e);
       });
     });
-
-    after(function() {
-      App.StackServiceComponent.find.restore();
-    });
-    var content = Em.Object.create({
-      hostComponents: Em.A([
-        Em.Object.create({
-          componentName: 'WITH_CUSTOM_COMMANDS',
-          displayName: 'WITH_CUSTOM_COMMANDS',
-          hostName: 'c6401',
-          service: Em.Object.create({
-            serviceName: 'TESTSRV'
-          })
-        }),
-        Em.Object.create({
-          componentName: 'WITHOUT_CUSTOM_COMMANDS',
-          displayName: 'WITHOUT_CUSTOM_COMMANDS',
-          hostName: 'c6401',
-          service: Em.Object.create({
-            serviceName: 'TESTSRV'
-          })
-        })
-      ])
-    });
-
-    it("Clients with custom commands only", function() {
-      mainHostSummaryView.set('content', content);
-      expect(mainHostSummaryView.get('clientsWithCustomCommands').length).to.be.equal(1);
-      expect(mainHostSummaryView.get('clientsWithCustomCommands')).to.have.deep.property('[0].commands[0].command', 'CUSTOMCOMMAND');
-    });
   });
 
   describe('#areClientsNotInstalled', function () {
@@ -475,4 +450,152 @@ describe('App.MainHostSummaryView', function() {
     });
 
   });
+
+  describe("#needToRestartMessage", function() {
+
+    it("one component", function() {
+      var expected = Em.I18n.t('hosts.host.details.needToRestart').format(1, Em.I18n.t('common.component').toLowerCase());
+      mainHostSummaryView.set('content', Em.Object.create({
+        componentsWithStaleConfigsCount: 1
+      }));
+      expect(mainHostSummaryView.get('needToRestartMessage')).to.equal(expected);
+    });
+
+    it("multiple components", function() {
+      var expected = Em.I18n.t('hosts.host.details.needToRestart').format(2, Em.I18n.t('common.components').toLowerCase());
+      mainHostSummaryView.set('content', Em.Object.create({
+        componentsWithStaleConfigsCount: 2
+      }));
+      expect(mainHostSummaryView.get('needToRestartMessage')).to.equal(expected);
+    });
+
+  });
+
+  describe("#redrawComponents()", function() {
+
+    beforeEach(function() {
+      this.mock = sinon.stub(App.router, 'get');
+      sinon.stub(mainHostSummaryView, 'sortedComponentsFormatter');
+      sinon.stub(App.router, 'set');
+    });
+    afterEach(function() {
+      this.mock.restore();
+      mainHostSummaryView.sortedComponentsFormatter.restore();
+      App.router.set.restore();
+    });
+
+    it("redrawComponents is false", function() {
+      this.mock.returns(false);
+      mainHostSummaryView.redrawComponents();
+      expect(mainHostSummaryView.sortedComponentsFormatter.called).to.be.false;
+    });
+
+    it("redrawComponents is true", function() {
+      this.mock.returns(true);
+      mainHostSummaryView.redrawComponents();
+      expect(mainHostSummaryView.sortedComponentsFormatter.calledOnce).to.be.true;
+      expect(mainHostSummaryView.get('sorteComponents')).to.be.empty;
+      expect(App.router.set.calledWith('mainHostDetailsController.redrawComponents', false)).to.be.true;
+    });
+
+  });
+
+  describe("#willInsertElement()", function() {
+
+    beforeEach(function() {
+      sinon.stub(mainHostSummaryView, 'sortedComponentsFormatter');
+      sinon.stub(mainHostSummaryView, 'addObserver');
+    });
+    afterEach(function() {
+      mainHostSummaryView.sortedComponentsFormatter.restore();
+      mainHostSummaryView.addObserver.restore();
+    });
+
+    it("sortedComponentsFormatter should be called ", function() {
+      mainHostSummaryView.willInsertElement();
+      expect(mainHostSummaryView.sortedComponentsFormatter.calledOnce).to.be.true;
+      expect(mainHostSummaryView.addObserver.calledWith('content.hostComponents.length', mainHostSummaryView, 'sortedComponentsFormatter')).to.be.true;
+      expect(mainHostSummaryView.get('sortedComponents')).to.be.empty;
+    });
+  });
+
+  describe("#didInsertElement()", function() {
+
+    beforeEach(function() {
+      sinon.stub(mainHostSummaryView, 'addToolTip');
+    });
+    afterEach(function() {
+      mainHostSummaryView.addToolTip.restore();
+    });
+
+    it("addToolTip should be called", function() {
+      mainHostSummaryView.didInsertElement();
+      expect(mainHostSummaryView.addToolTip.calledOnce).to.be.true;
+    });
+  });
+
+  describe("#addToolTip()", function() {
+
+    beforeEach(function() {
+      sinon.stub(App, 'tooltip');
+      mainHostSummaryView.removeObserver('addComponentDisabled', mainHostSummaryView, 'addToolTip');
+    });
+    afterEach(function() {
+      App.tooltip.restore();
+    });
+
+    it("addComponentDisabled is false ", function() {
+      mainHostSummaryView.reopen({
+        addComponentDisabled: false
+      });
+      mainHostSummaryView.addToolTip();
+      expect(App.tooltip.called).to.be.false;
+    });
+
+    it("addComponentDisabled is true ", function() {
+      mainHostSummaryView.reopen({
+        addComponentDisabled: true
+      });
+      mainHostSummaryView.addToolTip();
+      expect(App.tooltip.called).to.be.true;
+    });
+
+  });
+
+  describe("#installableClientComponents", function() {
+
+    beforeEach(function() {
+      sinon.stub(App.StackServiceComponent, 'find').returns([
+        Em.Object.create({
+          isClient: true,
+          serviceName: 'S1',
+          componentName: 'C1'
+        }),
+        Em.Object.create({
+          isClient: true,
+          serviceName: 'S1',
+          componentName: 'C2'
+        }),
+        Em.Object.create({
+          isClient: true,
+          serviceName: 'S2',
+          componentName: 'C1'
+        })
+      ]);
+    });
+    afterEach(function() {
+      App.StackServiceComponent.find.restore();
+    });
+
+    it("should return installable client components", function() {
+      mainHostSummaryView.reopen({
+        installedServices: ['S1'],
+        clients: [
+          Em.Object.create({componentName: 'C2'})
+        ]
+      });
+      mainHostSummaryView.propertyDidChange('installableClientComponents');
+      expect(mainHostSummaryView.get('installableClientComponents').mapProperty('componentName')).to.eql(['C1']);
+    });
+  });
 });