You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by yu...@apache.org on 2012/09/17 19:17:16 UTC

svn commit: r1386725 - in /incubator/ambari/branches/AMBARI-666: ./ ambari-web/app/ ambari-web/app/controllers/installer/ ambari-web/app/utils/ ambari-web/test/installer/

Author: yusaku
Date: Mon Sep 17 17:17:16 2012
New Revision: 1386725

URL: http://svn.apache.org/viewvc?rev=1386725&view=rev
Log:
AMBARI-745. Add unit tests for Installer Step 1 (Welcome page). (yusaku)

Added:
    incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/installer/step1_controller.js
    incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/installer/step2_controller.js
Removed:
    incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/installer/step1.js
    incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/installer/step2.js
Modified:
    incubator/ambari/branches/AMBARI-666/AMBARI-666-CHANGES.txt
    incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers.js
    incubator/ambari/branches/AMBARI-666/ambari-web/app/utils/db.js
    incubator/ambari/branches/AMBARI-666/ambari-web/test/installer/step1_test.js

Modified: incubator/ambari/branches/AMBARI-666/AMBARI-666-CHANGES.txt
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/AMBARI-666-CHANGES.txt?rev=1386725&r1=1386724&r2=1386725&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/AMBARI-666-CHANGES.txt (original)
+++ incubator/ambari/branches/AMBARI-666/AMBARI-666-CHANGES.txt Mon Sep 17 17:17:16 2012
@@ -12,6 +12,8 @@ AMBARI-666 branch (unreleased changes)
 
   NEW FEATURES
 
+  AMBARI-745. Add unit tests for Installer Step 1 (Welcome page). (yusaku)
+
   AMBARI-744. Add definition for service config properties. (yusaku)
 
   AMBARI-743. Add unit testing framework for Ambari Web. (yusaku)

Modified: incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers.js?rev=1386725&r1=1386724&r2=1386725&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers.js (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers.js Mon Sep 17 17:17:16 2012
@@ -22,8 +22,8 @@
 require('controllers/application');
 require('controllers/login_controller');
 require('controllers/installer');
-require('controllers/installer/step1');
-require('controllers/installer/step2');
+require('controllers/installer/step1_controller');
+require('controllers/installer/step2_controller');
 require('controllers/installer/step3');
 require('controllers/installer/step7_controller');
 require('controllers/main');

Added: incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/installer/step1_controller.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/installer/step1_controller.js?rev=1386725&view=auto
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/installer/step1_controller.js (added)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/installer/step1_controller.js Mon Sep 17 17:17:16 2012
@@ -0,0 +1,58 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var App = require('app');
+var db = require('utils/db');
+
+App.InstallerStep1Controller = Em.Controller.extend({
+  name: 'installerStep1Controller',
+  content: [],
+  clusterName: '',
+  invalidClusterName: false,
+  clusterNameError: '',
+
+  /**
+   * Returns true if the cluster name is valid and stores it in localStorage.
+   * Returns false otherwise, and sets appropriate field error message.
+   */
+  validateStep1: function () {
+    console.log('TRACE: Entering controller:InstallerStep1:validateStep1 function');
+    if (this.get('clusterName') == '') {
+      this.set('clusterNameError', Em.I18n.t('installer.step1.clusterName.error.required'));
+      this.set('invalidClusterName', true);
+      return false;
+    } else if (/\s/.test(this.get('clusterName'))) {
+      console.log('White spaces not allowed for cluster name');
+      this.set('clusterNameError', Em.I18n.t('installer.step1.clusterName.error.whitespaces'));
+      this.set('invalidClusterName', true);
+      return false;
+    } else if (/[^\w\s]/gi.test(this.get('clusterName'))) {
+      console.log('Special characters are not allowed for the cluster name');
+      this.set('clusterNameError', Em.I18n.t('installer.step1.clusterName.error.specialChar'));
+      this.set('invalidClusterName', true);
+      return false;
+    } else {
+      console.log('value of clusterName is: ' + this.get('clusterName'));
+      this.set('clusterNameError', '');
+      this.set('invalidClusterName', false);
+      db.setClusterName(this.get('clusterName'));
+      return true;
+    }
+  }.observes('clusterName')
+
+})
\ No newline at end of file

Added: incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/installer/step2_controller.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/installer/step2_controller.js?rev=1386725&view=auto
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/installer/step2_controller.js (added)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/installer/step2_controller.js Mon Sep 17 17:17:16 2012
@@ -0,0 +1,258 @@
+/**
+ * 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');
+
+App.InstallerStep2Controller = Em.Controller.extend({
+  name: 'installerStep2Controller',
+  content: [],
+  hostNames: '',
+  hostNameArr: [],
+  hostNameEmptyError: false,
+  hostNameErr: false,
+  manualInstall: false,
+  hostNameNotRequiredErr: false,
+  hostNameErrMsg: '',
+  sshKey: '',
+  passphrase: '',
+  confirmPassphrase: '',
+  sshKeyNullErr: false,
+  passphraseMatchErr: false,
+  localRepo: false,
+  localRepoPath: '',
+  softRepoLocalPathNullErr: false,
+  isSubmitDisabled: false,
+
+  installType: function () {
+    if (this.get('manualInstall') === true) {
+      return 'manualDriven';
+    } else {
+      return 'ambariDriven';
+    }
+  }.observes('manualInstall'),
+
+  hideRepoErrMsg: function () {
+    if (this.get('localRepo') === false) {
+      this.set('softRepoLocalPathNullErr', false);
+    }
+  }.observes('localRepo'),
+
+  validateHostNames: function () {
+    this.hostNameArr = this.get('hostNames').split(new RegExp("\\s"));
+    for (var i = 0; i < this.hostNameArr.length; i++) {
+      //TODO: other validation for hostnames will be covered over here
+      // For now hostnames that start or end with '-' are not allowed
+      if (/^\-/.test(this.hostNameArr[i]) || /\-$/.test(this.hostNameArr[i])) {
+        console.log('Invalid host name: ' + this.hostNameArr[i]);
+        this.set('hostNameErrMsg', Em.I18n.t('installer.step2.hostName.error.invalid'));
+        this.set('hostNameErr', true);
+        this.set('hostNameEmptyError', false);
+        this.set('hostNameNotRequiredErr', false);
+        return false;
+      }
+    }
+    return true;
+  },
+
+  validateHosts: function () {
+    if (this.get('hostNames') === '' && this.get('manualInstall') === false) {
+      this.set('hostNameEmptyError', true);
+      this.set('hostNameNotRequiredErr', false);
+      this.set('hostNameErr', false);
+      this.set('hostNameErrMsg', Em.I18n.t('installer.step2.hostName.error.required'));
+    } else if (this.get('hostNames') !== '' && this.get('manualInstall') === true) {
+      this.set('hostNameNotRequiredErr', true);
+      this.set('hostNameEmptyError', false);
+      this.set('hostNameErr', false);
+      this.set('hostNameErrMsg', Em.I18n.t('installer.step2.hostName.error.notRequired'));
+    } else {
+      this.set('hostNameErr', false);
+      this.set('hostNameEmptyError', false);
+      this.set('hostNameNotRequiredErr', false);
+      this.set('hostNameErrMsg', '');
+    }
+  }.observes('hostNames', 'manualInstall'),
+
+  validateSSHKey: function () {
+    if (this.get('manualInstall') === false) {
+      if (this.get('sshKey') === '') {
+        this.set('sshKeyNullErr', true);
+      }
+      else {
+        this.set('sshKeyNullErr', false);
+      }
+    }
+  }.observes('manualInstall', 'sshKey'),
+
+  validatePassphrase: function () {
+    if (this.get('manualInstall') === false) {
+      if (this.get('passphrase') !== this.get('confirmPassphrase')) {
+        this.set('passphraseMatchErr', true);
+      } else {
+        this.set('passphraseMatchErr', false);
+      }
+    }
+  }.observes('manualInstall', 'passphrase', 'confirmPassphrase'),
+
+  validateLocalRepo: function () {
+    if (this.get('localRepo') === true) {
+      if (this.get('localRepoPath') === '') {
+        this.set('softRepoLocalPathNullErr', true);
+      } else {
+        this.set('softRepoLocalPathNullErr', false);
+      }
+    } else {
+      this.set('softRepoLocalPathNullErr', false);
+    }
+  }.observes('localRepoPath'),
+
+  validateStep2: function () {
+    this.validateHosts();
+    this.validateSSHKey();
+    this.validatePassphrase();
+    this.validateLocalRepo();
+    return this.validateHostNames();
+  },
+
+  hostManageErr: function () {
+    return (this.get('hostNameEmptyError') || this.get('hostNameNotRequiredErr') ||
+      this.get('hostNameErr') || this.get('sshKeyNullErr') || this.get('passphraseMatchErr'));
+  }.property('hostNameErrMsg', 'sshKeyNullErr', 'passphraseMatchErr'),
+
+  sshLessInstall: function () {
+    if (this.get('manualInstall') === true) {
+      this.set('hostManageErr', false);
+      this.set('hostNameEmptyError', false);
+      this.set('sshKeyNullErr', false);
+      this.set('passphraseMatchErr', false);
+    }
+  }.observes('manualInstall'),
+
+  advOptErr: function () {
+    return this.get('softRepoLocalPathNullErr');
+  }.property('softRepoLocalPathNullErr'),
+
+  step2Err: function () {
+    if (this.get('hostManageErr') === true || this.get('advOptErr') === true) {
+      this.set('isSubmitDisabled', true);
+    } else {
+      this.set('isSubmitDisabled', false);
+    }
+  }.observes('hostManageErr', 'advOptErr'),
+
+  softRepo: function () {
+    if (this.get('localRepo') === false) {
+      this.set('localRepoPath', '');
+    }
+  }.observes('localRepo'),
+
+
+  evaluateStep2: function () {
+
+    //task1 = do primary validations on whole step before executing any further steps
+    //task2 = parsing hostnames string to hostnames json array
+    //task3 = check validation for every hostname and store it in localstorage
+    //task4 = Storing ambari agent Install type in localStorage (installType maps at host level and so every host will have this as an property)
+    //task5 = Storing path of software repository(remote/local repo) to localStorage
+    //task6 = call to rest API: @Post http://ambari_server/api/bootstrap
+    //task7 = On Manual Install, next button click pops up a warning with "proceed" and "close" buttons
+    //task8 = On faliure of the previous call, show 'error injecting host information in server db'
+    //task9 = On success of the previous call, go to step 3
+
+    console.log('TRACE: Entering controller:InstallerStep2:evaluateStep2 function');
+    console.log('value of manual install is: ' + this.get('manualInstall'));
+
+    var validateResult = this.validateStep2();
+
+    if (this.get('isSubmitDisabled') === true || validateResult === false) {
+      console.log("ERROR: error in validation");
+      return false;
+    } else {
+      if (this.get('manualInstall') === true) {
+        this.manualInstallPopup();
+        return true;
+      }
+    }
+
+    var hostInfo = {};
+    for (var i = 0; i < this.hostNameArr.length; i++) {
+      hostInfo[this.hostNameArr[i]] = {
+        name: this.hostNameArr[i],
+        installType: this.get('installType')
+      };
+    }
+    App.db.setHosts(hostInfo);
+
+    if (this.get('localRepo') === false) {
+      App.db.setSoftRepo({ 'repoType': 'remote', 'repoPath': null});
+    } else {
+      App.db.setSoftRepo({ 'repoType': 'local', 'repoPath': this.get('localRepoPath') });
+    }
+
+    // Just an additional check. If manualInstall is true, program should have not reached over here
+    if (this.get('manualInstall') === false) {
+      // For now using mock jquery call
+      //TODO: hook up with bootstrap call
+      var bootStrapData = {'sshKey': this.get('sshKey'), 'sshKeyPassphrase': this.get('passphrase'), hosts: this.get('hostNameArr')}.stringify;
+      $.ajax({
+        type: 'POST',
+        url: '/ambari_server/api/bootstrap',
+        data: bootStrapData,
+        async: false,
+        timeout: 2000,
+        success: function () {
+          console.log("TRACE: In success function for the post bootstrap function");
+          App.transitionTo('step3');
+        },
+        error: function () {
+          console.log("ERROR: bootstrap post call failed");
+          return false;
+        },
+        statusCode: {
+          404: function () {
+            console.log("URI not found.");
+            alert("URI not found,. This needs to be hooked up with a @POST bootstrap call");
+            //After the bootstrap call hook up change the below return statement to "return false"
+            console.log("TRACE: In faliure function for the post bootstrap function");
+            //Remove below line, once bootstrap has been implemented
+            App.router.transitionTo('step3');
+            return true;
+          }
+        },
+        dataType: 'application/json'
+      });
+    } else {
+      console.log("ERROR: ASSERTION FAILED -> program should have never reached over here");
+    }
+
+  },
+
+  manualInstallPopup: function (event) {
+    App.ModalPopup.show({
+      header: Em.I18n.t('installer.step2.manualInstall.popup.header'),
+      onPrimary: function () {
+        this.hide();
+        App.router.transitionTo('step3');
+      },
+      bodyClass: Ember.View.extend({
+        templateName: require('templates/installer/step2ManualInstallPopup')
+      })
+    });
+  }
+
+});
\ No newline at end of file

Modified: incubator/ambari/branches/AMBARI-666/ambari-web/app/utils/db.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/utils/db.js?rev=1386725&r1=1386724&r2=1386725&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/utils/db.js (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/utils/db.js Mon Sep 17 17:17:16 2012
@@ -18,17 +18,32 @@
 var App = require('app');
 App.db = {};
 
-
-Storage.prototype.setObject = function(key,value) {
-  this.setItem(key, JSON.stringify(value));
-}
-
-Storage.prototype.getObject = function(key) {
-  var value = this.getItem(key);
-  return value && JSON.parse(value);
+if (typeof Storage !== 'undefined') {
+  Storage.prototype.setObject = function(key,value) {
+    this.setItem(key, JSON.stringify(value));
+  }
+
+  Storage.prototype.getObject = function(key) {
+    var value = this.getItem(key);
+    return value && JSON.parse(value);
+  }
+} else {
+  // stub for unit testing purposes
+  window.localStorage = {};
+  localStorage.setItem = function (key, val) {
+    this[key] = val;
+  }
+  localStorage.getItem = function (key) {
+    return this[key];
+  }
+  window.localStorage.setObject = function(key, value) {
+    this[key] = value;
+  };
+  window.localStorage.getObject = function(key, value) {
+    return this[key];
+  };
 }
 
-
 App.db.cleanUp = function() {
   console.log('TRACE: Entering db:cleanup function');
   App.db.data = {
@@ -208,3 +223,4 @@ App.db.getHosts = function(name,hostInfo
   return App.db.data[user].Installer.hostInfo;
 }
 
+module.exports = App.db;

Modified: incubator/ambari/branches/AMBARI-666/ambari-web/test/installer/step1_test.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/test/installer/step1_test.js?rev=1386725&r1=1386724&r2=1386725&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/test/installer/step1_test.js (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/test/installer/step1_test.js Mon Sep 17 17:17:16 2012
@@ -1 +1,37 @@
-// TODO
+var App = require('app');
+require('controllers/installer/step1_controller');
+
+describe('App.InstallerStep1Controller', function () {
+
+  describe('#validateStep1()', function () {
+    it('should return false and sets invalidClusterName to true if cluster name is empty', function () {
+      var controller = App.InstallerStep1Controller.create();
+      controller.set('clusterName', '');
+      expect(controller.validateStep1()).to.equal(false);
+      expect(controller.get('invalidClusterName')).to.equal(true);
+    })
+    it('should return false and sets invalidClusterName to true if cluster name has whitespaces', function () {
+      var controller = App.InstallerStep1Controller.create();
+      controller.set('clusterName', 'My Cluster');
+      expect(controller.validateStep1()).to.equal(false);
+      expect(controller.get('invalidClusterName')).to.equal(true);
+    })
+    it('should return false and sets invalidClusterName to true if cluster name has special characters', function () {
+      var controller = App.InstallerStep1Controller.create();
+      controller.set('clusterName', 'my-cluster');
+      expect(controller.validateStep1()).to.equal(false);
+      expect(controller.get('invalidClusterName')).to.equal(true);
+    })
+    it('should return true, sets invalidClusterName to false, and sets cluster name in db if cluster name is valid', function () {
+      var controller = App.InstallerStep1Controller.create();
+      var clusterName = 'mycluster1';
+      controller.set('clusterName', clusterName);
+      // fake login so clusterName is properly retrieved from App.db
+      App.db.setLoginName('myuser');
+      expect(controller.validateStep1()).to.equal(true);
+      expect(controller.get('invalidClusterName')).to.equal(false);
+      expect(App.db.getClusterName()).to.equal(clusterName);
+    })
+  })
+
+})
\ No newline at end of file