diff --git a/docs/CONTRIBUTORS.rst b/docs/CONTRIBUTORS.rst index 54ef8a8d40..2ab205b2cc 100644 --- a/docs/CONTRIBUTORS.rst +++ b/docs/CONTRIBUTORS.rst @@ -139,9 +139,9 @@ Individual tests can also be executed. Optional '-v' flags can be added to increase log level up to DEBUG ('-vvvv'). :: - $ python3 test_updater.py # run a specific test file - $ python3 test_updater.py TestUpdater.test_4_refresh # run a specific test - $ python3 test_updater.py -vvvv TestUpdater.test_4_refresh # run test with DEBUG log level + $ python3 test_updater_ng.py # run a specific test file + $ python3 test_updater_ng.py TestUpdater.test_refresh_and_download # run a specific test + $ python3 test_updater_ng.py -vvvv TestUpdater.test_refresh_and_download # run test with DEBUG log level All of the log levels and the corresponding options that could be used for testing are: diff --git a/pyproject.toml b/pyproject.toml index e80efb4cf0..16d7675fc7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,6 +7,8 @@ build-backend = "setuptools.build_meta" # Read more here: https://black.readthedocs.io/en/stable/usage_and_configuration/the_basics.html#configuration-via-a-file [tool.black] line-length=80 +# TODO: remove "excludes" after deleting old test files +exclude="tests/.*old.py" # Isort section # Read more here: https://pycqa.github.io/isort/docs/configuration/config_files.html @@ -14,6 +16,8 @@ line-length=80 profile="black" line_length=80 known_first_party = ["tuf"] +# TODO: remove "skip_glob" after deleting old test files +skip_glob="*old.py" # Pylint section @@ -55,6 +59,8 @@ module-rgx="^(_?[a-z][a-z0-9_]*|__init__)$" no-docstring-rgx="(__.*__|main|test.*|.*test|.*Test)$" variable-rgx="^[a-z][a-z0-9_]*$" docstring-min-length=10 +# TODO: remove "ignore-patterns" after deleting old test files +ignore-patterns=".*_old.py" [tool.pylint.logging] logging-format-style="old" @@ -76,6 +82,9 @@ strict_equality = "True" disallow_untyped_defs = "True" disallow_untyped_calls = "True" show_error_codes = "True" +disable_error_code = ["attr-defined"] +# TODO: remove "exclude" after deleting old test files +exclude=".*_old.py" [[tool.mypy.overrides]] module = [ diff --git a/requirements-test.txt b/requirements-test.txt index fed1a6de24..10675fd8fe 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -14,3 +14,4 @@ pylint mypy bandit types-requests +types-python-dateutil diff --git a/tests/fast_server_exit.py b/tests/fast_server_exit_old.py similarity index 100% rename from tests/fast_server_exit.py rename to tests/fast_server_exit_old.py diff --git a/tests/repository_data/generate.py b/tests/repository_data/generate_old.py similarity index 100% rename from tests/repository_data/generate.py rename to tests/repository_data/generate_old.py diff --git a/tests/repository_data/generate_project_data.py b/tests/repository_data/generate_project_data_old.py similarity index 97% rename from tests/repository_data/generate_project_data.py rename to tests/repository_data/generate_project_data_old.py index fc93fd594e..db3d00dfdb 100755 --- a/tests/repository_data/generate_project_data.py +++ b/tests/repository_data/generate_project_data_old.py @@ -17,8 +17,8 @@ See LICENSE-MIT.txt OR LICENSE-APACHE.txt for licensing information. - Generate a pre-fabricated set of metadata files for 'test_developer_tool.py' - test cases. + Generate a pre-fabricated set of metadata files for + 'test_developer_tool_old.py' test cases. """ import shutil diff --git a/tests/repository_simulator.py b/tests/repository_simulator.py index 4e530cd32e..6377fe0a2b 100644 --- a/tests/repository_simulator.py +++ b/tests/repository_simulator.py @@ -216,7 +216,7 @@ def fetch(self, url: str) -> Iterator[bytes]: role = ver_and_name version = None - yield self._fetch_metadata(role, version) + yield self.fetch_metadata(role, version) elif path.startswith("/targets/"): # figure out target path and hash prefix target_path = path[len("/targets/") :] @@ -228,11 +228,11 @@ def fetch(self, url: str) -> Iterator[bytes]: prefix, _, filename = prefixed_filename.partition(".") target_path = f"{dir_parts}{sep}{filename}" - yield self._fetch_target(target_path, prefix) + yield self.fetch_target(target_path, prefix) else: raise FetcherHTTPError(f"Unknown path '{path}'", 404) - def _fetch_target( + def fetch_target( self, target_path: str, target_hash: Optional[str] ) -> bytes: """Return data for 'target_path', checking 'target_hash' if it is given. @@ -253,9 +253,7 @@ def _fetch_target( logger.debug("fetched target %s", target_path) return repo_target.data - def _fetch_metadata( - self, role: str, version: Optional[int] = None - ) -> bytes: + def fetch_metadata(self, role: str, version: Optional[int] = None) -> bytes: """Return signed metadata for 'role', using 'version' if it is given. If version is None, non-versioned metadata is being requested. @@ -298,7 +296,7 @@ def _fetch_metadata( def _compute_hashes_and_length( self, role: str ) -> Tuple[Dict[str, str], int]: - data = self._fetch_metadata(role) + data = self.fetch_metadata(role) digest_object = sslib_hash.digest(sslib_hash.DEFAULT_HASH_ALGORITHM) digest_object.update(data) hashes = {sslib_hash.DEFAULT_HASH_ALGORITHM: digest_object.hexdigest()} @@ -392,12 +390,12 @@ def write(self) -> None: for ver in range(1, len(self.signed_roots) + 1): with open(os.path.join(dest_dir, f"{ver}.root.json"), "wb") as f: - f.write(self._fetch_metadata(Root.type, ver)) + f.write(self.fetch_metadata(Root.type, ver)) for role in [Timestamp.type, Snapshot.type, Targets.type]: with open(os.path.join(dest_dir, f"{role}.json"), "wb") as f: - f.write(self._fetch_metadata(role)) + f.write(self.fetch_metadata(role)) for role in self.md_delegates: with open(os.path.join(dest_dir, f"{role}.json"), "wb") as f: - f.write(self._fetch_metadata(role)) + f.write(self.fetch_metadata(role)) diff --git a/tests/simple_https_server.py b/tests/simple_https_server_old.py similarity index 93% rename from tests/simple_https_server.py rename to tests/simple_https_server_old.py index 68d0512f93..bf29d0dac6 100755 --- a/tests/simple_https_server.py +++ b/tests/simple_https_server_old.py @@ -5,7 +5,7 @@ """ - simple_https_server.py + simple_https_server_old.py Vladimir Diaz. @@ -53,7 +53,7 @@ print(port_message) if len(sys.argv) > 1 and certfile != sys.argv[1]: - print('simple_https_server: cert file was not found: ' + sys.argv[1] + + print('simple_https_server_old: cert file was not found: ' + sys.argv[1] + '; using default: ' + certfile + " certfile") httpd.serve_forever() diff --git a/tests/slow_retrieval_server.py b/tests/slow_retrieval_server_old.py similarity index 96% rename from tests/slow_retrieval_server.py rename to tests/slow_retrieval_server_old.py index bac904f26a..c2586f2ef4 100755 --- a/tests/slow_retrieval_server.py +++ b/tests/slow_retrieval_server_old.py @@ -5,7 +5,7 @@ """ - slow_retrieval_server.py + slow_retrieval_server_old.py Konstantin Andrianov. @@ -18,7 +18,7 @@ Server that throttles data by sending one byte at a time (specified time - interval 'DELAY'). The server is used in 'test_slow_retrieval_attack.py'. + interval 'DELAY'). The server is used in 'test_slow_retrieval_attack_old.py'. """ import os diff --git a/tests/test_api.py b/tests/test_api.py index 8bd69c9b32..01b9d6526b 100755 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -28,6 +28,7 @@ from tests import utils from tuf import exceptions from tuf.api.metadata import ( + TOP_LEVEL_ROLE_NAMES, DelegatedRole, Delegations, Key, @@ -136,7 +137,7 @@ def test_compact_json(self) -> None: ) def test_read_write_read_compare(self) -> None: - for metadata in [Root.type, Snapshot.type, Timestamp.type, Targets.type]: + for metadata in TOP_LEVEL_ROLE_NAMES: path = os.path.join(self.repo_dir, "metadata", metadata + ".json") md_obj = Metadata.from_file(path) @@ -148,7 +149,7 @@ def test_read_write_read_compare(self) -> None: os.remove(path_2) def test_to_from_bytes(self) -> None: - for metadata in [Root.type, Snapshot.type, Timestamp.type, Targets.type]: + for metadata in TOP_LEVEL_ROLE_NAMES: path = os.path.join(self.repo_dir, "metadata", metadata + ".json") with open(path, "rb") as f: metadata_bytes = f.read() @@ -710,7 +711,9 @@ def test_targetfile_from_file(self) -> None: def test_targetfile_from_data(self) -> None: data = b"Inline test content" - target_file_path = os.path.join(self.repo_dir, Targets.type, "file1.txt") + target_file_path = os.path.join( + self.repo_dir, Targets.type, "file1.txt" + ) # Test with a valid hash algorithm targetfile_from_data = TargetFile.from_data( diff --git a/tests/test_arbitrary_package_attack.py b/tests/test_arbitrary_package_attack_old.py similarity index 99% rename from tests/test_arbitrary_package_attack.py rename to tests/test_arbitrary_package_attack_old.py index 02b4c24900..0791751220 100755 --- a/tests/test_arbitrary_package_attack.py +++ b/tests/test_arbitrary_package_attack_old.py @@ -5,7 +5,7 @@ """ - test_arbitrary_package_attack.py + test_arbitrary_package_attack_old.py Konstantin Andrianov. diff --git a/tests/test_developer_tool.py b/tests/test_developer_tool_old.py similarity index 99% rename from tests/test_developer_tool.py rename to tests/test_developer_tool_old.py index d066964437..bec0d62e8f 100755 --- a/tests/test_developer_tool.py +++ b/tests/test_developer_tool_old.py @@ -5,7 +5,7 @@ """ - test_developer_tool.py. + test_developer_tool_old.py. Santiago Torres Arias diff --git a/tests/test_download.py b/tests/test_download_old.py similarity index 98% rename from tests/test_download.py rename to tests/test_download_old.py index 3b4572ccb0..4af22738de 100755 --- a/tests/test_download.py +++ b/tests/test_download_old.py @@ -5,7 +5,7 @@ """ - test_download.py + test_download_old.py Konstantin Andrianov. @@ -19,7 +19,7 @@ Unit test for 'download.py'. - NOTE: Make sure test_download.py is ran in 'tuf/tests/' directory. + NOTE: Make sure test_download_old.py is ran in 'tuf/tests/' directory. Otherwise, module that launches simple server would not be found. TODO: Adopt the environment variable management from test_proxy_use.py here. @@ -274,16 +274,16 @@ def test_https_connection(self): good_https_server_handler = utils.TestServerProcess(log=logger, - server='simple_https_server.py', + server='simple_https_server_old.py', extra_cmd_args=[good_cert_fname]) good2_https_server_handler = utils.TestServerProcess(log=logger, - server='simple_https_server.py', + server='simple_https_server_old.py', extra_cmd_args=[good2_cert_fname]) bad_https_server_handler = utils.TestServerProcess(log=logger, - server='simple_https_server.py', + server='simple_https_server_old.py', extra_cmd_args=[bad_cert_fname]) expd_https_server_handler = utils.TestServerProcess(log=logger, - server='simple_https_server.py', + server='simple_https_server_old.py', extra_cmd_args=[expired_cert_fname]) suffix = '/' + os.path.basename(target_filepath) diff --git a/tests/test_endless_data_attack.py b/tests/test_endless_data_attack_old.py similarity index 99% rename from tests/test_endless_data_attack.py rename to tests/test_endless_data_attack_old.py index 251379bbee..aafed1a26c 100755 --- a/tests/test_endless_data_attack.py +++ b/tests/test_endless_data_attack_old.py @@ -5,7 +5,7 @@ """ - test_endless_data_attack.py + test_endless_data_attack_old.py Konstantin Andrianov. diff --git a/tests/test_examples.py b/tests/test_examples.py index 2d3c480462..8b1184fb12 100644 --- a/tests/test_examples.py +++ b/tests/test_examples.py @@ -7,9 +7,13 @@ import glob import os import shutil +import sys import tempfile import unittest from pathlib import Path +from typing import ClassVar, List + +from tests import utils class TestRepoExamples(unittest.TestCase): @@ -20,26 +24,30 @@ class TestRepoExamples(unittest.TestCase): """ + repo_examples_dir: ClassVar[Path] + @classmethod - def setUpClass(cls): + def setUpClass(cls) -> None: """Locate and cache 'repo_example' dir.""" base = Path(__file__).resolve().parents[1] cls.repo_examples_dir = base / "examples" / "repo_example" - def setUp(self): + def setUp(self) -> None: """Create and change into test dir. NOTE: Test scripts are expected to create dirs/files in new CWD.""" self.original_cwd = os.getcwd() self.base_test_dir = os.path.realpath(tempfile.mkdtemp()) os.chdir(self.base_test_dir) - def tearDown(self): + def tearDown(self) -> None: """Change back to original dir and remove test dir, which may contain dirs/files the test created at test-time CWD.""" os.chdir(self.original_cwd) shutil.rmtree(self.base_test_dir) - def _run_script_and_assert_files(self, script_name, filenames_created): + def _run_script_and_assert_files( + self, script_name: str, filenames_created: List[str] + ) -> None: """Run script in 'repo_example' dir and assert that it created the files corresponding to the passed filenames inside a 'tmp*' test dir at CWD.""" @@ -63,7 +71,7 @@ def _run_script_and_assert_files(self, script_name, filenames_created): metadata_path.exists(), f"missing '{metadata_path}' file" ) - def test_basic_repo(self): + def test_basic_repo(self) -> None: """Run 'basic_repo.py' and assert creation of metadata files.""" self._run_script_and_assert_files( "basic_repo.py", @@ -81,4 +89,5 @@ def test_basic_repo(self): if __name__ == "__main__": + utils.configure_test_logging(sys.argv) unittest.main() diff --git a/tests/test_extraneous_dependencies_attack.py b/tests/test_extraneous_dependencies_attack_old.py similarity index 99% rename from tests/test_extraneous_dependencies_attack.py rename to tests/test_extraneous_dependencies_attack_old.py index 7e2bff7386..f086e7e86f 100755 --- a/tests/test_extraneous_dependencies_attack.py +++ b/tests/test_extraneous_dependencies_attack_old.py @@ -5,7 +5,7 @@ """ - test_extraneous_dependencies_attack.py + test_extraneous_dependencies_attack_old.py Zane Fisher. diff --git a/tests/test_fetcher.py b/tests/test_fetcher_old.py similarity index 100% rename from tests/test_fetcher.py rename to tests/test_fetcher_old.py diff --git a/tests/test_formats.py b/tests/test_formats_old.py similarity index 99% rename from tests/test_formats.py rename to tests/test_formats_old.py index 96da912b12..498be2d107 100755 --- a/tests/test_formats.py +++ b/tests/test_formats_old.py @@ -5,7 +5,7 @@ """ - test_formats.py + test_formats_old.py Vladimir Diaz diff --git a/tests/test_indefinite_freeze_attack.py b/tests/test_indefinite_freeze_attack_old.py similarity index 99% rename from tests/test_indefinite_freeze_attack.py rename to tests/test_indefinite_freeze_attack_old.py index b8693dd0db..69d063a60d 100755 --- a/tests/test_indefinite_freeze_attack.py +++ b/tests/test_indefinite_freeze_attack_old.py @@ -5,7 +5,7 @@ """ - test_indefinite_freeze_attack.py + test_indefinite_freeze_attack_old.py Konstantin Andrianov. @@ -36,7 +36,6 @@ metadata without the client being aware. """ -import datetime import os import time import tempfile diff --git a/tests/test_key_revocation_integration.py b/tests/test_key_revocation_integration_old.py similarity index 99% rename from tests/test_key_revocation_integration.py rename to tests/test_key_revocation_integration_old.py index 4c00713445..8cb77f127f 100755 --- a/tests/test_key_revocation_integration.py +++ b/tests/test_key_revocation_integration_old.py @@ -5,7 +5,7 @@ """ - test_key_revocation_integration.py + test_key_revocation_integration_old.py Vladimir Diaz. @@ -18,7 +18,7 @@ Integration test that verifies top-level roles are updated after all of their - keys have been revoked. There are unit tests in 'test_repository_tool.py' + keys have been revoked. There are unit tests in 'test_repository_tool_old.py' that verify key and role revocation of specific roles, but these should be expanded to verify key revocations over the span of multiple snapshots of the repository. diff --git a/tests/test_keydb.py b/tests/test_keydb_old.py similarity index 99% rename from tests/test_keydb.py rename to tests/test_keydb_old.py index b075dd4acb..b76b5c0f39 100755 --- a/tests/test_keydb.py +++ b/tests/test_keydb_old.py @@ -5,7 +5,7 @@ """ - test_keydb.py + test_keydb_old.py Vladimir Diaz diff --git a/tests/test_log.py b/tests/test_log_old.py similarity index 99% rename from tests/test_log.py rename to tests/test_log_old.py index 82637f50f5..a92661b305 100755 --- a/tests/test_log.py +++ b/tests/test_log_old.py @@ -5,7 +5,7 @@ """ - test_log.py + test_log_old.py Vladimir Diaz diff --git a/tests/test_mirrors.py b/tests/test_mirrors_old.py similarity index 99% rename from tests/test_mirrors.py rename to tests/test_mirrors_old.py index ed87ff18e6..0d530154c6 100755 --- a/tests/test_mirrors.py +++ b/tests/test_mirrors_old.py @@ -5,7 +5,7 @@ """ - test_mirrors.py + test_mirrors_old.py Konstantin Andrianov. diff --git a/tests/test_mix_and_match_attack.py b/tests/test_mix_and_match_attack_old.py similarity index 99% rename from tests/test_mix_and_match_attack.py rename to tests/test_mix_and_match_attack_old.py index 2d9d672abe..cc033c291e 100755 --- a/tests/test_mix_and_match_attack.py +++ b/tests/test_mix_and_match_attack_old.py @@ -5,7 +5,7 @@ """ - test_mix_and_match_attack.py + test_mix_and_match_attack_old.py Konstantin Andrianov. diff --git a/tests/test_multiple_repositories_integration.py b/tests/test_multiple_repositories_integration_old.py similarity index 99% rename from tests/test_multiple_repositories_integration.py rename to tests/test_multiple_repositories_integration_old.py index 0339a0d2d0..6387764894 100755 --- a/tests/test_multiple_repositories_integration.py +++ b/tests/test_multiple_repositories_integration_old.py @@ -5,7 +5,7 @@ """ - test_multiple_repositories_integration.py + test_multiple_repositories_integration_old.py Vladimir Diaz diff --git a/tests/test_replay_attack.py b/tests/test_replay_attack_old.py similarity index 99% rename from tests/test_replay_attack.py rename to tests/test_replay_attack_old.py index 05cf572c7c..92dc3ba466 100755 --- a/tests/test_replay_attack.py +++ b/tests/test_replay_attack_old.py @@ -5,7 +5,7 @@ """ - test_replay_attack.py + test_replay_attack_old.py Konstantin Andrianov. diff --git a/tests/test_repository_lib.py b/tests/test_repository_lib_old.py similarity index 99% rename from tests/test_repository_lib.py rename to tests/test_repository_lib_old.py index 96dcb0e0e0..aa784a2e37 100755 --- a/tests/test_repository_lib.py +++ b/tests/test_repository_lib_old.py @@ -5,7 +5,7 @@ """ - test_repository_lib.py + test_repository_lib_old.py Vladimir Diaz diff --git a/tests/test_repository_tool.py b/tests/test_repository_tool_old.py similarity index 99% rename from tests/test_repository_tool.py rename to tests/test_repository_tool_old.py index be0333c351..8b04a8814c 100755 --- a/tests/test_repository_tool.py +++ b/tests/test_repository_tool_old.py @@ -5,7 +5,7 @@ """ - test_repository_tool.py + test_repository_tool_old.py Vladimir Diaz diff --git a/tests/test_roledb.py b/tests/test_roledb_old.py similarity index 99% rename from tests/test_roledb.py rename to tests/test_roledb_old.py index 73405b21bd..04b76e9545 100755 --- a/tests/test_roledb.py +++ b/tests/test_roledb_old.py @@ -5,7 +5,7 @@ """ - test_roledb.py + test_roledb_old.py Vladimir Diaz @@ -776,7 +776,7 @@ def setUpModule(): def tearDownModule(): # tearDownModule() is called after all the tests have run. # Ensure we clean up roledb. Courtesy is contagious, and it begins with - # test_roledb.py. + # test_roledb_old.py. tuf.roledb.clear_roledb() diff --git a/tests/test_root_versioning_integration.py b/tests/test_root_versioning_integration_old.py similarity index 99% rename from tests/test_root_versioning_integration.py rename to tests/test_root_versioning_integration_old.py index 5012029802..251bdfe6c4 100755 --- a/tests/test_root_versioning_integration.py +++ b/tests/test_root_versioning_integration_old.py @@ -5,7 +5,7 @@ """ - test_root_versioning_integration.py + test_root_versioning_integration_old.py Evan Cordell. diff --git a/tests/test_sig.py b/tests/test_sig_old.py similarity index 99% rename from tests/test_sig.py rename to tests/test_sig_old.py index a49c59c21c..d93659dad0 100755 --- a/tests/test_sig.py +++ b/tests/test_sig_old.py @@ -5,7 +5,7 @@ """ - test_sig.py + test_sig_old.py Geremy Condra diff --git a/tests/test_slow_retrieval_attack.py b/tests/test_slow_retrieval_attack_old.py similarity index 99% rename from tests/test_slow_retrieval_attack.py rename to tests/test_slow_retrieval_attack_old.py index 6cf2e1a837..9f22c88f36 100755 --- a/tests/test_slow_retrieval_attack.py +++ b/tests/test_slow_retrieval_attack_old.py @@ -5,7 +5,7 @@ """ - test_slow_retrieval_attack.py + test_slow_retrieval_attack_old.py Konstantin Andrianov. @@ -152,7 +152,7 @@ def setUp(self): repository_basepath = self.repository_directory[len(os.getcwd()):] self.server_process_handler = utils.TestServerProcess(log=logger, - server='slow_retrieval_server.py') + server='slow_retrieval_server_old.py') logger.info('Slow Retrieval Server process started.') diff --git a/tests/test_trusted_metadata_set.py b/tests/test_trusted_metadata_set.py index 6a3142c916..6b195cd732 100644 --- a/tests/test_trusted_metadata_set.py +++ b/tests/test_trusted_metadata_set.py @@ -364,7 +364,9 @@ def snapshot_expired_modifier(snapshot: Snapshot) -> None: snapshot.expires = datetime(1970, 1, 1) # expired intermediate snapshot is loaded but will raise - snapshot = self.modify_metadata(Snapshot.type, snapshot_expired_modifier) + snapshot = self.modify_metadata( + Snapshot.type, snapshot_expired_modifier + ) with self.assertRaises(exceptions.ExpiredMetadataError): self.trusted_set.update_snapshot(snapshot) @@ -399,7 +401,9 @@ def no_meta_modifier(snapshot: Snapshot) -> None: snapshot.meta = {} snapshot = self.modify_metadata(Snapshot.type, no_meta_modifier) - self._update_all_besides_targets(self.metadata[Timestamp.type], snapshot) + self._update_all_besides_targets( + self.metadata[Timestamp.type], snapshot + ) # remove meta information with information about targets from snapshot with self.assertRaises(exceptions.RepositoryError): self.trusted_set.update_targets(self.metadata[Targets.type]) @@ -410,7 +414,9 @@ def meta_length_modifier(snapshot: Snapshot) -> None: snapshot.meta[metafile_path] = MetaFile(version=1, length=1) snapshot = self.modify_metadata(Snapshot.type, meta_length_modifier) - self._update_all_besides_targets(self.metadata[Timestamp.type], snapshot) + self._update_all_besides_targets( + self.metadata[Timestamp.type], snapshot + ) # observed_hash != stored hash in snapshot meta for targets with self.assertRaises(exceptions.RepositoryError): self.trusted_set.update_targets(self.metadata[Targets.type]) @@ -421,7 +427,9 @@ def meta_modifier(snapshot: Snapshot) -> None: snapshot.meta[metafile_path] = MetaFile(version=2) snapshot = self.modify_metadata(Snapshot.type, meta_modifier) - self._update_all_besides_targets(self.metadata[Timestamp.type], snapshot) + self._update_all_besides_targets( + self.metadata[Timestamp.type], snapshot + ) # new_delegate.signed.version != meta.version stored in snapshot with self.assertRaises(exceptions.BadVersionNumberError): self.trusted_set.update_targets(self.metadata[Targets.type]) diff --git a/tests/test_tutorial.py b/tests/test_tutorial_old.py similarity index 99% rename from tests/test_tutorial.py rename to tests/test_tutorial_old.py index 32819b3816..ac33dec86a 100755 --- a/tests/test_tutorial.py +++ b/tests/test_tutorial_old.py @@ -2,7 +2,7 @@ """ - test_tutorial.py + test_tutorial_old.py See LICENSE-MIT OR LICENSE for licensing information. diff --git a/tests/test_unittest_toolbox.py b/tests/test_unittest_toolbox_old.py similarity index 97% rename from tests/test_unittest_toolbox.py rename to tests/test_unittest_toolbox_old.py index 5bd4169c87..d26d079286 100755 --- a/tests/test_unittest_toolbox.py +++ b/tests/test_unittest_toolbox_old.py @@ -5,7 +5,7 @@ """ - test_unittest_toolbox.py + test_unittest_toolbox_old.py Vladimir Diaz diff --git a/tests/test_updater_consistent_snapshot.py b/tests/test_updater_consistent_snapshot.py index 518693c8f9..a54756e4ac 100644 --- a/tests/test_updater_consistent_snapshot.py +++ b/tests/test_updater_consistent_snapshot.py @@ -16,6 +16,7 @@ from tuf.api.metadata import ( SPECIFICATION_VERSION, TOP_LEVEL_ROLE_NAMES, + TargetFile, Targets, ) from tuf.ngclient import Updater @@ -27,6 +28,7 @@ class TestConsistentSnapshot(unittest.TestCase): are formed for each combination""" def setUp(self) -> None: + # pylint: disable=consider-using-with self.temp_dir = tempfile.TemporaryDirectory() self.metadata_dir = os.path.join(self.temp_dir.name, "metadata") self.targets_dir = os.path.join(self.temp_dir.name, "targets") @@ -107,7 +109,9 @@ def _assert_targets_files_exist(self, filenames: Iterable[str]) -> None: } @utils.run_sub_tests_with_dataset(top_level_roles_data) - def test_top_level_roles_update(self, test_case_data: Dict[str, Any]): + def test_top_level_roles_update( + self, test_case_data: Dict[str, Any] + ) -> None: # Test if the client fetches and stores metadata files with the # correct version prefix, depending on 'consistent_snapshot' config consistent_snapshot: bool = test_case_data["consistent_snapshot"] @@ -139,7 +143,9 @@ def test_top_level_roles_update(self, test_case_data: Dict[str, Any]): } @utils.run_sub_tests_with_dataset(delegated_roles_data) - def test_delegated_roles_update(self, test_case_data: Dict[str, Any]): + def test_delegated_roles_update( + self, test_case_data: Dict[str, Any] + ) -> None: # Test if the client fetches and stores delegated metadata files with # the correct version prefix, depending on 'consistent_snapshot' config consistent_snapshot: bool = test_case_data["consistent_snapshot"] @@ -190,7 +196,7 @@ def test_delegated_roles_update(self, test_case_data: Dict[str, Any]): } @utils.run_sub_tests_with_dataset(targets_download_data) - def test_download_targets(self, test_case_data: Dict[str, Any]): + def test_download_targets(self, test_case_data: Dict[str, Any]) -> None: # Test if the client fetches and stores target files with # the correct hash prefix, depending on 'consistent_snapshot' # and 'prefix_targets_with_hash' config @@ -212,6 +218,7 @@ def test_download_targets(self, test_case_data: Dict[str, Any]): for targetpath in targetpaths: info = updater.get_targetinfo(targetpath) + assert isinstance(info, TargetFile) updater.download_target(info) # target files are always persisted without hash prefix diff --git a/tests/test_updater_key_rotations.py b/tests/test_updater_key_rotations.py index b91a88e553..66173a6602 100644 --- a/tests/test_updater_key_rotations.py +++ b/tests/test_updater_key_rotations.py @@ -10,14 +10,14 @@ import tempfile import unittest from dataclasses import dataclass -from typing import Dict, List, Optional, Type +from typing import ClassVar, Dict, List, Optional, Type from securesystemslib.signer import SSlibSigner from tests import utils from tests.repository_simulator import RepositorySimulator from tests.utils import run_sub_tests_with_dataset -from tuf.api.metadata import Key, Metadata, Root +from tuf.api.metadata import Key, Root from tuf.exceptions import UnsignedMetadataError from tuf.ngclient import Updater @@ -35,17 +35,18 @@ class TestUpdaterKeyRotations(unittest.TestCase): # set dump_dir to trigger repository state dumps dump_dir: Optional[str] = None + temp_dir: ClassVar[tempfile.TemporaryDirectory] + keys: ClassVar[List[Key]] + signers: ClassVar[List[SSlibSigner]] @classmethod def setUpClass(cls) -> None: - cls.sim: RepositorySimulator - cls.metadata_dir: str # pylint: disable-next=consider-using-with cls.temp_dir = tempfile.TemporaryDirectory() # Pre-create a bunch of keys and signers - cls.keys: List[Key] = [] - cls.signers: List[SSlibSigner] = [] + cls.keys = [] + cls.signers = [] for _ in range(10): key, signer = RepositorySimulator.create_key() cls.keys.append(key) @@ -57,12 +58,14 @@ def tearDownClass(cls) -> None: def setup_subtest(self) -> None: # Setup repository for subtest: make sure no roots have been published + # pylint: disable=attribute-defined-outside-init self.sim = RepositorySimulator() self.sim.signed_roots.clear() self.sim.root.version = 0 if self.dump_dir is not None: # create subtest dumpdir + # pylint: disable=no-member name = f"{self.id().split('.')[-1]}-{self.case_name}" self.sim.dump_dir = os.path.join(self.dump_dir, name) os.mkdir(self.sim.dump_dir) @@ -73,6 +76,7 @@ def _run_refresh(self) -> None: self.sim.write() # bootstrap with initial root + # pylint: disable=attribute-defined-outside-init self.metadata_dir = tempfile.mkdtemp(dir=self.temp_dir.name) with open(os.path.join(self.metadata_dir, "root.json"), "bw") as f: f.write(self.sim.signed_roots[0]) @@ -264,7 +268,7 @@ def test_non_root_rotations(self, md_version: MdVersion) -> None: self._run_refresh() # Call fetch_metadata to sign metadata with new keys - expected_local_md: Metadata = self.sim._fetch_metadata(role) + expected_local_md: bytes = self.sim.fetch_metadata(role) # assert local metadata role is on disk as expected md_path = os.path.join(self.metadata_dir, f"{role}.json") with open(md_path, "rb") as f: @@ -275,6 +279,7 @@ def test_non_root_rotations(self, md_version: MdVersion) -> None: with self.assertRaises(expected_error): self._run_refresh() + if __name__ == "__main__": if "--dump" in sys.argv: TestUpdaterKeyRotations.dump_dir = tempfile.mkdtemp() diff --git a/tests/test_updater_ng.py b/tests/test_updater_ng.py index 57907fe795..6de571cf59 100644 --- a/tests/test_updater_ng.py +++ b/tests/test_updater_ng.py @@ -19,7 +19,14 @@ from tests import utils from tuf import exceptions, ngclient, unittest_toolbox -from tuf.api.metadata import Metadata, Root, Snapshot, TargetFile, Targets, Timestamp +from tuf.api.metadata import ( + Metadata, + Root, + Snapshot, + TargetFile, + Targets, + Timestamp, +) logger = logging.getLogger(__name__) @@ -41,14 +48,14 @@ def setUpClass(cls) -> None: # Needed because in some tests simple_server.py cannot be found. # The reason is that the current working directory # has been changed when executing a subprocess. - SIMPLE_SERVER_PATH = os.path.join(os.getcwd(), "simple_server.py") + simple_server_path = os.path.join(os.getcwd(), "simple_server.py") # Launch a SimpleHTTPServer (serves files in the current directory). # Test cases will request metadata and target files that have been # pre-generated in 'tuf/tests/repository_data', which will be served # by the SimpleHTTPServer launched here. cls.server_process_handler = utils.TestServerProcess( - log=logger, server=SIMPLE_SERVER_PATH + log=logger, server=simple_server_path ) @classmethod @@ -112,7 +119,7 @@ def setUp(self) -> None: + utils.TEST_HOST_ADDRESS + ":" + str(self.server_process_handler.port) - + repository_basepath.replace("\\","/") + + repository_basepath.replace("\\", "/") ) self.metadata_url = f"{url_prefix}/metadata/" @@ -180,17 +187,27 @@ def test_refresh_and_download(self) -> None: # top-level metadata is in local directory already self.updater.refresh() - self._assert_files([Root.type, Snapshot.type, Targets.type, Timestamp.type]) + self._assert_files( + [Root.type, Snapshot.type, Targets.type, Timestamp.type] + ) # Get targetinfos, assert that cache does not contain files info1 = self.updater.get_targetinfo("file1.txt") assert isinstance(info1, TargetFile) - self._assert_files([Root.type, Snapshot.type, Targets.type, Timestamp.type]) + self._assert_files( + [Root.type, Snapshot.type, Targets.type, Timestamp.type] + ) # Get targetinfo for 'file3.txt' listed in the delegated role1 info3 = self.updater.get_targetinfo("file3.txt") assert isinstance(info3, TargetFile) - expected_files = ["role1", Root.type, Snapshot.type, Targets.type, Timestamp.type] + expected_files = [ + "role1", + Root.type, + Snapshot.type, + Targets.type, + Timestamp.type, + ] self._assert_files(expected_files) self.assertIsNone(self.updater.find_cached_target(info1)) self.assertIsNone(self.updater.find_cached_target(info3)) @@ -217,11 +234,19 @@ def test_refresh_with_only_local_root(self) -> None: self._assert_files([Root.type]) self.updater.refresh() - self._assert_files([Root.type, Snapshot.type, Targets.type, Timestamp.type]) + self._assert_files( + [Root.type, Snapshot.type, Targets.type, Timestamp.type] + ) # Get targetinfo for 'file3.txt' listed in the delegated role1 self.updater.get_targetinfo("file3.txt") - expected_files = ["role1", Root.type, Snapshot.type, Targets.type, Timestamp.type] + expected_files = [ + "role1", + Root.type, + Snapshot.type, + Targets.type, + Timestamp.type, + ] self._assert_files(expected_files) def test_implicit_refresh_with_only_local_root(self) -> None: @@ -234,7 +259,7 @@ def test_implicit_refresh_with_only_local_root(self) -> None: self._assert_files(["root"]) # Get targetinfo for 'file3.txt' listed in the delegated role1 - targetinfo3 = self.updater.get_targetinfo("file3.txt") + self.updater.get_targetinfo("file3.txt") expected_files = ["role1", "root", "snapshot", "targets", "timestamp"] self._assert_files(expected_files) diff --git a/tests/test_updater.py b/tests/test_updater_old.py similarity index 99% rename from tests/test_updater.py rename to tests/test_updater_old.py index 9f79fd8b12..f2148855d7 100755 --- a/tests/test_updater.py +++ b/tests/test_updater_old.py @@ -5,7 +5,7 @@ """ - test_updater.py + test_updater_old.py Konstantin Andrianov. @@ -21,7 +21,7 @@ See LICENSE-MIT OR LICENSE for licensing information. - 'test_updater.py' provides a collection of methods that test the public / + 'test_updater.py_old' provides a collection of methods that test the public / non-public methods and functions of 'tuf.client.updater.py'. The 'unittest_toolbox.py' module was created to provide additional testing @@ -89,7 +89,7 @@ def setUpClass(cls): # Launch a SimpleHTTPServer (serves files in the current directory). # Test cases will request metadata and target files that have been # pre-generated in 'tuf/tests/repository_data', which will be served - # by the SimpleHTTPServer launched here. The test cases of 'test_updater.py' + # by the SimpleHTTPServer launched here. The test cases of 'test_updater_old.py' # assume the pre-generated metadata files have a specific structure, such # as a delegated role 'targets/role1', three target files, five key files, # etc. diff --git a/tests/test_updater_root_rotation_integration.py b/tests/test_updater_root_rotation_integration_old.py similarity index 99% rename from tests/test_updater_root_rotation_integration.py rename to tests/test_updater_root_rotation_integration_old.py index 26faebb987..b8f93043ba 100755 --- a/tests/test_updater_root_rotation_integration.py +++ b/tests/test_updater_root_rotation_integration_old.py @@ -5,7 +5,7 @@ """ - test_updater_root_rotation_integration.py + test_updater_root_rotation_integration_old.py Evan Cordell. @@ -71,8 +71,9 @@ def setUpClass(cls): # Launch a SimpleHTTPServer (serves files in the current directory). Test # cases will request metadata and target files that have been pre-generated # in 'tuf/tests/repository_data', which will be served by the - # SimpleHTTPServer launched here. The test cases of 'test_updater.py' - # assume the pre-generated metadata files have a specific structure, such + # SimpleHTTPServer launched here. The test cases of + # 'test_updater_root_rotation_integration_old.py' assume the + # pre-generated metadata files have a specific structure, such # as a delegated role 'targets/role1', three target files, five key files, # etc. cls.server_process_handler = utils.TestServerProcess(log=logger) diff --git a/tests/test_updater_top_level_update.py b/tests/test_updater_top_level_update.py index 69f2236a84..ee61a3f4ca 100644 --- a/tests/test_updater_top_level_update.py +++ b/tests/test_updater_top_level_update.py @@ -14,7 +14,14 @@ from tests import utils from tests.repository_simulator import RepositorySimulator -from tuf.api.metadata import TOP_LEVEL_ROLE_NAMES, Metadata, Root, Snapshot, Targets, Timestamp +from tuf.api.metadata import ( + TOP_LEVEL_ROLE_NAMES, + Metadata, + Root, + Snapshot, + Targets, + Timestamp, +) from tuf.exceptions import ( BadVersionNumberError, ExpiredMetadataError, @@ -33,6 +40,7 @@ class TestRefresh(unittest.TestCase): past_datetime = datetime.utcnow().replace(microsecond=0) - timedelta(days=5) def setUp(self) -> None: + # pylint: disable=consider-using-with self.temp_dir = tempfile.TemporaryDirectory() self.metadata_dir = os.path.join(self.temp_dir.name, "metadata") self.targets_dir = os.path.join(self.temp_dir.name, "targets") @@ -82,8 +90,7 @@ def _assert_content_equals( self, role: str, version: Optional[int] = None ) -> None: """Assert that local file content is the expected""" - # pylint: disable=protected-access - expected_content = self.sim._fetch_metadata(role, version) + expected_content = self.sim.fetch_metadata(role, version) with open(os.path.join(self.metadata_dir, f"{role}.json"), "rb") as f: self.assertEqual(f.read(), expected_content) diff --git a/tests/test_updater_with_simulator.py b/tests/test_updater_with_simulator.py index 72c16ee162..241b0b6c5d 100644 --- a/tests/test_updater_with_simulator.py +++ b/tests/test_updater_with_simulator.py @@ -12,11 +12,11 @@ import tempfile import unittest from typing import Optional, Tuple -from unittest.mock import MagicMock, Mock, patch +from unittest.mock import MagicMock, patch from tests import utils from tests.repository_simulator import RepositorySimulator -from tuf.api.metadata import SPECIFICATION_VERSION, TargetFile, Targets +from tuf.api.metadata import SPECIFICATION_VERSION, Targets from tuf.exceptions import BadVersionNumberError, UnsignedMetadataError from tuf.ngclient import Updater diff --git a/tests/test_utils.py b/tests/test_utils.py index 2f1adeac65..6ad06a0fbb 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -63,7 +63,7 @@ def test_simple_https_server_startup(self) -> None: good_cert_path = os.path.join("ssl_certs", "ssl_cert.crt") server_process_handler = utils.TestServerProcess( log=logger, - server="simple_https_server.py", + server="simple_https_server_old.py", extra_cmd_args=[good_cert_path], ) @@ -73,7 +73,7 @@ def test_simple_https_server_startup(self) -> None: # Test when no cert file is provided server_process_handler = utils.TestServerProcess( - log=logger, server="simple_https_server.py" + log=logger, server="simple_https_server_old.py" ) # Make sure we can connect to the server @@ -84,7 +84,7 @@ def test_simple_https_server_startup(self) -> None: non_existing_cert_path = os.path.join("ssl_certs", "non_existing.crt") server_process_handler = utils.TestServerProcess( log=logger, - server="simple_https_server.py", + server="simple_https_server_old.py", extra_cmd_args=[non_existing_cert_path], ) @@ -95,7 +95,7 @@ def test_simple_https_server_startup(self) -> None: def test_slow_retrieval_server_startup(self) -> None: # Test normal case server_process_handler = utils.TestServerProcess( - log=logger, server="slow_retrieval_server.py" + log=logger, server="slow_retrieval_server_old.py" ) # Make sure we can connect to the server diff --git a/tests/utils.py b/tests/utils.py index ed06bf905a..3e257ef70f 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -222,6 +222,7 @@ def _start_process(self, extra_cmd_args: List[str], popen_cwd: str) -> None: # Reusing one subprocess in multiple tests, but split up the logs # for each. + # pylint: disable=consider-using-with self.__server_process = subprocess.Popen( command, stdout=subprocess.PIPE, diff --git a/tox.ini b/tox.ini index 443cc9b710..be17f3d3f1 100644 --- a/tox.ini +++ b/tox.ini @@ -38,7 +38,7 @@ commands = [testenv:lint] changedir = {toxinidir} -lint_dirs = tuf/api tuf/ngclient examples +lint_dirs = tuf/api tuf/ngclient examples tests commands = # Use different configs for new (tuf/api/*) and legacy code black --check --diff {[testenv:lint]lint_dirs} diff --git a/tuf/ATTACKS.md b/tuf/ATTACKS.md index 56042516b8..f76cf0b4c3 100644 --- a/tuf/ATTACKS.md +++ b/tuf/ATTACKS.md @@ -289,14 +289,14 @@ exception or error when it detects that a malicious server is serving it data at a slow enough rate. We first spawn the server that slowly streams data to the client. The -'slow_retrieval_server.py' module (can be found in the tests/ directory of the +'slow_retrieval_server_old.py' module (can be found in the tests/ directory of the source code) should be copied over to the server's 'repository/' directory from which to launch it. ```Bash -# Before launching the slow retrieval server, copy 'slow_retrieval_server.py' +# Before launching the slow retrieval server, copy 'slow_retrieval_server_old.py' # to the 'repository/' directory and run it from that directory as follows: -$ python3 slow_retrieval_server.py 8002 mode_2 +$ python3 slow_retrieval_server_old.py 8002 mode_2 ``` The client may now make a request to the slow retrieval server on port 8002. diff --git a/tuf/api/metadata.py b/tuf/api/metadata.py index 6adcf412da..1717682665 100644 --- a/tuf/api/metadata.py +++ b/tuf/api/metadata.py @@ -47,6 +47,7 @@ cast, ) +from dateutil.relativedelta import relativedelta from securesystemslib import exceptions as sslib_exceptions from securesystemslib import hash as sslib_hash from securesystemslib import keys as sslib_keys @@ -500,7 +501,9 @@ def is_expired(self, reference_time: Optional[datetime] = None) -> bool: return reference_time >= self.expires # Modification. - def bump_expiration(self, delta: timedelta = timedelta(days=1)) -> None: + def bump_expiration( + self, delta: Union[timedelta, relativedelta] = timedelta(days=1) + ) -> None: """Increments the expires attribute by the passed timedelta.""" self.expires += delta