Add Sunbeam feature functional test suite#652
Conversation
b11a6cf to
da340ba
Compare
da340ba to
fabe182
Compare
|
Can we think about replacing https://github.com/canonical/snap-openstack/blob/main/.github/workflows/build-snap.yml#L94 with these functional tests |
7d1ed04 to
7e6cc1e
Compare
6a292be to
7561df2
Compare
bab2a3b to
5905c21
Compare
There was a problem hiding this comment.
Pull request overview
Adds a new “feature functional” test suite intended to run against an existing Sunbeam deployment, with tox wiring and per-feature lifecycle tests (enable/verify/optional disable).
Changes:
- Add
functional-featuretox environment to execute the new feature functional test suite. - Introduce pytest-based feature tests plus CLI wrappers (Sunbeam + Juju) and a shared
BaseFeatureTest. - Add suite documentation, example configuration, and local ignores for config artifacts.
Reviewed changes
Copilot reviewed 32 out of 32 changed files in this pull request and generated 14 comments.
Show a summary per file
| File | Description |
|---|---|
| sunbeam-python/tox.ini | Adds functional-feature tox env to run the new suite. |
| sunbeam-python/tests/functional/feature/init.py | Declares the feature functional test package. |
| sunbeam-python/tests/functional/feature/.gitignore | Ignores local config/adminrc artifacts for the suite. |
| sunbeam-python/tests/functional/feature/README.md | Documents prerequisites, config, and how to run the suite. |
| sunbeam-python/tests/functional/feature/conftest.py | Adds pytest options and session fixtures for config + clients. |
| sunbeam-python/tests/functional/feature/pytest.ini | Suite-specific pytest settings (markers/opts/timeout). |
| sunbeam-python/tests/functional/feature/requirements.txt | Lists Python deps for running the suite standalone. |
| sunbeam-python/tests/functional/feature/test_config.yaml.example | Provides an example config for running against a deployment. |
| sunbeam-python/tests/functional/feature/test_features.py | Orchestrates running per-feature test classes. |
| sunbeam-python/tests/functional/feature/utils/init.py | Marks utility wrapper package. |
| sunbeam-python/tests/functional/feature/utils/sunbeam.py | Adds a SunbeamClient wrapper around the CLI. |
| sunbeam-python/tests/functional/feature/utils/juju.py | Adds a JujuClient wrapper using Jubilant. |
| sunbeam-python/tests/functional/feature/features/init.py | Marks feature test classes package. |
| sunbeam-python/tests/functional/feature/features/base.py | Introduces shared lifecycle logic and OpenStack env setup. |
| sunbeam-python/tests/functional/feature/features/baremetal.py | Adds baremetal feature lifecycle checks (currently skipped by runner). |
| sunbeam-python/tests/functional/feature/features/caas.py | Adds caas feature lifecycle checks + dependency enablement. |
| sunbeam-python/tests/functional/feature/features/dns.py | Adds dns feature lifecycle checks. |
| sunbeam-python/tests/functional/feature/features/images_sync.py | Adds images-sync feature lifecycle checks. |
| sunbeam-python/tests/functional/feature/features/instance_recovery.py | Adds instance-recovery feature lifecycle checks. |
| sunbeam-python/tests/functional/feature/features/ldap.py | Adds ldap feature lifecycle checks (currently skipped by runner). |
| sunbeam-python/tests/functional/feature/features/loadbalancer.py | Adds loadbalancer feature lifecycle checks. |
| sunbeam-python/tests/functional/feature/features/maintenance.py | Adds maintenance feature lifecycle checks (currently skipped by runner). |
| sunbeam-python/tests/functional/feature/features/observability.py | Adds observability embedded workflow checks. |
| sunbeam-python/tests/functional/feature/features/orchestration.py | Adds orchestration (heat) feature lifecycle checks. |
| sunbeam-python/tests/functional/feature/features/pro.py | Adds pro feature lifecycle checks (currently skipped by runner). |
| sunbeam-python/tests/functional/feature/features/resource_optimization.py | Adds resource-optimization feature lifecycle checks. |
| sunbeam-python/tests/functional/feature/features/secrets.py | Adds secrets feature lifecycle checks + vault prerequisite. |
| sunbeam-python/tests/functional/feature/features/shared_filesystem.py | Adds shared-filesystem (manila) feature lifecycle checks. |
| sunbeam-python/tests/functional/feature/features/telemetry.py | Adds telemetry feature lifecycle checks. |
| sunbeam-python/tests/functional/feature/features/tls.py | Adds TLS CA + TLS Vault test flows, CSR signing, and endpoint validation. |
| sunbeam-python/tests/functional/feature/features/validation.py | Adds validation feature lifecycle checks. |
| sunbeam-python/tests/functional/feature/features/vault.py | Adds vault enable/init/unseal/authorize flow and verification. |
Comments suppressed due to low confidence (1)
sunbeam-python/tests/functional/feature/features/base.py:262
_ensure_openstack_envends after logging an exception when writing/loading the generated openrc fails, and there is no fallback path whensunbeam openrcfails. This can leave OpenStack env vars unset and make all subsequentopenstackCLI checks fail; implement the documented fallback (e.g., load an existing adminrc) and/or return early with a clear skip/error when credentials can't be loaded.
except Exception: # noqa: BLE001
logger.exception(
"Failed to write or load openrc from %s", adminrc_path
)
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| ```bash | ||
| ../.venv/bin/python -m pytest \ | ||
| tests/functional/feature/test_features.py::test_<feature_name> \ | ||
| --config tests/functional/feature/test_config.yaml | ||
| ``` |
There was a problem hiding this comment.
The README examples pass --config tests/functional/feature/test_config.yaml, but conftest.py currently resolves --config relative to tests/functional/feature/, which will duplicate the path and skip. Either update the examples to use --config test_config.yaml (or adjust config path resolution in conftest.py to accept repo-relative paths).
| juju: | ||
| # Juju model name (default: "openstack") | ||
| model: "openstack" | ||
| # Juju controller (auto-detected from sunbeam if not specified) |
There was a problem hiding this comment.
This comment says the Juju controller is auto-detected from sunbeam when omitted, but the current JujuClient implementation doesn't do any controller detection/switching. Update the comment (or implement controller selection) so users aren't misled.
| # Juju controller (auto-detected from sunbeam if not specified) | |
| # Juju controller name (uncomment and set to target a specific controller) |
| vault: | ||
| disable_after: false # explicitly keep Vault enabled | ||
|
|
||
| You can also override this behaviour **from the command line** without editing | ||
| the config file, using the `--features-disable-after` pytest option. When |
There was a problem hiding this comment.
The fenced YAML block starting at You can also override this per feature: is missing a closing ``` before the following paragraph, so the rest of the document renders as code. Close the YAML fence after the vault: example.
| pytest>=7.4.0 | ||
| pytest-timeout>=2.1.0 | ||
| pyyaml>=6.0 | ||
| jubilant>=1.0.0 |
There was a problem hiding this comment.
jubilant>=1.0.0 here conflicts with the project dependency in pyproject.toml (currently jubilant>=1.3.0). Align the minimum versions (or explain why this requirements file intentionally differs) to avoid confusing or broken standalone installs of the feature test deps.
| jubilant>=1.0.0 | |
| jubilant>=1.3.0 |
| timeout = 1800 | ||
|
|
There was a problem hiding this comment.
timeout = 1800 requires the pytest-timeout plugin; it isn't included in the project's dev extra (and doesn't appear in uv.lock). If this pytest.ini is meant to be used in tox, either add pytest-timeout to the environment deps/dev extra or remove the timeout setting to avoid pytest failing with an unknown config option.
| timeout = 1800 |
| commands = uv run {[vars]uv_flags} \ | ||
| python -m pytest -s -vv tests/functional/feature \ | ||
| --config=test_config.yaml \ | ||
| --basetemp={env:HOME}/.local/share/openstack/tmp \ | ||
| {posargs} |
There was a problem hiding this comment.
tests/functional/feature/pytest.ini won't be picked up when running pytest from the repository root (pytest will use the top-level pyproject.toml config instead). If you want these marker/timeouts/settings applied for the tox env, pass -c tests/functional/feature/pytest.ini (or move the relevant options to the project-level pytest config).
| result = subprocess.run(cmd, check=True, capture_output=True, text=True) | ||
| if result.returncode != 0: | ||
| raise AssertionError( | ||
| "Basic OpenStack operation failed after TLS Vault enablement: " | ||
| f"openstack image list returned error: {result.stderr}" | ||
| ) |
There was a problem hiding this comment.
This returncode check is redundant/unreachable because subprocess.run(..., check=True) will raise on non-zero exit codes. Either drop the if result.returncode != 0 block or switch to check=False and handle stderr explicitly.
| result = subprocess.run(cmd, check=True, capture_output=True, text=True) | |
| if result.returncode != 0: | |
| raise AssertionError( | |
| "Basic OpenStack operation failed after TLS Vault enablement: " | |
| f"openstack image list returned error: {result.stderr}" | |
| ) | |
| subprocess.run(cmd, check=True, capture_output=True, text=True) |
| def is_connected(self) -> bool: | ||
| """Check if we can connect to the Sunbeam deployment.""" | ||
| result = subprocess.run( | ||
| ["sunbeam", "deployment", "list"], | ||
| capture_output=True, |
There was a problem hiding this comment.
is_connected() hardcodes sunbeam from PATH, while the rest of this wrapper uses self._sunbeam_cmd ("/snap/bin/sunbeam"). Use the same command path here (or consistently resolve via PATH) so connectivity checks behave the same as enable/disable/run.
| ```bash | ||
| ../.venv/bin/python -m pytest \ | ||
| tests/functional/feature/test_features.py::test_<feature_name> \ | ||
| --config tests/functional/feature/test_config.yaml \ | ||
| --features-disable-after true # or false |
There was a problem hiding this comment.
The fenced bash block starting at Or directly with the virtualenv Python: isn't closed until much later, which pulls headings and prose into the code block. Add a closing ``` right after the command example (after the --features-disable-after ... line).
| ] | ||
|
|
||
| self.enable() | ||
|
|
||
| # Automate the external CA flow: list CSRs, sign with our CA, and | ||
| # provide the signed certificate back to Vault. | ||
| self._sign_vault_csrs_and_install() |
There was a problem hiding this comment.
run_full_lifecycle() ignores the return value of self.enable(). If enablement fails, the subsequent CSR signing and validation steps will run anyway and fail in less clear ways; return early (or raise) when enable() returns False.
a459484 to
0b375a0
Compare
|
@ahmad-can Can you abandon this PR as you have already moved the functional tests to right repo |
No description provided.