test_release_version.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. """Tests for repository-owned Python release versions."""
  2. from __future__ import annotations
  3. import json
  4. import runpy
  5. import stat
  6. from pathlib import Path
  7. from types import SimpleNamespace
  8. import pytest
  9. ROOT = Path(__file__).resolve().parents[3]
  10. SCRIPT = ROOT / "scripts" / "build-python-release.py"
  11. build_python_release = SimpleNamespace(**runpy.run_path(str(SCRIPT)))
  12. def helper_header(target: str) -> bytes:
  13. header = bytearray(8)
  14. header[:4] = b"\xcf\xfa\xed\xfe"
  15. cpu_type = 0x01000007 if target == "macos-x64" else 0x0100000C
  16. header[4:8] = cpu_type.to_bytes(4, "little")
  17. return bytes(header)
  18. def test_repository_version_matches_root_package_json() -> None:
  19. expected = json.loads((ROOT / "package.json").read_text())["version"]
  20. assert build_python_release.repository_version() == expected
  21. def test_release_tag_is_optional_for_non_release_builds() -> None:
  22. build_python_release.validate_release_tag(None, "1.2.3")
  23. def test_release_tag_must_match_repository_version() -> None:
  24. build_python_release.validate_release_tag("python-v1.2.3", "1.2.3")
  25. with pytest.raises(ValueError, match="expected 'python-v1.2.3'"):
  26. build_python_release.validate_release_tag("python-v1.2.4", "1.2.3")
  27. def test_repository_version_rejects_non_stable_versions(tmp_path: Path) -> None:
  28. (tmp_path / "package.json").write_text('{"version":"1.2.3-dev"}\n')
  29. with pytest.raises(ValueError, match="must be stable X.Y.Z"):
  30. build_python_release.repository_version(tmp_path)
  31. def test_stage_runtime_copies_executable_and_spawn_helper(tmp_path: Path) -> None:
  32. executable = tmp_path / "dsh-jsonrpc-agent-pkg-macos-arm64"
  33. executable.write_bytes(b"runtime")
  34. executable.chmod(0o755)
  35. spawn_helper = Path(f"{executable}-spawn-helper")
  36. spawn_helper.write_bytes(helper_header("macos-arm64"))
  37. spawn_helper.chmod(0o751)
  38. destination = tmp_path / "staging"
  39. build_python_release.stage_runtime(
  40. destination,
  41. "1.2.3",
  42. executable,
  43. executable.name,
  44. )
  45. runtime_dir = destination / "src" / "deepseek_harness_runtime" / "runtime"
  46. assert (runtime_dir / executable.name).read_bytes() == b"runtime"
  47. copied_helper = runtime_dir / spawn_helper.name
  48. assert copied_helper.read_bytes() == helper_header("macos-arm64")
  49. assert copied_helper.stat().st_mode & stat.S_IXUSR
  50. def test_stage_runtime_rejects_missing_spawn_helper(tmp_path: Path) -> None:
  51. executable = tmp_path / "dsh-jsonrpc-agent-pkg-macos-arm64"
  52. executable.write_bytes(b"runtime")
  53. executable.chmod(0o755)
  54. with pytest.raises(FileNotFoundError, match="spawn helper"):
  55. build_python_release.stage_runtime(
  56. tmp_path / "staging",
  57. "1.2.3",
  58. executable,
  59. executable.name,
  60. )
  61. def test_stage_runtime_rejects_unsupported_executable_name(tmp_path: Path) -> None:
  62. executable = tmp_path / "custom-runtime"
  63. executable.write_bytes(b"runtime")
  64. executable.chmod(0o755)
  65. with pytest.raises(
  66. ValueError,
  67. match=(
  68. "unsupported runtime executable 'custom-runtime'; expected one of: "
  69. "dsh-jsonrpc-agent-pkg-linux-arm64, dsh-jsonrpc-agent-pkg-linux-x64, "
  70. "dsh-jsonrpc-agent-pkg-macos-arm64"
  71. ),
  72. ):
  73. build_python_release.stage_runtime(
  74. tmp_path / "staging",
  75. "1.2.3",
  76. executable,
  77. executable.name,
  78. )
  79. @pytest.mark.parametrize("target", ["linux-x64", "linux-arm64"])
  80. def test_stage_runtime_copies_linux_executable_without_spawn_helper(
  81. tmp_path: Path, target: str
  82. ) -> None:
  83. executable = tmp_path / f"dsh-jsonrpc-agent-pkg-{target}"
  84. executable.write_bytes(b"runtime")
  85. executable.chmod(0o755)
  86. destination = tmp_path / "staging"
  87. build_python_release.stage_runtime(destination, "1.2.3", executable, executable.name)
  88. runtime_dir = destination / "src" / "deepseek_harness_runtime" / "runtime"
  89. runtime_files = [path.name for path in runtime_dir.glob("dsh-jsonrpc-agent-pkg-*")]
  90. assert runtime_files == [executable.name]
  91. @pytest.mark.parametrize("target", ["macos-x64", "macos-arm64"])
  92. def test_spawn_helper_binary_target(target: str) -> None:
  93. assert build_python_release.spawn_helper_binary_target(helper_header(target)) == target
  94. def test_stage_runtime_rejects_mismatched_spawn_helper(tmp_path: Path) -> None:
  95. executable = tmp_path / "dsh-jsonrpc-agent-pkg-macos-arm64"
  96. executable.write_bytes(b"runtime")
  97. executable.chmod(0o755)
  98. spawn_helper = Path(f"{executable}-spawn-helper")
  99. spawn_helper.write_bytes(helper_header("macos-x64"))
  100. spawn_helper.chmod(0o755)
  101. with pytest.raises(ValueError, match="expected macos-arm64, found macos-x64"):
  102. build_python_release.stage_runtime(
  103. tmp_path / "staging",
  104. "1.2.3",
  105. executable,
  106. executable.name,
  107. )
  108. def test_stage_runtime_rejects_non_binary_spawn_helper(tmp_path: Path) -> None:
  109. executable = tmp_path / "dsh-jsonrpc-agent-pkg-macos-arm64"
  110. executable.write_bytes(b"runtime")
  111. executable.chmod(0o755)
  112. spawn_helper = Path(f"{executable}-spawn-helper")
  113. spawn_helper.write_bytes(b"helper")
  114. spawn_helper.chmod(0o755)
  115. with pytest.raises(ValueError, match="unsupported format or architecture"):
  116. build_python_release.stage_runtime(
  117. tmp_path / "staging",
  118. "1.2.3",
  119. executable,
  120. executable.name,
  121. )