Files
2026-07-13 13:17:40 +08:00

241 lines
7.6 KiB
Python

import os
import sys
import tempfile
import pytest
from ray_release.byod.build_context import (
_INSTALL_PYTHON_DEPS_SCRIPT,
build_context_digest,
decode_build_context,
encode_build_context,
fill_build_context_dir,
make_build_context,
)
def test_make_build_context() -> None:
with tempfile.TemporaryDirectory() as tmpdir:
script_path = os.path.join(tmpdir, "post_build.sh")
with open(script_path, "w") as f:
f.write("echo hello")
depset_path = os.path.join(tmpdir, "deps.lock")
with open(depset_path, "w") as f:
f.write("numpy==1.0.0")
ctx = make_build_context(
base_dir=tmpdir,
envs={"FOO": "bar"},
post_build_script="post_build.sh",
python_depset="deps.lock",
)
assert ctx == {
"envs": {"FOO": "bar"},
"post_build_script": "post_build.sh",
"post_build_script_digest": ctx["post_build_script_digest"],
"python_depset": "deps.lock",
"python_depset_digest": ctx["python_depset_digest"],
"install_python_deps_script_digest": ctx[
"install_python_deps_script_digest"
],
}
assert ctx["post_build_script_digest"].startswith("sha256:")
assert ctx["python_depset_digest"].startswith("sha256:")
assert ctx["install_python_deps_script_digest"].startswith("sha256:")
def test_make_build_context_partial() -> None:
with tempfile.TemporaryDirectory() as tmpdir:
script_path = os.path.join(tmpdir, "post_build.sh")
with open(script_path, "w") as f:
f.write("echo hello")
ctx = make_build_context(
base_dir=tmpdir,
post_build_script="post_build.sh",
)
assert ctx == {
"post_build_script": "post_build.sh",
"post_build_script_digest": ctx["post_build_script_digest"],
}
assert ctx["post_build_script_digest"].startswith("sha256:")
def test_make_build_context_empty() -> None:
with tempfile.TemporaryDirectory() as tmpdir:
ctx = make_build_context(base_dir=tmpdir)
assert ctx == {}
def test_encode_build_context() -> None:
with tempfile.TemporaryDirectory() as tmpdir:
with open(os.path.join(tmpdir, "build.sh"), "w") as f:
f.write("echo hello")
ctx = make_build_context(
base_dir=tmpdir,
envs={"ZZZ": "last", "AAA": "first"},
post_build_script="build.sh",
)
encoded = encode_build_context(ctx)
# Verify minified (no spaces)
assert " " not in encoded
# Verify deterministic via digest - same content in different order produces same digest
ctx_reordered = {
"post_build_script_digest": ctx["post_build_script_digest"],
"post_build_script": "build.sh",
"envs": {"AAA": "first", "ZZZ": "last"},
}
assert build_context_digest(ctx) == build_context_digest(ctx_reordered)
def test_decode_build_context() -> None:
data = '{"envs":{"FOO":"bar"},"post_build_script":"build.sh"}'
ctx = decode_build_context(data)
assert ctx["envs"] == {"FOO": "bar"}
assert ctx["post_build_script"] == "build.sh"
def test_encode_decode_roundtrip() -> None:
with tempfile.TemporaryDirectory() as tmpdir:
with open(os.path.join(tmpdir, "script.sh"), "w") as f:
f.write("echo hello")
with open(os.path.join(tmpdir, "deps.lock"), "w") as f:
f.write("numpy==1.0.0")
ctx = make_build_context(
base_dir=tmpdir,
envs={"KEY": "value"},
post_build_script="script.sh",
python_depset="deps.lock",
)
encoded = encode_build_context(ctx)
decoded = decode_build_context(encoded)
assert decoded == ctx
def test_build_context_digest() -> None:
with tempfile.TemporaryDirectory() as tmpdir:
with open(os.path.join(tmpdir, "build.sh"), "w") as f:
f.write("echo hello")
with open(os.path.join(tmpdir, "build2.sh"), "w") as f:
f.write("echo world")
ctx1 = make_build_context(
base_dir=tmpdir,
post_build_script="build.sh",
)
ctx2 = make_build_context(
base_dir=tmpdir,
post_build_script="build2.sh",
)
ctx3 = make_build_context(
base_dir=tmpdir,
envs={"FOO": "bar"},
post_build_script="build.sh",
)
digest1 = build_context_digest(ctx1)
digest2 = build_context_digest(ctx2)
digest3 = build_context_digest(ctx3)
# Different file contents produce different digests
assert digest1 != digest2
# Different envs produce different digests
assert digest1 != digest3
# All three are different
assert len({digest1, digest2, digest3}) == 3
def test_fill_build_context_dir_empty() -> None:
with (
tempfile.TemporaryDirectory() as source_dir,
tempfile.TemporaryDirectory() as build_dir,
):
ctx = make_build_context(base_dir=source_dir)
fill_build_context_dir(ctx, source_dir, build_dir)
# Check Dockerfile
with open(os.path.join(build_dir, "Dockerfile")) as f:
dockerfile = f.read()
expected_dockerfile = "\n".join(
[
"# syntax=docker/dockerfile:1.3-labs",
"ARG BASE_IMAGE",
"FROM ${BASE_IMAGE}",
"",
]
)
assert dockerfile == expected_dockerfile
# Check no other files were created
assert os.listdir(build_dir) == ["Dockerfile"]
def test_fill_build_context_dir() -> None:
with (
tempfile.TemporaryDirectory() as source_dir,
tempfile.TemporaryDirectory() as build_dir,
):
# Create input files
with open(os.path.join(source_dir, "post_build.sh"), "w") as f:
f.write("#!/bin/bash\necho hello")
with open(os.path.join(source_dir, "deps.lock"), "w") as f:
f.write("numpy==1.0.0\npandas==2.0.0")
ctx = make_build_context(
base_dir=source_dir,
envs={"FOO": "bar", "BAZ": "qux"},
post_build_script="post_build.sh",
python_depset="deps.lock",
)
fill_build_context_dir(ctx, source_dir, build_dir)
# Check Dockerfile
with open(os.path.join(build_dir, "Dockerfile")) as f:
dockerfile = f.read()
expected_dockerfile = "\n".join(
[
"# syntax=docker/dockerfile:1.3-labs",
"ARG BASE_IMAGE",
"FROM ${BASE_IMAGE}",
"ENV \\",
" BAZ=qux \\",
" FOO=bar",
"COPY install_python_deps.sh /tmp/install_python_deps.sh",
"COPY python_depset.lock python_depset.lock",
"RUN bash /tmp/install_python_deps.sh python_depset.lock",
"COPY post_build_script.sh /tmp/post_build_script.sh",
"RUN bash /tmp/post_build_script.sh",
"",
]
)
assert dockerfile == expected_dockerfile
# Check copied files
with open(os.path.join(build_dir, "post_build_script.sh")) as f:
assert f.read() == "#!/bin/bash\necho hello"
with open(os.path.join(build_dir, "python_depset.lock")) as f:
assert f.read() == "numpy==1.0.0\npandas==2.0.0"
with open(os.path.join(build_dir, "install_python_deps.sh")) as f:
assert f.read() == _INSTALL_PYTHON_DEPS_SCRIPT
if __name__ == "__main__":
sys.exit(pytest.main(["-vv", __file__]))