diff --git a/robottelo.properties.sample b/robottelo.properties.sample index c4a93559541..0ece6aee0d8 100644 --- a/robottelo.properties.sample +++ b/robottelo.properties.sample @@ -69,6 +69,66 @@ rhel7_repo=http://example.com/yum/repo_files/rhel7-updates.repo # in other words, the daemon is initialized with `--host tcp://0.0.0.0:`. external_url=http://localhost:2375 +[rhev] +# External RHEV to be added as a compute resource. +# name: Name of the RHEV compute resource +# hostname: RHEV API URL, for example: https://ovirt.example.com/api +# username: Login for RHEVM +# password: Password for RHEVM +# datacenter: RHEVM datacenter, for example: Default +name= +hostname= +username= +password= +datacenter= + +# vm_name: Name of VM to power On/Off & delete +vm_name= + +# Compute resource image data +# img_name: Chosen name of the image +# img_os: Operating system of the image +# img_arch: Architecture of the image +# img_username: Login to the image +# img_password: Password to the image +# img_image: Image on the external provider +img_name= +img_os= +img_arch= +img_username= +img_password= +img_image= + +[vmware] +# External Vmware to be added as a compute resource +# name: Name of the vmware compute resource +# vcenter: vmware vcenter URL +# username: Login for vmware +# password: Password for vmware +# datacenter: vmware datacenter +name= +vcenter= +username= +password= +datacenter= + +# vm_name: Name of VM to power On/Off & delete +vm_name= + +# Compute resource image data +# img_name: Chosen name of the image +# img_os: Operating system of the image +# img_arch: Architecture of the image +# img_username: Login to the image +# img_password: Password to the image +# img_image: Image on the external provider +img_name= +img_os= +img_arch= +img_username= +img_password= +img_image= + [foreman] admin.username=admin admin.password=changeme diff --git a/robottelo/ui/computeresource.py b/robottelo/ui/computeresource.py index 05d96129222..7df2e60beb5 100644 --- a/robottelo/ui/computeresource.py +++ b/robottelo/ui/computeresource.py @@ -1,6 +1,6 @@ # -*- encoding: utf-8 -*- from robottelo.common.constants import FILTER -from robottelo.ui.base import Base, UINoSuchElementError +from robottelo.ui.base import Base, UINoSuchElementError, UIError from robottelo.ui.locators import common_locators, locators, tab_locators from robottelo.ui.navigator import Navigator from selenium.webdriver.support.select import Select @@ -68,8 +68,8 @@ def _configure_resource_provider( 'button' )) self.click(locators[button_locator]) - self.find_element( - locators[param_locator] + Select( + self.find_element(locators[param_locator]) ).select_by_visible_text(parameter_value) def _configure_orgs(self, orgs, org_select): @@ -112,7 +112,8 @@ def create(self, name, provider_type, parameter_list, self._configure_locations(locations, loc_select) if orgs: self._configure_orgs(orgs, org_select) - self.click(common_locators['submit']) + #self.click(common_locators['submit']) + self.click(common_locators['submit'], wait_for_ajax=False) def search(self, name): """Searches existing compute resource from UI.""" @@ -142,6 +143,7 @@ def update(self, name, newname=None, parameter_list=None, def delete(self, name, really=True): """Removes the compute resource entity""" + Navigator(self.browser).go_to_compute_resources() self.delete_entity( name, really, @@ -149,3 +151,120 @@ def delete(self, name, really=True): locators['resource.delete'], drop_locator=locators['resource.dropdown'] ) + + def go_to_compute_resource(self, res_name): + """ Navigates to compute resource page """ + resource = self.search(res_name) + if resource is None: + raise UINoSuchElementError( + 'Could not find the resource {0}'.format(res_name)) + strategy, value = locators['resource.get_by_name'] + locator = (strategy, value % res_name) + self.click(locator) + self.wait_until_element(locators['resource.virtual_machines_tab']) + + def list_vms(self, res_name): + """ Lists vms on compute resource + + note: lists only vms that show up on the first page + """ + self.go_to_compute_resource(res_name) + self.click(locators['resource.virtual_machines_tab']) + vms = self.browser.find_elements_by_xpath( + "//table[contains(@id, 'DataTables')]//a[contains(@data-id, '%s')]" + % res_name) + return vms + + def add_image(self, res_name, parameter_list): + """ Adds an image to a compute resource """ + self.go_to_compute_resource(res_name) + self.click(locators['resource.image.add']) + self.wait_until_element(locators['resource.image.name']) + if parameter_list is None: + return + for parameter_name, parameter_value, parameter_type in parameter_list: + param_locator = '.'.join(( + 'resource.image', + (parameter_name.lower()).replace(' ', '_') + )) + if parameter_type == 'field': + self.find_element( + locators[param_locator]).send_keys(parameter_value) + elif parameter_type == 'select': + Select( + self.find_element(locators[param_locator]) + ).select_by_visible_text(parameter_value) + self.click(locators['resource.image.submit']) + self.wait_until_element(common_locators['notif.success']) + + def list_images(self, res_name): + """ Lists images on compute resource + + note: lists only images that show up on the first page + """ + self.go_to_compute_resource(res_name) + self.click(locators['resource.images_tab']) + images = self.browser.find_elements_by_xpath( + "//table[contains(@id, 'DataTables_Table_0')]/tbody/tr/*[1]") + return images + + def vm_action_stop(self, res_name, vm_name, really): + """ Stops a vm on the compute resource """ + self.go_to_compute_resource(res_name) + self.click(locators['resource.virtual_machines_tab']) + strategy, value = locators['resource.vm.power_button'] + locator = (strategy, value % (res_name, vm_name)) + button = self.find_element(locator) + if 'Off' in button.text: + self.click(locator, wait_for_ajax=False) + self.handle_alert(really) + #note: this should probably have a timeout + self.wait_until_element(common_locators['notif.success']) + else: + raise UIError( + 'Could not stop VM {0}. VM is not running'.format(vm_name) + ) + + def vm_action_start(self, res_name, vm_name): + """ Starts a vm on the compute resource """ + self.go_to_compute_resource(res_name) + self.click(locators['resource.virtual_machines_tab']) + strategy, value = locators['resource.vm.power_button'] + locator = (strategy, value % (res_name, vm_name)) + button = self.find_element(locator) + if 'On' in button.text: + self.click(locator,wait_for_ajax=False) + #note: this should probably have a timeout + self.wait_until_element(common_locators['notif.success']) + else: + raise UIError( + 'Could not start VM {0}. VM is already running'.format(vm_name) + ) + + def vm_action_toggle(self, res_name, vm_name, really): + """ Toggle power status of a vm on the compute resource """ + self.go_to_compute_resource(res_name) + self.click(locators['resource.virtual_machines_tab']) + strategy, value = locators['resource.vm.power_button'] + locator = (strategy, value % (res_name, vm_name)) + button = self.find_element(locator) + if "On" in button.text: + self.click(locator,wait_for_ajax=False) + self.wait_until_element(common_locators['notif.success']) + else: + self.click(locator, wait_for_ajax=False) + self.handle_alert(really) + self.wait_until_element(common_locators['notif.success']) + + def vm_delete(self, res_name, vm_name, really): + """ Removes a vm from the compute resource """ + self.go_to_compute_resource(res_name) + self.click(locators['resource.virtual_machines_tab']) + strategy, value = locators['resource.vm.delete_button_dropdown'] + locator = (strategy, value % (res_name, vm_name)) + self.click(locator) + strategy, value = locators['resource.vm.delete_button'] + locator = (strategy, value % (res_name, vm_name)) + self.click(locator, wait_for_ajax=False) + self.handle_alert(really) + self.wait_until_element(common_locators['notif.success']) diff --git a/robottelo/ui/locators.py b/robottelo/ui/locators.py index 110d1627de8..b921c24498d 100644 --- a/robottelo/ui/locators.py +++ b/robottelo/ui/locators.py @@ -817,9 +817,14 @@ def __iter__(self): "resource.username": (By.ID, "compute_resource_user"), "resource.password": (By.ID, "compute_resource_password"), "resource.datacenter": (By.XPATH, "//select[@id='compute_resource_uuid']"), + "resource.datacenter_vsphere": (By.XPATH, "//select[@id='compute_resource_datacenter']"), "resource.datacenter.button": ( By.XPATH, "//a[contains(@data-url, '/compute_resources/test_connection')]"), + "resource.datacenter_vsphere.button": ( + By.XPATH, + "//a[contains(@data-url, '/compute_resources/test_connection')]"), + "resource.quota_id": ( By.XPATH, "//select[@id='compute_resource_ovirt_quota']"), "resource.x509_certification_authorities": ( @@ -859,6 +864,84 @@ def __iter__(self): "resource.edit": ( By.XPATH, "//a[contains(@data-id,'edit') and contains(@href,'%s')]"), + # TODO testing locators + + "resource.virtual_machines_tab": ( + By.XPATH, + "//a[contains(@href, 'vms')]" + ), + "resource.images_tab": ( + By.XPATH, + #"//a[contains(@href, 'images')]" + #"//a[contains(@text, 'Images')]" + "//a[.='Images']" + ), + #TODO this is not used + "resource.virtual_machines": ( + By.XPATH, + #"//table[@id='DataTables_Table_0']//a" + #"//table[contains(@id, 'DataTables')]//*[contains(@data-id, 'vms')]" + #"//table[contains(@id, 'DataTables')]/../a" + #"//table[contains(@id, 'DataTables')]/tbody//tr/td/a" + #"//a[contains(@data-id, %s)]" + #"//a[contains(@href, %s)]" + "//a[contains(@href, 'vms')]" + ), + "resource.get_by_name": ( + By.XPATH, + #"//a[not(contains(@data-id, 'edit')) and contains(@href, '%s')]" + "//a[not(contains(@href, 'search')) and contains(@href, '%s')]" + ), + "resource.vm.power_button": ( + By.XPATH, + #"//table[contains(@id, 'DataTables')]//a[contains(@data-id, '%s')]/../../*[5]//a" + "//table[contains(@id, 'DataTables')]//a[contains(@data-id, '%s') and .='%s']/../../td[5]//a" + ), + "resource.vm.delete_button_dropdown": ( + By.XPATH, + "//table[contains(@id, 'DataTables')]//a[contains(@data-id, '%s') and .='%s']/../../td[5]//a[2]" + ), + "resource.vm.delete_button": ( + By.XPATH, + "//table[contains(@id, 'DataTables')]//a[contains(@data-id, '%s') and .='%s']/../../td[5]//a[.='Delete']" + ), + "resource.image.add": ( + By.XPATH, + "//a[.='New Image']" + ), + "resource.image.name": ( + By.ID, + "image_name" + ), + "resource.image.operatingsystem": ( + By.XPATH, + "//select[@id='image_operatingsystem_id']" + ), + "resource.image.architecture": ( + By.XPATH, + "//select[@id='image_architecture_id']" + ), + "resource.image.username": ( + By.ID, + "image_username" + ), + "resource.image.password": ( + By.ID, + "image_password" + ), + "resource.image.image": ( + By.XPATH, + "//select[@id='image_uuid']" + ), + "resource.image.submit": ( + By.XPATH, + "//input[@data-id='aid_create_image']" + ), + "resource.image.delete": ( + By.XPATH, + "" + ), + # Hosts # host.primary diff --git a/tests/foreman/rhci/test_computeresources.py b/tests/foreman/rhci/test_computeresources.py new file mode 100644 index 00000000000..f5369a40dec --- /dev/null +++ b/tests/foreman/rhci/test_computeresources.py @@ -0,0 +1,224 @@ +from robottelo.test import UITestCase +from robottelo.common import conf +from robottelo.ui.session import Session +from robottelo.common.constants import FOREMAN_PROVIDERS +from robottelo.ui.factory import make_resource +from ddt import data, ddt + +@ddt +class ComputeResourceTestCase(UITestCase): + + default_org = 'Default Organization' + default_loc = 'Default Location' + + rhev_name = conf.properties['rhev.name'] + rhev_hostname_api = conf.properties['rhev.hostname'] + rhev_username = conf.properties['rhev.username'] + rhev_password = conf.properties['rhev.password'] + rhev_datacenter = conf.properties['rhev.datacenter'] + rhev_vm_name=conf.properties['rhev.vm_name'] + + vmware_name = conf.properties['vmware.name'] + vmware_vcenter = conf.properties['vmware.vcenter'] + vmware_username = conf.properties['vmware.username'] + vmware_password = conf.properties['vmware.password'] + vmware_datacenter = conf.properties['vmware.datacenter'] + vmware_vm_name=conf.properties['vmware.vm_name'] + + @data( + #{'name': rhev_name, + # 'provider': FOREMAN_PROVIDERS['rhev'], + # 'url': rhev_hostname_api, + # 'username': rhev_username, + # 'password': rhev_password, + # 'datacenter': rhev_datacenter, + #this is the label of the URL field for rhev + # 'url_name': 'URL', + #this is for RHEV datacenter locator + # 'dc_locator': 'datacenter'}, + {'name': vmware_name, + 'provider': FOREMAN_PROVIDERS['vmware'], + 'url': vmware_vcenter, + 'username': vmware_username, + 'password': vmware_password, + 'datacenter': vmware_datacenter, + #this is the label of the URL field for vmware + 'url_name': 'vcenterserver', + #this is for vmware datacenter locator + 'dc_locator': 'datacenter_vsphere'} + ) + def test_create_compute_resource(self, data): + """ @Test: Create a compute resource. + + @Assert: A compute resource is created + + @Feature: Compute Resource + """ + with Session(self.browser) as session: + make_resource( + session, + name=data['name'], + provider_type=data['provider'], + parameter_list=[ + [data['url_name'], data['url'], 'field'], + ['Username', data['username'], 'field'], + ['Password', data['password'], 'field'], + [data['dc_locator'], data['datacenter'], 'special select'] + ], + orgs=[self.default_org], + org_select=False, + locations=[self.default_loc], + loc_select=True + ) + search = self.compute_resource.search(data['name']) + self.assertIsNotNone(search) + + @data( + {'name': rhev_name, + 'new_name': '%s-updated' % rhev_name}, + {'name': vmware_name, + 'new_name': '%s-updated' % vmware_name} + #{'name': 'osp name'}, + #{'name': 'docker name'} + ) + def test_edit_compute_resource(self, data): + """ @Test: Edit a compute resource. + + @Assert: A compute resource with new name exists + + @Feature: Compute Resource + """ + search = self.compute_resource.search(data['name']) + self.assertIsNotNone(search) + self.compute_resource.update(name=data['name'], + newname=data['new_name']) + search = self.compute_resource.search(data['new_name']) + self.assertIsNotNone(search) + self.compute_resource.update(name=data['new_name'], + newname=data['name']) + search = self.compute_resource.search(data['name']) + self.assertIsNotNone(search) + + @data( + {'name': rhev_name}, + {'name': vmware_name} + #{'name': 'osp name'}, + #{'name': 'docker name'} + ) + def test_retrieve_vm_list(self, data): + """ @Test: Retrieve list of VMs. + + @Feature: Compute Resource + """ + print "%s:" % data['name'] + for item in self.compute_resource.list_vms(data['name']): + if item.text: + print "VM: %s" % item.text + + @data( + {'name': rhev_name}, + {'name': vmware_name} + #{'name': 'osp name'}, + #{'name': 'docker name'} + ) + def test_retrieve_template_list(self, data): + """ @Test: Retrieve list of templates.. + + @Feature: Compute Resource + """ + print "%s:" % data['name'] + for item in self.compute_resource.list_images(data['name']): + print "Image: %s" % item.text + + @data( + {'name': rhev_name, + 'vm_name': rhev_vm_name}, + {'name': vmware_name, + 'vm_name': vmware_vm_name} + ) + def test_vm_start_stop(self, data): + """ @Test: Start & Stop a VM. + + @Feature: Compute Resource + + note: assuming the VM is powered down when starting this test + """ + self.compute_resource.vm_action_start(data['name'], data['vm_name']) + self.compute_resource.vm_action_stop(data['name'], data['vm_name'], + True) + + @data( + {'name': rhev_name, + 'vm_name': rhev_vm_name}, + {'name': vmware_name, + 'vm_name': vmware_vm_name} + ) + def test_delete_vm(self, data): + """ @Test: Deletes a VM. + + @Feature: Compute Resource + """ + self.compute_resource.vm_delete(data['name'], data['vm_name'], True) + + res = rhev_name + image_name = 'test_auto_img' + os = 'CentOS 6.6' + arch = 'i386' + uname = 'testing' + passw = 'testing' + img = 'Blank' + + @data( + {'name': rhev_name, + 'img_name': conf.properties['rhev.img_name'], + 'img_os': conf.properties['rhev.img_os'], + 'img_arch': conf.properties['rhev.img_arch'], + 'img_uname': conf.properties['rhev.img_username'], + 'img_passw': conf.properties['rhev.img_password'], + 'img_img': conf.properties['rhev.img_image']}, + {'name': vmware_name, + 'img_name': conf.properties['vmware.img_name'], + 'img_os': conf.properties['vmware.img_os'], + 'img_arch': conf.properties['vmware.img_arch'], + 'img_uname': conf.properties['vmware.img_username'], + 'img_passw': conf.properties['vmware.img_password'], + 'img_img': conf.properties['vmware.img_image']} + ) + def test_add_image(self, data): + """ @Test: Adds an image to compute resource. + + @Assert: Image added is on the first page + + @Feature: Compute Resource + """ + parameter_list=[ + ['Name', data['img_name'], 'field'], + ['Operatingsystem', data['img_os'], 'select'], + ['Architecture', data['img_arch'], 'select'], + ['Username', data['img_uname'], 'field'], + ['Password', data['img_passw'], 'field'], + ['Image', data['img_img'], 'select'] + ] + self.compute_resource.add_image(data['name'], parameter_list) + for item in self.compute_resource.list_images(data['name']): + if item.text == data['img_name']: + search = True + self.assertIsNotNone(search) + + + @data( + {'name': rhev_name}, + {'name': vmware_name} + ) + def test_delete_compute_resource(self, data): + """ @Test: Edit a compute resource. + + @Assert: A compute resource with new name exists + + @Feature: Compute Resource + """ + search = self.compute_resource.search(data['name']) + self.assertIsNotNone(search) + self.compute_resource.delete(data['name']) + search = self.compute_resource.search(data['name']) + self.assertIsNone(search)