AMBARI-18209. UI: add missing unit tests for models (alexantonenko)

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

Branch: refs/heads/branch-dev-logsearch
Commit: 9ad19662817e2c24a4c3e72bb465b0a35e521bf2
Parents: 2ad7c80
Author: Alex Antonenko <hiv...@gmail.com>
Authored: Fri Aug 19 14:42:46 2016 +0300
Committer: Alex Antonenko <hiv...@gmail.com>
Committed: Fri Aug 19 15:29:17 2016 +0300

----------------------------------------------------------------------
 ambari-web/app/assets/test/tests.js             |   8 +
 ambari-web/app/models/client_component.js       |   8 +-
 ambari-web/app/models/cluster.js                |   2 +-
 ambari-web/app/models/master_component.js       |   2 +-
 ambari-web/app/models/root_service.js           |   2 +-
 ambari-web/app/models/slave_component.js        |   2 +-
 ambari-web/app/models/widget_property.js        |  11 +-
 ambari-web/test/models/client_component_test.js | 115 +++++++
 ambari-web/test/models/cluster_test.js          |  89 ++++++
 ambari-web/test/models/master_component_test.js |  59 ++++
 ambari-web/test/models/root_service_test.js     |  78 +++++
 ambari-web/test/models/slave_component_test.js  |  59 ++++
 ambari-web/test/models/stack_test.js            | 226 +++++++++++++
 ambari-web/test/models/widget_property_test.js  | 320 +++++++++++++++++++
 ambari-web/test/models/widget_test.js           |  70 ++++
 15 files changed, 1036 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/9ad19662/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 364f2ed..7dbac75 100644
--- a/ambari-web/app/assets/test/tests.js
+++ b/ambari-web/app/assets/test/tests.js
@@ -373,17 +373,25 @@ var files = [
   'test/models/alerts/alert_group_test',
   'test/models/alerts/alert_instance_test',
   'test/models/authentication_test',
+  'test/models/client_component_test',
   'test/models/cluster_states_test',
+  'test/models/cluster_test',
   'test/models/form_test',
   'test/models/host_test',
   'test/models/host_component_test',
   'test/models/hosts_test',
+  'test/models/master_component_test',
   'test/models/operating_system_test',
   'test/models/repository_test',
+  'test/models/root_service_test',
   'test/models/stack_service_component_test',
   'test/models/service_test',
+  'test/models/slave_component_test',
+  'test/models/stack_test',
   'test/models/stack_service_test',
   'test/models/user_test',
+  'test/models/widget_test',
+  'test/models/widget_property_test',
   'test/models/host_stack_version_test',
   'test/models/upgrade_entity_test',
   'test/models/finished_upgrade_entity_test',

http://git-wip-us.apache.org/repos/asf/ambari/blob/9ad19662/ambari-web/app/models/client_component.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/client_component.js 
b/ambari-web/app/models/client_component.js
index 19ef7ce..50a3bb6 100644
--- a/ambari-web/app/models/client_component.js
+++ b/ambari-web/app/models/client_component.js
@@ -37,19 +37,19 @@ App.ClientComponent = DS.Model.extend({
    *
    * @type {boolean}
    */
-  allowToDelete: function() {
+  allowToDelete: function () {
     return this.get('totalCount') === (this.get('installedCount') + 
this.get('installFailedCount') + this.get('initCount') + 
this.get('unknownCount'));
   }.property('totalCount', 'installedCount', 'installFailedCount', 
'initCount', 'unknownCount'),
 
-  summaryLabelClassName:function(){
+  summaryLabelClassName: function () {
     return 'label_for_'+this.get('componentName').toLowerCase();
   }.property('componentName'),
 
-  summaryValueClassName:function(){
+  summaryValueClassName: function () {
     return 'value_for_'+this.get('componentName').toLowerCase();
   }.property('componentName'),
 
-  displayNamePluralized: function() {
+  displayNamePluralized: function () {
     return stringUtils.pluralize(this.get('installedCount'), 
this.get('displayName'));
   }.property('installedCount')
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/9ad19662/ambari-web/app/models/cluster.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/cluster.js b/ambari-web/app/models/cluster.js
index a571a28..57f91ee 100644
--- a/ambari-web/app/models/cluster.js
+++ b/ambari-web/app/models/cluster.js
@@ -35,7 +35,7 @@ App.Cluster = DS.Model.extend({
 
   isKerberosEnabled: Em.computed.equal('securityType', 'KERBEROS'),
 
-  isCredentialStorePersistent: function() {
+  isCredentialStorePersistent: function () {
     return 
this.get('credentialStoreProperties')[credentialUtils.STORE_TYPES.PERSISTENT_PATH]
 === "true";
   }.property('credentialStoreProperties')
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/9ad19662/ambari-web/app/models/master_component.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/master_component.js 
b/ambari-web/app/models/master_component.js
index ee44d0d..a4f3717 100644
--- a/ambari-web/app/models/master_component.js
+++ b/ambari-web/app/models/master_component.js
@@ -20,7 +20,7 @@ var App = require('app');
 var stringUtils = require('utils/string_utils');
 
 App.MasterComponent = App.ClientComponent.extend({
-  displayNamePluralized: function() {
+  displayNamePluralized: function () {
     return stringUtils.pluralize(this.get('startedCount'), 
this.get('displayName'));
   }.property('startedCount')
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/9ad19662/ambari-web/app/models/root_service.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/root_service.js 
b/ambari-web/app/models/root_service.js
index ff73675..06ca8d0 100644
--- a/ambari-web/app/models/root_service.js
+++ b/ambari-web/app/models/root_service.js
@@ -31,7 +31,7 @@ App.RootService = DS.Model.extend({
 
 App.RootService.FIXTURES = [];
 
-App.RootServiceComponents =   DS.Model.extend({
+App.RootServiceComponents = DS.Model.extend({
   componentName: DS.attr('string'),
   displayName: Em.computed.formatRole('componentName', false),
   componentVersion: DS.attr('string'),

http://git-wip-us.apache.org/repos/asf/ambari/blob/9ad19662/ambari-web/app/models/slave_component.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/slave_component.js 
b/ambari-web/app/models/slave_component.js
index eb20c75..a108678 100644
--- a/ambari-web/app/models/slave_component.js
+++ b/ambari-web/app/models/slave_component.js
@@ -20,7 +20,7 @@ var App = require('app');
 var stringUtils = require('utils/string_utils');
 
 App.SlaveComponent = App.ClientComponent.extend({
-  displayNamePluralized: function() {
+  displayNamePluralized: function () {
     return stringUtils.pluralize(this.get('startedCount'), 
this.get('displayName'));
   }.property('startedCount')
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/9ad19662/ambari-web/app/models/widget_property.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/widget_property.js 
b/ambari-web/app/models/widget_property.js
index 0b7e414..6b5dc82 100644
--- a/ambari-web/app/models/widget_property.js
+++ b/ambari-web/app/models/widget_property.js
@@ -73,13 +73,10 @@ App.WidgetProperty = Ember.Object.extend({
 
   /**
    * Define whether property is valid
-   * Computed property
-   * Should be defined in child class
+   * Computed property should be defined in child class
    * @type {Boolean}
    */
-  isValid: function () {
-    return true;
-  }.property(),
+  isValid: true,
 
   /**
    * Define whether property is required by user
@@ -96,7 +93,7 @@ App.WidgetPropertyTypes = [
     displayType: 'textField',
     classNames: 'widget-property-unit',
     isValid: function () {
-      return this.get('isRequired') ? this.get('value') : true;
+      return this.get('isRequired') ? Boolean(this.get('value')) : true;
     }.property('value'),
     valueMap: {
      "value": "display_unit"
@@ -214,7 +211,7 @@ App.WidgetPropertyTypes = [
      */
     validate: function (value) {
       value = Number(('' + value).trim());
-      if (!value) {
+      if (!value && !isNaN(value)) {
         return true;
       }
       return validator.isValidFloat(value) && value > this.get('MIN_VALUE') && 
value <= this.get('MAX_VALUE');

http://git-wip-us.apache.org/repos/asf/ambari/blob/9ad19662/ambari-web/test/models/client_component_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/models/client_component_test.js 
b/ambari-web/test/models/client_component_test.js
new file mode 100644
index 0000000..5f92b96
--- /dev/null
+++ b/ambari-web/test/models/client_component_test.js
@@ -0,0 +1,115 @@
+/**
+ * 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/client_component');
+
+describe('App.ClientComponent', function () {
+
+  var clientComponent;
+
+  beforeEach(function () {
+    clientComponent = App.ClientComponent.createRecord();
+  });
+
+  describe('#allowToDelete', function () {
+
+    var cases = [
+      {
+        statesCounts: {
+          installedCount: 1,
+          installFailedCount: 2,
+          initCount: 3,
+          unknownCount: 4,
+          totalCount: 10
+        },
+        allowToDelete: true,
+        title: 'delete allowed'
+      },
+      {
+        statesCounts: {
+          installedCount: 1,
+          installFailedCount: 2,
+          initCount: 3,
+          unknownCount: 4,
+          totalCount: 11
+        },
+        allowToDelete: false,
+        title: 'delete not allowed'
+      }
+    ];
+
+    cases.forEach(function (item) {
+
+      it(item.title, function () {
+        clientComponent.setProperties(item.statesCounts);
+        
expect(clientComponent.get('allowToDelete')).to.equal(item.allowToDelete);
+      });
+
+    });
+
+  });
+
+  describe('#summaryLabelClassName', function () {
+
+    it('should use lower case of component name', function () {
+      clientComponent.set('componentName', 'ZOOKEEPER_CLIENT');
+      
expect(clientComponent.get('summaryLabelClassName')).to.equal('label_for_zookeeper_client');
+    });
+
+  });
+
+  describe('#summaryValueClassName', function () {
+
+    it('should use lower case of component name', function () {
+      clientComponent.set('componentName', 'ZOOKEEPER_CLIENT');
+      
expect(clientComponent.get('summaryValueClassName')).to.equal('value_for_zookeeper_client');
+    });
+
+  });
+
+  describe('#displayNamePluralized', function () {
+
+    var cases = [
+      {
+        installedCount: 1,
+        displayNamePluralized: 'Zookeeper Client',
+        title: 'singular'
+      },
+      {
+        installedCount: 2,
+        displayNamePluralized: 'Zookeeper Clients',
+        title: 'plural'
+      }
+    ];
+
+    cases.forEach(function (item) {
+
+      it(item.title, function () {
+        clientComponent.setProperties({
+          displayName: 'Zookeeper Client',
+          installedCount: item.installedCount
+        });
+        
expect(clientComponent.get('displayNamePluralized')).to.equal(item.displayNamePluralized);
+      });
+
+    });
+
+  });
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9ad19662/ambari-web/test/models/cluster_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/models/cluster_test.js 
b/ambari-web/test/models/cluster_test.js
new file mode 100644
index 0000000..a6bafba
--- /dev/null
+++ b/ambari-web/test/models/cluster_test.js
@@ -0,0 +1,89 @@
+/**
+ * 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/cluster');
+
+describe('App.Cluster', function () {
+
+  var cluster;
+
+  beforeEach(function () {
+    cluster = App.Cluster.createRecord();
+  });
+
+  describe('#isKerberosEnabled', function () {
+
+    var cases = [
+      {
+        securityType: 'KERBEROS',
+        isKerberosEnabled: true,
+        title: 'Kerberos enabled'
+      },
+      {
+        securityType: 'NONE',
+        isKerberosEnabled: false,
+        title: 'Kerberos disabled'
+      }
+    ];
+
+    cases.forEach(function (item) {
+
+      it(item.title, function () {
+        cluster.set('securityType', item.securityType);
+        
expect(cluster.get('isKerberosEnabled')).to.equal(item.isKerberosEnabled);
+      });
+
+    });
+
+    describe('#isCredentialStorePersistent', function () {
+
+      var cases = [
+        {
+          propertyValue: 'false',
+          isCredentialStorePersistent: false,
+          title: 'no persistent credential store'
+        },
+        {
+          propertyValue: true,
+          isCredentialStorePersistent: false,
+          title: 'malformed value'
+        },
+        {
+          propertyValue: 'true',
+          isCredentialStorePersistent: true,
+          title: 'persistent credential store'
+        }
+      ];
+
+      cases.forEach(function (item) {
+
+        it(item.title, function () {
+          cluster.set('credentialStoreProperties', {
+            'storage.persistent': item.propertyValue
+          });
+          
expect(cluster.get('isCredentialStorePersistent')).to.equal(item.isCredentialStorePersistent);
+        });
+
+      });
+
+    });
+
+  });
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9ad19662/ambari-web/test/models/master_component_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/models/master_component_test.js 
b/ambari-web/test/models/master_component_test.js
new file mode 100644
index 0000000..2bd4e09
--- /dev/null
+++ b/ambari-web/test/models/master_component_test.js
@@ -0,0 +1,59 @@
+/**
+ * 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/master_component');
+
+describe('App.MasterComponent', function () {
+
+  var masterComponent;
+
+  beforeEach(function () {
+    masterComponent = App.MasterComponent.createRecord();
+  });
+
+  describe('#displayNamePluralized', function () {
+
+    var cases = [
+      {
+        startedCount: 1,
+        displayNamePluralized: 'Zookeeper Server',
+        title: 'singular'
+      },
+      {
+        startedCount: 2,
+        displayNamePluralized: 'Zookeeper Servers',
+        title: 'plural'
+      }
+    ];
+
+    cases.forEach(function (item) {
+
+      it(item.title, function () {
+        masterComponent.setProperties({
+          displayName: 'Zookeeper Server',
+          startedCount: item.startedCount
+        });
+        
expect(masterComponent.get('displayNamePluralized')).to.equal(item.displayNamePluralized);
+      });
+
+    });
+
+  });
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9ad19662/ambari-web/test/models/root_service_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/models/root_service_test.js 
b/ambari-web/test/models/root_service_test.js
new file mode 100644
index 0000000..fa4a646
--- /dev/null
+++ b/ambari-web/test/models/root_service_test.js
@@ -0,0 +1,78 @@
+/**
+ * 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/root_service');
+
+var roleMock = function (str, flag) {
+  return flag ? str.toLowerCase() : str.toCapital();
+};
+
+describe('App.RootService', function () {
+
+  var rootService;
+
+  beforeEach(function () {
+    rootService = App.RootService.createRecord();
+  });
+
+  describe('#displayName', function () {
+
+    beforeEach(function () {
+      sinon.stub(App.format, 'role', roleMock);
+    });
+
+    afterEach(function () {
+      App.format.role.restore();
+    });
+
+    it('should format service name', function () {
+      rootService.set('serviceName', 'HDFS');
+      expect(rootService.get('displayName')).to.equal('hdfs');
+    });
+
+  });
+
+});
+
+describe('App.RootServiceComponents', function () {
+
+  var rootServiceComponents;
+
+  beforeEach(function () {
+    rootServiceComponents = App.RootServiceComponents.createRecord();
+  });
+
+  describe('#displayName', function () {
+
+    beforeEach(function () {
+      sinon.stub(App.format, 'role', roleMock);
+    });
+
+    afterEach(function () {
+      App.format.role.restore();
+    });
+
+    it('should format component name', function () {
+      rootServiceComponents.set('componentName', 'DATANODE');
+      expect(rootServiceComponents.get('displayName')).to.equal('Datanode');
+    });
+
+  });
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9ad19662/ambari-web/test/models/slave_component_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/models/slave_component_test.js 
b/ambari-web/test/models/slave_component_test.js
new file mode 100644
index 0000000..cf21aef
--- /dev/null
+++ b/ambari-web/test/models/slave_component_test.js
@@ -0,0 +1,59 @@
+/**
+ * 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/slave_component');
+
+describe('App.SlaveComponent', function () {
+
+  var slaveComponent;
+
+  beforeEach(function () {
+    slaveComponent = App.SlaveComponent.createRecord();
+  });
+
+  describe('#displayNamePluralized', function () {
+
+    var cases = [
+      {
+        startedCount: 1,
+        displayNamePluralized: 'DataNode',
+        title: 'singular'
+      },
+      {
+        startedCount: 2,
+        displayNamePluralized: 'DataNodes',
+        title: 'plural'
+      }
+    ];
+
+    cases.forEach(function (item) {
+
+      it(item.title, function () {
+        slaveComponent.setProperties({
+          displayName: 'DataNode',
+          startedCount: item.startedCount
+        });
+        
expect(slaveComponent.get('displayNamePluralized')).to.equal(item.displayNamePluralized);
+      });
+
+    });
+
+  });
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9ad19662/ambari-web/test/models/stack_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/models/stack_test.js 
b/ambari-web/test/models/stack_test.js
new file mode 100644
index 0000000..7f1f467
--- /dev/null
+++ b/ambari-web/test/models/stack_test.js
@@ -0,0 +1,226 @@
+/**
+ * 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');
+
+describe('App.Stack', function () {
+
+  var stack;
+
+  beforeEach(function () {
+    stack = App.Stack.createRecord();
+  });
+
+  describe('#stackNameVersion', function () {
+
+    it('should concat stack name and stack version', function () {
+      stack.setProperties({
+        stackName: 'HDP',
+        stackVersion: '2.5'
+      });
+      expect(stack.get('stackNameVersion')).to.equal('HDP-2.5');
+    });
+
+  });
+
+  describe('#isPatch', function () {
+
+    var cases = [
+      {
+        type: 'PATCH',
+        isPatch: true
+      },
+      {
+        type: 'STANDARD',
+        isPatch: false
+      }
+    ];
+
+    cases.forEach(function (item) {
+
+      it(item.type, function () {
+        stack.set('type', item.type);
+        expect(stack.get('isPatch')).to.equal(item.isPatch);
+      });
+
+    });
+
+  });
+
+  describe('#displayName', function () {
+
+    it('should concat stack name and stack version', function () {
+      stack.setProperties({
+        stackName: 'HDP',
+        repositoryVersion: '2.5.0.0-999'
+      });
+      expect(stack.get('displayName')).to.equal('HDP-2.5.0.0-999');
+    });
+
+  });
+
+  describe('#repositories', function () {
+
+    beforeEach(function () {
+      stack.reopen({
+        operatingSystems: [
+          Em.Object.create({
+            isSelected: false,
+            repositories: [
+              {
+                id: 0
+              },
+              {
+                id: 1
+              }
+            ]
+          }),
+          Em.Object.create({
+            isSelected: false,
+            repositories: [
+              {
+                id: 2
+              },
+              {
+                id: 3
+              }
+            ]
+          }),
+          Em.Object.create({
+            isSelected: false,
+            repositories: [
+              {
+                id: 4
+              },
+              {
+                id: 5
+              }
+            ]
+          })
+        ]
+      });
+    });
+
+    it('no OSes selected', function () {
+      expect(stack.get('repositories')).to.be.empty;
+    });
+
+    it('some OSes selected', function () {
+      stack.get('operatingSystems')[0].isSelected = true;
+      stack.get('operatingSystems')[2].isSelected = true;
+      expect(stack.get('repositories').toArray()).to.eql([
+        {
+          id: 0
+        },
+        {
+          id: 1
+        },
+        {
+          id: 4
+        },
+        {
+          id: 5
+        }
+      ]);
+    });
+
+  });
+
+  describe('#cleanReposBaseUrls', function () {
+
+    beforeEach(function () {
+      stack.reopen({
+        operatingSystems: [
+          Em.Object.create({
+            isSelected: true,
+            repositories: [
+              Em.Object.create({
+                baseUrl: 'http://localhost/repo0'
+              }),
+              Em.Object.create({
+                baseUrl: 'http://localhost/repo1'
+              })
+            ]
+          }),
+          Em.Object.create({
+            isSelected: true,
+            repositories: [
+              Em.Object.create({
+                baseUrl: 'http://localhost/repo2'
+              }),
+              Em.Object.create({
+                baseUrl: 'http://localhost/repo3'
+              })
+            ]
+          })
+        ]
+      });
+      stack.cleanReposBaseUrls();
+    });
+
+    it('should clear repo urls', function () {
+      expect(stack.get('repositories').mapProperty('baseUrl')).to.eql(['', '', 
'', '']);
+    });
+
+  });
+
+  describe('#restoreReposBaseUrls', function () {
+
+    beforeEach(function () {
+      stack.reopen({
+        operatingSystems: [
+          Em.Object.create({
+            isSelected: true,
+            repositories: [
+              Em.Object.create({
+                baseUrlInit: 'http://localhost/repo0'
+              }),
+              Em.Object.create({
+                baseUrlInit: 'http://localhost/repo1'
+              })
+            ]
+          }),
+          Em.Object.create({
+            isSelected: true,
+            repositories: [
+              Em.Object.create({
+                baseUrlInit: 'http://localhost/repo2'
+              }),
+              Em.Object.create({
+                baseUrlInit: 'http://localhost/repo3'
+              })
+            ]
+          })
+        ]
+      });
+      stack.restoreReposBaseUrls();
+    });
+
+    it('should reset repo urls', function () {
+      expect(stack.get('repositories').mapProperty('baseUrl')).to.eql([
+        'http://localhost/repo0',
+        'http://localhost/repo1',
+        'http://localhost/repo2',
+        'http://localhost/repo3'
+      ]);
+    });
+
+  });
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9ad19662/ambari-web/test/models/widget_property_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/models/widget_property_test.js 
b/ambari-web/test/models/widget_property_test.js
new file mode 100644
index 0000000..ee1cdb4
--- /dev/null
+++ b/ambari-web/test/models/widget_property_test.js
@@ -0,0 +1,320 @@
+/**
+ * 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/widget_property');
+
+describe('App.WidgetProperty', function () {
+
+  var widgetProperty,
+    unit = App.WidgetPropertyTypes.findProperty('name', 'display_unit'),
+    threshold = App.WidgetPropertyTypes.findProperty('name', 'threshold'),
+    validate = function (value) {
+      return !isNaN(value);
+    };
+
+  beforeEach(function () {
+    widgetProperty = App.WidgetProperty.create();
+  });
+
+  describe('#viewClass', function () {
+
+    var cases = [
+      {
+        displayType: 'textField',
+        viewClass: App.WidgetPropertyTextFieldView
+      },
+      {
+        displayType: 'threshold',
+        viewClass: App.WidgetPropertyThresholdView
+      },
+      {
+        displayType: 'select',
+        viewClass: App.WidgetPropertySelectView
+      },
+      {
+        displayType: 'none',
+        viewClass: undefined
+      }
+    ];
+
+    cases.forEach(function (item) {
+
+      it(item.displayType, function () {
+        widgetProperty.set('displayType', item.displayType);
+        expect(widgetProperty.get('viewClass')).to.eql(item.viewClass);
+      });
+
+    });
+
+  });
+
+  describe('#isValid', function () {
+
+    describe('display_unit', function () {
+
+      var cases = [
+        {
+          isRequired: true,
+          value: 'MB',
+          isValid: true,
+          title: 'valid value'
+        },
+        {
+          isRequired: true,
+          value: '0',
+          isValid: true,
+          title: 'non-empty value'
+        },
+        {
+          isRequired: true,
+          value: '',
+          isValid: false,
+          title: 'empty value'
+        },
+        {
+          isRequired: false,
+          value: '',
+          isValid: true,
+          title: 'value not required'
+        }
+      ];
+
+      beforeEach(function () {
+        widgetProperty.reopen(unit);
+      });
+
+      cases.forEach(function (item) {
+
+        it(item.title, function () {
+          widgetProperty.setProperties({
+            isRequired: item.isRequired,
+            value: item.value
+          });
+          expect(widgetProperty.get('isValid')).to.equal(item.isValid);
+        });
+
+      });
+
+    });
+
+    describe('threshold', function () {
+
+      var cases = [
+        {
+          isSmallValueValid: true,
+          isBigValueValid: true,
+          isValid: true,
+          title: 'both threshold values are valid'
+        },
+        {
+          isSmallValueValid: false,
+          isBigValueValid: true,
+          isValid: false,
+          title: 'warning threshold value is invalid'
+        },
+        {
+          isSmallValueValid: true,
+          isBigValueValid: false,
+          isValid: false,
+          title: 'error threshold value is invalid'
+        },
+        {
+          isSmallValueValid: false,
+          isBigValueValid: false,
+          isValid: false,
+          title: 'both threshold values are invalid'
+        }
+      ];
+
+      cases.forEach(function (item) {
+
+        it(item.title, function () {
+          widgetProperty.reopen(threshold, {
+            isSmallValueValid: item.isSmallValueValid,
+            isBigValueValid: item.isBigValueValid
+          });
+          expect(widgetProperty.get('isValid')).to.equal(item.isValid);
+        });
+
+      });
+
+    });
+
+  });
+
+  describe('#isSmallValueValid', function () {
+
+    var cases = [
+      {
+        smallValue: '1',
+        isSmallValueValid: true,
+        title: 'valid value'
+      },
+      {
+        smallValue: 'value',
+        isSmallValueValid: false,
+        title: 'invalid value'
+      }
+    ];
+
+    beforeEach(function () {
+      widgetProperty.reopen(threshold);
+      sinon.stub(widgetProperty, 'validate', validate);
+    });
+
+    afterEach(function () {
+      widgetProperty.validate.restore();
+    });
+
+    cases.forEach(function (item) {
+
+      it(item.title, function () {
+        widgetProperty.set('smallValue', item.smallValue);
+        
expect(widgetProperty.get('isSmallValueValid')).to.equal(item.isSmallValueValid);
+      });
+
+    });
+
+  });
+
+  describe('#isBigValueValid', function () {
+
+    var cases = [
+      {
+        bigValue: '1',
+        isBigValueValid: true,
+        title: 'valid value'
+      },
+      {
+        bigValue: 'value',
+        isBigValueValid: false,
+        title: 'invalid value'
+      }
+    ];
+
+    beforeEach(function () {
+      widgetProperty.reopen(threshold);
+      sinon.stub(widgetProperty, 'validate', validate);
+    });
+
+    afterEach(function () {
+      widgetProperty.validate.restore();
+    });
+
+    cases.forEach(function (item) {
+
+      it(item.title, function () {
+        widgetProperty.set('bigValue', item.bigValue);
+        
expect(widgetProperty.get('isBigValueValid')).to.equal(item.isBigValueValid);
+      });
+
+    });
+
+  });
+
+  describe('#validate', function () {
+
+    var cases = [
+      {
+        value: '',
+        validateResult: true,
+        title: 'empty value'
+      },
+      {
+        value: ' \r\n\t ',
+        validateResult: true,
+        title: 'spaces only'
+      },
+      {
+        value: 'v',
+        validateResult: false,
+        title: 'invalid value'
+      },
+      {
+        value: ' v \r\n\t',
+        validateResult: false,
+        title: 'invalid value with spaces'
+      },
+      {
+        value: '-1',
+        validateResult: false,
+        title: 'value below the minimum'
+      },
+      {
+        value: ' -1 \r\n\t',
+        validateResult: false,
+        title: 'value below the minimum with spaces'
+      },
+      {
+        value: '2',
+        validateResult: false,
+        title: 'value above the minimum'
+      },
+      {
+        value: ' 2 \r\n\t',
+        validateResult: false,
+        title: 'value above the minimum with spaces'
+      },
+      {
+        value: '0,5',
+        validateResult: false,
+        title: 'malformed number'
+      },
+      {
+        value: ' 0,5 \r\n\t',
+        validateResult: false,
+        title: 'malformed number with spaces'
+      },
+      {
+        value: '0.5',
+        validateResult: true,
+        title: 'valid value'
+      },
+      {
+        value: ' 0.5 \r\n\t',
+        validateResult: true,
+        title: 'valid value with spaces'
+      },
+      {
+        value: '2E-1',
+        validateResult: true,
+        title: 'exponentially formatted value'
+      },
+      {
+        value: ' 2E-1 \r\n\t',
+        validateResult: true,
+        title: 'exponentially formatted value with spaces'
+      }
+    ];
+
+    beforeEach(function () {
+      widgetProperty.reopen(threshold);
+    });
+
+    cases.forEach(function (item) {
+
+      it(item.title, function () {
+        
expect(widgetProperty.validate(item.value)).to.equal(item.validateResult);
+      });
+
+    });
+
+  });
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9ad19662/ambari-web/test/models/widget_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/models/widget_test.js 
b/ambari-web/test/models/widget_test.js
new file mode 100644
index 0000000..589ecb9
--- /dev/null
+++ b/ambari-web/test/models/widget_test.js
@@ -0,0 +1,70 @@
+/**
+ * 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/widget');
+
+describe('App.Widget', function () {
+
+  var widget;
+
+  beforeEach(function () {
+    widget = App.Widget.createRecord();
+  });
+
+  describe('#viewClass', function () {
+
+    var cases = [
+      {
+        widgetType: 'GRAPH',
+        viewClass: App.GraphWidgetView
+      },
+      {
+        widgetType: 'TEMPLATE',
+        viewClass: App.TemplateWidgetView
+      },
+      {
+        widgetType: 'NUMBER',
+        viewClass: App.NumberWidgetView
+      },
+      {
+        widgetType: 'GAUGE',
+        viewClass: App.GaugeWidgetView
+      },
+      {
+        widgetType: 'HEATMAP',
+        viewClass: App.HeatmapWidgetView
+      },
+      {
+        widgetType: 'NONE',
+        viewClass: Em.View
+      }
+    ];
+
+    cases.forEach(function (item) {
+
+      it(item.widgetType, function () {
+        widget.set('widgetType', item.widgetType);
+        expect(widget.get('viewClass')).to.eql(item.viewClass);
+      });
+
+    });
+
+  });
+
+});
\ No newline at end of file

Reply via email to