Fix router integration tests

The aim of this PS is to fix skipped router integration tests
listed below:
  - test_router_add_delete_interface (Partial-Bug: #1792028)
  - test_router_delete_interface_by_row (Partial-Bug: #1792028)
  - test_router_overview_data (Partial-Bug: #1792028)
  - test_router_create_admin (Partial-Bug: #1792028)

Change-Id: I82b15d347831762808b17fbda8c944a1ee5de564
This commit is contained in:
Pallav Gupta 2019-09-27 12:11:24 +05:30
parent d74d91e5a9
commit 558f6701ab
7 changed files with 100 additions and 58 deletions

View File

@ -88,6 +88,12 @@ NetworkGroup = [
cfg.StrOpt('network_cidr', cfg.StrOpt('network_cidr',
default='10.100.0.0/16', default='10.100.0.0/16',
help='The cidr block to allocate tenant ipv4 subnets from'), help='The cidr block to allocate tenant ipv4 subnets from'),
cfg.StrOpt(
'external_network',
# Devstack default external network is 'public' but it
# can be changed as per available external network.
default='public',
help='The external network for a router creation.'),
] ]
AvailableServiceGroup = [ AvailableServiceGroup = [

View File

@ -80,6 +80,10 @@ unique_last_password_count=2
[network] [network]
# The cidr block to allocate tenant ipv4 subnets from (string value) # The cidr block to allocate tenant ipv4 subnets from (string value)
network_cidr=10.100.0.0/16 network_cidr=10.100.0.0/16
# The external network for a router creation(string value)
# Devstack default external network is 'public' but it can be changed
# as per available external network.
external_network=public
[service_available] [service_available]
# Whether is Neutron expected to be available (boolean value) # Whether is Neutron expected to be available (boolean value)

View File

@ -17,19 +17,18 @@ from openstack_dashboard.test.integration_tests.pages import basepage
class NetworkOverviewPage(basepage.BaseNavigationPage): class NetworkOverviewPage(basepage.BaseNavigationPage):
DEFAULT_NETWORK_NAME = 'public' _network_dd_name_locator = (by.By.CSS_SELECTOR, 'dt[title*="Name"]+dd')
_network_dd_name_locator = (by.By.CSS_SELECTOR, _network_dd_status_locator = (by.By.CSS_SELECTOR, 'dt[title*="Status"]+dd')
'dt[title*="Name"]+dd')
_network_dd_status_locator = (by.By.CSS_SELECTOR,
'dt[title*="Status"]+dd')
def __init__(self, driver, conf): def __init__(self, driver, conf):
super(NetworkOverviewPage, self).__init__(driver, conf) super(NetworkOverviewPage, self).__init__(driver, conf)
self._page_title = 'Network Details' self._page_title = 'Network Details'
self._external_network = conf.network.external_network
def is_network_name_present(self, network_name=DEFAULT_NETWORK_NAME): def is_network_name_present(self, network_name=None):
if network_name is None:
network_name = self._external_network
dd_text = self._get_element(*self._network_dd_name_locator).text dd_text = self._get_element(*self._network_dd_name_locator).text
return dd_text == network_name return dd_text == network_name

View File

@ -10,7 +10,6 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from selenium.webdriver.common import by from selenium.webdriver.common import by
from openstack_dashboard.test.integration_tests.pages import basepage from openstack_dashboard.test.integration_tests.pages import basepage
@ -28,8 +27,7 @@ class InterfacesTable(tables.TableRegion):
return forms.FormRegion( return forms.FormRegion(
self.driver, self.driver,
self.conf, self.conf,
field_mappings=self.CREATE_INTERFACE_FORM_FIELDS field_mappings=self.CREATE_INTERFACE_FORM_FIELDS)
)
@tables.bind_table_action('delete') @tables.bind_table_action('delete')
def delete_interface(self, delete_button): def delete_interface(self, delete_button):
@ -46,37 +44,49 @@ class RouterInterfacesPage(basepage.BaseNavigationPage):
INTERFACES_TABLE_STATUS_COLUMN = 'Status' INTERFACES_TABLE_STATUS_COLUMN = 'Status'
INTERFACES_TABLE_NAME_COLUMN = 'Name' INTERFACES_TABLE_NAME_COLUMN = 'Name'
DEFAULT_IPv4_ADDRESS = '10.0.0.10' INTERFACES_TABLE_FIXED_IPS_COLUMN = 'Fixed IPs'
DEFAULT_SUBNET = 'private: 10.0.0.0/26 (private-subnet)' DEFAULT_IPv4_ADDRESS = '10.100.0.1'
_interface_subnet_selector = (by.By.CSS_SELECTOR, 'div > .themable-select')
_breadcrumb_routers_locator = (by.By.CSS_SELECTOR, _breadcrumb_routers_locator = (
'ol.breadcrumb>li>' + by.By.CSS_SELECTOR,
'a[href*="/dashboard/project/routers"]') 'ol.breadcrumb>li>' + 'a[href*="/project/routers"]')
def __init__(self, driver, conf, router_name): def __init__(self, driver, conf, router_name):
super(RouterInterfacesPage, self).__init__(driver, conf) super(RouterInterfacesPage, self).__init__(driver, conf)
self._page_title = router_name self._page_title = router_name
def _get_row_with_interface_name(self, name): def _get_row_with_interface_name(self, name):
return self.interfaces_table.get_row(self.INTERFACES_TABLE_NAME_COLUMN,
name)
def _get_row_with_ip_address(self):
return self.interfaces_table.get_row( return self.interfaces_table.get_row(
self.INTERFACES_TABLE_NAME_COLUMN, name) self.INTERFACES_TABLE_FIXED_IPS_COLUMN, self.DEFAULT_IPv4_ADDRESS)
@property
def subnet_selector(self):
src_elem = self._get_element(*self._interface_subnet_selector)
return forms.ThemableSelectFormFieldRegion(
self.driver,
self.conf,
src_elem=src_elem,
strict_options_match=False)
@property @property
def interfaces_table(self): def interfaces_table(self):
return InterfacesTable(self.driver, self.conf) return InterfacesTable(self.driver, self.conf)
@property @property
def interfaces_names(self): def interface_name(self):
return map(lambda row: row.cells[self. row = self._get_row_with_ip_address()
INTERFACES_TABLE_NAME_COLUMN].text, return row.cells[self.INTERFACES_TABLE_NAME_COLUMN].text
self.interfaces_table.rows)
def switch_to_routers_page(self): def switch_to_routers_page(self):
self._get_element(*self._breadcrumb_routers_locator).click() self._get_element(*self._breadcrumb_routers_locator).click()
def create_interface(self): def create_interface(self, subnet):
interface_form = self.interfaces_table.create_interface() interface_form = self.interfaces_table.create_interface()
interface_form.subnet_id.text = self.DEFAULT_SUBNET self.subnet_selector.text = subnet
interface_form.ip_address.text = self.DEFAULT_IPv4_ADDRESS interface_form.ip_address.text = self.DEFAULT_IPv4_ADDRESS
interface_form.submit() interface_form.submit()

View File

@ -10,7 +10,6 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from selenium.common import exceptions from selenium.common import exceptions
from selenium.webdriver.common import by from selenium.webdriver.common import by
@ -26,14 +25,14 @@ from openstack_dashboard.test.integration_tests.regions import tables
class RoutersTable(tables.TableRegion): class RoutersTable(tables.TableRegion):
name = "routers" name = "routers"
CREATE_ROUTER_FORM_FIELDS = ("name", "admin_state_up", CREATE_ROUTER_FORM_FIELDS = ("name", "admin_state_up", "external_network")
"external_network")
SET_GATEWAY_FORM_FIELDS = ("network_id",) SET_GATEWAY_FORM_FIELDS = ("network_id",)
@tables.bind_table_action('create') @tables.bind_table_action('create')
def create_router(self, create_button): def create_router(self, create_button):
create_button.click() create_button.click()
return forms.FormRegion(self.driver, self.conf, return forms.FormRegion(self.driver,
self.conf,
field_mappings=self.CREATE_ROUTER_FORM_FIELDS) field_mappings=self.CREATE_ROUTER_FORM_FIELDS)
@tables.bind_table_action('delete') @tables.bind_table_action('delete')
@ -49,14 +48,14 @@ class RoutersTable(tables.TableRegion):
@tables.bind_row_action('setgateway') @tables.bind_row_action('setgateway')
def set_gateway(self, set_gateway_button, row): def set_gateway(self, set_gateway_button, row):
set_gateway_button.click() set_gateway_button.click()
return forms.FormRegion(self.driver, self.conf, return forms.FormRegion(self.driver,
self.conf,
field_mappings=self.SET_GATEWAY_FORM_FIELDS) field_mappings=self.SET_GATEWAY_FORM_FIELDS)
class RoutersPage(basepage.BaseNavigationPage): class RoutersPage(basepage.BaseNavigationPage):
DEFAULT_ADMIN_STATE_UP = 'True' DEFAULT_ADMIN_STATE_UP = 'True'
DEFAULT_EXTERNAL_NETWORK = 'public'
ROUTERS_TABLE_NAME_COLUMN = 'Name' ROUTERS_TABLE_NAME_COLUMN = 'Name'
ROUTERS_TABLE_STATUS_COLUMN = 'Status' ROUTERS_TABLE_STATUS_COLUMN = 'Status'
ROUTERS_TABLE_NETWORK_COLUMN = 'External Network' ROUTERS_TABLE_NETWORK_COLUMN = 'External Network'
@ -67,29 +66,26 @@ class RoutersPage(basepage.BaseNavigationPage):
def __init__(self, driver, conf): def __init__(self, driver, conf):
super(RoutersPage, self).__init__(driver, conf) super(RoutersPage, self).__init__(driver, conf)
self._page_title = "Routers" self._page_title = "Routers"
self._external_network = conf.network.external_network
def _get_row_with_router_name(self, name): def _get_row_with_router_name(self, name):
return self.routers_table.get_row( return self.routers_table.get_row(self.ROUTERS_TABLE_NAME_COLUMN, name)
self.ROUTERS_TABLE_NAME_COLUMN, name)
@property @property
def routers_table(self): def routers_table(self):
return RoutersTable(self.driver, self.conf) return RoutersTable(self.driver, self.conf)
def create_router(self, name, admin_state_up=DEFAULT_ADMIN_STATE_UP, def create_router(self, name, admin_state_up=DEFAULT_ADMIN_STATE_UP):
external_network=DEFAULT_EXTERNAL_NETWORK):
create_router_form = self.routers_table.create_router() create_router_form = self.routers_table.create_router()
create_router_form.name.text = name create_router_form.name.text = name
create_router_form.admin_state_up.value = admin_state_up create_router_form.admin_state_up.value = admin_state_up
create_router_form.external_network.text = external_network create_router_form.external_network.text = self._external_network
create_router_form.submit() create_router_form.submit()
def set_gateway(self, router_id, def set_gateway(self, router_id):
network_name=DEFAULT_EXTERNAL_NETWORK):
row = self._get_row_with_router_name(router_id) row = self._get_row_with_router_name(router_id)
set_gateway_form = self.routers_table.set_gateway(row) set_gateway_form = self.routers_table.set_gateway(row)
set_gateway_form.network_id.text = network_name set_gateway_form.network_id.text = self._external_network
set_gateway_form.submit() set_gateway_form.submit()
def clear_gateway(self, name): def clear_gateway(self, name):
@ -111,6 +107,7 @@ class RoutersPage(basepage.BaseNavigationPage):
def cell_getter(): def cell_getter():
return row.cells[self.ROUTERS_TABLE_STATUS_COLUMN] return row.cells[self.ROUTERS_TABLE_STATUS_COLUMN]
try: try:
self._wait_till_text_present_in_element(cell_getter, 'Active') self._wait_till_text_present_in_element(cell_getter, 'Active')
except exceptions.TimeoutException: except exceptions.TimeoutException:
@ -122,19 +119,22 @@ class RoutersPage(basepage.BaseNavigationPage):
def cell_getter(): def cell_getter():
return row.cells[self.ROUTERS_TABLE_NETWORK_COLUMN] return row.cells[self.ROUTERS_TABLE_NETWORK_COLUMN]
try: try:
self._wait_till_text_present_in_element(cell_getter, '-') self._wait_till_text_present_in_element(cell_getter, '-')
except exceptions.TimeoutException: except exceptions.TimeoutException:
return False return False
return True return True
def is_gateway_set(self, name, network_name=DEFAULT_EXTERNAL_NETWORK): def is_gateway_set(self, name):
row = self._get_row_with_router_name(name) row = self._get_row_with_router_name(name)
def cell_getter(): def cell_getter():
return row.cells[self.ROUTERS_TABLE_NETWORK_COLUMN] return row.cells[self.ROUTERS_TABLE_NETWORK_COLUMN]
try: try:
self._wait_till_text_present_in_element(cell_getter, network_name) self._wait_till_text_present_in_element(cell_getter,
self._external_network)
except exceptions.TimeoutException: except exceptions.TimeoutException:
return False return False
return True return True

View File

@ -54,7 +54,6 @@ class FieldFactory(baseregion.BaseRegion):
class MetaBaseFormFieldRegion(type): class MetaBaseFormFieldRegion(type):
"""Register form field class in FieldFactory.""" """Register form field class in FieldFactory."""
def __init__(cls, name, bases, dct): def __init__(cls, name, bases, dct):
FieldFactory.register_field_cls(cls, bases) FieldFactory.register_field_cls(cls, bases)
super(MetaBaseFormFieldRegion, cls).__init__(name, bases, dct) super(MetaBaseFormFieldRegion, cls).__init__(name, bases, dct)
@ -231,8 +230,8 @@ class ThemableSelectFormFieldRegion(BaseFormFieldRegion):
_dropdown_menu_locator = (by.By.CSS_SELECTOR, 'ul.dropdown-menu > li > a') _dropdown_menu_locator = (by.By.CSS_SELECTOR, 'ul.dropdown-menu > li > a')
def __init__(self, driver, conf, strict_options_match=True, **kwargs): def __init__(self, driver, conf, strict_options_match=True, **kwargs):
super(ThemableSelectFormFieldRegion, self).__init__( super(ThemableSelectFormFieldRegion,
driver, conf, **kwargs) self).__init__(driver, conf, **kwargs)
self.strict_options_match = strict_options_match self.strict_options_match = strict_options_match
@property @property
@ -264,7 +263,7 @@ class ThemableSelectFormFieldRegion(BaseFormFieldRegion):
if self.strict_options_match: if self.strict_options_match:
match = text == str(option.text.strip()) match = text == str(option.text.strip())
else: else:
match = option.text.startswith(text) match = text in str(option.text.strip())
if match: if match:
option.click() option.click()
return return
@ -348,6 +347,8 @@ class FormRegion(BaseFormRegion):
self.fields_src_elem = self._get_element(*self._fields_locator) self.fields_src_elem = self._get_element(*self._fields_locator)
fields = self._get_form_fields() fields = self._get_form_fields()
for accessor_name, accessor_expr in self.field_mappings.items(): for accessor_name, accessor_expr in self.field_mappings.items():
if accessor_expr not in fields:
continue
if isinstance(accessor_expr, six.string_types): if isinstance(accessor_expr, six.string_types):
self._dynamic_properties[accessor_name] = fields[accessor_expr] self._dynamic_properties[accessor_name] = fields[accessor_expr]
else: # it is a class else: # it is a class
@ -426,8 +427,9 @@ class TabbedFormRegion(FormRegion):
def __init__(self, driver, conf, field_mappings=None, default_tab=0): def __init__(self, driver, conf, field_mappings=None, default_tab=0):
self.current_tab = default_tab self.current_tab = default_tab
super(TabbedFormRegion, self).__init__( super(TabbedFormRegion, self).__init__(driver,
driver, conf, field_mappings=field_mappings) conf,
field_mappings=field_mappings)
def _prepare_mappings(self, field_mappings): def _prepare_mappings(self, field_mappings):
return [ return [
@ -444,6 +446,8 @@ class TabbedFormRegion(FormRegion):
fields = self._get_form_fields() fields = self._get_form_fields()
current_tab_mappings = self.field_mappings[tab_index] current_tab_mappings = self.field_mappings[tab_index]
for accessor_name, accessor_expr in current_tab_mappings.items(): for accessor_name, accessor_expr in current_tab_mappings.items():
if accessor_expr not in fields:
continue
if isinstance(accessor_expr, six.string_types): if isinstance(accessor_expr, six.string_types):
self._dynamic_properties[accessor_name] = fields[accessor_expr] self._dynamic_properties[accessor_name] = fields[accessor_expr]
else: # it is a class else: # it is a class
@ -456,8 +460,9 @@ class TabbedFormRegion(FormRegion):
@property @property
def tabs(self): def tabs(self):
return menus.TabbedMenuRegion( return menus.TabbedMenuRegion(self.driver,
self.driver, self.conf, src_elem=self.src_elem) self.conf,
src_elem=self.src_elem)
class DateFormRegion(BaseFormRegion): class DateFormRegion(BaseFormRegion):

View File

@ -19,6 +19,8 @@ from openstack_dashboard.test.integration_tests.regions import messages
@decorators.services_required("neutron") @decorators.services_required("neutron")
class TestRouters(helpers.TestCase): class TestRouters(helpers.TestCase):
ROUTER_NAME = helpers.gen_random_resource_name("router") ROUTER_NAME = helpers.gen_random_resource_name("router")
NETWORK_NAME = helpers.gen_random_resource_name("network")
SUBNET_NAME = helpers.gen_random_resource_name("subnet")
@property @property
def routers_page(self): def routers_page(self):
@ -54,15 +56,15 @@ class TestRouters(helpers.TestCase):
self._delete_router() self._delete_router()
def _create_interface(self, interfaces_page): def _create_interface(self, interfaces_page):
interfaces_page.create_interface() interfaces_page.create_interface(self.SUBNET_NAME)
interface_name = interfaces_page.interfaces_names[0]
self.assertTrue( self.assertTrue(
interfaces_page.find_message_and_dismiss(messages.SUCCESS)) interfaces_page.find_message_and_dismiss(messages.SUCCESS))
self.assertFalse( self.assertFalse(
interfaces_page.find_message_and_dismiss(messages.ERROR)) interfaces_page.find_message_and_dismiss(messages.ERROR))
interface_name = interfaces_page.interface_name
self.assertTrue(interfaces_page.is_interface_present(interface_name)) self.assertTrue(interfaces_page.is_interface_present(interface_name))
self.assertTrue(interfaces_page.is_interface_status( self.assertTrue(
interface_name, 'Down')) interfaces_page.is_interface_status(interface_name, 'Down'))
def _delete_interface(self, interfaces_page, interface_name): def _delete_interface(self, interfaces_page, interface_name):
interfaces_page.delete_interface(interface_name) interfaces_page.delete_interface(interface_name)
@ -72,7 +74,18 @@ class TestRouters(helpers.TestCase):
interfaces_page.find_message_and_dismiss(messages.ERROR)) interfaces_page.find_message_and_dismiss(messages.ERROR))
self.assertFalse(interfaces_page.is_interface_present(interface_name)) self.assertFalse(interfaces_page.is_interface_present(interface_name))
@decorators.skip_because(bugs=['1792028']) def _create_subnet(self):
networks_page = self.home_pg.go_to_project_network_networkspage()
networks_page.create_network(self.NETWORK_NAME, self.SUBNET_NAME)
self.assertTrue(
networks_page.find_message_and_dismiss(messages.SUCCESS))
def _delete_subnet(self):
networks_page = self.home_pg.go_to_project_network_networkspage()
networks_page.delete_network(self.NETWORK_NAME)
self.assertTrue(
networks_page.find_message_and_dismiss(messages.SUCCESS))
def test_router_add_delete_interface(self): def test_router_add_delete_interface(self):
"""Tests the router interface creation and deletion functionalities: """Tests the router interface creation and deletion functionalities:
@ -87,6 +100,8 @@ class TestRouters(helpers.TestCase):
* Switches to the routers view by clicking on the breadcrumb link * Switches to the routers view by clicking on the breadcrumb link
* Follows the steps to delete the router * Follows the steps to delete the router
""" """
self._create_subnet()
self._create_router() self._create_router()
routers_page = self.routers_page routers_page = self.routers_page
@ -96,7 +111,7 @@ class TestRouters(helpers.TestCase):
self._create_interface(router_interfaces_page) self._create_interface(router_interfaces_page)
interface_name = router_interfaces_page.interfaces_names[0] interface_name = router_interfaces_page.interface_name
self._delete_interface(router_interfaces_page, interface_name) self._delete_interface(router_interfaces_page, interface_name)
@ -104,7 +119,8 @@ class TestRouters(helpers.TestCase):
self._delete_router() self._delete_router()
@decorators.skip_because(bugs=['1792028']) self._delete_subnet()
def test_router_delete_interface_by_row(self): def test_router_delete_interface_by_row(self):
"""Tests the router interface creation and deletion by row action: """Tests the router interface creation and deletion by row action:
@ -118,6 +134,8 @@ class TestRouters(helpers.TestCase):
* Switches to the routers view by clicking on the breadcrumb link * Switches to the routers view by clicking on the breadcrumb link
* Follows the steps to delete the router * Follows the steps to delete the router
""" """
self._create_subnet()
self._create_router() self._create_router()
routers_page = self.routers_page routers_page = self.routers_page
@ -127,7 +145,7 @@ class TestRouters(helpers.TestCase):
self._create_interface(router_interfaces_page) self._create_interface(router_interfaces_page)
interface_name = router_interfaces_page.interfaces_names[0] interface_name = router_interfaces_page.interface_name
router_interfaces_page.delete_interface_by_row_action(interface_name) router_interfaces_page.delete_interface_by_row_action(interface_name)
@ -135,7 +153,8 @@ class TestRouters(helpers.TestCase):
self._delete_router() self._delete_router()
@decorators.skip_because(bugs=['1792028']) self._delete_subnet()
def test_router_overview_data(self): def test_router_overview_data(self):
self._create_router() self._create_router()
@ -162,7 +181,6 @@ class TestRouters(helpers.TestCase):
class TestAdminRouters(helpers.AdminTestCase): class TestAdminRouters(helpers.AdminTestCase):
ROUTER_NAME = helpers.gen_random_resource_name("router") ROUTER_NAME = helpers.gen_random_resource_name("router")
@decorators.skip_because(bugs=['1792028'])
@decorators.services_required("neutron") @decorators.services_required("neutron")
def test_router_create_admin(self): def test_router_create_admin(self):
"""tests the router creation and deletion functionalities: """tests the router creation and deletion functionalities: