Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: testing common wheels #2031

Merged
merged 37 commits into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
15d65a8
wip: testing common wheels
tdejager Sep 10, 2024
3a492c2
Merge branch 'main' into test/test-common-wheels
tdejager Sep 10, 2024
c933a70
feat: created toml file to make richer specification for testing
tdejager Sep 10, 2024
55315f6
fix: linting
tdejager Sep 10, 2024
0edf55d
Merge branch 'main' into test/test-common-wheels
tdejager Sep 10, 2024
b17957e
feat: better output
tdejager Sep 10, 2024
02e995d
feat: made test suite more fully-fledged with summary support, and fi…
tdejager Sep 12, 2024
4e316e3
feat: add github ci
tdejager Sep 12, 2024
c608706
feat: upload logs
tdejager Sep 12, 2024
1bff8cf
fix: dont error out if results file does not exist
tdejager Sep 12, 2024
ec3e682
fix: attempt to fix ci path
tdejager Sep 12, 2024
aa749e7
feat: change name
tdejager Sep 12, 2024
e32b00b
Merge branch 'main' into test/test-common-wheels
tdejager Sep 12, 2024
af38ae0
feat: actually make use of pixi command
tdejager Sep 12, 2024
017d8b4
feat: fix pixi path again
tdejager Sep 13, 2024
93479dd
fix: use ci for pipeline
tdejager Sep 13, 2024
150c09f
fix: try to fix ci by switching with and except
tdejager Sep 13, 2024
0c1edda
Merge branch 'main' into test/test-common-wheels
tdejager Sep 13, 2024
e117eb4
fix: ci
tdejager Sep 13, 2024
c6e6ac5
fix: use tmp_path instead of custom temp dir, thx julian
tdejager Sep 13, 2024
97cad74
Merge branch 'main' into test/test-common-wheels
tdejager Sep 14, 2024
62f7887
Merge branch 'main' into test/test-common-wheels
tdejager Sep 16, 2024
dd9e12d
fix: try to fix windows encoding
tdejager Sep 16, 2024
c1f8b54
feat: continue on error
tdejager Sep 16, 2024
790b4f1
fix: try to fix windows encoding, again
tdejager Sep 16, 2024
6dbf5ec
fix: upload of logs
tdejager Sep 16, 2024
9be448a
fix: pin wheel version for windows
tdejager Sep 16, 2024
78fb42e
Merge branch 'main' into test/test-common-wheels
tdejager Sep 16, 2024
baad74e
Update pixi.toml
tdejager Sep 16, 2024
38dea84
fix: fix ci name
tdejager Sep 16, 2024
5cc1996
fix: some misc fixes
tdejager Sep 16, 2024
a80c65a
fix: remove continue on error
tdejager Sep 16, 2024
eedaf7d
feat: make summaries nicer and move wheels
tdejager Sep 16, 2024
2894114
feat: try different alwats conditionals
tdejager Sep 16, 2024
40c309e
fix: brought back test failures
tdejager Sep 17, 2024
c3053f2
fix: retry for flaky windows tests
tdejager Sep 17, 2024
9ee517a
fix: added some comments
tdejager Sep 17, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -417,3 +417,9 @@ jobs:
needs:
- build
uses: ./.github/workflows/test_downstream.yml

test_common_wheels:
name: "Test installation of common wheels"
needs:
- build
uses: ./.github/workflows/test_common_wheels.yml
79 changes: 79 additions & 0 deletions .github/workflows/test_common_wheels.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
name: "Test common wheel files for installation with pixi"

on:
workflow_call:

jobs:
test_common_wheels:
name: ${{ matrix.arch.name }} - Test Installation of Common Wheels
runs-on: ${{ matrix.arch.os }}
env:
TARGET_RELEASE: "${{ github.workspace }}/.pixi/target/release"
LOGS_DIR: "${{ github.workspace }}/tests/wheel_tests/.logs"
SUMMARY_FILE: "${{ github.workspace }}/tests/wheel_tests/.summary.md"
PYTHONIOENCODING: utf-8
strategy:
fail-fast: false
matrix:
arch:
# Linux
- {
target: x86_64-unknown-linux-musl,
os: 8core_ubuntu_latest_runner,
name: "Linux",
}
# MacOS
- { target: x86_64-apple-darwin, os: macos-13, name: "MacOS-x86" }
- { target: aarch64-apple-darwin, os: macos-14, name: "MacOS-Arm" } # macOS-14 is the ARM chipset
# Windows
- {
target: x86_64-pc-windows-msvc,
os: windows-latest,
extension: .exe,
name: "Windows",
}
steps:
- name: Checkout repo
uses: actions/checkout@v4
- name: Download binary from build
uses: actions/download-artifact@v4
with:
name: pixi-${{ matrix.arch.target }}${{ matrix.arch.extension }}
path: pixi_bin
- name: Debug
run: |
pwd
- name: Create Directory and Move Executable to TARGET_RELEASE
if: matrix.arch.name != 'Windows'
run: |
mkdir -p ${{ env.TARGET_RELEASE }}
mv pixi_bin/pixi-${{ matrix.arch.target }} ${{ env.TARGET_RELEASE }}/pixi
chmod a+x ${{ env.TARGET_RELEASE }}/pixi
- name: Create Directory and Move Executable to TARGET_RELEASE
if: matrix.arch.name == 'Windows' && matrix.arch.target == 'x86_64-pc-windows-msvc'
run: |
New-Item -ItemType Directory -Force -Path "${{ env.TARGET_RELEASE }}"
Move-Item -Path "pixi_bin/pixi-${{ matrix.arch.target }}${{ matrix.arch.extension }}" -Destination "${{ env.TARGET_RELEASE }}/pixi.exe"
shell: pwsh
- name: Test common wheels
continue-on-error: true
tdejager marked this conversation as resolved.
Show resolved Hide resolved
run: ${{ env.TARGET_RELEASE }}/pixi${{ matrix.arch.extension }} run test-common-wheels-ci
- name: Write .summary.md to Github Summary
if: matrix.arch.name != 'Windows'
continue-on-error: true
shell: bash
run: |
cat ${{ env.SUMMARY_FILE }} >> $GITHUB_STEP_SUMMARY
- name: Write .summary.md to GitHub Summary (Windows)
if: matrix.arch.name == 'Windows'
continue-on-error: true
shell: pwsh
run: |
$resolvedPath = Resolve-Path $env:SUMMARY_FILE
Get-Content $resolvedPath | Out-File -Append -FilePath $env:GITHUB_STEP_SUMMARY
- name: Upload Logs
uses: actions/upload-artifact@v4
with:
name: test-results
include-hidden-files: true
path: ${{ env.LOGS_DIR }}
104 changes: 104 additions & 0 deletions pixi.lock

Large diffs are not rendered by default.

8 changes: 7 additions & 1 deletion pixi.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ channels = ["https://fast.prefix.dev/conda-forge"]
platforms = ["linux-64", "win-64", "osx-64", "osx-arm64"]

[dependencies]
python = ">=3.12.3,<4"
python = "3.12.*"

[tasks]
build = "cargo build --release"
Expand All @@ -32,8 +32,14 @@ mypy = ">=1.11,<1.12"
psutil = ">=6.0.0,<7"
# For running tests in parallel, use this instead of regular pytest
pytest-xdist = ">=3.6.1,<4"
rich = ">=13.7.1,<14"
toml = ">=0.10.2,<0.11"

[feature.pytest.tasks]
test-common-wheels = { cmd = "pytest -n logical tests/wheel_tests/", depends-on = [
"build",
] }
test-common-wheels-ci = { cmd = "pytest -n logical tests/wheel_tests/" }
tdejager marked this conversation as resolved.
Show resolved Hide resolved
test-integration-ci = "pytest -n logical tests/integration"
test-integration-dev = { cmd = "pytest -n logical tests/integration", depends-on = [
"build",
Expand Down
3 changes: 3 additions & 0 deletions tests/wheel_tests/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.wheel_test_results.toml
.logs/**
.summary.md
25 changes: 25 additions & 0 deletions tests/wheel_tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from generate_summaries import terminal_summary, markdown_summary
from helpers import setup_stdout_stderr_logging


def pytest_configure(config):
setup_stdout_stderr_logging()


def pytest_addoption(parser):
parser.addoption("--pixi-exec", action="store", help="Path to the pixi executable")


def pytest_terminal_summary(terminalreporter, exitstatus, config):
"""
At the end of the test session, generate a summary report.
"""
terminal_summary()


def pytest_sessionfinish(session, exitstatus):
"""
At the end of the test session, generate a `.summary.md` report. That contains the
same information as the terminal summary.
"""
markdown_summary()
100 changes: 100 additions & 0 deletions tests/wheel_tests/generate_summaries.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
from record_results import RESULTS_FILE
import toml
from rich.console import Console
from rich.table import Table
from rich.text import Text
from rich.panel import Panel
from pathlib import Path


def terminal_summary():
# Read aggregated results from the shared file
results_file = RESULTS_FILE
if not results_file.exists():
print("Error: No test results found.")
return

with results_file.open("r") as f:
results = toml.load(f)["results"]

console = Console()
table = Table(title="Test Results", show_header=True, header_style="bold magenta")
table.add_column("Test Name", style="dim", width=60)
table.add_column("Outcome", justify="right")
table.add_column("Duration (s)", justify="right")
table.add_column("Error Details")

# Populate the table with collected results
for result in sorted(results, key=lambda r: r["name"]):
outcome_color = "green" if result["outcome"] == "passed" else "red"
error_details = result["longrepr"] if result["outcome"] == "failed" else ""
table.add_row(
Text(result["name"]),
Text(result["outcome"], style=outcome_color),
f"{result['duration']:.2f}",
error_details,
)

# Display the table in the terminal
console.print(table)

# Add a summary box with instructions
summary_text = (
"[bold]Summary:[/bold]\n\n"
f"- Total tests run: {len(results)}\n"
f"- Passed: {sum(1 for r in results if r['outcome'] == 'passed')}\n"
f"- Failed: {sum(1 for r in results if r['outcome'] == 'failed')}\n\n"
"To filter tests by a specific wheel, use the command:\n"
"[bold green]pytest -k '<pixi_add_cmd>'[/]\n\n"
"Replace [bold]<pixi_add_com>[/] with the desired wheel's name to run only tests for that wheel.\n"
r'E.g use [magenta] pixi r test-common-wheels -k "jax\[cuda12]"[/] to run tests for the [bold]jax\[cuda12][/] wheel.'
"\n\n"
"[bold yellow]Note:[/]\n"
"Any [italic]failed[/] tests will have recorded their output to the [bold].log/[/] directory, which"
" resides next to to `wheels.toml` file.\n"
)

# Create a Rich panel (box) for the summary text
summary_panel = Panel(
summary_text, title="Test Debrief", title_align="left", border_style="bright_blue"
)

# Display the summary box in the terminal
console.print(summary_panel)


def markdown_summary():
if not RESULTS_FILE.exists():
return

summary_file = Path(__file__).parent / ".summary.md"
with summary_file.open("w") as f:
# Read the RESULTS_FILE and generate a markdown summary
f.write("# Test Summary\n\n")
f.write("""
This document contains a summary of the test results for the wheels in the `wheels.toml` file.
You can use the following command, in the pixi repository, to filter tests by a specific wheel:
```bash
pixi r test-common-wheels -k "<pixi_add_cmd>"
# E.g
pixi r test-common-wheels -k "jax[cuda12]"
```

""")
f.write("## Test Results\n\n")
f.write("\n")
f.write("| Test Name | Outcome | Duration (s) | Error Details |\n")
f.write("| :--- | ---: | ---: | --- |\n")

results_file = RESULTS_FILE
with results_file.open("r") as r:
results = toml.load(r)["results"]
for result in results:
outcome = (
'<span style="color: green">Passed</span>'
if result["outcome"] == "passed"
else '<span style="color: red">Failed</span>'
)
error_details = result["longrepr"] if result["outcome"] == "failed" else ""
f.write(f"|{result["name"]}|{outcome}|{result['duration']:.2f}|{error_details}|\n")
f.write("\n")
61 changes: 61 additions & 0 deletions tests/wheel_tests/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import os
import subprocess
import pathlib
from typing import Any
import toml

StrPath = str | os.PathLike[str]


def run(args: list[StrPath], cwd: StrPath | None = None) -> None:
"""
Run a subprocess and check the return code
"""
proc: subprocess.CompletedProcess[bytes] = subprocess.run(
args, cwd=cwd, capture_output=True, check=False
)
proc.check_returncode()


def add_system_requirements(manifest_path: pathlib.Path, system_requirements: dict[str, Any]):
"""
Add system requirements to the manifest file
add something like this:
[system-requirements]
libc = { family = "glibc", version = "2.17" }
to the manifest file
"""
with manifest_path.open("r") as f:
manifest = toml.load(f)
manifest["system-requirements"] = system_requirements
with manifest_path.open("w") as f:
toml.dump(manifest, f)


LOG_DIR = pathlib.Path(__file__).parent / ".logs"


def setup_stdout_stderr_logging():
"""
Set up the logging directory
"""
if not LOG_DIR.exists():
LOG_DIR.mkdir()
for file in LOG_DIR.iterdir():
file.unlink()


def log_called_process_error(name: str, err: subprocess.CalledProcessError, std_err_only=False):
"""
Log the output of a subprocess that failed
"""
if not LOG_DIR.exists():
raise RuntimeError("Call setup_stdout_stderr_logging before logging")
std_out_log = LOG_DIR / f"{name}.stdout"
std_err_log = LOG_DIR / f"{name}.stderr"
if err.returncode != 0:
if not std_err_only:
with std_out_log.open("w", encoding="utf-8") as f:
f.write(err.stdout.decode("uft-8"))
with std_err_log.open("w", encoding="utf-8") as f:
f.write(err.stderr.decode("utf-8"))
Loading
Loading