Source code
Revision control
Copy as Markdown
Other Tools
Test Info:
- Manifest: tools/update-packaging/test/python.toml
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
import hashlib
import importlib.util
import sys
import types
from pathlib import Path
from mozunit import main
# Pre-populate sys.modules with stub modules for mardor so the script's
# top-level "from mardor.* import ..." statements resolve without needing
# the real mardor package installed in the test environment. This must
# run before the script is loaded below; a fixture would fire too late.
mardor_pkg = types.ModuleType("mardor")
mardor_reader = types.ModuleType("mardor.reader")
mardor_reader.MarReader = object
mardor_signing = types.ModuleType("mardor.signing")
mardor_signing.get_keysize = lambda _cert: 4096
sys.modules.setdefault("mardor", mardor_pkg)
sys.modules.setdefault("mardor.reader", mardor_reader)
sys.modules.setdefault("mardor.signing", mardor_signing)
# tools/update-packaging is a script directory, not a Python package, so
# `import make_incremental_zucchini` wouldn't find it. Load the file by
# absolute path through importlib instead.
SCRIPT_PATH = Path(__file__).resolve().parent.parent / "make_incremental_zucchini.py"
spec = importlib.util.spec_from_file_location("make_incremental_zucchini", SCRIPT_PATH)
mz = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mz)
def _write(path, content):
path.parent.mkdir(parents=True, exist_ok=True)
path.write_bytes(content)
def _sha256(path):
"""Compute sha256 of a file via stdlib so test fixtures stay independent
of the script's own get_hash helper."""
return hashlib.sha256(Path(path).read_bytes()).hexdigest()
def test_hash_dir_walks_files(tmp_path):
_write(tmp_path / "a.txt", b"alpha")
_write(tmp_path / "sub/b.txt", b"beta")
_write(tmp_path / "sub/nested/c.txt", b"gamma")
hashes = mz._hash_dir(str(tmp_path))
assert hashes == {
"a.txt": _sha256(tmp_path / "a.txt"),
"sub/b.txt": _sha256(tmp_path / "sub/b.txt"),
"sub/nested/c.txt": _sha256(tmp_path / "sub/nested/c.txt"),
}
def test_hash_dir_empty(tmp_path):
assert mz._hash_dir(str(tmp_path)) == {}
def _make_cache_setup(tmp_path, rel_path, from_bytes, to_bytes, cache_state):
"""Build a fixture: returns (cache_entry, partials_dir, manifest_file,
cache_extracted_dir) and writes the local from/to files.
cache_state is "patch", "full", or "missing"."""
local_from = tmp_path / "from" / rel_path
local_to = tmp_path / "to" / rel_path
_write(local_from, from_bytes)
_write(local_to, to_bytes)
cache_extracted_dir = tmp_path / "cache_extracted"
cache_extracted_dir.mkdir()
if cache_state == "patch":
_write(cache_extracted_dir / f"{rel_path}.patch", b"PATCH-BYTES")
elif cache_state == "full":
_write(cache_extracted_dir / rel_path, to_bytes)
# "missing" leaves the cache dir empty
partials_dir = tmp_path / "partials"
partials_dir.mkdir()
manifest_file = tmp_path / "updatev3.manifest"
manifest_file.write_text("")
cache_entry = {
"from_mar_files": {rel_path: _sha256(local_from)},
"to_mar_files": {rel_path: _sha256(local_to)},
}
return (
cache_entry,
str(local_from),
str(local_to),
str(cache_extracted_dir),
str(partials_dir),
str(manifest_file),
)
def test_cache_lookup_patch_hit(tmp_path):
rel = "firefox.exe"
(
cache_entry,
local_from,
local_to,
cache_extracted_dir,
partials_dir,
manifest_file,
) = _make_cache_setup(tmp_path, rel, b"OLD", b"NEW", "patch")
result = mz._maybe_use_cached_file(
cache_entry,
rel,
cache_entry["from_mar_files"][rel],
cache_entry["to_mar_files"][rel],
cache_extracted_dir,
partials_dir,
manifest_file,
)
assert result == f"{rel}.patch"
assert (Path(partials_dir) / f"{rel}.patch").read_bytes() == b"PATCH-BYTES"
assert Path(manifest_file).read_text() == f'patch "{rel}.patch" "{rel}"\n'
def test_cache_lookup_full_hit(tmp_path):
rel = "libxul.so"
(
cache_entry,
local_from,
local_to,
cache_extracted_dir,
partials_dir,
manifest_file,
) = _make_cache_setup(tmp_path, rel, b"OLD", b"NEW", "full")
result = mz._maybe_use_cached_file(
cache_entry,
rel,
cache_entry["from_mar_files"][rel],
cache_entry["to_mar_files"][rel],
cache_extracted_dir,
partials_dir,
manifest_file,
)
assert result == rel
assert (Path(partials_dir) / rel).read_bytes() == b"NEW"
assert Path(manifest_file).read_text() == f'add "{rel}"\n'
def test_cache_lookup_from_hash_miss(tmp_path):
rel = "firefox.exe"
(
cache_entry,
local_from,
local_to,
cache_extracted_dir,
partials_dir,
manifest_file,
) = _make_cache_setup(tmp_path, rel, b"OLD", b"NEW", "patch")
result = mz._maybe_use_cached_file(
cache_entry,
rel,
"deadbeef" * 8,
cache_entry["to_mar_files"][rel],
cache_extracted_dir,
partials_dir,
manifest_file,
)
assert result is None
assert Path(manifest_file).read_text() == ""
assert not (Path(partials_dir) / f"{rel}.patch").exists()
def test_cache_lookup_to_hash_miss(tmp_path):
rel = "firefox.exe"
(
cache_entry,
local_from,
local_to,
cache_extracted_dir,
partials_dir,
manifest_file,
) = _make_cache_setup(tmp_path, rel, b"OLD", b"NEW", "patch")
result = mz._maybe_use_cached_file(
cache_entry,
rel,
cache_entry["from_mar_files"][rel],
"deadbeef" * 8,
cache_extracted_dir,
partials_dir,
manifest_file,
)
assert result is None
assert Path(manifest_file).read_text() == ""
def test_cache_lookup_relpath_absent_from_index(tmp_path):
rel = "firefox.exe"
(
cache_entry,
local_from,
local_to,
cache_extracted_dir,
partials_dir,
manifest_file,
) = _make_cache_setup(tmp_path, rel, b"OLD", b"NEW", "patch")
cache_entry["from_mar_files"].pop(rel)
cache_entry["to_mar_files"].pop(rel)
result = mz._maybe_use_cached_file(
cache_entry,
rel,
"deadbeef" * 8,
"deadbeef" * 8,
cache_extracted_dir,
partials_dir,
manifest_file,
)
assert result is None
def test_cache_lookup_hashes_match_but_file_missing(tmp_path):
rel = "firefox.exe"
(
cache_entry,
local_from,
local_to,
cache_extracted_dir,
partials_dir,
manifest_file,
) = _make_cache_setup(tmp_path, rel, b"OLD", b"NEW", "missing")
result = mz._maybe_use_cached_file(
cache_entry,
rel,
cache_entry["from_mar_files"][rel],
cache_entry["to_mar_files"][rel],
cache_extracted_dir,
partials_dir,
manifest_file,
)
assert result is None
assert Path(manifest_file).read_text() == ""
def test_cache_lookup_none_local_hash(tmp_path):
rel = "firefox.exe"
(
cache_entry,
local_from,
local_to,
cache_extracted_dir,
partials_dir,
manifest_file,
) = _make_cache_setup(tmp_path, rel, b"OLD", b"NEW", "patch")
result = mz._maybe_use_cached_file(
cache_entry,
rel,
None,
cache_entry["to_mar_files"][rel],
cache_extracted_dir,
partials_dir,
manifest_file,
)
assert result is None
if __name__ == "__main__":
main()