# How the vt_resolver Plugin Selects Which Tests to Run Based on Configuration Filters

> Learn how the vt_resolver plugin uses configuration filters like only_filter and no_filter to select specific tests for execution within the avocado-framework.

- Repository: [avocado/avocado-vt](https://github.com/avocado-framework/avocado-vt)
- Tags: how-to-guide
- Published: 2026-02-25

---

**The vt_resolver plugin constructs a Cartesian configuration parser, applies cascading default and user-defined filters (including `only_filter` and `no_filter`), optionally restricts results by test reference, and converts surviving parameter combinations into Avocado Runnable objects for execution.**

The vt_resolver plugin serves as the critical bridge between Avocado-VT's cartesian configuration system and Avocado's test resolution engine. When you execute a test command, this plugin determines exactly which tests to run by filtering the full Cartesian product of test parameters according to your configuration settings and command-line options.

## Entry Point and Resolution Flow

The resolution process begins in [`avocado_vt/plugins/vt_resolver.py`](https://github.com/avocado-framework/avocado-vt/blob/main/avocado_vt/plugins/vt_resolver.py) within the `VTResolver.resolve()` method:

```python
class VTResolver(VTResolverUtils, Resolver):
    name = "vt"
    description = "Test resolver for Avocado-VT tests"

    def resolve(self, reference):
        """Resolve vt test references into resolutions."""
        return self._get_reference_resolution(reference)

```

The `resolve()` method receives a test reference string (which may be empty) and delegates to `_get_reference_resolution()`. This internal method orchestrates the entire filtering pipeline before returning a `ReferenceResolution` object indicating success or failure.

## Building the Cartesian Parser with VirtTestOptionsProcess

Before applying filters, the resolver must construct a Cartesian parser populated with base configuration values. This occurs in [`avocado_vt/discovery.py`](https://github.com/avocado-framework/avocado-vt/blob/main/avocado_vt/discovery.py) through the `DiscoveryMixIn` class:

```python
class DiscoveryMixIn:
    def _get_parser(self):
        options_processor = VirtTestOptionsProcess(self.config)
        return options_processor.get_parser()

```

The `VirtTestOptionsProcess` class (defined in [`avocado_vt/options.py`](https://github.com/avocado-framework/avocado-vt/blob/main/avocado_vt/options.py)) serves as the configuration engine. Its `get_parser()` method returns a fully configured `cartesian_config.Parser` instance that has already processed all default and user-specified options.

## Applying Configuration Filters in Three Stages

The filtering logic operates in distinct phases within `VirtTestOptionsProcess._process_options()` (lines 48-80 of [`avocado_vt/options.py`](https://github.com/avocado-framework/avocado-vt/blob/main/avocado_vt/options.py)). Each phase narrows the test set further.

### Default Filters and Exclusions

When no explicit `vt.config` file is provided, the system loads [`tests-shared.cfg`](https://github.com/avocado-framework/avocado-vt/blob/main/tests-shared.cfg) and applies built-in default filters. Lines 53-68 check the `vt.filter.default_filters` configuration and automatically exclude specific test variants unless explicitly overridden:

```python
for arg in ("no_9p_export", "no_virtio_rng", ...):
    if arg not in get_opt(self.config, "vt.filter.default_filters"):
        self.cartesian_parser.only_filter(arg)

```

These hardcoded exclusions prevent running tests that require unsupported features (such as 9p exports or virtio RNG devices) unless the user explicitly opts into them via the default_filters setting.

### User-Defined Only and No Filters

The resolver processes explicit user filters through dedicated methods that parse space-separated values from the configuration. For `vt.only_filter`:

```python
def _process_only_filter(self):
    if get_opt(self.config, "vt.only_filter"):
        for item in get_opt(self.config, "vt.only_filter").split(" "):
            self.cartesian_parser.only_filter(item)

```

An identical pattern exists for `vt.no_filter` in `_process_no_filter()`, which calls `self.cartesian_parser.no_filter(item)` for each token. These methods allow precise inclusion or exclusion of test variants based on tags, architectures, or custom labels.

### Reference-Based Filtering

After the general configuration filters are applied, the resolver performs a final narrowing step in [`avocado_vt/plugins/vt_resolver.py`](https://github.com/avocado-framework/avocado-vt/blob/main/avocado_vt/plugins/vt_resolver.py) if the user provided a specific test reference:

```python
if reference != "":
    cartesian_parser.only_filter(reference)

```

This step ensures that when you run `avocado vt run mysuite/virtio_net`, the resolver restricts results to variants matching that specific reference while still respecting all previously applied configuration filters.

## Converting Filtered Parameters to Avocado Runnables

Once filtering is complete, the resolver retrieves the surviving parameter combinations via `cartesian_parser.get_dicts()` and converts each into an Avocado nrunner `Runnable`. The conversion occurs in `_parameters_to_runnable()`:

```python
def _parameters_to_runnable(self, params):
    params = self.convert_parameters(params)
    uri = params.get("name")
    vt_params = params.get("vt_params")
    for key in ("_name_map_file", "_short_name_map_file", "dep"):
        if key in vt_params:
            del vt_params[key]
    return Runnable("avocado-vt", uri, **vt_params)

```

The `convert_parameters()` method (lines 41-64 of [`avocado_vt/discovery.py`](https://github.com/avocado-framework/avocado-vt/blob/main/avocado_vt/discovery.py)) extracts the test name and packages remaining cartesian variables into `vt_params`. The resulting `Runnable` objects carry all necessary configuration to execute the specific test variants.

## Practical Usage Examples

To run tests while applying specific configuration filters:

```bash

# Apply custom only-filters while respecting default exclusions

avocado vt run --vt-only-filter "up smp2" --vt-no-filter "no_9p_export"

# Request a specific test reference with additional filtering

avocado vt run mysuite/virtio_net --vt-only-filter "nic_custom"

```

In the first command, the resolver applies default filters (excluding `no_9p_export` unless overridden), then adds the user-specified `only_filter` tokens ("up", "smp2") and `no_filter` exclusions. In the second command, the resolver additionally restricts results to variants matching the `mysuite/virtio_net` reference.

## Summary

- The **vt_resolver** plugin coordinates test selection through a multi-stage filtering pipeline implemented across [`avocado_vt/plugins/vt_resolver.py`](https://github.com/avocado-framework/avocado-vt/blob/main/avocado_vt/plugins/vt_resolver.py), [`avocado_vt/discovery.py`](https://github.com/avocado-framework/avocado-vt/blob/main/avocado_vt/discovery.py), and [`avocado_vt/options.py`](https://github.com/avocado-framework/avocado-vt/blob/main/avocado_vt/options.py).
- **Default filters** automatically exclude unsupported test variants (such as `no_9p_export`) unless explicitly included via `vt.filter.default_filters`.
- **User-defined filters** (`vt.only_filter` and `vt.no_filter`) parse space-separated tokens to narrow the test set according to specific requirements.
- **Reference filtering** provides a final narrowing step when users specify explicit test paths, ensuring only matching variants are returned.
- Surviving parameter sets are converted into **Avocado Runnables** via `_parameters_to_runnable()`, enabling execution through Avocado's nrunner architecture.

## Frequently Asked Questions

### How do default filters interact with user-specified only_filter options?

Default filters apply first during `VirtTestOptionsProcess._process_options()` in [`avocado_vt/options.py`](https://github.com/avocado-framework/avocado-vt/blob/main/avocado_vt/options.py) (lines 53-68), excluding variants like `no_9p_export` unless listed in `vt.filter.default_filters`. User-specified `vt.only_filter` values are applied afterward through `_process_only_filter()`, further narrowing the set. The final test list represents the intersection of all applied filters.

### Can I override the default exclusion of specific test variants?

Yes. The default filters check `vt.filter.default_filters` before applying hardcoded exclusions such as `no_9p_export` or `no_virtio_rng`. If you include these specific tokens in your `vt.filter.default_filters` configuration, the `VirtTestOptionsProcess` class skips the automatic `only_filter()` call for those arguments, effectively including them in the test set.

### What happens when I provide a specific test reference to the resolver?

When `VTResolver.resolve()` receives a non-empty reference string, the `_get_reference_resolution()` method in [`avocado_vt/plugins/vt_resolver.py`](https://github.com/avocado-framework/avocado-vt/blob/main/avocado_vt/plugins/vt_resolver.py) applies an additional `only_filter(reference)` call to the Cartesian parser (line 37). This ensures the final parameter set includes only variants matching your specific reference, such as `mysuite/virtio_net`, while still respecting all previously applied configuration filters.

### How are the filtered parameters converted into executable tests?

After filtering, `cartesian_parser.get_dicts()` yields the surviving parameter dictionaries. The `_parameters_to_runnable()` method in [`avocado_vt/plugins/vt_resolver.py`](https://github.com/avocado-framework/avocado-vt/blob/main/avocado_vt/plugins/vt_resolver.py) processes these through `convert_parameters()` (defined in [`avocado_vt/discovery.py`](https://github.com/avocado-framework/avocado-vt/blob/main/avocado_vt/discovery.py), lines 41-64) to extract the test URI and `vt_params`. It then instantiates an `Runnable("avocado-vt", uri, **vt_params)` object that Avocado's nrunner architecture executes.