Skip to content

Commit 9d6afde

Browse files
authored
Merge pull request #414 from mdboom/add-unit-tests
Improve test coverage
2 parents 8d87a49 + 55ac61c commit 9d6afde

File tree

12 files changed

+404
-203
lines changed

12 files changed

+404
-203
lines changed

.github/workflows/ci.yml

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,40 @@ jobs:
3232
with:
3333
python-version: ${{ matrix.python_version }}
3434
cache: pip
35-
- name: Install dependencies
35+
- name: install dependencies
36+
run: |
37+
python -m pip install .[test]
38+
- name: run tests
39+
run: |
40+
python -m pytest tests -n auto -m "not long_running"
41+
42+
long_test_linux:
43+
runs-on: ubuntu-latest
44+
steps:
45+
- uses: actions/checkout@v4
46+
- uses: actions/setup-python@v5
47+
with:
48+
python-version: 3.13
49+
cache: pip
50+
- name: install dependencies
3651
run: |
3752
python -m pip install .[test]
38-
- name: Run tests
53+
- name: run tests
3954
run: |
40-
python -m pytest tests -n auto
55+
python -m pytest tests -n auto -m long_running
56+
57+
long_test_windows:
58+
runs-on: windows-latest
59+
steps:
60+
- uses: actions/checkout@v4
61+
- uses: actions/setup-python@v5
62+
with:
63+
python-version: 3.13
64+
cache: pip
65+
- name: install dependencies
66+
run: |
67+
python -m pip install .[test]
68+
- name: run tests
69+
run: |
70+
python -m pytest tests -n auto -m long_running
71+

bench_runner/config.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,24 @@
99

1010

1111
from . import runners
12+
from .util import PathLike
1213

1314

1415
@functools.cache
15-
def get_bench_runner_config(
16-
filepath: Path | str = Path("bench_runner.toml"),
17-
):
18-
with Path(filepath).open("rb") as fd:
16+
def get_bench_runner_config(filepath: PathLike | None = None):
17+
if filepath is None:
18+
filepath = Path("bench_runner.toml")
19+
else:
20+
filepath = Path(filepath)
21+
22+
with filepath.open("rb") as fd:
1923
return tomllib.load(fd)
2024

2125

22-
def get_config_for_current_runner() -> dict[str, Any]:
23-
config = get_bench_runner_config()
24-
runner = runners.get_runner_for_hostname()
25-
all_runners = config.get("runners", [])
26+
def get_config_for_current_runner(filepath: PathLike | None = None) -> dict[str, Any]:
27+
config = get_bench_runner_config(filepath)
28+
runner = runners.get_runner_for_hostname(cfgpath=filepath)
29+
all_runners = config.get("runners", {})
2630
if len(all_runners) >= 1:
27-
return all_runners[0].get(runner.nickname, {})
31+
return all_runners.get(runner.nickname, {})
2832
return {}

bench_runner/runners.py

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88

99
from . import config
10+
from .util import PathLike
1011

1112

1213
class Runner:
@@ -47,8 +48,8 @@ def display_name(self) -> str:
4748

4849

4950
@functools.cache
50-
def get_runners() -> list[Runner]:
51-
conf = config.get_bench_runner_config().get("runners", {})
51+
def get_runners(cfgpath: PathLike | None = None) -> list[Runner]:
52+
conf = config.get_bench_runner_config(cfgpath).get("runners", {})
5253
runners = []
5354
for nickname, section in conf.items():
5455
runners.append(
@@ -73,27 +74,31 @@ def get_runners() -> list[Runner]:
7374
return runners
7475

7576

76-
def get_runners_by_hostname() -> dict[str, Runner]:
77-
return {x.hostname: x for x in get_runners()}
77+
def get_runners_by_hostname(cfgpath: PathLike | None = None) -> dict[str, Runner]:
78+
return {x.hostname: x for x in get_runners(cfgpath)}
7879

7980

80-
def get_runners_by_nickname() -> dict[str, Runner]:
81-
return {x.nickname: x for x in get_runners()}
81+
def get_runners_by_nickname(cfgpath: PathLike | None = None) -> dict[str, Runner]:
82+
return {x.nickname: x for x in get_runners(cfgpath)}
8283

8384

84-
def get_nickname_for_hostname(hostname: str | None = None) -> str:
85+
def get_nickname_for_hostname(
86+
hostname: str | None = None, cfgpath: PathLike | None = None
87+
) -> str:
8588
# The envvar BENCHMARK_MACHINE_NICKNAME is used to override the machine that
8689
# results are reported for.
8790
if "BENCHMARK_MACHINE_NICKNAME" in os.environ:
8891
return os.environ["BENCHMARK_MACHINE_NICKNAME"]
89-
return get_runner_for_hostname(hostname).nickname
92+
return get_runner_for_hostname(hostname, cfgpath).nickname
9093

9194

92-
def get_runner_by_nickname(nickname: str) -> Runner:
93-
return get_runners_by_nickname().get(nickname, unknown_runner)
95+
def get_runner_by_nickname(nickname: str, cfgpath: PathLike | None = None) -> Runner:
96+
return get_runners_by_nickname(cfgpath).get(nickname, unknown_runner)
9497

9598

96-
def get_runner_for_hostname(hostname: str | None = None) -> Runner:
99+
def get_runner_for_hostname(
100+
hostname: str | None = None, cfgpath: PathLike | None = None
101+
) -> Runner:
97102
if hostname is None:
98103
hostname = socket.gethostname()
99-
return get_runners_by_hostname().get(hostname, unknown_runner)
104+
return get_runners_by_hostname(cfgpath).get(hostname, unknown_runner)

bench_runner/scripts/install.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,18 +308,29 @@ def generate_generic(dst: Any) -> Any:
308308
def _main(check: bool) -> None:
309309
WORKFLOW_PATH.mkdir(parents=True, exist_ok=True)
310310

311+
# Copy the bench_runner.toml file first, because it might be needed by the
312+
# other steps
313+
314+
if not (ROOT_PATH / "bench_runner.toml").is_file():
315+
shutil.copyfile(
316+
TEMPLATE_PATH / "bench_runner.toml",
317+
ROOT_PATH / "bench_runner.toml",
318+
)
319+
311320
for src_path in TEMPLATE_PATH.glob("*"):
312321
if not src_path.is_file():
313322
continue
314323

324+
print(f"Processing {src_path}...")
325+
315326
if src_path.name.endswith(".src.yml"):
316327
dst_path = WORKFLOW_PATH / (src_path.name[:-8] + ".yml")
317328
generator = GENERATORS.get(src_path.name, generate_generic)
318329
src = load_yaml(src_path)
319330
dst = generator(src)
320331
write_yaml(dst_path, dst, check)
321332
elif src_path.name.endswith(".src.py"):
322-
dst_path = WORKFLOW_PATH / (src_path.name[:-7] + ".py")
333+
dst_path = ROOT_PATH / (src_path.name[:-7] + ".py")
323334
write_python(dst_path, src_path.read_text(), check)
324335
else:
325336
dst_path = ROOT_PATH / src_path.name

bench_runner/scripts/workflow.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ def _main(
254254
pystats: bool,
255255
force_32bit: bool,
256256
run_id: str | None = None,
257+
fast: bool = False,
257258
):
258259
venv = Path("venv")
259260
cpython = Path("cpython")
@@ -270,7 +271,9 @@ def _main(
270271
checkout_cpython(fork, ref, cpython)
271272

272273
with log_group("Determining if we need to run benchmarks"):
273-
if not should_run(force, fork, ref, machine, False, flags, cpython=cpython):
274+
if not fast and not should_run(
275+
force, fork, ref, machine, False, flags, cpython=cpython
276+
):
274277
print("No need to run benchmarks. Skipping...")
275278
return
276279

@@ -291,8 +294,9 @@ def _main(
291294
with log_group("Installing pyperformance"):
292295
install_pyperformance(venv)
293296

294-
with log_group("Tuning system"):
295-
tune_system(venv, perf)
297+
if not fast:
298+
with log_group("Tuning system"):
299+
tune_system(venv, perf)
296300

297301
try:
298302
if Path(".debug").exists():
@@ -319,11 +323,12 @@ def _main(
319323
benchmarks,
320324
flags=flags,
321325
run_id=run_id,
322-
test_mode=False,
326+
test_mode=fast,
323327
individual=pystats,
324328
)
325329
finally:
326-
reset_system(venv)
330+
if not fast:
331+
reset_system(venv)
327332

328333

329334
def main():
@@ -364,6 +369,9 @@ def main():
364369
help="Do a 32-bit build (Windows only)",
365370
)
366371
parser.add_argument("--run_id", default=None, type=str, help="The github run id")
372+
parser.add_argument(
373+
"--_fast", action="store_true", help="Use fast mode, for testing"
374+
)
367375
args = parser.parse_args()
368376

369377
_main(
@@ -378,6 +386,7 @@ def main():
378386
args.pystats,
379387
args.force_32bit,
380388
args.run_id,
389+
args._fast,
381390
)
382391

383392

bench_runner/util.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,6 @@
99
from typing import Iterable, Iterator, Literal, TypeAlias, Union
1010

1111

12-
from . import config
13-
14-
1512
PathLike: TypeAlias = Union[str, os.PathLike]
1613

1714

@@ -32,6 +29,8 @@ def apply_suffix(path: PathLike, suffix: str) -> Path:
3229

3330
@functools.cache
3431
def get_excluded_benchmarks() -> set[str]:
32+
from . import config
33+
3534
conf = config.get_bench_runner_config()
3635
benchmarks_section = conf.get("benchmarks", {})
3736
for key in ("excluded", "excluded_benchmarks"):

pyproject.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,8 @@ include-package-data = true
4242

4343
[tool.setuptools.package-data]
4444
bench_runner = ["templates/*"]
45+
46+
[tool.pytest.ini_options]
47+
markers = [
48+
"long_running: marks tests as long_running (deselect with '-m \"not running\"')",
49+
]

tests/data/bench_runner.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,11 @@ markers = ["s", "s", "s", "^", ".", "."]
2525

2626
[publish_mirror]
2727
skip = false
28+
29+
[weekly.default]
30+
runners = ["linux"]
31+
flags = []
32+
33+
[weekly.jit]
34+
runners = ["linux"]
35+
flags = ["JIT"]

tests/test_config.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from pathlib import Path
2+
import socket
3+
4+
5+
from bench_runner import config
6+
7+
8+
DATA_PATH = Path(__file__).parent / "data"
9+
10+
11+
def test_get_runner_for_hostname(monkeypatch):
12+
monkeypatch.setattr(socket, "gethostname", lambda: "pyperf")
13+
14+
runner = config.get_config_for_current_runner(DATA_PATH / "bench_runner.toml")
15+
16+
assert runner["os"] == "linux"
17+
assert runner["arch"] == "x86_64"
18+
assert runner["hostname"] == "pyperf"

tests/test_flags.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import pytest
2+
3+
4+
from bench_runner import flags
5+
6+
7+
def test_parse_flags():
8+
assert flags.parse_flags("tier2,jit") == ["PYTHON_UOPS", "JIT"]
9+
assert flags.parse_flags("jit,tier2") == ["JIT", "PYTHON_UOPS"]
10+
assert flags.parse_flags("jit,tier2,") == ["JIT", "PYTHON_UOPS"]
11+
assert flags.parse_flags(",jit,tier2,") == ["JIT", "PYTHON_UOPS"]
12+
assert flags.parse_flags(",") == []
13+
assert flags.parse_flags("") == []
14+
15+
with pytest.raises(ValueError):
16+
flags.parse_flags("tier2,jit,foo")
17+
18+
19+
def test_flags_to_human():
20+
assert list(flags.flags_to_human(["PYTHON_UOPS", "JIT"])) == ["T2", "JIT"]

0 commit comments

Comments
 (0)