pytest-based selenium tests add volume actions tests

test_extend_volume_demo
test_volume_launch_as_instance_demo
test_volume_upload_to_image_demo

Change-Id: Ic577a94514881e56d32087a4fc4d6a06414ff568
This commit is contained in:
Jan Jasek 2023-12-11 19:00:08 +01:00
parent 42915b6a78
commit 35da6c52e4
6 changed files with 225 additions and 132 deletions

View File

@ -11,6 +11,7 @@
# under the License.
import openstack as openstack_sdk
from oslo_utils import uuidutils
import pytest
from openstack_dashboard.test.selenium import widgets
@ -183,3 +184,91 @@ def complete_default_test_network(new_default_test_network,
new_default_test_router,
new_default_test_interface_for_router):
yield new_default_test_network
# Instances fixtures
@pytest.fixture
def instance_name():
return 'horizon_instance_%s' % uuidutils.generate_uuid(dashed=False)
@pytest.fixture(params=[(1, False)])
def new_instance_demo(complete_default_test_network, request, instance_name,
openstack_demo, config):
count = request.param[0]
auto_ip_param = request.param[1]
instance = openstack_demo.create_server(
instance_name,
image=config.image.images_list[0],
flavor=config.launch_instances.flavor,
availability_zone=config.launch_instances.available_zone,
network=complete_default_test_network.name,
auto_ip=auto_ip_param,
wait=True,
max_count=count,
)
yield instance
if count > 1:
for instance in range(0, count):
openstack_demo.delete_server(f"{instance_name}-{instance+1}")
else:
openstack_demo.delete_server(instance_name)
@pytest.fixture
def clear_instance_demo(instance_name, openstack_demo):
yield None
openstack_demo.delete_server(
instance_name,
wait=True,
)
# Volumes fixtures
@pytest.fixture(params=[1])
def volume_name(request):
count = request.param
vol_name_list = ['horizon_vol_%s' % uuidutils.generate_uuid(dashed=False)]
if count > 1:
vol_name_list = [f"{vol_name_list[0]}-{item}"
for item in range(1, count + 1)]
return vol_name_list
@pytest.fixture
def new_volume_demo(volume_name, openstack_demo, config):
for vol in volume_name:
volume = openstack_demo.create_volume(
name=vol,
image=config.image.images_list[0],
size=1,
wait=True,
)
yield volume
for vol in volume_name:
openstack_demo.delete_volume(
name_or_id=vol,
wait=True,
)
@pytest.fixture
def new_volume_admin(volume_name, openstack_admin, config):
for vol in volume_name:
volume = openstack_admin.create_volume(
name=vol,
image=config.image.images_list[0],
size=1,
wait=True,
)
yield volume
for vol in volume_name:
openstack_admin.delete_volume(
name_or_id=vol,
wait=True,
)

View File

@ -14,14 +14,9 @@ import re
from oslo_utils import uuidutils
import pytest
import test_instances
from openstack_dashboard.test.selenium import widgets
# Imported fixtures
instance_name = test_instances.instance_name
new_instance_demo = test_instances.new_instance_demo
@pytest.fixture
def floatingip_description():

View File

@ -10,49 +10,12 @@
# License for the specific language governing permissions and limitations
# under the License.
from oslo_utils import uuidutils
import pytest
from selenium.common import exceptions
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
import test_volumes
from openstack_dashboard.test.selenium import widgets
# Imported fixtures
volume_name = test_volumes.volume_name
new_volume_demo = test_volumes.new_volume_demo
@pytest.fixture
def instance_name():
return 'horizon_instance_%s' % uuidutils.generate_uuid(dashed=False)
@pytest.fixture(params=[(1, False)])
def new_instance_demo(complete_default_test_network, request, instance_name,
openstack_demo, config):
count = request.param[0]
auto_ip_param = request.param[1]
instance = openstack_demo.create_server(
instance_name,
image=config.image.images_list[0],
flavor=config.launch_instances.flavor,
availability_zone=config.launch_instances.available_zone,
network=complete_default_test_network.name,
auto_ip=auto_ip_param,
wait=True,
max_count=count,
)
yield instance
if count > 1:
for instance in range(0, count):
openstack_demo.delete_server(f"{instance_name}-{instance+1}")
else:
openstack_demo.delete_server(instance_name)
@pytest.fixture(params=[(1, False)])
def new_instance_admin(complete_default_test_network, request, instance_name,
@ -78,15 +41,6 @@ def new_instance_admin(complete_default_test_network, request, instance_name,
openstack_admin.delete_server(instance_name)
@pytest.fixture
def clear_instance_demo(instance_name, openstack_demo):
yield None
openstack_demo.delete_server(
instance_name,
wait=True,
)
@pytest.fixture
def clear_instance_admin(instance_name, openstack_admin):
yield None
@ -96,25 +50,6 @@ def clear_instance_admin(instance_name, openstack_admin):
)
def select_from_transfer_table(element, label):
"""Choose row from available Images, Flavors, Networks, etc.
in launch tab for example: m1.tiny for Flavor, cirros for image, etc.
"""
try:
element.find_element_by_xpath(
f".//*[text()='{label}']//ancestor::tr/td//*"
f"[@class='btn btn-default fa fa-arrow-up']").click()
except exceptions.NoSuchElementException:
try:
element.find_element_by_xpath(
f".//*[text()='{label}']//ancestor::tr/td//*"
f"[@class='btn btn-default fa fa-arrow-down']")
except exceptions.NoSuchElementException:
raise
def create_new_volume_during_create_instance(driver, required_state):
create_new_volume_btn = widgets.find_already_visible_element_by_xpath(
f".//*[@id='vol-create'][text()='{required_state}']", driver
@ -154,19 +89,19 @@ def test_create_instance_demo(complete_default_test_network, login, driver,
network_table = wizard.find_element_by_css_selector(
"ng-include[ng-form=launchInstanceNetworkForm]"
)
select_from_transfer_table(network_table, network)
widgets.select_from_transfer_table(network_table, network)
navigation.find_element_by_link_text("Flavor").click()
flavor_table = wizard.find_element_by_css_selector(
"ng-include[ng-form=launchInstanceFlavorForm]"
)
select_from_transfer_table(flavor_table, flavor)
widgets.select_from_transfer_table(flavor_table, flavor)
navigation.find_element_by_link_text("Source").click()
source_table = wizard.find_element_by_css_selector(
"ng-include[ng-form=launchInstanceSourceForm]"
)
# create_new_volume_during_create_instance(source_table, "No")
delete_volume_on_instance_delete(source_table, "Yes")
select_from_transfer_table(source_table, image)
widgets.select_from_transfer_table(source_table, image)
wizard.find_element_by_css_selector(
"button.btn-primary.finish").click()
@ -207,12 +142,12 @@ def test_create_instance_from_volume_demo(complete_default_test_network, login,
network_table = wizard.find_element_by_css_selector(
"ng-include[ng-form=launchInstanceNetworkForm]"
)
select_from_transfer_table(network_table, network)
widgets.select_from_transfer_table(network_table, network)
navigation.find_element_by_link_text("Flavor").click()
flavor_table = wizard.find_element_by_css_selector(
"ng-include[ng-form=launchInstanceFlavorForm]"
)
select_from_transfer_table(flavor_table, flavor)
widgets.select_from_transfer_table(flavor_table, flavor)
navigation.find_element_by_link_text("Source").click()
source_table = wizard.find_element_by_css_selector(
"ng-include[ng-form=launchInstanceSourceForm]"
@ -223,7 +158,7 @@ def test_create_instance_from_volume_demo(complete_default_test_network, login,
select_boot_sources_type_tab.find_element_by_css_selector(
"option[value='volume']").click()
delete_volume_on_instance_delete(source_table, "No")
select_from_transfer_table(source_table, volume_name)
widgets.select_from_transfer_table(source_table, volume_name)
wizard.find_element_by_css_selector("button.btn-primary.finish").click()
WebDriverWait(driver, config.selenium.page_timeout).until(
EC.invisibility_of_element_located(launch_instance_btn))
@ -331,19 +266,19 @@ def test_create_instance_admin(complete_default_test_network, login, driver,
network_table = wizard.find_element_by_css_selector(
"ng-include[ng-form=launchInstanceNetworkForm]"
)
select_from_transfer_table(network_table, network)
widgets.select_from_transfer_table(network_table, network)
navigation.find_element_by_link_text("Flavor").click()
flavor_table = wizard.find_element_by_css_selector(
"ng-include[ng-form=launchInstanceFlavorForm]"
)
select_from_transfer_table(flavor_table, flavor)
widgets.select_from_transfer_table(flavor_table, flavor)
navigation.find_element_by_link_text("Source").click()
source_table = wizard.find_element_by_css_selector(
"ng-include[ng-form=launchInstanceSourceForm]"
)
# create_new_volume_during_create_instance(source_table, "No")
delete_volume_on_instance_delete(source_table, "Yes")
select_from_transfer_table(source_table, image)
widgets.select_from_transfer_table(source_table, image)
wizard.find_element_by_css_selector(
"button.btn-primary.finish").click()
WebDriverWait(driver, config.selenium.page_timeout).until(

View File

@ -18,11 +18,6 @@ import test_volumes
from openstack_dashboard.test.selenium import widgets
# Imported fixtures
volume_name = test_volumes.volume_name
new_volume_demo = test_volumes.new_volume_demo
new_volume_admin = test_volumes.new_volume_admin
@pytest.fixture(params=[1])
def volume_snapshot_names(request):

View File

@ -12,56 +12,16 @@
import time
from oslo_utils import uuidutils
import pytest
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
import test_images
from openstack_dashboard.test.selenium import widgets
@pytest.fixture(params=[1])
def volume_name(request):
count = request.param
vol_name_list = ['horizon_vol_%s' % uuidutils.generate_uuid(dashed=False)]
if count > 1:
vol_name_list = [f"{vol_name_list[0]}-{item}"
for item in range(1, count + 1)]
return vol_name_list
@pytest.fixture
def new_volume_demo(volume_name, openstack_demo, config):
for vol in volume_name:
volume = openstack_demo.create_volume(
name=vol,
image=config.image.images_list[0],
size=1,
wait=True,
)
yield volume
for vol in volume_name:
openstack_demo.delete_volume(
name_or_id=vol,
wait=True,
)
@pytest.fixture
def new_volume_admin(volume_name, openstack_admin, config):
for vol in volume_name:
volume = openstack_admin.create_volume(
name=vol,
image=config.image.images_list[0],
size=1,
wait=True,
)
yield volume
for vol in volume_name:
openstack_admin.delete_volume(
name_or_id=vol,
wait=True,
)
# Import image fixtures
image_names = test_images.image_names
clear_image_demo = test_images.clear_image_demo
@pytest.fixture
@ -87,8 +47,8 @@ def clear_volume_admin(volume_name, openstack_admin):
def wait_for_steady_state_of_volume(openstack, volume_name):
for attempt in range(10):
if (openstack.block_storage.find_volume(volume_name).status in
["available", "error", "error_restoring", "error_extending",
"error_managing"]):
["available", "error", "in-use", "error_restoring",
"error_extending", "error_managing"]):
break
else:
time.sleep(3)
@ -196,6 +156,108 @@ def test_edit_volume_description_demo(login, driver, volume_name, config,
volume_name).description == f"EDITED_Description for: {volume_name}")
def test_extend_volume_demo(login, driver, openstack_demo, new_volume_demo,
config):
login('user')
url = '/'.join((
config.dashboard.dashboard_url,
'project',
'volumes',
))
driver.get(url)
rows = driver.find_elements_by_css_selector(
f"table#volumes tr[data-display='{new_volume_demo.name}']"
)
assert len(rows) == 1
assert(openstack_demo.block_storage.find_volume(
new_volume_demo.name).size == 1)
actions_column = rows[0].find_element_by_css_selector("td.actions_column")
widgets.select_from_dropdown(actions_column, "Extend Volume")
volume_form = driver.find_element_by_css_selector(".modal-dialog form")
volume_form.find_element_by_id("id_new_size").send_keys(2)
volume_form.find_element_by_css_selector(
".btn-primary[value='Extend Volume']").click()
messages = widgets.get_and_dismiss_messages(driver)
assert f'Info: Extending volume: "{new_volume_demo.name}"' in messages
assert(openstack_demo.block_storage.find_volume(
new_volume_demo.name).size == 2)
def test_volume_launch_as_instance_demo(login, driver, openstack_demo,
new_volume_demo, instance_name,
clear_instance_demo, config,
complete_default_test_network):
flavor = config.launch_instances.flavor
network = complete_default_test_network.name
login('user')
url = '/'.join((
config.dashboard.dashboard_url,
'project',
'volumes',
))
driver.get(url)
rows = driver.find_elements_by_css_selector(
f"table#volumes tr[data-display='{new_volume_demo.name}']"
)
assert len(rows) == 1
actions_column = rows[0].find_element_by_css_selector("td.actions_column")
widgets.select_from_dropdown(actions_column, "Launch as Instance")
wizard = driver.find_element_by_css_selector("wizard")
navigation = wizard.find_element_by_css_selector("div.wizard-nav")
widgets.find_already_visible_element_by_xpath(
".//*[@id='name']", wizard).send_keys(instance_name)
navigation.find_element_by_link_text("Flavor").click()
flavor_table = wizard.find_element_by_css_selector(
"ng-include[ng-form=launchInstanceFlavorForm]")
widgets.select_from_transfer_table(flavor_table, flavor)
navigation.find_element_by_link_text("Networks").click()
network_table = wizard.find_element_by_css_selector(
"ng-include[ng-form=launchInstanceNetworkForm]")
widgets.select_from_transfer_table(network_table, network)
wizard.find_element_by_css_selector(
"button.btn-primary.finish").click()
# For create instance - message appears earlier than the page is refreshed.
# We are unable to ensure that the message will be captured.
# Checking of message is skipped, we wait for refresh page
# and then result is checked.
# JJ
WebDriverWait(driver, config.selenium.page_timeout).until(
EC.invisibility_of_element_located(actions_column))
wait_for_steady_state_of_volume(openstack_demo, new_volume_demo.name)
assert(openstack_demo.block_storage.find_volume(
new_volume_demo.name).attachments[0]['server_id'] ==
openstack_demo.compute.find_server(instance_name).id)
def test_volume_upload_to_image_demo(login, driver, openstack_demo,
new_volume_demo, image_names,
clear_image_demo, config):
login('user')
url = '/'.join((
config.dashboard.dashboard_url,
'project',
'volumes',
))
driver.get(url)
rows = driver.find_elements_by_css_selector(
f"table#volumes tr[data-display='{new_volume_demo.name}']"
)
assert len(rows) == 1
actions_column = rows[0].find_element_by_css_selector("td.actions_column")
widgets.select_from_dropdown(actions_column, "Upload to Image")
volume_form = driver.find_element_by_css_selector(
".modal-dialog form")
volume_form.find_element_by_id("id_image_name").send_keys(image_names[0])
volume_form.find_element_by_css_selector(
".btn-primary[value='Upload']").click()
messages = widgets.get_and_dismiss_messages(driver)
assert(f'Info: Successfully sent the request to upload volume to image for '
f'volume: "{new_volume_demo.name}"' in messages)
wait_for_steady_state_of_volume(openstack_demo, new_volume_demo.name)
assert openstack_demo.compute.find_image(image_names[0]) is not None
@pytest.mark.parametrize('volume_name', [3], indirect=True)
def test_volumes_pagination_demo(login, driver, volume_name,
change_page_size_demo,

View File

@ -105,3 +105,20 @@ def get_image_table_definition(driver, sorting=False):
prev=is_prev_link_available(driver),
count=len(names), names=[names[0].text])
return actual_table
def select_from_transfer_table(element, label):
# Choose row from available Images, Flavors, Networks, etc.
# In launch tab for example: m1.tiny for Flavor, cirros for image, etc.
try:
element.find_element_by_xpath(
f".//*[text()='{label}']//ancestor::tr/td//*"
f"[@class='btn btn-default fa fa-arrow-up']").click()
except exceptions.NoSuchElementException:
try:
element.find_element_by_xpath(
f".//*[text()='{label}']//ancestor::tr/td//*"
f"[@class='btn btn-default fa fa-arrow-down']")
except exceptions.NoSuchElementException:
raise