# SPDX-License-Identifier: CC0-1.0 # Copyright (C) 2022 Wojtek Kosior # # Available under the terms of Creative Commons Zero v1.0 Universal. import pytest import json from tempfile import TemporaryDirectory from pathlib import Path from hashlib import sha256, sha1 from zipfile import ZipFile here = Path(__file__).resolve().parent @pytest.fixture() def tmpdir(): with TemporaryDirectory() as tmpdir: yield tmpdir def test_build(tmpdir): """Build the sample source package and verify the produced files.""" from hydrilla_builder.build import Build # First, build the package srcdir = here / 'source-package-example' dstdir = Path(tmpdir) build = Build(srcdir, Path('index.json')) build.write_package_files(dstdir) # Verify directories under destination directory assert {'file', 'resource', 'mapping', 'source'} == \ set([path.name for path in dstdir.iterdir()]) # Verify files under 'file/' file_dir = dstdir / 'file' js_filenames = ('bye.js', 'hello.js', 'message.js') dist_filenames = (*js_filenames, str(Path('LICENSES') / 'CC0-1.0.txt')) file_contents = {} file_sha256_hashes = {} file_sha1_hashes = {} for fn in dist_filenames: with open(srcdir / fn, 'rb') as file_handle: file_contents = file_handle.read() file_sha256_hashes[fn] = sha256(file_contents).digest().hex() file_sha1_hashes[fn] = sha1(file_contents).digest().hex() dist_file_path = file_dir / f'sha256-{file_sha256_hashes[fn]}' assert dist_file_path.is_file() with open(dist_file_path, 'rb') as file_handle: assert file_handle.read() == file_contents sha256_hashes = set(file_sha256_hashes.values()) spdx_report_sha256 = None spdx_report_checked = False for path in file_dir.iterdir(): assert path.name.startswith('sha256-') if path.name[7:] in sha256_hashes: continue assert spdx_report_sha256 is None with open(path, 'rt') as file_handle: spdx_contents = file_handle.read() spdx_report_sha256 = sha256(spdx_contents.encode()).digest().hex() assert spdx_report_sha256 == path.name[7:] for fn in js_filenames: assert file_sha1_hashes[fn] in spdx_contents # Verify files under 'resource/' resource_dir = dstdir / 'resource' expected_resource_jsons = [{ 'api_schema_version': [1, 0, 1], 'source_name': 'hello', 'source_copyright': [{ 'file': 'report.spdx', 'sha256': spdx_report_sha256 }, { 'file': 'LICENSES/CC0-1.0.txt', 'sha256': file_sha256_hashes['LICENSES/CC0-1.0.txt'] }], 'type': 'resource', 'identifier': 'helloapple', 'long_name': 'Hello Apple', 'uuid': 'a6754dcb-58d8-4b7a-a245-24fd7ad4cd68', 'version': [2021, 11, 10], 'revision': 1, 'description': 'greets an apple', 'dependencies': ['hello-message'], 'scripts': [{ 'file': 'hello.js', 'sha256': file_sha256_hashes['hello.js'] }, { 'file': 'bye.js', 'sha256': file_sha256_hashes['bye.js'] }] }, { 'api_schema_version': [1, 0, 1], 'source_name': 'hello', 'source_copyright': [{ 'file': 'report.spdx', 'sha256': spdx_report_sha256 }, { 'file': 'LICENSES/CC0-1.0.txt', 'sha256': file_sha256_hashes['LICENSES/CC0-1.0.txt'] }], 'type': 'resource', 'identifier': 'hello-message', 'long_name': 'Hello Message', 'uuid': '1ec36229-298c-4b35-8105-c4f2e1b9811e', 'version': [2021, 11, 10], 'revision': 2, 'description': 'define messages for saying hello and bye', 'dependencies': [], 'scripts': [{ 'file': 'message.js', 'sha256': file_sha256_hashes['message.js'] }] }] assert set([rj['identifier'] for rj in expected_resource_jsons]) == \ set([path.name for path in resource_dir.iterdir()]) for resource_json in expected_resource_jsons: subdir = resource_dir / resource_json['identifier'] assert ['2021.11.10'] == [path.name for path in subdir.iterdir()] with open(subdir / '2021.11.10', 'rt') as file_handle: assert json.load(file_handle) == resource_json # Verify files under 'mapping/' mapping_dir = dstdir / 'mapping' assert ['helloapple'] == [path.name for path in mapping_dir.iterdir()] subdir = mapping_dir / 'helloapple' assert ['2021.11.10'] == [path.name for path in subdir.iterdir()] expected_mapping_json = { 'api_schema_version': [1, 0, 1], 'source_name': 'hello', 'source_copyright': [{ 'file': 'report.spdx', 'sha256': spdx_report_sha256 }, { 'file': 'LICENSES/CC0-1.0.txt', 'sha256': file_sha256_hashes['LICENSES/CC0-1.0.txt'] }], 'type': 'mapping', 'identifier': 'helloapple', 'long_name': 'Hello Apple', 'uuid': '54d23bba-472e-42f5-9194-eaa24c0e3ee7', 'version': [2021, 11, 10], 'description': 'causes apple to get greeted on Hydrillabugs issue tracker', 'payloads': { 'https://hydrillabugs.koszko.org/***': { 'identifier': 'helloapple' }, 'https://hachettebugs.koszko.org/***': { 'identifier': 'helloapple' } } } with open(subdir / '2021.11.10', 'rt') as file_handle: assert json.load(file_handle) == expected_mapping_json # Verify files under 'source/' source_dir = dstdir / 'source' assert {'hello.json', 'hello.zip'} == \ set([path.name for path in source_dir.iterdir()]) src_filenames = ( *dist_filenames, 'README.txt', 'README.txt.license', '.reuse/dep5', 'index.json' ) zip_filenames = [f'hello/{fn}' for fn in src_filenames] with ZipFile(source_dir / 'hello.zip', 'r') as archive: assert set([f.filename for f in archive.filelist]) == set(zip_filenames) for zip_fn, src_fn in zip(zip_filenames, src_filenames): src_path = srcdir for segment in src_fn.split('/'): src_path = src_path / segment with archive.open(zip_fn, 'r') as zip_file_handle: with open(src_path, 'rb') as disk_file_handle: assert zip_file_handle.read() == disk_file_handle.read() with open(source_dir / 'hello.zip', 'rb') as file_handle: zipfile_sha256_hash = sha256(file_handle.read()).digest().hex() expected_source_description = { 'api_schema_version': [1, 0, 1], 'source_name': 'hello', 'source_copyright': [{ 'file': 'report.spdx', 'sha256': spdx_report_sha256 }, { 'file': 'LICENSES/CC0-1.0.txt', 'sha256': file_sha256_hashes['LICENSES/CC0-1.0.txt'] }], 'source_archives': { 'zip': { 'sha256': zipfile_sha256_hash, } }, 'upstream_url': 'https://git.koszko.org/hydrilla-source-package-example', 'definitions': [{ 'type': 'resource', 'identifier': 'helloapple', 'version': [2021, 11, 10], }, { 'type': 'resource', 'identifier': 'hello-message', 'version': [2021, 11, 10], }, { 'type': 'mapping', 'identifier': 'helloapple', 'version': [2021, 11, 10], }] } with open(source_dir / 'hello.json', 'rt') as file_handle: assert json.load(file_handle) == expected_source_description # TODO: also verify on slightly different examples and check error handling