Skip to content
Open
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
1 change: 0 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,6 @@ ignore = [
"tmt/queue.py",
"tmt/utils/__init__.py",
"tmt/utils/structured_field.py",
"tmt/hardware.py", # pyright does not pick up pint's _typing.py or something :/
]

pythonVersion = "3.9"
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/provision/mrack/test_hw.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

import tmt.utils
from tests.unit.test_hardware import FULL_HARDWARE_REQUIREMENTS, OR_HARDWARE_REQUIREMENTS
from tmt.hardware import (
from tmt.hardware.constraints import Operator
from tmt.hardware.requirements import (
Hardware,
Operator,
_parse_cpu,
_parse_device,
_parse_disk,
Expand Down
3 changes: 2 additions & 1 deletion tests/unit/provision/testcloud/test_hw.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
from testcloud.domain_configuration import DomainConfiguration, TPMConfiguration

from tests.unit import MATCH, assert_log
from tmt.hardware import TPM_VERSION_ALLOWED_OPERATORS, Hardware, Operator
from tmt.hardware.constraints import Operator
from tmt.hardware.requirements import TPM_VERSION_ALLOWED_OPERATORS, Hardware
from tmt.log import Logger
from tmt.steps.provision.testcloud import (
TPM_VERSION_ALLOWED_OPERATORS as virtual_TPM_VERSION_ALLOWED_OPERATORS, # noqa: N811
Expand Down
32 changes: 18 additions & 14 deletions tests/unit/test_hardware.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

import tmt.guest
import tmt.hardware
import tmt.hardware.constraints
import tmt.utils
from tmt.hardware import Hardware
from tmt.log import Logger
Expand All @@ -31,15 +32,15 @@ def parse_hw(text: str) -> Hardware:
]
+ [
(f'{operator.value} 10', (operator.value, '10'))
for operator in tmt.hardware.INPUTABLE_OPERATORS
for operator in tmt.hardware.constraints.INPUTABLE_OPERATORS
]
+ [
(f'{operator.value} 10 GiB', (operator.value, '10 GiB'))
for operator in tmt.hardware.INPUTABLE_OPERATORS
for operator in tmt.hardware.constraints.INPUTABLE_OPERATORS
]
+ [
(f'{operator.value}10GiB', (operator.value, '10GiB'))
for operator in tmt.hardware.INPUTABLE_OPERATORS
for operator in tmt.hardware.constraints.INPUTABLE_OPERATORS
]
)

Expand All @@ -53,7 +54,7 @@ def parse_hw(text: str) -> Hardware:
],
)
def test_constraint_value_pattern(value: str, expected: tuple[Any, Any]) -> None:
match = tmt.hardware.CONSTRAINT_VALUE_PATTERN.match(value)
match = tmt.hardware.constraints.CONSTRAINT_VALUE_PATTERN.match(value)

assert match is not None
assert match.groups() == expected
Expand All @@ -75,7 +76,7 @@ def test_constraint_value_pattern(value: str, expected: tuple[Any, Any]) -> None
],
)
def test_constraint_name_pattern(value: str, expected: tuple[Any, Any]) -> None:
match = tmt.hardware.CONSTRAINT_NAME_PATTERN.match(value)
match = tmt.hardware.constraints.CONSTRAINT_NAME_PATTERN.match(value)

assert match is not None
assert match.groups() == expected
Expand Down Expand Up @@ -128,7 +129,7 @@ def test_constraint_default_unit(value: dict, expected: tuple[Any, Any]) -> None
],
)
def test_constraint_components_pattern(value: str, expected: tuple[Any, Any]) -> None:
match = tmt.hardware.CONSTRAINT_COMPONENTS_PATTERN.match(value)
match = tmt.hardware.constraints.CONSTRAINT_COMPONENTS_PATTERN.match(value)

assert match is not None
assert match.groups() == expected
Expand Down Expand Up @@ -180,7 +181,10 @@ def test_normalize_hardware(root_logger) -> None:
],
)
def test_normalize_invalid_hardware(
spec: tmt.hardware.Spec, expected_exc: type[Exception], expected_message: str, root_logger
spec: tmt.hardware.constraints.Spec,
expected_exc: type[Exception],
expected_message: str,
root_logger,
) -> None:
with pytest.raises(expected_exc, match=expected_message):
tmt.guest.normalize_hardware('', spec, root_logger)
Expand Down Expand Up @@ -441,15 +445,15 @@ def _test_check(constraint: tmt.hardware.Constraint) -> bool:
@pytest.mark.parametrize(
('operator', 'left', 'right', 'expected'),
[
(tmt.hardware.not_contains, ['foo'], 'foo', False),
(tmt.hardware.not_contains, ['foo', 'bar'], 'foo', False),
(tmt.hardware.not_contains, ['foo'], 'bar', True),
(tmt.hardware.not_contains_exclusive, ['foo'], 'foo', False),
(tmt.hardware.not_contains_exclusive, ['foo', 'bar'], 'foo', True),
(tmt.hardware.not_contains_exclusive, ['foo'], 'bar', True),
(tmt.hardware.constraints.not_contains, ['foo'], 'foo', False),
(tmt.hardware.constraints.not_contains, ['foo', 'bar'], 'foo', False),
(tmt.hardware.constraints.not_contains, ['foo'], 'bar', True),
(tmt.hardware.constraints.not_contains_exclusive, ['foo'], 'foo', False),
(tmt.hardware.constraints.not_contains_exclusive, ['foo', 'bar'], 'foo', True),
(tmt.hardware.constraints.not_contains_exclusive, ['foo'], 'bar', True),
],
)
def test_operators(
operator: tmt.hardware.OperatorHandlerType, left: Any, right: Any, expected: bool
operator: tmt.hardware.constraints.OperatorHandlerType, left: Any, right: Any, expected: bool
) -> None:
assert operator(left, right) is expected
9 changes: 5 additions & 4 deletions tmt/guest/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@

import tmt
import tmt.hardware
import tmt.hardware.constraints
import tmt.log
import tmt.package_managers
import tmt.steps
Expand Down Expand Up @@ -1108,7 +1109,7 @@ def _flag(field: str, label: str) -> tuple[str, str, str]:

def normalize_hardware(
key_address: str,
raw_hardware: Union[None, tmt.hardware.Spec, tmt.hardware.Hardware],
raw_hardware: Union[None, tmt.hardware.constraints.Spec, tmt.hardware.Hardware],
logger: tmt.log.Logger,
) -> Optional[tmt.hardware.Hardware]:
"""
Expand All @@ -1130,10 +1131,10 @@ def normalize_hardware(
merged: dict[str, Any] = {}

for raw_datum in raw_hardware:
components = tmt.hardware.ConstraintComponents.from_spec(raw_datum)
components = tmt.hardware.constraints.ConstraintComponents.from_spec(raw_datum)

if (
components.name not in tmt.hardware.CHILDLESS_CONSTRAINTS
components.name not in tmt.hardware.constraints.CHILDLESS_CONSTRAINTS
and components.child_name is None
):
raise tmt.utils.SpecificationError(
Expand All @@ -1142,7 +1143,7 @@ def normalize_hardware(
)

if (
components.name in tmt.hardware.INDEXABLE_CONSTRAINTS
components.name in tmt.hardware.constraints.INDEXABLE_CONSTRAINTS
and components.peer_index is None
):
raise tmt.utils.SpecificationError(
Expand Down
51 changes: 51 additions & 0 deletions tmt/hardware/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"""
Guest hardware requirements specification and helpers.

tmt metadata allow to describe various HW requirements a guest needs to satisfy.
This package provides useful functions and classes for core functionality and
shared across provision plugins.

Parsing of HW requirements
==========================

Set of HW requirements, as given by test or plan metadata, is represented by
Python structures - lists, mappings, primitive types - when loaded from fmf
files. Part of the code below converts this representation to a tree of objects
that provide helpful operations for easier evaluation and processing of HW
requirements.

Each HW requirement "rule" in original metadata is a constraint, a condition
the eventual guest HW must satisfy. Each node of the tree created from HW
requirements is therefore called "a constraint", and represents either a single
condition ("trivial" constraints), or a set of such conditions plus a function
reducing their individual outcomes to one final answer for the whole set (think
:py:func:`any` and :py:func:`all` built-in functions) ("compound" constraints).
Components of each constraint - dimension, operator, value, units - are
decoupled from the rest, and made available for inspection.

[1] https://tmt.readthedocs.io/en/stable/spec/hardware.html
"""

from tmt.hardware.constraints import (
UNITS,
Constraint,
FlagConstraint,
IntegerConstraint,
NumberConstraint,
Operator,
SizeConstraint,
TextConstraint,
)
from tmt.hardware.requirements import Hardware

__all__ = [
'UNITS',
'Constraint',
'FlagConstraint',
'Hardware',
'IntegerConstraint',
'NumberConstraint',
'Operator',
'SizeConstraint',
'TextConstraint',
]
Loading
Loading