feat: add charm-ci integration test workflow#687
Open
javierdelapuente wants to merge 45 commits into
Open
Conversation
Add files needed to run integration tests using canonical/charm-ci's reusable workflow alongside the existing observability workflow: - artifacts.yaml: charm build manifest (opcli artifacts init) - spread.yaml: integration-test backend with 14 MODULE variants - tests/integration/run/task.yaml: spread task bridging CHARM_PATH - concierge.yaml: microk8s + juju 3.6/stable provisioning - .github/workflows/integration-test-charm-ci.yaml: PR workflow The CHARM_PATH env var is extracted from opcli's --charm-file output since traefik's conftest uses CHARM_PATH rather than --charm-file. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
77da5c5 to
090ea1b
Compare
juju requires local charm paths to start with ./ or be absolute. opcli produces relative paths like ./built-charm-.../foo.charm, but Python's Path() strips the ./ prefix causing juju to error with 'charm is ambiguous'. Use realpath to convert to absolute path, matching what the observability workflow does. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Switch from microk8s to k8s provider with load balancer, add LXD, model defaults (test-mode, automatically-retry-hooks), and remove charmcraft (not needed - main charm is pre-built, testers are not used in this test setup). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Tester charms need charmcraft + LXD to build during integration tests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add pytest-invocation-mode: observability to spread.yaml (traefik uses CHARM_PATH env var, not --charm-file flags) - Replace custom grep-based task.yaml with standard opcli template - opcli pytest expand now handles CHARM_PATH automatically in observability mode Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This was referenced May 26, 2026
Add publish-charm-ci.yaml that: - Calls canonical/charm-ci publish-artifacts reusable workflow on push to main - Publishes to latest/edge channel - Releases charm libraries after successful publish using charming-actions Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replaced by publish-charm-ci.yaml which uses canonical/charm-ci publish-artifacts reusable workflow. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Also update the workflow name to 'Integration Tests' and fix the reference in publish-charm-ci.yaml. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Neither is needed for integration tests — charmcraft pack doesn't require a keyring, and the default channel is sufficient. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Not used by any automated integration test. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Calling request.getfixturevalue('ops_test') from within an async fixture
causes 'RuntimeError: This event loop is already running' because ops_test
is itself async — initializing it from inside a running event loop fails.
Instead, override ops_test in conftest.py to yield None for jubilant modules.
This prevents python-libjuju from attempting a juju 4 connection (which it
doesn't support), while keeping the original direct-parameter pattern for
setup_env intact.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Move juju fixture into conftest.py, honouring --model (concierge) and --keep-models pytest-operator options; use name='juju' to avoid shadowing the juju module import - Remove redundant inline juju fixtures from both jubilant test modules - Add _all_settled() helper (all_active + all_agents_idle) for more robust waits in test_dynamic_configs_jubilant - Fix race in test_dynamic_config_removed_after_relation_removed: wait for the ingress relation to disappear from status before asserting the config file is gone Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…emplate charm-ci PR #45 replaced the pytest-invocation-mode enum with Jinja2 templates. Migrate from the removed 'observability' mode to the new pytest-environment-template key, which sets CHARM_PATH for the tests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add pytest-arguments-template: "" to suppress the default pfe-style --charm-file flag; traefik tests use CHARM_PATH env var instead, which is set by pytest-environment-template. Without this, both CHARM_PATH and --charm-file=... were passed, causing pytest to reject the unknown --charm-file argument. - Fix import order in conftest.py (ruff I001: jubilant before juju) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Path('./foo/bar.charm') strips the leading ./ so is_local_charm() in
python-libjuju fails both startswith('.') and os.path.isabs() checks,
causing it to treat the charm as a Charmhub URL and send empty string
to Juju. Using .resolve() makes it absolute.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Same Path('./...') issue as in conftest.py: juju CLI also rejects
relative paths without ./ prefix as ambiguous.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Create tests/integration/jubilant/ with its own conftest.py that owns traefik_charm, juju, and no-op shadows for the two autouse fixtures (copy_traefik_library_into_tester_charms, setup_env) - Move test_dynamic_configs_jubilant.py and test_tls_multi_unit_jubilant.py into the new subdirectory; remove their now-redundant local traefik_charm fixtures - Clean up tests/integration/conftest.py: remove ops_test override, remove jubilant name-guards, remove juju_fixture, remove ops_test is None check - Add a second integration-suite in spread.yaml for tests/integration/jubilant/ so charm-ci auto-discovers jubilant tests independently; move juju4 variant overrides into that suite Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add norecursedirs = ["jubilant"] to pytest config so auto-discovery doesn't recurse into tests/integration/jubilant/ during regular runs - Set pytest-arguments-template to pass tests/integration/jubilant/ as an explicit path for the jubilant suite (explicit paths override norecursedirs, so jubilant tests are still collected) This prevents -k test_tls from substring-matching test_tls_multi_unit_jubilant. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This reverts commit 670ea59.
test_dynamic_configs_jubilant → test_dynamic_configs (no regular counterpart) test_tls_multi_unit_jubilant → test_https_multi_unit + rename test function test_tls_on_all_units → test_https_on_all_units The regular suite has test_tls.py (MODULE test_tls). Pytest's -k does substring matching so -k test_tls would also collect test_tls_multi_unit_jubilant and its test_tls_on_all_units function. Renaming to test_https_multi_unit breaks this. Also drop the _jubilant suffix — the jubilant/ subdirectory already signals that. Update spread.yaml MODULE/CONCIERGE variant keys accordingly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
charm-ci@main changed _discover_modules_in to use rglob and return relative file paths (e.g. jubilant/test_dynamic_configs.py) instead of stems. MODULE values are now full paths relative to OPCLI_CWD, and pytest receives the file path directly (no -k) — exact file selection with no substring collision risk. This makes the two-suite workaround unnecessary. Revert to a single suite tests/integration/ whose auto-discover recursively finds all test files including those under jubilant/. Update juju4 variant keys to the new path-based naming convention: jubilant_test_dynamic_configs_juju4 / jubilant_test_https_multi_unit_juju4 with MODULE values as explicit file paths. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
seb4stien
reviewed
Jun 2, 2026
| branches: | ||
| - main | ||
|
|
||
| permissions: |
Contributor
There was a problem hiding this comment.
I think the recommendation is to have the permissions at the job level to be specific.
seb4stien
reviewed
Jun 2, 2026
| branches: | ||
| - main | ||
|
|
||
| permissions: |
Contributor
There was a problem hiding this comment.
Should be at the job level.
Contributor
There was a problem hiding this comment.
Which is already the case for publish
javierdelapuente
commented
Jun 2, 2026
| - .*_cache | ||
| integration-suites: | ||
| tests/integration/: | ||
| cwd: ./ |
Contributor
Author
There was a problem hiding this comment.
working-dir
javierdelapuente
commented
Jun 2, 2026
| pytest-arguments-template: "" | ||
| pytest-environment-template: | | ||
| {% for build in artifacts.charms[0].builds if build.arch == arch %} | ||
| CHARM_PATH={{ build.path }} |
Contributor
Author
There was a problem hiding this comment.
what guardrails can we have in here?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Integrates
canonical/charm-cireusable workflows for building, testing, and publishing the charm, replacing the old observability release workflow.CI workflows
.github/workflows/integration-test.yamlcharm-ci/integration-test.ymlon PRs; builds charm and runs spread jobs.github/workflows/publish.yamlcharm-ci/publish-artifacts.yml+ lib release on push to main.github/workflows/pull-request.yaml.github/workflows/quality-gates.yaml.github/workflows/release.yamlcharm-ci configuration
artifacts.yamlopcli artifacts init)spread.yamlintegration-suitesentry;opclirecursively auto-discovers alltest_*.pyfiles undertests/integration/including the jubilant subdirectory. Juju 4.0 variants for jubilant tests overrideCONCIERGEand set explicitMODULEfile paths.concierge.yamlconcierge-juju4.yamlJubilant tests refactor
The two existing jubilant tests (
test_dynamic_configs_jubilant.py,test_tls_multi_unit_jubilant.py) were moved into atests/integration/jubilant/subdirectory with a dedicatedconftest.py:tests/integration/jubilant/conftest.py(new): owns all jubilant-specific fixtures —traefik_charm(resolvesCHARM_PATHto absolute path),jujufixture (honours--model/--keep-models), and no-op autouse shadows that prevent the outersetup_envandcopy_traefik_library_into_tester_charmsfixtures (which depend onops_test) from running for jubilant tests.tests/integration/conftest.py: cleaned up — all jubilant-awareness removed (no moreops_testoverride, no"jubilant" in module.__name__guards, noimport jubilant).test_tls_multi_unit_jubilant.py→test_https_multi_unit.py(function also renamed totest_https_on_all_units) to avoid pytest-k test_tlssubstring collisions with the regular TLS test modules.How it works
opcliusingrglob). Each job receives the test file path as a positional pytest argument — not-k— so there is no risk of substring-based test selection bleeding across modules.concierge-juju4.yamlto bootstrap juju 4.0/stable.latest/edge, then releases charm libraries.