From e87b49e61e2f4a5d7ee2edc562e646e6429417b9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kalinowski Date: Wed, 13 Dec 2023 14:57:23 +0400 Subject: [PATCH] Integration tests with different versions --- b2/_b2v4/__init__.py | 2 +- test/conftest.py | 51 ++++++++++++++++++++++++++++++++++ test/helpers.py | 4 +-- test/integration/conftest.py | 33 ++++++++++++++++++++-- test/unit/conftest.py | 45 ++++-------------------------- test/unit/test_apiver.py | 11 ++++++-- test/unit/test_console_tool.py | 3 +- 7 files changed, 100 insertions(+), 49 deletions(-) create mode 100644 test/conftest.py diff --git a/b2/_b2v4/__init__.py b/b2/_b2v4/__init__.py index fd18dd885..d06136040 100644 --- a/b2/_b2v4/__init__.py +++ b/b2/_b2v4/__init__.py @@ -1,4 +1,4 @@ -from ..console_tool import * # noqa +from ..console_tool import * # noqa (this includes ConsoleTool, main and all other things) B2.register_subcommand(AuthorizeAccount) B2.register_subcommand(CancelAllUnfinishedLargeFiles) diff --git a/test/conftest.py b/test/conftest.py new file mode 100644 index 000000000..e14d7fbcc --- /dev/null +++ b/test/conftest.py @@ -0,0 +1,51 @@ +import sys + +import pytest + + +@pytest.hookimpl +def pytest_configure(config): + config.addinivalue_line( + "markers", + "cli_version(from_version, to_version): run tests only on certain versions", + ) + + +@pytest.fixture(autouse=True) +def run_on_cli_version_handler(request, cli_int_version): + """ + Auto-fixture that allows skipping tests based on the CLI version. + + Usage: + @pytest.mark.cli_version(1, 3) + def test_foo(): + # Test is run only for versions 1 and 3 + ... + + @pytest.mark.cli_version(from_version=2, to_version=5) + def test_bar(): + # Test is run only for versions 2, 3, 4 and 5 + ... + + Note that it requires the `cli_int_version` fixture to be defined. + Both unit tests and integration tests handle it a little bit different, thus + two different fixtures are provided. + """ + node = request.node.get_closest_marker('cli_version') + if not node: + return + + if node.args: + if cli_int_version in node.args: + # Run the test. + return + + if node.kwargs: + from_version = node.kwargs.get('from_version', 0) + to_version = node.kwargs.get('to_version', sys.maxsize) + + if from_version <= cli_int_version <= to_version: + # Run the test. + return + + pytest.skip('Not supported on this CLI version') diff --git a/test/helpers.py b/test/helpers.py index 7fe7a5364..3a652299a 100644 --- a/test/helpers.py +++ b/test/helpers.py @@ -10,7 +10,6 @@ import pathlib import platform import re -from typing import Union import pytest @@ -26,8 +25,7 @@ def skip_on_windows(*args, reason='Not supported on Windows', **kwargs): def get_versions() -> list[str]: return [ - path.name - for path in sorted((pathlib.Path(__file__).parent.parent / 'b2').glob('*b2v*')) + path.name for path in sorted((pathlib.Path(__file__).parent.parent / 'b2').glob('*b2v*')) ] diff --git a/test/integration/conftest.py b/test/integration/conftest.py index 7786d4ec8..4d9e488f9 100755 --- a/test/integration/conftest.py +++ b/test/integration/conftest.py @@ -12,6 +12,7 @@ import logging import os import pathlib +import re import subprocess import sys import tempfile @@ -21,8 +22,8 @@ import pytest from b2sdk.v2 import B2_ACCOUNT_INFO_ENV_VAR, XDG_CONFIG_HOME_ENV_VAR, Bucket +from ..helpers import CLI_VERSIONS, DEFAULT_CLI_VERSION, get_int_version from .helpers import NODE_DESCRIPTION, RNG_SEED, Api, CommandLine, bucket_name_part, random_token -from ..helpers import DEFAULT_CLI_VERSION logger = logging.getLogger(__name__) @@ -56,7 +57,7 @@ def node_stats(summary_notes): def pytest_addoption(parser): parser.addoption( '--sut', - default='%s -m b2.%s' % (sys.executable, DEFAULT_CLI_VERSION), + default=f'{sys.executable} -m b2.{DEFAULT_CLI_VERSION}', help='Path to the System Under Test', ) parser.addoption( @@ -72,11 +73,37 @@ def pytest_addoption(parser): '--as_version', default=None, help='Force running tests as a particular version of the CLI, ' - 'useful if version cannot be determined easily from the executable', + 'useful if version cannot be determined easily from the executable', ) parser.addoption('--cleanup', action='store_true', help='Perform full cleanup at exit') +def get_cli_int_version(config) -> int: + forced_version = config.getoption('--as_version') + if forced_version: + return int(forced_version) + + executable = config.getoption('--sut') + # If the executable contains anything that looks like a proper version, we can try to pick it up. + versions_list = '|'.join(CLI_VERSIONS) + versions_match = re.search(rf'({versions_list})', executable) + if versions_match: + return get_int_version(versions_match.group(1)) + + raise pytest.UsageError('Unable to determine used CLI version') + + +@pytest.hookimpl +def pytest_report_header(config): + cli_version = get_cli_int_version(config) + return f'b2cli version: {cli_version}' + + +@pytest.fixture(scope='session') +def cli_int_version(request) -> int: + return get_cli_int_version(request.config) + + @pytest.fixture(scope='session') def application_key() -> str: key = environ.get('B2_TEST_APPLICATION_KEY') diff --git a/test/unit/conftest.py b/test/unit/conftest.py index 4b8c6990d..276592784 100644 --- a/test/unit/conftest.py +++ b/test/unit/conftest.py @@ -9,12 +9,6 @@ ###################################################################### import importlib import os -import sys -from typing import Optional - -from ..helpers import DEFAULT_CLI_VERSION, CLI_VERSIONS, get_int_version -from .helpers import RunOrDieExecutor -from .test_console_tool import BaseConsoleToolTest from unittest import mock import pytest @@ -22,6 +16,10 @@ from b2.console_tool import _TqdmCloser +from ..helpers import CLI_VERSIONS, DEFAULT_CLI_VERSION, get_int_version +from .helpers import RunOrDieExecutor +from .test_console_tool import BaseConsoleToolTest + @pytest.hookimpl def pytest_addoption(parser): @@ -35,39 +33,8 @@ def pytest_addoption(parser): @pytest.hookimpl def pytest_report_header(config): - return f'b2cli version: {config.getoption("--cli")}' - - -@pytest.hookimpl -def pytest_configure(config): - config.addinivalue_line( - "markers", "cli_version(from_version, to_version): run tests only on certain versions", - ) - - -@pytest.fixture(autouse=True) -def run_on_cli_version_handler(request, cli_int_version): - node = request.node.get_closest_marker('cli_version') - if not node: - return - - if node.args and node.kwargs: - raise pytest.UsageError('`cli_version` should be used with either args or kwargs') - - if node.args: - if cli_int_version in node.args: - # Run the test. - return - - if node.kwargs: - from_version = node.kwargs.get('from_version', 0) - to_version = node.kwargs.get('to_version', sys.maxsize) - - if from_version <= cli_int_version <= to_version: - # Run the test. - return - - pytest.skip('Not supported on this CLI version') + int_version = get_int_version(config.getoption('--cli')) + return f'b2cli version: {int_version}' @pytest.fixture(scope='session') diff --git a/test/unit/test_apiver.py b/test/unit/test_apiver.py index 2b530f843..bf1176772 100644 --- a/test/unit/test_apiver.py +++ b/test/unit/test_apiver.py @@ -1,3 +1,12 @@ +###################################################################### +# +# File: test/unit/test_apiver.py +# +# Copyright 2023 Backblaze Inc. All Rights Reserved. +# +# License https://www.backblaze.com/using_b2_code.html +# +###################################################################### import unittest import pytest @@ -24,12 +33,10 @@ def test_passes_above_and_on_v4(self): def test_passes_only_on_v3(self): assert self.cli_int_version == 3 - @pytest.mark.cli_version(4) def test_passes_only_on_v4(self): assert self.cli_int_version == 4 - @pytest.mark.cli_version(3, 4) def test_passes_on_both_v3_and_v4(self): assert self.cli_int_version in {3, 4} diff --git a/test/unit/test_console_tool.py b/test/unit/test_console_tool.py index 63930e22d..bb2cd1e2e 100644 --- a/test/unit/test_console_tool.py +++ b/test/unit/test_console_tool.py @@ -77,7 +77,8 @@ def _run_command_ignore_output(self, argv): success, but ignoring the stdout. """ stdout, stderr = self._get_stdouterr() - actual_status = self.console_tool_class(self.b2_api, stdout, stderr).run_command(['b2'] + argv) + actual_status = self.console_tool_class(self.b2_api, stdout, + stderr).run_command(['b2'] + argv) actual_stderr = self._trim_trailing_spaces(stderr.getvalue()) if actual_stderr != '':