Skip to content

Commit f487b25

Browse files
committed
Add tests for commodore tool command group
1 parent d097ba5 commit f487b25

2 files changed

Lines changed: 162 additions & 0 deletions

File tree

tests/test_cli.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,18 @@ def test_package_sync_command():
107107
def test_version_command():
108108
exit_status = call("commodore version --help", shell=True)
109109
assert exit_status == 0
110+
111+
112+
def test_tool_list_command():
113+
exit_status = call("commodore tool list --help", shell=True)
114+
assert exit_status == 0
115+
116+
117+
def test_tool_install_command():
118+
exit_status = call("commodore tool install --help", shell=True)
119+
assert exit_status == 0
120+
121+
122+
def test_tool_upgrade_command():
123+
exit_status = call("commodore tool upgrade --help", shell=True)
124+
assert exit_status == 0

tests/test_tools.py

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
import json
2+
3+
from pathlib import Path
4+
from typing import Optional
5+
from unittest.mock import patch
6+
7+
import pytest
8+
import responses
9+
10+
DATA_DIR = Path(__file__).parent.absolute() / "testdata" / "github"
11+
12+
TOOL_VERSIONS = {
13+
"helm": "v3.18.3",
14+
"jb": "0.6.3",
15+
"kustomize": "v5.7.0",
16+
}
17+
18+
19+
class MockToolInfo:
20+
tool: str
21+
path: Optional[str]
22+
version: Optional[str]
23+
24+
def __init__(self, tool: str):
25+
self.tool = tool
26+
self.path = f"/path/to/{tool}"
27+
self.version = TOOL_VERSIONS[tool]
28+
29+
30+
from commodore.config import Config
31+
32+
from commodore import tools
33+
34+
35+
def _parse_list_tools_output(out: str) -> dict[str, list[str]]:
36+
tool = None
37+
tool_lines = {}
38+
for line in out.splitlines():
39+
trimmed_line = " ".join(line.strip().split())
40+
if trimmed_line.startswith(tuple(TOOL_VERSIONS.keys())):
41+
tool = trimmed_line.split(" ")[0]
42+
tool_lines.setdefault(tool, []).append(trimmed_line)
43+
return tool_lines
44+
45+
46+
def _setup_tool_github_responses() -> dict[str, str]:
47+
latest_versions = {}
48+
for repo, tool in {
49+
"helm/helm": "helm",
50+
"projectsyn/jsonnet-bundler": "jb",
51+
"kubernetes-sigs/kustomize": "kustomize",
52+
}.items():
53+
repo_key = repo.replace("/", "-")
54+
with open(DATA_DIR / f"{repo_key}.json", "r", encoding="utf-8") as respf:
55+
resp = json.load(respf)
56+
responses.add(
57+
responses.GET,
58+
f"https://api.github.com:443/repos/{repo}",
59+
json=resp,
60+
status=200,
61+
)
62+
with open(
63+
DATA_DIR / f"{repo_key}-releases-latest.json", "r", encoding="utf-8"
64+
) as latestf:
65+
latest = json.load(latestf)
66+
responses.add(
67+
responses.GET,
68+
f"https://api.github.com:443/repos/{repo}/releases/latest",
69+
json=latest,
70+
status=200,
71+
)
72+
latest_versions[tool] = latest["tag_name"].removeprefix(f"{tool}/")
73+
return latest_versions
74+
75+
76+
@patch.object(tools, "ToolInfo")
77+
def test_list_tools_no_version_check(mock_tinfo, config: Config, capsys):
78+
mock_tinfo.side_effect = MockToolInfo
79+
tools.list_tools(config, False)
80+
81+
out, _ = capsys.readouterr()
82+
tool_lines = _parse_list_tools_output(out)
83+
84+
for tool, version in TOOL_VERSIONS.items():
85+
assert tool_lines[tool][0] == f"{tool} {version}"
86+
assert tool_lines[tool][1] == f"Location: /path/to/{tool}"
87+
assert tool_lines[tool][2] == f"Managed: {False}"
88+
assert tool_lines[tool][3] == "Latest version: N/A (Version check skipped)"
89+
assert tool_lines[tool][4] == "Updated: UNKNOWN"
90+
91+
92+
@patch.object(tools, "ToolInfo")
93+
@responses.activate
94+
def test_list_tool_version_check(mock_tinfo, config: Config, capsys):
95+
mock_tinfo.side_effect = MockToolInfo
96+
latest_versions = _setup_tool_github_responses()
97+
98+
tools.list_tools(config, True)
99+
100+
out, _ = capsys.readouterr()
101+
tool_lines = _parse_list_tools_output(out)
102+
103+
for tool, version in TOOL_VERSIONS.items():
104+
assert tool_lines[tool][0] == f"{tool} {version}"
105+
assert tool_lines[tool][1] == f"Location: /path/to/{tool}"
106+
assert tool_lines[tool][2] == f"Managed: {False}"
107+
if latest_versions[tool].removeprefix("v") == TOOL_VERSIONS[tool].removeprefix(
108+
"v"
109+
):
110+
# Latest version is always GH tag name even for tools that report
111+
# their own version without a v prefix.
112+
assert (
113+
tool_lines[tool][3]
114+
== f"Latest version: v{TOOL_VERSIONS[tool].removeprefix('v')} (No upgrade available)"
115+
)
116+
else:
117+
assert (
118+
tool_lines[tool][3]
119+
== f"Latest version: {latest_versions[tool]} (Upgrade available!)"
120+
)
121+
assert tool_lines[tool][4] == "Updated: UNKNOWN"
122+
123+
124+
@patch.object(tools, "ToolInfo")
125+
def test_list_tool_version_check(mock_tinfo, config: Config, capsys):
126+
class MockToolInfo2(MockToolInfo):
127+
def __init__(self, tool):
128+
if tool != "jb":
129+
super().__init__(tool)
130+
else:
131+
self.tool = tool
132+
self.path = None
133+
self.version = None
134+
135+
mock_tinfo.side_effect = MockToolInfo2
136+
137+
tools.list_tools(config, False)
138+
139+
out, _ = capsys.readouterr()
140+
tool_lines = _parse_list_tools_output(out)
141+
for tool, version in TOOL_VERSIONS.items():
142+
if tool == "jb":
143+
assert len(tool_lines[tool]) == 1
144+
assert tool_lines[tool][0] == f"{tool} missing!"
145+
else:
146+
assert len(tool_lines[tool]) == 5
147+
assert tool_lines[tool][0] == f"{tool} {version}"

0 commit comments

Comments
 (0)