Skip to content

Commit af7d285

Browse files
committed
test: Add integration tests
Adds basic integration test to be run. Includes a github action so that it is run automatically on each PR. Signed-off-by: Billy Olsen <[email protected]>
1 parent 582ad51 commit af7d285

File tree

3 files changed

+167
-0
lines changed

3 files changed

+167
-0
lines changed

.github/workflows/ci.yaml

+23
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,26 @@ jobs:
6363
- name: Run tests
6464
run: tox -e unit
6565

66+
integration-test:
67+
strategy:
68+
fail-fast: true
69+
matrix:
70+
bases:
71+
72+
73+
name: Integration tests (LXD) | ${{ matrix.bases }}
74+
runs-on: ubuntu-latest
75+
needs:
76+
- inclusive-naming-check
77+
- lint
78+
- unit-test
79+
steps:
80+
- name: Checkout
81+
uses: actions/checkout@v3
82+
- name: Setup operator environment
83+
uses: charmed-kubernetes/actions-operator@main
84+
with:
85+
provider: lxd
86+
juju-channel: 3/stable
87+
- name: Run tests
88+
run: tox run -e integration -- --charm-base=${{ matrix.bases }}

tests/integration/conftest.py

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#!/usr/bin/env python3
2+
# Copyright 2024 Canonical Ltd.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
"""Configure lldpd operator integration tests."""
17+
18+
import logging
19+
import platform
20+
from pathlib import Path
21+
22+
import pytest
23+
from pytest_operator.plugin import OpsTest
24+
25+
26+
logger = logging.getLogger(__name__)
27+
28+
29+
def pytest_addoption(parser) -> None:
30+
parser.addoption(
31+
"--charm-base",
32+
action="store",
33+
default="[email protected]",
34+
help="Charm base version to use for integration tests",
35+
)
36+
parser.addoption(
37+
"--enable-discovery",
38+
action="store_true",
39+
default=False,
40+
help="Enables lldpd discovery tests. "
41+
"May not succeed if using VMs or containers",
42+
)
43+
44+
45+
@pytest.fixture(scope="module")
46+
def charm_base(request) -> str:
47+
"""Get the lldp charm base to use."""
48+
return request.config.option.charm_base
49+
50+
51+
@pytest.fixture(scope="module")
52+
async def lldpd_charm(ops_test: OpsTest, charm_base: str) -> Path:
53+
# Multiple charms will be built, but the build_charm function only returns
54+
# the path to one of the charms. Find the charm that matches the charm_base
55+
# in order to test the right one.
56+
await ops_test.build_charm(".")
57+
58+
base = charm_base.replace("@", "-")
59+
arch = platform.machine()
60+
# convert the x86_64 arch into the amd64 arch used by charmcraft.
61+
if arch == "x86_64":
62+
arch = "amd64"
63+
64+
build_dir = (ops_test.tmp_path / "charms").absolute()
65+
charm_file = build_dir / f"lldpd_{base}-{arch}.charm"
66+
if not charm_file.exists():
67+
raise ValueError(f"Unable to find charm file {charm_file}")
68+
69+
return charm_file

tests/integration/test_charm.py

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#!/usr/bin/env python3
2+
# Copyright 2024 Canonical Ltd.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
"""Test lldpd charm deployment."""
17+
18+
import asyncio
19+
import logging
20+
import pytest
21+
22+
from pytest_operator.plugin import OpsTest
23+
24+
25+
logger = logging.getLogger(__name__)
26+
27+
NUM_UNITS = 2
28+
29+
30+
@pytest.mark.abort_on_fail
31+
@pytest.mark.skip_if_deployed
32+
@pytest.mark.order(1)
33+
async def test_build_and_deploy(
34+
ops_test: OpsTest, charm_base: str, lldpd_charm
35+
) -> None:
36+
"""Test the lldpd charm builds and deploys."""
37+
logger.info(f"Building and deploying lldp charms for base: {charm_base}")
38+
lldpd = await lldpd_charm
39+
40+
logger.info(f"lldpd charm is located at: {lldpd}")
41+
42+
# Deploy ubuntu and lldpd charms.
43+
await asyncio.gather(
44+
ops_test.model.deploy(
45+
"ubuntu",
46+
application_name="ubuntu",
47+
num_units=NUM_UNITS,
48+
base=charm_base,
49+
),
50+
ops_test.model.deploy(
51+
str(lldpd),
52+
application_name="lldpd",
53+
num_units=0,
54+
base=charm_base,
55+
),
56+
)
57+
58+
# Integrate lldpd with ubuntu
59+
await ops_test.model.integrate("ubuntu:juju-info", "lldpd:juju-info")
60+
async with ops_test.fast_forward():
61+
await ops_test.model.wait_for_idle(
62+
apps=["lldpd", "ubuntu"], status="active", timeout=1800
63+
)
64+
for unit in range(NUM_UNITS):
65+
uname = f"lldpd/{unit}"
66+
assert ops_test.model.units.get(uname).workload_status == "active"
67+
68+
69+
@pytest.mark.order(2)
70+
async def test_lldpd_is_active(ops_test: OpsTest) -> None:
71+
"""Test that the lldpd services are active in each juju unit."""
72+
logger.info("Validating that lldpd is active inside each juju unit.")
73+
for unit in ops_test.model.applications["lldpd"].units:
74+
status = (await unit.ssh("systemctl is-active lldpd")).strip()
75+
assert status == "active", f"{unit.name} lldpd is not active"

0 commit comments

Comments
 (0)