Skip to content

Commit

Permalink
Refactor test collection
Browse files Browse the repository at this point in the history
  • Loading branch information
hmaerki committed Jan 22, 2025
1 parent ba7e42d commit fa6d1aa
Show file tree
Hide file tree
Showing 9 changed files with 177 additions and 535 deletions.
2 changes: 2 additions & 0 deletions src/testbed/multiprocessing/test_bartender.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"""
Important Terms (abbreviations)
* ts: TentacleSpec
* tss: TentacleSpecs
* tsv: TentacleSpecVariant
* tsvs: TentacleSpecVariants
* tbt: ToBeTested
Expand Down
5 changes: 0 additions & 5 deletions src/testbed/testcollection/baseclasses_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,6 @@ def generate(
available_tentacles=applicable_tentacles,
firmwares_built=firmwares_built,
)
if testrun_spec.tentacles_required > 1:
yield from testrun_spec.generate(
available_tentacles=applicable_tentacles[::-1],
firmwares_built=firmwares_built,
)

@property
def tests_todo(self) -> int:
Expand Down
23 changes: 0 additions & 23 deletions src/testbed/testcollection/baseclasses_spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,13 +114,6 @@ def remove_tentacle_variant(
f"remove_tentacle_variant(): Could not remove as not found: {tentacle_variant.board_variant}"
)

def filter_firmwares_built(self, firmwares_built: set) -> TentacleSpecVariants:
assert isinstance(firmwares_built, set)

return TentacleSpecVariants(
[tsv for tsv in self if tsv.board_variant in firmwares_built]
)

@property
def sorted_text(self) -> list[str]:
return sorted([s.board_variant for s in self])
Expand All @@ -140,22 +133,6 @@ def verify(self, required_tentacles_count: int) -> None:
def tests_todo(self) -> int:
return sum([len(tsvs_todo) for tsvs_todo in self])

def filter_firmwares_built(
self,
firmwares_built: set[str] | None,
) -> RolesTentacleSpecVariants:
assert isinstance(firmwares_built, set | None)

if firmwares_built is None:
return self

return RolesTentacleSpecVariants(
[
tsvs.filter_firmwares_built(firmwares_built=firmwares_built)
for tsvs in self
]
)


class ConnectedTentacles(list[TentacleMicropython]):
@property
Expand Down
105 changes: 52 additions & 53 deletions src/testbed/testcollection/testrun_specs.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import abc
import contextlib
import dataclasses
import itertools
import pathlib
import typing
from collections.abc import Iterator
Expand All @@ -14,7 +13,6 @@
ConnectedTentacles,
RolesTentacleSpecVariants,
TentacleMicropython,
TentacleSpecVariant,
TentacleSpecVariants,
TentacleVariant,
)
Expand Down Expand Up @@ -214,63 +212,64 @@ def mark_as_done(self, testrun: TestRun) -> None:
def tests_todo(self) -> int:
return self.roles_tsvs_todo.tests_todo

def tsvs_combinations(
self,
firmwares_built: set[str] | None,
) -> list[tuple[TentacleSpecVariant]]:
assert isinstance(firmwares_built, set | None)
roles_tsvs_todo = self.roles_tsvs_todo.filter_firmwares_built(
firmwares_built=firmwares_built
)
if len(roles_tsvs_todo) == 0:
return []
tsvs_combinations = list(itertools.product(*roles_tsvs_todo))
for tsvs_combination in tsvs_combinations:
assert len(tsvs_combination) == self.tentacles_required
return tsvs_combinations

def generate(
self,
available_tentacles: list[TentacleMicropython],
firmwares_built: set[str] | None,
) -> Iterator[TestRun]:
assert isinstance(available_tentacles, list)

tsvs_combinations = self.tsvs_combinations(firmwares_built=firmwares_built)

def tentacles_suitable(
tentacles: typing.Sequence[TentacleMicropython],
) -> bool:
"""
True if all tentacle matches the tentacle_specs
"""
assert len(tsvs_combination) == len(tentacles)
for tsv, tentacle in zip(tsvs_combination, tentacles, strict=False):
if tsv.tentacle_spec is not tentacle.tentacle_spec:
return False
return True

for tsvs_combination in tsvs_combinations:
for tentacles in itertools.combinations(
available_tentacles, self.tentacles_required
):
if not tentacles_suitable(tentacles=tentacles):
continue

list_tentacle_variant = [
TentacleVariant(
tentacle=tentacle,
board=variant.board,
variant=variant.variant,
)
for variant, tentacle in zip(
tsvs_combination, tentacles, strict=False
)
]

yield self.testrun_class(
testrun_spec=self, list_tentacle_variant=list_tentacle_variant
def iter_tvs(tentacle: TentacleMicropython) -> typing.Iterator[TentacleVariant]:
for variant in tentacle.tentacle_spec.build_variants:
tv = TentacleVariant(
tentacle=tentacle,
board=tentacle.tentacle_spec.board,
variant=variant,
)
if firmwares_built is not None:
if tv.board_variant not in firmwares_built:
continue
yield tv

if self.tentacles_required == 1:
for tentacle in available_tentacles:
for tv in iter_tvs(tentacle):
first_second = [tv]
if self._matches(first_second):
yield self.testrun_class(
testrun_spec=self,
list_tentacle_variant=first_second,
)
return

if self.tentacles_required == 2:
for tentacle1 in available_tentacles:
for tentacle2 in available_tentacles:
if tentacle1 is tentacle2:
continue
for tv1 in iter_tvs(tentacle1):
for tv2 in iter_tvs(tentacle2):
first_second = [tv1, tv2]
if self._matches(first_second):
yield self.testrun_class(
testrun_spec=self,
list_tentacle_variant=first_second,
)
return

raise ValueError(f"Not supported: {self.tentacles_required=}")

def _matches(self, tvs: list[TentacleVariant]) -> bool:
"""
Return True if at lease 1 role matches.
Example tvs: Tentacle A is WLAN-First <-> Tentacle B is WLAN-Second.
"""
assert len(tvs) == len(self.roles_tsvs_todo)
for tentacle_variant, tsvs in zip(tvs, self.roles_tsvs_todo, strict=False):
assert isinstance(tentacle_variant, TentacleVariant)
assert isinstance(tsvs, TentacleSpecVariants)
for tsv in tsvs:
if tentacle_variant.board_variant == tsv.board_variant:
return True
return False

def pytest_print(self, indent: int, file: typing.TextIO) -> None:
for idx0_role, role_tsvs_todo in enumerate(self.roles_tsvs_todo):
Expand Down
21 changes: 9 additions & 12 deletions tests/test_collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,14 +126,6 @@ def testrun_done(len_actual_testruns_at_least: int) -> None:
print(f"## {i}: testrun_specs", file=file)
testrun_specs.pytest_print(indent=1, file=file)

print(f"## {i}: tsvs_combinations", file=file)
for testrun_spec in bartender.testrun_specs:
print(f" TestRunSpec[{testrun_spec.label}]", file=file)
for tsvs_combination in sorted(
testrun_spec.tsvs_combinations(firmwares_built=firmwares_built)
):
print(f" {tsvs_combination!r}")

possible_testruns = bartender.possible_testruns(
firmwares_built=firmwares_built
)
Expand Down Expand Up @@ -191,12 +183,16 @@ def testrun_done(len_actual_testruns_at_least: int) -> None:
specs=[LOLIN_D1_MINI, LOLIN_C3_MINI],
testrun_specs=baseclasses_run.TestRunSpecs([_TESTRUNSPEC_WLAN]),
)

_TESTPARAM_WLAN_SYMMETRICAL = Ttestparam(
label="wlan_symmetrical",
_TESTPARAM_WLAN_SYMMETRICAL2 = Ttestparam(
label="wlan_symmetrical2",
specs=[LOLIN_C3_MINI, LOLIN_C3_MINI],
testrun_specs=baseclasses_run.TestRunSpecs([_TESTRUNSPEC_WLAN]),
)
_TESTPARAM_WLAN_SYMMETRICAL3 = Ttestparam(
label="wlan_symmetrical3",
specs=[LOLIN_C3_MINI, LOLIN_C3_MINI, LOLIN_C3_MINI],
testrun_specs=baseclasses_run.TestRunSpecs([_TESTRUNSPEC_WLAN]),
)
_TESTPARAM_POTPOURRY = Ttestparam(
label="potpourry",
specs=[RPI_PICO, RPI_PICO, LOLIN_D1_MINI, LOLIN_C3_MINI],
Expand All @@ -206,7 +202,8 @@ def testrun_done(len_actual_testruns_at_least: int) -> None:
)
_TESTPARAMS = [
_TESTPARAM_WLAN_ASYMMETRICAL,
_TESTPARAM_WLAN_SYMMETRICAL,
_TESTPARAM_WLAN_SYMMETRICAL2,
_TESTPARAM_WLAN_SYMMETRICAL3,
_TESTPARAM_POTPOURRY,
]

Expand Down
Loading

0 comments on commit fa6d1aa

Please sign in to comment.