diff --git a/swh/lister/opam/lister.py b/swh/lister/opam/lister.py --- a/swh/lister/opam/lister.py +++ b/swh/lister/opam/lister.py @@ -52,6 +52,12 @@ ) self.env = os.environ.copy() self.opamroot = tempfile.mkdtemp(prefix="swh_opam_lister") + + def prepare(self): + """Prepare internal state that lister opam requires. This actually does network access + to bootstrap the self.opamroot folder. + + """ call( [ "opam", @@ -61,8 +67,8 @@ "--no-setup", "--root", self.opamroot, - instance, - url, + self.instance, + self.url, ], env=self.env, ) diff --git a/swh/lister/opam/tests/test_lister.py b/swh/lister/opam/tests/test_lister.py --- a/swh/lister/opam/tests/test_lister.py +++ b/swh/lister/opam/tests/test_lister.py @@ -6,24 +6,40 @@ import io from unittest.mock import MagicMock -from swh.lister.opam.lister import OpamLister +import pytest +from swh.lister.opam.lister import OpamLister -def test_urls(swh_scheduler, mocker): +module_name = "swh.lister.opam.lister" - instance_url = "https://opam.ocaml.org" - lister = OpamLister(swh_scheduler, url=instance_url, instance="opam") +@pytest.fixture +def mock_opam(mocker): + """Fixture to bypass the actual opam calls within the test context. + """ + # replaces the real prepare method (this prepares the internal opam state) + mock_init = mocker.patch(f"{module_name}.OpamLister.prepare", return_value=None) + # replaces the real Popen with a fake one (list origins command) mocked_popen = MagicMock() mocked_popen.stdout = io.BytesIO(b"bar\nbaz\nfoo\n") + mock_open = mocker.patch(f"{module_name}.Popen", return_value=mocked_popen) + return mock_init, mock_open + - # replaces the real Popen with a fake one - mocker.patch("swh.lister.opam.lister.Popen", return_value=mocked_popen) +def test_urls(swh_scheduler, mock_opam): + mock_init, mock_popen = mock_opam + + instance_url = "https://opam.ocaml.org" + + lister = OpamLister(swh_scheduler, url=instance_url, instance="opam") # call the lister and get all listed origins urls stats = lister.run() + assert mock_init.called + assert mock_popen.called + assert stats.pages == 3 assert stats.origins == 3 @@ -41,7 +57,6 @@ def test_opam_binary(datadir, swh_scheduler): - instance_url = f"file://{datadir}/fake_opam_repo" lister = OpamLister(swh_scheduler, url=instance_url, instance="fake") diff --git a/swh/lister/pattern.py b/swh/lister/pattern.py --- a/swh/lister/pattern.py +++ b/swh/lister/pattern.py @@ -113,6 +113,18 @@ self.state = self.get_state_from_scheduler() self.updated = False + def prepare(self) -> None: + """Prepare some state that the lister requires. + + This should centralize all external state configurations that do side effects; + reading from network or disk... Those should not run within the class + constructor and be moved within their dedicated prepare call. + + See opam lister prepare call for an example + + """ + pass + def run(self) -> ListerStats: """Run the lister. @@ -121,6 +133,7 @@ of the lister. """ + self.prepare() full_stats = ListerStats() try: