Browse Source

AMBARI-14568. Write UT for Wizard controllers (onechiporenko)

Oleg Nechiporenko 9 years ago
parent
commit
15a33a5929

+ 1 - 1
ambari-web/app/controllers/wizard/step3_controller.js

@@ -1373,7 +1373,7 @@ App.WizardStep3Controller = Em.Controller.extend(App.ReloadPopupMixin, {
       var name = Em.I18n.t('installer.step3.hostWarningsPopup.resolution.validation.error');
       var hostInfo = this.get("hostCheckWarnings").findProperty('name', name);
       if (["FAILED", "COMPLETED", "TIMEDOUT"].contains(task.Tasks.status)) {
-        if (task.Tasks.status == "COMPLETED" && Em.get(task, "Tasks.structured_out.host_resolution_check.failed_count") != 0) {
+        if (task.Tasks.status === "COMPLETED" && !!Em.get(task, "Tasks.structured_out.host_resolution_check.failed_count")) {
           var targetHostName = Em.get(task, "Tasks.host_name");
           var relatedHostNames = Em.get(task, "Tasks.structured_out.host_resolution_check.failures")
             ? Em.get(task, "Tasks.structured_out.host_resolution_check.failures").mapProperty('host') : [];

+ 1 - 1
ambari-web/app/controllers/wizard/step7_controller.js

@@ -1349,7 +1349,7 @@ App.WizardStep7Controller = Em.Controller.extend(App.ServerValidatorMixin, App.E
       if (!stackProperty || !this.get('installedServices')[stackProperty.serviceName]) {
         return true;
       } else if (stackProperty.propertyDependsOn.length) {
-        return stackProperty.propertyDependsOn.filter(function (p) {
+        return !!stackProperty.propertyDependsOn.filter(function (p) {
           var service = App.config.getServiceByConfigType(p.type);
           return service && !this.get('installedServices')[service.get('serviceName')];
         }, this).length;

+ 24 - 25
ambari-web/app/controllers/wizard/step9_controller.js

@@ -847,34 +847,33 @@ App.WizardStep9Controller = Em.Controller.extend(App.ReloadPopupMixin, {
           self.changeParseHostInfo(false);
         });
         return;
+      }
+      if (App.get('supports.skipComponentStartAfterInstall')) {
+        clusterStatus.status = 'START_SKIPPED';
+        clusterStatus.isCompleted = true;
+        this.saveClusterStatus(clusterStatus);
+        this.get('hosts').forEach(function (host) {
+          host.set('status', 'success');
+          host.set('message', Em.I18n.t('installer.step9.host.status.success'));
+          host.set('progress', '100');
+        });
+        this.set('progress', '100');
+        self.saveInstalledHosts(self);
+        this.changeParseHostInfo(true);
       } else {
-        if (App.get('supports.skipComponentStartAfterInstall')) {
-          clusterStatus.status = 'START_SKIPPED';
-          clusterStatus.isCompleted = true;
-          this.saveClusterStatus(clusterStatus);
-          this.get('hosts').forEach(function (host) {
-            host.set('status', 'success');
-            host.set('message', Em.I18n.t('installer.step9.host.status.success'));
-            host.set('progress', '100');
+        this.set('progress', '34');
+        if (this.get('content.controllerName') === 'installerController') {
+          this.isAllComponentsInstalled().done(function () {
+            self.saveInstalledHosts(self);
+            self.changeParseHostInfo(true);
           });
-          this.set('progress', '100');
-          self.saveInstalledHosts(self);
-          this.changeParseHostInfo(true);
+          return;
         } else {
-          this.set('progress', '34');
-          if (this.get('content.controllerName') === 'installerController') {
-            this.isAllComponentsInstalled().done(function () {
-              self.saveInstalledHosts(self);
-              self.changeParseHostInfo(true);
-            });
-            return;
-          } else {
-            this.launchStartServices(function () {
-              self.saveInstalledHosts(self);
-              self.changeParseHostInfo(true);
-            });
-            return;
-          }
+          this.launchStartServices(function () {
+            self.saveInstalledHosts(self);
+            self.changeParseHostInfo(true);
+          });
+          return;
         }
       }
     }

+ 144 - 11
ambari-web/test/controllers/wizard/step3_test.js

@@ -16,8 +16,6 @@
  * limitations under the License.
  */
 
-
-var Ember = require('ember');
 var App = require('app');
 var c;
 require('utils/ajax/ajax');
@@ -606,17 +604,25 @@ describe('App.WizardStep3Controller', function () {
     it('shouldn\'t do nothing if isRetryDisabled is true', function () {
       c.set('isRetryDisabled', true);
       c.retrySelectedHosts();
-      expect(c.retryHosts.called).to.equal(false);
-    });
-
-    it('should retry hosts with FAILED bootStatus and set isRetryDisabled to true', function () {
-      c.set('isRetryDisabled', false);
-      c.set('bootHosts', Em.A([Em.Object.create({name: 'c1', bootStatus: 'FAILED'}), Em.Object.create({name: 'c2', bootStatus: 'REGISTERED'})]));
+      expect(c.retryHosts.called).to.be.false;
+    });
+
+    it('should retry hosts with FAILED bootStatus', function () {
+      c.set('bootHosts', Em.A([
+        Em.Object.create({
+          name: 'c1',
+          bootStatus: 'FAILED'
+        }),
+        Em.Object.create({
+          name: 'c2',
+          bootStatus: 'REGISTERED'
+        })
+      ]));
+      c.reopen({isRetryDisabled: false});
       c.retrySelectedHosts();
       expect(c.retryHosts.calledWith([
-        {name: 'c1', bootStatus: 'RUNNING'}
-      ]));
-      expect(c.get('isRetryDisabled')).to.equal(true);
+        Em.Object.create({name: 'c1', bootStatus: 'DONE', bootLog: 'Retrying ...'})
+      ])).to.be.true;
     });
 
   });
@@ -3080,4 +3086,131 @@ describe('App.WizardStep3Controller', function () {
     });
 
   });
+
+  describe('#hostsInCluster', function () {
+
+    var hosts = {
+      host1: {isInstalled: true},
+      host2: {isInstalled: false},
+      host3: {isInstalled: true},
+      host4: {isInstalled: false}
+    };
+
+    beforeEach(function () {
+      c.set('content', {hosts: hosts});
+      c.propertyDidChange('hostsInCluster');
+    });
+
+    it('should take only installed hosts', function () {
+      expect(c.get('hostsInCluster')).to.be.eql(['host1', 'host3']);
+    });
+
+  });
+
+  describe('#filterHostsData', function () {
+
+    var bootHosts = [
+      Em.Object.create({name: 'c1'}),
+      Em.Object.create({name: 'c2'}),
+      Em.Object.create({name: 'c3'})
+    ];
+
+    var data = {
+      href: 'abc',
+      tasks: [
+        {Tasks: {host_name: 'c1'}},
+        {Tasks: {host_name: 'c2'}},
+        {Tasks: {host_name: 'c3'}},
+        {Tasks: {host_name: 'c2'}},
+        {Tasks: {host_name: 'c3'}},
+        {Tasks: {host_name: 'c4'}}
+      ]
+    };
+
+    beforeEach(function() {
+      c.set('bootHosts', bootHosts);
+      this.result = c.filterHostsData(data);
+    });
+
+    it('href is valid', function () {
+      expect(this.result.href).to.be.equal('abc');
+    });
+
+    it('tasks are valid', function () {
+      expect(this.result.tasks).to.be.eql([
+        {Tasks: {host_name: 'c1'}},
+        {Tasks: {host_name: 'c2'}},
+        {Tasks: {host_name: 'c3'}},
+        {Tasks: {host_name: 'c2'}},
+        {Tasks: {host_name: 'c3'}}
+      ]);
+    });
+
+
+  });
+
+  describe('#parseHostNameResolution', function () {
+
+    var data = {
+      tasks: [
+        {Tasks: {status: 'COMPLETED', host_name: 'h1', structured_out: {host_resolution_check: {failed_count: 2, failures: [{host: 'h2'}, {host: 'h3'}]}}}},
+        {Tasks: {status: 'COMPLETED', host_name: 'h4', structured_out: {host_resolution_check: {failed_count: 2, failures: [{host: 'h5'}, {host: 'h6'}]}}}},
+        {Tasks: {status: 'COMPLETED', host_name: 'h7', structured_out: {host_resolution_check: {failed_count: 1, failures: [{host: 'h8'}]}}}}
+      ]
+    };
+    var hostCheckWarnings = [];
+
+    beforeEach(function () {
+      c.set('hostCheckWarnings', hostCheckWarnings);
+      c.parseHostNameResolution(data);
+      this.warnings = c.get('hostCheckWarnings').findProperty('name', Em.I18n.t('installer.step3.hostWarningsPopup.resolution.validation.error'));
+    });
+
+    it('Host check warnings for hostname resolutions exist', function () {
+      expect(this.warnings).to.exist;
+    });
+
+    it('hostsNames are ["h1", "h4", "h7"]', function () {
+      expect(this.warnings.hostsNames.toArray()).to.be.eql(['h1', 'h4', 'h7']);
+    });
+
+    it('warning appears on many hosts', function () {
+      expect(this.warnings.onSingleHost).to.be.false;
+    });
+
+    it('validation context for hosts is valid', function () {
+      var hosts = this.warnings.hosts;
+      var expected = [
+        Em.I18n.t('installer.step3.hostWarningsPopup.resolution.validation.context').format('h1', 2 + ' ' + Em.I18n.t('installer.step3.hostWarningsPopup.hosts')),
+        Em.I18n.t('installer.step3.hostWarningsPopup.resolution.validation.context').format('h4', 2 + ' ' + Em.I18n.t('installer.step3.hostWarningsPopup.hosts')),
+        Em.I18n.t('installer.step3.hostWarningsPopup.resolution.validation.context').format('h7', 1 + ' ' + Em.I18n.t('installer.step3.hostWarningsPopup.host'))
+      ];
+      expect(hosts).to.be.eql(expected);
+    });
+
+    it('validation context (long) for hosts is valid', function () {
+      var hostsLong = this.warnings.hostsLong;
+      var expected = [
+        Em.I18n.t('installer.step3.hostWarningsPopup.resolution.validation.context').format('h1', 'h2, h3'),
+        Em.I18n.t('installer.step3.hostWarningsPopup.resolution.validation.context').format('h4', 'h5, h6'),
+        Em.I18n.t('installer.step3.hostWarningsPopup.resolution.validation.context').format('h7', 'h8')
+      ];
+      expect(hostsLong).to.be.eql(expected);
+    });
+
+  });
+
+  describe('#getHostCheckTasksError', function () {
+
+    beforeEach(function () {
+      c.set('stopChecking', false);
+    });
+
+    it('should set `stopChecking` to true', function () {
+      c.getHostCheckTasksError();
+      expect(c.get('stopChecking')).to.be.true;
+    });
+
+  });
+
 });

+ 50 - 0
ambari-web/test/controllers/wizard/step4_test.js

@@ -866,4 +866,54 @@ describe('App.WizardStep4Controller', function () {
 
   });
 
+  describe('Service warnings popup', function () {
+
+    var target = {
+      clb: Em.K
+    };
+    var id = 1;
+
+    beforeEach(function () {
+      sinon.spy(target, 'clb');
+      sinon.stub(controller, 'onPrimaryPopupCallback', Em.K);
+    });
+
+    afterEach(function () {
+      target.clb.restore();
+      controller.onPrimaryPopupCallback.restore();
+    });
+
+    Em.A([
+      'ambariMetricsCheckPopup',
+      'rangerRequirementsPopup',
+      'sparkWarningPopup'
+    ]).forEach(function (methodName) {
+
+      describe('#' + methodName, function () {
+
+        beforeEach(function () {
+          this.popup = controller[methodName](target.clb, id);
+        });
+
+        it('#onPrimary', function () {
+          this.popup.onPrimary();
+          expect(controller.onPrimaryPopupCallback.calledWith(target.clb)).to.be.true;
+        });
+
+        it('#onSecondary', function () {
+          this.popup.onSecondary();
+          expect(target.clb.calledWith(id)).to.be.true;
+        });
+
+        it('#onClose', function () {
+          this.popup.onClose();
+          expect(target.clb.calledWith(id)).to.be.true;
+        });
+
+      });
+
+    });
+
+  });
+
 });

+ 224 - 6
ambari-web/test/controllers/wizard/step6_test.js

@@ -16,7 +16,6 @@
  * limitations under the License.
  */
 
-var Ember = require('ember');
 var App = require('app');
 var validationUtils = require('utils/validator');
 require('utils/helper');
@@ -46,7 +45,7 @@ var controller,
   ];
 
 function getController() {
-  var controller = App.WizardStep6Controller.create({
+  var c = App.WizardStep6Controller.create({
     content: Em.Object.create({
       hosts: {},
       masterComponentHosts: {},
@@ -66,10 +65,10 @@ function getController() {
     m.push(obj);
   });
 
-  controller.set('content.hosts', h);
-  controller.set('content.masterComponentHosts', m);
-  controller.set('isMasters', false);
-  return controller;
+  c.set('content.hosts', h);
+  c.set('content.masterComponentHosts', m);
+  c.set('isMasters', false);
+  return c;
 }
 
 describe('App.WizardStep6Controller', function () {
@@ -1617,4 +1616,223 @@ describe('App.WizardStep6Controller', function () {
 
   });
 
+  describe('#isAllCheckboxesEmpty', function () {
+
+    Em.A([
+      {
+        m: 'all checkboxes are not empty',
+        hosts: [
+          {checkboxes: [{checked: true}, {checked: true}]},
+          {checkboxes: [{checked: true}, {checked: true}]}
+        ],
+        e: false
+      },
+      {
+        m: 'some checkboxes are empty',
+        hosts: [
+          {checkboxes: [{checked: true}, {checked: false}]},
+          {checkboxes: [{checked: true}, {checked: false}]}
+        ],
+        e: false
+      },
+      {
+        m: 'all checkboxes are empty',
+        hosts: [
+          {checkboxes: [{checked: false}, {checked: false}]},
+          {checkboxes: [{checked: false}, {checked: false}]}
+        ],
+        e: true
+      }
+    ]).forEach(function (test) {
+
+      it(test.m, function () {
+        controller.set('hosts', test.hosts);
+        expect(controller.isAllCheckboxesEmpty()).to.be.equal(test.e);
+      });
+
+    });
+
+  });
+
+  describe('#loadStep', function () {
+
+    beforeEach(function () {
+      sinon.stub(controller, 'render', Em.K);
+      sinon.stub(controller, 'callValidation', Em.K);
+      sinon.stub(App.StackService, 'find').returns([
+        Em.Object.create({
+          isSelected: true,
+          serviceName: 's1',
+          serviceComponents: [
+            Em.Object.create({isShownOnInstallerSlaveClientPage: true, componentName: 's1c1', isRequired: true}),
+            Em.Object.create({isShownOnInstallerSlaveClientPage: true, componentName: 's1c2', isRequired: true})
+          ]
+        }),
+        Em.Object.create({
+          isSelected: true,
+          serviceName: 's2',
+          serviceComponents: [
+            Em.Object.create({isShownOnInstallerSlaveClientPage: true, componentName: 's2c3', isRequired: false}),
+            Em.Object.create({isShownOnInstallerSlaveClientPage: true, componentName: 's2c4', isRequired: false})
+          ]
+        }),
+        Em.Object.create({
+          isInstalled: true,
+          serviceName: 's3',
+          serviceComponents: [
+            Em.Object.create({isShownOnInstallerSlaveClientPage: true, componentName: 's3c1', isRequired: true}),
+            Em.Object.create({isShownOnInstallerSlaveClientPage: true, componentName: 's3c2', isRequired: true})
+          ]
+        }),
+        Em.Object.create({
+          isInstalled: true,
+          serviceName: 's4',
+          serviceComponents: [
+            Em.Object.create({isShownOnInstallerSlaveClientPage: true, componentName: 's4c3', isRequired: false}),
+            Em.Object.create({isShownOnInstallerSlaveClientPage: true, componentName: 's4c4', isRequired: false})
+          ]
+        })
+      ]);
+    });
+
+    afterEach(function () {
+      controller.render.restore();
+      controller.callValidation.restore();
+      App.StackService.find.restore();
+    });
+
+    describe('isInstallerWizard', function () {
+
+      beforeEach(function () {
+        controller.set('content', {
+          clients: [{}],
+          controllerName: 'installerController'
+        });
+        controller.loadStep();
+      });
+
+      it('component names are valid', function () {
+        expect(controller.get('headers').mapProperty('name')).to.be.eql(['s1c1', 's1c2', 's2c3', 's2c4', 'CLIENT']);
+      });
+
+      it('component labels are valid', function () {
+        expect(controller.get('headers').mapProperty('label')).to.be.eql(['S1c1', 'S1c2', 'S2c3', 'S2c4', 'Client']);
+      });
+
+      it('everyone allChecked is false', function () {
+        expect(controller.get('headers').everyProperty('allChecked', false)).to.be.true;
+      });
+
+      it('component required-flags are valid', function () {
+        expect(controller.get('headers').mapProperty('isRequired')).to.be.eql([true, true, false, false, undefined]);
+      });
+
+      it('everyone noChecked is false', function () {
+        expect(controller.get('headers').everyProperty('noChecked', true)).to.be.true;
+      });
+
+      it('everyone isDisabled is false', function () {
+        expect(controller.get('headers').everyProperty('isDisabled', false)).to.be.true;
+      });
+
+      it('component allId-fields are valid', function () {
+        expect(controller.get('headers').mapProperty('allId')).to.be.eql(['all-s1c1', 'all-s1c2', 'all-s2c3', 'all-s2c4', 'all-CLIENT']);
+      });
+
+      it('component noneId-fields are valid', function () {
+        expect(controller.get('headers').mapProperty('noneId')).to.be.eql(['none-s1c1', 'none-s1c2', 'none-s2c3', 'none-s2c4', 'none-CLIENT']);
+      });
+
+    });
+
+    describe('isAddHostWizard', function () {
+
+      beforeEach(function () {
+        controller.set('content', {
+          clients: [{}],
+          controllerName: 'addHostController'
+        });
+        controller.loadStep();
+      });
+
+      it('component names are valid', function () {
+        expect(controller.get('headers').mapProperty('name')).to.be.eql(['s3c1', 's3c2', 's4c3', 's4c4', 'CLIENT']);
+      });
+
+      it('component labels are valid', function () {
+        expect(controller.get('headers').mapProperty('label')).to.be.eql(['S3c1', 'S3c2', 'S4c3', 'S4c4', 'Client']);
+      });
+
+      it('everyone allChecked is false', function () {
+        expect(controller.get('headers').everyProperty('allChecked', false)).to.be.true;
+      });
+
+      it('component required-flags are valid', function () {
+        expect(controller.get('headers').mapProperty('isRequired')).to.be.eql([true, true, false, false, undefined]);
+      });
+
+      it('everyone noChecked is false', function () {
+        expect(controller.get('headers').everyProperty('noChecked', true)).to.be.true;
+      });
+
+      it('everyone isDisabled is false', function () {
+        expect(controller.get('headers').everyProperty('isDisabled', false)).to.be.true;
+      });
+
+      it('component allId-fields are valid', function () {
+        expect(controller.get('headers').mapProperty('allId')).to.be.eql(['all-s3c1', 'all-s3c2', 'all-s4c3', 'all-s4c4', 'all-CLIENT']);
+      });
+
+      it('component noneId-fields are valid', function () {
+        expect(controller.get('headers').mapProperty('noneId')).to.be.eql(['none-s3c1', 'none-s3c2', 'none-s4c3', 'none-s4c4', 'none-CLIENT']);
+      });
+
+    });
+
+    describe('isAddServiceWizard', function () {
+
+      beforeEach(function () {
+        controller.set('content', {
+          clients: [{}],
+          controllerName: 'addServiceController'
+        });
+        controller.loadStep();
+      });
+
+      it('component names are valid', function () {
+        expect(controller.get('headers').mapProperty('name')).to.be.eql(['s3c1', 's3c2', 's4c3', 's4c4', 's1c1', 's1c2', 's2c3', 's2c4', 'CLIENT']);
+      });
+
+      it('component labels are valid', function () {
+        expect(controller.get('headers').mapProperty('label')).to.be.eql(['S3c1', 'S3c2', 'S4c3', 'S4c4', 'S1c1', 'S1c2', 'S2c3', 'S2c4', 'Client']);
+      });
+
+      it('everyone allChecked is false', function () {
+        expect(controller.get('headers').everyProperty('allChecked', false)).to.be.true;
+      });
+
+      it('component required-flags are valid', function () {
+        expect(controller.get('headers').mapProperty('isRequired')).to.be.eql([true, true, false, false, true, true, false, false, undefined]);
+      });
+
+      it('everyone noChecked is false', function () {
+        expect(controller.get('headers').everyProperty('noChecked', true)).to.be.true;
+      });
+
+      it('installed services are disabled', function () {
+        expect(controller.get('headers').mapProperty('isDisabled', false)).to.be.eql([true, true, true, true, false, false, false, false, false]);
+      });
+
+      it('component allId-fields are valid', function () {
+        expect(controller.get('headers').mapProperty('allId')).to.be.eql(['all-s3c1', 'all-s3c2', 'all-s4c3', 'all-s4c4', 'all-s1c1', 'all-s1c2', 'all-s2c3', 'all-s2c4', 'all-CLIENT']);
+      });
+
+      it('component noneId-fields are valid', function () {
+        expect(controller.get('headers').mapProperty('noneId')).to.be.eql(['none-s3c1', 'none-s3c2', 'none-s4c3', 'none-s4c4', 'none-s1c1', 'none-s1c2', 'none-s2c3', 'none-s2c4', 'none-CLIENT']);
+      });
+
+    });
+
+  });
+
 });

+ 430 - 1
ambari-web/test/controllers/wizard/step7_test.js

@@ -17,7 +17,6 @@
  */
 
 var App = require('app');
-var numberUtils = require('utils/number_utils');
 require('mixins/common/localStorage');
 require('controllers/wizard/step7_controller');
 
@@ -1997,4 +1996,434 @@ describe('App.InstallerStep7Controller', function () {
 
   });
 
+  describe('#supportsPreInstallChecks', function () {
+
+    beforeEach(function () {
+      this.stub = sinon.stub(App, 'get');
+    });
+
+    afterEach(function () {
+      this.stub.restore();
+    });
+
+    Em.A([
+      {preInstallChecks: true, controllerName: 'installerController', e: true},
+      {preInstallChecks: true, controllerName: '', e: false},
+      {preInstallChecks: false, controllerName: 'installerController', e: false},
+      {preInstallChecks: false, controllerName: '', e: false}
+    ]).forEach(function (test) {
+
+      it(JSON.stringify(test), function () {
+        this.stub.withArgs('supports.preInstallChecks').returns(test.preInstallChecks);
+        installerStep7Controller.set('content', {controllerName: test.controllerName});
+        installerStep7Controller.propertyDidChange('supportsPreInstallChecks');
+
+        expect(installerStep7Controller.get('supportsPreInstallChecks')).to.be.equal(test.e);
+      });
+
+    });
+
+  });
+
+  describe('#getHash', function () {
+
+    var stepConfigs = [
+      {
+        configs: [
+          Em.Object.create({name: 's1c1', isFinal: true, value: 'v11'}),
+          Em.Object.create({name: 's1c2', isFinal: false, value: 'v12', overrides: []}),
+          Em.Object.create({name: 's1c3', isFinal: true, value: 'v13', overrides: [
+            Em.Object.create({value: 'v131'})
+          ]})
+        ]
+      },
+      {
+        configs: [
+          Em.Object.create({name: 's2c1', isFinal: true, value: 'v21'}),
+          Em.Object.create({name: 's2c2', isFinal: false, value: 'v22', overrides: []}),
+          Em.Object.create({name: 's2c3', isFinal: true, value: 'v23', overrides: [
+            Em.Object.create({value: 'v231'})
+          ]})
+        ]
+      }
+    ];
+
+    beforeEach(function () {
+      installerStep7Controller.set('stepConfigs', stepConfigs);
+      this.hash = installerStep7Controller.getHash();
+    });
+
+    it('should map value, isFinal and overrides values', function () {
+      var expected = JSON.stringify({
+        s1c1: {
+          value: 'v11',
+          overrides: [],
+          isFinal: true
+        },
+        s1c2: {
+          value: 'v12',
+          overrides: [],
+          isFinal: false
+        },
+        s1c3: {
+          value: 'v13',
+          overrides: ['v131'],
+          isFinal: true
+        },
+        s2c1: {
+          value: 'v21',
+          overrides: [],
+          isFinal: true
+        },
+        s2c2: {
+          value: 'v22',
+          overrides: [],
+          isFinal: false
+        },
+        s2c3: {
+          value: 'v23',
+          overrides: ['v231'],
+          isFinal: true
+        }
+      });
+      expect(this.hash).to.be.equal(expected);
+    });
+
+  });
+
+  describe('#loadServiceConfigGroupOverrides', function () {
+
+    var serviceConfigs = [
+      {filename: 'f1', name: 'n1'}
+    ];
+
+    var configGroups = [
+      {
+        "name": "Default",
+        "description": "desc",
+        "isDefault": true,
+        "hosts": ['h1', 'h2', 'h3'],
+        "parentConfigGroup": null,
+        "service": {"id": "YARN"},
+        "serviceName": "YARN",
+        "configSiteTags": [],
+        "clusterHosts": []
+      }
+    ];
+
+    var loadedGroupToOverrideSiteToTagMap = {
+      Default: {
+        type1: 'tag1',
+        type2: 'tag2',
+        type3: 'tag3'
+      }
+    };
+
+    beforeEach(function () {
+      installerStep7Controller.loadServiceConfigGroupOverrides(serviceConfigs, loadedGroupToOverrideSiteToTagMap, configGroups);
+      this.args = App.ajax.send.args[0][0].data;
+    });
+
+    it('url params are valid', function () {
+      expect(this.args.params).to.be.equal('(type=type1&tag=tag1)|(type=type2&tag=tag2)|(type=type3&tag=tag3)');
+    });
+
+    it('configKeyToConfigMap is valid', function () {
+      var expected = {
+        "f1": {
+          "n1": {
+            "filename": "f1",
+            "name": "n1"
+          }
+        }
+      };
+      expect(this.args.configKeyToConfigMap).to.be.eql(expected);
+    });
+
+    describe('typeTagToGroupMap is valid', function () {
+
+      it('type1///tag1', function () {
+        var expected = {
+          "name": "Default",
+          "description": "desc",
+          "isDefault": true,
+          "hosts": [
+            "h1",
+            "h2",
+            "h3"
+          ],
+          "parentConfigGroup": null,
+          "service": {
+            "id": "YARN"
+          },
+          "serviceName": "YARN",
+          "configSiteTags": [],
+          "clusterHosts": []
+        };
+
+        expect(this.args.typeTagToGroupMap['type1///tag1']).to.be.eql(expected);
+
+      });
+
+      it('type2///tag2', function () {
+        var expected = {
+          "name": "Default",
+          "description": "desc",
+          "isDefault": true,
+          "hosts": [
+            "h1",
+            "h2",
+            "h3"
+          ],
+          "parentConfigGroup": null,
+          "service": {
+            "id": "YARN"
+          },
+          "serviceName": "YARN",
+          "configSiteTags": [],
+          "clusterHosts": []
+        };
+
+        expect(this.args.typeTagToGroupMap['type2///tag2']).to.be.eql(expected);
+
+      });
+
+      it('type3///tag3', function () {
+        var expected = {
+          "name": "Default",
+          "description": "desc",
+          "isDefault": true,
+          "hosts": [
+            "h1",
+            "h2",
+            "h3"
+          ],
+          "parentConfigGroup": null,
+          "service": {
+            "id": "YARN"
+          },
+          "serviceName": "YARN",
+          "configSiteTags": [],
+          "clusterHosts": []
+        };
+
+        expect(this.args.typeTagToGroupMap['type3///tag3']).to.be.eql(expected);
+
+      });
+
+    });
+
+    it('serviceConfigs is valid', function () {
+
+      var expected = [
+        {
+          "filename": "f1",
+          "name": "n1"
+        }
+      ];
+
+      expect(this.args.serviceConfigs).to.be.eql(expected);
+
+    });
+
+  });
+
+  describe('#updateHostOverrides', function () {
+
+    var configProperty;
+    var storedConfigProperty;
+
+    beforeEach(function () {
+      configProperty = Em.Object.create({});
+      storedConfigProperty = {
+        overrides: [
+          {value: 'v1'}
+        ]
+      };
+      installerStep7Controller.updateHostOverrides(configProperty, storedConfigProperty);
+    });
+
+    it('override is valid', function () {
+      var override = configProperty.get('overrides.0');
+      expect(override.get('value')).to.be.equal('v1');
+      expect(override.get('isOriginalSCP')).to.be.false;
+      expect(override.get('parentSCP')).to.be.eql(configProperty);
+    });
+
+  });
+
+  describe('#allowUpdateProperty', function () {
+
+    it('true if it is installer', function () {
+      installerStep7Controller.set('wizardController', {name: 'installerController'});
+      expect(installerStep7Controller.allowUpdateProperty([], '', '')).to.be.true;
+    });
+
+    it('true if it is parentProperties are not empty', function () {
+      installerStep7Controller.set('wizardController', {name: 'some'});
+      expect(installerStep7Controller.allowUpdateProperty([{}], '', '')).to.be.true;
+    });
+
+    describe('#addServiceController', function () {
+
+      var installedServices = [];
+
+      beforeEach(function () {
+        installerStep7Controller.set('wizardController', {name: 'addServiceController'});
+        this.stub = sinon.stub(App.configsCollection, 'getConfigByName');
+        sinon.stub(App.config, 'getServiceByConfigType', function (type) {
+          return Em.Object.create({serviceName: type === 't1' ? 's1' : 's2'});
+        })
+      });
+
+      afterEach(function () {
+        App.configsCollection.getConfigByName.restore();
+        App.config.getServiceByConfigType.restore();
+      });
+
+      it('stackProperty does not exist', function () {
+        this.stub.returns(null);
+        expect(installerStep7Controller.allowUpdateProperty([], '', '')).to.be.true;
+      });
+
+      it('installedServices does not contain stackProperty.serviceName', function () {
+        this.stub.returns({serviceName: 's1'});
+        installerStep7Controller.set('installedServices', {});
+        expect(installerStep7Controller.allowUpdateProperty([], '', '')).to.be.true;
+      });
+
+      it('stackProperty.propertyDependsOn is empty', function () {
+        installerStep7Controller.reopen({installedServices: {s1: true}});
+        this.stub.returns({serviceName: 's1', propertyDependsOn: []});
+
+        expect(installerStep7Controller.allowUpdateProperty([], '', '')).to.be.false;
+      });
+
+      it('stackProperty.propertyDependsOn is not empty', function () {
+        installerStep7Controller.reopen({installedServices: {s1: true}});
+        this.stub.returns({serviceName: 's1', propertyDependsOn: [
+          {type: 't1'},
+          {type: 't2'}
+        ]});
+
+        expect(installerStep7Controller.allowUpdateProperty([], '', '')).to.be.true;
+      });
+
+      it('stackProperty.propertyDependsOn is not empty (2)', function () {
+        installerStep7Controller.reopen({installedServices: {s1: true}});
+        this.stub.returns({serviceName: 's1', propertyDependsOn: [
+          {type: 't1'},
+          {type: 't1'}
+        ]});
+
+        expect(installerStep7Controller.allowUpdateProperty([], '', '')).to.be.false;
+      });
+
+    });
+
+    it('true if it is not installer or addService', function () {
+      installerStep7Controller.set('wizardController', {name: 'some'});
+      expect(installerStep7Controller.allowUpdateProperty([], '', '')).to.be.true;
+    });
+
+  });
+
+  describe('#loadServiceConfigGroupOverridesSuccess', function () {
+
+    var data = {
+      items: [
+        {
+          type: 'type1',
+          tag: 'tag1',
+          properties: {
+            p1: 'v1',
+            p3: 'v3'
+          },
+          properties_attributes: {
+            final: {
+              p1: true,
+              p3: true
+            }
+          }
+        },
+        {
+          type: 'type2',
+          tag: 'tag1',
+          properties: {
+            p2: 'v2',
+            p4: 'v4'
+          },
+          properties_attributes: {}
+        }
+      ]
+    };
+
+    var params;
+
+    beforeEach(function () {
+      params = {
+        serviceConfigs: [],
+        typeTagToGroupMap: {
+          'type1///tag1': Em.Object.create({
+            name: 't1t1'
+          }),
+          'type2///tag1': Em.Object.create({
+            name: 't2t1'
+          })
+        },
+        configKeyToConfigMap: {
+          type1: {},
+          type2: {
+            p4: {}
+          }
+        }
+      };
+      sinon.stub(installerStep7Controller, 'onLoadOverrides', Em.K);
+      sinon.stub(App.config, 'getOriginalFileName', function (type) {return type;});
+      sinon.stub(App.config, 'formatPropertyValue', function (serviceConfigProperty, originalValue) {
+        return Em.isNone(originalValue) ? Em.get(serviceConfigProperty, 'value') : originalValue;
+      });
+      installerStep7Controller.loadServiceConfigGroupOverridesSuccess(data, {}, params);
+      this.serviceConfigs = installerStep7Controller.onLoadOverrides.args[0][0];
+    });
+
+    afterEach(function () {
+      installerStep7Controller.onLoadOverrides.restore();
+      App.config.getOriginalFileName.restore();
+      App.config.formatPropertyValue.restore();
+    });
+
+    it('type2/p4 is mapped to the params.configKeyToConfigMap', function () {
+      expect(params).to.have.deep.property('configKeyToConfigMap.type2.p4').that.is.an('object').with.deep.property('overrides');
+    });
+
+    it('type2/p4 has 1 override', function () {
+      expect(params.configKeyToConfigMap.type2.p4.overrides).to.have.property('length').equal(1);
+    });
+
+    it('type2/p4 override is valid', function () {
+      var override = params.configKeyToConfigMap.type2.p4.overrides[0];
+      expect(override.value).to.be.equal('v4');
+      expect(override.group.name).to.be.equal('t2t1');
+      expect(override.isFinal).to.be.false;
+    });
+
+    it('onLoadOverrides is called for 3 configs', function () {
+      expect(this.serviceConfigs).to.have.property('length').equal(3);
+    });
+
+    it('serviceConfigs ids are valid', function () {
+      expect(this.serviceConfigs.mapProperty('id')).to.be.eql(['p1__type1', 'p3__type1', 'p2__type2']);
+    });
+
+    it('serviceConfigs groups are valid', function () {
+      expect(this.serviceConfigs.mapProperty('group.name')).to.be.eql(['t1t1', 't1t1', 't2t1']);
+    });
+
+    it('serviceConfigs filenames are valid', function () {
+      expect(this.serviceConfigs.mapProperty('filename')).to.be.eql(['type1', 'type1', 'type2']);
+    });
+
+  });
+
 });

+ 36 - 0
ambari-web/test/controllers/wizard/step8_test.js

@@ -2428,4 +2428,40 @@ describe('App.WizardStep8Controller', function () {
 
   });
 
+  describe('#updateKerberosDescriptor', function () {
+
+    var requestData = {artifactName: 'kerberos_descriptor',
+      data: {
+        artifact_data: 1234
+      }
+    };
+
+    beforeEach(function () {
+      sinon.stub(App.db, 'get').withArgs('KerberosWizard', 'kerberosDescriptorConfigs').returns(1234);
+      sinon.stub(App.ajax, 'send', Em.K);
+      sinon.stub(installerStep8Controller, 'addRequestToAjaxQueue', Em.K);
+    });
+
+    afterEach(function () {
+      App.db.get.restore();
+      App.ajax.send.restore();
+      installerStep8Controller.addRequestToAjaxQueue.restore();
+    });
+
+    it('should send request instantly', function () {
+      installerStep8Controller.updateKerberosDescriptor(true);
+      expect(App.ajax.send.calledOnce).to.be.true;
+      expect(installerStep8Controller.addRequestToAjaxQueue.called).to.be.false;
+      expect(App.ajax.send.args[0][0].data).to.be.eql(requestData);
+    });
+
+    it('should add request to the queue', function () {
+      installerStep8Controller.updateKerberosDescriptor(false);
+      expect(App.ajax.send.called).to.be.false;
+      expect(installerStep8Controller.addRequestToAjaxQueue.calledOnce).to.be.true;
+      expect(installerStep8Controller.addRequestToAjaxQueue.args[0][0].data).to.be.eql(requestData);
+    });
+
+  });
+
 });

+ 173 - 3
ambari-web/test/controllers/wizard/step9_test.js

@@ -1,4 +1,4 @@
-  /**
+/**
  * 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
@@ -16,8 +16,6 @@
  * limitations under the License.
  */
 
-
-var Ember = require('ember');
 var App = require('app');
 require('models/stack_service_component');
 require('models/hosts');
@@ -523,9 +521,69 @@ describe('App.InstallerStep9Controller', function () {
       it(test.m, function () {
         c.setProperties(test.c);
         c.setIsServicesInstalled(test.polledData);
+        expect(c.get('progress')).to.equal(test.e.progress);
+        expect(c.get('isPolling')).to.be.equal(test.e.isPolling);
       });
     });
 
+    describe('`skipComponentStartAfterInstall` is true', function () {
+
+      var polledData = Em.A([
+        Em.Object.create({
+          Tasks: Em.Object.create({
+            status: 'NONE'
+          })
+        }),
+        Em.Object.create({
+          Tasks: Em.Object.create({
+            status: 'NONE'
+          })
+        })
+      ]);
+
+      var hosts = [
+        Em.Object.create({status: '', message: '', progress: 0}),
+        Em.Object.create({status: '', message: '', progress: 0}),
+        Em.Object.create({status: '', message: '', progress: 0}),
+        Em.Object.create({status: '', message: '', progress: 0})
+      ];
+
+      beforeEach(function () {
+        sinon.stub(App, 'get').withArgs('supports.skipComponentStartAfterInstall').returns(true);
+        sinon.stub(c, 'saveClusterStatus', Em.K);
+        sinon.stub(c, 'saveInstalledHosts', Em.K);
+        sinon.stub(c, 'changeParseHostInfo', Em.K);
+        c.set('hosts', hosts);
+        c.setIsServicesInstalled(polledData);
+      });
+
+      afterEach(function () {
+        App.get.restore();
+        c.saveClusterStatus.restore();
+        c.saveInstalledHosts.restore();
+        c.changeParseHostInfo.restore();
+      });
+
+      it('cluster status is valid', function () {
+        var clusterStatus = c.saveClusterStatus.args[0][0];
+        expect(clusterStatus.status).to.be.equal('START_SKIPPED');
+        expect(clusterStatus.isCompleted).to.be.true;
+      });
+
+      it('each host status is `success`', function () {
+        expect(c.get('hosts').everyProperty('status', 'success')).to.be.true;
+      });
+
+      it('each host progress is `100`', function () {
+        expect(c.get('hosts').everyProperty('progress', '100')).to.be.true;
+      });
+
+      it('each host message is valid', function () {
+        expect(c.get('hosts').everyProperty('message', Em.I18n.t('installer.step9.host.status.success'))).to.be.true;
+      });
+
+    });
+
   });
 
   describe('#launchStartServices', function () {
@@ -1687,4 +1745,116 @@ describe('App.InstallerStep9Controller', function () {
       });
   });
 
+  describe('#isAllComponentsInstalledSuccessCallback', function () {
+
+    var hosts = [
+      Em.Object.create({name: 'h1', status: '', message: '', progress: ''}),
+      Em.Object.create({name: 'h2', status: '', message: '', progress: ''})
+    ];
+
+    var jsonData = {
+      items: [
+        {
+          Hosts: {
+            host_state: 'HEARTBEAT_LOST',
+            host_name: 'h1'
+          },
+          host_components: [
+            {
+              HostRoles: {
+                component_name: 'c1'
+              }
+            },
+            {
+              HostRoles: {
+                component_name: 'c2'
+              }
+            }
+          ]
+        },
+        {
+          Hosts: {
+            host_state: 'HEARTBEAT_LOST',
+            host_name: 'h2'
+          },
+          host_components: [
+            {
+              HostRoles: {
+                component_name: 'c3'
+              }
+            },
+            {
+              HostRoles: {
+                component_name: 'c4'
+              }
+            }
+          ]
+        }
+      ]
+    };
+
+    beforeEach(function () {
+      sinon.stub(c, 'changeParseHostInfo', Em.K);
+      sinon.stub(c, 'launchStartServices', Em.K);
+      sinon.stub(c, 'saveClusterStatus', Em.K);
+      c.set('hosts', hosts);
+      c.isAllComponentsInstalledSuccessCallback(jsonData);
+      this.clusterStatus = c.saveClusterStatus.args[0][0];
+    });
+
+    afterEach(function () {
+      c.changeParseHostInfo.restore();
+      c.launchStartServices.restore();
+      c.saveClusterStatus.restore();
+    });
+
+    it('cluster status / status', function () {
+      expect(this.clusterStatus.status).to.be.equal('INSTALL FAILED');
+    });
+
+    it('cluster status / isStartError', function () {
+      expect(this.clusterStatus.isStartError).to.be.true;
+    });
+
+    it('cluster status / isCompleted', function () {
+      expect(this.clusterStatus.isCompleted).to.be.false;
+    });
+
+    it('each host progress is 100', function () {
+      expect(c.get('hosts').everyProperty('progress', '100')).to.be.true;
+    });
+
+    it('each host status is `heartbeat_lost`', function () {
+      expect(c.get('hosts').everyProperty('status', 'heartbeat_lost')).to.be.true;
+    });
+
+    it('overall progress is 100', function () {
+      expect(c.get('progress')).to.be.equal('100');
+    });
+
+  });
+
+  describe('#loadDoServiceChecksFlagSuccessCallback', function () {
+
+    var data = {
+      RootServiceComponents: {
+        properties: {
+          'skip.service.checks': 'true'
+        }
+      }
+    };
+
+    it('skipServiceChecks should be true', function () {
+      c.loadDoServiceChecksFlagSuccessCallback(data);
+      expect(c.get('skipServiceChecks')).to.be.true;
+    });
+
+    it('skipServiceChecks should be false', function () {
+      data.RootServiceComponents.properties['skip.service.checks'] = 'false';
+      c.loadDoServiceChecksFlagSuccessCallback(data);
+      expect(c.get('skipServiceChecks')).to.be.false;
+    });
+
+  });
+
 });