Merge "pytest-based selenium tests add volume actions tests"
This commit is contained in:
commit
a77818d745
@ -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,
|
||||
)
|
||||
|
@ -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():
|
||||
|
@ -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(
|
||||
|
@ -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):
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user