You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by ab...@apache.org on 2016/06/30 07:25:39 UTC

ambari git commit: AMBARI-17474 Configs validation: UI does not show warning if a slider value is more than maximum. (ababiichuk)

Repository: ambari
Updated Branches:
  refs/heads/trunk c86672cb7 -> b618d22bd


AMBARI-17474 Configs validation: UI does not show warning if a slider value is more than maximum. (ababiichuk)


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

Branch: refs/heads/trunk
Commit: b618d22bd27ee24cad8855c5e8b6160307aa8ad9
Parents: c86672c
Author: ababiichuk <ab...@hortonworks.com>
Authored: Wed Jun 29 18:24:56 2016 +0300
Committer: ababiichuk <ab...@hortonworks.com>
Committed: Thu Jun 30 10:20:02 2016 +0300

----------------------------------------------------------------------
 ambari-web/app/mixins/common/serverValidator.js | 302 +++++++++----------
 .../config_recommendation_popup.hbs             |  78 ++---
 ambari-web/app/views.js                         |   2 +
 .../config_validation_failed_popup.js           |  46 +++
 .../config_validation_popup.js                  |  54 ++++
 .../test/mixins/common/serverValidator_test.js  | 254 +++++++++-------
 6 files changed, 412 insertions(+), 324 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/b618d22b/ambari-web/app/mixins/common/serverValidator.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins/common/serverValidator.js b/ambari-web/app/mixins/common/serverValidator.js
index e8774b0..428b0cd 100644
--- a/ambari-web/app/mixins/common/serverValidator.js
+++ b/ambari-web/app/mixins/common/serverValidator.js
@@ -31,26 +31,6 @@ App.ServerValidatorMixin = Em.Mixin.create({
   }.property('wizardController.name'),
 
   /**
-   * @type {boolean} set true if at least one config has error
-   */
-  configValidationError: false,
-
-  /**
-   * @type {boolean} set true if at least one config has warning
-   */
-  configValidationWarning: false,
-
-  /**
-   * @type {boolean} set true if at least one config has warning
-   */
-  configValidationFailed: false,
-
-  /**
-   * @type {object[]} contains additional message about validation errors
-   */
-  configValidationGlobalMessage: [],
-
-  /**
    * recommendation configs loaded from server
    * (used only during install)
    * @type {Object}
@@ -65,6 +45,24 @@ App.ServerValidatorMixin = Em.Mixin.create({
   clusterEnvConfigs: [],
 
   /**
+   * Collection of all config validation errors
+   *
+   * @type {Object[]}
+   */
+  configErrorList: [],
+
+  /**
+   * Map with allowed error types
+   *
+   * @type {Object}
+   */
+  errorTypes: {
+    ERROR: 'ERROR',
+    WARN: 'WARN',
+    GENERAL: 'GENERAL'
+  },
+
+  /**
    * by default loads data from model otherwise must be overridden as computed property
    * refer to \assets\data\stacks\HDP-2.1\recommendations_configs.json to learn structure
    * (shouldn't contain configurations filed)
@@ -103,25 +101,23 @@ App.ServerValidatorMixin = Em.Mixin.create({
   stepConfigs: null,
 
   serverSideValidation: function () {
-    var deferred = $.Deferred();
-    this.set('configValidationFailed', false);
-    this.set('configValidationGlobalMessage', []);
-    if (this.get('configValidationFailed')) {
-      this.warnUser(deferred);
-    } else {
-      this.runServerSideValidation(deferred);
-    }
-    return deferred;
-  },
+    var deferred = $.Deferred(),
+      self = this,
+      primary = function() { deferred.resolve(); },
+      secondary = function() { deferred.reject('invalid_configs'); };
+    this.set('configErrorList', []);
 
-  getAllHostsWithComponents: function() {
-    return App.ajax.send({
-      sender: this,
-      name: 'common.hosts.all',
-      data: {
-        urlParams: 'fields=HostRoles/component_name,HostRoles/host_name'
+    this.runServerSideValidation().done(function() {
+      if (self.get('configErrorList.length')) {
+        App.showConfigValidationPopup(self.get('configErrorList'), primary, secondary);
+      } else {
+        deferred.resolve();
       }
+    }).fail(function() {
+      App.showConfigValidationFailedPopup(primary, secondary);
     });
+
+    return deferred.promise();
   },
 
   /**
@@ -129,14 +125,15 @@ App.ServerValidatorMixin = Em.Mixin.create({
    * send request to validate configs
    * @returns {*}
    */
-  runServerSideValidation: function (deferred) {
+  runServerSideValidation: function () {
     var self = this;
     var recommendations = this.get('hostGroups');
     var stepConfigs = this.get('stepConfigs');
+    var dfd = $.Deferred();
 
-    return this.getBlueprintConfigurations().done(function(blueprintConfigurations){
+    this.getBlueprintConfigurations().done(function(blueprintConfigurations) {
       recommendations.blueprint.configurations = blueprintConfigurations;
-      return App.ajax.send({
+      App.ajax.send({
         name: 'config.validations',
         sender: self,
         data: {
@@ -148,10 +145,11 @@ App.ServerValidatorMixin = Em.Mixin.create({
         },
         success: 'validationSuccess',
         error: 'validationError'
-      }).complete(function () {
-        self.warnUser(deferred);
+      }).complete(function() {
+        dfd.resolve();
       });
     });
+    return dfd.promise();
   },
 
   /**
@@ -206,144 +204,116 @@ App.ServerValidatorMixin = Em.Mixin.create({
   },
 
   /**
-   * @method validationSuccess
-   * success callback after getting response from server
-   * go through the step configs and set warn and error messages
+   * Creates config validation error object
+   *
+   * @param type - error type, see <code>errorTypes<code>
+   * @param property - config property object
+   * @param messages - array of messages
+   * @returns {{type: String, isError: boolean, isWarn: boolean, isGeneral: boolean, messages: Array}}
+   */
+  createErrorMessage: function (type, property, messages) {
+    var errorTypes = this.get('errorTypes');
+    var error = {
+      type: type,
+      isError: type === errorTypes.ERROR,
+      isWarn: type === errorTypes.WARN,
+      isGeneral: type === errorTypes.GENERAL,
+      messages: Em.makeArray(messages)
+    };
+
+    Em.assert('Unknown config error type ' + type, error.isError || error.isWarn || error.isGeneral);
+    if (property) {
+      error.serviceName = App.StackService.find(Em.get(property, 'serviceName')).get('displayName');
+      error.propertyName = Em.get(property, 'name');
+      error.filename = Em.get(property, 'filename');
+      error.value = Em.get(property, 'value');
+      error.description = Em.get(property, 'description');
+    }
+    return error;
+  },
+
+
+  /**
+   * Parse data from server to
+   *  <code>configErrorsMap<code> and
+   *  <code>generalErrors<code>
+   *
    * @param data
+   * @returns {{configErrorsMap: {}, generalErrors: Array}}
    */
-  validationSuccess: function(data) {
-    var self = this;
-    var checkedProperties = [];
-    var globalWarning = [];
-    self.set('configValidationError', false);
-    self.set('configValidationWarning', false);
+  parseValidation: function(data) {
+    var configErrorsMap = {},  generalErrors = [];
+
     data.resources.forEach(function(r) {
       r.items.forEach(function(item){
         if (item.type == "configuration") {
-          self.get('stepConfigs').forEach(function(service) {
-            service.get('configs').forEach(function(property) {
-              if ((property.get('filename') == item['config-type'] + '.xml') && (property.get('name') == item['config-name'])) {
-                if (item.level == "ERROR") {
-                  self.set('configValidationError', true);
-                  property.set('validationErrors', property.get('validationErrors').concat(item.message).slice());
-                } else if (item.level == "WARN") {
-                  self.set('configValidationWarning', true);
-                  property.set('validationWarnings', property.get('validationWarnings').concat(item.message).slice());
-                }
-                // store property data to detect WARN or ERROR messages for missed property
-                if (["ERROR", "WARN"].contains(item.level)) checkedProperties.push(item['config-type'] + '/' + item['config-name']);
-              }
-            });
-          });
-          // check if error or warn message detected for property that absent in step configs
-          if (["ERROR", "WARN"].contains(item.level) && !checkedProperties.contains(item['config-type'] + '/' + item['config-name'])) {
-            var message = {
-              propertyName: item['config-name'],
-              filename: item['config-type'],
-              validationWarnings: [item.message]
-            };
-            if (item['config-type'] === "" && item['config-name'] === "") {
-              //service-independent validation
-              message.isGeneral = true;
+          var configId = (item['config-name'] && item['config-type']) && App.config.configId(item['config-name'], item['config-type']);
+          if (configId) {
+            if (configErrorsMap[configId]) {
+              configErrorsMap[configId].messages.push(item.message);
             } else {
-              message.serviceName = App.StackService.find().filter(function(service) {
-                return !!service.get('configTypes')[item['config-type']];
-              })[0].get('displayName');
+              configErrorsMap[configId] = {
+                type: item.level,
+                messages: [item.message]
+              }
             }
-            self.set(item.level == 'WARN' ? 'configValidationWarning' : 'configValidationError', true);
-            globalWarning.push(message);
+          } else {
+            generalErrors.push({
+              type: this.get('errorTypes').GENERAL,
+              messages: [item.message]
+            });
           }
         }
-      });
-    });
-    self.set('configValidationGlobalMessage', globalWarning);
-  },
+      }, this);
+    }, this);
 
-  validationError: function (jqXHR, ajaxOptions, error, opt) {
-    this.set('configValidationFailed', true);
+    return {
+      configErrorsMap: configErrorsMap,
+      generalErrors: generalErrors
+    }
   },
 
+  /**
+   * Generates list of all config errors that should be displayed in popup
+   *
+   * @param configErrorsMap
+   * @param generalErrors
+   * @returns {Array}
+   */
+  collectAllIssues: function(configErrorsMap, generalErrors)  {
+    var errorTypes = this.get('errorTypes');
+    var configErrorList = [];
+
+    this.get('stepConfigs').forEach(function(service) {
+      service.get('configs').forEach(function(property) {
+        if (property.get('isVisible') && !property.get('hiddenBySection')) {
+          var serverIssue = configErrorsMap[property.get('id')];
+          if (serverIssue) {
+            configErrorList.push(this.createErrorMessage(serverIssue.type, property, serverIssue.messages));
+          } else if (property.get('warnMessage')) {
+            configErrorList.push(this.createErrorMessage(errorTypes.WARN, property, [property.get('warnMessage')]));
+          }
+        }
+      }, this);
+    }, this);
+
+    generalErrors.forEach(function(serverIssue) {
+      configErrorList.push(this.createErrorMessage(errorTypes.GENERAL, null, serverIssue.messages));
+    }, this);
+
+    return configErrorList;
+  },
 
   /**
-   * warn user if some errors or warning were
-   * in setting up configs otherwise go to the nex operation
-   * @param deferred
-   * @returns {*}
+   * @method validationSuccess
+   * success callback after getting response from server
+   * go through the step configs and set warn and error messages
+   * @param data
    */
-  warnUser: function(deferred) {
-    var self = this;
-    if (this.get('configValidationFailed')) {
-      return App.ModalPopup.show({
-        header: Em.I18n.t('installer.step7.popup.validation.failed.header'),
-        primary: Em.I18n.t('common.proceedAnyway'),
-        primaryClass: 'btn-danger',
-        marginBottom: 200,
-        onPrimary: function () {
-          this.hide();
-          deferred.resolve();
-        },
-        onSecondary: function () {
-          this.hide();
-          deferred.reject("invalid_configs"); // message used to differentiate types of rejections.
-        },
-        onClose: function () {
-          this.hide();
-          deferred.reject("invalid_configs"); // message used to differentiate types of rejections.
-        },
-        body: Em.I18n.t('installer.step7.popup.validation.request.failed.body')
-      });
-    } else if (this.get('configValidationWarning') || this.get('configValidationError')) {
-      // Motivation: for server-side validation warnings allow user to continue wizard
-      var stepConfigs = self.get('name') === 'mainServiceInfoConfigsController'
-        ? [self.get('selectedService')]
-        : self.get('stepConfigs');
-      var configsWithErrors = stepConfigs.some(function (step) {
-        return step.get('configs').some(function(c) {
-          return c.get('isVisible') && !c.get('hiddenBySection') && (c.get('hasValidationWarnings') || c.get('hasValidationErrors'));
-        });
-      });
-      if (configsWithErrors) {
-        return App.ModalPopup.show({
-          header: Em.I18n.t('installer.step7.popup.validation.warning.header'),
-          classNames: ['sixty-percent-width-modal','modal-full-width'],
-          primary: Em.I18n.t('common.proceedAnyway'),
-          primaryClass: 'btn-danger',
-          marginBottom: 200,
-          onPrimary: function () {
-            this.hide();
-            deferred.resolve();
-          },
-          onSecondary: function () {
-            this.hide();
-            deferred.reject("invalid_configs"); // message used to differentiate types of rejections.
-          },
-          onClose: function () {
-            this.hide();
-            deferred.reject("invalid_configs"); // message used to differentiate types of rejections.
-          },
-          hide: function() {
-            stepConfigs.forEach(function(serviceConfig) {
-              serviceConfig.get('configs').invoke('setProperties', {
-                validationErrors: [].slice(),
-                validationWarnings: [].slice()
-              });
-            });
-            this._super();
-          },
-          bodyClass: Em.View.extend({
-            controller: self,
-            templateName: require('templates/common/modal_popups/config_recommendation_popup'),
-            serviceConfigs: stepConfigs,
-            messageBody: Em.I18n.t(self.get('configValidationError')
-                                 ? 'installer.step7.popup.validation.error.body'
-                                 : 'installer.step7.popup.validation.warning.body')
-          })
-        });
-      } else {
-        deferred.resolve();
-      }
-    } else {
-      deferred.resolve();
-    }
-  }
+  validationSuccess: function(data) {
+    var parsed = this.parseValidation(data);
+    this.set('configErrorList', this.collectAllIssues(parsed.configErrorsMap, parsed.generalErrors));
+  },
+
+  validationError: Em.K
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/b618d22b/ambari-web/app/templates/common/modal_popups/config_recommendation_popup.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/common/modal_popups/config_recommendation_popup.hbs b/ambari-web/app/templates/common/modal_popups/config_recommendation_popup.hbs
index bb629ff..8100dff 100644
--- a/ambari-web/app/templates/common/modal_popups/config_recommendation_popup.hbs
+++ b/ambari-web/app/templates/common/modal_popups/config_recommendation_popup.hbs
@@ -29,63 +29,33 @@
     </tr>
     </thead>
     <tbody>
-      {{#each service in view.serviceConfigs}}
-        {{#each property in service.configs}}
-          {{#if property.isVisible}}
-            {{#unless property.hiddenBySection}}
-              {{#if property.hasValidationErrors}}
-                {{#each error in property.validationErrors}}
-                  <tr class="error">
-                    <td>{{t common.error}}</td>
-                    <td>{{property.serviceName}}</td>
-                    <td>{{property.name}}</td>
-                    <td>{{property.value}}</td>
-                    <td>
-                      <div class="property-message">{{error}}</div>
-                      <div class="property-description">{{property.description}}</div>
-                    </td>
-                  </tr>
-                {{/each}}
-              {{/if}}
-            {{/unless}}
+    {{#each error in view.configErrors}}
+      <tr {{bindAttr class="error.isError:error:warning"}}>
+        <td>
+          {{#if error.isError}}
+            {{t common.error}}
+          {{else}}
+            {{t common.warning}}
           {{/if}}
-        {{/each}}
-      {{/each}}
-      {{#each service in view.serviceConfigs}}
-        {{#each property in service.configs}}
-          {{#if property.isVisible}}
-            {{#unless property.hiddenBySection}}
-              {{#if property.hasValidationWarnings}}
-                {{#each warning in property.validationWarnings}}
-                  <tr class="warning">
-                    <td>{{t common.warning}}</td>
-                    <td>{{property.serviceName}}</td>
-                    <td>{{property.name}}</td>
-                    <td>{{property.value}}</td>
-                    <td>
-                      <div class="property-message">{{warning}}</div>
-                      <div class="property-description">{{property.description}}</div>
-                    </td>
-                  </tr>
-                {{/each}}
-              {{/if}}
-            {{/unless}}
-          {{/if}}
-        {{/each}}
-      {{/each}}
-      {{#each message in configValidationGlobalMessage}}
-        {{#if message.isGeneral}}
-          <tr>
-            <td colspan="4">{{message.warnMessage}}</td>
-          </tr>
+        </td>
+
+        {{#if error.isGeneral}}
+          {{#each message in error.messages}}
+            <td colspan="4">{{error.message}}</td>
+          {{/each}}
         {{else}}
-          <tr>
-            <td>{{message.serviceName}}</td>
-            <td>{{message.propertyName}}</td>
-            <td colspan="2">{{message.warnMessage}} {{t in}} {{message.filename}}</td>
-          </tr>
+          <td>{{error.serviceName}}</td>
+          <td>{{error.propertyName}}</td>
+          <td>{{error.value}}</td>
+          <td>
+            {{#each message in error.messages}}
+              <div class="property-message">{{message}}</div>
+            {{/each}}
+            <div class="property-description">{{error.description}}</div>
+          </td>
         {{/if}}
-      {{/each}}
+      </tr>
+    {{/each}}
     </tbody>
   </table>
 </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b618d22b/ambari-web/app/views.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views.js b/ambari-web/app/views.js
index 7127420..ab79b98 100644
--- a/ambari-web/app/views.js
+++ b/ambari-web/app/views.js
@@ -42,6 +42,8 @@ require('views/common/modal_popups/select_groups_popup');
 require('views/common/modal_popups/logs_popup');
 require('views/common/modal_popups/log_file_search_popup');
 require('views/common/modal_popups/log_tail_popup');
+require('views/common/modal_popups/config_validation/config_validation_failed_popup');
+require('views/common/modal_popups/config_validation/config_validation_popup');
 require('views/common/editable_list');
 require('views/common/host_progress_popup_body_view');
 require('views/common/rolling_restart_view');

http://git-wip-us.apache.org/repos/asf/ambari/blob/b618d22b/ambari-web/app/views/common/modal_popups/config_validation/config_validation_failed_popup.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/modal_popups/config_validation/config_validation_failed_popup.js b/ambari-web/app/views/common/modal_popups/config_validation/config_validation_failed_popup.js
new file mode 100644
index 0000000..20639b4
--- /dev/null
+++ b/ambari-web/app/views/common/modal_popups/config_validation/config_validation_failed_popup.js
@@ -0,0 +1,46 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var App = require('app');
+
+/**
+ * Show alert popup
+ *
+ * @return {*}
+ */
+App.showConfigValidationFailedPopup = function (primary, secondary) {
+  return App.ModalPopup.show({
+    header: Em.I18n.t('installer.step7.popup.validation.failed.header'),
+    primary: Em.I18n.t('common.proceedAnyway'),
+    primaryClass: 'btn-danger',
+    marginBottom: 200,
+    onPrimary: function () {
+      this._super();
+      primary();
+    },
+    onSecondary: function () {
+      this._super();
+      secondary();
+    },
+    onClose: function () {
+      this._super();
+      secondary();
+    },
+    body: Em.I18n.t('installer.step7.popup.validation.request.failed.body')
+  });
+};

http://git-wip-us.apache.org/repos/asf/ambari/blob/b618d22b/ambari-web/app/views/common/modal_popups/config_validation/config_validation_popup.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/modal_popups/config_validation/config_validation_popup.js b/ambari-web/app/views/common/modal_popups/config_validation/config_validation_popup.js
new file mode 100644
index 0000000..98e1ce5
--- /dev/null
+++ b/ambari-web/app/views/common/modal_popups/config_validation/config_validation_popup.js
@@ -0,0 +1,54 @@
+/**
+ * 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');
+
+/**
+ * Show alert popup
+ *
+ * @return {*}
+ */
+App.showConfigValidationPopup = function (configErrors, primary, secondary) {
+  return App.ModalPopup.show({
+    header: Em.I18n.t('installer.step7.popup.validation.warning.header'),
+    classNames: ['sixty-percent-width-modal','modal-full-width'],
+    primary: Em.I18n.t('common.proceedAnyway'),
+    primaryClass: 'btn-danger',
+    marginBottom: 200,
+    onPrimary: function () {
+      this._super();
+      primary();
+    },
+    onSecondary: function () {
+      this._super();
+      secondary();
+    },
+    onClose: function () {
+      this._super();
+      secondary();
+    },
+    bodyClass: Em.View.extend({
+      templateName: require('templates/common/modal_popups/config_recommendation_popup'),
+      configErrors: configErrors,
+      configValidationError: Em.computed.someBy('configErrors', 'isError', true),
+      messageBody: Em.I18n.t(this.get('configValidationError')
+        ? 'installer.step7.popup.validation.error.body'
+        : 'installer.step7.popup.validation.warning.body')
+    })
+  });
+};

http://git-wip-us.apache.org/repos/asf/ambari/blob/b618d22b/ambari-web/test/mixins/common/serverValidator_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/mixins/common/serverValidator_test.js b/ambari-web/test/mixins/common/serverValidator_test.js
index 39e71a0..4a22e28 100644
--- a/ambari-web/test/mixins/common/serverValidator_test.js
+++ b/ambari-web/test/mixins/common/serverValidator_test.js
@@ -18,123 +18,169 @@
 
 var App = require('app');
 
-describe('App.ServerValidatorMixin', function() {
+describe('App.ServerValidatorMixin', function () {
   var mixinObject = Em.Object.extend(App.ServerValidatorMixin, {});
-  describe('#validationSuccess', function() {
-    var instanceObject;
-    var genRespItem = function(name, filename, level, message) {
-      return {
-        type: 'configuration',
-        'config-name': name,
-        'config-type': filename,
-        level: level,
-        message: message
-      };
-    };
-    var genResponse = function(items) {
-      return {
-        items: items.map(function(item) { return genRespItem.apply(undefined, item); })
-      };
+  var instanceObject;
+  beforeEach(function () {
+    instanceObject = mixinObject.create();
+  });
+  describe('#collectAllIssues', function () {
+    var result = [];
+    var stepConfigs = [
+      Em.Object.create({
+        serviceName: 'service1',
+        configs: [
+          Em.Object.create({
+            id: 'c1_f1',
+            name: 'c1',
+            filename: 'f1',
+            isVisible: true,
+            hiddenBySection: false
+          }),
+          Em.Object.create({
+            id: 'c2_f2',
+            name: 'c2',
+            filename: 'f2',
+            isVisible: true,
+            hiddenBySection: false
+          }),
+          Em.Object.create({
+            id: 'c3_f3',
+            name: 'c3',
+            filename: 'f3',
+            isVisible: true,
+            hiddenBySection: false,
+            warnMessage: 'warn3'
+          }),
+          Em.Object.create({
+            id: 'c4_f4',
+            name: 'c4',
+            filename: 'f4',
+            isVisible: false,
+            hiddenBySection: false
+          })
+        ]
+      })
+    ];
+
+    var response = {
+      configErrorsMap: {
+        'c1_f1': {
+          type: 'WARN',
+          messages: ['warn1']
+        },
+        'c2_f2': {
+          type: 'ERROR',
+          messages: ['error2']
+        },
+        'c4_f4': {
+          type: 'ERROR',
+          messages: ['error4']
+        }
+      },
+      generalErrors: [{
+        type: 'GENERAL',
+        messages: ['general issue']
+      }]
     };
-    var genConfigs = function(configs) {
-      return Em.Object.create({
-        configs: configs.map(function(item) {
-          return Em.Object.create({ name: item[0], filename: item[1], validationErrors: [], validationWarnings: []});
-        })
-      });
+
+    beforeEach(function () {
+      instanceObject.set('stepConfigs', stepConfigs);
+      result = instanceObject.collectAllIssues(response.configErrorsMap, response.generalErrors);
+    });
+
+    it('should add server warnings', function () {
+      var error = result.find(function(r) { return r.propertyName === 'c1' && r.filename === 'f1'; });
+      expect(error.type).to.equal('WARN');
+      expect(error.messages).to.eql(['warn1']);
+    });
+
+    it('should add server errors', function () {
+      var error = result.find(function(r) { return r.propertyName === 'c2' && r.filename === 'f2'; });
+      expect(error.type).to.equal('ERROR');
+      expect(error.messages).to.eql(['error2']);
+    });
+
+    it('should add ui warning', function () {
+      var error = result.find(function(r) { return r.propertyName === 'c3' && r.filename === 'f3'; });
+      expect(error.type).to.equal('WARN');
+      expect(error.messages).to.eql(['warn3']);
+    });
+
+    it('should add general issues', function () {
+      var error = result.findProperty('type', 'GENERAL');
+      expect(error.messages).to.eql(['general issue']);
+    });
+
+    it('should ignore issues for hidden configs', function () {
+      var error = result.find(function(r) { return r.propertyName === 'c4' && r.filename === 'f4'; });
+      expect(error).to.be.undefined;
+    });
+  });
+
+  describe('#createErrorMessage', function() {
+    var property = {
+      name: 'p1',
+      filename: 'f1',
+      value: 'v1',
+      description: 'd1'
     };
-    var tests = [
-      {
-        stepConfigs: Em.A([
-          genConfigs([
-            ['prop1', 'some-site.xml']
-          ])
-        ]),
-        resources: [
-          genResponse([
-            ['prop1', 'some-site', 'WARN', 'Some warn'],
-            ['prop2', 'some-site', 'ERROR', 'Value should be set']
-          ])
-        ],
-        expected: [
-          { prop: 'configValidationError', value: true },
-          { prop: 'configValidationWarning', value: true },
-          { prop: 'configValidationGlobalMessage.length', value: 1 },
-          { prop: 'configValidationGlobalMessage[0].serviceName', value: 'Some Service' },
-          { prop: 'configValidationGlobalMessage[0].propertyName', value: 'prop2' }
-        ],
-        message: 'validation failed on absent property from step configs. global message should be showed.'
-      },
-      {
-        stepConfigs: Em.A([
-          genConfigs([
-            ['prop1', 'some-site.xml'],
-            ['prop2', 'some-site.xml']
-          ])
-        ]),
-        resources: [
-          genResponse([
-            ['prop1', 'some-site', 'WARN', 'Some warn']
-          ])
-        ],
-        expected: [
-          { prop: 'configValidationError', value: false },
-          { prop: 'configValidationWarning', value: true },
-          { prop: 'configValidationGlobalMessage.length', value: 0}
-        ],
-        message: 'all properties present in step configs. validation failed. Present WARN and ERROR level messages.'
-      },
-            {
-        stepConfigs: Em.A([
-          genConfigs([
-            ['prop1', 'some-site.xml'],
-            ['prop2', 'some-site.xml']
-          ])
-        ]),
-        resources: [
-          {
-            items: []
-          }
-        ],
-        expected: [
-          { prop: 'configValidationFailed', value: false },
-          { prop: 'configValidationError', value: false },
-          { prop: 'configValidationWarning', value: false },
-          { prop: 'configValidationGlobalMessage.length', value: 0}
-        ],
-        message: 'validation success. no errors flags should be set.'
-      }
-    ];
-    
     beforeEach(function() {
-      instanceObject = mixinObject.create({});
-      sinon.stub(App.StackService, 'find').returns([
-        Em.Object.create({
-          displayName: 'Some Service',
-          configTypes: { 'some-site': {} }
-        })
-      ]);
+      sinon.stub(App.StackService, 'find', function() {
+        return Em.Object.create({
+          displayName: 'sName'
+        });
+      });
     });
 
     afterEach(function() {
       App.StackService.find.restore();
     });
-    
-    tests.forEach(function(test) {
-      describe(test.message, function() {
 
-        beforeEach(function () {
-          instanceObject.set('stepConfigs', test.stepConfigs);
-          instanceObject.validationSuccess({resources: test.resources});
-        });
+    it('creates warn object', function() {
+      expect(instanceObject.createErrorMessage('WARN', property, ['msg1'])).to.eql({
+        type: 'WARN',
+        isError: false,
+        isWarn: true,
+        isGeneral: false,
+        messages: ['msg1'],
+        propertyName: 'p1',
+        filename: 'f1',
+        value: 'v1',
+        description: 'd1',
+        serviceName: 'sName'
+      });
+    });
 
-        test.expected.forEach(function(e) {
-          it(e.prop + ': ' + e.value, function () {
-            expect(instanceObject).to.have.deep.property(e.prop, e.value);
-          });
-        });
+    it('creates error object', function() {
+      expect(instanceObject.createErrorMessage('ERROR', property, ['msg2'])).to.eql({
+        type: 'ERROR',
+        isError: true,
+        isWarn: false,
+        isGeneral: false,
+        messages: ['msg2'],
+        propertyName: 'p1',
+        filename: 'f1',
+        value: 'v1',
+        description: 'd1',
+        serviceName: 'sName'
+      });
+    });
+
+    it('creates general issue object', function() {
+      expect(instanceObject.createErrorMessage('GENERAL', null, ['msg3'])).to.eql({
+        type: 'GENERAL',
+        isError: false,
+        isWarn: false,
+        isGeneral: true,
+        messages: ['msg3']
       });
     });
+
+    it('creates general issue object', function() {
+      expect(instanceObject.createErrorMessage.bind(instanceObject, 'WRONG TYPE', null, ['msg3']))
+        .to.throw(Error, 'Unknown config error type WRONG TYPE');
+    });
   });
 });