From ff759b50e5aadc3c973724021ec9fca3759f9639 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Wed, 15 Jun 2022 17:33:07 +0200 Subject: New upstream version 1.1~beta1 --- tests/test_server.py | 154 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 106 insertions(+), 48 deletions(-) (limited to 'tests/test_server.py') diff --git a/tests/test_server.py b/tests/test_server.py index 0820d5c..65ae8ce 100644 --- a/tests/test_server.py +++ b/tests/test_server.py @@ -31,6 +31,7 @@ import pytest import sys import shutil import json +import functools as ft from pathlib import Path from hashlib import sha256 @@ -42,9 +43,10 @@ from markupsafe import escape from werkzeug import Response from hydrilla import util as hydrilla_util -from hydrilla.builder import Build -from hydrilla.server import config, _version -from hydrilla.server.serve import HydrillaApp +from hydrilla.builder import build +from hydrilla.server import config, _version, serve + +from .helpers import * here = Path(__file__).resolve().parent config_path = here / 'config.json' @@ -55,13 +57,41 @@ expected_generated_by = { 'version': _version.version } -SetupMod = Optional[Callable['Setup', None]] +SetupMod = Optional[Callable[['Setup'], None]] source_files = ( 'index.json', 'hello.js', 'bye.js', 'message.js', 'README.txt', 'README.txt.license', '.reuse/dep5', 'LICENSES/CC0-1.0.txt' ) +def run_reuse(command, **kwargs): + """ + Instead of running a 'reuse' command, check if 'mock_reuse_missing' file + exists under root directory. If yes, raise FileNotFoundError as if 'reuse' + command was missing. If not, check if 'README.txt.license' file exists + in the requested directory and return zero if it does. + """ + expected = ['reuse', '--root', '', + 'lint' if 'lint' in command else 'spdx'] + + root_path = Path(process_command(command, expected)['root']) + + if (root_path / 'mock_reuse_missing').exists(): + raise FileNotFoundError('dummy') + + is_reuse_compliant = (root_path / 'README.txt.license').exists() + + return MockedCompletedProcess(command, 1 - is_reuse_compliant, + stdout=f'dummy {expected[-1]} output', + text_output=kwargs.get('text')) + +@pytest.fixture +def mock_reuse(mock_subprocess_run): + """ + Mock the REUSE command when executed through subprocess.run() from serve.py. + """ + mock_subprocess_run(build, run_reuse) + class Setup: """ Facilitate preparing test malcontent directory, Hydrilla config file and the @@ -95,8 +125,8 @@ class Setup: if self._modify_before_build: self._modify_before_build(self) - build = Build(self.source_dir, self.index_json) - build.write_package_files(self.malcontent_dir) + build_obj = build.Build(self.source_dir, self.index_json) + build_obj.write_package_files(self.malcontent_dir) if self._modify_after_build: self._modify_after_build(self) @@ -114,48 +144,64 @@ class Setup: Provide app client that serves the objects from built sample package. """ if self._client is None: - app = HydrillaApp(self.config(), flask_config={'TESTING': True}) + app = serve.HydrillaApp(self.config(), + flask_config={'TESTING': True}) self._client = app.test_client() return self._client -def remove_all_uuids(setup: Setup) -> None: - """Modify sample packages before build to contain no (optional) UUIDs""" - index_json = (setup.source_dir / 'index.json').read_text() - index_json = json.loads(hydrilla_util.strip_json_comments(index_json)) +def index_json_modification(modify_index_json): + """Decorator for function that modifies index.json before build.""" + def handle_index_json(setup): + """Modify index.json before build.""" + index_path = setup.source_dir / 'index.json' + index_json, _ = hydrilla_util.load_instance_from_file(index_path) + + index_json = modify_index_json(index_json) or index_json + + index_json = f''' + // SPDX-License-Identifier: CC0-1.0 + // Copyright (C) 2021, 2022 Wojtek Kosior + {json.dumps(index_json)} + ''' + + index_path.write_text(index_json) + return handle_index_json + +@index_json_modification +def remove_all_uuids(index_json): + """Modify sample packages to contain no (optional) UUIDs""" for definition in index_json['definitions']: del definition['uuid'] - index_json = ("// SPDX-License-Identifier: CC0-1.0\n" + - "// Copyright (C) 2021, 2022 Wojtek Kosior\n" + - json.dumps(index_json)) +@index_json_modification +def bump_schema_v2(index_json) -> None: + """Modify sample packages to use version 2 of Hydrilla JSON schemas.""" + for definition in index_json['definitions']: + definition['min_haketilo_version'] = [1, 1] - (setup.source_dir / 'index.json').write_text(index_json) + if definition['identifier'] == 'helloapple' and \ + definition['type'] == 'resource': + definition['required_mappings'] = {'identifier': 'helloapple'} -default_setup = Setup() -uuidless_setup = Setup(modify_before_build=remove_all_uuids) +default_setup = lambda: Setup() +uuidless_setup = lambda: Setup(modify_before_build=remove_all_uuids) +schema_v2_setup = lambda: Setup(modify_before_build=bump_schema_v2) -def def_get(url: str) -> Response: - """Convenience wrapper for def_get()""" - return default_setup.client().get(url) +setup_makers = [default_setup, uuidless_setup, schema_v2_setup] -def test_project_url() -> None: - """Fetch index.html and verify project URL from config is present there.""" - response = def_get('/') - assert b'html' in response.data - project_url = default_setup.config()['hydrilla_project_url'] - assert escape(project_url).encode() in response.data - -@pytest.mark.parametrize('setup', [default_setup, uuidless_setup]) +@pytest.mark.usefixtures('mock_reuse') +@pytest.mark.parametrize('setup_maker', setup_makers) @pytest.mark.parametrize('item_type', ['resource', 'mapping']) -def test_get_newest(setup: Setup, item_type: str) -> None: +def test_get_newest(setup_maker, item_type: str) -> None: """ Verify that GET '/{item_type}/{item_identifier}.json' returns proper definition that is also served at: GET '/{item_type}/{item_identifier}/{item_version}' """ + setup = setup_maker() response = setup.client().get(f'/{item_type}/helloapple.json') assert response.status_code == 200 definition = json.loads(response.data.decode()) @@ -166,46 +212,58 @@ def test_get_newest(setup: Setup, item_type: str) -> None: assert response.status_code == 200 assert definition == json.loads(response.data.decode()) - assert ('uuid' in definition) == (setup is not uuidless_setup) + assert ('uuid' in definition) == (setup_maker is not uuidless_setup) hydrilla_util.validator_for(f'api_{item_type}_description-1.0.1.schema.json')\ .validate(definition) +@pytest.fixture +def setup(mock_reuse): + """Prepare server test environment in the default way.""" + return default_setup() + +def test_project_url(setup) -> None: + """Fetch index.html and verify project URL from config is present there.""" + response = setup.client().get('/') + assert b'html' in response.data + project_url = setup.config()['hydrilla_project_url'] + assert escape(project_url).encode() in response.data + @pytest.mark.parametrize('item_type', ['resource', 'mapping']) -def test_get_nonexistent(item_type: str) -> None: +def test_get_nonexistent(setup, item_type: str) -> None: """ Verify that attempts to GET a JSON definition of a nonexistent item or item version result in 404. """ - response = def_get(f'/{item_type}/nonexistentapple.json') + response = setup.client().get(f'/{item_type}/nonexistentapple.json') assert response.status_code == 404 - response = def_get(f'/{item_type}/helloapple/1.2.3.999') + response = setup.client().get(f'/{item_type}/helloapple/1.2.3.999') assert response.status_code == 404 @pytest.mark.parametrize('item_type', ['resource', 'mapping']) -def test_file_refs(item_type: str) -> None: +def test_file_refs(setup, item_type: str) -> None: """ Verify that files referenced by definitions are accessible under their proper URLs and that their hashes match. """ - response = def_get(f'/{item_type}/helloapple/2021.11.10') + response = setup.client().get(f'/{item_type}/helloapple/2021.11.10') assert response.status_code == 200 definition = json.loads(response.data.decode()) for file_ref in [*definition.get('scripts', []), *definition['source_copyright']]: hash_sum = file_ref["sha256"] - response = def_get(f'/file/sha256/{hash_sum}') + response = setup.client().get(f'/file/sha256/{hash_sum}') assert response.status_code == 200 assert sha256(response.data).digest().hex() == hash_sum -def test_empty_query() -> None: +def test_empty_query(setup) -> None: """ Verify that querying mappings for URL gives an empty list when there're no mathes. """ - response = def_get(f'/query?url=https://nonexiste.nt/example') + response = setup.client().get(f'/query?url=https://nonexiste.nt/example') assert response.status_code == 200 response_object = json.loads(response.data.decode()) @@ -219,12 +277,12 @@ def test_empty_query() -> None: hydrilla_util.validator_for('api_query_result-1.0.1.schema.json')\ .validate(response_object) -def test_query() -> None: +def test_query(setup) -> None: """ Verify that querying mappings for URL gives a list with reference(s) the the matching mapping(s). """ - response = def_get(f'/query?url=https://hydrillabugs.koszko.org/') + response = setup.client().get(f'/query?url=https://hydrillabugs.koszko.org/') assert response.status_code == 200 response_object = json.loads(response.data.decode()) @@ -239,12 +297,12 @@ def test_query() -> None: 'generated_by': expected_generated_by } - hydrilla_util.validator_for('api_query_result-1.0.1.schema.json')\ + hydrilla_util.validator_for('api_query_result-1.schema.json')\ .validate(response_object) -def test_source() -> None: +def test_source(setup) -> None: """Verify source descriptions are properly served.""" - response = def_get(f'/source/hello.json') + response = setup.client().get(f'/source/hello.json') assert response.status_code == 200 description = json.loads(response.data.decode()) @@ -254,18 +312,18 @@ def test_source() -> None: ['hello-message', 'helloapple', 'helloapple'] zipfile_hash = description['source_archives']['zip']['sha256'] - response = def_get(f'/source/hello.zip') + response = setup.client().get(f'/source/hello.zip') assert sha256(response.data).digest().hex() == zipfile_hash - hydrilla_util.validator_for('api_source_description-1.0.1.schema.json')\ + hydrilla_util.validator_for('api_source_description-1.schema.json')\ .validate(description) -def test_missing_source() -> None: +def test_missing_source(setup) -> None: """Verify requests for nonexistent sources result in 404.""" - response = def_get(f'/source/nonexistent.json') + response = setup.client().get(f'/source/nonexistent.json') assert response.status_code == 404 - response = def_get(f'/source/nonexistent.zip') + response = setup.client().get(f'/source/nonexistent.zip') assert response.status_code == 404 def test_normalize_version(): -- cgit v1.2.3