Skip to content

Commit a0aef33

Browse files
authored
Add integration test for entrypoint creation (#252)
1 parent 32c2730 commit a0aef33

File tree

7 files changed

+174
-11
lines changed

7 files changed

+174
-11
lines changed

.github/workflows/build.yml

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -172,19 +172,10 @@ jobs:
172172
PYTHON_MANAGER_CONFIG: .\test-config.json
173173
PYMANAGER_DEBUG: true
174174

175-
- name: 'Validate entrypoint script'
175+
- name: 'Validate entrypoint scripts'
176176
run: |
177177
$env:PYTHON_MANAGER_CONFIG = (gi $env:PYTHON_MANAGER_CONFIG).FullName
178-
cd .\test_installs\_bin
179-
del pip* -Verbose
180-
pymanager install --refresh
181-
dir pip*
182-
Get-Item .\pip.exe
183-
Get-Item .\pip.exe.__target__
184-
Get-Content .\pip.exe.__target__
185-
Get-Item .\pip.exe.__script__.py
186-
Get-Content .\pip.exe.__script__.py
187-
.\pip.exe --version
178+
pymanager exec tests\run-eptest.py
188179
env:
189180
PYTHON_MANAGER_INCLUDE_UNMANAGED: false
190181
PYTHON_MANAGER_CONFIG: .\test-config.json

ci/release.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,16 @@ stages:
313313
PYTHON_MANAGER_CONFIG: .\test-config.json
314314
PYMANAGER_DEBUG: true
315315
316+
- powershell: |
317+
$env:PYTHON_MANAGER_CONFIG = (gi $env:PYTHON_MANAGER_CONFIG).FullName
318+
pymanager exec tests\run-eptest.py
319+
displayName: 'Validate entrypoint scripts'
320+
timeoutInMinutes: 5
321+
env:
322+
PYTHON_MANAGER_INCLUDE_UNMANAGED: false
323+
PYTHON_MANAGER_CONFIG: .\test-config.json
324+
PYMANAGER_DEBUG: true
325+
316326
- powershell: |
317327
pymanager list --online 3 3-32 3-64 3-arm64
318328
pymanager install --download .\bundle 3 3-32 3-64 3-arm64

src/manage/commands.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,8 @@ def __init__(self, args, root=None):
425425
LOGGER.warn("Failed to read configuration file from %s", self.config_file)
426426
raise
427427

428+
self.config = config
429+
428430
# Top-level arguments get updated manually from the config
429431
# (per-command config gets loaded automatically below)
430432

src/manage/list_command.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,11 @@ def list_formats(cmd, installs):
222222
LOGGER.print(f"{k:<{max_key_width}} {doc}", always=True)
223223

224224

225+
def list_config(cmd, installs):
226+
"List the current config"
227+
LOGGER.print(json.dumps(cmd.config, default=str), always=True)
228+
229+
225230
def format_legacy(cmd, installs, paths=False):
226231
"List runtimes using the old format"
227232
seen_default = False
@@ -262,6 +267,7 @@ def format_legacy_paths(cmd, installs):
262267
"legacy": format_legacy,
263268
"legacy-paths": format_legacy_paths,
264269
"formats": list_formats,
270+
"config": list_config,
265271
}
266272

267273

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[console_scripts]
2+
eptest=eptestpackage:main
3+
eptest-refresh=eptestpackage:do_refresh
4+
5+
[gui_scripts]
6+
eptestw=eptestpackage:mainw
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
def main():
2+
print("eptestpackage:main")
3+
4+
def mainw():
5+
print("eptestpackage:mainw")
6+
7+
def do_refresh():
8+
import subprocess
9+
with subprocess.Popen(
10+
["pymanager", "install", "-v", "--refresh"],
11+
stdout=subprocess.PIPE,
12+
stderr=subprocess.STDOUT,
13+
encoding="ascii",
14+
errors="replace",
15+
) as p:
16+
out, _ = p.communicate(None)
17+
print(out)
18+
19+
print("eptestpackage:do_refresh")

tests/run-eptest.py

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
# This is an integration test, rather than a unit test.
2+
# It should be run in a Python runtime that has been installed.
3+
# The 'pymanager.exe' under test should be first on PATH
4+
5+
import json
6+
import shutil
7+
import subprocess
8+
import sys
9+
10+
from pathlib import Path
11+
12+
EXIT_SETUP_FAILED = 1
13+
EXIT_ALIAS_NOT_CREATED = 2
14+
EXIT_ALIAS_INVALID = 3
15+
16+
CLEANUP = []
17+
18+
def run(*args, **kwargs):
19+
print("##[command]", end="")
20+
print(*args)
21+
with subprocess.Popen(
22+
args,
23+
stdout=kwargs.pop("stdout", subprocess.PIPE),
24+
stderr=kwargs.pop("stderr", subprocess.STDOUT),
25+
encoding=kwargs.pop("encoding", "ascii"),
26+
errors=kwargs.pop("errors", "replace"),
27+
**kwargs,
28+
) as p:
29+
out, err = p.communicate(None)
30+
if p.returncode:
31+
raise subprocess.CalledProcessError(p.returncode, args, out, err)
32+
return out, err
33+
34+
def main():
35+
out, _ = run("pymanager", "list", "-f=json", "-q")
36+
for install in json.loads(out)["versions"]:
37+
if not install.get("unmanaged"):
38+
break
39+
else:
40+
print("##[error]No suitable (managed) runtime found.")
41+
sys.exit(EXIT_SETUP_FAILED)
42+
43+
print("Using", install["display-name"], "from", install["prefix"], "for test")
44+
45+
prefix = install["prefix"]
46+
exe = install["executable"]
47+
48+
site = Path(prefix) / "Lib/site-packages"
49+
if not site.is_dir():
50+
print("##[error]Selected runtime has no site-packages folder.")
51+
sys.exit(EXIT_SETUP_FAILED)
52+
53+
eptest_src = Path(__file__).parent / "eptestpackage"
54+
if not eptest_src.is_dir():
55+
print("##[error]eptestpackage is missing from test script location.")
56+
sys.exit(EXIT_SETUP_FAILED)
57+
58+
dist_info = site / "eptestpackage-1.0.dist-info"
59+
dist_info.mkdir(parents=True, exist_ok=True)
60+
CLEANUP.append(lambda: shutil.rmtree(dist_info))
61+
for f in (eptest_src / "eptestpackage.dist-info").glob("*"):
62+
(dist_info / f.name).write_bytes(f.read_bytes())
63+
(site / "eptestpackage.py").write_bytes((eptest_src / "eptestpackage.py").read_bytes())
64+
CLEANUP.append((site / "eptestpackage.py").unlink)
65+
66+
print("Listing 'installed' packages (should include eptestpackage)")
67+
print(*site.glob("*"), sep="\n")
68+
print()
69+
70+
out, _ = run(exe, "-c", "import eptestpackage; eptestpackage.main()")
71+
if out.strip() != "eptestpackage:main":
72+
print(out)
73+
print("##[error]Failed to import eptestpackage")
74+
sys.exit(EXIT_SETUP_FAILED)
75+
print("Confirmed eptestpackage is importable")
76+
77+
out, _ = run("pymanager", "list", "-f=config", "-q")
78+
try:
79+
config = json.loads(out)
80+
except json.JSONDecodeError:
81+
print("py list -f=config output:")
82+
print(out)
83+
raise
84+
bin_dir = Path(config["global_dir"])
85+
print(bin_dir)
86+
87+
refresh_log, _ = run("pymanager", "install", "--refresh", "-vv")
88+
CLEANUP.append(lambda: run("pymanager", "install", "--refresh"))
89+
90+
print("Listing global aliases (should include eptest, eptestw, eptest-refresh)")
91+
print(*bin_dir.glob("eptest*"), sep="\n")
92+
93+
for n in ["eptest.exe", "eptestw.exe", "eptest-refresh.exe"]:
94+
if not (bin_dir / n).is_file():
95+
print("--refresh log follows")
96+
print(refresh_log)
97+
print("##[error]Did not create", n)
98+
sys.exit(EXIT_ALIAS_NOT_CREATED)
99+
100+
out, _ = run(bin_dir / "eptest.exe")
101+
print(out)
102+
if out.strip() != "eptestpackage:main":
103+
print("##[error]eptest.exe alias failed")
104+
sys.exit(EXIT_ALIAS_INVALID)
105+
106+
out, _ = run(bin_dir / "eptestw.exe")
107+
print(out)
108+
if out.strip() != "eptestpackage:mainw":
109+
print("##[error]eptestw.exe alias failed")
110+
sys.exit(EXIT_ALIAS_INVALID)
111+
112+
out, _ = run(bin_dir / "eptest-refresh.exe")
113+
print(out)
114+
if not out.strip().endswith("eptestpackage:do_refresh"):
115+
print("##[error]eptest-refresh.exe alias failed")
116+
sys.exit(EXIT_ALIAS_INVALID)
117+
118+
119+
try:
120+
main()
121+
finally:
122+
print("Beginning cleanup")
123+
while CLEANUP:
124+
try:
125+
CLEANUP.pop()()
126+
except subprocess.CalledProcessError as ex:
127+
print("Subprocess failed during cleanup:")
128+
print(ex.args, ex.returncode)
129+
print(ex.output)

0 commit comments

Comments
 (0)