Skip to content

Refactor suite, device, plan and CLI around typed inputs - #47

Merged
jaenrig-ifx merged 15 commits into
mainfrom
arch-refactor
Nov 4, 2026
Merged

jaenrig-ifx merged 15 commits into
mainfrom
arch-refactor

Conversation

@jaenrig-ifx

Copy link
Copy Markdown
Member

Refactors the suite into a package with one Suite class per execution mode, and moves device, plan, backend, config and CLI parsing onto typed inputs. See the individual commits for details.

jaenrig-ifx and others added 15 commits October 28, 2026 18:19
Signed-off-by: jaenrig-ifx <enriquezgarcia.external@infineon.com>
… model.

Signed-off-by: jaenrig-ifx <enriquezgarcia.external@infineon.com>
Signed-off-by: jaenrig-ifx <enriquezgarcia.external@infineon.com>
Print a sectioned report per suite: a "> suite : <name>" heading, the
acquired devices, the test results, and a summary line such as
"1 passed, 1 failed". Sections are divided by separator lines whose width
matches the longest line of the report.

List each device once, stacked under a cyan "> device [n]" heading with
aligned name, uid and address fields in magenta. Prefix every test row
with its device index instead of repeating the device name, and drop the
parallel job id from the displayed test name.

Pre-refactor and clean up.

Signed-off-by: jaenrig-ifx <enriquezgarcia.external@infineon.com>
Signed-off-by: jaenrig-ifx <enriquezgarcia.external@infineon.com>
…ter.

The class exports completed test output to files and does not render CLI
output, so it belongs with the report observer API. Rename it to
TestOutputExporter, update ottu/cli/cmd/run, and move its tests to
tests/test_report with extra branch coverage.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: jaenrig-ifx <enriquezgarcia.external@infineon.com>
…onfig.

Fold the versioned DotOttu model and its ProjectConfig loader from
config_models/project into one pydantic ProjectConfig in ottu/config.py.
There is only one schema version, so the version-to-model dispatch is gone.
The version field is checked by a validator that keeps the "Unsupported
.ottu schema version" message. An empty .ottu file now fails validation
instead of raising an AttributeError.

Remove the config_models/project package, point backend, report and
test_path at ottu.config, and move the tests to tests/test_config.py.

Signed-off-by: jaenrig-ifx <enriquezgarcia.external@infineon.com>
Move the device list models into the device package. DeviceDefinition and
DeviceList now live in ottu/device/device.py, together with the new
DeviceInput model that describes the values a device must have. Device
gains from_input() to resolve an input into a runtime device, and
from_file() validates the YAML directly. The version adapter in
config_models/device is removed; a new schema version will bring its own.

Make DeviceQuery work on DeviceInput filters instead of parsed strings.
The string and key=value parsing, and the combining of filters, are gone
from the query; the CLI parses them into DeviceInput values instead.
Device.from_string() and from_mapping() are replaced by from_input().

Remove config_models/device and move its tests to tests/device, and update
the device and query tests for the typed inputs.

Signed-off-by: jaenrig-ifx <enriquezgarcia.external@infineon.com>
Add the TestPathInput model, a test selector with an optional device role,
and TestPath.from_input() to resolve it into test paths.

Replace TestPathResolver.resolve_all() with two smaller pieces:
exclude() removes already resolved exclude paths, and any path matching
the context's own exclude patterns, from a list of test paths, and
is_single_file() tells whether a selector names exactly one file that is
not excluded. Callers now resolve their inputs and then exclude, instead
of passing selectors through one combined call.

Replace the resolve_all tests with tests for from_input(), exclude() and
is_single_file().

Signed-off-by: jaenrig-ifx <enriquezgarcia.external@infineon.com>
Add SuiteReport, which describes a suite about to run with its devices
already acquired, and SuiteReportObserver, a runtime-checkable protocol
for observers that want to hear when a suite starts. SuiteReportNotifier
hands the report to the observers that implement it and skips the rest, so
existing test observers keep working unchanged.

Drop the job_id from TestReport and QueueTestReportObserver. Concurrent
replicas of a test run on distinct devices, so the device already tells
their reports apart. The queue observer now forwards reports as they are.

Update the queue observer test for the report being forwarded unchanged.

Signed-off-by: jaenrig-ifx <enriquezgarcia.external@infineon.com>
Move backend.py to ottu/backend/backend.py and backend_builtins.py to
ottu/backend/builtins.py. The package re-exports Backend and
BackendCommandError, so importers are unchanged; the built-in definitions
stay an internal module.

Remove the 3 second sleeps from the debug backend commands, so debug runs
finish at once and the tests no longer have to strip them.

Move the tests to tests/backend and build their device with
Device.from_input() instead of the removed Device.from_string().

Signed-off-by: jaenrig-ifx <enriquezgarcia.external@infineon.com>
Test.run() now uses the device assigned to the test and raises a
ValueError when there is none, as it already does for a missing backend.
It no longer falls back to an empty Device or acquires the device again:
the suite books and acquires its devices once before running its tests.

Remove Test.from_inputs(). The suite builder creates the tests from the
resolved test paths, which keeps test selection and exclusion out of Test.

Update the tests to run with an explicit device, add a test for the missing
device, and drop the from_inputs tests.

Signed-off-by: jaenrig-ifx <enriquezgarcia.external@infineon.com>
Turn suite.py into a package. suite/suite.py holds the runtime: the value
types (RoleCount, SuiteOpts, DevicePool) and the suites. suite/builder.py
holds what builds them from user inputs. The package re-exports every
public name, so importers are unchanged.

Replace the string-based SuiteBuilder, RoleSuiteBuilder and
StandardSuiteBuilder with typed inputs. SuiteInput and SuiteDeviceInput
describe a suite; SuiteInputValidator and SuiteRoleInputValidator check
them; SuiteDeviceResolver and SuiteRoleDeviceResolver turn them into a
device pool, one pool per role for role suites. SuiteBuilder.build() runs
these steps and picks the suite class. Candidate pools are resolved and
sized against count and jobs without touching hardware.

Make Suite abstract. run() books the connected devices from the pool,
acquires them, tells the observers with a SuiteReport and then runs. Each
mode is a subclass that books its devices and assigns them to its tests:
SuiteSequential, SuiteReplicated, SuiteRole and SuiteDistributed. This
replaces the runner_* method names. A suite no longer keeps the requested
and available devices, only its pool.

Only connected devices are booked: a device without hardware access no
longer counts as available.

Move the tests to tests/suite and split them by suite and builder.

Signed-off-by: jaenrig-ifx <enriquezgarcia.external@infineon.com>
Move the plan file models into plan.py. PlanFile validates a version 1
plan file; its suites are PlanSuiteInput values with PlanTestInput tests
and a PlanSuiteRequires section. The version adapter in config_models/plan
is removed; a new schema version will bring its own.

Plan now turns each plan suite into a SuiteInput and builds it with
SuiteBuilder.build(), so a plan suite is built the same way as one given
on the command line. The command count overrides the plan count, and
Plan.build_suites() takes the device inputs and the jobs of the command.
Suite selection by name is now private to Plan.

Remove config_models/plan, move its tests to tests/test_plan_file.py and
update the plan tests for the typed inputs.

Signed-off-by: jaenrig-ifx <enriquezgarcia.external@infineon.com>
Add cli/parse.py, which turns the argument and option strings into typed
inputs: test paths, counts and device selectors, with the role qualifier
for role suites. Bad values become click.BadParameter errors.

run builds its suite with SuiteBuilder.build() from those inputs. For a
plan, the --device, --count and --jobs options now override what the plan
defines, instead of being rejected, and --tests and --exclude still
select its suites. The suite acquires its own devices and announces
itself to the observers, so run no longer acquires them.

device parses its filters with parse_device_input, so a filter can be a
bare identifier as well as key=value pairs.

CliOutput follows suite events: suite_started() takes a SuiteReport
instead of begin_suite(), and rows are keyed on test and device only, as
the job id is gone.

Document that --device replaces requires.device of every selected suite.
Update the run, device and output tests, and add tests for the parsers.

Signed-off-by: jaenrig-ifx <enriquezgarcia.external@infineon.com>
@jaenrig-ifx
jaenrig-ifx requested a review from a team as a code owner November 4, 2026 10:14
@jaenrig-ifx
jaenrig-ifx enabled auto-merge (rebase) November 4, 2026 10:14
@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown

☂️ Python Coverage

current status: ✅

Overall Coverage

Lines Covered Coverage Threshold Status
1750 1750 100% 0% 🟢

New Files

File Coverage Status
ottu/backend/_init_.py 100% 🟢
ottu/cli/parse.py 100% 🟢
ottu/config.py 100% 🟢
ottu/suite/_init_.py 100% 🟢
ottu/suite/builder.py 100% 🟢
ottu/suite/suite.py 100% 🟢
TOTAL 100% 🟢

Modified Files

File Coverage Status
ottu/cli/cmd/device.py 100% 🟢
ottu/cli/cmd/run.py 100% 🟢
ottu/cli/output.py 100% 🟢
ottu/device/_init_.py 100% 🟢
ottu/device/device.py 100% 🟢
ottu/device/query.py 100% 🟢
ottu/plan.py 100% 🟢
ottu/report.py 100% 🟢
ottu/test.py 100% 🟢
ottu/test_path.py 100% 🟢
TOTAL 100% 🟢

updated for commit: 62db010 by action🐍

@jaenrig-ifx
jaenrig-ifx merged commit 8940bdc into main Nov 4, 2026
20 checks passed
@jaenrig-ifx
jaenrig-ifx deleted the arch-refactor branch November 4, 2026 10:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant