# 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
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import hashlib
from unittest import mock
import mozunit
import pytest
from mozrelease import generate_checksums
from mozrelease.checksums import parse_checksums_file
PREFIX = "pub/firefox/candidates/1.0-candidates/build1/"
LISTING_PAGE_1 = f"""
bucket{PREFIX}true
{PREFIX}a.beet
{PREFIX}a.beet
{PREFIX}a.tar.xz
"""
LISTING_PAGE_2 = f"""
bucket{PREFIX}false
{PREFIX}b.beet
{PREFIX}old.checksums
"""
def _sums(data):
return {
"sha256": hashlib.sha256(data).hexdigest().encode("ascii"),
"sha512": hashlib.sha512(data).hexdigest().encode("ascii"),
}
def _beet(entries):
lines = []
for name, data in entries.items():
sums = _sums(data)
for fmt in ("sha256", "sha512"):
lines.append(f"{sums[fmt].decode()} {fmt} {len(data)} {name}")
return ("\n".join(lines) + "\n").encode("utf-8")
BEETS = {
f"{PREFIX}a.beet": _beet({
"linux-x86_64/en-US/firefox-1.0.tar.xz": b"linux",
"linux-x86_64/en-US/firefox-1.0.txt": b"ignored",
}),
f"{PREFIX}b.beet": _beet({
"win64/en-US/Firefox Setup 1.0.exe": b"win",
"linux-x86_64/en-US/firefox-1.0.tar.xz": b"linux",
}),
}
class FakeResponse:
def __init__(self, content):
self.content = content
def raise_for_status(self):
pass
class FakeSession:
def __init__(self):
self.requests = []
def get(self, url, params=None, timeout=None):
self.requests.append((url, params))
if url == f"{generate_checksums.STORAGE_URL}/bucket":
if params.get("marker"):
return FakeResponse(LISTING_PAGE_2.encode("utf-8"))
return FakeResponse(LISTING_PAGE_1.encode("utf-8"))
key = url[len(f"{generate_checksums.STORAGE_URL}/bucket/") :]
return FakeResponse(BEETS[key])
def test_list_keys_follows_markers():
session = FakeSession()
keys = list(generate_checksums.list_keys(session, "bucket", PREFIX))
assert keys == [
f"{PREFIX}a.beet",
f"{PREFIX}a.tar.xz",
f"{PREFIX}b.beet",
f"{PREFIX}old.checksums",
]
assert session.requests[1][1]["marker"] == f"{PREFIX}a.beet"
def test_find_checksums_files_prefers_beets():
keys = generate_checksums.find_checksums_files(FakeSession(), "bucket", PREFIX)
assert keys == [f"{PREFIX}a.beet", f"{PREFIX}b.beet"]
def test_collect_individual_checksums_filters_and_dedupes():
checksums = generate_checksums.collect_individual_checksums(
FakeSession(), "bucket", PREFIX, 2
)
assert sorted(checksums) == [
"linux-x86_64/en-US/firefox-1.0.tar.xz",
"win64/en-US/Firefox Setup 1.0.exe",
]
assert checksums["linux-x86_64/en-US/firefox-1.0.tar.xz"]["hashes"] == _sums(
b"linux"
)
def test_collect_individual_checksums_rejects_conflicts():
beets = dict(BEETS)
beets[f"{PREFIX}b.beet"] = _beet({
"linux-x86_64/en-US/firefox-1.0.tar.xz": b"different",
})
with mock.patch.dict(BEETS, beets), pytest.raises(SystemExit):
generate_checksums.collect_individual_checksums(
FakeSession(), "bucket", PREFIX, 2
)
def test_outputs():
checksums = parse_checksums_file(
_beet({
"b/firefox-1.0.tar.xz": b"two",
"a/firefox-1.0.tar.xz": b"one",
})
)
sums = generate_checksums.create_big_checksums(checksums, "sha256")
assert sums == (
f"{hashlib.sha256(b'one').hexdigest()} a/firefox-1.0.tar.xz\n"
f"{hashlib.sha256(b'two').hexdigest()} b/firefox-1.0.tar.xz\n"
)
summary = generate_checksums.create_summary(checksums, "sha256")
lines = summary.splitlines()
assert lines[0].endswith(" TREE_HEAD")
assert lines[1].endswith(" a/firefox-1.0.tar.xz")
assert lines[2].endswith(" b/firefox-1.0.tar.xz")
def test_file_prefix():
assert (
generate_checksums.get_file_prefix("firefox", "59.0b5", "2")
== "pub/firefox/candidates/59.0b5-candidates/build2/"
)
if __name__ == "__main__":
mozunit.main()