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

[34/35] git commit: AMBARI-7034 Update UI unit tests for models. (atkach)

AMBARI-7034 Update UI unit tests for models. (atkach)


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

Branch: refs/heads/branch-alerts-dev
Commit: a82633457b56667238d1824b6d901b1a85b530ca
Parents: 1f48b24
Author: atkach <at...@hortonworks.com>
Authored: Wed Aug 27 15:01:58 2014 +0300
Committer: atkach <at...@hortonworks.com>
Committed: Wed Aug 27 15:01:58 2014 +0300

----------------------------------------------------------------------
 ambari-web/app/assets/test/tests.js             |   2 +
 ambari-web/app/models/host_component.js         |  28 +-
 ambari-web/app/models/stack_service.js          |   3 +-
 ambari-web/test/models/host_component_test.js   | 212 ++++++++++-
 ambari-web/test/models/host_test.js             | 357 ++++++++++++++++++-
 ambari-web/test/models/service_test.js          |  59 +--
 ambari-web/test/models/stack_service_test.js    | 343 ++++++++++++++++++
 .../common/configs/config_history_flow_test.js  |  22 +-
 8 files changed, 969 insertions(+), 57 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/a8263345/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 985da16..8634d34 100644
--- a/ambari-web/app/assets/test/tests.js
+++ b/ambari-web/app/assets/test/tests.js
@@ -193,6 +193,8 @@ var files = ['test/init_model_test',
   'test/models/run_test',
   'test/models/service_config_test',
   'test/models/stack_service_component_test',
+  'test/models/service_test',
+  'test/models/stack_service_test',
   'test/models/user_test'
 ];
 App.initialize();

http://git-wip-us.apache.org/repos/asf/ambari/blob/a8263345/ambari-web/app/models/host_component.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/host_component.js b/ambari-web/app/models/host_component.js
index b437d26..73fc852 100644
--- a/ambari-web/app/models/host_component.js
+++ b/ambari-web/app/models/host_component.js
@@ -32,7 +32,7 @@ App.HostComponent = DS.Model.extend({
    * Determine if component is client
    * @returns {bool}
    */
-  isClient:function () {
+  isClient: function () {
     return App.get('components.clients').contains(this.get('componentName'));
   }.property('componentName'),
   /**
@@ -40,7 +40,7 @@ App.HostComponent = DS.Model.extend({
    * Based on <code>workStatus</code>
    * @returns {bool}
    */
-  isRunning: function(){
+  isRunning: function () {
     return (this.get('workStatus') == 'STARTED' || this.get('workStatus') == 'STARTING');
   }.property('workStatus'),
 
@@ -64,17 +64,17 @@ App.HostComponent = DS.Model.extend({
    * Determine if component is slave
    * @returns {bool}
    */
-  isSlave: function(){
+  isSlave: function () {
     return App.get('components.slaves').contains(this.get('componentName'));
   }.property('componentName'),
   /**
    * Only certain components can be deleted.
-   * They include some from master components, 
-   * some from slave components, and rest from 
+   * They include some from master components,
+   * some from slave components, and rest from
    * client components.
    * @returns {bool}
    */
-  isDeletable: function() {
+  isDeletable: function () {
     return App.get('components.deletable').contains(this.get('componentName'));
   }.property('componentName'),
   /**
@@ -98,19 +98,19 @@ App.HostComponent = DS.Model.extend({
    * User friendly host component status
    * @returns {String}
    */
-  isActive: function() {
+  isActive: function () {
     return (this.get('passiveState') == 'OFF');
   }.property('passiveState'),
 
-  passiveTooltip: function() {
+  passiveTooltip: function () {
     if (!this.get('isActive')) {
       return Em.I18n.t('hosts.component.passive.mode');
     }
   }.property('isActive'),
 
-  statusClass: function() {
+  statusClass: function () {
     return this.get('isActive') ? this.get('workStatus') : 'icon-medkit';
-  }.property('workStatus','isActive'),
+  }.property('workStatus', 'isActive'),
 
   statusIconClass: function () {
     switch (this.get('statusClass')) {
@@ -133,7 +133,7 @@ App.HostComponent = DS.Model.extend({
 
   componentTextStatus: function () {
     return App.HostComponentStatus.getTextStatus(this.get("workStatus"));
-  }.property('workStatus','isDecommissioning')
+  }.property('workStatus', 'isDecommissioning')
 });
 
 App.HostComponent.FIXTURES = [];
@@ -155,8 +155,8 @@ App.HostComponentStatus = {
    * @param {String} value
    * @returns {String}
    */
-  getKeyName:function(value){
-    switch(value){
+  getKeyName: function (value) {
+    switch (value) {
       case this.started:
         return 'started';
       case this.starting:
@@ -213,7 +213,7 @@ App.HostComponentStatus = {
    * Get list of possible <code>App.HostComponent</code> statuses
    * @returns {String[]}
    */
-  getStatusesList: function() {
+  getStatusesList: function () {
     var ret = [];
     for (var st in this) {
       if (this.hasOwnProperty(st) && Em.typeOf(this[st]) == 'string') {

http://git-wip-us.apache.org/repos/asf/ambari/blob/a8263345/ambari-web/app/models/stack_service.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/stack_service.js b/ambari-web/app/models/stack_service.js
index 2baf65a..7c69804 100644
--- a/ambari-web/app/models/stack_service.js
+++ b/ambari-web/app/models/stack_service.js
@@ -113,7 +113,7 @@ App.StackService = DS.Model.extend({
       serviceDependencyMap = App.StackService.dependency['HDP-1'];
     }
     for (key in serviceDependencyMap) {
-      if (serviceDependencyMap[key].contains(serviceName)) serviceDependencies.pushObject(key);
+      if (serviceDependencyMap[key].contains(serviceName)) serviceDependencies.push(key);
     }
     return  serviceDependencies;
   }.property('serviceName'),
@@ -178,7 +178,6 @@ App.StackService = DS.Model.extend({
    */
   configCategories: function () {
     var configCategories = [];
-    var serviceName = this.get('serviceName');
     var configTypes = this.get('configTypes');
     var serviceComponents = this.get('serviceComponents');
     if (configTypes && Object.keys(configTypes).length) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/a8263345/ambari-web/test/models/host_component_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/models/host_component_test.js b/ambari-web/test/models/host_component_test.js
index f9f14a0..8e7cedf 100644
--- a/ambari-web/test/models/host_component_test.js
+++ b/ambari-web/test/models/host_component_test.js
@@ -19,10 +19,24 @@
 var App = require('app');
 require('models/host_component');
 
-describe('App.HostComponentStatus', function() {
+describe('App.HostComponent', function() {
+
+  App.store.load(App.HostComponent, {
+    id: 'COMP_host',
+    component_name: 'COMP1'
+  });
+  var hc = App.HostComponent.find('COMP_host');
+
 
   describe('#getStatusesList', function() {
+    it('allowed statuses', function() {
+      var statuses = ["STARTED","STARTING","INSTALLED","STOPPING","INSTALL_FAILED","INSTALLING","UPGRADE_FAILED","UNKNOWN","DISABLED","INIT"];
+      expect(App.HostComponentStatus.getStatusesList()).to.include.members(statuses);
+      expect(statuses).to.include.members(App.HostComponentStatus.getStatusesList());
+    });
+  });
 
+  describe('#getStatusesList', function() {
     it('allowed statuses', function() {
       var statuses = ["STARTED","STARTING","INSTALLED","STOPPING","INSTALL_FAILED","INSTALLING","UPGRADE_FAILED","UNKNOWN","DISABLED","INIT"];
       expect(App.HostComponentStatus.getStatusesList()).to.include.members(statuses);
@@ -30,4 +44,200 @@ describe('App.HostComponentStatus', function() {
     });
   });
 
+  describe('#isClient', function() {
+    it('', function() {
+      sinon.stub(App.get('components.clients'), 'contains', Em.K);
+      hc.propertyDidChange('isClient');
+      hc.get('isClient');
+      expect(App.get('components.clients').contains.calledWith('COMP1')).to.be.true;
+      App.get('components.clients').contains.restore();
+    });
+  });
+
+  describe('#displayName', function() {
+    it('', function() {
+      sinon.stub(App.format, 'role', Em.K);
+      hc.propertyDidChange('displayName');
+      hc.get('displayName');
+      expect(App.format.role.calledWith('COMP1')).to.be.true;
+      App.format.role.restore();
+    });
+  });
+
+  describe('#isMaster', function() {
+    it('', function() {
+      sinon.stub(App.get('components.masters'), 'contains', Em.K);
+      hc.propertyDidChange('isMaster');
+      hc.get('isMaster');
+      expect(App.get('components.masters').contains.calledWith('COMP1')).to.be.true;
+      App.get('components.masters').contains.restore();
+    });
+  });
+
+  describe('#isSlave', function() {
+    it('', function() {
+      sinon.stub(App.get('components.slaves'), 'contains', Em.K);
+      hc.propertyDidChange('isSlave');
+      hc.get('isSlave');
+      expect(App.get('components.slaves').contains.calledWith('COMP1')).to.be.true;
+      App.get('components.slaves').contains.restore();
+    });
+  });
+
+  describe('#isDeletable', function() {
+    it('', function() {
+      sinon.stub(App.get('components.deletable'), 'contains', Em.K);
+      hc.propertyDidChange('isDeletable');
+      hc.get('isDeletable');
+      expect(App.get('components.deletable').contains.calledWith('COMP1')).to.be.true;
+      App.get('components.deletable').contains.restore();
+    });
+  });
+
+  describe('#isRunning', function() {
+    var testCases = [
+      {
+        workStatus: 'INSTALLED',
+        result: false
+      },
+      {
+        workStatus: 'STARTING',
+        result: true
+      },
+      {
+        workStatus: 'STARTED',
+        result: true
+      }
+    ];
+    testCases.forEach(function(test){
+      it('workStatus - ' + test.workStatus, function() {
+        hc.set('workStatus', test.workStatus);
+        hc.propertyDidChange('isRunning');
+        expect(hc.get('isRunning')).to.equal(test.result);
+      });
+    });
+  });
+
+  describe('#isDecommissioning', function() {
+    var mock = [];
+    beforeEach(function () {
+      sinon.stub(App.HDFSService, 'find', function () {
+        return mock;
+      })
+    });
+    afterEach(function () {
+      App.HDFSService.find.restore();
+    });
+    it('component name is not DATANODE', function() {
+      hc.propertyDidChange('isDecommissioning');
+      expect(hc.get('isDecommissioning')).to.be.false;
+    });
+    it('component name is DATANODE but no HDFS service', function() {
+      hc.set('componentName', 'DATANODE');
+      hc.propertyDidChange('isDecommissioning');
+      expect(hc.get('isDecommissioning')).to.be.false;
+    });
+    it('HDFS has no decommission DataNodes', function() {
+      hc.set('componentName', 'DATANODE');
+      mock.push(Em.Object.create({
+        decommissionDataNodes: []
+      }));
+      hc.propertyDidChange('isDecommissioning');
+      expect(hc.get('isDecommissioning')).to.be.false;
+    });
+    it('HDFS has decommission DataNodes', function() {
+      hc.set('componentName', 'DATANODE');
+      hc.set('hostName', 'host1');
+      mock.clear();
+      mock.push(Em.Object.create({
+        decommissionDataNodes: [{hostName: 'host1'}]
+      }));
+      hc.propertyDidChange('isDecommissioning');
+      expect(hc.get('isDecommissioning')).to.be.true;
+    });
+  });
+
+  describe('#isActive', function() {
+    it('passiveState is ON', function() {
+      hc.set('passiveState', "ON");
+      hc.propertyDidChange('isActive');
+      expect(hc.get('isActive')).to.be.false;
+    });
+    it('passiveState is OFF', function() {
+      hc.set('passiveState', "OFF");
+      hc.propertyDidChange('isActive');
+      expect(hc.get('isActive')).to.be.true;
+    });
+  });
+
+  describe('#statusClass', function() {
+    it('isActive is false', function() {
+      hc.reopen({
+        isActive: false
+      });
+      hc.propertyDidChange('statusClass');
+      expect(hc.get('statusClass')).to.equal('icon-medkit');
+    });
+    it('isActive is true', function() {
+      var status = 'INSTALLED';
+      hc.set('isActive', true);
+      hc.set('workStatus', status);
+      hc.propertyDidChange('statusClass');
+      expect(hc.get('statusClass')).to.equal(status);
+    });
+  });
+
+  describe('#statusIconClass', function () {
+    var testCases = [
+      {
+        statusClass: 'STARTED',
+        result: 'icon-ok-sign'
+      },
+      {
+        statusClass: 'STARTING',
+        result: 'icon-ok-sign'
+      },
+      {
+        statusClass: 'INSTALLED',
+        result: 'icon-warning-sign'
+      },
+      {
+        statusClass: 'STOPPING',
+        result: 'icon-warning-sign'
+      },
+      {
+        statusClass: 'UNKNOWN',
+        result: 'icon-question-sign'
+      },
+      {
+        statusClass: '',
+        result: ''
+      }
+    ];
+
+    it('reset statusClass to plain property', function () {
+      hc.reopen({
+        statusClass: ''
+      })
+    });
+    testCases.forEach(function (test) {
+      it('statusClass - ' + test.statusClass, function () {
+        hc.set('statusClass', test.statusClass);
+        hc.propertyDidChange('statusIconClass');
+        expect(hc.get('statusIconClass')).to.equal(test.result);
+      });
+    });
+  });
+
+  describe('#componentTextStatus', function() {
+    it('', function() {
+      var status = 'INSTALLED';
+      sinon.stub(App.HostComponentStatus, 'getTextStatus', Em.K);
+      hc.set('workStatus', status);
+      hc.propertyDidChange('componentTextStatus');
+      hc.get('componentTextStatus');
+      expect(App.HostComponentStatus.getTextStatus.calledWith(status)).to.be.true;
+      App.HostComponentStatus.getTextStatus.restore();
+    });
+  });
 });
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/a8263345/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 26144d7..674496d 100644
--- a/ambari-web/test/models/host_test.js
+++ b/ambari-web/test/models/host_test.js
@@ -17,6 +17,7 @@
  */
 
 var App = require('app');
+var misc = require('utils/misc');
 
 require('models/host');
 
@@ -54,13 +55,17 @@ describe('App.Host', function () {
   before(function() {
     App.set('testMode', false);
   });
+  App.Host.reopen({
+    hostComponents: []
+  });
   App.store.loadMany(App.Host, data);
 
+  var host1 = App.Host.find('host1');
+
   describe('#diskUsedFormatted', function () {
 
     it('host1 - 10GB ', function () {
-      var host = App.Host.find().findProperty('hostName', 'host1');
-      expect(host.get('diskUsedFormatted')).to.equal('10GB');
+      expect(host1.get('diskUsedFormatted')).to.equal('10GB');
     });
     it('host2 - 0GB', function () {
       var host = App.Host.find().findProperty('hostName', 'host2');
@@ -75,8 +80,7 @@ describe('App.Host', function () {
   describe('#diskTotalFormatted', function () {
 
     it('host1 - 100.56GB ', function () {
-      var host = App.Host.find().findProperty('hostName', 'host1');
-      expect(host.get('diskTotalFormatted')).to.equal('100.56GB');
+      expect(host1.get('diskTotalFormatted')).to.equal('100.56GB');
     });
     it('host2 - 90GB', function () {
       var host = App.Host.find().findProperty('hostName', 'host2');
@@ -91,8 +95,7 @@ describe('App.Host', function () {
   describe('#diskUsageFormatted', function () {
 
     it('host1 - 9.94% ', function () {
-      var host = App.Host.find().findProperty('hostName', 'host1');
-      expect(host.get('diskUsageFormatted')).to.equal('9.94%');
+      expect(host1.get('diskUsageFormatted')).to.equal('9.94%');
     });
     it('host2 - 0%', function () {
       var host = App.Host.find().findProperty('hostName', 'host2');
@@ -115,4 +118,346 @@ describe('App.Host', function () {
     });
   });
 
+  describe('#cpuUsage', function () {
+    var testCases = [
+      {
+        params: {
+          cpuSystem: undefined,
+          cpuUser: undefined
+        },
+        result: 0
+      },
+      {
+        params: {
+          cpuSystem: 0,
+          cpuUser: 0
+        },
+        result: 0
+      },
+      {
+        params: {
+          cpuSystem: 1,
+          cpuUser: 0
+        },
+        result: 0
+      },
+      {
+        params: {
+          cpuSystem: 0,
+          cpuUser: 1
+        },
+        result: 0
+      },
+      {
+        params: {
+          cpuSystem: 1,
+          cpuUser: 1
+        },
+        result: 2
+      }
+    ];
+    testCases.forEach(function (test) {
+      it('cpuSystem - ' + test.params.cpuSystem + ', cpuUser - ' + test.params.cpuUser, function () {
+        host1.set('cpuSystem', test.params.cpuSystem);
+        host1.set('cpuUser', test.params.cpuUser);
+        host1.propertyDidChange('cpuUsage');
+
+        expect(host1.get('cpuUsage')).to.equal(test.result);
+      });
+    });
+  });
+
+  describe('#memoryUsage', function () {
+    var testCases = [
+      {
+        params: {
+          memFree: undefined,
+          memTotal: undefined
+        },
+        result: 0
+      },
+      {
+        params: {
+          memFree: 0,
+          memTotal: 0
+        },
+        result: 0
+      },
+      {
+        params: {
+          memFree: 1,
+          memTotal: 0
+        },
+        result: 0
+      },
+      {
+        params: {
+          memFree: 0,
+          memTotal: 1
+        },
+        result: 0
+      },
+      {
+        params: {
+          memFree: 1,
+          memTotal: 2
+        },
+        result: 50
+      }
+    ];
+    testCases.forEach(function (test) {
+      it('memFree - ' + test.params.memFree + ', memTotal - ' + test.params.memTotal, function () {
+        host1.set('memFree', test.params.memFree);
+        host1.set('memTotal', test.params.memTotal);
+        host1.propertyDidChange('memoryUsage');
+
+        expect(host1.get('memoryUsage')).to.equal(test.result);
+      });
+    });
+  });
+
+  describe('#componentsWithStaleConfigs', function () {
+    it('One component with stale configs', function () {
+      host1.set('hostComponents', [Em.Object.create({
+        staleConfigs: true
+      })]);
+      host1.propertyDidChange('componentsWithStaleConfigs');
+      expect(host1.get('componentsWithStaleConfigs')).to.eql([Em.Object.create({
+        staleConfigs: true
+      })]);
+    });
+    it('No components with stale configs', function () {
+      host1.set('hostComponents', [Em.Object.create({
+        staleConfigs: false
+      })]);
+      host1.propertyDidChange('componentsWithStaleConfigs');
+      expect(host1.get('componentsWithStaleConfigs')).to.be.empty;
+    });
+  });
+
+  describe('#componentsInPassiveStateCount', function () {
+    it('No component in passive state', function () {
+      host1.set('hostComponents', [Em.Object.create({
+        passiveState: 'OFF'
+      })]);
+      host1.propertyDidChange('componentsInPassiveStateCount');
+
+      expect(host1.get('componentsInPassiveStateCount')).to.equal(0);
+    });
+    it('One component in passive state', function () {
+      host1.set('hostComponents', [Em.Object.create({
+        passiveState: 'ON'
+      })]);
+      host1.propertyDidChange('componentsInPassiveStateCount');
+
+      expect(host1.get('componentsInPassiveStateCount')).to.equal(1);
+    });
+  });
+
+  describe('#disksMounted', function () {
+    it('', function () {
+      host1.set('diskInfo', [
+        {}
+      ]);
+      host1.propertyDidChange('disksMounted');
+      expect(host1.get('disksMounted')).to.equal(1);
+    });
+  });
+
+  describe('#coresFormatted', function () {
+    it('', function () {
+      host1.set('cpu', 1);
+      host1.set('cpuPhysical', 2);
+      host1.propertyDidChange('coresFormatted');
+      expect(host1.get('coresFormatted')).to.equal('1 (2)');
+    });
+  });
+
+  describe('#diskUsed', function () {
+    it('diskFree and diskTotal are 0', function () {
+      host1.set('diskFree', 0);
+      host1.set('diskTotal', 0);
+      host1.propertyDidChange('diskUsed');
+      expect(host1.get('diskUsed')).to.equal(0);
+    });
+    it('diskFree is 0 and diskTotal is 10', function () {
+      host1.set('diskFree', 0);
+      host1.set('diskTotal', 10);
+      host1.propertyDidChange('diskUsed');
+      expect(host1.get('diskUsed')).to.equal(10);
+    });
+  });
+
+  describe('#diskUsage', function () {
+    it('', function () {
+      host1.reopen({
+        diskUsed: 10
+      });
+      host1.set('diskTotal', 100);
+      host1.propertyDidChange('diskUsage');
+      expect(host1.get('diskUsage')).to.equal(10);
+    });
+  });
+
+  describe('#memoryFormatted', function () {
+    it('', function () {
+      host1.set('memory', 1024);
+      sinon.stub(misc, 'formatBandwidth', Em.K);
+      host1.propertyDidChange('memoryFormatted');
+      host1.get('memoryFormatted');
+      expect(misc.formatBandwidth.calledWith(1048576)).to.be.true;
+      misc.formatBandwidth.restore()
+    });
+  });
+
+  describe('#loadAvg', function () {
+    var testCases = [
+      {
+        params: {
+          loadOne: null,
+          loadFive: null,
+          loadFifteen: null
+        },
+        result: null
+      },
+      {
+        params: {
+          loadOne: 1.111,
+          loadFive: 5.555,
+          loadFifteen: 15.555
+        },
+        result: '1.11'
+      },
+      {
+        params: {
+          loadOne: null,
+          loadFive: 5.555,
+          loadFifteen: 15.555
+        },
+        result: '5.55'
+      },
+      {
+        params: {
+          loadOne: null,
+          loadFive: null,
+          loadFifteen: 15.555
+        },
+        result: '15.55'
+      }
+    ];
+
+    testCases.forEach(function (test) {
+      it('loadOne - ' + test.params.loadOne + ', loadFive - ' + test.params.loadFive + ', loadFifteen - ' + test.params.loadFifteen, function () {
+        host1.set('loadOne', test.params.loadOne);
+        host1.set('loadFive', test.params.loadFive);
+        host1.set('loadFifteen', test.params.loadFifteen);
+        host1.propertyDidChange('loadAvg');
+        expect(host1.get('loadAvg')).to.equal(test.result);
+      });
+    });
+  });
+
+  describe('#healthClass', function () {
+    var testCases = [
+      {
+        params: {
+          passiveState: 'ON',
+          healthStatus: null
+        },
+        result: 'icon-medkit'
+      },
+      {
+        params: {
+          passiveState: 'OFF',
+          healthStatus: 'UNKNOWN'
+        },
+        result: 'health-status-DEAD-YELLOW'
+      },
+      {
+        params: {
+          passiveState: 'OFF',
+          healthStatus: 'HEALTHY'
+        },
+        result: 'health-status-LIVE'
+      },
+      {
+        params: {
+          passiveState: 'OFF',
+          healthStatus: 'UNHEALTHY'
+        },
+        result: 'health-status-DEAD-RED'
+      },
+      {
+        params: {
+          passiveState: 'OFF',
+          healthStatus: 'ALERT'
+        },
+        result: 'health-status-DEAD-ORANGE'
+      },
+      {
+        params: {
+          passiveState: 'OFF',
+          healthStatus: null
+        },
+        result: 'health-status-DEAD-YELLOW'
+      }
+    ];
+
+    testCases.forEach(function (test) {
+      it('passiveState - ' + test.params.passiveState + ', healthStatus - ' + test.params.healthStatus, function () {
+        host1.set('passiveState', test.params.passiveState);
+        host1.set('healthStatus', test.params.healthStatus);
+        host1.propertyDidChange('healthClass');
+        expect(host1.get('healthClass')).to.equal(test.result);
+      });
+    });
+  });
+
+  describe('#healthIconClass', function () {
+    var testCases = [
+      {
+        params: {
+          healthClass: 'health-status-LIVE'
+        },
+        result: 'icon-ok-sign'
+      },
+      {
+        params: {
+          healthClass: 'health-status-DEAD-RED'
+        },
+        result: 'icon-warning-sign'
+      },
+      {
+        params: {
+          healthClass: 'health-status-DEAD-YELLOW'
+        },
+        result: 'icon-question-sign'
+      },
+      {
+        params: {
+          healthClass: 'health-status-DEAD-ORANGE'
+        },
+        result: 'icon-minus-sign'
+      },
+      {
+        params: {
+          healthClass: ''
+        },
+        result: ''
+      }
+    ];
+
+    it('reset healthClass to plain property', function(){
+      host1.reopen({
+        healthClass: ''
+      });
+    });
+    testCases.forEach(function (test) {
+      it('healthClass - ' + test.params.healthClass, function () {
+        host1.set('healthClass', test.params.healthClass);
+        host1.propertyDidChange('healthIconClass');
+        expect(host1.get('healthIconClass')).to.equal(test.result);
+      });
+    });
+  });
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/a8263345/ambari-web/test/models/service_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/models/service_test.js b/ambari-web/test/models/service_test.js
index 204badc..2467932 100644
--- a/ambari-web/test/models/service_test.js
+++ b/ambari-web/test/models/service_test.js
@@ -225,32 +225,6 @@ describe('App.Service', function () {
     });
   });
 
-  describe('#isClientsOnly', function () {
-    clientsOnly.forEach(function (item) {
-      it('should be true', function () {
-        service.set('serviceName', item);
-        expect(service.get('isClientsOnly')).to.be.true;
-      });
-    });
-    it('should be false', function () {
-      service.set('serviceName', 'HDFS');
-      expect(service.get('isClientsOnly')).to.be.false;
-    });
-  });
-
-  describe('#isConfigurable', function () {
-    configurable.forEach(function (item) {
-      it('should be true', function () {
-        service.set('serviceName', item);
-        expect(service.get('isConfigurable')).to.be.true;
-      });
-    });
-    it('should be false', function () {
-      service.set('serviceName', 'SQOOP');
-      expect(service.get('isConfigurable')).to.be.false;
-    });
-  });
-
   describe('#isRestartRequired', function () {
     hostComponentsDataFalse.forEach(function (item) {
       it('should be false', function () {
@@ -279,4 +253,37 @@ describe('App.Service', function () {
     });
   });
 
+  describe('#serviceTypes', function () {
+    var testCases = [
+      {
+        serviceName: 'PIG',
+        result: []
+      },
+      {
+        serviceName: 'GANGLIA',
+        result: ['MONITORING']
+      },
+      {
+        serviceName: 'NAGIOS',
+        result: ['MONITORING']
+      },
+      {
+        serviceName: 'HDFS',
+        result: ['HA_MODE']
+      },
+      {
+        serviceName: 'YARN',
+        result: ['HA_MODE']
+      }
+    ];
+    testCases.forEach(function (test) {
+      it('service name - ' + test.serviceName, function () {
+        service.set('serviceName', test.serviceName);
+        service.propertyDidChange('serviceTypes');
+        expect(service.get('serviceTypes')).to.eql(test.result);
+      });
+    });
+  });
+
+
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/a8263345/ambari-web/test/models/stack_service_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/models/stack_service_test.js b/ambari-web/test/models/stack_service_test.js
new file mode 100644
index 0000000..07b4d66
--- /dev/null
+++ b/ambari-web/test/models/stack_service_test.js
@@ -0,0 +1,343 @@
+/**
+ * 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('models/stack_service');
+
+describe('App.StackService', function () {
+
+  App.store.load(App.StackService, {
+    id: 'S1'
+  });
+
+  var ss = App.StackService.find('S1');
+  ss.reopen({
+    serviceComponents: []
+  });
+
+  describe('#isDFS', function () {
+    it('service name is "SERVICE"', function () {
+      ss.set('serviceName', 'SERVICE');
+      ss.propertyDidChange('isDFS');
+      expect(ss.get('isDFS')).to.be.false;
+    });
+    it('service name is "HDFS"', function () {
+      ss.set('serviceName', 'HDFS');
+      ss.propertyDidChange('isDFS');
+      expect(ss.get('isDFS')).to.be.true;
+    });
+    it('service name is "GLUSTERFS"', function () {
+      ss.set('serviceName', 'GLUSTERFS');
+      ss.propertyDidChange('isDFS');
+      expect(ss.get('isDFS')).to.be.true;
+    });
+  });
+
+  describe('#isPrimaryDFS', function () {
+    it('service name is "SERVICE"', function () {
+      ss.set('serviceName', 'SERVICE');
+      ss.propertyDidChange('isPrimaryDFS');
+      expect(ss.get('isPrimaryDFS')).to.be.false;
+    });
+    it('service name is "HDFS"', function () {
+      ss.set('serviceName', 'HDFS');
+      ss.propertyDidChange('isPrimaryDFS');
+      expect(ss.get('isPrimaryDFS')).to.be.true;
+    });
+  });
+
+  describe('#configTypesRendered', function () {
+    ss.set('configTypes', {
+      'core-site': {},
+      'hdfs-site': {}
+    });
+    it('service name is "SERVICE"', function () {
+      ss.set('serviceName', 'SERVICE');
+      ss.propertyDidChange('configTypesRendered');
+      expect(ss.get('configTypesRendered')).to.eql({'hdfs-site': {}});
+    });
+    it('service name is "GLUSTERFS"', function () {
+      ss.set('serviceName', 'GLUSTERFS');
+      ss.propertyDidChange('configTypesRendered');
+      expect(ss.get('configTypesRendered')).to.eql({'core-site': {}, 'hdfs-site': {}});
+    });
+    it('service name is "HDFS"', function () {
+      ss.set('serviceName', 'HDFS');
+      ss.propertyDidChange('configTypesRendered');
+      expect(ss.get('configTypesRendered')).to.eql({'core-site': {}, 'hdfs-site': {}});
+    });
+  });
+
+  describe('#displayNameOnSelectServicePage', function () {
+    it('No coSelectedServices', function () {
+      ss.set('serviceName', 'HDFS');
+      ss.set('displayName', 'HDFS');
+      ss.propertyDidChange('displayNameOnSelectServicePage');
+      expect(ss.get('displayNameOnSelectServicePage')).to.equal('HDFS');
+    });
+    it('Present coSelectedServices', function () {
+      ss.set('serviceName', 'YARN');
+      ss.set('displayName', 'YARN');
+      ss.propertyDidChange('displayNameOnSelectServicePage');
+      expect(ss.get('displayNameOnSelectServicePage')).to.equal('YARN + MapReduce2');
+    });
+  });
+
+  describe('#isHiddenOnSelectServicePage', function () {
+    var testCases = [
+      {
+        serviceName: 'HDFS',
+        result: false
+      },
+      {
+        serviceName: 'MAPREDUCE2',
+        result: true
+      },
+      {
+        serviceName: 'HCATALOG',
+        result: true
+      },
+      {
+        serviceName: 'WEBHCAT',
+        result: true
+      }
+    ];
+
+    testCases.forEach(function (test) {
+      it('service name - ' + test.serviceName, function () {
+        ss.set('serviceName', test.serviceName);
+        ss.propertyDidChange('isHiddenOnSelectServicePage');
+        expect(ss.get('isHiddenOnSelectServicePage')).to.equal(test.result);
+      });
+    });
+  });
+
+  describe('#dependentServices', function () {
+    var mock = {
+      isHadoop2Stack: false
+    };
+    beforeEach(function () {
+      sinon.stub(App, 'get', function () {
+        return mock.isHadoop2Stack;
+      })
+    });
+    afterEach(function () {
+      App.get.restore();
+    });
+    it('isHadoop2Stack is false', function () {
+      ss.set('serviceName', 'HDFS');
+      ss.propertyDidChange('dependentServices');
+      expect(ss.get('dependentServices')).to.eql(['MAPREDUCE', 'HBASE', 'SQOOP']);
+    });
+    it('isHadoop2Stack is true', function () {
+      mock.isHadoop2Stack = true;
+      ss.set('serviceName', 'HDFS');
+      ss.propertyDidChange('dependentServices');
+      expect(ss.get('dependentServices')).to.eql(['YARN', 'HBASE', 'FLUME', 'SQOOP']);
+    });
+  });
+
+  describe('#serviceDependency', function () {
+    var mock = {
+      isHadoop2Stack: false
+    };
+    beforeEach(function () {
+      sinon.stub(App, 'get', function () {
+        return mock.isHadoop2Stack;
+      })
+    });
+    afterEach(function () {
+      App.get.restore();
+    });
+    it('isHadoop2Stack is false', function () {
+      ss.set('serviceName', 'HDFS');
+      ss.propertyDidChange('serviceDependency');
+      expect(ss.get('serviceDependency')).to.eql([]);
+    });
+    it('isHadoop2Stack is true', function () {
+      mock.isHadoop2Stack = true;
+      ss.set('serviceName', 'HDFS');
+      ss.propertyDidChange('serviceDependency');
+      expect(ss.get('serviceDependency')).to.eql(["ZOOKEEPER"]);
+    });
+  });
+
+  describe('#isMonitoringService', function () {
+    var testCases = [
+      {
+        serviceName: 'HDFS',
+        result: false
+      },
+      {
+        serviceName: 'NAGIOS',
+        result: true
+      },
+      {
+        serviceName: 'GANGLIA',
+        result: true
+      }
+    ];
+
+    testCases.forEach(function (test) {
+      it('service name - ' + test.serviceName, function () {
+        ss.set('serviceName', test.serviceName);
+        ss.propertyDidChange('isMonitoringService');
+        expect(ss.get('isMonitoringService')).to.equal(test.result);
+      });
+    });
+  });
+
+  describe('#hasClient', function () {
+    it('No client serviceComponents', function () {
+      ss.set('serviceComponents', []);
+      ss.propertyDidChange('hasClient');
+      expect(ss.get('hasClient')).to.be.false;
+    });
+    it('Has client serviceComponents', function () {
+      ss.set('serviceComponents', [Em.Object.create({isClient: true})]);
+      ss.propertyDidChange('hasClient');
+      expect(ss.get('hasClient')).to.be.true;
+    });
+  });
+
+  describe('#hasMaster', function () {
+    it('No master serviceComponents', function () {
+      ss.set('serviceComponents', []);
+      ss.propertyDidChange('hasMaster');
+      expect(ss.get('hasMaster')).to.be.false;
+    });
+    it('Has master serviceComponents', function () {
+      ss.set('serviceComponents', [Em.Object.create({isMaster: true})]);
+      ss.propertyDidChange('hasMaster');
+      expect(ss.get('hasMaster')).to.be.true;
+    });
+  });
+
+  describe('#hasSlave', function () {
+    it('No slave serviceComponents', function () {
+      ss.set('serviceComponents', []);
+      ss.propertyDidChange('hasSlave');
+      expect(ss.get('hasSlave')).to.be.false;
+    });
+    it('Has slave serviceComponents', function () {
+      ss.set('serviceComponents', [Em.Object.create({isSlave: true})]);
+      ss.propertyDidChange('hasSlave');
+      expect(ss.get('hasSlave')).to.be.true;
+    });
+  });
+
+  describe('#isClientOnlyService', function () {
+    it('Has not only client serviceComponents', function () {
+      ss.set('serviceComponents', [Em.Object.create({isSlave: true}), Em.Object.create({isClient: true})]);
+      ss.propertyDidChange('isClientOnlyService');
+      expect(ss.get('isClientOnlyService')).to.be.false;
+    });
+    it('Has only client serviceComponents', function () {
+      ss.set('serviceComponents', [Em.Object.create({isClient: true})]);
+      ss.propertyDidChange('isClientOnlyService');
+      expect(ss.get('isClientOnlyService')).to.be.true;
+    });
+  });
+
+  describe('#isNoConfigTypes', function () {
+    it('configTypes is null', function () {
+      ss.set('configTypes', null);
+      ss.propertyDidChange('isNoConfigTypes');
+      expect(ss.get('isNoConfigTypes')).to.be.true;
+    });
+    it('configTypes is empty', function () {
+      ss.set('configTypes', {});
+      ss.propertyDidChange('isNoConfigTypes');
+      expect(ss.get('isNoConfigTypes')).to.be.true;
+    });
+    it('configTypes is correct', function () {
+      ss.set('configTypes', {'key': {}});
+      ss.propertyDidChange('isNoConfigTypes');
+      expect(ss.get('isNoConfigTypes')).to.be.false;
+    });
+  });
+
+  describe('#customReviewHandler', function () {
+    it('service name is HDFS', function () {
+      ss.set('serviceName', 'HDFS');
+      ss.propertyDidChange('customReviewHandler');
+      expect(ss.get('customReviewHandler')).to.be.undefined;
+    });
+    it('service name is HIVE', function () {
+      ss.set('serviceName', 'HIVE');
+      ss.propertyDidChange('customReviewHandler');
+      expect(ss.get('customReviewHandler')).to.eql({
+        "Database": "loadHiveDbValue"
+      });
+    });
+  });
+
+  describe('#defaultsProviders', function () {
+    it('service name is HDFS', function () {
+      ss.set('serviceName', 'HDFS');
+      ss.propertyDidChange('defaultsProviders');
+      expect(ss.get('defaultsProviders')).to.be.undefined;
+    });
+    it('service name is HIVE', function () {
+      ss.set('serviceName', 'HIVE');
+      ss.propertyDidChange('defaultsProviders');
+      expect(ss.get('defaultsProviders')).to.not.be.empty;
+    });
+  });
+
+  describe('#configsValidator', function () {
+    it('service name is HDFS', function () {
+      ss.set('serviceName', 'HDFS');
+      ss.propertyDidChange('configsValidator');
+      expect(ss.get('configsValidator')).to.be.undefined;
+    });
+    it('service name is HIVE', function () {
+      ss.set('serviceName', 'HIVE');
+      ss.propertyDidChange('configsValidator');
+      expect(ss.get('configsValidator')).to.not.be.empty;
+    });
+  });
+
+  describe('#configCategories', function () {
+    it('HDFS service with no serviceComponents', function () {
+      ss.set('serviceComponents', []);
+      ss.set('serviceName', 'HDFS');
+      ss.propertyDidChange('configCategories');
+      expect(ss.get('configCategories').mapProperty('name')).to.eql([
+        "General",
+        "Advanced",
+        "Advanced key",
+        "Custom key"
+      ]);
+    });
+    it('HDFS service with DATANODE serviceComponents', function () {
+      ss.set('serviceComponents', [Em.Object.create({componentName: 'DATANODE'})]);
+      ss.set('serviceName', 'HDFS');
+      ss.propertyDidChange('configCategories');
+      expect(ss.get('configCategories').mapProperty('name')).to.eql([
+        "DATANODE",
+        "General",
+        "Advanced",
+        "Advanced key",
+        "Custom key"]);
+    });
+  });
+
+
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/a8263345/ambari-web/test/views/common/configs/config_history_flow_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/common/configs/config_history_flow_test.js b/ambari-web/test/views/common/configs/config_history_flow_test.js
index 3317550..59d38e2 100644
--- a/ambari-web/test/views/common/configs/config_history_flow_test.js
+++ b/ambari-web/test/views/common/configs/config_history_flow_test.js
@@ -512,7 +512,7 @@ describe('App.ConfigHistoryFlowView', function () {
       sinon.spy(view.get('controller'), 'onConfigGroupChange');
       view.compare({context: Em.Object.create({version: 1})});
 
-      expect(view.get('controller.compareServiceVersion.version')).to.equal(1);
+      expect(view.get('controller.compareServiceVersion')).to.eql(Em.Object.create({version: 1}));
       expect(view.get('controller').onConfigGroupChange.calledOnce).to.be.true;
       view.get('controller').onConfigGroupChange.restore();
     });
@@ -520,13 +520,16 @@ describe('App.ConfigHistoryFlowView', function () {
 
   describe('#revert()', function () {
     beforeEach(function () {
-      sinon.stub(App, 'showConfirmationPopup', function (callback) {
-        callback();
+      sinon.stub(App.ModalPopup, 'show', function (options) {
+        options.onPrimary.call(Em.Object.create({
+          serviceConfigNote: 'note',
+          hide: Em.K
+        }));
       });
       sinon.stub(view, 'sendRevertCall', Em.K);
     });
     afterEach(function () {
-      App.showConfirmationPopup.restore();
+      App.ModalPopup.show.restore();
       view.sendRevertCall.restore();
     });
     it('context passed', function () {
@@ -535,10 +538,11 @@ describe('App.ConfigHistoryFlowView', function () {
         serviceName: 'S1'
       })});
 
-      expect(App.showConfirmationPopup.calledOnce).to.be.true;
+      expect(App.ModalPopup.show.calledOnce).to.be.true;
       expect(view.sendRevertCall.calledWith(Em.Object.create({
         version: 1,
-        serviceName: 'S1'
+        serviceName: 'S1',
+        serviceConfigNote: 'note'
       }))).to.be.true;
     });
     it('context is not passed', function () {
@@ -548,10 +552,12 @@ describe('App.ConfigHistoryFlowView', function () {
       }));
       view.revert({});
 
-      expect(App.showConfirmationPopup.calledOnce).to.be.true;
+      expect(App.ModalPopup.show.calledOnce).to.be.true;
       expect(view.sendRevertCall.calledWith(Em.Object.create({
         version: 1,
-        serviceName: 'S1'
+        serviceName: 'S1',
+        serviceConfigNote: 'note',
+        notes: ''
       }))).to.be.true;
     });
   });