99
1010import jubilant
1111import pytest
12- from pytest_operator .plugin import OpsTest
1312
14- from integration .helpers . pytest_operator import APP_NAME , CONTROLLER_NAME , KRaftMode
13+ from integration .helpers import APP_NAME , CONTROLLER_NAME , KRaftMode
1514
1615
1716def pytest_addoption (parser ):
@@ -21,16 +20,50 @@ def pytest_addoption(parser):
2120 )
2221
2322
24- # TODO: this a temp solution until we migrate to DP workflows for int. testing
25- def pytest_configure (config ):
26- if os .environ .get ("CI" ) == "true" :
27- # Running in GitHub Actions; skip build step
28- plugin = config .pluginmanager .get_plugin ("pytest-operator" )
29- plugin .OpsTest .build_charm = _build_charm
23+ def _find_charm (charm_path : typing .Union [str , os .PathLike ]) -> pathlib .Path :
24+ charm_path = pathlib .Path (charm_path )
25+ architecture = subprocess .run (
26+ ["dpkg" , "--print-architecture" ],
27+ capture_output = True ,
28+ check = True ,
29+ encoding = "utf-8" ,
30+ ).stdout .strip ()
31+ assert architecture in ("amd64" , "arm64" )
32+ packed_charms = list (charm_path .glob (f"*{ architecture } .charm" ))
33+ if len (packed_charms ) == 1 :
34+ # python-libjuju's model.deploy(), juju deploy, and juju bundle files expect local charms
35+ # to begin with `./` or `/` to distinguish them from Charmhub charms.
36+ # Therefore, we need to return an absolute path—a relative `pathlib.Path` does not start
37+ # with `./` when cast to a str.
38+ # (python-libjuju model.deploy() expects a str but will cast any input to a str as a
39+ # workaround for pytest-operator's non-compliant `build_charm` return type of
40+ # `pathlib.Path`.)
41+ return packed_charms [0 ].resolve (strict = True )
42+ elif len (packed_charms ) > 1 :
43+ raise ValueError (
44+ f"More than one matching .charm file found at { charm_path = } for { architecture = } ."
45+ )
46+ else :
47+ raise FileNotFoundError (f"Unable to find .charm file for { architecture = } at { charm_path = } " )
48+
49+
50+ def _build_charm (path : str ) -> None :
51+ if os .environ .get ("CI" ):
52+ return
3053
31- # Remove charmcraft dependency from `ops_test` fixture
32- check_deps = plugin .check_deps
33- plugin .check_deps = lambda * deps : check_deps (* (dep for dep in deps if dep != "charmcraft" ))
54+ # try:
55+ # _find_charm(path)
56+ # except FileNotFoundError:
57+ # pass
58+
59+ # Build locally
60+ cwd = os .getcwd ()
61+ os .chdir (path )
62+ failed = os .system ("charmcraft pack -v" )
63+ os .chdir (cwd )
64+
65+ if failed :
66+ raise RuntimeError ("Charm build failed" )
3467
3568
3669@pytest .fixture (scope = "module" )
@@ -65,51 +98,19 @@ def usernames():
6598
6699
67100@pytest .fixture (scope = "module" )
68- async def kafka_charm (ops_test : OpsTest ):
101+ def kafka_charm ():
69102 """Kafka charm used for integration testing."""
70- charm = await ops_test .build_charm ("." )
71- return charm
103+ charm_path = "."
104+ _build_charm (charm_path )
105+ return _find_charm (charm_path )
72106
73107
74108@pytest .fixture (scope = "module" )
75- async def app_charm (ops_test : OpsTest ):
109+ def app_charm ():
76110 """Build the application charm."""
77111 charm_path = "tests/integration/app-charm"
78- charm = await ops_test .build_charm (charm_path )
79- return charm
80-
81-
82- async def _build_charm (self , charm_path : typing .Union [str , os .PathLike ]) -> pathlib .Path :
83- charm_path = pathlib .Path (charm_path )
84- architecture = subprocess .run (
85- ["dpkg" , "--print-architecture" ],
86- capture_output = True ,
87- check = True ,
88- encoding = "utf-8" ,
89- ).stdout .strip ()
90- assert architecture in ("amd64" , "arm64" )
91- packed_charms = list (charm_path .glob (f"*{ architecture } .charm" ))
92- if len (packed_charms ) == 1 :
93- # python-libjuju's model.deploy(), juju deploy, and juju bundle files expect local charms
94- # to begin with `./` or `/` to distinguish them from Charmhub charms.
95- # Therefore, we need to return an absolute path—a relative `pathlib.Path` does not start
96- # with `./` when cast to a str.
97- # (python-libjuju model.deploy() expects a str but will cast any input to a str as a
98- # workaround for pytest-operator's non-compliant `build_charm` return type of
99- # `pathlib.Path`.)
100- return packed_charms [0 ].resolve (strict = True )
101- elif len (packed_charms ) > 1 :
102- raise ValueError (
103- f"More than one matching .charm file found at { charm_path = } for { architecture = } and "
104- f"Ubuntu 22.04: { packed_charms } ."
105- )
106- else :
107- raise ValueError (
108- f"Unable to find .charm file for { architecture = } and Ubuntu 22.04 at { charm_path = } "
109- )
110-
111-
112- # -- Jubilant --
112+ _build_charm (charm_path )
113+ return _find_charm (charm_path )
113114
114115
115116@pytest .fixture (scope = "module" )
0 commit comments