Tuesday, March 6, 2012

Automated Testing of Openstack Dashboard(Horizon)

OpenStack Dashboard (Horizon) is an incubated project in the OpenStack ecosystem, OpenStack offers open source software to build public and private clouds. OpenStack is a community and a project as well as a stack of open source software to help organizations run clouds for virtual computing or storage. OpenStack contains a collection of open source projects that are community-maintained including OpenStack Compute (Nova), OpenStack Object Storage (Swift), OpenStack Imaging Service (Glance), OpenStack Identity Service (keystone), OpenStack Dashboard (Horizon). OpenStack provides an operating platform, or toolkit, for orchestrating private and public clouds. Since its inception it has grown many folds, Here is a video showing its evolution.


                          


OpenStack Dashboard is a Django based application that integrates with cloud compute. It provides a visual way to interact with the cloud.It provides web-based interactions with the OpenStack Compute cloud controller through the OpenStack APIs.Horizon ships with three central dashboards, a “User Dashboard”, a “System Dashboard”, and a “Settings” dashboard. Between these three they cover the core OpenStack applications and deliver on Core Support.For more information about the Openstack-Dashboard project, please visit: http://horizon.openstack.org/

                          



In order to test horizon, we need  a working OpenStack installation. So lets pull the Silver Bullet script (DevStack) from github and run it.When it is done, it will show you something like this:
horizon is now available at http://10.10.10.18/
keystone is serving at http://10.10.10.18:5000/v2.0/
examples on using novaclient command line is in exercise.sh
the default users are: admin and demo
the password: root
This is your host ip: 10.10.10.18



If you try the host ip address in your browser, you will see the login page. On  successful login you will be redirected to a very nice system panel page from where you can manage your infrastructure.



For Automating the test scenarios, we have to create test data and test cases. Here are a couple of possible test cases for the Login Scenario.
                     

To automate these test cases and others like Launching an Image, Deleting Image, Running functional UI tests in a headless (no X-server), Taking Browser screenshots with no display, we will use Selenium Webdriver, PyVirtualDisplay (uses xvfb), unittest2, xlrd , firebug and a Data Driven Framework. All the data that we need in order to execute our tests will be pulled from the spreadsheet shown below. If you want to integrate your functional UI tests (Selenium/WebDriver) with Jenkins CI system then you must run your GUI tests in a headless X-server The problem is that Jenkins CI server has no display.



Let us first automate the test case for Launching of an Image.
##########################################################################################
#!/usr/bin/env python
import xlrd
import unittest2 as unittest
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait

class ImageLaunch(unittest.TestCase):

    def setUp(self):
        self.driver = webdriver.Firefox()

    def test_instance_creation(self):
        #Open a workbook
        workbook = xlrd.open_workbook('/home/armani/test_data/path.xls')

        #Get a sheet by name
        sheet1 = workbook.sheet_by_name('login')
        sheet2 = workbook.sheet_by_name('stack_instance2')
        for x in range(1,sheet1.nrows):
            for y in range(0,1):
                uname = sheet1.cell_value(x,y) # Extracting user name from the login sheet
                passwd = sheet1.cell_value(x,y+1) # Extracting password from the login sheet
                driver = self.driver
                driver.get("http://10.10.10.18")
                driver.find_element_by_id("id_username").send_keys(uname) #filling user name field
                driver.find_element_by_id("id_password").send_keys(passwd) #filling password field
                driver.find_element_by_id("home_login_btn").click()
                selection = list()
              
                #Pulling all the Xpath values from spreadsheet
                for x in range(1,sheet2.nrows):
                    for y in range(0,1):
                        selection.append(sheet2.cell_value(x,y+1))
                project_link = selection[0]
                images_link = selection[1]
                Select_image = selection[2]
                Launch_button = selection[3]
                server_name_text_field = selection[4]
                user_data_field = selection[5]
                select_the_flavor = selection[6]
                Number_of_instances = selection[7]
                Launch_Instance_Button = selection[8]
                running_state = selection[9]    
       
                #select the project or wait until the link is available
                WebDriverWait(driver, timeout=10).until(lambda x1: x1.find_element_by_xpath(project_link)).click()
              
                #Go to the images & snapshots page
                WebDriverWait(driver, timeout=10).until(lambda x: x.find_element_by_xpath(images_link)).click()
              
                #Select the first image
                driver.find_element_by_xpath(Select_image).click()
              

                #Launch the image
                driver.find_element_by_xpath(Launch_button).click()

                # fill the server name text field
                WebDriverWait(driver, timeout=10).until(lambda x:  \  
                 x.find_element_by_xpath(server_name_text_field)).send_keys("server1")
              
                #fill the user data field
                driver.find_element_by_xpath(user_data_field).send_keys("server1 user data")
                                                            
                #select the flavor
                select = driver.find_element_by_xpath(select_the_flavor)
                select.send_keys(Keys.DOWN)
                select.send_keys(Keys.RETURN)

                #Number of instances
                driver.find_element_by_xpath(Number_of_instances).clear()
                driver.find_element_by_xpath(Number_of_instances).send_keys("1")
              
              
                #Scroll Down and Launch Instance
                driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
                driver.find_element_by_xpath(Launch_Instance_Button).click()
                assert "Instances & Volumes" in driver.title
                                                                                                                                   

    def tearDown(self):
        self.driver.close()

if __name__ == "__main__":
    unittest.main()


Note: If there is a change in Xpath of any element, It has to be changed accordingly in the respective sheet.
##########################################################################################

To Run the above test  in a headless mode (no X-server), we have to make few changes in the above script.

#Import Display from pyvirtualdisplay
from pyvirtualdisplay import Display

#Changes in setUp() function
  def setUp(self):
        self.display = Display(visible=0, size=(800, 600))
        self.display.start()
        self.driver = webdriver.Firefox()


#Changes in tearDown() function
 def tearDown(self):
        self.driver.close()
        self.display.stop()

##########################################################################################
Now, Lets execute tests for Login Scenario. Lets execute test case TC002, the objective of this test case is if a user enters a wrong Username or Password, an error message should appear as " Error: Invalid username or password "


#!/usr/bin/env python
#TC002.py
import xlrd
import unittest2 as unittest
from selenium import webdriver
from selenium.webdriver.common.keys import Keys

class horizonLogin(unittest.TestCase):

    def setUp(self):
        self.driver = webdriver.Firefox()

    def test_search_in_python_org(self):
        #Open a workbook
        workbook = xlrd.open_workbook('/home/armani/test_data/path.xls')
        #Get a sheet by name
        sheet = workbook.sheet_by_name('invalid_user')
        for x in range(1,sheet.nrows):
            for y in range(0,1):
                uname = sheet.cell_value(x,y)
                passwd = sheet.cell_value(x,y+1)
                driver = self.driver
                driver.get("http://10.10.10.18")
                driver.find_element_by_id("id_username").send_keys(uname)
                driver.find_element_by_id("id_password").send_keys(passwd)
                driver.find_element_by_id("home_login_btn").click() #Click on Login
                msg = driver.find_element_by_xpath("//*[@id='splash']/div[1]/form/div[2]/div/p").text
                self.assertIn("Error: Invalid user name or password.",msg) # assert Error message
             

    def tearDown(self):
        self.driver.close()

if __name__ == "__main__":
    unittest.main()

##########################################################################################

#TC003
#!/usr/bin/env python
import xlrd
import unittest2 as unittest
from selenium import webdriver
from selenium.webdriver.common.keys import Keys

class horizonLogin(unittest.TestCase):

    def setUp(self):
        self.driver = webdriver.Firefox()

    def test_search_in_python_org(self):
        #Open a workbook
        workbook = xlrd.open_workbook('/home/armani/test_data/path.xls')
        #Get a sheet by name
        sheet = workbook.sheet_by_name('login')
        for x in range(1,sheet.nrows):
            for y in range(0,1):
                uname = sheet.cell_value(x,y)
                passwd = sheet.cell_value(x,y+1)
                driver = self.driver
                driver.get("http://10.10.10.18")
                driver.find_element_by_id("id_username").send_keys(uname)
                driver.find_element_by_id("home_login_btn").click()
                self.assertIn("This field is required.", driver.find_element_by_xpath("//*[@id='splash']/div[1]/form/div[2]/fieldset/div[2]/span[1]").text)
             

    def tearDown(self):
        self.driver.close()

if __name__ == "__main__":
    unittest.main()


 RESULTS:



Development History Visualisations of OpenStack Projects

(1)OpenStack Compute (Nova)


(2)OpenStack Object Storage (Swift)


(3) OpenStack Identity Service (keystone)


                                       



(4) OpenStack Imaging Service (Glance)


No comments:

Post a Comment