Skip to content

Commit ade9fda

Browse files
committed
Tests for uninstall and list
1 parent 59f0a3a commit ade9fda

File tree

6 files changed

+472
-66
lines changed

6 files changed

+472
-66
lines changed

.config/dictionary.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ platlib
2222
platstdlib
2323
purelib
2424
reqs
25+
sessionstart
2526
setenv
2627
treemaker
2728
usefixtures

src/ansible_dev_environment/subcommands/lister.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,7 @@ def __init__(self: Lister, config: Config, output: Output) -> None:
2626
self._output = output
2727

2828
def run(self: Lister) -> None:
29-
"""Run the Lister.
30-
31-
Raises:
32-
TypeError: If the link is not a string.
33-
"""
29+
"""Run the Lister."""
3430
collections = collect_manifests(
3531
target=self._config.site_pkg_collections_path,
3632
venv_cache_dir=self._config.venv_cache_dir,
@@ -80,10 +76,10 @@ def run(self: Lister) -> None:
8076
homepage = ci.get("homepage")
8177
repository = ci.get("repository")
8278
issues = ci.get("issues")
83-
link = repository or homepage or docs or issues or "http://ansible.com"
79+
link = repository or homepage or docs or issues or "https://ansible.com"
8480
if not isinstance(link, str):
85-
msg = "Link is not a string."
86-
raise TypeError(msg)
81+
self._output.error(err)
82+
link = "https://ansible.com"
8783
fqcn_linked = term_link(
8884
uri=link,
8985
label=fqcn,

src/ansible_dev_environment/subcommands/uninstaller.py

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -92,22 +92,21 @@ def _remove_collection(self: UnInstaller) -> None:
9292
self._output.debug(msg)
9393

9494
collection_namespace_root = self._collection.site_pkg_path.parent
95-
try:
96-
collection_namespace_root.rmdir()
97-
msg = f"Removed collection namespace root: {collection_namespace_root}"
98-
self._output.debug(msg)
99-
except FileNotFoundError:
100-
pass
101-
except OSError as exc:
102-
msg = f"Failed to remove collection namespace root: {exc}"
103-
self._output.debug(msg)
10495

105-
try:
106-
self._config.site_pkg_collections_path.rmdir()
107-
msg = f"Removed collection root: {self._config.site_pkg_collections_path}"
108-
self._output.debug(msg)
109-
except FileNotFoundError:
110-
pass
111-
except OSError as exc:
112-
msg = f"Failed to remove collection root: {exc}"
113-
self._output.debug(msg)
96+
if collection_namespace_root.exists():
97+
try:
98+
collection_namespace_root.rmdir()
99+
msg = f"Removed collection namespace root: {collection_namespace_root}"
100+
self._output.debug(msg)
101+
except OSError as exc:
102+
msg = f"Failed to remove collection namespace root: {exc}"
103+
self._output.debug(msg)
104+
105+
if self._config.site_pkg_collections_path.exists():
106+
try:
107+
self._config.site_pkg_collections_path.rmdir()
108+
msg = f"Removed collection root: {self._config.site_pkg_collections_path}"
109+
self._output.debug(msg)
110+
except OSError as exc:
111+
msg = f"Failed to remove collection root: {exc}"
112+
self._output.debug(msg)

tests/conftest.py

Lines changed: 106 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@
1616
Tracing '/**/src/<package>/__init__.py'
1717
"""
1818

19+
import json
1920
import os
2021
import shutil
21-
import subprocess
2222
import tempfile
2323
import warnings
2424

2525
from collections.abc import Generator
26-
from datetime import datetime, timedelta
2726
from pathlib import Path
27+
from urllib.request import HTTPError, urlopen
2828

2929
import pytest
3030
import yaml
@@ -35,7 +35,55 @@
3535
from ansible_dev_environment.config import Config
3636

3737

38-
TESTING_CACHE = Path(__file__).parent.parent / ".cache" / ".galaxy_cache"
38+
GALAXY_CACHE = Path(__file__).parent.parent / ".cache" / ".galaxy_cache"
39+
REQS_FILE_NAME = "requirements.yml"
40+
41+
42+
@pytest.fixture()
43+
def galaxy_cache() -> Path:
44+
"""Return the galaxy cache directory.
45+
46+
Returns:
47+
The galaxy cache directory.
48+
"""
49+
return GALAXY_CACHE
50+
51+
52+
def check_download_collection(name: str, dest: Path) -> None:
53+
"""Download a collection if necessary.
54+
55+
Args:
56+
name: The collection name.
57+
dest: The destination directory.
58+
"""
59+
namespace, name = name.split(".")
60+
base_url = "https://galaxy.ansible.com/api/v3/plugin/ansible/content/published/collections"
61+
62+
url = f"{base_url}/index/{namespace}/{name}/versions/?is_highest=true"
63+
try:
64+
with urlopen(url) as response: # noqa: S310
65+
body = response.read()
66+
except HTTPError:
67+
err = f"Failed to check collection version: {name}"
68+
pytest.fail(err)
69+
with urlopen(url) as response: # noqa: S310
70+
body = response.read()
71+
json_response = json.loads(body)
72+
version = json_response["data"][0]["version"]
73+
file_name = f"{namespace}-{name}-{version}.tar.gz"
74+
file_path = dest / file_name
75+
if file_path.exists():
76+
return
77+
for found_file in dest.glob(f"{namespace}-{name}-*"):
78+
found_file.unlink()
79+
url = f"{base_url}/artifacts/{file_name}"
80+
warnings.warn(f"Downloading collection: {file_name}", stacklevel=0)
81+
try:
82+
with urlopen(url) as response, file_path.open(mode="wb") as file: # noqa: S310
83+
file.write(response.read())
84+
except HTTPError:
85+
err = f"Failed to download collection: {name}"
86+
pytest.fail(err)
3987

4088

4189
def pytest_sessionstart(session: pytest.Session) -> None:
@@ -50,46 +98,19 @@ def pytest_sessionstart(session: pytest.Session) -> None:
5098
if os.environ.get("PYTEST_XDIST_WORKER"):
5199
return
52100

53-
if not TESTING_CACHE.exists():
54-
TESTING_CACHE.mkdir(parents=True, exist_ok=True)
55-
56-
warnings.warn(f"Checking the galaxy cache: {TESTING_CACHE}", stacklevel=0)
57-
update_needed = not any(TESTING_CACHE.iterdir())
58-
warnings.warn(f"Update needed: {update_needed}", stacklevel=0)
59-
tz = datetime.now().astimezone().tzinfo
60-
one_week_ago = datetime.now(tz) - timedelta(weeks=1)
61-
62-
if not update_needed:
63-
for file in TESTING_CACHE.glob("*"):
64-
file_creation = datetime.fromtimestamp(file.stat().st_mtime, tz=tz)
65-
warnings.warn(f"File: {file.name}, created: {file_creation}", stacklevel=0)
66-
if file_creation < one_week_ago:
67-
update_needed = True
68-
break
69-
70-
if not update_needed:
71-
warnings.warn("Galaxy cache is up to date.", stacklevel=0)
72-
return
101+
if not GALAXY_CACHE.exists():
102+
GALAXY_CACHE.mkdir(parents=True, exist_ok=True)
73103

74-
warnings.warn("Updating the galaxy cache.", stacklevel=0)
75-
shutil.rmtree(TESTING_CACHE, ignore_errors=True)
76-
TESTING_CACHE.mkdir(parents=True, exist_ok=True)
104+
for collection in ("ansible.utils", "ansible.scm", "ansible.posix"):
105+
check_download_collection(collection, GALAXY_CACHE)
77106

78-
command = (
79-
"ansible-galaxy collection download"
80-
f" ansible.utils ansible.scm ansible.posix -p {TESTING_CACHE}/ -vvv"
81-
)
82-
warnings.warn(f"Running: {command}", stacklevel=0)
83-
subprocess.run(command, shell=True, check=True)
107+
reqs: dict[str, list[dict[str, str]]] = {"collections": []}
84108

85-
files = ",".join(str(f.name) for f in list(TESTING_CACHE.glob("*")))
86-
warnings.warn(f"Galaxy cache updated, contains: {files}", stacklevel=0)
109+
for found_file in GALAXY_CACHE.glob("*.tar.gz"):
110+
reqs["collections"].append({"name": str(found_file)})
87111

88-
requirements = TESTING_CACHE / "requirements.yml"
89-
contents = yaml.load(requirements.read_text(), Loader=yaml.SafeLoader)
90-
for collection in contents["collections"]:
91-
collection["name"] = f"file://{TESTING_CACHE / collection['name']}"
92-
requirements.write_text(yaml.dump(contents))
112+
requirements = GALAXY_CACHE / REQS_FILE_NAME
113+
requirements.write_text(yaml.dump(reqs))
93114

94115

95116
@pytest.fixture(name="monkey_session", scope="session")
@@ -139,7 +160,7 @@ def session_venv(session_dir: Path, monkey_session: pytest.MonkeyPatch) -> Confi
139160
"ade",
140161
"install",
141162
"-r",
142-
str(TESTING_CACHE / "requirements.yml"),
163+
str(GALAXY_CACHE / REQS_FILE_NAME),
143164
"--venv",
144165
str(venv_path),
145166
"--ll",
@@ -159,3 +180,48 @@ def session_venv(session_dir: Path, monkey_session: pytest.MonkeyPatch) -> Confi
159180
with pytest.raises(SystemExit):
160181
cli.run()
161182
return cli.config
183+
184+
185+
@pytest.fixture()
186+
def function_venv(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> Config:
187+
"""Create a temporary venv for the session.
188+
189+
Add some common collections to the venv.
190+
191+
Since this is a session level fixture, care should be taken to not manipulate it
192+
or the resulting config in a way that would affect other tests.
193+
194+
Args:
195+
tmp_path: Temporary directory.
196+
monkeypatch: Pytest monkeypatch fixture.
197+
198+
Returns:
199+
The configuration object for the venv.
200+
"""
201+
venv_path = tmp_path / "venv"
202+
monkeypatch.setattr(
203+
"sys.argv",
204+
[
205+
"ade",
206+
"install",
207+
"-r",
208+
str(GALAXY_CACHE / REQS_FILE_NAME),
209+
"--venv",
210+
str(venv_path),
211+
"--ll",
212+
"debug",
213+
"--la",
214+
"true",
215+
"--lf",
216+
str(tmp_path / "ade.log"),
217+
"-vvv",
218+
],
219+
)
220+
cli = Cli()
221+
cli.parse_args()
222+
cli.init_output()
223+
cli.args_sanity()
224+
cli.ensure_isolated()
225+
with pytest.raises(SystemExit):
226+
cli.run()
227+
return cli.config

0 commit comments

Comments
 (0)