From 91677bfb0049a710f01371bf4cb15e9aab0f28c5 Mon Sep 17 00:00:00 2001 From: Jan Jasek Date: Tue, 29 Jul 2025 18:10:41 +0200 Subject: [PATCH] Add manila-ui job and first manila-ui integration tests Add manila-ui-integration-pytest job which deploy devstack with enabled manila, manila-ui, horizon and with a dummy backend. Add manila-ui-integration-pytest job among the check jobs as a non-voting. Add first bunch of manila shares tests: test_create_share_demo test_delete_share_demo test_edit_share_demo Change-Id: I62c6ac72d030b932f3eed99fdc8ac190072b5d6f Signed-off-by: Jan Jasek --- .zuul.yaml | 59 ++++++++ manila_ui/tests/selenium/conftest.py | 18 +++ .../tests/selenium/integration/test_shares.py | 131 ++++++++++++++++++ test-requirements.txt | 1 + tox.ini | 11 ++ 5 files changed, 220 insertions(+) create mode 100644 manila_ui/tests/selenium/conftest.py create mode 100644 manila_ui/tests/selenium/integration/test_shares.py diff --git a/.zuul.yaml b/.zuul.yaml index 05cb8584..d36789a5 100644 --- a/.zuul.yaml +++ b/.zuul.yaml @@ -13,6 +13,8 @@ - manila-ui-integration-tests: voting: false - manila-ui-tox-bandit + - manila-ui-integration-pytest: + voting: false gate: jobs: - manila-ui-integration-tests: @@ -89,6 +91,63 @@ horizon: true tox_envlist: integration +- job: + name: manila-ui-integration-pytest + parent: horizon-integration-pytest + required-projects: + - openstack/manila + - openstack/manila-ui + vars: + devstack_services: + manila: true + manila-ui: true + devstack_localrc: + SHARE_DRIVER: manila.tests.share.drivers.dummy.DummyDriver + MANILA_CONFIGURE_GROUPS: buenosaires,saopaulo,lima,bogota,membernet,adminnet + MANILA_CONFIGURE_DEFAULT_TYPES: true + MANILA_SERVICE_IMAGE_ENABLED: false + MANILA_SHARE_MIGRATION_PERIOD_TASK_INTERVAL: 1 + MANILA_SERVER_MIGRATION_PERIOD_TASK_INTERVAL: 10 + MANILA_REPLICA_STATE_UPDATE_INTERVAL: 10 + MANILA_DEFERRED_DELETE_TASK_INTERVAL: 10 + MANILA_DEFAULT_SHARE_TYPE_EXTRA_SPECS: 'snapshot_support=True create_share_from_snapshot_support=True revert_to_snapshot_support=True mount_snapshot_support=True' + MANILA_ENABLED_BACKENDS: buenosaires,saopaulo,lima,bogota + MANILA_OPTGROUP_buenosaires_driver_handles_share_servers: false + MANILA_OPTGROUP_buenosaires_replication_domain: DUMMY_DOMAIN + MANILA_OPTGROUP_buenosaires_share_backend_name: ALPHA + MANILA_OPTGROUP_buenosaires_share_driver: manila.tests.share.drivers.dummy.DummyDriver + MANILA_OPTGROUP_saopaulo_driver_handles_share_servers: false + MANILA_OPTGROUP_saopaulo_replication_domain: DUMMY_DOMAIN + MANILA_OPTGROUP_saopaulo_share_backend_name: BETA + MANILA_OPTGROUP_saopaulo_share_driver: manila.tests.share.drivers.dummy.DummyDriver + MANILA_OPTGROUP_lima_driver_handles_share_servers: true + MANILA_OPTGROUP_lima_network_config_group: membernet + MANILA_OPTGROUP_lima_share_backend_name: GAMMA + MANILA_OPTGROUP_lima_share_driver: manila.tests.share.drivers.dummy.DummyDriver + MANILA_OPTGROUP_lima_admin_network_config_group: membernet + MANILA_OPTGROUP_bogota_share_driver: manila.tests.share.drivers.dummy.DummyDriver + MANILA_OPTGROUP_bogota_driver_handles_share_servers: False + MANILA_OPTGROUP_bogota_share_backend_name: DELTA + MANILA_OPTGROUP_bogota_replication_domain: DUMMY_DOMAIN + MANILA_OPTGROUP_membernet_network_api_class: manila.network.standalone_network_plugin.StandaloneNetworkPlugin + MANILA_OPTGROUP_membernet_network_plugin_ipv4_enabled: true + MANILA_OPTGROUP_membernet_standalone_network_plugin_allowed_ip_ranges: 10.0.0.10-10.0.0.209 + MANILA_OPTGROUP_membernet_standalone_network_plugin_gateway: 10.0.0.1 + MANILA_OPTGROUP_membernet_standalone_network_plugin_mask: 24 + MANILA_OPTGROUP_membernet_standalone_network_plugin_network_type: vlan + MANILA_OPTGROUP_membernet_standalone_network_plugin_segmentation_id: 1010 + MANILA_OPTGROUP_adminnet_network_api_class: manila.network.standalone_network_plugin.StandaloneNetworkPlugin + MANILA_OPTGROUP_adminnet_standalone_network_plugin_gateway: 11.0.0.1 + MANILA_OPTGROUP_adminnet_standalone_network_plugin_mask: 24 + MANILA_OPTGROUP_adminnet_standalone_network_plugin_network_type: vlan + MANILA_OPTGROUP_adminnet_standalone_network_plugin_segmentation_id: 1011 + MANILA_OPTGROUP_adminnet_standalone_network_plugin_allowed_ip_ranges: 11.0.0.10-11.0.0.19,11.0.0.30-11.0.0.39,11.0.0.50-11.0.0.199 + MANILA_OPTGROUP_adminnet_network_plugin_ipv4_enabled: True + devstack_plugins: + manila: https://opendev.org/openstack/manila + manila-ui: https://opendev.org/openstack/manila-ui + tox_envlist: manila-ui-integration-pytest + tox_constraints_file: "{{ ansible_user_dir }}/{{ zuul.projects['opendev.org/openstack/requirements'].src_dir }}/upper-constraints.txt" - job: # Security testing for known issues diff --git a/manila_ui/tests/selenium/conftest.py b/manila_ui/tests/selenium/conftest.py new file mode 100644 index 00000000..3e416f00 --- /dev/null +++ b/manila_ui/tests/selenium/conftest.py @@ -0,0 +1,18 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from openstack_dashboard.test.selenium.conftest import config # noqa: F401 +from openstack_dashboard.test.selenium.conftest import driver # noqa: F401 +from openstack_dashboard.test.selenium.conftest import login # noqa: F401 +from openstack_dashboard.test.selenium.conftest import xdisplay # noqa: F401 +from openstack_dashboard.test.selenium.integration.conftest import \ + openstack_demo # noqa: F401 diff --git a/manila_ui/tests/selenium/integration/test_shares.py b/manila_ui/tests/selenium/integration/test_shares.py new file mode 100644 index 00000000..0e9aa6d8 --- /dev/null +++ b/manila_ui/tests/selenium/integration/test_shares.py @@ -0,0 +1,131 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import time + +from oslo_utils import uuidutils +import pytest + +from openstack_dashboard.test.selenium import widgets + + +@pytest.fixture +def share_name(): + return 'horizon_share_%s' % uuidutils.generate_uuid(dashed=False) + + +@pytest.fixture +def new_share(share_name, openstack_demo): + share = openstack_demo.shared_file_system.create_share( + name=share_name, + size=1, + share_protocol="NFS", + wait=True, + ) + wait_for_steady_state_of_share(openstack_demo, share_name) + yield share + openstack_demo.shared_file_system.delete_share(share) + + +@pytest.fixture +def clear_share(share_name, openstack_demo): + yield None + wait_for_steady_state_of_share(openstack_demo, share_name) + openstack_demo.shared_file_system.delete_share( + openstack_demo.shared_file_system.find_share(share_name).id) + + +def wait_for_steady_state_of_share(openstack, share_name): + for attempt in range(120): + if (openstack.shared_file_system.get_share( + openstack.shared_file_system.find_share( + share_name).id).status in + ["available", "error", "inactive"]): + break + else: + time.sleep(3) + + +def wait_for_share_is_deleted(openstack, share_name): + for attempt in range(120): + if openstack.shared_file_system.find_share(share_name) is None: + break + else: + time.sleep(3) + + +def test_create_share_demo(login, driver, share_name, + openstack_demo, + config, clear_share): + login('user') + url = '/'.join(( + config.dashboard.dashboard_url, + 'project', + 'shares', + )) + driver.get(url) + driver.find_element_by_link_text("Create Share").click() + share_form = driver.find_element_by_css_selector(".modal-content form") + share_form.find_element_by_id("id_name").send_keys(share_name) + share_form.find_element_by_id("id_size").send_keys("1") + share_form.find_element_by_css_selector( + ".btn-primary[value='Create']").click() + messages = widgets.get_and_dismiss_messages(driver, config) + assert f'Success: Creating share "{share_name}"' in messages + assert openstack_demo.shared_file_system.find_share(share_name) is not None + + +def test_delete_share_demo(login, driver, openstack_demo, + config, new_share): + login('user') + url = '/'.join(( + config.dashboard.dashboard_url, + 'project', + 'shares', + )) + driver.get(url) + rows = driver.find_elements_by_css_selector( + f"table#shares tr[data-display='{new_share.name}']") + assert len(rows) == 1 + actions_column = rows[0].find_element_by_css_selector("td.actions_column") + widgets.select_from_dropdown(actions_column, "Delete Share") + widgets.confirm_modal(driver) + messages = widgets.get_and_dismiss_messages(driver, config) + assert f"Success: Deleted Share: {new_share.name}" in messages + wait_for_share_is_deleted(openstack_demo, new_share.name) + assert openstack_demo.shared_file_system.find_share(new_share.name) is None + + +def test_edit_share_demo(login, driver, openstack_demo, + config, new_share): + login('user') + url = '/'.join(( + config.dashboard.dashboard_url, + 'project', + 'shares', + )) + driver.get(url) + rows = driver.find_elements_by_css_selector( + f"table#shares tr[data-display='{new_share.name}']") + assert len(rows) == 1 + rows[0].find_element_by_css_selector(".data-table-action").click() + share_form = driver.find_element_by_css_selector(".modal-content form") + share_form.find_element_by_id("id_description").send_keys( + f"EDITED_Description for: {new_share.name}") + share_form.find_element_by_css_selector( + ".btn-primary[value='Edit']").click() + messages = widgets.get_and_dismiss_messages(driver, config) + assert f'Success: Updating share "{new_share.name}"' in messages + assert (openstack_demo.shared_file_system.get_share( + openstack_demo.shared_file_system.find_share( + new_share.name).id).description == + f"EDITED_Description for: {new_share.name}") diff --git a/test-requirements.txt b/test-requirements.txt index 59199777..54b5581b 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -2,6 +2,7 @@ hacking>=6.1.0,<6.2.0 # Apache-2.0 coverage>=5.2.1 # Apache-2.0 ddt>=1.4.1 # MIT pytest>=5.3.5 # MIT +pytest-html>=2.0.1 #MPL-2.0 testrepository>=0.0.20 # Apache-2.0/BSD testscenarios>=0.4 # Apache-2.0/BSD testtools>=2.4.0 # MIT diff --git a/tox.ini b/tox.ini index 33507345..75f108ca 100644 --- a/tox.ini +++ b/tox.ini @@ -36,6 +36,17 @@ setenv = HORIZON_INTEGRATION_TESTS_CONFIG_FILE=manila_ui/tests/integration/horizon.conf commands = {envpython} {toxinidir}/manage.py test manila_ui --settings=manila_ui.tests.settings --tag integration +[testenv:manila-ui-integration-pytest] +# Run Manila pytest integration tests only +passenv = + DISPLAY + FFMPEG_INSTALLED + XAUTHORITY +setenv = + SELENIUM_HEADLESS=True +commands = + pytest manila_ui/tests/selenium/integration/ --junitxml="{toxinidir}/test_reports/manila_integration_pytest_results.xml" --html="{toxinidir}/test_reports/manila_integration_pytest_results.html" --self-contained-html {posargs:{toxinidir}/manila_ui/tests/selenium/integration} + [testenv:newnote] deps = -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}