You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by se...@apache.org on 2014/03/28 11:22:14 UTC

git commit: updated refs/heads/master to 9b07979

Repository: cloudstack
Updated Branches:
  refs/heads/master 91a5e3bb6 -> 9b0797944


CLOUDSTACK-6015: add user account, add user, login as new user, delete user, delete user account.

Signed-off-by: Sebastien Goasguen <ru...@gmail.com>


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

Branch: refs/heads/master
Commit: 9b07979442c251438004bfb0781dee85a5c29100
Parents: 91a5e3b
Author: yichi.lu <yi...@sungard.com>
Authored: Tue Mar 25 15:37:37 2014 -0500
Committer: Sebastien Goasguen <ru...@gmail.com>
Committed: Fri Mar 28 06:21:59 2014 -0400

----------------------------------------------------------------------
 test/selenium/common/shared.py                  |   4 +-
 test/selenium/cspages/accounts/accountspage.py  | 175 +++++++++++++++++++
 test/selenium/cspages/accounts/userspage.py     | 146 ++++++++++++++++
 test/selenium/cspages/cspage.py                 |  21 +++
 .../selenium/cspages/dashboard/dashboardpage.py |   3 +-
 test/selenium/cspages/login/loginpage.py        |   9 +-
 .../selenium/cstests/smoketests/adduser_test.py | 103 +++++++++++
 .../cstests/smoketests/adduseraccount_test.py   |  96 ++++++++++
 .../cstests/smoketests/deleteuser_test.py       | 100 +++++++++++
 .../smoketests/deleteuseraccount_test.py        |  91 ++++++++++
 .../smoketests/login_logout_as_JohnD_test.py    |  61 +++++++
 test/selenium/cstests/smoketests/smokecfg.py    |  31 +++-
 12 files changed, 826 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/9b079794/test/selenium/common/shared.py
----------------------------------------------------------------------
diff --git a/test/selenium/common/shared.py b/test/selenium/common/shared.py
index b4f537f..7016871 100644
--- a/test/selenium/common/shared.py
+++ b/test/selenium/common/shared.py
@@ -42,7 +42,7 @@ def try_except_decor(func):
             print repr(traceback.format_exception(exc_type, exc_value,exc_traceback))
         except TimeoutException as err:
             exc_type, exc_value, exc_traceback = sys.exc_info()
-            print "Element error. Function: {0}, error: {1}".format(func.func_code, err)
+            print "Timeout error. Function: {0}, error: {1}".format(func.func_code, err)
             print repr(traceback.format_exception(exc_type, exc_value,exc_traceback))
 
     return try_except
@@ -53,8 +53,6 @@ class Shared(object):
     @try_except_decor
     def option_selection(browser, element_type, element_name, option_text, wait_element_type = '', wait_element_name = ''):
 
-        import pdb
-        pdb.set_trace()
         ret = False
         Shared.wait_for_element(browser, element_type, element_name)
         if element_type == 'id':

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/9b079794/test/selenium/cspages/accounts/accountspage.py
----------------------------------------------------------------------
diff --git a/test/selenium/cspages/accounts/accountspage.py b/test/selenium/cspages/accounts/accountspage.py
new file mode 100644
index 0000000..15eccd3
--- /dev/null
+++ b/test/selenium/cspages/accounts/accountspage.py
@@ -0,0 +1,175 @@
+# 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.
+
+from selenium import webdriver
+from selenium.common.exceptions import *
+from selenium.webdriver.support.ui import WebDriverWait # available since 2.4.0
+from selenium.webdriver.common.action_chains import ActionChains as action
+from common import Global_Locators
+from cspages.cspage import CloudStackPage
+
+from common.shared import *
+
+class AccountsPage(CloudStackPage):
+
+    def __init__(self, browser):
+        self.browser = browser
+        self.accounts = []
+
+    @try_except_decor
+    def get_accounts(self):
+        rows = self.browser.find_elements_by_xpath("//div[@class='data-table']/table[@class='body']/tbody/tr")
+        for row in rows:
+            account = {}
+            columes = row.find_elements_by_tag_name('td')
+            account['Name'] =   columes[0].get_attribute('title').lower()
+            account['Role'] =   columes[1].get_attribute('title').lower()
+            account['Domain'] = columes[2].get_attribute('title').lower()
+            account['State'] =  columes[3].get_attribute('title').lower()
+            self.accounts.append(account)
+
+    @try_except_decor
+    def account_exists(self, name):
+        if len(self.accounts) == 0:
+            self.get_accounts()
+        account = [acct for acct in self.accounts if acct['Name'] == name.lower()]
+        if len(account) > 0:
+            return True
+        else:
+            return False
+
+    @try_except_decor
+    def add_account(self, username = "", password = "", email = "", firstname = "", lastname = "", domain = "", account = "", type = "", timezone = "", network_domain = ""):
+        # type = role
+        if len(username) == 0 or len(password) == 0 or len(email) == 0 or len(firstname) == 0 or len(lastname) == 0 or len(domain) == 0 or len(type) == 0:
+            return;
+        if type not in ('User', 'Admin'):
+            print "Account type must be either User or Admin."
+            return;
+        if self.account_exists(username):
+            return
+
+        # click Add Account
+        ele = self.browser.find_element_by_xpath("//div[@class='toolbar']")
+        ele1 = ele.find_element_by_xpath("//div[3]/span")
+        ele1.click()
+
+        Shared.wait_for_element(self.browser, 'id', 'label_username')
+        ele = self.browser.find_element_by_xpath("(//input[@name='username' and @type='text' and @id='label_username'])")
+        ele.send_keys(username)
+        ele = self.browser.find_element_by_xpath("(//input[@name='password' and @type='password' and @id='password'])")
+        ele.send_keys(password)
+        ele = self.browser.find_element_by_xpath("(//input[@name='password-confirm' and @type='password' and @id='label_confirm_password'])")
+        ele.send_keys(password)
+        ele = self.browser.find_element_by_xpath("(//input[@name='email' and @type='text' and @id='label_email'])")
+        ele.send_keys(email)
+        ele = self.browser.find_element_by_xpath("(//input[@name='firstname' and @type='text' and @id='label_first_name'])")
+        ele.send_keys(firstname)
+        ele = self.browser.find_element_by_xpath("(//input[@name='lastname' and @type='text' and @id='label_last_name'])")
+        ele.send_keys(lastname)
+        Shared.option_selection(self.browser, 'id', 'label_domain', 'ROOT')
+        if len(account) > 0:
+            ele = self.browser.find_element_by_xpath("(//input[@name='account' and @type='text' and @id='label_account'])")
+            ele.send_keys(account)
+        Shared.option_selection(self.browser, 'id', 'label_type', type)
+        Shared.option_selection(self.browser, 'id', 'label_timezone', timezone)
+        if len(network_domain) > 0:
+            ele = self.browser.find_element_by_xpath("(//input[@name='networkdomain' and @type='text' and @id='label_network_domain'])")
+            ele.send_keys(network_domain)
+        self.button_add()
+
+        Shared.wait_for_element(self.browser, 'class_name', 'fixed-header')
+
+    @try_except_decor
+    def select_account(self, username = "", domain = "", type = ""):
+        if len(username) == 0 or len(domain) == 0 or len(type) == 0:
+            return False;
+        if self.account_exists(username) == False:
+            print "The account does not exist"
+            return False
+
+        # select the account
+        ele = self.browser.find_element_by_xpath("//div[@class='data-table']/div[@class='fixed-header']/table")
+        ele1 = ele.find_element_by_xpath("//tbody")
+        ele2 = ele1.find_elements_by_tag_name('tr')
+        for e in ele2:
+            ele3 = e.find_elements_by_tag_name('td')
+            # move mouse to quickview
+            if len(ele3) > 4 and \
+                ele3[0].text == username and \
+                ele3[1].text == type and \
+                ele3[2].text == domain and \
+                ele3[3].text == 'enabled':
+                ele3[4].find_element_by_tag_name('span').click()
+                Shared.wait_for_element(self.browser, 'class_name', 'details')
+                # select account
+                ele = self.browser.find_element_by_xpath("//div[@id='details-tab-details']/div[@class='details']/div/table/tbody/tr/td[@class='view-all']")
+                ele1 = ele.find_element_by_tag_name('a').find_element_by_tag_name('span').click()
+                break
+
+        Shared.wait_for_element(self.browser, 'class_name', 'view-all')
+
+    @try_except_decor
+    def delete_account(self, username = "", domain = "", type = ""):
+        if len(username) == 0 or len(domain) == 0 or len(type) == 0:
+            return False;
+        if self.account_exists(username) == False:
+            print "The account does not exist"
+            return False
+
+        # find the account
+        ele = self.browser.find_element_by_xpath("//div[@class='data-table']/div[@class='fixed-header']/table")
+        ele1 = ele.find_element_by_xpath("//tbody")
+        ele2 = ele1.find_elements_by_tag_name('tr')
+        for e in ele2:
+            ele3 = e.find_elements_by_tag_name('td')
+            # move mouse to quickview
+            if len(ele3) > 4 and \
+                ele3[0].text == username and \
+                ele3[1].text == type and \
+                ele3[2].text == domain and \
+                ele3[3].text == 'enabled':
+                ele3[4].find_element_by_tag_name('span').click()
+                Shared.wait_for_element(self.browser, 'class_name', 'details')
+                # delete account
+                ele = self.browser.find_element_by_xpath("//div[@id='details-tab-details']/div[@class='details']/div/table/tbody/tr/td/div[@class='buttons']")
+                ele1 = ele.find_element_by_xpath("//div[@class='action remove single text' and @title='Delete account']/span").click()
+                Shared.wait_for_element(self.browser, 'class_name', 'ui-dialog-buttonset')
+                self.button_yes()
+                break
+
+        Shared.wait_for_element(self.browser, 'class_name', 'fixed-header')
+
+    @try_except_decor
+    def button_cancel(self):
+        ele = self.browser.find_element_by_xpath("/html/body/div[4]/div[2]/div/button[1]/span").click()
+        Shared.wait_for_element(self.browser, 'class_name', 'fixed-header')
+
+    @try_except_decor
+    def button_add(self):
+        ele = self.browser.find_element_by_xpath("/html/body/div[4]/div[2]/div/button[2]/span").click()
+        Shared.wait_for_element(self.browser, 'class_name', 'fixed-header')
+
+    @try_except_decor
+    def button_no(self):
+        ele = self.browser.find_element_by_xpath("/html/body/div[4]/div[10]/div/button[1]/span").click()
+        Shared.wait_for_element(self.browser, 'class_name', 'fixed-header')
+
+    @try_except_decor
+    def button_yes(self):
+        ele = self.browser.find_element_by_xpath("/html/body/div[4]/div[10]/div/button[2]/span").click()
+        Shared.wait_for_element(self.browser, 'class_name', 'fixed-header')

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/9b079794/test/selenium/cspages/accounts/userspage.py
----------------------------------------------------------------------
diff --git a/test/selenium/cspages/accounts/userspage.py b/test/selenium/cspages/accounts/userspage.py
new file mode 100644
index 0000000..25375f5
--- /dev/null
+++ b/test/selenium/cspages/accounts/userspage.py
@@ -0,0 +1,146 @@
+# 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.
+
+from selenium import webdriver
+from selenium.common.exceptions import *
+from selenium.webdriver.support.ui import WebDriverWait # available since 2.4.0
+from selenium.webdriver.common.action_chains import ActionChains as action
+from common import Global_Locators
+from cspages.cspage import CloudStackPage
+
+from common.shared import *
+
+class UsersPage(CloudStackPage):
+
+    def __init__(self, browser):
+        self.browser = browser
+        self.users = []
+
+    @try_except_decor
+    def get_users(self):
+        ele = self.browser.find_element_by_xpath("//div[@class='container cloudStack-widget cloudBrowser']")
+        rows = ele.find_elements_by_xpath("//div[@class='panel']/div[2]/div[@class='view list-view']/div[@class='data-table']/table[@class='body']/tbody/tr")
+        for row in rows:
+            user = {}
+            columes = row.find_elements_by_tag_name('td')
+            user['username'] =   columes[0].get_attribute('title').lower()
+            user['firstname'] =   columes[1].get_attribute('title').lower()
+            user['lastname'] = columes[2].get_attribute('title').lower()
+            self.users.append(user)
+
+    @try_except_decor
+    def user_exists(self, username):
+        if len(self.users) == 0:
+            self.get_users()
+        users = [u for u in self.users if u['username'] == username.lower()]
+        if len(users) > 0:
+            return True
+        else:
+            return False
+
+    @try_except_decor
+    def add_user(self, username = "", password = "", email = "", firstname = "", lastname = "", timezone = ""):
+        if len(username) == 0 or len(password) == 0 or len(email) == 0 or len(firstname) == 0 or len(lastname) == 0:
+            return;
+        if self.user_exists(username):
+            return
+
+        # click Add User
+        ele = self.browser.find_element_by_xpath("//div[@class='container cloudStack-widget cloudBrowser']")
+        ele1 = ele.find_element_by_xpath("//div[@class='panel']/div[2]/div[@class='view list-view']/div[@class='toolbar']/div[@class='button action add reduced-hide']/span")
+        ele1.click()
+
+        Shared.wait_for_element(self.browser, 'id', 'label_username')
+        ele = self.browser.find_element_by_xpath("(//input[@name='username' and @type='text' and @id='label_username'])")
+        ele.send_keys(username)
+        ele = self.browser.find_element_by_xpath("(//input[@name='password' and @type='password' and @id='password'])")
+        ele.send_keys(password)
+        ele = self.browser.find_element_by_xpath("(//input[@name='password-confirm' and @type='password' and @id='label_confirm_password'])")
+        ele.send_keys(password)
+        ele = self.browser.find_element_by_xpath("(//input[@name='email' and @type='text' and @id='label_email'])")
+        ele.send_keys(email)
+        ele = self.browser.find_element_by_xpath("(//input[@name='firstname' and @type='text' and @id='label_first_name'])")
+        ele.send_keys(firstname)
+        ele = self.browser.find_element_by_xpath("(//input[@name='lastname' and @type='text' and @id='label_last_name'])")
+        ele.send_keys(lastname)
+        Shared.option_selection(self.browser, 'id', 'label_timezone', timezone)
+        self.button_ok()
+
+        Shared.wait_for_element(self.browser, 'class_name', 'fixed-header')
+
+    @try_except_decor
+    def delete_user(self, username = "", firstname = "", lastname = ""):
+        if len(username) == 0 or len(firstname) == 0 or len(lastname) == 0:
+            return False;
+        if self.user_exists(username) == False:
+            print "The user does not exist"
+            return False
+
+        # find the user
+        ele = self.browser.find_element_by_xpath("//div[@class='container cloudStack-widget cloudBrowser']")
+        ele1 = ele.find_element_by_xpath("//div[@class='panel']/div[2]/div[@class='view list-view']/div[@class='data-table']/table[@class='body']/tbody")
+        ele2 = ele1.find_elements_by_tag_name('tr')
+        for e in ele2:
+            ele3 = e.find_elements_by_tag_name('td')
+            # move mouse to quickview
+            if len(ele3) > 3 and \
+                ele3[0].text == username and \
+                ele3[1].text == firstname and \
+                ele3[2].text == lastname:
+                ele3[3].find_element_by_tag_name('span').click()
+                Shared.wait_for_element(self.browser, 'class_name', 'details')
+                # delete user
+                ele = self.browser.find_element_by_xpath("//div[@id='details-tab-details']/div[@class='details']/div/table/tbody/tr/td/div[@class='buttons']")
+                ele1 = ele.find_element_by_xpath("//div[@class='action remove single text' and @title='Delete User']/span").click()
+                Shared.wait_for_element(self.browser, 'class_name', 'ui-dialog-buttonset')
+                self.button_yes()
+                break
+
+        Shared.wait_for_element(self.browser, 'class_name', 'fixed-header')
+
+    @try_except_decor
+    def button_yes(self):
+        eles = self.browser.find_elements_by_xpath("//div[@class='ui-dialog-buttonset']/button[@type='button' and @role='button']")
+        for e in eles:
+            ele = e.find_element_by_class_name('ui-button-text')
+            if e.text == 'Yes':
+                e.click()
+                break
+        Shared.wait_for_element(self.browser, 'class_name', 'fixed-header')
+
+    @try_except_decor
+    def button_no(self):
+        ele = self.browser.find_element_by_xpath("/html/body/div[4]/div[10]/div/button[1]/span").click()
+        Shared.wait_for_element(self.browser, 'class_name', 'fixed-header')
+
+    @try_except_decor
+    def button_ok(self):
+        eles = self.browser.find_elements_by_xpath("//button[@type='button' and @role='button']")
+        for e in eles:
+            if e.text == 'OK':
+                e.click()
+                break
+        Shared.wait_for_element(self.browser, 'class_name', 'fixed-header')
+
+    @try_except_decor
+    def button_cancel(self):
+        eles = self.browser.find_elements_by_xpath("//button[@type='button' and @role='button']")
+        for e in eles:
+            if e.text == 'Cancel':
+                e.click()
+                break
+        Shared.wait_for_element(self.browser, 'class_name', 'fixed-header')

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/9b079794/test/selenium/cspages/cspage.py
----------------------------------------------------------------------
diff --git a/test/selenium/cspages/cspage.py b/test/selenium/cspages/cspage.py
new file mode 100644
index 0000000..087dc7e
--- /dev/null
+++ b/test/selenium/cspages/cspage.py
@@ -0,0 +1,21 @@
+# 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.
+
+class CloudStackPage(object):
+    def __init__():
+        self.browser = None
+

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/9b079794/test/selenium/cspages/dashboard/dashboardpage.py
----------------------------------------------------------------------
diff --git a/test/selenium/cspages/dashboard/dashboardpage.py b/test/selenium/cspages/dashboard/dashboardpage.py
index 4394199..c4b7711 100644
--- a/test/selenium/cspages/dashboard/dashboardpage.py
+++ b/test/selenium/cspages/dashboard/dashboardpage.py
@@ -20,10 +20,11 @@ from selenium.common.exceptions import *
 from selenium.webdriver.support.ui import WebDriverWait # available since 2.4.0
 from selenium.webdriver.common.action_chains import ActionChains as action
 from common import Global_Locators
+from cspages.cspage import CloudStackPage
 
 from common.shared import *
 
-class DashboardPage(object):
+class DashboardPage(CloudStackPage):
 
     def __init__(self, browser):
         self.browser = browser

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/9b079794/test/selenium/cspages/login/loginpage.py
----------------------------------------------------------------------
diff --git a/test/selenium/cspages/login/loginpage.py b/test/selenium/cspages/login/loginpage.py
index e7795d9..f4b0e8a 100644
--- a/test/selenium/cspages/login/loginpage.py
+++ b/test/selenium/cspages/login/loginpage.py
@@ -20,12 +20,13 @@ from selenium.common.exceptions import *
 from selenium.webdriver.support.ui import WebDriverWait # available since 2.4.0
 from selenium.webdriver.common.action_chains import ActionChains as action
 from common import Global_Locators
+from cspages.cspage import CloudStackPage
 
 from common.shared import *
 
 import pdb
 
-class LoginPage(object):
+class LoginPage(CloudStackPage):
     def __init__(self, browser):
         self.browser = browser
         self.username = ""
@@ -76,11 +77,9 @@ class LoginPage(object):
     @try_except_decor
     def logout(self, directly_logout = False):
 
-#       self.browser.set_window_size(1200,980)
         Shared.wait_for_element(self.browser, 'id', 'user')
 
         # must click this icon options first
-#       pdb.set_trace()
         if directly_logout == False:
             try:
                 ele = self.browser.find_element_by_xpath("//div[@id='user-options' and @style='display: block;']")
@@ -88,10 +87,8 @@ class LoginPage(object):
                     ele1 = self.browser.find_element_by_xpath("//div[@id='user' and @class='button']/div[@class='icon options']/div[@class='icon arrow']").click()
             except NoSuchElementException as err:
                 ele1 = self.browser.find_element_by_xpath("//div[@id='user' and @class='button']/div[@class='icon options']/div[@class='icon arrow']").click()
+        time.sleep(1)
 
-        # this is for cs 4.2.0-2
-#       ele2 = self.browser.find_element_by_xpath("//div[@id='header']/div[@id='user-options']")
-        # this is for cs 4.4.0
         ele2 = self.browser.find_element_by_xpath("//div[@id='user' and @class='button']/div[@id='user-options']/a[1]").click()
 
         Shared.wait_for_element(self.browser, 'class_name', 'login')

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/9b079794/test/selenium/cstests/smoketests/adduser_test.py
----------------------------------------------------------------------
diff --git a/test/selenium/cstests/smoketests/adduser_test.py b/test/selenium/cstests/smoketests/adduser_test.py
new file mode 100644
index 0000000..b19a060
--- /dev/null
+++ b/test/selenium/cstests/smoketests/adduser_test.py
@@ -0,0 +1,103 @@
+# 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.
+
+import unittest
+import sys, os, time
+import json
+
+sys.path.append('./')
+
+import browser.firefox as firefox
+import common.shared as shared
+from cstests.smoketests.smokecfg import smokecfg
+import cspages.login.loginpage as loginpage
+import cspages.dashboard.dashboardpage as dashboardpage
+import cspages.accounts.accountspage as accountspage
+import cspages.accounts.userspage as userspage
+
+# from cstests.smoketests import smokecfg as smokecfg
+
+class TestCSAddUser(unittest.TestCase):
+    def setUp(self):
+        # Create a new instance of the Firefox browser
+        self.browser = firefox.Firefox('firefox')
+
+    def tearDown(self):
+        self.browser.quit_browser()
+
+    def test_success(self):
+        self.browser.set_url(smokecfg['cssite'])
+        self.loginpage = loginpage.LoginPage(self.browser.get_browser())
+
+        # wait for at most 5 minutes, in case we have an anoyingly slow server
+        shared.Shared.wait_for_element(self.browser.get_browser(), 'class_name', 'select-language', waittime = 300)
+
+        # language selection must be done before username and password
+        self.loginpage.set_language(smokecfg['language'])
+
+        shared.Shared.wait_for_element(self.browser.get_browser(), 'class_name', 'fields', waittime = 300)
+
+        self.loginpage.set_username(smokecfg['username'])
+        self.loginpage.set_password(smokecfg['password'])
+        self.loginpage.login()
+
+        shared.Shared.wait_for_element(self.browser.browser, 'id', 'navigation')
+
+        time.sleep(3)
+
+        self.dashboardpage = dashboardpage.DashboardPage(self.browser.get_browser())
+
+        # navigate to Accounts page
+        self.dashboardpage.navigate_to('accounts')
+
+        # make sure we are on Accounts page
+        activeitem = self.dashboardpage.get_active_item()
+        if activeitem.find('accounts') < 0:
+            self.assertRaises(ValueError, self.dashboardpage.get_active_item(), activeitem)
+
+        # now we are at Accounts page
+        self.accountspage = accountspage.AccountsPage(self.browser.get_browser())
+        self.accountspage.select_account(username = smokecfg['account']['username'],
+                                      domain = smokecfg['account']['domain'],
+                                      type = smokecfg['account']['type'],
+                                     )
+
+        # now we are at users page
+        self.userspage = userspage.UsersPage(self.browser.get_browser())
+        self.userspage.add_user(username  = smokecfg['new user']['username'],
+                                password  = smokecfg['new user']['password'],
+                                email     = smokecfg['new user']['email'],
+                                firstname = smokecfg['new user']['firstname'],
+                                lastname  = smokecfg['new user']['lastname'],
+                                timezone  = smokecfg['new user']['timezone'],
+                              )
+
+        self.loginpage.logout()
+
+        shared.Shared.wait_for_element(self.browser.browser, 'class_name', 'login')
+
+    def xtest_failure_8(self):
+        self.browser.set_url(smokecfg['cssite'])
+        self.loginpage = loginpage.LoginPage(self.browser.get_browser())
+        # language selection must be done before username and password
+        self.loginpage.set_language(smokecfg['language'])
+        self.loginpage.set_username(smokecfg['sqlinjection_5'])
+        self.loginpage.set_password(smokecfg['password'])
+        self.loginpage.login(expect_fail = True)
+
+if __name__ == '__main__':
+    unittest.main()

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/9b079794/test/selenium/cstests/smoketests/adduseraccount_test.py
----------------------------------------------------------------------
diff --git a/test/selenium/cstests/smoketests/adduseraccount_test.py b/test/selenium/cstests/smoketests/adduseraccount_test.py
new file mode 100644
index 0000000..e687c6b
--- /dev/null
+++ b/test/selenium/cstests/smoketests/adduseraccount_test.py
@@ -0,0 +1,96 @@
+# 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.
+
+import unittest
+import sys, os, time
+import json
+
+sys.path.append('./')
+
+import browser.firefox as firefox
+import common.shared as shared
+from cstests.smoketests.smokecfg import smokecfg
+import cspages.login.loginpage as loginpage
+import cspages.dashboard.dashboardpage as dashboardpage
+import cspages.accounts.accountspage as accountspage
+
+# from cstests.smoketests import smokecfg as smokecfg
+
+class TestCSAddUserAccount(unittest.TestCase):
+    def setUp(self):
+        # Create a new instance of the Firefox browser
+        self.browser = firefox.Firefox('firefox')
+
+    def tearDown(self):
+        self.browser.quit_browser()
+
+    def test_success(self):
+        self.browser.set_url(smokecfg['cssite'])
+        self.loginpage = loginpage.LoginPage(self.browser.get_browser())
+
+        # wait for at most 5 minutes, in case we have an anoyingly slow server
+        shared.Shared.wait_for_element(self.browser.get_browser(), 'class_name', 'select-language', waittime = 300)
+
+        # language selection must be done before username and password
+        self.loginpage.set_language(smokecfg['language'])
+
+        shared.Shared.wait_for_element(self.browser.get_browser(), 'class_name', 'fields', waittime = 300)
+
+        self.loginpage.set_username(smokecfg['username'])
+        self.loginpage.set_password(smokecfg['password'])
+        self.loginpage.login()
+
+        shared.Shared.wait_for_element(self.browser.browser, 'id', 'navigation')
+
+        time.sleep(3)
+
+        self.dashboardpage = dashboardpage.DashboardPage(self.browser.get_browser())
+
+        # navigate to Accounts page
+        self.dashboardpage.navigate_to('accounts')
+
+        # make sure we are on Accounts page
+        activeitem = self.dashboardpage.get_active_item()
+        if activeitem.find('accounts') < 0:
+            self.assertRaises(ValueError, self.dashboardpage.get_active_item(), activeitem)
+
+        # now we are at Accounts page
+        self.accountspage = accountspage.AccountsPage(self.browser.get_browser())
+        self.accountspage.add_account(username = smokecfg['new user account']['username'],
+                                      password = smokecfg['new user account']['password'],
+                                      email = smokecfg['new user account']['email'],
+                                      firstname = smokecfg['new user account']['firstname'],
+                                      lastname = smokecfg['new user account']['lastname'],
+                                      domain = smokecfg['new user account']['domain'],
+                                      type = smokecfg['new user account']['type'],
+                                      timezone = smokecfg['new user account']['timezone'],
+                                     )
+        self.loginpage.logout()
+
+        shared.Shared.wait_for_element(self.browser.browser, 'class_name', 'login')
+
+    def xtest_failure_8(self):
+        self.browser.set_url(smokecfg['cssite'])
+        self.loginpage = loginpage.LoginPage(self.browser.get_browser())
+        # language selection must be done before username and password
+        self.loginpage.set_language(smokecfg['language'])
+        self.loginpage.set_username(smokecfg['sqlinjection_5'])
+        self.loginpage.set_password(smokecfg['password'])
+        self.loginpage.login(expect_fail = True)
+
+if __name__ == '__main__':
+    unittest.main()

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/9b079794/test/selenium/cstests/smoketests/deleteuser_test.py
----------------------------------------------------------------------
diff --git a/test/selenium/cstests/smoketests/deleteuser_test.py b/test/selenium/cstests/smoketests/deleteuser_test.py
new file mode 100644
index 0000000..8d3d28d
--- /dev/null
+++ b/test/selenium/cstests/smoketests/deleteuser_test.py
@@ -0,0 +1,100 @@
+# 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.
+
+import unittest
+import sys, os, time
+import json
+
+sys.path.append('./')
+
+import browser.firefox as firefox
+import common.shared as shared
+from cstests.smoketests.smokecfg import smokecfg
+import cspages.login.loginpage as loginpage
+import cspages.dashboard.dashboardpage as dashboardpage
+import cspages.accounts.accountspage as accountspage
+import cspages.accounts.userspage as userspage
+
+# from cstests.smoketests import smokecfg as smokecfg
+
+class TestCSDeleteUser(unittest.TestCase):
+    def setUp(self):
+        # Create a new instance of the Firefox browser
+        self.browser = firefox.Firefox('firefox')
+
+    def tearDown(self):
+        self.browser.quit_browser()
+
+    def test_success(self):
+        self.browser.set_url(smokecfg['cssite'])
+        self.loginpage = loginpage.LoginPage(self.browser.get_browser())
+
+        # wait for at most 5 minutes, in case we have an anoyingly slow server
+        shared.Shared.wait_for_element(self.browser.get_browser(), 'class_name', 'select-language', waittime = 300)
+
+        # language selection must be done before username and password
+        self.loginpage.set_language(smokecfg['language'])
+
+        shared.Shared.wait_for_element(self.browser.get_browser(), 'class_name', 'fields', waittime = 300)
+
+        self.loginpage.set_username(smokecfg['username'])
+        self.loginpage.set_password(smokecfg['password'])
+        self.loginpage.login()
+
+        shared.Shared.wait_for_element(self.browser.browser, 'id', 'navigation')
+
+        time.sleep(3)
+
+        self.dashboardpage = dashboardpage.DashboardPage(self.browser.get_browser())
+
+        # navigate to Accounts page
+        self.dashboardpage.navigate_to('accounts')
+
+        # make sure we are on Accounts page
+        activeitem = self.dashboardpage.get_active_item()
+        if activeitem.find('accounts') < 0:
+            self.assertRaises(ValueError, self.dashboardpage.get_active_item(), activeitem)
+
+        # now we are at Accounts page
+        self.accountspage = accountspage.AccountsPage(self.browser.get_browser())
+        self.accountspage.select_account(username = smokecfg['account']['username'],
+                                      domain = smokecfg['account']['domain'],
+                                      type = smokecfg['account']['type'],
+                                     )
+
+        # now we are at users page
+        self.userspage = userspage.UsersPage(self.browser.get_browser())
+        self.userspage.delete_user(username  = smokecfg['new user']['username'],
+                                   firstname = smokecfg['new user']['firstname'],
+                                   lastname  = smokecfg['new user']['lastname'],
+                                  )
+
+        self.loginpage.logout()
+
+        shared.Shared.wait_for_element(self.browser.browser, 'class_name', 'login')
+
+    def xtest_failure_8(self):
+        self.browser.set_url(smokecfg['cssite'])
+        self.loginpage = loginpage.LoginPage(self.browser.get_browser())
+        # language selection must be done before username and password
+        self.loginpage.set_language(smokecfg['language'])
+        self.loginpage.set_username(smokecfg['sqlinjection_5'])
+        self.loginpage.set_password(smokecfg['password'])
+        self.loginpage.login(expect_fail = True)
+
+if __name__ == '__main__':
+    unittest.main()

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/9b079794/test/selenium/cstests/smoketests/deleteuseraccount_test.py
----------------------------------------------------------------------
diff --git a/test/selenium/cstests/smoketests/deleteuseraccount_test.py b/test/selenium/cstests/smoketests/deleteuseraccount_test.py
new file mode 100644
index 0000000..179646a
--- /dev/null
+++ b/test/selenium/cstests/smoketests/deleteuseraccount_test.py
@@ -0,0 +1,91 @@
+# 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.
+
+import unittest
+import sys, os, time
+import json
+
+sys.path.append('./')
+
+import browser.firefox as firefox
+import common.shared as shared
+from cstests.smoketests.smokecfg import smokecfg
+import cspages.login.loginpage as loginpage
+import cspages.dashboard.dashboardpage as dashboardpage
+import cspages.accounts.accountspage as accountspage
+
+# from cstests.smoketests import smokecfg as smokecfg
+
+class TestCSDeleteAccount(unittest.TestCase):
+    def setUp(self):
+        # Create a new instance of the Firefox browser
+        self.browser = firefox.Firefox('firefox')
+
+    def tearDown(self):
+        self.browser.quit_browser()
+
+    def test_success(self):
+        self.browser.set_url(smokecfg['cssite'])
+        self.loginpage = loginpage.LoginPage(self.browser.get_browser())
+
+        # wait for at most 5 minutes, in case we have an anoyingly slow server
+        shared.Shared.wait_for_element(self.browser.get_browser(), 'class_name', 'select-language', waittime = 300)
+
+        # language selection must be done before username and password
+        self.loginpage.set_language(smokecfg['language'])
+
+        shared.Shared.wait_for_element(self.browser.get_browser(), 'class_name', 'fields', waittime = 300)
+
+        self.loginpage.set_username(smokecfg['username'])
+        self.loginpage.set_password(smokecfg['password'])
+        self.loginpage.login()
+
+        shared.Shared.wait_for_element(self.browser.browser, 'id', 'navigation')
+
+        time.sleep(3)
+
+        self.dashboardpage = dashboardpage.DashboardPage(self.browser.get_browser())
+
+        # navigate to Accounts page
+        self.dashboardpage.navigate_to('accounts')
+
+        # make sure we are on Accounts page
+        activeitem = self.dashboardpage.get_active_item()
+        if activeitem.find('accounts') < 0:
+            self.assertRaises(ValueError, self.dashboardpage.get_active_item(), activeitem)
+
+        # now we are at Accounts page
+        self.accountspage = accountspage.AccountsPage(self.browser.get_browser())
+        self.accountspage.delete_account(username = smokecfg['new user account']['username'],
+                                         domain   = smokecfg['new user account']['domain'],
+                                         type     = smokecfg['new user account']['type'],
+                                        )
+        self.loginpage.logout()
+
+        shared.Shared.wait_for_element(self.browser.browser, 'class_name', 'login')
+
+    def xtest_failure_8(self):
+        self.browser.set_url(smokecfg['cssite'])
+        self.loginpage = loginpage.LoginPage(self.browser.get_browser())
+        # language selection must be done before username and password
+        self.loginpage.set_language(smokecfg['language'])
+        self.loginpage.set_username(smokecfg['sqlinjection_5'])
+        self.loginpage.set_password(smokecfg['password'])
+        self.loginpage.login(expect_fail = True)
+
+if __name__ == '__main__':
+    unittest.main()

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/9b079794/test/selenium/cstests/smoketests/login_logout_as_JohnD_test.py
----------------------------------------------------------------------
diff --git a/test/selenium/cstests/smoketests/login_logout_as_JohnD_test.py b/test/selenium/cstests/smoketests/login_logout_as_JohnD_test.py
new file mode 100644
index 0000000..a01f2f8
--- /dev/null
+++ b/test/selenium/cstests/smoketests/login_logout_as_JohnD_test.py
@@ -0,0 +1,61 @@
+# 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.
+
+import unittest
+import sys, os, time
+import json
+
+sys.path.append('./')
+
+import browser.firefox as firefox
+import cspages.login.loginpage as loginpage
+import common.shared as shared
+from cstests.smoketests.smokecfg import smokecfg
+
+# from cstests.smoketests import smokecfg as smokecfg
+
+class TestCSLoginLogout(unittest.TestCase):
+    def setUp(self):
+        # Create a new instance of the Firefox browser
+        self.browser = firefox.Firefox('firefox')
+
+    def tearDown(self):
+        self.browser.quit_browser()
+
+    def test_success(self):
+        self.browser.set_url(smokecfg['cssite'])
+        self.loginpage = loginpage.LoginPage(self.browser.get_browser())
+
+        # wait for at most 5 minutes, in case we have an anoyingly slow server
+        shared.Shared.wait_for_element(self.browser.get_browser(), 'class_name', 'select-language', waittime = 300)
+
+        # language selection must be done before username and password
+        self.loginpage.set_language(smokecfg['language'])
+
+        shared.Shared.wait_for_element(self.browser.get_browser(), 'class_name', 'fields', waittime = 300)
+
+        self.loginpage.set_username(smokecfg['new user account']['username'])
+        self.loginpage.set_password(smokecfg['new user account']['password'])
+        self.loginpage.login()
+
+        time.sleep(5)
+
+        self.loginpage.logout(directly_logout = True)
+        shared.Shared.wait_for_element(self.browser.browser, 'class_name', 'login', waittime = 300)
+
+if __name__ == '__main__':
+    unittest.main()

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/9b079794/test/selenium/cstests/smoketests/smokecfg.py
----------------------------------------------------------------------
diff --git a/test/selenium/cstests/smoketests/smokecfg.py b/test/selenium/cstests/smoketests/smokecfg.py
index 8bbb350..901c3ad 100644
--- a/test/selenium/cstests/smoketests/smokecfg.py
+++ b/test/selenium/cstests/smoketests/smokecfg.py
@@ -22,9 +22,8 @@ smokecfg = {
             'browser':         'Firefox',
 #           'window position': '10, 10',        # upper left coordinates
 #           'window size':     '2000, 1500',
-#           'cssite':          'http://127.0.0.1:8080/client/',
-#           'cssite':          'http://10.88.91.68:8080/client/',
-            'cssite':          'http://192.168.1.31:8080/client/',
+            'cssite':          'http://127.0.0.1:8080/client/',
+#           'cssite':          'http://192.168.1.31:8080/client/',
             'username':        'admin',
             'password':        'password',
             'badusername':     'badname',
@@ -35,6 +34,30 @@ smokecfg = {
             'sqlinjection_4':  '\'; drop table user--\'',
             'sqlinjection_5':  '\'OR\' \'=\'',
             'language':        'English',
-           }
 
+            # add a new user account
+            'new user account':{'username':   'JohnD',
+                                'password':   'password',
+                                'email':      'johndoe@aol.com',
+                                'firstname':  'John',
+                                'lastname':   'Doe',
+                                'domain':     'ROOT',
+                                'type':       'User',                   # either 'User' or 'Admin'
+                                'timezone':   'US/Eastern [Eastern Standard Time]',
+                               },
+            # add a new user under JohnD
+            'account':         {'username':   'JohnD',
+                                'domain':     'ROOT',
+                                'type':       'User',
+                               },
+            # add a new user
+            'new user':        {'username':   'JaneD',
+                                'password':   'password',
+                                'email':      'janedoe@aol.com',
+                                'firstname':  'Jane',
+                                'lastname':   'Doe',
+                                'timezone':   'US/Eastern [Eastern Standard Time]',
+                               },
+
+           }