Преглед изворни кода

AMBARI-3501. Wizard Step 9 Unit tests. (onechiporenko)

Oleg Nechiporenko пре 11 година
родитељ
комит
b3ca22261e

+ 2 - 0
ambari-web/app/assets/test/tests.js

@@ -49,6 +49,7 @@ require('test/installer/step4_test');
 require('test/installer/step5_test');
 require('test/installer/step5_test');
 require('test/installer/step6_test');
 require('test/installer/step6_test');
 require('test/installer/step7_test');
 require('test/installer/step7_test');
+require('test/installer/step9_test');
 require('test/installer/step10_test');
 require('test/installer/step10_test');
 require('test/login_test');
 require('test/login_test');
 require('test/mappers/server_data_mapper_test');
 require('test/mappers/server_data_mapper_test');
@@ -90,5 +91,6 @@ require('test/views/main/dashboard/widgets/links_widget_test');
 require('test/views/main/dashboard/widgets/pie_chart_widget_test');
 require('test/views/main/dashboard/widgets/pie_chart_widget_test');
 require('test/views/main/dashboard/widgets/namenode_cpu_test');
 require('test/views/main/dashboard/widgets/namenode_cpu_test');
 require('test/views/common/configs/services_config_test');
 require('test/views/common/configs/services_config_test');
+require('test/views/wizard/step9_view_test');
 require('test/models/host_test');
 require('test/models/host_test');
 require('test/models/rack_test');
 require('test/models/rack_test');

+ 117 - 100
ambari-web/app/controllers/wizard/step9_controller.js

@@ -26,7 +26,6 @@ App.WizardStep9Controller = Em.Controller.extend({
   isStepCompleted: false,
   isStepCompleted: false,
 
 
   isSubmitDisabled: function () {
   isSubmitDisabled: function () {
-    // return !this.get('isStepCompleted');
     var validStates = ['STARTED','START FAILED'];
     var validStates = ['STARTED','START FAILED'];
     if (this.get('content.controllerName') == 'addHostController') {
     if (this.get('content.controllerName') == 'addHostController') {
       validStates.push('INSTALL FAILED');
       validStates.push('INSTALL FAILED');
@@ -46,12 +45,14 @@ App.WizardStep9Controller = Em.Controller.extend({
   mockDataPrefix: '/data/wizard/deploy/5_hosts',
   mockDataPrefix: '/data/wizard/deploy/5_hosts',
   pollDataCounter: 0,
   pollDataCounter: 0,
   polledData: [],
   polledData: [],
+  numPolls: 1,
+  POLL_INTERVAL: 4000,
 
 
   status: function () {
   status: function () {
-    if (this.hosts.someProperty('status', 'failed')) {
+    if (this.get('hosts').someProperty('status', 'failed')) {
       return 'failed';
       return 'failed';
     }
     }
-    if (this.hosts.someProperty('status', 'warning')) {
+    if (this.get('hosts').someProperty('status', 'warning')) {
       if (this.isStepFailed()) {
       if (this.isStepFailed()) {
         return 'failed';
         return 'failed';
       } else {
       } else {
@@ -65,6 +66,10 @@ App.WizardStep9Controller = Em.Controller.extend({
     return 'info';
     return 'info';
   }.property('hosts.@each.status', 'progress'),
   }.property('hosts.@each.status', 'progress'),
 
 
+  showRetry: function () {
+    return this.get('content.cluster.status') == 'INSTALL FAILED';
+  }.property('content.cluster.status'),
+
   categoryObject: Em.Object.extend({
   categoryObject: Em.Object.extend({
     hostsCount: function () {
     hostsCount: function () {
       var category = this;
       var category = this;
@@ -80,12 +85,6 @@ App.WizardStep9Controller = Em.Controller.extend({
       return "%@ (%@)".fmt(this.get('value'), this.get('hostsCount'));
       return "%@ (%@)".fmt(this.get('value'), this.get('hostsCount'));
     }.property('value', 'hostsCount')
     }.property('value', 'hostsCount')
   }),
   }),
-  getCategory: function(field, value){
-    return this.get('categories').find(function(item){
-      return item.get(field) == value;
-    });
-  },
-
   categories: function () {
   categories: function () {
     var self = this;
     var self = this;
     self.categoryObject.reopen({
     self.categoryObject.reopen({
@@ -111,7 +110,6 @@ App.WizardStep9Controller = Em.Controller.extend({
     this.set('category', categories.get('firstObject'));
     this.set('category', categories.get('firstObject'));
     return categories;
     return categories;
   }.property(),
   }.property(),
-
   category: false,
   category: false,
   visibleHosts: function(){
   visibleHosts: function(){
     var targetStatus = this.get('category.hostStatus');
     var targetStatus = this.get('category.hostStatus');
@@ -127,13 +125,17 @@ App.WizardStep9Controller = Em.Controller.extend({
     return visibleHosts;
     return visibleHosts;
   }.property('category', 'hosts.@each.status'),
   }.property('category', 'hosts.@each.status'),
 
 
+  logTasksChangesCounter: 0,
+
   selectCategory: function(event){
   selectCategory: function(event){
     this.set('category', event.context);
     this.set('category', event.context);
   },
   },
 
 
-  showRetry: function () {
-    return this.get('content.cluster.status') == 'INSTALL FAILED';
-  }.property('content.cluster.status'),
+  getCategory: function(field, value){
+    return this.get('categories').find(function(item){
+      return item.get(field) == value;
+    });
+  },
 
 
   // content.cluster.status can be:
   // content.cluster.status can be:
   // PENDING: set upon successful transition from step 1 to step 2
   // PENDING: set upon successful transition from step 1 to step 2
@@ -186,11 +188,11 @@ App.WizardStep9Controller = Em.Controller.extend({
     }
     }
   },
   },
   clearStep: function () {
   clearStep: function () {
-    this.hosts.clear();
+    this.get('hosts').clear();
     this.set('status', 'info');
     this.set('status', 'info');
     this.set('progress', '0');
     this.set('progress', '0');
     this.set('isStepCompleted', false);
     this.set('isStepCompleted', false);
-    this.numPolls = 1;
+    this.set('numPolls', 1);
   },
   },
 
 
   loadStep: function () {
   loadStep: function () {
@@ -238,7 +240,7 @@ App.WizardStep9Controller = Em.Controller.extend({
         progress: _hostInfo.progress
         progress: _hostInfo.progress
       });
       });
       console.log('pushing ' + hostInfo.name);
       console.log('pushing ' + hostInfo.name);
-      this.hosts.pushObject(hostInfo);
+      this.get('hosts').pushObject(hostInfo);
     }, this);
     }, this);
   },
   },
 
 
@@ -330,6 +332,7 @@ App.WizardStep9Controller = Em.Controller.extend({
             return role + Em.I18n.t('installer.step9.serviceStatus.abort.failed');
             return role + Em.I18n.t('installer.step9.serviceStatus.abort.failed');
         }
         }
     }
     }
+    return '';
   },
   },
 
 
   /**
   /**
@@ -364,7 +367,7 @@ App.WizardStep9Controller = Em.Controller.extend({
     }
     }
     data = JSON.stringify(data);
     data = JSON.stringify(data);
     if (App.testMode) {
     if (App.testMode) {
-      this.numPolls = 6;
+      this.set('numPolls', 6);
     }
     }
 
 
     App.ajax.send({
     App.ajax.send({
@@ -380,12 +383,13 @@ App.WizardStep9Controller = Em.Controller.extend({
   },
   },
 
 
   launchStartServicesSuccessCallback: function (jsonData) {
   launchStartServicesSuccessCallback: function (jsonData) {
+    var clusterStatus = {};
     if (jsonData) {
     if (jsonData) {
       console.log("TRACE: Step9 -> In success function for the startService call");
       console.log("TRACE: Step9 -> In success function for the startService call");
       console.log("TRACE: Step9 -> value of the received data is: " + jsonData);
       console.log("TRACE: Step9 -> value of the received data is: " + jsonData);
       var requestId = jsonData.Requests.id;
       var requestId = jsonData.Requests.id;
       console.log('requestId is: ' + requestId);
       console.log('requestId is: ' + requestId);
-      var clusterStatus = {
+      clusterStatus = {
         status: 'INSTALLED',
         status: 'INSTALLED',
         requestId: requestId,
         requestId: requestId,
         isStartError: false,
         isStartError: false,
@@ -396,7 +400,7 @@ App.WizardStep9Controller = Em.Controller.extend({
     } else {
     } else {
       console.log('ERROR: Error occurred in parsing JSON data');
       console.log('ERROR: Error occurred in parsing JSON data');
       this.hostHasClientsOnly(true);
       this.hostHasClientsOnly(true);
-      var clusterStatus = {
+      clusterStatus = {
         status: 'STARTED',
         status: 'STARTED',
         isStartError: false,
         isStartError: false,
         isCompleted: true
         isCompleted: true
@@ -418,12 +422,14 @@ App.WizardStep9Controller = Em.Controller.extend({
   },
   },
 
 
   hostHasClientsOnly: function(jsonError) {
   hostHasClientsOnly: function(jsonError) {
-    this.hosts.forEach(function(host){
+    this.get('hosts').forEach(function(host){
       var OnlyClients = true;
       var OnlyClients = true;
       var tasks = host.get('logTasks');
       var tasks = host.get('logTasks');
       tasks.forEach(function(task){
       tasks.forEach(function(task){
         var component = serviceComponents.findProperty('component_name',task.Tasks.role);
         var component = serviceComponents.findProperty('component_name',task.Tasks.role);
-        (component && component.isClient) ? null : OnlyClients = false;
+        if(!(component && component.isClient)) {
+          OnlyClients = false;
+        }
       });
       });
       if (OnlyClients || jsonError) {
       if (OnlyClients || jsonError) {
         host.set('status', 'success');
         host.set('status', 'success');
@@ -444,6 +450,7 @@ App.WizardStep9Controller = Em.Controller.extend({
 
 
   // marks a host's status as "success" if all tasks are in COMPLETED state
   // marks a host's status as "success" if all tasks are in COMPLETED state
   onSuccessPerHost: function (actions, contentHost) {
   onSuccessPerHost: function (actions, contentHost) {
+    if (!actions) return;
     if (actions.everyProperty('Tasks.status', 'COMPLETED') && this.get('content.cluster.status') === 'INSTALLED') {
     if (actions.everyProperty('Tasks.status', 'COMPLETED') && this.get('content.cluster.status') === 'INSTALLED') {
       contentHost.set('status', 'success');
       contentHost.set('status', 'success');
     }
     }
@@ -453,6 +460,7 @@ App.WizardStep9Controller = Em.Controller.extend({
   // note that if the master failed to install because of ABORTED or TIMEDOUT, we don't mark it as failed, because this would mark all hosts as "failed" and makes it difficult for the user
   // note that if the master failed to install because of ABORTED or TIMEDOUT, we don't mark it as failed, because this would mark all hosts as "failed" and makes it difficult for the user
   // to find which host FAILED occurred on, if any
   // to find which host FAILED occurred on, if any
   onErrorPerHost: function (actions, contentHost) {
   onErrorPerHost: function (actions, contentHost) {
+    if (!actions) return;
     if (actions.someProperty('Tasks.status', 'FAILED') || actions.someProperty('Tasks.status', 'ABORTED') || actions.someProperty('Tasks.status', 'TIMEDOUT')) {
     if (actions.someProperty('Tasks.status', 'FAILED') || actions.someProperty('Tasks.status', 'ABORTED') || actions.someProperty('Tasks.status', 'TIMEDOUT')) {
       contentHost.set('status', 'warning');
       contentHost.set('status', 'warning');
     }
     }
@@ -473,13 +481,14 @@ App.WizardStep9Controller = Em.Controller.extend({
     return result;
     return result;
   },
   },
 
 
-  onInProgressPerHost: function (tasks, contentHost) {
-    var runningAction = tasks.findProperty('Tasks.status', 'IN_PROGRESS');
+  onInProgressPerHost: function (actions, contentHost) {
+    if (!actions) return;
+    var runningAction = actions.findProperty('Tasks.status', 'IN_PROGRESS');
     if (runningAction === undefined || runningAction === null) {
     if (runningAction === undefined || runningAction === null) {
-      runningAction = tasks.findProperty('Tasks.status', 'QUEUED');
+      runningAction = actions.findProperty('Tasks.status', 'QUEUED');
     }
     }
     if (runningAction === undefined || runningAction === null) {
     if (runningAction === undefined || runningAction === null) {
-      runningAction = tasks.findProperty('Tasks.status', 'PENDING');
+      runningAction = actions.findProperty('Tasks.status', 'PENDING');
     }
     }
     if (runningAction !== null && runningAction !== undefined) {
     if (runningAction !== null && runningAction !== undefined) {
       contentHost.set('message', this.displayMessage(runningAction.Tasks));
       contentHost.set('message', this.displayMessage(runningAction.Tasks));
@@ -510,10 +519,10 @@ App.WizardStep9Controller = Em.Controller.extend({
      */
      */
     switch (this.get('content.cluster.status')) {
     switch (this.get('content.cluster.status')) {
       case 'PENDING':
       case 'PENDING':
-        progress = Math.ceil(((queuedActions * 0.09) + (inProgressActions * 0.35) + completedActions ) / actionsPerHost * 33);
+        progress = actionsPerHost?(Math.ceil(((queuedActions * 0.09) + (inProgressActions * 0.35) + completedActions ) / actionsPerHost * 33)):33;
         break;
         break;
       case 'INSTALLED':
       case 'INSTALLED':
-        progress = 34 + Math.ceil(((queuedActions * 0.09) + (inProgressActions * 0.35) + completedActions ) / actionsPerHost * 66);
+        progress = actionsPerHost?(34 + Math.ceil(((queuedActions * 0.09) + (inProgressActions * 0.35) + completedActions ) / actionsPerHost * 66)):100;
         break;
         break;
       default:
       default:
         progress = 100;
         progress = 100;
@@ -568,54 +577,74 @@ App.WizardStep9Controller = Em.Controller.extend({
   // returns true if polling should stop; false otherwise
   // returns true if polling should stop; false otherwise
   // polling from ui stops only when no action has 'PENDING', 'QUEUED' or 'IN_PROGRESS' status
   // polling from ui stops only when no action has 'PENDING', 'QUEUED' or 'IN_PROGRESS' status
   finishState: function (polledData) {
   finishState: function (polledData) {
-    var clusterStatus = {};
-    var requestId = this.get('content.cluster.requestId');
     if (this.get('content.cluster.status') === 'INSTALLED') {
     if (this.get('content.cluster.status') === 'INSTALLED') {
-      if (!polledData.someProperty('Tasks.status', 'PENDING') && !polledData.someProperty('Tasks.status', 'QUEUED') && !polledData.someProperty('Tasks.status', 'IN_PROGRESS')) {
-        this.set('progress', '100');
-        clusterStatus = {
-          status: 'INSTALLED',
-          requestId: requestId,
-          isCompleted: true
-        };
-        if (this.isSuccess(polledData)) {
-          clusterStatus.status = 'STARTED';
-          var serviceStartTime = new Date().getTime();
-          var timeToStart = ((parseInt(serviceStartTime) - parseInt(this.get('content.cluster.installStartTime'))) / 60000).toFixed(2);
-          clusterStatus.installTime = timeToStart;
-        } else {
-            clusterStatus.status = 'START FAILED'; // 'START FAILED' implies to step10 that installation was successful but start failed
-        }
-        App.router.get(this.get('content.controllerName')).saveClusterStatus(clusterStatus);
-        this.set('isStepCompleted', true);
-        this.setTasksPerHost();
-        App.router.get(this.get('content.controllerName')).saveInstalledHosts(this);
-        return true;
+      return this.finishStateInstalled(polledData);
+    }
+    else
+      if (this.get('content.cluster.status') === 'PENDING') {
+        return this.finishStatePending(polledData);
       }
       }
-    } else if (this.get('content.cluster.status') === 'PENDING') {
-      if (!polledData.someProperty('Tasks.status', 'PENDING') && !polledData.someProperty('Tasks.status', 'QUEUED') && !polledData.someProperty('Tasks.status', 'IN_PROGRESS')) {
-        clusterStatus = {
-          status: 'PENDING',
-          requestId: requestId,
-          isCompleted: false
-        };
-        if (this.get('status') === 'failed') {
-          clusterStatus.status = 'INSTALL FAILED';
+      else
+        if (this.get('content.cluster.status') === 'INSTALL FAILED' ||
+            this.get('content.cluster.status') === 'START FAILED' ||
+            this.get('content.cluster.status') === 'STARTED') {
           this.set('progress', '100');
           this.set('progress', '100');
-          this.get('hosts').setEach('progress', '100');
-          App.router.get(this.get('content.controllerName')).saveClusterStatus(clusterStatus);
-          this.set('isStepCompleted', true);
-        } else {
-          clusterStatus.status = 'INSTALLED';
-          this.set('progress', '34');
-          this.launchStartServices();
+          return true;
         }
         }
-        this.setTasksPerHost();
-        App.router.get(this.get('content.controllerName')).saveInstalledHosts(this);
-        return true;
-      }
-    } else if (this.get('content.cluster.status') === 'INSTALL FAILED' || this.get('content.cluster.status') === 'START FAILED' || this.get('content.cluster.status') === 'STARTED') {
+    return false;
+  },
+
+  finishStateInstalled: function(polledData) {
+    var clusterStatus = {};
+    if (!polledData.someProperty('Tasks.status', 'PENDING') &&
+        !polledData.someProperty('Tasks.status', 'QUEUED') &&
+        !polledData.someProperty('Tasks.status', 'IN_PROGRESS')) {
       this.set('progress', '100');
       this.set('progress', '100');
+      clusterStatus = {
+        status: 'INSTALLED',
+        requestId: this.get('content.cluster.requestId'),
+        isCompleted: true
+      };
+      if (this.isSuccess(polledData)) {
+        clusterStatus.status = 'STARTED';
+        var serviceStartTime = new Date().getTime();
+        var timeToStart = ((parseInt(serviceStartTime) - parseInt(this.get('content.cluster.installStartTime'))) / 60000).toFixed(2);
+        clusterStatus.installTime = timeToStart;
+      } else {
+        clusterStatus.status = 'START FAILED'; // 'START FAILED' implies to step10 that installation was successful but start failed
+      }
+      App.router.get(this.get('content.controllerName')).saveClusterStatus(clusterStatus);
+      this.set('isStepCompleted', true);
+      this.setTasksPerHost();
+      App.router.get(this.get('content.controllerName')).saveInstalledHosts(this);
+      return true;
+    }
+    return false;
+  },
+
+  finishStatePending: function(polledData) {
+    var clusterStatus = {};
+    if (!polledData.someProperty('Tasks.status', 'PENDING') &&
+        !polledData.someProperty('Tasks.status', 'QUEUED') &&
+        !polledData.someProperty('Tasks.status', 'IN_PROGRESS')) {
+      clusterStatus = {
+        status: 'PENDING',
+        requestId: this.get('content.cluster.requestId'),
+        isCompleted: false
+      };
+      if (this.get('status') === 'failed') {
+        clusterStatus.status = 'INSTALL FAILED';
+        this.set('progress', '100');
+        this.get('hosts').setEach('progress', '100');
+        App.router.get(this.get('content.controllerName')).saveClusterStatus(clusterStatus);
+        this.set('isStepCompleted', true);
+      } else {
+        clusterStatus.status = 'INSTALLED';
+        this.set('progress', '34');
+        this.launchStartServices();
+      }
+      this.setTasksPerHost();
+      App.router.get(this.get('content.controllerName')).saveInstalledHosts(this);
       return true;
       return true;
     }
     }
     return false;
     return false;
@@ -625,35 +654,26 @@ App.WizardStep9Controller = Em.Controller.extend({
     var tasksData = this.get('polledData');
     var tasksData = this.get('polledData');
     this.get('hosts').forEach(function (_host) {
     this.get('hosts').forEach(function (_host) {
       var tasksPerHost = tasksData.filterProperty('Tasks.host_name', _host.name); // retrieved from polled Data
       var tasksPerHost = tasksData.filterProperty('Tasks.host_name', _host.name); // retrieved from polled Data
-      if (tasksPerHost.length === 0) {
-        //alert('For testing with mockData follow the sequence: hit referesh,"mockData btn", "pollData btn", again "pollData btn"');
-        //exit();
-      }
       if (tasksPerHost !== null && tasksPerHost !== undefined && tasksPerHost.length !== 0) {
       if (tasksPerHost !== null && tasksPerHost !== undefined && tasksPerHost.length !== 0) {
         tasksPerHost.forEach(function (_taskPerHost) {
         tasksPerHost.forEach(function (_taskPerHost) {
           console.log('In step9 _taskPerHost function.');
           console.log('In step9 _taskPerHost function.');
-          //if (_taskPerHost.Tasks.status !== 'PENDING' && _taskPerHost.Tasks.status !== 'QUEUED' &&  _taskPerHost.Tasks.status !== 'IN_PROGRESS') {
           _host.tasks.pushObject(_taskPerHost);
           _host.tasks.pushObject(_taskPerHost);
-          //}
         }, this);
         }, this);
       }
       }
     }, this);
     }, this);
   },
   },
 
 
-  logTasksChangesCounter: 0,
-
   // This is done at HostRole level.
   // This is done at HostRole level.
   setLogTasksStatePerHost: function (tasksPerHost, host) {
   setLogTasksStatePerHost: function (tasksPerHost, host) {
+    if (!tasksPerHost) return;
     console.log('In step9 setTasksStatePerHost function.');
     console.log('In step9 setTasksStatePerHost function.');
     tasksPerHost.forEach(function (_task) {
     tasksPerHost.forEach(function (_task) {
       console.log('In step9 _taskPerHost function.');
       console.log('In step9 _taskPerHost function.');
-      //if (_task.Tasks.status !== 'PENDING' && _task.Tasks.status !== 'QUEUED') {
       var task = host.logTasks.findProperty('Tasks.id', _task.Tasks.id);
       var task = host.logTasks.findProperty('Tasks.id', _task.Tasks.id);
       if (task) {
       if (task) {
         host.logTasks.removeObject(task);
         host.logTasks.removeObject(task);
       }
       }
       host.logTasks.pushObject(_task);
       host.logTasks.pushObject(_task);
-      //}
     }, this);
     }, this);
     this.set('logTasksChangesCounter', this.get('logTasksChangesCounter') + 1);
     this.set('logTasksChangesCounter', this.get('logTasksChangesCounter') + 1);
   },
   },
@@ -669,34 +689,34 @@ App.WizardStep9Controller = Em.Controller.extend({
     }
     }
     var requestId = this.get('content.cluster.requestId');
     var requestId = this.get('content.cluster.requestId');
     if(polledData.Requests && polledData.Requests.id && polledData.Requests.id!=requestId){
     if(polledData.Requests && polledData.Requests.id && polledData.Requests.id!=requestId){
-      // We dont want to use non-current requestId's tasks data to
+      // We don't want to use non-current requestId's tasks data to
       // determine the current install status.
       // determine the current install status.
-      // Also, we dont want to keep polling if it is not the
+      // Also, we don't want to keep polling if it is not the
       // current requestId.
       // current requestId.
       return false;
       return false;
     }
     }
     this.replacePolledData(tasksData);
     this.replacePolledData(tasksData);
-    this.hosts.forEach(function (_host) {
+    this.get('hosts').forEach(function (_host) {
       var actionsPerHost = tasksData.filterProperty('Tasks.host_name', _host.name); // retrieved from polled Data
       var actionsPerHost = tasksData.filterProperty('Tasks.host_name', _host.name); // retrieved from polled Data
       if (actionsPerHost.length === 0) {
       if (actionsPerHost.length === 0) {
-        _host.set('message', this.t('installer.step9.host.status.nothingToInstall'));
-        if (_host.get('progress') == 0) {
+        if(this.get('content.cluster.status') === 'PENDING') {
           _host.set('progress', '33');
           _host.set('progress', '33');
         }
         }
+        if(this.get('content.cluster.status') === 'INSTALLED') {
+          _host.set('progress', '100');
+        }
         console.log("INFO: No task is hosted on the host");
         console.log("INFO: No task is hosted on the host");
       }
       }
-      if (actionsPerHost !== null && actionsPerHost !== undefined && actionsPerHost.length !== 0) {
-        this.setLogTasksStatePerHost(actionsPerHost, _host);
-        this.onSuccessPerHost(actionsPerHost, _host);     // every action should be a success
-        this.onErrorPerHost(actionsPerHost, _host);     // any action should be a failure
-        this.onInProgressPerHost(actionsPerHost, _host);  // current running action for a host
-        totalProgress += self.progressPerHost(actionsPerHost, _host);
-      }
+      this.setLogTasksStatePerHost(actionsPerHost, _host);
+      this.onSuccessPerHost(actionsPerHost, _host);     // every action should be a success
+      this.onErrorPerHost(actionsPerHost, _host);     // any action should be a failure
+      this.onInProgressPerHost(actionsPerHost, _host);  // current running action for a host
+      totalProgress += self.progressPerHost(actionsPerHost, _host);
       if (_host.get('progress') == '33') {
       if (_host.get('progress') == '33') {
         _host.set('message', this.t('installer.step9.host.status.nothingToInstall'));
         _host.set('message', this.t('installer.step9.host.status.nothingToInstall'));
       }
       }
     }, this);
     }, this);
-    totalProgress = Math.floor(totalProgress / this.hosts.length);
+    totalProgress = Math.floor(totalProgress / this.get('hosts.length'));
     this.set('progress', totalProgress.toString());
     this.set('progress', totalProgress.toString());
     console.log("INFO: right now the progress is: " + this.get('progress'));
     console.log("INFO: right now the progress is: " + this.get('progress'));
     return this.finishState(tasksData);
     return this.finishState(tasksData);
@@ -707,8 +727,6 @@ App.WizardStep9Controller = Em.Controller.extend({
     this.doPolling();
     this.doPolling();
   },
   },
 
 
-  numPolls: 1,
-
   getUrl: function (requestId) {
   getUrl: function (requestId) {
     var clusterName = this.get('content.cluster.name');
     var clusterName = this.get('content.cluster.name');
     var requestId = requestId || this.get('content.cluster.requestId');
     var requestId = requestId || this.get('content.cluster.requestId');
@@ -717,8 +735,6 @@ App.WizardStep9Controller = Em.Controller.extend({
     return url;
     return url;
   },
   },
 
 
-  POLL_INTERVAL: 4000,
-
   loadLogData: function(requestId) {
   loadLogData: function(requestId) {
     var url = this.getUrl(requestId);
     var url = this.getUrl(requestId);
     var requestsId = App.db.getCluster().oldRequestsId;
     var requestsId = App.db.getCluster().oldRequestsId;
@@ -746,9 +762,10 @@ App.WizardStep9Controller = Em.Controller.extend({
       timeout: App.timeout,
       timeout: App.timeout,
       dataType: 'text',
       dataType: 'text',
       success: function (data) {
       success: function (data) {
+        var parsedData = jQuery.parseJSON(data);
         console.log("TRACE: In success function for the GET logs data");
         console.log("TRACE: In success function for the GET logs data");
-        console.log("TRACE: STep9 -> The value is: ", jQuery.parseJSON(data));
-        var result = self.parseHostInfo(jQuery.parseJSON(data));
+        console.log("TRACE: Step9 -> The value is: ", parsedData);
+        var result = self.parseHostInfo(parsedData);
         if (!polling) {
         if (!polling) {
           return;
           return;
         }
         }
@@ -804,4 +821,4 @@ App.WizardStep9Controller = Em.Controller.extend({
       App.router.send('back');
       App.router.send('back');
     }
     }
   }
   }
-});
+});

+ 7 - 17
ambari-web/app/views/wizard/step9_view.js

@@ -92,34 +92,24 @@ App.HostStatusView = Em.View.extend({
       if (this.get('obj.progress') === '100') {
       if (this.get('obj.progress') === '100') {
         this.set('obj.message', Em.I18n.t('installer.step9.host.status.failed'));
         this.set('obj.message', Em.I18n.t('installer.step9.host.status.failed'));
       }
       }
-    } else if (this.get('obj.status') === 'success' && this.get('isHostCompleted') && parseInt(this.get('controller.progress')) > 35) {
+    } else {
+      if (this.get('obj.status') === 'success' && this.get('isHostCompleted') && parseInt(this.get('controller.progress')) > 34) {
         this.set('barColor', 'progress-success');
         this.set('barColor', 'progress-success');
         this.set('obj.message', Em.I18n.t('installer.step9.host.status.success'));
         this.set('obj.message', Em.I18n.t('installer.step9.host.status.success'));
       }
       }
-  }.observes('obj.status', 'obj.progress'),
+    }
+  }.observes('obj.status', 'obj.progress', 'controller.progress'),
 
 
   isFailed:function () {
   isFailed:function () {
-    if (this.get('controller.isStepCompleted') === true && this.get('obj.status') === 'failed') {
-      return true;
-    } else {
-      return false;
-    }
+    return (this.get('controller.isStepCompleted') === true && this.get('obj.status') === 'failed');
   }.property('controller.isStepCompleted', 'controller.status'),
   }.property('controller.isStepCompleted', 'controller.status'),
 
 
   isSuccess:function () {
   isSuccess:function () {
-    if (this.get('controller.isStepCompleted') === true && this.get('obj.status') === 'success') {
-      return true;
-    } else {
-      return false;
-    }
+    return (this.get('controller.isStepCompleted') === true && this.get('obj.status') === 'success');
   }.property('controller.isStepCompleted', 'controller.status'),
   }.property('controller.isStepCompleted', 'controller.status'),
 
 
   isWarning:function () {
   isWarning:function () {
-    if (this.get('controller.isStepCompleted') === true && this.get('obj.status') === 'warning') {
-      return true;
-    } else {
-      return false;
-    }
+    return(this.get('controller.isStepCompleted') === true && this.get('obj.status') === 'warning');
   }.property('controller.isStepCompleted', 'controller.status'),
   }.property('controller.isStepCompleted', 'controller.status'),
 
 
   isHostCompleted:function () {
   isHostCompleted:function () {

+ 930 - 123
ambari-web/test/installer/step9_test.js

@@ -22,144 +22,951 @@ var App = require('app');
 require('models/hosts');
 require('models/hosts');
 require('controllers/wizard/step9_controller');
 require('controllers/wizard/step9_controller');
 
 
-/*describe('App.InstallerStep9Controller', function () {
-  //var controller = App.InstallerStep3Controller.create();
-
-  describe('#isStepFailed', function () {
-    var controller = App.InstallerStep9Controller.create();
-    it('should return true if even a single action of a role with 100% success factor fails', function () {
-      var polledData = new Ember.Set([
-        {
-          actionId: '1',
-          name: '192.168.1.1',
-          status: 'completed',
-          sf: '100',
-          role: 'DataNode',
-          message: 'completed 30%'
-        },
-        {
-          actionId: '2',
-          name: '192.168.1.2',
-          status: 'completed',
-          sf: '100',
-          role: 'DataNode',
-          message: 'completed 20%'
-        },
-        {
-          actionId: '3',
-          name: '192.168.1.3',
-          status: 'completed',
-          sf: '100',
-          role: 'DataNode',
-          message: 'completed 30%'
-        },
-        {
-          actionId: '4',
-          name: '192.168.1.4',
-          status: 'failed',
-          sf: '100',
-          role: 'DataNode',
-          message: 'completed 40%'
+describe('App.InstallerStep9Controller', function () {
+
+  describe('#isSubmitDisabled', function () {
+    var tests = [
+      {controllerName: 'addHostController',state: 'STARTED',e: false},
+      {controllerName: 'addHostController',state: 'START FAILED',e: false},
+      {controllerName: 'addHostController',state: 'INSTALL FAILED',e: false},
+      {controllerName: 'addHostController',state: 'PENDING',e: true},
+      {controllerName: 'addHostController',state: 'INSTALLED',e: true},
+      {controllerName: 'installerController',state: 'STARTED',e: false},
+      {controllerName: 'installerController',state: 'START FAILED',e: false},
+      {controllerName: 'installerController',state: 'INSTALL FAILED',e: true},
+      {controllerName: 'installerController',state: 'INSTALLED',e: true},
+      {controllerName: 'installerController',state: 'PENDING',e: true}
+    ];
+    tests.forEach(function(test) {
+      var controller = App.WizardStep9Controller.create({
+        content: {
+          controllerName: test.controllerName,
+            cluster: {
+            status: test.state
+          }
         }
         }
-      ]);
+      });
+      it('controllerName is ' + test.controllerName + '; cluster status is ' + test.state + '; isSubmitDisabled should be ' + test.e, function() {
+        expect(controller.get('isSubmitDisabled')).to.equal(test.e);
+      });
+    });
 
 
+  });
 
 
-      expect(controller.isStepFailed(polledData)).to.equal(true);
+  describe('#status', function() {
+    var tests = [
+      {
+        hosts: [{status: 'failed'},{status: 'success'}],
+        isStepFailed: false,
+        progress: '100',
+        m:'One host is failed',
+        e:'failed'
+      },
+      {
+        hosts: [{status: 'warning'},{status: 'success'}],
+        m:'One host is failed and step is not failed',
+        isStepFailed: false,
+        progress: '100',
+        e:'warning'
+      },
+      {
+        hosts: [{status: 'warning'},{status: 'success'}],
+        m:'One host is failed and step is failed',
+        isStepFailed: true,
+        progress: '100',
+        e:'failed'
+      },
+      {
+        hosts: [{status: 'success'},{status: 'success'}],
+        m:'All hosts are success and progress is 100',
+        isStepFailed: false,
+        progress: '100',
+        e:'success'
+      },
+      {
+        hosts: [{status: 'success'},{status: 'success'}],
+        m:'All hosts are success and progress is 50',
+        isStepFailed: false,
+        progress: '50',
+        e:'info'
+      }
+    ];
+    tests.forEach(function(test) {
+      var controller = App.WizardStep9Controller.create({hosts: test.hosts, isStepFailed: function(){return test.isStepFailed}, progress: test.progress});
+      it(test.m, function() {
+        expect(controller.get('status')).to.equal(test.e);
+      });
+    });
+  });
 
 
-    })
+  describe('#visibleHosts', function() {
+    var hosts = [
+      Em.Object.create({status: 'failed'}),
+      Em.Object.create({status: 'success'}),
+      Em.Object.create({status: 'success'}),
+      Em.Object.create({status: 'warning'}),
+      Em.Object.create({status: 'info'}),
+      Em.Object.create({status: 'info'})
+    ];
+    var tests = [
+      {category: {hostStatus: 'all'},e: hosts.length},
+      {category:{hostStatus: 'inProgress'},e: 2},
+      {category: {hostStatus: 'warning'},e: 1},
+      {category: {hostStatus: 'failed'},e: 1},
+      {category: {hostStatus: 'success'},e: 2}
+    ];
+    var controller = App.WizardStep9Controller.create({
+      hosts: hosts
+    });
+    tests.forEach(function(test) {
+      it('selected category with hostStatus "' + test.category.hostStatus + '"', function() {
+        controller.selectCategory({context: test.category});
+        expect(controller.get('visibleHosts.length')).to.equal(test.e);
+      });
+    });
+  });
 
 
-    it('should return false if action of a role fails but with less percentage than success factor of the role', function () {
-      var polledData = new Ember.Set([
-        {
-          actionId: '1',
-          name: '192.168.1.1',
-          status: 'failed',
-          sf: '30',
-          role: 'DataNode',
-          message: 'completed 30%'
-        },
-        {
-          actionId: '2',
-          name: '192.168.1.2',
-          status: 'failed',
-          sf: '30',
-          role: 'DataNode',
-          message: 'completed 20%'
-        },
-        {
-          actionId: '3',
-          name: '192.168.1.3',
-          status: 'completed',
-          sf: '30',
-          role: 'DataNode',
-          message: 'completed 30%'
-        },
-        {
-          actionId: '4',
-          name: '192.168.1.4',
-          status: 'completed',
-          sf: '30',
-          role: 'DataNode',
-          message: 'completed 40%'
-        }
-      ]);
+  describe('#showRetry', function() {
+    it('cluster status is not INSTALL FAILED', function() {
+      var controller = App.WizardStep9Controller.create({content: {cluster:{status:'INSTALLED'}}});
+      expect(controller.get('showRetry')).to.equal(false);
+    });
+    it('cluster status is INSTALL FAILED', function() {
+      var controller = App.WizardStep9Controller.create({content: {cluster:{status:'INSTALL FAILED'}}});
+      expect(controller.get('showRetry')).to.equal(true);
+    });
+  });
+
+  describe('#resetHostsForRetry', function() {
+    var hosts = {'host1':Em.Object.create({status:'failed', message:'Failed'}), 'host2':Em.Object.create({status:'success', message:'Success'})};
+    var controller = App.WizardStep9Controller.create({content:{hosts: hosts}});
+    it('All should have status "pending" and message "Waiting"', function() {
+      controller.resetHostsForRetry();
+      for (var name in hosts) {
+        expect(controller.get('content.hosts')[name].get('status','pending')).to.equal('pending');
+        expect(controller.get('content.hosts')[name].get('message','Waiting')).to.equal('Waiting');
+      }
+    });
+  });
 
 
-      expect(controller.isStepFailed(polledData)).to.equal(false);
+  var hosts_for_load_and_render = {
+    'host1': {
+      message: 'message1',
+      status: 'unknown',
+      progress: '1',
+      tasks: [{},{}],
+      logTasks: [{},{}],
+      bootStatus: 'REGISTERED'
+    },
+    'host2': {
+      message: '',
+      status: 'failed',
+      progress: '1',
+      tasks: [{},{}],
+      logTasks: [{},{}],
+      bootStatus: ''
+    },
+    'host3': {
+      message: '',
+      status: 'waiting',
+      progress: null,
+      tasks: [{},{}],
+      logTasks: [{},{}],
+      bootStatus: ''
+    },
+    'host4': {
+      message: 'message4',
+      status: null,
+      progress: '10',
+      tasks: [],
+      logTasks: [{}],
+      bootStatus: 'REGISTERED'
+    }
+  };
+  
+  describe('#loadHosts', function() {
+    var controller = App.WizardStep9Controller.create({content: {hosts: hosts_for_load_and_render}});
+    var loaded_hosts = controller.loadHosts();
+    it('Only REGISTERED hosts', function() {
+      expect(loaded_hosts.length).to.equal(2);
+    });
+    it('All hosts have progress 0', function() {
+      expect(loaded_hosts.everyProperty('progress', 0)).to.equal(true);
+    });
+    it('All hosts have progress 0', function() {
+      expect(loaded_hosts.everyProperty('progress', 0)).to.equal(true);
+    });
+    it('All host don\'t have tasks and logTasks', function() {
+      expect(loaded_hosts.everyProperty('tasks.length', 0)).to.equal(true);
+      expect(loaded_hosts.everyProperty('logTasks.length', 0)).to.equal(true);
+    });
+  });
 
 
-    })
+  describe('#renderHosts', function() {
+    var controller = App.WizardStep9Controller.create({content: {hosts: hosts_for_load_and_render}});
+    var loaded_hosts = controller.loadHosts();
+    controller.renderHosts(loaded_hosts);
+    it('All host should be rendered', function() {
+      expect(controller.get('hosts.length')).to.equal(loaded_hosts.length);
+    });
+  });
+
+  describe('#hostHasClientsOnly', function() {
+    var tests = [
+      {
+        hosts: [
+          Em.Object.create({
+            hostName: 'host1',
+            logTasks: [{Tasks: {role: 'HDFS_CLIENT'}},{Tasks: {role: 'DATANODE'}}],
+            status: 'old_status',
+            progress: '10',
+            e: {status: 'old_status',progress: '10'}
+          }),
+          Em.Object.create({
+            hostName: 'host2',
+            logTasks: [{Tasks: {role: 'HDFS_CLIENT'}}],
+            status: 'old_status',
+            progress: '10',
+            e: {status: 'success',progress: '100'}
+          })
+        ],
+        jsonError: false
+      },
+      {
+        hosts: [
+          Em.Object.create({
+            hostName: 'host1',
+            logTasks: [{Tasks: {role: 'HDFS_CLIENT'}},{Tasks: {role: 'DATANODE'}}],
+            status: 'old_status',
+            progress: '10',
+            e: {status: 'success',progress: '100'}
+          }),
+          Em.Object.create({
+            hostName: 'host2',
+            logTasks: [{Tasks: {role: 'HDFS_CLIENT'}}],
+            status: 'old_status',
+            progress: '10',
+            e: {status: 'success',progress: '100'}
+          })
+        ],
+        jsonError: true
+      }
+    ];
+    tests.forEach(function(test) {
+      it('', function() {
+        var controller = App.WizardStep9Controller.create({hosts: test.hosts});
+        controller.hostHasClientsOnly(test.jsonError);
+        test.hosts.forEach(function(host) {
+          expect(controller.get('hosts').findProperty('hostName', host.hostName).get('status')).to.equal(host.e.status);
+          expect(controller.get('hosts').findProperty('hostName', host.hostName).get('progress')).to.equal(host.e.progress);
+        });
+      });
+    });
+  });
+
+  describe('#onSuccessPerHost', function() {
+    var tests = [
+      {
+        cluster: {status: 'INSTALLED'},
+        host: Em.Object.create({status: 'pending'}),
+        actions: [],
+        e: {status: 'success'},
+        m: 'No tasks for host'
+      },
+      {
+        cluster: {status: 'INSTALLED'},
+        host: Em.Object.create({status: 'info'}),
+        actions: [{Tasks: {status: 'COMPLETED'}},{Tasks: {status: 'COMPLETED'}}],
+        e: {status: 'success'},
+        m: 'All Tasks COMPLETED and cluster status INSTALLED'
+      },
+      {
+        cluster: {status: 'FAILED'},
+        host: Em.Object.create({status: 'info'}),
+        actions: [{Tasks: {status: 'COMPLETED'}},{Tasks: {status: 'COMPLETED'}}],
+        e: {status: 'info'},
+        m: 'All Tasks COMPLETED and cluster status FAILED'
+      },
+      {
+        cluster: {status: 'INSTALLED'},
+        host: Em.Object.create({status: 'info'}),
+        actions: [{Tasks: {status: 'FAILED'}},{Tasks: {status: 'COMPLETED'}}],
+        e: {status: 'info'},
+        m: 'Not all Tasks COMPLETED and cluster status INSTALLED'
+      },
+      {
+        cluster: {status: 'FAILED'},
+        host: Em.Object.create({status: 'info'}),
+        actions: [{Tasks: {status: 'FAILED'}},{Tasks: {status: 'COMPLETED'}}],
+        e: {status: 'info'},
+        m: 'Not all Tasks COMPLETED and cluster status FAILED'
+      }
+    ];
+    tests.forEach(function(test) {
+      var controller = App.WizardStep9Controller.create({content: {cluster: {status: test.cluster.status}}});
+      controller.onSuccessPerHost(test.actions, test.host);
+      it(test.m, function() {
+        expect(test.host.status).to.equal(test.e.status);
+      });
+    });
+  });
+
+  describe('#onErrorPerHost', function() {
+    var tests = [
+      {
+        cluster: {status: 'INSTALLED'},
+        host: Em.Object.create({status: 'pending'}),
+        actions: [],
+        e: {status: 'pending'},
+        isMasterFailed: false,
+        m: 'No tasks for host'
+      },
+      {
+        cluster: {status: 'INSTALLED'},
+        host: Em.Object.create({status: 'info'}),
+        actions: [{Tasks: {status: 'FAILED'}},{Tasks: {status: 'COMPLETED'}}],
+        e: {status: 'warning'},
+        isMasterFailed: false,
+        m: 'One Task FAILED and cluster status INSTALLED'
+      },
+      {
+        cluster: {status: 'INSTALLED'},
+        host: Em.Object.create({status: 'info'}),
+        actions: [{Tasks: {status: 'ABORTED'}},{Tasks: {status: 'COMPLETED'}}],
+        e: {status: 'warning'},
+        isMasterFailed: false,
+        m: 'One Task ABORTED and cluster status INSTALLED'
+      },
+      {
+        cluster: {status: 'INSTALLED'},
+        host: Em.Object.create({status: 'info'}),
+        actions: [{Tasks: {status: 'TIMEDOUT'}},{Tasks: {status: 'COMPLETED'}}],
+        e: {status: 'warning'},
+        isMasterFailed: false,
+        m: 'One Task TIMEDOUT and cluster status INSTALLED'
+      },
+      {
+        cluster: {status: 'PENDING'},
+        host: Em.Object.create({status: 'info'}),
+        actions: [{Tasks: {status: 'FAILED'}},{Tasks: {status: 'COMPLETED'}}],
+        e: {status: 'failed'},
+        isMasterFailed: true,
+        m: 'One Task FAILED and cluster status PENDING isMasterFailed true'
+      },
+      {
+        cluster: {status: 'PENDING'},
+        host: Em.Object.create({status: 'info'}),
+        actions: [{Tasks: {status: 'COMPLETED'}},{Tasks: {status: 'COMPLETED'}}],
+        e: {status: 'info'},
+        isMasterFailed: false,
+        m: 'One Task FAILED and cluster status PENDING isMasterFailed false'
+      }
+    ];
+    tests.forEach(function(test) {
+      var controller = App.WizardStep9Controller.create({content: {cluster: {status: test.cluster.status}}, isMasterFailed: function(){return test.isMasterFailed;}});
+      controller.onErrorPerHost(test.actions, test.host);
+      it(test.m, function() {
+        expect(test.host.status).to.equal(test.e.status);
+      });
+    });
+  });
+
+  describe('#isMasterFailed', function() {
+    var tests = [
+      {
+        actions: [
+          {Tasks: {command: 'INSTALL',status: 'FAILED',role: 'DATANODE'}},
+          {Tasks: {command: 'INSTALL',status: 'FAILED',role: 'TASKTRACKER'}},
+          {Tasks: {command: 'INSTALL',status: 'FAILED',role: 'HBASE_REGIONSERVER'}},
+          {Tasks: {command: 'INSTALL',status: 'FAILED',role: 'GANGLIA_MONITOR'}}
+        ],
+        e: false,
+        m: 'No one Master is failed'
+      },
+      {
+        actions: [
+          {Tasks: {command: 'INSTALL',status: 'FAILED',role: 'NAMENODE'}},
+          {Tasks: {command: 'INSTALL',status: 'FAILED',role: 'TASKTRACKER'}},
+          {Tasks: {command: 'INSTALL',status: 'FAILED',role: 'HBASE_REGIONSERVER'}},
+          {Tasks: {command: 'INSTALL',status: 'FAILED',role: 'GANGLIA_MONITOR'}}
+        ],
+        e: true,
+        m: 'One Master is failed'
+      },
+      {
+        actions: [
+          {Tasks: {command: 'PENDING',status: 'FAILED',role: 'NAMENODE'}},
+          {Tasks: {command: 'INSTALL',status: 'FAILED',role: 'TASKTRACKER'}},
+          {Tasks: {command: 'INSTALL',status: 'FAILED',role: 'HBASE_REGIONSERVER'}},
+          {Tasks: {command: 'INSTALL',status: 'FAILED',role: 'GANGLIA_MONITOR'}}
+        ],
+        e: false,
+        m: 'one Master is failed but command is not install'
+      }
+    ];
+    tests.forEach(function(test) {
+      it(test.m, function() {
+        var controller = App.WizardStep9Controller.create();
+        expect(controller.isMasterFailed(test.actions)).to.equal(test.e);
+      });
+    });
+  });
+
+  describe('#onInProgressPerHost', function() {
+    var tests = [
+      {
+        host: Em.Object.create({message: 'default_message'}),
+        actions: [{Tasks: {status: 'COMPLETED'}},{Tasks: {status: 'COMPLETED'}}],
+        e: {message: 'default_message',b: true},
+        m: 'All Tasks COMPLETED'
+      },
+      {
+        host: Em.Object.create({message: 'default_message'}),
+        actions: [{Tasks: {status: 'IN_PROGRESS'}},{Tasks: {status: 'COMPLETED'}}],
+        e: {message: 'default_message',b: false},
+        m: 'One Task IN_PROGRESS'
+      },
+      {
+        host: Em.Object.create({message: 'default_message'}),
+        actions: [{Tasks: {status: 'QUEUED'}},{Tasks: {status: 'COMPLETED'}}],
+        e: {message: 'default_message',b: false},
+        m: 'One Task QUEUED'
+      },
+      {
+        host: Em.Object.create({message: 'default_message'}),
+        actions: [{Tasks: {status: 'PENDING'}},{Tasks: {status: 'COMPLETED'}}],
+        e: {message: 'default_message',b: false},
+        m: 'One Task PENDING'
+      }
+    ];
+    tests.forEach(function(test) {
+      it(test.m, function() {
+        var controller = App.WizardStep9Controller.create();
+        controller.onInProgressPerHost(test.actions, test.host);
+        expect(test.host.message == test.e.message).to.equal(test.e.b);
+      });
+    });
+  });
+
+  describe('#progressPerHost', function() {
+    var tests = [
+      {
+        cluster: {status: 'PENDING'},
+        host: Em.Object.create({progress: 0}),
+        actions: [
+          {Tasks: {status: 'COMPLETED'}},
+          {Tasks: {status: 'COMPLETED'}},
+          {Tasks: {status: 'QUEUED'}},
+          {Tasks: {status: 'QUEUED'}},
+          {Tasks: {status: 'IN_PROGRESS'}}
+        ],
+        e: {ret: 17,host: '17'},
+        m: 'All types of status available. cluster status PENDING'
+      },
+      {
+        cluster: {status: 'PENDING'},
+        host: Em.Object.create({progress: 0}),
+        actions: [],
+        e: {ret: 33,host: '33'},
+        m: 'No tasks available. cluster status PENDING'
+      },
+      {
+        cluster: {status: 'INSTALLED'},
+        host: Em.Object.create({progress: 0}),
+        actions: [],
+        e: {ret: 100,host: '100'},
+        m: 'No tasks available. cluster status INSTALLED'
+      },
+      {
+        cluster: {status: 'INSTALLED'},
+        host: Em.Object.create({progress: 0}),
+        actions: [
+          {Tasks: {status: 'COMPLETED'}},
+          {Tasks: {status: 'COMPLETED'}},
+          {Tasks: {status: 'QUEUED'}},
+          {Tasks: {status: 'QUEUED'}},
+          {Tasks: {status: 'IN_PROGRESS'}}
+        ],
+        e: {ret: 68,host: '68'},
+        m: 'All types of status available. cluster status INSTALLED'
+      },
+      {
+        cluster: {status: 'FAILED'},
+        host: Em.Object.create({progress: 0}),
+        actions: [],
+        e: {ret: 100,host: '100'},
+        m: 'Cluster status is not PENDING or INSTALLED'
+      }
+    ];
+    tests.forEach(function(test) {
+      it(test.m, function() {
+        var controller = App.WizardStep9Controller.create({content: {cluster: {status: test.cluster.status}}});
+        var progress = controller.progressPerHost(test.actions, test.host);
+        expect(progress).to.equal(test.e.ret);
+        expect(test.host.progress).to.equal(test.e.host);
+      });
+    });
+  });
 
 
-  })
+  describe('#clearStep', function() {
+    var controller = App.WizardStep9Controller.create({hosts: [{},{},{}]});
+    it('All to default values', function() {
+      controller.clearStep();
+      expect(controller.get('hosts.length')).to.equal(0);
+      expect(controller.get('status')).to.equal('info');
+      expect(controller.get('progress')).to.equal('0');
+      expect(controller.get('isStepCompleted')).to.equal(false);
+      expect(controller.get('numPolls')).to.equal(1);
+    });
+  });
 
 
-  describe('#setHostsStatus', function () {
-    var controller = App.InstallerStep9Controller.create();
-    it('sets the status of all hosts in the content to the passed status value', function () {
-      var mockData = new Ember.Set(
-        {
-          actionId: '1',
-          name: '192.168.1.1',
-          status: 'completed',
-          sf: '100',
-          role: 'DataNode',
-          message: 'completed 30%'
+  describe('#replacePolledData', function() {
+    var controller = App.WizardStep9Controller.create({polledData: [{},{},{}]});
+    var newPolledData = [{}];
+    controller.replacePolledData(newPolledData);
+    it('replacing polled data', function() {
+      expect(controller.get('polledData.length')).to.equal(newPolledData.length);
+    });
+  });
+
+  describe('#isSuccess', function() {
+    var tests = [
+      {
+        polledData: [
+          {Tasks: {status: 'COMPLETED'}},
+          {Tasks: {status: 'COMPLETED'}}
+        ],
+        e: true,
+        m: 'All tasks are COMPLETED'
+      },
+      {
+        polledData: [
+          {Tasks: {status: 'COMPLETED'}},
+          {Tasks: {status: 'FAILED'}}
+        ],
+        e: false,
+        m: 'Not all tasks are COMPLETED'
+      }
+    ];
+    tests.forEach(function(test) {
+      it(test.m, function() {
+        var controller = App.WizardStep9Controller.create();
+        expect(controller.isSuccess(test.polledData)).to.equal(test.e);
+      });
+    });
+  });
+
+  describe('#isStepFailed', function() {
+    var tests = [
+      {
+        polledData: [
+          {Tasks: {command: 'INSTALL',role: 'GANGLIA_MONITOR',status: 'TIMEDOUT'}},
+          {Tasks: {command: 'INSTALL',role: 'GANGLIA_MONITOR',status: 'FAILED'}},
+          {Tasks: {command: 'INSTALL',role: 'GANGLIA_MONITOR',status: 'PENDING'}}
+        ],
+        e: true,
+        m: 'GANGLIA_MONITOR 2/3 failed'
+      },
+      {
+        polledData: [
+          {Tasks: {command: 'INSTALL',role: 'GANGLIA_MONITOR',status: 'TIMEDOUT'}},
+          {Tasks: {command: 'INSTALL',role: 'GANGLIA_MONITOR',status: 'PENDING'}},
+          {Tasks: {command: 'INSTALL',role: 'GANGLIA_MONITOR',status: 'PENDING'}}
+        ],
+        e: false,
+        m: 'GANGLIA_MONITOR 1/3 failed'
+      },
+      {
+        polledData: [
+          {Tasks: {command: 'INSTALL',role: 'HBASE_REGIONSERVER',status: 'TIMEDOUT'}},
+          {Tasks: {command: 'INSTALL',role: 'HBASE_REGIONSERVER',status: 'FAILED'}},
+          {Tasks: {command: 'INSTALL',role: 'HBASE_REGIONSERVER',status: 'PENDING'}}
+        ],
+        e: true,
+        m: 'HBASE_REGIONSERVER 2/3 failed'
+      },
+      {
+        polledData: [
+          {Tasks: {command: 'INSTALL',role: 'HBASE_REGIONSERVER',status: 'TIMEDOUT'}},
+          {Tasks: {command: 'INSTALL',role: 'HBASE_REGIONSERVER',status: 'PENDING'}},
+          {Tasks: {command: 'INSTALL',role: 'HBASE_REGIONSERVER',status: 'PENDING'}}
+        ],
+        e: false,
+        m: 'HBASE_REGIONSERVER 1/3 failed'
+      },
+      {
+        polledData: [
+          {Tasks: {command: 'INSTALL',role: 'TASKTRACKER',status: 'TIMEDOUT'}},
+          {Tasks: {command: 'INSTALL',role: 'TASKTRACKER',status: 'FAILED'}},
+          {Tasks: {command: 'INSTALL',role: 'TASKTRACKER',status: 'PENDING'}}
+        ],
+        e: true,
+        m: 'TASKTRACKER 2/3 failed'
+      },
+      {
+        polledData: [
+          {Tasks: {command: 'INSTALL',role: 'TASKTRACKER',status: 'TIMEDOUT'}},
+          {Tasks: {command: 'INSTALL',role: 'TASKTRACKER',status: 'PENDING'}},
+          {Tasks: {command: 'INSTALL',role: 'TASKTRACKER',status: 'PENDING'}}
+        ],
+        e: false,
+        m: 'TASKTRACKER 1/3 failed'
+      },
+      {
+        polledData: [
+          {Tasks: {command: 'INSTALL',role: 'DATANODE',status: 'TIMEDOUT'}},
+          {Tasks: {command: 'INSTALL',role: 'DATANODE',status: 'FAILED'}},
+          {Tasks: {command: 'INSTALL',role: 'DATANODE',status: 'PENDING'}}
+        ],
+        e: true,
+        m: 'DATANODE 2/3 failed'
+      },
+      {
+        polledData: [
+          {Tasks: {command: 'INSTALL',role: 'DATANODE',status: 'TIMEDOUT'}},
+          {Tasks: {command: 'INSTALL',role: 'DATANODE',status: 'PENDING'}},
+          {Tasks: {command: 'INSTALL',role: 'DATANODE',status: 'PENDING'}}
+        ],
+        e: false,
+        m: 'DATANODE 1/3 failed'
+      },
+      {
+        polledData: [
+          {Tasks: {command: 'INSTALL',role: 'NAMENODE',status: 'TIMEDOUT'}},
+          {Tasks: {command: 'INSTALL',role: 'DATANODE',status: 'PENDING'}},
+          {Tasks: {command: 'INSTALL',role: 'DATANODE',status: 'PENDING'}}
+        ],
+        e: true,
+        m: 'NAMENODE failed'
+      },
+      {
+        polledData: [
+          {Tasks: {command: 'INSTALL',role: 'NAMENODE',status: 'PENDING'}},
+          {Tasks: {command: 'INSTALL',role: 'DATANODE',status: 'PENDING'}},
+          {Tasks: {command: 'INSTALL',role: 'DATANODE',status: 'PENDING'}}
+        ],
+        e: false,
+        m: 'Nothing failed failed'
+      }
+    ];
+    tests.forEach(function(test) {
+      var controller = App.WizardStep9Controller.create({polledData: test.polledData});
+      it(test.m, function() {
+        expect(controller.isStepFailed()).to.equal(test.e);
+      });
+    });
+  });
+
+  describe('#getUrl', function() {
+    var clusterName = 'tdk';
+    var cluster = App.WizardStep9Controller.create({content:{cluster:{name: clusterName, requestId: null}}});
+    it('check requestId priority', function() {
+      cluster.set('content.cluster.requestId', 123);
+      var url = cluster.getUrl(321);
+      expect(url).to.equal(App.apiPrefix + '/clusters/' + clusterName + '/requests/' + '321' + '?fields=tasks/*');
+      url = cluster.getUrl();
+      expect(url).to.equal(App.apiPrefix + '/clusters/' + clusterName + '/requests/' + '123' + '?fields=tasks/*');
+    });
+  });
+
+  describe('#finishState', function() {
+    var statuses = ['INSTALL FAILED', 'START FAILED', 'STARTED'];
+    it('Installer is finished', function() {
+      statuses.forEach(function(status) {
+        var controller = App.WizardStep9Controller.create({content:{cluster:{status:status}}});
+        var result = controller.finishState();
+        expect(result).to.equal(true);
+      });
+    });
+    it('Unknown cluster status ', function() {
+      var controller = App.WizardStep9Controller.create({content:{cluster:{status:'FAKE_STATUS'}}});
+      var result = controller.finishState();
+      expect(result).to.equal(false);
+    });
+  });
+
+  describe('#setTasksPerHost', function() {
+    var tests = [
+      {
+        hosts: [
+          Em.Object.create({
+            name: 'host1',
+            tasks: [],
+            bootStatus: 'REGISTERED'
+          }),
+          Em.Object.create({
+            name: 'host2',
+            tasks: [],
+            bootStatus: 'REGISTERED'
+          }),
+          Em.Object.create({
+            name: 'host3',
+            tasks: [],
+            bootStatus: 'REGISTERED'
+          })
+        ],
+        polledData: [
+          {Tasks: {host_name: 'host1'}},
+          {Tasks: {host_name: 'host1'}},
+          {Tasks: {host_name: 'host1'}},
+          {Tasks: {host_name: 'host2'}},
+          {Tasks: {host_name: 'host2'}},
+          {Tasks: {host_name: 'host3'}}
+        ],
+        e: {
+          host1: {count: 3},
+          host2: {count: 2},
+          host3: {count: 1}
         },
         },
-        {
-          actionId: '2',
-          name: '192.168.1.2',
-          status: 'completed',
-          sf: '100',
-          role: 'DataNode',
-          message: 'completed 20%'
+        m: 'Several tasks for each host'
+      },
+      {
+        hosts: [
+          Em.Object.create({
+            name: 'host1',
+            tasks: [],
+            bootStatus: 'REGISTERED'
+          }),
+          Em.Object.create({
+            name: 'host2',
+            tasks: [],
+            bootStatus: 'REGISTERED'
+          }),
+          Em.Object.create({
+            name: 'host3',
+            tasks: [],
+            bootStatus: 'REGISTERED'
+          })
+        ],
+        polledData: [
+          {Tasks: {host_name: 'host1'}},
+          {Tasks: {host_name: 'host2'}}
+        ],
+        e: {
+          host1: {count: 1},
+          host2: {count: 1},
+          host3: {count: 0}
         },
         },
-        {
-          actionId: '3',
-          name: '192.168.1.3',
-          status: 'completed',
-          sf: '100',
-          role: 'DataNode',
-          message: 'completed 30%'
+        m: 'Some hosts without tasks'
+      },
+      {
+        hosts: [
+          Em.Object.create({
+            name: 'host1',
+            tasks: [],
+            bootStatus: 'REGISTERED'
+          }),
+          Em.Object.create({
+            name: 'host2',
+            tasks: [],
+            bootStatus: 'REGISTERED'
+          }),
+          Em.Object.create({
+            name: 'host3',
+            tasks: [],
+            bootStatus: 'REGISTERED'
+          })
+        ],
+        polledData: [],
+        e: {
+          host1: {count: 0},
+          host2: {count: 0},
+          host3: {count: 0}
         },
         },
-        {
-          actionId: '4',
-          name: '192.168.1.4',
-          status: 'completed',
-          sf: '100',
-          role: 'DataNode',
-          message: 'completed 40%'
+        m: 'No tasks'
+      }
+    ];
+    tests.forEach(function(test) {
+      it(test.m, function() {
+        var controller = App.WizardStep9Controller.create({polledData: test.polledData, hosts: test.hosts});
+        controller.setTasksPerHost();
+        for(var name in test.e.hosts) {
+          expect(controller.get('hosts').findProperty('name', name).get('tasks.length')).to.equal(test.e[name].count);
         }
         }
-      );
-      mockData.forEach(function(_polledData){
-        controller.content.pushObject(_polledData);
       });
       });
+    });
+  });
 
 
-      controller.setHostsStatus(mockData,'finish');
-      var result = controller.content.everyProperty('status','finish');
-      //console.log('value of pop is: '+ result.pop.actionId);
-      expect(result).to.equal(true);
-
-    })
-  })
-
+  describe('#setLogTasksStatePerHost', function() {
+    var tests = [
+      {
+        tasksPerHost: [{Tasks: {id: 1,message: '2'}},{Tasks: {id: 2,message: '2'}}],
+        tasks: [],
+        e: {m: '2',l: 2},
+        m: 'host didn\'t have tasks and got 2 new'
+      },
+      {
+        tasksPerHost: [{Tasks: {id: 1,message: '2'}},{Tasks: {id: 2,message: '2'}}],
+        tasks: [{Tasks: {id: 1,message: '1'}},{Tasks: {id: 2,message: '1'}}],
+        e: {m: '2',l: 2},
+        m: 'host had 2 tasks and got both updated'
+      },
+      {
+        tasksPerHost: [],
+        tasks: [{Tasks: {id: 1,message: '1'}},{Tasks: {id: 2,message: '1'}}],
+        e: {m: '1',l: 2},
+        m: 'host had 2 tasks and didn\'t get updates'
+      },
+      {
+        tasksPerHost: [{Tasks: {id: 1,message: '2'}},{Tasks: {id: 2,message: '2'}},{Tasks: {id: 3,message: '2'}}],
+        tasks: [{Tasks: {id: 1,message: '1'}},{Tasks: {id: 2,message: '1'}}],
+        e: {m: '2',l: 3},
+        m: 'host had 2 tasks and got both updated and 1 new'
+      }
+    ];
+    tests.forEach(function(test) {
+      it(test.m, function() {
+        var controller = App.WizardStep9Controller.create({hosts: [Em.Object.create({logTasks: test.tasks})]});
+        var logTasksChangesCounter = controller.get('logTasksChangesCounter');
+        controller.setLogTasksStatePerHost(test.tasksPerHost, controller.get('hosts')[0]);
+        expect(controller.get('hosts')[0].get('logTasks').everyProperty('Tasks.message', test.e.m)).to.equal(true);
+        expect(controller.get('hosts')[0].get('logTasks.length')).to.equal(test.e.l);
+        expect(controller.get('logTasksChangesCounter')).to.equal(logTasksChangesCounter + 1);
+      });
+    });
+  });
 
 
-})*/
+  describe('#parseHostInfo', function() {
+    var requestId = 1;
+    var polledData = {Requests:{id:2}};
+    it('Invalid requestId. Should return false', function() {
+      var controller = App.WizardStep9Controller.create({content: {cluster:{requestId: requestId}}});
+      var res = controller.parseHostInfo(polledData);
+      expect(res).to.equal(false);
+    });
 
 
+    var tests = [
+      {
+        cluster: {status: 'PENDING'},
+        hosts: [
+          Em.Object.create({name: 'host1',status: '',message: '',progress: '',logTasks: []}),
+          Em.Object.create({name: 'host2',status: '',message: '',progress: '',logTasks: []})
+        ],
+        polledData: {
+          tasks:[
+            {Tasks: {host_name: 'host2',status: 'COMPLETED'}},
+            {Tasks: {host_name: 'host2',status: 'COMPLETED'}}
+          ]
+        },
+        e: {
+          hosts:{
+            host1: {progress: '33'},
+            host2: {progress: '33'}
+          },
+          progress: '33'
+        },
+        m: 'Two hosts. One host without tasks. Second host has all tasks COMPLETED. Cluster status is PENDING'
+      },
+      {
+        cluster: {status: 'PENDING'},
+        hosts: [
+          Em.Object.create({name: 'host1',status: '',message: '',progress: '',logTasks: []}),
+          Em.Object.create({name: 'host2',status: '',message: '',progress: '',logTasks: []})
+        ],
+        polledData: {
+          tasks:[
+            {Tasks: {host_name: 'host1',status: 'IN_PROGRESS'}},
+            {Tasks: {host_name: 'host2',status: 'IN_PROGRESS'}}
+          ]
+        },
+        e: {hosts:{host1: {progress: '12'},host2: {progress: '12'}},progress: '12'},
+        m: 'Two hosts. Each host has one task IN_PROGRESS. Cluster status is PENDING'
+      },
+      {
+        cluster: {status: 'PENDING'},
+        hosts: [
+          Em.Object.create({name: 'host1',status: '',message: '',progress: '',logTasks: []}),
+          Em.Object.create({name: 'host2',status: '',message: '',progress: '',logTasks: []})
+        ],
+        polledData: {
+          tasks:[
+            {Tasks: {host_name: 'host1',status: 'QUEUED'}},
+            {Tasks: {host_name: 'host2',status: 'QUEUED'}}
+          ]
+        },
+        e: {
+          hosts:{
+            host1: {progress: '3'},
+            host2: {progress: '3'}
+          },
+          progress: '3'
+        },
+        m: 'Two hosts. Each host has one task QUEUED. Cluster status is PENDING'
+      },
+      {
+        cluster: {status: 'INSTALLED'},
+        hosts: [
+          Em.Object.create({name: 'host1',status: '',message: '',progress: '',logTasks: []}),
+          Em.Object.create({name: 'host2',status: '',message: '',progress: '',logTasks: []})
+        ],
+        polledData: {
+          tasks:[
+            {Tasks: {host_name: 'host2',status: 'COMPLETED'}},
+            {Tasks: {host_name: 'host2',status: 'COMPLETED'}}
+          ]
+        },
+        e: {
+          hosts:{
+            host1: {progress: '100'},
+            host2: {progress: '100'}
+          },
+          progress: '100'
+        },
+        m: 'Two hosts. One host without tasks. Second host has all tasks COMPLETED. Cluster status is INSTALLED'
+      },
+      {
+        cluster: {status: 'INSTALLED'},
+        hosts: [
+          Em.Object.create({name: 'host1',status: '',message: '',progress: '',logTasks: []}),
+          Em.Object.create({name: 'host2',status: '',message: '',progress: '',logTasks: []})
+        ],
+        polledData: {
+          tasks:[
+            {Tasks: {host_name: 'host1',status: 'IN_PROGRESS'}},
+            {Tasks: {host_name: 'host2',status: 'IN_PROGRESS'}}
+          ]
+        },
+        e: {
+          hosts:{
+            host1: {progress: '58'},
+            host2: {progress: '58'}
+          },
+          progress: '58'
+        },
+        m: 'Two hosts. Each host has one task IN_PROGRESS. Cluster status is INSTALLED'
+      },
+      {
+        cluster: {status: 'INSTALLED'},
+        hosts: [
+          Em.Object.create({name: 'host1',status: '',message: '',progress: '',logTasks: []}),
+          Em.Object.create({name: 'host2',status: '',message: '',progress: '',logTasks: []})
+        ],
+        polledData: {
+          tasks:[
+            {Tasks: {host_name: 'host1',status: 'QUEUED'}},
+            {Tasks: {host_name: 'host2',status: 'QUEUED'}}
+          ]
+        },
+        e: {
+          hosts:{
+            host1: {progress: '40'},
+            host2: {progress: '40'}
+          },
+          progress: '40'
+        },
+        m: 'Two hosts. Each host has one task QUEUED. Cluster status is INSTALLED'
+      }
+    ];
+    tests.forEach(function(test) {
+      it(test.m, function() {
+        var controller = App.WizardStep9Controller.create({hosts: test.hosts, content: {cluster:{status: test.cluster.status}}, finishState: function(){return false;}});
+        controller.parseHostInfo(test.polledData);
+        for (var name in test.e.hosts) {
+          expect(controller.get('hosts').findProperty('name', name).get('progress')).to.equal(test.e.hosts[name].progress);
+        }
+        expect(controller.get('progress')).to.equal(test.e.progress);
+      });
+    });
+  });
 
 
+});

+ 112 - 0
ambari-web/test/views/wizard/step9_view_test.js

@@ -0,0 +1,112 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var App = require('app');
+require('views/wizard/step9_view');
+
+describe('App.HostStatusView', function () {
+  var tests = [
+    {
+      p: 'isFailed',
+      tests: [
+        {
+          controller: {isStepCompleted: true},
+          obj: {status: 'failed'},
+          e: true
+        },
+        {
+          controller: {isStepCompleted: false},
+          obj: {status: 'failed'},
+          e: false
+        },
+        {
+          controller: {isStepCompleted: true},
+          obj: {status: 'success'},
+          e: false
+        },
+        {
+          controller: {isStepCompleted: false},
+          obj: {status: 'success'},
+          e: false
+        }
+      ]
+    },
+    {
+      p: 'isSuccess',
+      tests: [
+        {
+          controller: {isStepCompleted: true},
+          obj: {status: 'success'},
+          e: true
+        },
+        {
+          controller: {isStepCompleted: false},
+          obj: {status: 'success'},
+          e: false
+        },
+        {
+          controller: {isStepCompleted: true},
+          obj: {status: 'failed'},
+          e: false
+        },
+        {
+          controller: {isStepCompleted: false},
+          obj: {status: 'failed'},
+          e: false
+        }
+      ]
+    },
+    {
+      p: 'isWarning',
+      tests: [
+        {
+          controller: {isStepCompleted: true},
+          obj: {status: 'warning'},
+          e: true
+        },
+        {
+          controller: {isStepCompleted: false},
+          obj: {status: 'warning'},
+          e: false
+        },
+        {
+          controller: {isStepCompleted: true},
+          obj: {status: 'failed'},
+          e: false
+        },
+        {
+          controller: {isStepCompleted: false},
+          obj: {status: 'failed'},
+          e: false
+        }
+      ]
+    }
+  ];
+  tests.forEach(function(test) {
+    describe(test.p, function() {
+      test.tests.forEach(function(t) {
+        var hostStatusView = App.HostStatusView.create();
+        it('controller.isStepCompleted = ' + t.controller.isStepCompleted + '; obj.status = ' + t.obj.status, function() {
+          hostStatusView.set('controller', t.controller);
+          hostStatusView.set('obj', t.obj);
+          expect(hostStatusView.get(test.p)).to.equal(t.e);
+        });
+      });
+    });
+  });
+});