Skip to content

Commit 9fd88f2

Browse files
committed
Migrate integration tests to Jubilant
python-libjuju is in maintenance only and its series map has no 26.04, so deploys on ubuntu@26.04 fail. Jubilant drives the juju CLI, which resolves the base and knows 26.04, so drop the libjuju revision pin. Signed-off-by: Seyeong Kim <seyeong.kim@canonical.com>
1 parent 4c14232 commit 9fd88f2

3 files changed

Lines changed: 33 additions & 66 deletions

File tree

tests/integration/conftest.py

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,12 @@
1616
"""Configure lldpd operator integration tests."""
1717

1818
import logging
19+
import pathlib
1920
import platform
20-
from pathlib import Path
21+
import subprocess
2122

23+
import jubilant
2224
import pytest
23-
from pytest_operator.plugin import OpsTest
2425

2526
logger = logging.getLogger(__name__)
2627

@@ -48,20 +49,25 @@ def charm_base(request) -> str:
4849

4950

5051
@pytest.fixture(scope="module")
51-
async def lldpd_charm(ops_test: OpsTest, charm_base: str) -> Path:
52-
# Multiple charms will be built, but the build_charm function only returns
53-
# the path to one of the charms. Find the charm that matches the charm_base
54-
# in order to test the right one.
55-
await ops_test.build_charm(".")
52+
def juju():
53+
"""Provide a temporary model, torn down at the end of the module."""
54+
with jubilant.temp_model(config={"update-status-hook-interval": "10s"}) as juju:
55+
yield juju
56+
57+
58+
@pytest.fixture(scope="module")
59+
def lldpd_charm(charm_base: str) -> pathlib.Path:
60+
# charmcraft packs one file per platform. Build and return the charm that
61+
# matches charm_base so the right one is tested.
62+
subprocess.run(["charmcraft", "pack"], check=True)
5663

5764
base = charm_base.replace("@", "-")
5865
arch = platform.machine()
5966
# convert the x86_64 arch into the amd64 arch used by charmcraft.
6067
if arch == "x86_64":
6168
arch = "amd64"
6269

63-
build_dir = (ops_test.tmp_path / "charms").absolute()
64-
charm_file = build_dir / f"lldpd_{base}-{arch}.charm"
70+
charm_file = pathlib.Path(f"lldpd_{base}-{arch}.charm").absolute()
6571
if not charm_file.exists():
6672
raise ValueError(f"Unable to find charm file {charm_file}")
6773

tests/integration/test_charm.py

Lines changed: 17 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -15,74 +15,39 @@
1515

1616
"""Test lldpd charm deployment."""
1717

18-
import asyncio
1918
import logging
20-
import pytest
19+
import pathlib
2120

22-
from pytest_operator.plugin import OpsTest
21+
import jubilant
22+
import pytest
2323

2424
logger = logging.getLogger(__name__)
2525

2626
NUM_UNITS = 2
2727

28-
# The charmhub "ubuntu" charm is published as a separate revision per base, and
29-
# libjuju resolves the bare "ubuntu" name to the 24.04 revision regardless of the
30-
# requested base. Pin the latest/stable revision that matches each base so the
31-
# subordinate can be tested on every base. Refresh these if the charm is
32-
# republished (charmhub.io/ubuntu, Releases tab).
33-
UBUNTU_REVISION = {
34-
"ubuntu@20.04": 26,
35-
"ubuntu@22.04": 77,
36-
"ubuntu@24.04": 79,
37-
"ubuntu@26.04": 81,
38-
}
3928

40-
41-
@pytest.mark.abort_on_fail
42-
@pytest.mark.skip_if_deployed
4329
@pytest.mark.order(1)
44-
async def test_build_and_deploy(
45-
ops_test: OpsTest, charm_base: str, lldpd_charm
30+
def test_build_and_deploy(
31+
juju: jubilant.Juju, charm_base: str, lldpd_charm: pathlib.Path
4632
) -> None:
4733
"""Test the lldpd charm builds and deploys."""
4834
logger.info(f"Building and deploying lldp charms for base: {charm_base}")
49-
lldpd = lldpd_charm
50-
51-
logger.info(f"lldpd charm is located at: {lldpd}")
35+
logger.info(f"lldpd charm is located at: {lldpd_charm}")
5236

53-
# Deploy ubuntu and lldpd charms.
54-
await asyncio.gather(
55-
ops_test.model.deploy(
56-
"ubuntu",
57-
application_name="ubuntu",
58-
num_units=NUM_UNITS,
59-
base=charm_base,
60-
channel="latest/stable",
61-
revision=UBUNTU_REVISION[charm_base],
62-
),
63-
ops_test.model.deploy(
64-
str(lldpd),
65-
application_name="lldpd",
66-
num_units=0,
67-
base=charm_base,
68-
),
69-
)
37+
# Deploy the ubuntu principal and the lldpd subordinate. The juju CLI
38+
# resolves the ubuntu charm revision for the requested base.
39+
juju.deploy("ubuntu", "ubuntu", num_units=NUM_UNITS, base=charm_base)
40+
juju.deploy(lldpd_charm, "lldpd", num_units=0, base=charm_base)
7041

71-
# Integrate lldpd with ubuntu
72-
await ops_test.model.integrate("ubuntu:juju-info", "lldpd:juju-info")
73-
async with ops_test.fast_forward():
74-
await ops_test.model.wait_for_idle(
75-
apps=["lldpd", "ubuntu"], status="active", timeout=1800
76-
)
77-
for unit in range(NUM_UNITS):
78-
uname = f"lldpd/{unit}"
79-
assert ops_test.model.units.get(uname).workload_status == "active"
42+
juju.integrate("ubuntu:juju-info", "lldpd:juju-info")
43+
juju.wait(jubilant.all_active, timeout=1800)
8044

8145

8246
@pytest.mark.order(2)
83-
async def test_lldpd_is_active(ops_test: OpsTest) -> None:
47+
def test_lldpd_is_active(juju: jubilant.Juju) -> None:
8448
"""Test that the lldpd services are active in each juju unit."""
8549
logger.info("Validating that lldpd is active inside each juju unit.")
86-
for unit in ops_test.model.applications["lldpd"].units:
87-
status = (await unit.ssh("systemctl is-active lldpd")).strip()
88-
assert status == "active", f"{unit.name} lldpd is not active"
50+
status = juju.status()
51+
for unit in status.apps["lldpd"].units:
52+
result = juju.ssh(unit, "systemctl is-active lldpd").strip()
53+
assert result == "active", f"{unit} lldpd is not active"

tox.ini

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@ skipsdist=True
66
skip_missing_interpreters = True
77
envlist = lint, static-{charm,lib}, unit
88

9-
[pytest]
10-
asyncio_mode = auto
11-
129
[vars]
1310
src_path = {toxinidir}/src
1411
tst_path = {toxinidir}/tests
@@ -79,9 +76,8 @@ commands =
7976
[testenv:integration]
8077
description = Run integration tests
8178
deps =
82-
juju<=3.6.0,>3.3.0
79+
jubilant>=1.8,<2
8380
pytest
84-
pytest-operator
8581
pytest-order
8682
-r{toxinidir}/requirements.txt
8783
commands =

0 commit comments

Comments
 (0)