Repository: ambari Updated Branches: refs/heads/trunk 1af1a31fe -> a55c81267
AMBARI-14415 Cover Config models with unit tests. (atkach) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/a55c8126 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/a55c8126 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/a55c8126 Branch: refs/heads/trunk Commit: a55c81267c787b3ab980ba22375b47cf66bd6ec0 Parents: 1af1a31 Author: Andrii Tkach <[email protected]> Authored: Thu Dec 17 16:00:51 2015 +0200 Committer: Andrii Tkach <[email protected]> Committed: Thu Dec 17 16:00:51 2015 +0200 ---------------------------------------------------------------------- ambari-web/app/assets/test/tests.js | 2 + .../alerts/manage_alert_groups_controller.js | 12 +- .../app/controllers/main/charts/heatmap.js | 30 +- ambari-web/app/models/alerts/alert_group.js | 6 +- ambari-web/app/models/configs/config_group.js | 19 +- .../models/configs/service_config_version.js | 61 +++- ambari-web/app/utils/config.js | 11 + .../notification_configs_view.js | 25 +- .../views/main/charts/heatmap/heatmap_host.js | 93 +++-- .../main/charts/heatmap/heatmap_host_detail.js | 15 +- .../wizard/step3/hostWarningPopupBody_view.js | 2 +- .../controllers/main/charts/heatmap_test.js | 359 ++++++++++++++++++- .../test/controllers/main/host/details_test.js | 11 +- ambari-web/test/init_test.js | 6 +- .../test/models/configs/config_group_test.js | 138 +++++++ .../configs/service_config_version_test.js | 288 ++++++++++++++- .../configs/stack_config_property_test.js | 128 +++++++ ambari-web/test/utils/config_test.js | 15 + .../notification_configs_view_test.js | 169 +++++++++ .../test/views/common/filter_view_test.js | 13 +- .../main/charts/heatmap/heatmap_host_test.js | 318 +++++++++++++++- 21 files changed, 1592 insertions(+), 129 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/a55c8126/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 3df5f1c..c44eda8 100644 --- a/ambari-web/app/assets/test/tests.js +++ b/ambari-web/app/assets/test/tests.js @@ -323,6 +323,8 @@ var files = [ 'test/models/configs/sub_section_test', 'test/models/configs/section_test', 'test/models/configs/service_config_version_test', + 'test/models/configs/config_group_test', + 'test/models/configs/stack_config_property_test', 'test/models/configs/objects/service_config_test', 'test/models/configs/objects/service_config_category_test', 'test/models/configs/objects/service_config_property_test', http://git-wip-us.apache.org/repos/asf/ambari/blob/a55c8126/ambari-web/app/controllers/main/alerts/manage_alert_groups_controller.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers/main/alerts/manage_alert_groups_controller.js b/ambari-web/app/controllers/main/alerts/manage_alert_groups_controller.js index 7eb0945..3e1291d 100644 --- a/ambari-web/app/controllers/main/alerts/manage_alert_groups_controller.js +++ b/ambari-web/app/controllers/main/alerts/manage_alert_groups_controller.js @@ -254,11 +254,7 @@ App.ManageAlertGroupsController = Em.Controller.extend({ name: group.get('name'), default: group.get('default'), displayName: function () { - var name = this.get('name'); - if (name && name.length > App.config.CONFIG_GROUP_NAME_MAX_LENGTH) { - var middle = Math.floor(App.config.CONFIG_GROUP_NAME_MAX_LENGTH / 2); - name = name.substring(0, middle) + "..." + name.substring(name.length - middle); - } + var name = App.config.truncateGroupName(this.get('name')); return this.get('default') ? (name + ' Default') : name; }.property('name', 'default'), label: function () { @@ -743,11 +739,7 @@ App.ManageAlertGroupsController = Em.Controller.extend({ name: this.get('alertGroupName').trim(), default: false, displayName: function () { - var name = this.get('name'); - if (name && name.length > App.config.CONFIG_GROUP_NAME_MAX_LENGTH) { - var middle = Math.floor(App.config.CONFIG_GROUP_NAME_MAX_LENGTH / 2); - name = name.substring(0, middle) + "..." + name.substring(name.length - middle); - } + var name = App.config.truncateGroupName(this.get('name')); return this.get('default') ? (name + ' Default') : name; }.property('name', 'default'), label: function () { http://git-wip-us.apache.org/repos/asf/ambari/blob/a55c8126/ambari-web/app/controllers/main/charts/heatmap.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers/main/charts/heatmap.js b/ambari-web/app/controllers/main/charts/heatmap.js index 2ff1341..aacb8e5 100644 --- a/ambari-web/app/controllers/main/charts/heatmap.js +++ b/ambari-web/app/controllers/main/charts/heatmap.js @@ -41,6 +41,9 @@ App.MainChartsHeatmapController = Em.Controller.extend(App.WidgetSectionMixin, { loadRacksUrlParams: 'fields=Hosts/rack_info,Hosts/host_name,Hosts/public_host_name,Hosts/os_type,Hosts/ip,host_components,metrics/disk,metrics/cpu/cpu_system,metrics/cpu/cpu_user,metrics/memory/mem_total,metrics/memory/mem_free&minimal_response=true', + /** + * @type {string} + */ loadHeatmapsUrlParams: function() { var serviceName = this.get('content.serviceName'); if (serviceName) { @@ -86,23 +89,24 @@ App.MainChartsHeatmapController = Em.Controller.extend(App.WidgetSectionMixin, { * @param {Array} allHeatmaps * @return {Array} */ - categorizeByServiceName: function(allHeatmaps) { + categorizeByServiceName: function (allHeatmaps) { var categories = []; - allHeatmaps.forEach(function(_heatmap){ - var serviceNames = JSON.parse(_heatmap.metrics).mapProperty('service_name').uniq(); - serviceNames.forEach(function(_serviceName){ - var category = categories.findProperty('serviceName',_serviceName); + + allHeatmaps.forEach(function (_heatmap) { + var serviceNames = JSON.parse(_heatmap.metrics).mapProperty('service_name').uniq(); + serviceNames.forEach(function (_serviceName) { + var category = categories.findProperty('serviceName', _serviceName); if (!category) { categories.pushObject(Em.Object.create({ serviceName: _serviceName, - displayName: _serviceName === 'STACK' ? 'Host' : App.StackService.find().findProperty('serviceName',_serviceName).get('displayName'), + displayName: _serviceName === 'STACK' ? 'Host' : App.format.role(_serviceName), heatmaps: [_heatmap] })); } else { category.get('heatmaps').pushObject(_heatmap); } - },this); - },this); + }, this); + }, this); return categories; }, @@ -174,8 +178,13 @@ App.MainChartsHeatmapController = Em.Controller.extend(App.WidgetSectionMixin, { this.set('racks', racks); }, + /** + * @param {Array} hosts + * @returns {Object} rackMap + */ indexByRackId: function (hosts) { var rackMap = {}; + hosts.forEach(function (host) { var rackId = host.rack; if(!rackMap[rackId]) { @@ -192,6 +201,11 @@ App.MainChartsHeatmapController = Em.Controller.extend(App.WidgetSectionMixin, { return rackMap; }, + /** + * + * @param {Object} rackMap + * @returns {Array} racks + */ toList: function (rackMap) { var racks = []; var i = 0; http://git-wip-us.apache.org/repos/asf/ambari/blob/a55c8126/ambari-web/app/models/alerts/alert_group.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/models/alerts/alert_group.js b/ambari-web/app/models/alerts/alert_group.js index 489e617..4f40ccf 100644 --- a/ambari-web/app/models/alerts/alert_group.js +++ b/ambari-web/app/models/alerts/alert_group.js @@ -55,11 +55,7 @@ App.AlertGroup = DS.Model.extend({ * @type {string} */ displayName: function () { - var name = this.get('name'); - if (name && name.length > App.config.CONFIG_GROUP_NAME_MAX_LENGTH) { - var middle = Math.floor(App.config.CONFIG_GROUP_NAME_MAX_LENGTH / 2); - name = name.substring(0, middle) + "..." + name.substring(name.length - middle); - } + var name = App.config.truncateGroupName(this.get('name')); return this.get('default') ? (name + ' Default') : name; }.property('name', 'default'), http://git-wip-us.apache.org/repos/asf/ambari/blob/a55c8126/ambari-web/app/models/configs/config_group.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/models/configs/config_group.js b/ambari-web/app/models/configs/config_group.js index 5c76527..f2af891 100644 --- a/ambari-web/app/models/configs/config_group.js +++ b/ambari-web/app/models/configs/config_group.js @@ -63,9 +63,7 @@ App.ServiceConfigGroup = DS.Model.extend({ * defines if group is default * @type {boolean} */ - isDefault: function() { - return this.get('configGroupId') == "-1"; - }.property('configGroupId'), + isDefault: Em.computed.equal('configGroupId', '-1'), /** * list of group names that shows which config @@ -91,17 +89,13 @@ App.ServiceConfigGroup = DS.Model.extend({ childConfigGroups: DS.hasMany('App.ServiceConfigGroup'), hash: DS.attr('string'), + /** * Provides a display friendly name. This includes trimming * names to a certain length. */ displayName: function () { - var name = this.get('name'); - if (name && name.length>App.config.CONFIG_GROUP_NAME_MAX_LENGTH) { - var middle = Math.floor(App.config.CONFIG_GROUP_NAME_MAX_LENGTH / 2); - name = name.substring(0, middle) + "..." + name.substring(name.length-middle); - } - return name; + return App.config.truncateGroupName(this.get('name')); }.property('name'), /** @@ -112,6 +106,7 @@ App.ServiceConfigGroup = DS.Model.extend({ /** * Provides hosts which are available for inclusion in * non-default configuration groups. + * @type {Array} */ availableHosts: function () { if (this.get('isDefault')) return []; @@ -131,6 +126,9 @@ App.ServiceConfigGroup = DS.Model.extend({ return availableHosts; }.property('isDefault', 'parentConfigGroup', 'childConfigGroups', 'parentConfigGroup.hosts.@each', 'clusterHosts'), + /** + * @type {boolean} + */ isAddHostsDisabled: Em.computed.or('isDefault', '!availableHosts.length'), /** @@ -138,6 +136,9 @@ App.ServiceConfigGroup = DS.Model.extend({ */ properties: DS.attr('array', {defaultValue: []}), + /** + * @type {string} + */ propertiesList: function () { var result = ''; http://git-wip-us.apache.org/repos/asf/ambari/blob/a55c8126/ambari-web/app/models/configs/service_config_version.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/models/configs/service_config_version.js b/ambari-web/app/models/configs/service_config_version.js index 36cd572..1315ff7 100644 --- a/ambari-web/app/models/configs/service_config_version.js +++ b/ambari-web/app/models/configs/service_config_version.js @@ -22,6 +22,8 @@ var dateUtil = require('utils/date/date'); App.ServiceConfigVersion = DS.Model.extend({ + MAX_AUTHOR_LENGTH: 20, + MAX_NOTES_LENGTH: 80, serviceName: DS.attr('string'), displayName: Em.computed.formatRole('serviceName'), groupName: DS.attr('string'), @@ -41,36 +43,79 @@ App.ServiceConfigVersion = DS.Model.extend({ canBeMadeCurrent: Em.computed.and('isCompatible', '!isCurrent'), isDefault: Em.computed.equal('groupName', 'default'), currentTooltip: Em.computed.i18nFormat('dashboard.configHistory.table.current.tooltip', 'displayName', 'configGroupName'), + + /** + * @type {string} + */ configGroupName: function () { return this.get('isDefault') ? Em.I18n.t('common.default') : this.get('groupName'); }.property('groupName','isDefault'), + + /** + * @type {string} + */ authorFormatted: function () { var author = this.get('author'); if (author) { - return author.length > 20 ? author.slice(0, 20) + '...' : author; + return author.length > this.get('MAX_AUTHOR_LENGTH') ? author.slice(0, this.get('MAX_AUTHOR_LENGTH')) + '...' : author; } }.property('author'), + + /** + * @type {string} + */ fullNotes: function () { - return (typeof this.get('notes') === 'string') ? this.get('notes') || Em.I18n.t('dashboard.configHistory.table.notes.no') : Em.I18n.t('dashboard.configHistory.table.notes.no'); + return (typeof this.get('notes') === 'string') ? + (this.get('notes') || Em.I18n.t('dashboard.configHistory.table.notes.no')) : + Em.I18n.t('dashboard.configHistory.table.notes.no'); }.property('notes'), + + /** + * @type {string} + */ briefNotes: function () { - return this.get('fullNotes').slice(0, 81); + return this.get('fullNotes').slice(0, (this.get('MAX_NOTES_LENGTH') + 1)); }.property('fullNotes'), + + /** + * @type {boolean} + */ moreNotesExists: function () { - return (typeof this.get('notes') === 'string') ? this.get('notes').length > 80 : false; + return (typeof this.get('notes') === 'string') && this.get('notes').length > this.get('MAX_NOTES_LENGTH'); }.property('notes'), + + /** + * @type {string} + */ versionText: Em.computed.i18nFormat('dashboard.configHistory.table.version.versionText', 'version'), + + /** + * @type {string} + */ makeCurrentButtonText: Em.computed.i18nFormat('dashboard.configHistory.info-bar.revert.versionButton', 'versionText'), + + /** + * @type {string} + */ createdDate: function () { return dateUtil.dateFormat(this.get('createTime')); }.property('createTime'), + + /** + * @type {string} + */ timeSinceCreated: function () { return $.timeago(this.get('rawCreateTime')); }.property('rawCreateTime'), + /** * determine whether ServiceConfigVersion is requested from server */ isRequested: DS.attr('boolean'), + + /** + * @type {boolean} + */ isRestartRequired: function () { if (this.get('service.isRestartRequired') && this.get('isCurrent')) { var hostNames = this.get('hosts'); @@ -83,6 +128,10 @@ App.ServiceConfigVersion = DS.Model.extend({ } return false; }.property('service.isRestartRequired','isDefault', 'isCurrent', 'hosts', 'service.restartRequiredHostsAndComponents', 'router.mainServiceInfoConfigsController.configGroups'), + + /** + * {{view: string, compare: string, revert: string}} disabledActionMessages + */ disabledActionMessages: function () { return { view: (this.get('isDisplayed')) ? Em.I18n.t('dashboard.configHistory.info-bar.view.button.disabled') : '', @@ -90,6 +139,10 @@ App.ServiceConfigVersion = DS.Model.extend({ revert: (this.get('isCurrent')) ? Em.I18n.t('dashboard.configHistory.info-bar.revert.button.disabled') : '' } }.property('isDisplayed', 'isCurrent'), + + /** + * {{view: (string|boolean), compare: (string|boolean), revert: (string|boolean)}} disabledActionAttr + */ disabledActionAttr: function () { return { view: (this.get('isDisplayed')) ? 'disabled' : false, http://git-wip-us.apache.org/repos/asf/ambari/blob/a55c8126/ambari-web/app/utils/config.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/utils/config.js b/ambari-web/app/utils/config.js index 9a14c78..f474748 100644 --- a/ambari-web/app/utils/config.js +++ b/ambari-web/app/utils/config.js @@ -51,6 +51,17 @@ App.config = Em.Object.create({ }, /** + * truncate Config Group name to <CONFIG_GROUP_NAME_MAX_LENGTH> length and paste "..." in the middle + */ + truncateGroupName: function (name) { + if (name && name.length > App.config.CONFIG_GROUP_NAME_MAX_LENGTH) { + var middle = Math.floor(App.config.CONFIG_GROUP_NAME_MAX_LENGTH / 2); + name = name.substring(0, middle) + "..." + name.substring(name.length - middle); + } + return name; + }, + + /** * Check if Hive installation with new MySQL database created via Ambari is allowed * @param osFamily * @returns {boolean} http://git-wip-us.apache.org/repos/asf/ambari/blob/a55c8126/ambari-web/app/views/common/configs/custom_category_views/notification_configs_view.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/common/configs/custom_category_views/notification_configs_view.js b/ambari-web/app/views/common/configs/custom_category_views/notification_configs_view.js index 2947a95..3da387a 100644 --- a/ambari-web/app/views/common/configs/custom_category_views/notification_configs_view.js +++ b/ambari-web/app/views/common/configs/custom_category_views/notification_configs_view.js @@ -45,7 +45,7 @@ App.NotificationsConfigsView = App.ServiceConfigsByCategoryView.extend({ * Determines if notification configs should be disabled * @type {boolean} */ - configsAreDisabled: true, + configsAreDisabled: Em.computed.equal('createNotification', 'no'), /** * Config with flag for user auth in the notification @@ -63,8 +63,7 @@ App.NotificationsConfigsView = App.ServiceConfigsByCategoryView.extend({ this.set('createNotification', this.get('categoryConfigsAll').findProperty('name', 'create_notification').get('value')); this.set('tlsOrSsl', this.get('categoryConfigsAll').findProperty('name', 'mail.smtp.starttls.enable').get('value') ? 'tls' : 'ssl'); var smtp_use_auth = this.get('categoryConfigsAll').findProperty('name', 'smtp_use_auth'); - var v = (smtp_use_auth.get('value') == 'true'); - smtp_use_auth.set('value', v); + smtp_use_auth.set('value', Boolean(smtp_use_auth.get('value') === 'true')); this.updateCategoryConfigs(); }, @@ -85,15 +84,15 @@ App.NotificationsConfigsView = App.ServiceConfigsByCategoryView.extend({ */ onUseAuthConfigChange: function () { var configsToUpdate = ['ambari.dispatch.credential.username', 'ambari.dispatch.credential.password'], - useAuthConfigValue = this.get('useAuthConfig.value'), - useAuthConfigIsEditable = this.get('useAuthConfig.isEditable'), - self = this; + useAuthConfigValue = this.get('useAuthConfig.value'), + useAuthConfigIsEditable = this.get('useAuthConfig.isEditable'); + this.getWithDefault('categoryConfigs', []).forEach(function (config) { if (configsToUpdate.contains(config.get('name'))) { var flag = useAuthConfigIsEditable ? useAuthConfigValue : false; - self.updateConfig(config, flag); + this.updateConfig(config, flag); } - }); + }, this); }.observes('useAuthConfig.value'), /** @@ -103,13 +102,11 @@ App.NotificationsConfigsView = App.ServiceConfigsByCategoryView.extend({ * @method updateCategoryConfigs */ updateCategoryConfigs: function () { - var createNotification = this.get('createNotification'), - self = this; + var createNotification = this.get('createNotification'); + this.getWithDefault('categoryConfigs', []).forEach(function (config) { - var flag = (createNotification == 'yes'); - self.updateConfig(config, flag); - }); - this.set('configsAreDisabled', this.get('createNotification') == 'no'); + this.updateConfig(config, Boolean(createNotification === 'yes')); + }, this); this.onUseAuthConfigChange(); this.get('categoryConfigsAll').findProperty('name', 'create_notification').set('value', createNotification); }.observes('createNotification'), http://git-wip-us.apache.org/repos/asf/ambari/blob/a55c8126/ambari-web/app/views/main/charts/heatmap/heatmap_host.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/main/charts/heatmap/heatmap_host.js b/ambari-web/app/views/main/charts/heatmap/heatmap_host.js index de9d878..544ad85 100644 --- a/ambari-web/app/views/main/charts/heatmap/heatmap_host.js +++ b/ambari-web/app/views/main/charts/heatmap/heatmap_host.js @@ -43,45 +43,80 @@ App.MainChartsHeatmapHostView = Em.View.extend({ * @this App.MainChartsHeatmapHostView */ mouseEnter: function (event) { - var host = this.get('content'); - var view = App.MainChartsHeatmapHostDetailView.create(); - var self = this; - var nonClientComponents = App.get('components.slaves').concat(App.get('components.masters')); + var host = this.get('content'), + view = App.MainChartsHeatmapHostDetailView.create(); - $.each(view.get('details'), function (i) { + Object.keys(view.get('details')).forEach(function (i) { var val = host[i]; switch (i) { case 'diskUsage': - val = self.getUsage(host, 'diskTotal', 'diskFree'); + val = this.getUsage(host['diskTotal'], host['diskFree']); break; case 'cpuUsage': - val = 0; - if (Number.isFinite(host.cpuSystem) && Number.isFinite(host.cpuUser)) { - val = host.cpuSystem + host.cpuUser; - } - val = val.toFixed(1); + val = this.getCpuUsage(host['cpuSystem'], host['cpuUser']); break; case 'memoryUsage': - val = self.getUsage(host, 'memTotal', 'memFree'); + val = this.getUsage(host['memTotal'], host['memFree']); break; case 'hostComponents': - val = []; - host[i].forEach(function (componentName) { - if (nonClientComponents.contains(componentName)) { - val.push(App.format.role(componentName)); - } - }, this); - val = val.join(', ') + val = this.getHostComponents(host[i]); } view.set('details.' + i, val); - }); + }, this); this.setMetric(view, host); this.openDetailsBlock(event); }, /** + * get relative usage of metric in percents + * @param {number} total + * @param {number} free + * @return {string} + */ + getUsage: function (total, free) { + var result = 0; + + if (Number.isFinite(total) && Number.isFinite(free) && total > 0) { + result = ((total - free) / total) * 100; + } + return result.toFixed(1); + }, + + /** + * get CPU usage + * @param {number} cpuSystem + * @param {number} cpuUser + * @returns {string} + */ + getCpuUsage: function (cpuSystem, cpuUser) { + var result = 0; + + if (Number.isFinite(cpuSystem) && Number.isFinite(cpuUser)) { + result = cpuSystem + cpuUser; + } + return result.toFixed(1); + }, + + /** + * get non-client host-components of host + * @param {Array} components + * @returns {string} + */ + getHostComponents: function (components) { + var nonClientComponents = App.get('components.slaves').concat(App.get('components.masters')); + var result = []; + + components.forEach(function (componentName) { + if (nonClientComponents.contains(componentName)) { + result.push(App.format.role(componentName)); + } + }, this); + return result.join(', ') + }, + + /** * show tooltip with host's details */ openDetailsBlock: function (event) { @@ -108,7 +143,7 @@ App.MainChartsHeatmapHostView = Em.View.extend({ if (Em.isNone(value)) { value = this.t('charts.heatmap.unknown'); } else { - if (metricName == 'Garbage Collection Time') { + if (metricName === 'Garbage Collection Time') { value = date.timingFormat(parseInt(value)); } else { if (isNaN(value)) { @@ -123,22 +158,6 @@ App.MainChartsHeatmapHostView = Em.View.extend({ } } }, - /** - * get relative usage of metric in percents - * @param item - * @param totalProperty - * @param freeProperty - * @return {String} - */ - getUsage: function (item, totalProperty, freeProperty) { - var result = 0; - var total = item[totalProperty]; - - if (Number.isFinite(total) && Number.isFinite(item[freeProperty]) && total > 0) { - result = ((total - item[freeProperty]) / total) * 100; - } - return result.toFixed(1); - }, /** * hide Host details block http://git-wip-us.apache.org/repos/asf/ambari/blob/a55c8126/ambari-web/app/views/main/charts/heatmap/heatmap_host_detail.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/main/charts/heatmap/heatmap_host_detail.js b/ambari-web/app/views/main/charts/heatmap/heatmap_host_detail.js index 76873c1..d431df1 100644 --- a/ambari-web/app/views/main/charts/heatmap/heatmap_host_detail.js +++ b/ambari-web/app/views/main/charts/heatmap/heatmap_host_detail.js @@ -20,11 +20,14 @@ var App = require('app'); App.MainChartsHeatmapHostDetailView = Em.View.extend({ templateName: require('templates/main/charts/heatmap/heatmap_host_detail'), - /** @private */ classNames:['heatmap_host_details'], - /** @private */ elementId:'heatmapDetailsBlock', - /** @private */ details:{ - hostName:'test node', - publicHostName:'test node', + /** @private */ classNames: ['heatmap_host_details'], + /** @private */ elementId: 'heatmapDetailsBlock', + /** + * @private + */ + details: { + hostName: 'test node', + publicHostName: 'test node', osType: 'OS', ip: '192.168.0.0', rack: '/default_rack', @@ -33,6 +36,6 @@ App.MainChartsHeatmapHostDetailView = Em.View.extend({ diskUsage: '10', cpuUsage: '10', memoryUsage: '10', - hostComponents: 'host components' + hostComponents: [] } }); http://git-wip-us.apache.org/repos/asf/ambari/blob/a55c8126/ambari-web/app/views/wizard/step3/hostWarningPopupBody_view.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/wizard/step3/hostWarningPopupBody_view.js b/ambari-web/app/views/wizard/step3/hostWarningPopupBody_view.js index 531f94b..5128ca3 100644 --- a/ambari-web/app/views/wizard/step3/hostWarningPopupBody_view.js +++ b/ambari-web/app/views/wizard/step3/hostWarningPopupBody_view.js @@ -132,7 +132,7 @@ App.WizardStep3HostWarningPopupBody = Em.View.extend({ var warningsByHost = this.get('warningsByHost'); if (Em.isNone(warningsByHost)) return []; var category = warningsByHost.findProperty('name', this.get('category')); - return Em.isNone(category) ? []: category.warnings; + return Em.isNone(category) ? [] : category.warnings || []; }.property('warningsByHost', 'category'), /** http://git-wip-us.apache.org/repos/asf/ambari/blob/a55c8126/ambari-web/test/controllers/main/charts/heatmap_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/controllers/main/charts/heatmap_test.js b/ambari-web/test/controllers/main/charts/heatmap_test.js index dbdf8c3..1dca028 100644 --- a/ambari-web/test/controllers/main/charts/heatmap_test.js +++ b/ambari-web/test/controllers/main/charts/heatmap_test.js @@ -18,6 +18,7 @@ var App = require('app'); +var controller; require('models/rack'); require('controllers/main/charts/heatmap'); @@ -27,26 +28,34 @@ function getController() { describe('MainChartsHeatmapController', function () { + before(function () { + controller = getController(); + }); + App.TestAliases.testAsComputedAlias(getController(), 'activeWidget', 'widgets.firstObject', 'object'); App.TestAliases.testAsComputedAlias(getController(), 'hostToSlotMap', 'selectedMetric.hostToSlotMap', 'object'); describe('#validation()', function () { - var controller = App.MainChartsHeatmapController.create({ - allMetrics: [], - selectedMetric: Ember.Object.create({maximumValue: 100}) + + beforeEach(function() { + controller.setProperties({ + allMetrics: [], + selectedMetric: Ember.Object.create({maximumValue: 100}) + }); }); + it('should set maximumValue if inputMaximum consists only of digits', function () { controller.set("inputMaximum", 5); expect(controller.get('selectedMetric.maximumValue')).to.equal(5); }); it('should not set maximumValue if inputMaximum consists not only of digits', function () { controller.set("inputMaximum", 'qwerty'); - expect(controller.get('selectedMetric.maximumValue')).to.equal(5); + expect(controller.get('selectedMetric.maximumValue')).to.equal(100); }); it('should not set maximumValue if inputMaximum consists not only of digits', function () { controller.set("inputMaximum", '100%'); - expect(controller.get('selectedMetric.maximumValue')).to.equal(5); + expect(controller.get('selectedMetric.maximumValue')).to.equal(100); }); it('should set maximumValue if inputMaximum consists only of digits', function () { controller.set("inputMaximum", 1000); @@ -63,22 +72,21 @@ describe('MainChartsHeatmapController', function () { } } }); + controller.setProperties({ + activeWidgetLayout: Em.Object.create({ + displayName: 'widget', + id: '1', + scope: 'CLUSTER', + layoutName: 'defualt_layout', + sectionName: 'default_section' + }) + }); }); afterEach(function () { App.ajax.send.restore(); }); - var controller = App.MainChartsHeatmapController.create({ - activeWidgetLayout: Em.Object.create({ - displayName: 'widget', - id: '1', - scope: 'CLUSTER', - layoutName: 'defualt_layout', - sectionName: 'default_section' - }) - }); - it('should call App.ajax', function () { controller.showHeatMapMetric({context:{id: 2}}); expect(App.ajax.send.called).to.be.true; @@ -86,10 +94,14 @@ describe('MainChartsHeatmapController', function () { }); describe('#rackClass', function () { - var controller = App.MainChartsHeatmapController.create({ - allMetrics: [], - racks: [1] + + beforeEach(function () { + controller.setProperties({ + allMetrics: [], + racks: [1] + }); }); + it('should return "span12" for 1 cluster rack', function () { expect(controller.get('rackClass')).to.equal('span12'); }); @@ -102,5 +114,316 @@ describe('MainChartsHeatmapController', function () { expect(controller.get('rackClass')).to.equal('span4'); }); }); + + describe("#loadHeatmapsUrlParams", function() { + + it("content.serviceName is null", function() { + controller.set('content', Em.Object.create({serviceName: null})); + expect(controller.get('loadHeatmapsUrlParams')).to.equal('WidgetInfo/widget_type=HEATMAP&WidgetInfo/scope=CLUSTER&fields=WidgetInfo/metrics'); + }); + + it("content.serviceName is correct", function() { + controller.set('content', Em.Object.create({serviceName: 'S1'})); + expect(controller.get('loadHeatmapsUrlParams')).to.equal('WidgetInfo/widget_type=HEATMAP&WidgetInfo/scope=CLUSTER&WidgetInfo/metrics.matches(.*\"service_name\":\"S1\".*)&fields=WidgetInfo/metrics'); + }); + }); + + describe("#loadPageData()", function() { + var allHeatmapData = { + items: [ + { + WidgetInfo: 'info' + } + ] + }; + + beforeEach(function(){ + sinon.stub(controller, 'loadRacks').returns({ + always: function(callback) { + callback(); + } + }); + sinon.stub(controller, 'getAllHeatMaps').returns({ + done: function(callback) { + callback(allHeatmapData); + } + }); + sinon.stub(controller, 'resetPageData'); + sinon.stub(controller, 'categorizeByServiceName').returns('categories'); + sinon.stub(controller, 'getActiveWidgetLayout'); + controller.get('allHeatmaps').clear(); + controller.loadPageData(); + }); + + afterEach(function() { + controller.loadRacks.restore(); + controller.resetPageData.restore(); + controller.getAllHeatMaps.restore(); + controller.categorizeByServiceName.restore(); + controller.getActiveWidgetLayout.restore(); + }); + + it("loadRacks() should be called", function() { + expect(controller.loadRacks.calledOnce).to.be.true; + expect(controller.resetPageData.calledOnce).to.be.true; + }); + + it("getAllHeatMaps() should be called", function() { + expect(controller.getAllHeatMaps.calledOnce).to.be.true; + expect(controller.get('isLoaded')).to.be.true; + expect(controller.get('allHeatmaps')[0]).to.equal('info') + }); + + it("categorizeByServiceName() should be called", function() { + expect(controller.categorizeByServiceName.calledOnce).to.be.true; + expect(controller.get('heatmapCategories')).to.equal('categories'); + }); + + it("getActiveWidgetLayout() should be called", function() { + expect(controller.getActiveWidgetLayout.calledOnce).to.be.true; + }); + }); + + describe("#categorizeByServiceName()", function() { + + beforeEach(function() { + sinon.stub(App.format, 'role').returns('S1'); + }); + + afterEach(function() { + App.format.role.restore(); + }); + + it("single category", function() { + var allHeatmaps = [ + { + metrics: JSON.stringify([{service_name: 'S1'}]) + } + ]; + var categories = controller.categorizeByServiceName(allHeatmaps); + expect(categories[0].get('serviceName')).to.equal('S1'); + expect(categories[0].get('displayName')).to.equal('S1'); + expect(categories[0].get('heatmaps')).to.eql(allHeatmaps); + }); + + it("two categories", function() { + var allHeatmaps = [ + { + metrics: JSON.stringify([{service_name: 'S1'}]) + }, + { + metrics: JSON.stringify([{service_name: 'S1'}]) + } + ]; + var categories = controller.categorizeByServiceName(allHeatmaps); + expect(categories[0].get('serviceName')).to.equal('S1'); + expect(categories[0].get('displayName')).to.equal('S1'); + expect(categories[0].get('heatmaps')[0]).to.eql(allHeatmaps[0]); + expect(categories[0].get('heatmaps')[1]).to.eql(allHeatmaps[1]); + }); + }); + + describe("#resetPageData()", function() { + + it("should clean heatmapCategories and allHeatmaps", function() { + controller.set('heatmapCategories', [{}]); + controller.set('allHeatmaps', [{}]); + controller.resetPageData(); + expect(controller.get('heatmapCategories')).to.be.empty; + expect(controller.get('allHeatmaps')).to.be.empty; + }); + }); + + describe("#getAllHeatMaps()", function() { + + beforeEach(function() { + sinon.stub(App.ajax, 'send'); + }); + + afterEach(function() { + App.ajax.send.restore(); + }); + + it("should call App.ajax.send", function() { + controller.reopen({ + loadHeatmapsUrlParams: 'url', + sectionName: 's1' + }); + controller.getAllHeatMaps(); + expect(App.ajax.send.calledWith({ + name: 'widgets.get', + sender: controller, + data: { + urlParams: 'url', + sectionName: 's1' + } + })).to.be.true; + }); + }); + + describe("#loadRacks()", function() { + + beforeEach(function() { + sinon.stub(App.ajax, 'send'); + }); + + afterEach(function() { + App.ajax.send.restore(); + }); + + it("should call App.ajax.send", function() { + controller.reopen({ + loadRacksUrlParams: 'url' + }); + controller.loadRacks(); + expect(App.ajax.send.calledWith({ + name: 'hosts.heatmaps', + sender: controller, + data: { + urlParams: 'url' + }, + success: 'loadRacksSuccessCallback' + })).to.be.true; + + }); + }); + + describe("#loadRacksSuccessCallback()", function() { + + var data = { + items: [ + { + Hosts: { + host_name: 'host1', + public_host_name: 'host1', + os_type: 'os1', + ip: 'ip1', + rack_info: 'info' + }, + host_components: [ + { + HostRoles: { + component_name: 'c1' + } + } + ] + } + ] + }; + + beforeEach(function() { + sinon.stub(controller, 'indexByRackId').returns({rack: {}}); + sinon.stub(controller, 'toList').returns(['rack']); + controller.loadRacksSuccessCallback(data); + }); + + afterEach(function(){ + controller.indexByRackId.restore(); + controller.toList.restore(); + }); + + it("indexByRackId should be called", function() { + expect(controller.indexByRackId.calledWith([{ + hostName: 'host1', + publicHostName: 'host1', + osType: 'os1', + ip: 'ip1', + rack: 'info', + diskTotal: 0, + diskFree: 0, + cpuSystem: 0, + cpuUser: 0, + memTotal: 0, + memFree: 0, + hostComponents: ['c1'] + }])).to.be.true; + }); + + it("toList should be called", function() { + expect(controller.toList.calledWith({rack: {}})).to.be.true; + expect(controller.get('rackMap')).to.eql({rack: {}}); + expect(controller.get('racks')).to.eql(['rack']); + }); + }); + + describe("#indexByRackId()", function() { + + it("should return rack map", function() { + var hosts = [ + {rack: 'r1'}, + {rack: 'r1'} + ]; + var rackMap = controller.indexByRackId(hosts); + expect(rackMap['r1'].name).to.equal('r1'); + expect(rackMap['r1'].rackId).to.equal('r1'); + expect(rackMap['r1'].hosts).to.eql([{rack: 'r1'}, {rack: 'r1'}]); + }); + }); + + describe("#toList()", function() { + it("", function() { + var rackMap = {'r1': { + name: 'r1', + rackId: 'r1', + hosts: [{rack: 'r1'}, {rack: 'r1'}] + }}; + expect(controller.toList(rackMap)).to.eql([Em.Object.create({ + name: 'r1', + rackId: 'r1', + hosts: [{rack: 'r1'}, {rack: 'r1'}], + isLoaded: false, + index: 0 + })]); + }); + }); + + describe("#addRackView()", function() { + + beforeEach(function() { + sinon.stub(controller, 'displayAllRacks'); + }); + + afterEach(function() { + controller.displayAllRacks.restore(); + }); + + it("displayAllRacks should be called", function() { + controller.set('racks', [{}]); + controller.set('rackViews', []); + controller.addRackView({}); + expect(controller.displayAllRacks.calledOnce).to.be.true; + }); + }); + + describe("#displayAllRacks", function() { + var rackView = { + displayHosts: Em.K + }; + + beforeEach(function() { + sinon.spy(controller, 'displayAllRacks'); + sinon.spy(rackView, 'displayHosts'); + }); + + afterEach(function() { + controller.displayAllRacks.restore(); + rackView.displayHosts.restore(); + }); + + it("displayAllRacks should be called again", function() { + controller.set('rackViews', [rackView]); + controller.displayAllRacks(); + expect(controller.displayAllRacks.calledTwice).to.be.true; + expect(rackView.displayHosts.calledOnce).to.be.true; + }); + + it("displayAllRacks should not be called again", function() { + controller.set('rackViews', []); + controller.displayAllRacks(); + expect(controller.displayAllRacks.calledOnce).to.be.true; + }); + }); + + }); http://git-wip-us.apache.org/repos/asf/ambari/blob/a55c8126/ambari-web/test/controllers/main/host/details_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/controllers/main/host/details_test.js b/ambari-web/test/controllers/main/host/details_test.js index 1ed9d47..0806823 100644 --- a/ambari-web/test/controllers/main/host/details_test.js +++ b/ambari-web/test/controllers/main/host/details_test.js @@ -1816,20 +1816,15 @@ describe('App.MainHostDetailsController', function () { }); it('serviceActiveComponents is correct', function () { + var components = [{}]; controller.reopen({ - serviceActiveComponents: [ - {} - ] + serviceActiveComponents: components }); var popup = controller.doRestartAllComponents(); expect(App.showConfirmationPopup.calledOnce).to.be.true; popup.onPrimary(); - expect(batchUtils.restartHostComponents.calledWith( - [ - {} - ]) - ).to.be.true; + expect(batchUtils.restartHostComponents.calledWith(components)).to.be.true; }); it('serviceActiveComponents is correct, NAMENODE started', function () { controller.reopen({ http://git-wip-us.apache.org/repos/asf/ambari/blob/a55c8126/ambari-web/test/init_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/init_test.js b/ambari-web/test/init_test.js index 5a4b223..8b1cfab 100644 --- a/ambari-web/test/init_test.js +++ b/ambari-web/test/init_test.js @@ -47,4 +47,8 @@ if (!Function.prototype.bind) { return fBound; }; -} \ No newline at end of file +} + +Number.isFinite = Number.isFinite || function(value) { + return typeof value === 'number' && isFinite(value); +}; \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/a55c8126/ambari-web/test/models/configs/config_group_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/models/configs/config_group_test.js b/ambari-web/test/models/configs/config_group_test.js new file mode 100644 index 0000000..9ba8469 --- /dev/null +++ b/ambari-web/test/models/configs/config_group_test.js @@ -0,0 +1,138 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var App = require('app'); +var model; + +function getModel() { + return App.ServiceConfigGroup.createRecord({ + parentConfigGroup: Em.Object.create({ + hosts: [] + }) + }); +} + +describe('App.ServiceConfigGroup', function () { + + beforeEach(function () { + model = getModel(); + }); + + App.TestAliases.testAsComputedEqual(getModel(), 'isDefault', 'configGroupId', '-1'); + + describe("#displayName", function() { + + before(function () { + sinon.stub(App.config, 'truncateGroupName'); + }); + after(function () { + App.config.truncateGroupName.restore(); + }); + + it("App.config.truncateGroupName should be called", function() { + model.set('name', 'group1'); + model.get('displayName'); + expect(App.config.truncateGroupName.called).to.be.true; + }); + }); + + describe("#availableHosts", function() { + + it("default group", function() { + model.reopen({ + isDefault: true + }); + expect(model.get('availableHosts')).to.be.empty; + }); + + it("no cluster hosts", function() { + model.reopen({ + isDefault: false, + clusterHosts: [] + }); + expect(model.get('availableHosts')).to.be.empty; + }); + + it("cluster hosts used", function() { + model.reopen({ + isDefault: false, + clusterHosts: [ + Em.Object.create({id: 'g1'}) + ] + }); + expect(model.get('availableHosts')).to.be.empty; + }); + + it("cluster hosts not used", function() { + var host = Em.Object.create({ + id: 'g1', + hostComponents: [{componentName: 'c1'}] + }); + + model.reopen({ + isDefault: false, + clusterHosts: [host] + }); + model.set('parentConfigGroup.hosts', ['g1']); + expect(model.get('availableHosts')).to.not.be.empty; + expect(model.get('availableHosts')[0].get('selected')).to.be.false; + expect(model.get('availableHosts')[0].get('hostComponentNames')).to.eql(['c1']); + expect(model.get('availableHosts')[0].get('host')).to.eql(host); + }); + }); + + describe("#propertiesList", function() { + + it("properties is null", function() { + model.set('properties', null); + expect(model.get('propertiesList')).to.be.empty; + }); + + it("properties is correct", function() { + model.set('properties', [ + { + name: 'p1', + value: 'v1' + } + ]); + expect(model.get('propertiesList')).to.equal('p1 : v1<br/>'); + }); + }); + + describe("#getParentConfigGroupId()", function () { + + before(function () { + sinon.stub(App.ServiceConfigGroup, 'groupId'); + }); + after(function () { + App.ServiceConfigGroup.groupId.restore(); + }); + + it("App.ServiceConfigGroup.groupId should be called", function () { + App.ServiceConfigGroup.getParentConfigGroupId('S1'); + expect(App.ServiceConfigGroup.groupId.calledWith('S1', 'Default')).to.be.true; + }); + }); + + describe("#groupId()", function () { + + it("should return group id", function () { + expect(App.ServiceConfigGroup.groupId('S1', 'g1')).to.be.equal('S1_g1'); + }); + }); +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/a55c8126/ambari-web/test/models/configs/service_config_version_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/models/configs/service_config_version_test.js b/ambari-web/test/models/configs/service_config_version_test.js index b5b730c..06cf915 100644 --- a/ambari-web/test/models/configs/service_config_version_test.js +++ b/ambari-web/test/models/configs/service_config_version_test.js @@ -31,6 +31,8 @@ describe('App.ServiceConfigVersion', function () { model = getModel(); }); + App.TestAliases.testAsComputedAnd(getModel(), 'canBeMadeCurrent', ['isCompatible', '!isCurrent']); + describe('#authorFormatted', function () { var cases = [ @@ -55,6 +57,290 @@ describe('App.ServiceConfigVersion', function () { }); - App.TestAliases.testAsComputedAnd(getModel(), 'canBeMadeCurrent', ['isCompatible', '!isCurrent']); + describe("#configGroupName", function() { + + it("default group", function() { + model.reopen({ + groupName: 'g1', + isDefault: false + }); + expect(model.get('configGroupName')).to.equal('g1'); + }); + + it("default group", function() { + model.reopen({ + isDefault: true + }); + expect(model.get('configGroupName')).to.equal(Em.I18n.t('common.default')); + }); + + }); + + describe("#fullNotes", function() { + + it("notes is null", function() { + model.set('notes', null); + expect(model.get('fullNotes')).to.equal(Em.I18n.t('dashboard.configHistory.table.notes.no')); + }); + + it("notes is empty", function() { + model.set('notes', ""); + expect(model.get('fullNotes')).to.equal(Em.I18n.t('dashboard.configHistory.table.notes.no')); + }); + + it("notes has value", function() { + model.set('notes', "notes-value"); + expect(model.get('fullNotes')).to.equal('notes-value'); + }); + + }); + + describe("#briefNotes", function() { + + it("notes shorter than MAX_NOTES_LENGTH", function() { + model.reopen({ + fullNotes: 'short-notes' + }); + expect(model.get('briefNotes')).to.equal('short-notes'); + }); + + it("notes longer than MAX_NOTES_LENGTH", function() { + model.reopen({ + fullNotes: 'long-notes-long-notes-long-notes-long-notes-long-notes-long-notes-long-notes-long-notes' + + '-long-notes-long-notes-long-notes-long-notes-long-notes' + }); + expect(model.get('briefNotes')).to.equal('long-notes-long-notes-long-notes-long-notes-long-notes-long-notes-long-notes-long'); + }); + + }); + + describe("#moreNotesExists", function() { + + it("notes is null", function() { + model.set('notes', null); + expect(model.get('moreNotesExists')).to.be.false; + }); + + it("notes is shorter than MAX_NOTES_LENGTH", function() { + model.set('notes', 'short-notes'); + expect(model.get('moreNotesExists')).to.be.false; + }); + + it("notes is longer than MAX_NOTES_LENGTH", function() { + model.set('notes', 'long-notes-long-notes-long-notes-long-notes-long-notes-long-notes-long-notes-long-notes' + + '-long-notes-long-notes-long-notes-long-notes-long-notes'); + expect(model.get('moreNotesExists')).to.be.true; + }); + + }); + + describe("#createdDate", function() { + + it("should return created date", function() { + model.set('createTime', 1450267588961); + expect(model.get('createdDate')).to.equal('Wed, Dec 16, 2015 14:06'); + }); + + }); + + describe("#timeSinceCreated", function () { + + before(function () { + sinon.stub($, 'timeago').returns('timeago'); + }); + after(function () { + $.timeago.restore() + }); + + it("should return time since created", function () { + model.set('rawCreateTime', 1450267588961); + expect(model.get('timeSinceCreated')).to.equal('timeago'); + }); + + }); + + describe("#isRestartRequired", function() { + + it("service.isRestartRequired is false", function() { + model.set('service', Em.Object.create({ + isRestartRequired: false + })); + expect(model.get('isRestartRequired')).to.be.false; + }); + + it("non-current version", function() { + model.set('service', Em.Object.create({ + isRestartRequired: true + })); + model.set('isCurrent', false); + expect(model.get('isRestartRequired')).to.be.false; + }); + + it("version has no hosts", function() { + model.setProperties({ + service: Em.Object.create({ + isRestartRequired: true + }), + isCurrent: true, + hosts: [] + }); + expect(model.get('isRestartRequired')).to.be.false; + }); + + it("version hosts don't need restart", function() { + model.setProperties({ + service: Em.Object.create({ + isRestartRequired: true, + restartRequiredHostsAndComponents: {} + }), + isCurrent: true, + hosts: ['host1'] + }); + expect(model.get('isRestartRequired')).to.be.false; + }); + + it("version hosts need restart", function() { + model.setProperties({ + service: Em.Object.create({ + isRestartRequired: true, + restartRequiredHostsAndComponents: {'host1': {}} + }), + isCurrent: true, + hosts: ['host1'] + }); + expect(model.get('isRestartRequired')).to.be.true; + }); + + }); + + describe("#disabledActionMessages", function() { + var testCases = [ + { + input: { + isDisplayed: false, + isCurrent: false + }, + expected: { + view: '', + compare: '', + revert: '' + } + }, + { + input: { + isDisplayed: true, + isCurrent: false + }, + expected: { + view: Em.I18n.t('dashboard.configHistory.info-bar.view.button.disabled'), + compare: Em.I18n.t('dashboard.configHistory.info-bar.compare.button.disabled'), + revert: '' + } + }, + { + input: { + isDisplayed: false, + isCurrent: true + }, + expected: { + view: '', + compare: '', + revert: Em.I18n.t('dashboard.configHistory.info-bar.revert.button.disabled') + } + }, + { + input: { + isDisplayed: true, + isCurrent: true + }, + expected: { + view: Em.I18n.t('dashboard.configHistory.info-bar.view.button.disabled'), + compare: Em.I18n.t('dashboard.configHistory.info-bar.compare.button.disabled'), + revert: Em.I18n.t('dashboard.configHistory.info-bar.revert.button.disabled') + } + } + ]; + + testCases.forEach(function(test) { + it("isDisplayed = " + test.input.isDisplayed + ", isCurrent = " + test.input.isCurrent, function() { + model.setProperties(test.input); + expect(model.get('disabledActionMessages')).to.eql(test.expected); + }); + }); + + }); + + describe("#disabledActionAttr", function() { + var testCases = [ + { + input: { + isDisplayed: false, + isCurrent: false, + isDisabled: false + }, + expected: { + view: false, + compare: false, + revert: false + } + }, + { + input: { + isDisplayed: true, + isCurrent: false, + isDisabled: false + }, + expected: { + view: 'disabled', + compare: 'disabled', + revert: false + } + }, + { + input: { + isDisplayed: false, + isCurrent: false, + isDisabled: true + }, + expected: { + view: false, + compare: 'disabled', + revert: 'disabled' + } + }, + { + input: { + isDisplayed: false, + isCurrent: true, + isDisabled: false + }, + expected: { + view: false, + compare: false, + revert: 'disabled' + } + }, + { + input: { + isDisplayed: true, + isCurrent: true, + isDisabled: true + }, + expected: { + view: 'disabled', + compare: 'disabled', + revert: 'disabled' + } + } + ]; + + testCases.forEach(function(test) { + it("isDisplayed = " + test.input.isDisplayed + ", isCurrent = " + test.input.isCurrent + ", isDisabled = " + test.input.isDisabled, function() { + model.setProperties(test.input); + expect(model.get('disabledActionAttr')).to.eql(test.expected); + }); + }); + + }); }); http://git-wip-us.apache.org/repos/asf/ambari/blob/a55c8126/ambari-web/test/models/configs/stack_config_property_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/models/configs/stack_config_property_test.js b/ambari-web/test/models/configs/stack_config_property_test.js new file mode 100644 index 0000000..9c8da3a --- /dev/null +++ b/ambari-web/test/models/configs/stack_config_property_test.js @@ -0,0 +1,128 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var App = require('app'); +var model; + +function getModel() { + return App.StackConfigProperty.createRecord(); +} + +describe('App.StackConfigProperty', function () { + + beforeEach(function () { + model = getModel(); + }); + + describe("#Attributes", function() { + var testCases = [ + { + propertyKey: 'type', + propertyName: 'displayType', + value: 't1', + expectedValue: 't1', + defaultValue: 'string' + }, + { + propertyKey: 'overridable', + propertyName: 'isOverridable', + value: false, + expectedValue: false, + defaultValue: true + }, + { + propertyKey: 'visible', + propertyName: 'isVisible', + value: false, + expectedValue: false, + defaultValue: true + }, + { + propertyKey: 'empty_value_valid', + propertyName: 'isRequired', + value: true, + expectedValue: false, + defaultValue: true + }, + { + propertyKey: 'editable_only_at_install', + propertyName: 'isReconfigurable', + value: true, + expectedValue: false, + defaultValue: true + }, + { + propertyKey: 'show_property_name', + propertyName: 'showLabel', + value: false, + expectedValue: false, + defaultValue: true + }, + { + propertyKey: 'read_only', + propertyName: 'isEditable', + value: false, + expectedValue: false, + defaultValue: true + }, + { + propertyKey: 'unit', + propertyName: 'unit', + value: 'mb', + expectedValue: 'mb', + defaultValue: '' + } + ]; + + testCases.forEach(function(test) { + + it("valueAttributes is null, " + test.propertyName + " should be " + test.defaultValue, function() { + model.set('valueAttributes', null); + expect(model.get(test.propertyName)).to.equal(test.defaultValue); + }); + + it("valueAttributes is object, " + test.propertyName + " should be " + test.expectedValue, function() { + var valueAttributes = {}; + valueAttributes[test.propertyKey] = test.value; + model.set('valueAttributes', valueAttributes); + expect(model.get(test.propertyName)).to.equal(test.expectedValue); + }); + + }); + }); + + describe("#getAttribute()", function() { + + it("valueAttributes is null", function() { + model.set('valueAttributes', null); + expect(model.getAttribute('attr1', 'defVal')).to.equal('defVal'); + }); + + it("valueAttributes is empty object", function() { + model.set('valueAttributes', {}); + expect(model.getAttribute('attr1', 'defVal')).to.equal('defVal'); + }); + + it("valueAttributes is correct object", function() { + model.set('valueAttributes', {attr1: 'val'}); + expect(model.getAttribute('attr1', 'defVal')).to.equal('val'); + }); + + }); + +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/a55c8126/ambari-web/test/utils/config_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/utils/config_test.js b/ambari-web/test/utils/config_test.js index ff770f0..d3b4d8d 100644 --- a/ambari-web/test/utils/config_test.js +++ b/ambari-web/test/utils/config_test.js @@ -1068,4 +1068,19 @@ describe('App.config', function () { }); }); }); + + describe("#truncateGroupName()", function() { + + it("name is empty", function() { + expect(App.config.truncateGroupName('')).to.be.empty; + }); + + it("name has less than max chars", function() { + expect(App.config.truncateGroupName('group1')).to.equal('group1'); + }); + + it("name has more than max chars", function() { + expect(App.config.truncateGroupName('group_has_more_than_max_characters')).to.equal('group_has...haracters'); + }); + }); }); http://git-wip-us.apache.org/repos/asf/ambari/blob/a55c8126/ambari-web/test/views/common/configs/custom_category_views/notification_configs_view_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/views/common/configs/custom_category_views/notification_configs_view_test.js b/ambari-web/test/views/common/configs/custom_category_views/notification_configs_view_test.js index ce0dd39..4552f78 100644 --- a/ambari-web/test/views/common/configs/custom_category_views/notification_configs_view_test.js +++ b/ambari-web/test/views/common/configs/custom_category_views/notification_configs_view_test.js @@ -29,6 +29,8 @@ function getView() { name: 'name' }, serviceConfigs: [], + categoryConfigs: [], + categoryConfigsAll: [], parentView: Em.View.create({ filter: '', columns: [] @@ -48,10 +50,12 @@ describe('App.NotificationsConfigsView', function () { beforeEach(function () { sinon.stub(view, 'updateCategoryConfigs', Em.K); + sinon.stub(view, 'onTlsOrSslChanged'); }); afterEach(function () { view.updateCategoryConfigs.restore(); + view.onTlsOrSslChanged.restore(); }); it('should not do nothing if no configs', function () { @@ -62,6 +66,171 @@ describe('App.NotificationsConfigsView', function () { }); + it('should update category configs', function () { + var configs = [ + Em.Object.create({ + name: "create_notification", + value: 'yes' + }), + Em.Object.create({ + name: 'mail.smtp.starttls.enable', + value: false + }), + Em.Object.create({ + name: 'smtp_use_auth', + value: 'true' + }) + ]; + + view.set('categoryConfigsAll', configs); + view.didInsertElement(); + expect(view.get('createNotification')).to.equal('yes'); + expect(view.get('tlsOrSsl')).to.equal('ssl'); + expect(configs.findProperty('name', 'smtp_use_auth').get('value')).to.be.true; + expect(view.updateCategoryConfigs.called).to.be.true; + }); + }); + + describe("#onTlsOrSslChanged()", function () { + + var configs = [ + Em.Object.create({ + name: "mail.smtp.starttls.enable", + value: 'yes' + }), + Em.Object.create({ + name: 'mail.smtp.startssl.enable', + value: false + }) + ]; + + it("tls", function () { + view.set('categoryConfigsAll', configs); + view.set('tlsOrSsl', 'tls'); + view.onTlsOrSslChanged(); + expect(configs.findProperty('name', 'mail.smtp.starttls.enable').get('value')).to.be.true; + expect(configs.findProperty('name', 'mail.smtp.startssl.enable').get('value')).to.be.false; + }); + + it("ssl", function () { + view.set('categoryConfigsAll', configs); + view.set('tlsOrSsl', 'ssl'); + view.onTlsOrSslChanged(); + expect(configs.findProperty('name', 'mail.smtp.starttls.enable').get('value')).to.be.false; + expect(configs.findProperty('name', 'mail.smtp.startssl.enable').get('value')).to.be.true; + }); + }); + + describe("#onUseAuthConfigChange()", function () { + + beforeEach(function () { + sinon.stub(view, 'updateConfig'); + view.set('categoryConfigs', [ + Em.Object.create({name: 'ambari.dispatch.credential.username'}), + Em.Object.create({name: 'smtp_use_auth'}) + ]); + }); + + afterEach(function () { + view.updateConfig.restore(); + }); + + it("auth config is not editable", function () { + view.get('categoryConfigs').findProperty('name', 'smtp_use_auth').setProperties({ + value: true, + isEditable: false + }); + view.onUseAuthConfigChange(); + expect(view.updateConfig.calledWith( + Em.Object.create({name: 'ambari.dispatch.credential.username'}), + false + )).to.be.true; + }); + + it("auth config is editable", function () { + view.get('categoryConfigs').findProperty('name', 'smtp_use_auth').setProperties({ + value: true, + isEditable: true + }); + view.onUseAuthConfigChange(); + expect(view.updateConfig.calledWith( + Em.Object.create({name: 'ambari.dispatch.credential.username'}), + true + )).to.be.true; + }); + }); + + describe("#updateCategoryConfigs()", function () { + + beforeEach(function () { + sinon.stub(view, 'updateConfig'); + sinon.stub(view, 'onUseAuthConfigChange'); + view.set('categoryConfigs', [ + Em.Object.create({name: 'ambari.dispatch.credential.username'}) + ]); + view.set('categoryConfigsAll', [ + Em.Object.create({ + name: 'create_notification' + }) + ]); + }); + + afterEach(function () { + view.updateConfig.restore(); + view.onUseAuthConfigChange.restore(); + }); + + it("createNotification is 'yes'", function () { + view.set('createNotification', 'yes'); + view.updateCategoryConfigs(); + expect(view.onUseAuthConfigChange.called).to.be.true; + expect(view.get('categoryConfigsAll').findProperty('name', 'create_notification').get('value')).to.equal('yes'); + expect(view.updateConfig.calledWith( + Em.Object.create({name: 'ambari.dispatch.credential.username'}), + true + )).to.be.true; + }); + + it("createNotification is 'no'", function () { + view.set('createNotification', 'no'); + view.updateCategoryConfigs(); + expect(view.onUseAuthConfigChange.called).to.be.true; + expect(view.get('categoryConfigsAll').findProperty('name', 'create_notification').get('value')).to.equal('no'); + expect(view.updateConfig.calledWith( + Em.Object.create({name: 'ambari.dispatch.credential.username'}), + false + )).to.be.true; + }); }); + describe("#updateConfig()", function () { + + var config; + + beforeEach(function () { + config = Em.Object.create({ + validate: Em.K + }); + sinon.spy(config, 'validate'); + }); + + afterEach(function () { + config.validate.restore(); + }); + + it("flag is true", function () { + view.updateConfig(config, true); + expect(config.get('isRequired')).to.be.true; + expect(config.get('isEditable')).to.be.true; + expect(config.validate.calledOnce).to.be.true; + }); + + it("flag is false", function () { + view.updateConfig(config, false); + expect(config.get('isRequired')).to.be.false; + expect(config.get('isEditable')).to.be.false; + expect(config.get('errorMessage')).to.be.empty; + expect(config.validate.called).to.be.false; + }); + }); }); http://git-wip-us.apache.org/repos/asf/ambari/blob/a55c8126/ambari-web/test/views/common/filter_view_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/views/common/filter_view_test.js b/ambari-web/test/views/common/filter_view_test.js index 1afd844..3bf8152 100644 --- a/ambari-web/test/views/common/filter_view_test.js +++ b/ambari-web/test/views/common/filter_view_test.js @@ -202,31 +202,30 @@ describe('filters.getFilterByType', function () { describe('date', function () { var filter = filters.getFilterByType('date'); - var currentTime = new Date().getTime(); var testData = [ { condition: 'Past 1 Day', - value: currentTime - 86300000, + value: 86300000, result: true }, { condition: 'Past 2 Days', - value: currentTime - 172700000, + value: 172700000, result: true }, { condition: 'Past 7 Days', - value: currentTime - 604700000, + value: 604700000, result: true }, { condition: 'Past 14 Days', - value: currentTime - 1209500000, + value: 1209500000, result: true }, { condition: 'Past 30 Days', - value: currentTime - 2591900000, + value: 2591900000, result: true }, { @@ -238,6 +237,8 @@ describe('filters.getFilterByType', function () { testData.forEach(function(item){ it('Condition: ' + item.condition + ' - match value: ' + item.value, function () { + var currentTime = App.dateTime(); + item.value = currentTime - item.value; expect(filter(item.value, item.condition)).to.equal(item.result); }) }); http://git-wip-us.apache.org/repos/asf/ambari/blob/a55c8126/ambari-web/test/views/main/charts/heatmap/heatmap_host_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/views/main/charts/heatmap/heatmap_host_test.js b/ambari-web/test/views/main/charts/heatmap/heatmap_host_test.js index e8dbe99..0ce182a 100644 --- a/ambari-web/test/views/main/charts/heatmap/heatmap_host_test.js +++ b/ambari-web/test/views/main/charts/heatmap/heatmap_host_test.js @@ -18,9 +18,11 @@ var App = require('app'); +var date = require('utils/date/date'); +require('models/host'); require('views/main/charts/heatmap/heatmap_host'); -describe('App.MainChartsHeatmapHostView', function() { +describe('App.MainChartsHeatmapHostView', function () { var view = App.MainChartsHeatmapHostView.create({ templateName: '', @@ -117,4 +119,318 @@ describe('App.MainChartsHeatmapHostView', function() { }); }); + describe("#hostModelLink", function () { + + before(function () { + sinon.stub(App.Host, 'find').returns(Em.Object.create({id: 'host1'})); + }); + + after(function () { + App.Host.find.restore(); + }); + + it("should return hostname", function () { + view.set('content.hostName', 'host1'); + view.propertyDidChange('hostModelLink'); + expect(view.get('hostModelLink.id')).to.equal('host1'); + }); + }); + + describe("#mouseEnter()", function () { + + beforeEach(function () { + sinon.stub(view, 'getUsage').returns('usage'); + sinon.stub(view, 'getCpuUsage').returns('cpu_usage'); + sinon.stub(view, 'getHostComponents').returns(['c1']); + sinon.stub(view, 'setMetric'); + sinon.stub(view, 'openDetailsBlock'); + this.mock = sinon.stub(App.MainChartsHeatmapHostDetailView, 'create'); + view.set('details', {}); + }); + + afterEach(function () { + view.getUsage.restore(); + view.getCpuUsage.restore(); + view.getHostComponents.restore(); + view.setMetric.restore(); + view.openDetailsBlock.restore(); + this.mock.restore(); + }); + + it("set diskUsage", function () { + var childView = Em.Object.create({ + details: { + diskUsage: '' + } + }); + this.mock.returns(childView); + view.set('content', { + diskTotal: 100, + diskFree: 50 + }); + view.mouseEnter(); + expect(childView.get('details.diskUsage')).to.equal('usage'); + expect(view.getUsage.calledWith(100, 50)).to.be.true; + expect(view.setMetric.calledOnce).to.be.true; + expect(view.openDetailsBlock.calledOnce).to.be.true; + }); + + it("set cpuUsage", function () { + var childView = Em.Object.create({ + details: { + cpuUsage: '' + } + }); + this.mock.returns(childView); + view.set('content', { + cpuSystem: 100, + cpuUser: 50 + }); + view.mouseEnter(); + expect(childView.get('details.cpuUsage')).to.equal('cpu_usage'); + expect(view.getCpuUsage.calledWith(100, 50)).to.be.true; + expect(view.setMetric.calledOnce).to.be.true; + expect(view.openDetailsBlock.calledOnce).to.be.true; + }); + + it("set memoryUsage", function () { + var childView = Em.Object.create({ + details: { + memoryUsage: '' + } + }); + this.mock.returns(childView); + view.set('content', { + memTotal: 100, + memFree: 50 + }); + view.mouseEnter(); + expect(childView.get('details.memoryUsage')).to.equal('usage'); + expect(view.getUsage.calledWith(100, 50)).to.be.true; + expect(view.setMetric.calledOnce).to.be.true; + expect(view.openDetailsBlock.calledOnce).to.be.true; + }); + + it("set hostComponents", function () { + var childView = Em.Object.create({ + details: { + hostComponents: '' + } + }); + this.mock.returns(childView); + view.set('content', { + hostComponents: ['host1'] + }); + view.mouseEnter(); + expect(childView.get('details.hostComponents')).to.eql(['c1']); + expect(view.getHostComponents.calledWith(['host1'])).to.be.true; + expect(view.setMetric.calledOnce).to.be.true; + expect(view.openDetailsBlock.calledOnce).to.be.true; + }); + + it("set hostName", function () { + var childView = Em.Object.create({ + details: { + hostName: '' + } + }); + this.mock.returns(childView); + view.set('content', { + hostName: 'host1' + }); + view.mouseEnter(); + expect(childView.get('details.hostName')).to.equal('host1'); + expect(view.setMetric.calledOnce).to.be.true; + expect(view.openDetailsBlock.calledOnce).to.be.true; + }); + }); + + describe("#getUsage()", function () { + var testCases = [ + { + input: { + total: null, + free: null + }, + expected: '0.0' + }, + { + input: { + total: 100, + free: null + }, + expected: '0.0' + }, + { + input: { + total: null, + free: 50 + }, + expected: '0.0' + }, + { + input: { + total: 0, + free: 0 + }, + expected: '0.0' + }, + { + input: { + total: 100, + free: 50 + }, + expected: '50.0' + } + ]; + + testCases.forEach(function (test) { + it("total = " + test.input.total + "; free = " + test.input.free, function () { + expect(view.getUsage(test.input.total, test.input.free)).to.equal(test.expected); + }); + }); + }); + + describe("#getCpuUsage()", function () { + var testCases = [ + { + input: { + cpuSystem: null, + cpuUser: null + }, + expected: '0.0' + }, + { + input: { + cpuSystem: 1.0, + cpuUser: null + }, + expected: '0.0' + }, + { + input: { + cpuSystem: null, + cpuUser: 1.0 + }, + expected: '0.0' + }, + { + input: { + cpuSystem: 2.22, + cpuUser: 1.0 + }, + expected: '3.2' + } + ]; + + testCases.forEach(function (test) { + it("cpuSystem = " + test.input.cpuSystem + "; cpuUser = " + test.input.cpuUser, function () { + expect(view.getCpuUsage(test.input.cpuSystem, test.input.cpuUser)).to.equal(test.expected); + }); + }); + }); + + describe("#getHostComponents()", function () { + + beforeEach(function () { + sinon.stub(App.format, 'role', function (name) { + return name; + }); + sinon.stub(App, 'get').returns('non-client'); + }); + + afterEach(function () { + App.format.role.restore(); + App.get.restore(); + }); + + it("should return host-components", function () { + expect(view.getHostComponents(['is-client', 'non-client', 'non-client'])).to.equal('non-client, non-client'); + }); + }); + + describe("#setMetric()", function () { + var viewObject; + + beforeEach(function () { + sinon.stub(date, 'timingFormat').returns('time'); + viewObject = Em.Object.create({ + details: {} + }); + }); + + afterEach(function () { + date.timingFormat.restore(); + }); + + it("selected metric is null", function () { + view.set('controller.selectedMetric', null); + view.setMetric(viewObject, {}); + expect(viewObject.get('details')).to.be.empty; + }); + + it("metric name is null", function () { + view.set('controller.selectedMetric', Em.Object.create({ + name: null, + hostToValueMap: {} + })); + view.setMetric(viewObject, {}); + expect(viewObject.get('details')).to.be.empty; + }); + + it("host value is undefined", function () { + view.set('controller.selectedMetric', Em.Object.create({ + name: 'm1', + hostToValueMap: {} + })); + view.setMetric(viewObject, {hostName: 'host1'}); + expect(viewObject.get('details')).to.eql({ + metricName: 'm1', + metricValue: Em.I18n.t('charts.heatmap.unknown') + }); + }); + + it("metric name is 'Garbage Collection Time'", function () { + view.set('controller.selectedMetric', Em.Object.create({ + name: 'Garbage Collection Time', + hostToValueMap: { + host1: 'val' + } + })); + view.setMetric(viewObject, {hostName: 'host1'}); + expect(viewObject.get('details')).to.eql({ + metricName: 'Garbage Collection Time', + metricValue: 'time' + }); + }); + + it("metric value is NaN", function () { + view.set('controller.selectedMetric', Em.Object.create({ + name: 'm1', + hostToValueMap: { + host1: 'val' + } + })); + view.setMetric(viewObject, {hostName: 'host1'}); + expect(viewObject.get('details')).to.eql({ + metricName: 'm1', + metricValue: Em.I18n.t('charts.heatmap.unknown') + }); + }); + + it("metric value is number", function () { + view.set('controller.selectedMetric', Em.Object.create({ + name: 'm1', + hostToValueMap: { + host1: 10 + }, + units: 'mb' + })); + view.setMetric(viewObject, {hostName: 'host1'}); + expect(viewObject.get('details')).to.eql({ + metricName: 'm1', + metricValue: '10mb' + }); + }); + }); });
