Merge ~weii-wang/content-cache-charm:fix-integration-test into content-cache-charm:master

Proposed by Weii Wang
Status: Merged
Approved by: Haw Loeung
Approved revision: 152edecec75fe7037a9f8063309fc12daaac0612
Merged at revision: 9a8fe20a0882a7bbd53e02edd565f1b107cd8a11
Proposed branch: ~weii-wang/content-cache-charm:fix-integration-test
Merge into: content-cache-charm:master
Diff against target: 83 lines (+44/-3)
1 file modified
tests/integration/integration_test.py (+44/-3)
Reviewer Review Type Date Requested Status
Haw Loeung +1 Approve
Colin Watson (community) Approve
Canonical IS Reviewers Pending
Review via email: mp+434637@code.launchpad.net

Commit message

Use charmcraft to build charm in integration tests

The pytest-operator for integration testing uses `charm` instead of `charmcraft` to build reactive charm. `charm` uses the host environment to build the charm. when the host contains an incorrect version of Python, `charm` will package the incorrect Python package into the charm. `charmcraft` builds the charm using the LXD container with the appropriate Ubuntu image, so there is no such problem with `charmcraft`.

In this commit, change the integration test to call `charmcraft` instead of using `ops_test.build_charm` to build the charm.

Description of the change

The pytest-operator for integration testing uses `charm` instead of `charmcraft` to build reactive charm. `charm` uses the host environment to build the charm. when the host contains an incorrect version of Python, `charm` will package the incorrect Python package into the charm. `charmcraft` builds the charm using the LXD container with the appropriate Ubuntu image, so there is no such problem with `charmcraft`.

In this MP, change the integration test to call `charmcraft` instead of using `ops_test.build_charm` to build the charm.

To post a comment you must log in.
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote :

This merge proposal is being monitored by mergebot. Change the status to Approved to merge.

Revision history for this message
Colin Watson (cjwatson) :
review: Approve
Revision history for this message
Haw Loeung (hloeung) wrote :

LGTM too, see comments. Let me know if you want to fix it or land as is.

Thanks!

review: Approve (+1)
Revision history for this message
Haw Loeung (hloeung) wrote :

Also, can we move the description of change into the commit message? Much easier to see "why" via "git log" rather than having to open up this Launchpad MP.

Revision history for this message
Haw Loeung (hloeung) :
Revision history for this message
Weii Wang (weii-wang) wrote :

> Also, can we move the description of change into the commit message? Much
> easier to see "why" via "git log" rather than having to open up this Launchpad
> MP.

I updated the code to use short-form bases in the metadata.yaml. Also, updated the commit message of this PR. Thanks!

Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote :

Change successfully merged at revision 9a8fe20a0882a7bbd53e02edd565f1b107cd8a11

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/tests/integration/integration_test.py b/tests/integration/integration_test.py
2index aa43008..4463a53 100644
3--- a/tests/integration/integration_test.py
4+++ b/tests/integration/integration_test.py
5@@ -1,3 +1,6 @@
6+import csv
7+import logging
8+import pathlib
9 import re
10 import socket
11 import textwrap
12@@ -7,6 +10,10 @@ import pytest_asyncio
13 import requests
14 import yaml
15
16+from pytest_operator.plugin import check_deps
17+
18+logger = logging.getLogger()
19+
20
21 def supported_series():
22 with open("metadata.yaml", encoding="utf-8") as f:
23@@ -14,13 +21,48 @@ def supported_series():
24 return metadata['series']
25
26
27+def series_version_mapping():
28+ reader = csv.DictReader(pathlib.Path("/usr/share/distro-info/ubuntu.csv").open())
29+ return {row["series"]: row["version"].split(" ")[0] for row in reader}
30+
31+
32 @pytest.fixture(params=supported_series(), scope="module", name="series")
33 def fixture_series(request):
34 return request.param
35
36
37+@pytest_asyncio.fixture(scope="module", name="charm_file")
38+async def charm_file_fixture(ops_test, series, tmp_path_factory):
39+ tmp_path = tmp_path_factory.mktemp(f"charm-{series}")
40+ charmcraft_file = pathlib.Path(".") / "charmcraft.yaml"
41+ charmcraft = yaml.safe_load(charmcraft_file.read_text())
42+ metadata_file = pathlib.Path(".") / "metadata.yaml"
43+ charm_name = yaml.safe_load(metadata_file.read_text())["name"]
44+ base_version = series_version_mapping()[series]
45+ base_index = None
46+ for idx, base in enumerate(charmcraft["bases"]):
47+ if base["channel"] == base_version:
48+ base_index = idx
49+ logger.info(f"build charm {charm_name}")
50+ check_deps("charmcraft")
51+ cmd = ("charmcraft", "pack", "-p", pathlib.Path.cwd(), "--bases-index", str(base_index))
52+ logger.info(f"run command: {cmd}")
53+ return_code, stdout, stderr = await ops_test.run(*cmd, cwd=tmp_path)
54+ if return_code != 0:
55+ m = re.search(r"Failed to build charm.*full execution logs in '([^']+)'", stderr)
56+ if m:
57+ try:
58+ stderr = pathlib.Path(m.group(1)).read_text()
59+ except FileNotFoundError:
60+ logger.error(f"Failed to read full build log from {m.group(1)}")
61+ raise RuntimeError(f"Failed to build charm:\n{stderr}\n{stdout}")
62+ charm_file = next(tmp_path.glob(f"{charm_name}*.charm"))
63+ logger.info(f"built charm file: {charm_file}")
64+ return charm_file
65+
66+
67 @pytest_asyncio.fixture(scope="module", name="application")
68-async def fixture_application(ops_test, series):
69+async def fixture_application(ops_test, series, charm_file):
70 def dns_lookup_ipv4(hostname):
71 records = socket.getaddrinfo(hostname, 0)
72 for record in records:
73@@ -28,9 +70,8 @@ async def fixture_application(ops_test, series):
74 return record[4][0]
75 raise RuntimeError("No IPv4 DNS record for host: {}".format(hostname))
76
77- my_charm = await ops_test.build_charm(".")
78 application_name = "content-cache-{}".format(series)
79- await ops_test.model.deploy(my_charm, series=series, application_name=application_name)
80+ await ops_test.model.deploy(charm_file, series=series, application_name=application_name)
81 # Get the IPv4 address for site to prevent some test environment IPv6 connectivity issues
82 website_ip = dns_lookup_ipv4("archive.ubuntu.com")
83 application = ops_test.model.applications[application_name]

Subscribers

People subscribed via source and target branches