浏览代码

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/step6_test');
 require('test/installer/step7_test');
+require('test/installer/step9_test');
 require('test/installer/step10_test');
 require('test/login_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/namenode_cpu_test');
 require('test/views/common/configs/services_config_test');
+require('test/views/wizard/step9_view_test');
 require('test/models/host_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,
 
   isSubmitDisabled: function () {
-    // return !this.get('isStepCompleted');
     var validStates = ['STARTED','START FAILED'];
     if (this.get('content.controllerName') == 'addHostController') {
       validStates.push('INSTALL FAILED');
@@ -46,12 +45,14 @@ App.WizardStep9Controller = Em.Controller.extend({
   mockDataPrefix: '/data/wizard/deploy/5_hosts',
   pollDataCounter: 0,
   polledData: [],
+  numPolls: 1,
+  POLL_INTERVAL: 4000,
 
   status: function () {
-    if (this.hosts.someProperty('status', 'failed')) {
+    if (this.get('hosts').someProperty('status', 'failed')) {
       return 'failed';
     }
-    if (this.hosts.someProperty('status', 'warning')) {
+    if (this.get('hosts').someProperty('status', 'warning')) {
       if (this.isStepFailed()) {
         return 'failed';
       } else {
@@ -65,6 +66,10 @@ App.WizardStep9Controller = Em.Controller.extend({
     return 'info';
   }.property('hosts.@each.status', 'progress'),
 
+  showRetry: function () {
+    return this.get('content.cluster.status') == 'INSTALL FAILED';
+  }.property('content.cluster.status'),
+
   categoryObject: Em.Object.extend({
     hostsCount: function () {
       var category = this;
@@ -80,12 +85,6 @@ App.WizardStep9Controller = Em.Controller.extend({
       return "%@ (%@)".fmt(this.get('value'), this.get('hostsCount'));
     }.property('value', 'hostsCount')
   }),
-  getCategory: function(field, value){
-    return this.get('categories').find(function(item){
-      return item.get(field) == value;
-    });
-  },
-
   categories: function () {
     var self = this;
     self.categoryObject.reopen({
@@ -111,7 +110,6 @@ App.WizardStep9Controller = Em.Controller.extend({
     this.set('category', categories.get('firstObject'));
     return categories;
   }.property(),
-
   category: false,
   visibleHosts: function(){
     var targetStatus = this.get('category.hostStatus');
@@ -127,13 +125,17 @@ App.WizardStep9Controller = Em.Controller.extend({
     return visibleHosts;
   }.property('category', 'hosts.@each.status'),
 
+  logTasksChangesCounter: 0,
+
   selectCategory: function(event){
     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:
   // PENDING: set upon successful transition from step 1 to step 2
@@ -186,11 +188,11 @@ App.WizardStep9Controller = Em.Controller.extend({
     }
   },
   clearStep: function () {
-    this.hosts.clear();
+    this.get('hosts').clear();
     this.set('status', 'info');
     this.set('progress', '0');
     this.set('isStepCompleted', false);
-    this.numPolls = 1;
+    this.set('numPolls', 1);
   },
 
   loadStep: function () {
@@ -238,7 +240,7 @@ App.WizardStep9Controller = Em.Controller.extend({
         progress: _hostInfo.progress
       });
       console.log('pushing ' + hostInfo.name);
-      this.hosts.pushObject(hostInfo);
+      this.get('hosts').pushObject(hostInfo);
     }, this);
   },
 
@@ -330,6 +332,7 @@ App.WizardStep9Controller = Em.Controller.extend({
             return role + Em.I18n.t('installer.step9.serviceStatus.abort.failed');
         }
     }
+    return '';
   },
 
   /**
@@ -364,7 +367,7 @@ App.WizardStep9Controller = Em.Controller.extend({
     }
     data = JSON.stringify(data);
     if (App.testMode) {
-      this.numPolls = 6;
+      this.set('numPolls', 6);
     }
 
     App.ajax.send({
@@ -380,12 +383,13 @@ App.WizardStep9Controller = Em.Controller.extend({
   },
 
   launchStartServicesSuccessCallback: function (jsonData) {
+    var clusterStatus = {};
     if (jsonData) {
       console.log("TRACE: Step9 -> In success function for the startService call");
       console.log("TRACE: Step9 -> value of the received data is: " + jsonData);
       var requestId = jsonData.Requests.id;
       console.log('requestId is: ' + requestId);
-      var clusterStatus = {
+      clusterStatus = {
         status: 'INSTALLED',
         requestId: requestId,
         isStartError: false,
@@ -396,7 +400,7 @@ App.WizardStep9Controller = Em.Controller.extend({
     } else {
       console.log('ERROR: Error occurred in parsing JSON data');
       this.hostHasClientsOnly(true);
-      var clusterStatus = {
+      clusterStatus = {
         status: 'STARTED',
         isStartError: false,
         isCompleted: true
@@ -418,12 +422,14 @@ App.WizardStep9Controller = Em.Controller.extend({
   },
 
   hostHasClientsOnly: function(jsonError) {
-    this.hosts.forEach(function(host){
+    this.get('hosts').forEach(function(host){
       var OnlyClients = true;
       var tasks = host.get('logTasks');
       tasks.forEach(function(task){
         var component = serviceComponents.findProperty('component_name',task.Tasks.role);
-        (component && component.isClient) ? null : OnlyClients = false;
+        if(!(component && component.isClient)) {
+          OnlyClients = false;
+        }
       });
       if (OnlyClients || jsonError) {
         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
   onSuccessPerHost: function (actions, contentHost) {
+    if (!actions) return;
     if (actions.everyProperty('Tasks.status', 'COMPLETED') && this.get('content.cluster.status') === 'INSTALLED') {
       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
   // to find which host FAILED occurred on, if any
   onErrorPerHost: function (actions, contentHost) {
+    if (!actions) return;
     if (actions.someProperty('Tasks.status', 'FAILED') || actions.someProperty('Tasks.status', 'ABORTED') || actions.someProperty('Tasks.status', 'TIMEDOUT')) {
       contentHost.set('status', 'warning');
     }
@@ -473,13 +481,14 @@ App.WizardStep9Controller = Em.Controller.extend({
     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) {
-      runningAction = tasks.findProperty('Tasks.status', 'QUEUED');
+      runningAction = actions.findProperty('Tasks.status', 'QUEUED');
     }
     if (runningAction === undefined || runningAction === null) {
-      runningAction = tasks.findProperty('Tasks.status', 'PENDING');
+      runningAction = actions.findProperty('Tasks.status', 'PENDING');
     }
     if (runningAction !== null && runningAction !== undefined) {
       contentHost.set('message', this.displayMessage(runningAction.Tasks));
@@ -510,10 +519,10 @@ App.WizardStep9Controller = Em.Controller.extend({
      */
     switch (this.get('content.cluster.status')) {
       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;
       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;
       default:
         progress = 100;
@@ -568,54 +577,74 @@ App.WizardStep9Controller = Em.Controller.extend({
   // returns true if polling should stop; false otherwise
   // polling from ui stops only when no action has 'PENDING', 'QUEUED' or 'IN_PROGRESS' status
   finishState: function (polledData) {
-    var clusterStatus = {};
-    var requestId = this.get('content.cluster.requestId');
     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.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');
+      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 false;
@@ -625,35 +654,26 @@ App.WizardStep9Controller = Em.Controller.extend({
     var tasksData = this.get('polledData');
     this.get('hosts').forEach(function (_host) {
       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) {
         tasksPerHost.forEach(function (_taskPerHost) {
           console.log('In step9 _taskPerHost function.');
-          //if (_taskPerHost.Tasks.status !== 'PENDING' && _taskPerHost.Tasks.status !== 'QUEUED' &&  _taskPerHost.Tasks.status !== 'IN_PROGRESS') {
           _host.tasks.pushObject(_taskPerHost);
-          //}
         }, this);
       }
     }, this);
   },
 
-  logTasksChangesCounter: 0,
-
   // This is done at HostRole level.
   setLogTasksStatePerHost: function (tasksPerHost, host) {
+    if (!tasksPerHost) return;
     console.log('In step9 setTasksStatePerHost function.');
     tasksPerHost.forEach(function (_task) {
       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);
       if (task) {
         host.logTasks.removeObject(task);
       }
       host.logTasks.pushObject(_task);
-      //}
     }, this);
     this.set('logTasksChangesCounter', this.get('logTasksChangesCounter') + 1);
   },
@@ -669,34 +689,34 @@ App.WizardStep9Controller = Em.Controller.extend({
     }
     var requestId = this.get('content.cluster.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.
-      // 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.
       return false;
     }
     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
       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');
         }
+        if(this.get('content.cluster.status') === 'INSTALLED') {
+          _host.set('progress', '100');
+        }
         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') {
         _host.set('message', this.t('installer.step9.host.status.nothingToInstall'));
       }
     }, this);
-    totalProgress = Math.floor(totalProgress / this.hosts.length);
+    totalProgress = Math.floor(totalProgress / this.get('hosts.length'));
     this.set('progress', totalProgress.toString());
     console.log("INFO: right now the progress is: " + this.get('progress'));
     return this.finishState(tasksData);
@@ -707,8 +727,6 @@ App.WizardStep9Controller = Em.Controller.extend({
     this.doPolling();
   },
 
-  numPolls: 1,
-
   getUrl: function (requestId) {
     var clusterName = this.get('content.cluster.name');
     var requestId = requestId || this.get('content.cluster.requestId');
@@ -717,8 +735,6 @@ App.WizardStep9Controller = Em.Controller.extend({
     return url;
   },
 
-  POLL_INTERVAL: 4000,
-
   loadLogData: function(requestId) {
     var url = this.getUrl(requestId);
     var requestsId = App.db.getCluster().oldRequestsId;
@@ -746,9 +762,10 @@ App.WizardStep9Controller = Em.Controller.extend({
       timeout: App.timeout,
       dataType: 'text',
       success: function (data) {
+        var parsedData = jQuery.parseJSON(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) {
           return;
         }
@@ -804,4 +821,4 @@ App.WizardStep9Controller = Em.Controller.extend({
       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') {
         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('obj.message', Em.I18n.t('installer.step9.host.status.success'));
       }
-  }.observes('obj.status', 'obj.progress'),
+    }
+  }.observes('obj.status', 'obj.progress', 'controller.progress'),
 
   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'),
 
   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'),
 
   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'),
 
   isHostCompleted:function () {

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

@@ -22,144 +22,951 @@ var App = require('app');
 require('models/hosts');
 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);
+        });
+      });
+    });
+  });
+});