Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion doc/changes/unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

## Summary

Updated the nox DB-version default to come from `BaseConfig` instead of the hardcoded `7.1.9`,
Comment thread
ArBridgeman marked this conversation as resolved.
so ITDE-related test flows use the configured Exasol baseline and unit-test help no longer advertises `--db-version`.

## Bug

* #744: Updated nox DB-version handling to use `BaseConfig.minimum_exasol_version` instead hardcoded `7.1.9`

## Refactoring

* #744: Extracted shared minimum-version selection logic into `minimum_declared_version()`
## Security

* #867: Fixed zizmor linting results
* #867: Fixed zizmor linting results
25 changes: 21 additions & 4 deletions exasol/toolbox/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,13 @@ def valid_version_string(version_string: str) -> str:
return version_string


def minimum_declared_version(versions: tuple[str, ...]) -> str:
Comment thread
ArBridgeman marked this conversation as resolved.
versioned = [Version.from_string(v) for v in versions]
min_version = min(versioned)
index_min_version = versioned.index(min_version)
return versions[index_min_version]


ValidPluginHook = Annotated[type[Any], AfterValidator(validate_plugin_hook)]
ValidVersionStr = Annotated[str, AfterValidator(valid_version_string)]

Expand Down Expand Up @@ -230,10 +237,20 @@ def minimum_python_version(self) -> str:
This is used in specific testing scenarios where it would be either
costly to run the tests for all ``python_versions`` or we need a single metric.
"""
versioned = [Version.from_string(v) for v in self.python_versions]
min_version = min(versioned)
index_min_version = versioned.index(min_version)
return self.python_versions[index_min_version]
return minimum_declared_version(self.python_versions)
Comment thread
ArBridgeman marked this conversation as resolved.

@computed_field # type: ignore[misc]
@property
def minimum_exasol_version(self) -> str | None:
"""
Minimum Exasol version declared from the ``exasol_versions`` list.

This is used in scenarios where a single baseline Exasol version is
needed instead of iterating across the full configured matrix.
"""
if len(self.exasol_versions) == 0:
return None
return minimum_declared_version(self.exasol_versions)

@computed_field # type: ignore[misc]
@property
Expand Down
47 changes: 38 additions & 9 deletions exasol/toolbox/nox/_shared.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,20 +43,49 @@ def _context_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter
)
parser.add_argument(
"--db-version", default="7.1.9", help="Specify the Exasol DB version to be used"
)
parser.add_argument(
"--coverage", action="store_true", help="Enable the collection of coverage data"
)
return parser


def _context(session: Session, **kwargs: Any) -> MutableMapping[str, Any]:
parser = _context_parser()
def _context(
session: Session,
parser: argparse.ArgumentParser,
default_context: dict[str, Any],
**kwargs: Any,
) -> MutableMapping[str, Any]:
namespace, args = parser.parse_known_args(session.posargs)
cli_context: MutableMapping[str, Any] = vars(namespace)
cli_context["fwd-args"] = args
default_context = {"db_version": "7.1.9", "coverage": False}
# Note: ChainMap scans last to first
return ChainMap(kwargs, cli_context, default_context)


def _unit_test_context(session: Session, **kwargs: Any) -> MutableMapping[str, Any]:
parser = _context_parser()
parser.add_argument(
"--coverage", action="store_true", help="Enable the collection of coverage data"
)
return _context(session, parser, {"coverage": False}, **kwargs)


def _integration_test_context(
session: Session,
**kwargs: Any,
) -> MutableMapping[str, Any]:
parser = _context_parser()
parser.add_argument(
"--coverage", action="store_true", help="Enable the collection of coverage data"
)
parser.add_argument(
"--db-version",
default=PROJECT_CONFIG.minimum_exasol_version,
help="Specify the Exasol DB version to be used",
)
return _context(
session,
parser,
{
"coverage": False,
"db_version": PROJECT_CONFIG.minimum_exasol_version,
},
**kwargs,
)
11 changes: 7 additions & 4 deletions exasol/toolbox/nox/_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@
from nox import Session

from exasol.toolbox.config import BaseConfig
from exasol.toolbox.nox._shared import _context
from exasol.toolbox.nox._shared import (
_integration_test_context,
_unit_test_context,
)
from exasol.toolbox.nox.plugin import NoxTasks
from noxconfig import (
PROJECT_CONFIG,
Expand Down Expand Up @@ -76,7 +79,7 @@ def _coverage(
@nox.session(name="test:unit", python=False)
def unit_tests(session: Session) -> None:
"""Runs all unit tests"""
context = _context(session)
context = _unit_test_context(session)
_unit_tests(session, PROJECT_CONFIG, context)


Expand All @@ -90,12 +93,12 @@ def integration_tests(session: Session) -> None:
* pre_integration_tests_hook(session: Session, config: Config, context: MutableMapping[str, Any]) -> bool:
* post_integration_tests_hook(session: Session, config: Config, context: MutableMapping[str, Any]) -> bool:
"""
context = _context(session)
context = _integration_test_context(session)
_integration_tests(session, PROJECT_CONFIG, context)


@nox.session(name="test:coverage", python=False)
def coverage(session: Session) -> None:
"""Runs all tests (unit + integration) and reports the code coverage"""
context = _context(session, coverage=True)
context = _integration_test_context(session, coverage=True)
_coverage(session, PROJECT_CONFIG, context)
4 changes: 2 additions & 2 deletions exasol/toolbox/nox/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
@nox.session(name="project:check", python=False)
def check(session: Session) -> None:
"""Runs all available checks on the project"""
context = _context(session, coverage=True)
context = _integration_test_context(session, coverage=True)
py_files = get_filtered_python_files(PROJECT_CONFIG.root_path)
_code_format(session, Mode.Check, py_files)
_pylint(session, py_files)
Expand Down Expand Up @@ -61,7 +61,7 @@ def check(session: Session) -> None:
from exasol.toolbox.nox._release import prepare_release
from exasol.toolbox.nox._shared import (
Mode,
_context,
_integration_test_context,
get_filtered_python_files,
)

Expand Down
23 changes: 23 additions & 0 deletions test/unit/config_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
DEFAULT_EXCLUDED_PATHS,
BaseConfig,
DependencyManager,
minimum_declared_version,
valid_version_string,
warnings,
)
Expand Down Expand Up @@ -65,6 +66,7 @@ def test_works_as_defined(tmp_path, test_project_config_factory):
"merge_gate": False,
},
},
"minimum_exasol_version": "8.29.13",
"minimum_python_version": "3.10",
"os_version": "ubuntu-24.04",
"sonar_token_name": "SONAR_TOKEN",
Expand Down Expand Up @@ -153,6 +155,27 @@ def test_minimum_python_version(test_project_config_factory):
assert conf.minimum_python_version == "1.10"


@pytest.mark.parametrize(
"declared_versions,expected",
[
pytest.param(("3.11", "3.10", "3.12"), "3.10", id="python"),
pytest.param(("2025.1.8", "8.29.13", "9.9.9"), "8.29.13", id="exasol"),
],
)
def test_minimum_declared_version(declared_versions, expected):
assert minimum_declared_version(declared_versions) == expected


def test_minimum_exasol_version(test_project_config_factory):
conf = test_project_config_factory(exasol_versions=("2025.1.8", "8.29.13", "9.9.9"))
assert conf.minimum_exasol_version == "8.29.13"


def test_minimum_exasol_version_when_empty(test_project_config_factory):
conf = test_project_config_factory(exasol_versions=())
assert conf.minimum_exasol_version is None


def test_sonar_token_name_can_be_overridden(tmp_path):
config = AlternateSonarConfig(project_name="test", root_path=tmp_path)

Expand Down
51 changes: 51 additions & 0 deletions test/unit/nox/_shared_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import pytest

from exasol.toolbox.nox._shared import (
_integration_test_context,
_unit_test_context,
get_filtered_python_files,
)

Expand Down Expand Up @@ -74,3 +76,52 @@ def test_get_filtered_python_files(
exceptions = [f for f in actual if f.endswith("sample.py")]
assert len(exceptions) == 1
assert "toolbox/sample.py" in exceptions[0]


def test_unit_test_context_help_excludes_db_version(nox_session):
captured: dict[str, str] = {}

def _capture_context(session, parser, default_context, **kwargs):
captured["help_text"] = parser.format_help()
return default_context

with patch("exasol.toolbox.nox._shared._context", side_effect=_capture_context):
_unit_test_context(nox_session)

help_text = captured["help_text"]
assert "--coverage" in help_text
assert "--db-version" not in help_text


def test_integration_test_context_help_includes_db_version(nox_session):
captured: dict[str, str] = {}

def _capture_context(session, parser, default_context, **kwargs):
captured["help_text"] = parser.format_help()
return default_context

with patch("exasol.toolbox.nox._shared._context", side_effect=_capture_context):
_integration_test_context(nox_session)

help_text = captured["help_text"]
assert "--coverage" in help_text
assert "--db-version" in help_text


def test_unit_test_context_has_no_db_version(nox_session):
context = _unit_test_context(nox_session)

assert context["coverage"] is False
assert "db_version" not in context


def test_integration_test_context_uses_minimum_exasol_version(
nox_session, test_project_config_factory
):
config = test_project_config_factory(exasol_versions=("2025.1.8", "8.29.13"))

with patch("exasol.toolbox.nox._shared.PROJECT_CONFIG", config):
context = _integration_test_context(nox_session)

assert context["coverage"] is False
assert context["db_version"] == "8.29.13"
43 changes: 40 additions & 3 deletions test/unit/nox/_test_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from exasol.toolbox.nox._test import (
_test_command,
coverage,
integration_tests,
unit_tests,
)
Expand All @@ -16,7 +17,7 @@ def default_context():
"""
The default context comes from `toolbox/nox/_shared.py::_context`
"""
return {"db_version": "7.1.9", "coverage": False, "fwd-args": []}
return {"db_version": "8.29.13", "coverage": False, "fwd-args": []}


class TestTestCommand:
Expand Down Expand Up @@ -74,9 +75,16 @@ def test_unit_tests(nox_session, test_project_config_factory):
test_filepath = test_directory / "dummy_test.py"
test_filepath.write_text("def test_dummy():\n assert True")

with patch("exasol.toolbox.nox._test.PROJECT_CONFIG", new=config):
with (
patch("exasol.toolbox.nox._test.PROJECT_CONFIG", new=config),
patch(
"exasol.toolbox.nox._test._unit_test_context",
wraps=lambda session: {"coverage": False, "fwd-args": []},
) as unit_context,
):
unit_tests(nox_session)

unit_context.assert_called_once_with(nox_session)
assert (test_directory / "__pycache__").exists()


Expand All @@ -95,7 +103,36 @@ def test_works_without_hooks(nox_session, test_project_config_factory):
test_filepath = test_directory / "dummy_test.py"
test_filepath.write_text("def test_dummy():\n assert True")

with patch("exasol.toolbox.nox._test.PROJECT_CONFIG", new=config):
with (
patch("exasol.toolbox.nox._test.PROJECT_CONFIG", new=config),
patch(
"exasol.toolbox.nox._test._integration_test_context",
wraps=lambda session: {
"coverage": False,
"db_version": "8.29.13",
"fwd-args": [],
},
) as integration_context,
):
integration_tests(nox_session)

integration_context.assert_called_once_with(nox_session)
assert (test_directory / "__pycache__").exists()


def test_coverage_uses_integration_test_context(nox_session):
with (
patch(
"exasol.toolbox.nox._test._integration_test_context",
return_value={"coverage": True, "db_version": "8.29.13", "fwd-args": []},
) as integration_context,
patch("exasol.toolbox.nox._test._coverage") as coverage_impl,
):
coverage(nox_session)

integration_context.assert_called_once_with(nox_session, coverage=True)
coverage_impl.assert_called_once_with(
nox_session,
PROJECT_CONFIG,
{"coverage": True, "db_version": "8.29.13", "fwd-args": []},
)