Repository: ambari
Updated Branches:
  refs/heads/branch-3.0-perf d4cd91436 -> f26436798


AMBARI-21404 Integrate Hosts page with websocket events. (atkach)


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

Branch: refs/heads/branch-3.0-perf
Commit: f2643679847f9123b3b522651987ef12f3e96aad
Parents: d4cd914
Author: Andrii Tkach <[email protected]>
Authored: Wed Jul 5 14:55:04 2017 +0300
Committer: Andrii Tkach <[email protected]>
Committed: Wed Jul 5 14:55:04 2017 +0300

----------------------------------------------------------------------
 ambari-web/app/assets/test/tests.js             |  1 +
 .../app/controllers/global/update_controller.js | 25 +++++++++--
 ambari-web/app/mappers.js                       |  1 +
 ambari-web/app/mappers/hosts_mapper.js          |  5 +--
 .../socket/host_component_status_mapper.js      | 10 +++--
 .../app/mappers/socket/host_state_mapper.js     | 37 ++++++++++++++++
 ambari-web/app/messages.js                      |  1 +
 ambari-web/app/models/host.js                   | 12 ++++--
 ambari-web/app/utils/stomp_client.js            |  2 +-
 ambari-web/app/views/main/host/summary.js       | 10 +++--
 .../global/update_controller_test.js            |  4 +-
 .../socket/host_component_status_mapper_test.js | 10 +++--
 .../mappers/socket/host_state_mapper_test.js    | 44 ++++++++++++++++++++
 ambari-web/test/models/host_test.js             | 14 +++++++
 ambari-web/test/views/main/host/summary_test.js | 17 ++++++--
 15 files changed, 166 insertions(+), 27 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/f2643679/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 11ab702..5575627 100644
--- a/ambari-web/app/assets/test/tests.js
+++ b/ambari-web/app/assets/test/tests.js
@@ -170,6 +170,7 @@ var files = [
   'test/mappers/socket/alert_summary_mapper_test',
   'test/mappers/socket/host_component_status_mapper_test',
   'test/mappers/socket/service_state_mapper_test',
+  'test/mappers/socket/host_state_mapper_test',
   'test/mixins/common/configs/enhanced_configs_test',
   'test/mixins/common/configs/config_recommendations_test',
   'test/mixins/common/configs/config_recommendation_parser_test',

http://git-wip-us.apache.org/repos/asf/ambari/blob/f2643679/ambari-web/app/controllers/global/update_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/global/update_controller.js 
b/ambari-web/app/controllers/global/update_controller.js
index 109b266..d556831 100644
--- a/ambari-web/app/controllers/global/update_controller.js
+++ b/ambari-web/app/controllers/global/update_controller.js
@@ -192,8 +192,9 @@ App.UpdateController = Em.Controller.extend({
       App.StompClient.subscribe('/events/topologies', 
App.topologyMapper.map.bind(App.topologyMapper));
       App.StompClient.subscribe('/events/configs', 
this.makeCallForClusterEnv.bind(this));
       App.StompClient.subscribe('/events/services', 
App.serviceStateMapper.map.bind(App.serviceStateMapper));
+      App.StompClient.subscribe('/events/hosts', 
App.hostStateMapper.map.bind(App.hostStateMapper));
 
-      App.updater.run(this, 'updateHost', 'isWorking');
+      App.updater.run(this, 'updateHostsMetrics', 'isWorking', 
App.contentUpdateInterval, '\/main\/(hosts).*');
       App.updater.run(this, 'updateServiceMetric', 'isWorking', 
App.componentsUpdateInterval, '\/main\/(dashboard|services).*');
       App.updater.run(this, 'updateComponentsState', 'isWorking', 
App.componentsUpdateInterval, '\/main\/(dashboard|services|hosts).*');
       App.updater.run(this, 'graphsUpdate', 'isWorking');
@@ -212,6 +213,7 @@ App.UpdateController = Em.Controller.extend({
       App.StompClient.unsubscribe('/events/topologies');
       App.StompClient.unsubscribe('/events/configs');
       App.StompClient.unsubscribe('/events/services');
+      App.StompClient.unsubscribe('/events/hosts');
     }
   }.observes('isWorking', 
'App.router.mainAlertInstancesController.isUpdating'),
 
@@ -226,7 +228,7 @@ App.UpdateController = Em.Controller.extend({
         self = this,
         hostDetailsFilter = '',
         realUrl = 
'/hosts?fields=Hosts/rack_info,Hosts/host_name,Hosts/maintenance_state,Hosts/public_host_name,Hosts/cpu_count,Hosts/ph_cpu_count,Hosts/last_agent_env,'
 +
-            
'alerts_summary,Hosts/host_status,Hosts/last_heartbeat_time,Hosts/ip,host_components/HostRoles/state,host_components/HostRoles/maintenance_state,'
 +
+            
'alerts_summary,Hosts/host_status,Hosts/host_state,Hosts/last_heartbeat_time,Hosts/ip,host_components/HostRoles/state,host_components/HostRoles/maintenance_state,'
 +
             
'host_components/HostRoles/stale_configs,host_components/HostRoles/service_name,host_components/HostRoles/display_name,host_components/HostRoles/desired_admin_state,'
 +
             
'<metrics>Hosts/total_mem<hostDetailsParams><stackVersions>&minimal_response=true',
         hostDetailsParams = 
',Hosts/os_arch,Hosts/os_type,metrics/cpu/cpu_system,metrics/cpu/cpu_user,metrics/memory/mem_total,metrics/memory/mem_free',
@@ -316,6 +318,23 @@ App.UpdateController = Em.Controller.extend({
     }
   },
 
+  updateHostsMetrics: function(callback) {
+    let queryParams = 
App.router.get('mainHostController').getQueryParameters(true);
+    if (App.router.get('currentState.parentState.name') === 'hostDetails') {
+      const currentHostname = App.router.get('location.lastSetURL')
+        
.match(/\/hosts\/(.*)\/(summary|configs|alerts|stackVersions|logs)/)[1];
+      queryParams = [
+        {
+          key: 'Hosts/host_name',
+          value: [currentHostname],
+          type: 'MULTIPLE',
+          isHostDetails: true
+        }
+      ]
+    }
+    this.loadHostsMetric(queryParams).always(callback);
+  },
+
   /**
    *
    * @param {Array} queryParams
@@ -353,7 +372,7 @@ App.UpdateController = Em.Controller.extend({
         success: 'loadHostsMetricSuccessCallback'
       });
     }
-    return null;
+    return $.Deferred().resolve().promise();
   },
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/f2643679/ambari-web/app/mappers.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mappers.js b/ambari-web/app/mappers.js
index aca5291..f4c7e5c 100644
--- a/ambari-web/app/mappers.js
+++ b/ambari-web/app/mappers.js
@@ -49,3 +49,4 @@ require('mappers/socket/topology_mapper');
 require('mappers/socket/service_state_mapper');
 require('mappers/socket/host_component_status_mapper');
 require('mappers/socket/alert_summary_mapper');
+require('mappers/socket/host_state_mapper');

http://git-wip-us.apache.org/repos/asf/ambari/blob/f2643679/ambari-web/app/mappers/hosts_mapper.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mappers/hosts_mapper.js 
b/ambari-web/app/mappers/hosts_mapper.js
index 203cd67..545f312 100644
--- a/ambari-web/app/mappers/hosts_mapper.js
+++ b/ambari-web/app/mappers/hosts_mapper.js
@@ -43,6 +43,7 @@ App.hostsMapper = App.QuickDataMapper.create({
     disk_total: 'metrics.disk.disk_total',
     disk_free: 'metrics.disk.disk_free',
     health_status: 'Hosts.host_status',
+    state: 'Hosts.host_state',
     load_one: 'metrics.load.load_one',
     load_five: 'metrics.load.load_five',
     load_fifteen: 'metrics.load.load_fifteen',
@@ -51,7 +52,6 @@ App.hostsMapper = App.QuickDataMapper.create({
     mem_total: 'metrics.memory.mem_total',
     mem_free: 'metrics.memory.mem_free',
     last_heart_beat_time: "Hosts.last_heartbeat_time",
-    raw_last_heart_beat_time: "Hosts.last_heartbeat_time",
     os_arch: 'Hosts.os_arch',
     os_type: 'Hosts.os_type',
     ip: 'Hosts.ip',
@@ -177,8 +177,6 @@ App.hostsMapper = App.QuickDataMapper.create({
           stackVersions.push(this.parseIt(stackVersion, 
this.stackVersionConfig));
         }
 
-        var alertsSummary = item.alerts_summary;
-        item.critical_warning_alerts_count = alertsSummary ? 
(alertsSummary.CRITICAL || 0) + (alertsSummary.WARNING || 0) : 0;
         item.cluster_id = clusterName;
         var existingHost = hostsMap[item.Hosts.host_name];
         // There is no need to override existing index in host detail view 
since old model(already have indexes) will not be cleared.
@@ -193,7 +191,6 @@ App.hostsMapper = App.QuickDataMapper.create({
         });
         var parsedItem = this.parseIt(item, this.config);
 
-        parsedItem.last_heart_beat_time = 
App.dateTimeWithTimeZone(parsedItem.last_heart_beat_time);
         parsedItem.selected = selectedHosts.contains(parsedItem.host_name);
         parsedItem.not_started_components = notStartedComponents;
         parsedItem.components_in_passive_state = componentsInPassiveState;

http://git-wip-us.apache.org/repos/asf/ambari/blob/f2643679/ambari-web/app/mappers/socket/host_component_status_mapper.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mappers/socket/host_component_status_mapper.js 
b/ambari-web/app/mappers/socket/host_component_status_mapper.js
index 6069cbc..0d253d4 100644
--- a/ambari-web/app/mappers/socket/host_component_status_mapper.js
+++ b/ambari-web/app/mappers/socket/host_component_status_mapper.js
@@ -23,9 +23,11 @@ App.hostComponentStatusMapper = App.QuickDataMapper.create({
    * @param {object} event
    */
   map: function (event) {
-    const hostComponent = App.HostComponent.find(event.componentName + '_' + 
event.hostName);
-    if (hostComponent.get('isLoaded')) {
-      hostComponent.set('workStatus', event.currentState);
-    }
+    event.hostComponents.forEach((componentState) => {
+      const hostComponent = 
App.HostComponent.find(componentState.componentName + '_' + 
componentState.hostName);
+      if (hostComponent.get('isLoaded')) {
+        hostComponent.set('workStatus', componentState.currentState);
+      }
+    });
   }
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/f2643679/ambari-web/app/mappers/socket/host_state_mapper.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mappers/socket/host_state_mapper.js 
b/ambari-web/app/mappers/socket/host_state_mapper.js
new file mode 100644
index 0000000..7d469d7
--- /dev/null
+++ b/ambari-web/app/mappers/socket/host_state_mapper.js
@@ -0,0 +1,37 @@
+/**
+ * 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');
+
+App.hostStateMapper = App.QuickDataMapper.create({
+
+  config: {
+    alertsSummary: 'alerts_summary',
+    healthStatus: 'host_status',
+    state: 'host_state',
+    lastHeartBeatTime: 'last_heartbeat_time',
+    passiveState: 'maintenance_state'
+  },
+
+  /**
+   * @param {object} event
+   */
+  map: function(event) {
+    //TODO event should have properties named in CamelCase format
+    this.updatePropertiesByConfig(App.Host.find(event.host_name), event, 
this.config);
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f2643679/ambari-web/app/messages.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js
index 8f8d981..f76821d 100644
--- a/ambari-web/app/messages.js
+++ b/ambari-web/app/messages.js
@@ -350,6 +350,7 @@ Em.I18n.translations = {
   'common.hostOrdered': 'Host Ordered',
   'common.rolling.downgrade': 'Rolling Downgrade',
   'common.express.downgrade': 'Express Downgrade',
+  'common.minute.ago': 'less than a minute ago',
 
   'models.alert_instance.tiggered.verbose': "Occurred on {0} <br> Checked on 
{1}",
   'models.alert_definition.triggered.verbose': "Occurred on {0}",

http://git-wip-us.apache.org/repos/asf/ambari/blob/f2643679/ambari-web/app/models/host.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/host.js b/ambari-web/app/models/host.js
index 58ffd41..4116cc3 100644
--- a/ambari-web/app/models/host.js
+++ b/ambari-web/app/models/host.js
@@ -37,8 +37,8 @@ App.Host = DS.Model.extend({
   ip: DS.attr('string'),
   rack: DS.attr('string'),
   healthStatus: DS.attr('string'),
+  state: DS.attr('string'),
   lastHeartBeatTime: DS.attr('number'),
-  rawLastHeartBeatTime: DS.attr('number'),
   hasJcePolicy: DS.attr('string'),
   osType: DS.attr("string"),
   diskInfo: DS.attr('object'),
@@ -49,7 +49,6 @@ App.Host = DS.Model.extend({
   memFree:DS.attr('number'),
   cpuSystem:DS.attr('number'),
   cpuUser:DS.attr('number'),
-  criticalWarningAlertsCount: DS.attr('number'),
   alertsSummary: DS.attr('object'),
   passiveState: DS.attr('string'),
   index: DS.attr('number'),
@@ -60,6 +59,11 @@ App.Host = DS.Model.extend({
    */
   selected:DS.attr('boolean'),
 
+  criticalWarningAlertsCount: function() {
+    const alertsSummary = this.get('alertsSummary');
+    return alertsSummary ? (alertsSummary.CRITICAL || 0) + 
(alertsSummary.WARNING || 0) : 0;
+  }.property('alertsSummary.CRITICAL', 'alertsSummary.WARNING'),
+
   currentVersion: function () {
     var current = this.get('stackVersions').findProperty('isCurrent');
     return current ? current.get('repoVersion') : null;
@@ -178,8 +182,8 @@ App.Host = DS.Model.extend({
    * @returns {bool}
    */
   isNotHeartBeating : function() {
-    return (App.get('testMode')) ? false : (this.get('healthStatus') === 
"UNKNOWN");
-  }.property('lastHeartBeatTime'),
+    return this.get('state') === "HEARTBEAT_LOST";
+  }.property('state'),
 
   /**
    * Average load

http://git-wip-us.apache.org/repos/asf/ambari/blob/f2643679/ambari-web/app/utils/stomp_client.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/stomp_client.js 
b/ambari-web/app/utils/stomp_client.js
index 11a62b7..18167f6 100644
--- a/ambari-web/app/utils/stomp_client.js
+++ b/ambari-web/app/utils/stomp_client.js
@@ -156,7 +156,7 @@ module.exports = Em.Object.extend({
     const handlers = {
       default: handler
     };
-    if (!this.get('client.connected') || 
this.get('subscriptions')[destination]) {
+    if (!this.get('client.connected')) {
       return null;
     }
     const subscription = this.get('client').subscribe(destination, (message) 
=> {

http://git-wip-us.apache.org/repos/asf/ambari/blob/f2643679/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 89332de..e1e4313 100644
--- a/ambari-web/app/views/main/host/summary.js
+++ b/ambari-web/app/views/main/host/summary.js
@@ -297,9 +297,13 @@ App.MainHostSummaryView = 
Em.View.extend(App.TimeRangeMixin, {
    * @type {String}
    */
   timeSinceHeartBeat: function () {
-    var d = this.get('content.rawLastHeartBeatTime');
-    return d ? $.timeago(d) : '';
-  }.property('content.rawLastHeartBeatTime'),
+    if (this.get('content.isNotHeartBeating')) {
+      const d = this.get('content.lastHeartBeatTime');
+      return d ? $.timeago(d) : '';
+    }
+    //when host hasn't lost heartbeat we assume that last heartbeat was a 
minute ago
+    return Em.I18n.t('common.minute.ago');
+  }.property('content.lastHeartBeatTime', 'content.isNotHeartBeating'),
 
   /**
    * Get clients with custom commands

http://git-wip-us.apache.org/repos/asf/ambari/blob/f2643679/ambari-web/test/controllers/global/update_controller_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/global/update_controller_test.js 
b/ambari-web/test/controllers/global/update_controller_test.js
index c793750..44b6c36 100644
--- a/ambari-web/test/controllers/global/update_controller_test.js
+++ b/ambari-web/test/controllers/global/update_controller_test.js
@@ -74,6 +74,7 @@ describe('App.UpdateController', function () {
       
expect(App.StompClient.unsubscribe.calledWith('/events/topologies')).to.be.true;
       
expect(App.StompClient.unsubscribe.calledWith('/events/configs')).to.be.true;
       
expect(App.StompClient.unsubscribe.calledWith('/events/services')).to.be.true;
+      
expect(App.StompClient.unsubscribe.calledWith('/events/hosts')).to.be.true;
     });
 
     it('isWorking = true', function () {
@@ -84,6 +85,7 @@ describe('App.UpdateController', function () {
       
expect(App.StompClient.subscribe.calledWith('/events/topologies')).to.be.true;
       
expect(App.StompClient.subscribe.calledWith('/events/configs')).to.be.true;
       
expect(App.StompClient.subscribe.calledWith('/events/services')).to.be.true;
+      expect(App.StompClient.subscribe.calledWith('/events/hosts')).to.be.true;
     });
   });
 
@@ -290,7 +292,7 @@ describe('App.UpdateController', function () {
     });
     it("AMBARI_METRICS is not started", function () {
       this.mock.returns(Em.Object.create({isStarted: false}));
-      expect(controller.loadHostsMetric([])).to.be.null;
+      expect(controller.loadHostsMetric([])).to.be.object;
       var args = testHelpers.findAjaxRequest('name', 
'hosts.metrics.lazy_load');
       expect(args).to.not.exists;
     });

http://git-wip-us.apache.org/repos/asf/ambari/blob/f2643679/ambari-web/test/mappers/socket/host_component_status_mapper_test.js
----------------------------------------------------------------------
diff --git 
a/ambari-web/test/mappers/socket/host_component_status_mapper_test.js 
b/ambari-web/test/mappers/socket/host_component_status_mapper_test.js
index 0de9846..eab309e 100644
--- a/ambari-web/test/mappers/socket/host_component_status_mapper_test.js
+++ b/ambari-web/test/mappers/socket/host_component_status_mapper_test.js
@@ -36,9 +36,13 @@ describe('App.hostComponentStatusMapper', function () {
 
     it('host-component should have STARTED status', function() {
       const event = {
-        componentName: 'C1',
-        hostName: 'host1',
-        currentState: 'STARTED'
+        hostComponents: [
+          {
+            componentName: 'C1',
+            hostName: 'host1',
+            currentState: 'STARTED'
+          }
+        ]
       };
       App.hostComponentStatusMapper.map(event);
       expect(hc.get('workStatus')).to.be.equal('STARTED');

http://git-wip-us.apache.org/repos/asf/ambari/blob/f2643679/ambari-web/test/mappers/socket/host_state_mapper_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/mappers/socket/host_state_mapper_test.js 
b/ambari-web/test/mappers/socket/host_state_mapper_test.js
new file mode 100644
index 0000000..614015c
--- /dev/null
+++ b/ambari-web/test/mappers/socket/host_state_mapper_test.js
@@ -0,0 +1,44 @@
+/**
+ * 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('mappers/socket/host_state_mapper');
+
+describe('App.hostStateMapper', function () {
+
+  describe('#map', function() {
+    beforeEach(function() {
+      sinon.stub(App.Host, 'find');
+      sinon.stub(App.hostStateMapper, 'updatePropertiesByConfig');
+    });
+    afterEach(function() {
+      App.Host.find.restore();
+      App.hostStateMapper.updatePropertiesByConfig.restore();
+    });
+
+    it('updatePropertiesByConfig should be called', function() {
+      const event = {
+        host_name: 'S1',
+        state: 'HEARTBEAT_LOST'
+      };
+      App.hostStateMapper.map(event);
+      
expect(App.hostStateMapper.updatePropertiesByConfig.calledOnce).to.be.true;
+    });
+  });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/f2643679/ambari-web/test/models/host_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/models/host_test.js 
b/ambari-web/test/models/host_test.js
index 5b63b10..fc3e391 100644
--- a/ambari-web/test/models/host_test.js
+++ b/ambari-web/test/models/host_test.js
@@ -31,6 +31,7 @@ describe('App.Host', function () {
       disk_total: 100.555,
       disk_free: 90.555,
       health_status: 'HEALTHY',
+      state: 'HEALTHY',
       last_heart_beat_time: (new Date()).getTime() - 18100000
     },
     {
@@ -40,6 +41,7 @@ describe('App.Host', function () {
       disk_total: 90,
       disk_free: 90,
       health_status: 'HEALTHY',
+      state: 'HEALTHY',
       last_heart_beat_time: (new Date()).getTime() - 170000
     },
     {
@@ -49,6 +51,7 @@ describe('App.Host', function () {
       disk_total: 99.999,
       disk_free: 0,
       health_status: 'UNKNOWN',
+      state: 'HEARTBEAT_LOST',
       last_heart_beat_time: (new Date()).getTime()
     }
   ];
@@ -425,6 +428,17 @@ describe('App.Host', function () {
     });
   });
 
+  describe('#criticalWarningAlertsCount', function () {
+    it('should return sum of critical and warning alerts', function () {
+      host1.set('alertsSummary', {
+        CRITICAL: 1,
+        WARNING: 2,
+        OK: 0
+      });
+      expect(host1.get('criticalWarningAlertsCount')).to.equal(3);
+    });
+  });
+
   App.TestAliases.testAsComputedGetByKey(host1, 'healthIconClass', 
'healthIconClassMap', 'healthClass', {defaultValue: '', map: {
     'health-status-LIVE': App.healthIconClassGreen,
     'health-status-DEAD-RED': App.healthIconClassRed,

http://git-wip-us.apache.org/repos/asf/ambari/blob/f2643679/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 f1c9d06..0c4cf7b 100644
--- a/ambari-web/test/views/main/host/summary_test.js
+++ b/ambari-web/test/views/main/host/summary_test.js
@@ -705,17 +705,26 @@ describe('App.MainHostSummaryView', function() {
       $.timeago.restore();
     });
 
-    it("rawLastHeartBeatTime = null", function() {
-      mainHostSummaryView.set('content.rawLastHeartBeatTime', null);
+    it("lastHeartBeatTime = null", function() {
+      mainHostSummaryView.set('content.isNotHeartBeating', true);
+      mainHostSummaryView.set('content.lastHeartBeatTime', null);
       mainHostSummaryView.propertyDidChange('timeSinceHeartBeat');
       expect(mainHostSummaryView.get('timeSinceHeartBeat')).to.be.empty;
     });
 
-    it("rawLastHeartBeatTime = 1", function() {
-      mainHostSummaryView.set('content.rawLastHeartBeatTime', '1');
+    it("lastHeartBeatTime = 1", function() {
+      mainHostSummaryView.set('content.isNotHeartBeating', true);
+      mainHostSummaryView.set('content.lastHeartBeatTime', '1');
       mainHostSummaryView.propertyDidChange('timeSinceHeartBeat');
       expect(mainHostSummaryView.get('timeSinceHeartBeat')).to.be.equal('1');
     });
+
+    it("host has heartbeat", function() {
+      mainHostSummaryView.set('content.isNotHeartBeating', false);
+      mainHostSummaryView.set('content.lastHeartBeatTime', '1');
+      mainHostSummaryView.propertyDidChange('timeSinceHeartBeat');
+      
expect(mainHostSummaryView.get('timeSinceHeartBeat')).to.be.equal(Em.I18n.t('common.minute.ago'));
+    });
   });
 
   describe("#clientsWithCustomCommands", function () {

Reply via email to