mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-09-28 06:45:17 +08:00
Verified with a build_environment test venv (no editable finder, no committed PM selection) plus real uv on PATH — the shape CI runs. - test_old_updater_takeover: the fake NEW checkout carries update_handoff.py; the test never relied on the source being importable from an editable venv. - test_update_launch_completion: record the completion-tail child instead of running the checkout's (nonexistent) source_completion.py. - test_update_missing_configured_deps: source_launch already stubs hermes_cli/; link the remaining modules beside the stub. - test_worker: the injected runtime_lock stub accepts the timeout kwarg the worker now passes (it raised TypeError before reaching the lock). - test_plugin_guard / test_plugin_install_ref: PM publishes plugins only under the active home's plugins/ and does so in the worker — install into the sandboxed home, and fail the metadata write inside the worker. - test_pm_build_consumers: setup_toolchain deliberately puts uv on PATH after the interpreter (c8bbac5c6e); assert that ordering instead of its absence. - test_icon_flavors: tile_color reads the most chromatic lower-half pixel (the inward contrasting border and LANCZOS smear defeat a fixed coordinate); the SHA glyph readback skips cells the portrait covers (da9f6d2dcdrenders her in front of the badge) and requires a majority of each glyph. - test_desktop_update_target: the fixture CLI reports the checkout as its install directory again (parents[1] inside the string was bumped with the file move incb7c688171). - test_termux_python_linkage: skip when the host has no shared libpython or no patchelf (relocatable python-build-standalone in CI). - test_source_build_env: smoke-env.mjs is dependency-free (main removed the Playwright entry it imported through); pm/_fixtures.stage_host_python copies the stdlib beside the interpreter for payload tests. test_api_server_runs::test_events_stream_forwards_interim_commentary is an upstream flake (identical file on origin/main fails 2/3 locally).
65 lines
2.8 KiB
Python
65 lines
2.8 KiB
Python
"""Exercise the linker repair against a real native extension on Linux."""
|
|
from __future__ import annotations
|
|
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import sysconfig
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from scripts.termux import python_linkage
|
|
|
|
|
|
@pytest.mark.platforms("linux")
|
|
def test_python_symbols_gain_an_explicit_library_dependency(tmp_path):
|
|
import _cffi_backend
|
|
|
|
library = Path(sysconfig.get_config_var("LIBDIR")) / sysconfig.get_config_var("LDLIBRARY")
|
|
if not library.is_file():
|
|
# A relocatable python-build-standalone reports its build-time prefix (/install)
|
|
# and links libpython statically; there is no shared library to name here.
|
|
pytest.skip(f"host interpreter has no shared libpython at {library}")
|
|
if shutil.which("patchelf") is None:
|
|
pytest.skip("patchelf is not on PATH")
|
|
extension = tmp_path / Path(_cffi_backend.__file__).name
|
|
shutil.copyfile(_cffi_backend.__file__, extension) # Writable scratch even from a read-only Nix store.
|
|
original = subprocess.check_output(["patchelf", "--print-needed", str(extension)], text=True).splitlines()
|
|
for name in original:
|
|
if name.startswith("libpython"):
|
|
subprocess.run(["patchelf", "--remove-needed", name, str(extension)], check=True)
|
|
assert python_linkage.link_extension(extension, library)
|
|
needed = subprocess.check_output(["patchelf", "--print-needed", str(extension)], text=True).splitlines()
|
|
soname = subprocess.check_output(["patchelf", "--print-soname", str(library)], text=True).strip()
|
|
assert soname in needed
|
|
assert not python_linkage.link_extension(extension, library), "a second pass must not edit a correct extension"
|
|
subprocess.run(
|
|
[sys.executable, "-c", "import _cffi_backend; print(_cffi_backend.__file__)"],
|
|
cwd=tmp_path, check=True,
|
|
)
|
|
|
|
|
|
def test_wheel_rewrite_regenerates_record_for_changed_member(tmp_path):
|
|
import zipfile
|
|
from scripts.termux import retag_wheel
|
|
from tests.termux_fixtures import write_wheel, verify_record
|
|
|
|
wheel = write_wheel(tmp_path)
|
|
|
|
def repair(path, library):
|
|
assert library == tmp_path / "libpython.so"
|
|
assert path.read_bytes() == b"\x7fELFfake"
|
|
path.write_bytes(b"repaired native bytes")
|
|
return True
|
|
|
|
python_linkage.repair_wheel(wheel, tmp_path / "libpython.so", repair=repair)
|
|
verify_record(wheel) # Retagging must not hide a stale repair RECORD.
|
|
with zipfile.ZipFile(wheel) as archive:
|
|
assert archive.read("fakedep/_native.so") == b"repaired native bytes"
|
|
retagged = retag_wheel.retag_wheel(str(wheel), "android_24_arm64_v8a")
|
|
verify_record(retagged)
|
|
with zipfile.ZipFile(retagged) as archive:
|
|
assert archive.read("fakedep/_native.so") == b"repaired native bytes"
|
|
assert b"Tag: py3-none-android_24_arm64_v8a\n" in archive.read("fakedep-1.2.3.dist-info/WHEEL")
|