Skip to content

[conditional_mark] Fix nodeid normalization so skips apply when rootdir floats above tests/#25930

Merged
lguohan merged 2 commits into
sonic-net:masterfrom
nhegde-microsoft:csonic-fix/conditional-mark-nodeid-tests-prefix
Jul 8, 2026
Merged

[conditional_mark] Fix nodeid normalization so skips apply when rootdir floats above tests/#25930
lguohan merged 2 commits into
sonic-net:masterfrom
nhegde-microsoft:csonic-fix/conditional-mark-nodeid-tests-prefix

Conversation

@nhegde-microsoft

@nhegde-microsoft nhegde-microsoft commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Fixes #25929

ADO: https://msazure.visualstudio.com/One/_workitems/edit/38913902

Description of PR

conditional_mark matches each test's item.nodeid against the tests-mark-conditions files, whose keys are relative to the tests/ directory (e.g. platform_tests/api). Before matching, pytest_collection_modifyitems normalizes the nodeid by stripping basename(rootpath) + "/" (added for pytest 9.0+ in #22944).

That normalization breaks when pytest's rootdir is not the tests/ directory. When the harness is invoked with a path argument outside tests/ (e.g. run_tests.sh passes --inventory ../ansible/veos_vtb), pytest 9.0 floats rootdir up to the sonic-mgmt checkout root, so item.nodeid becomes tests/platform_tests/api/.... root_prefix is then basename(<checkout>)/, which does not prefix tests/...; the strip no-ops, the tests/ survives, and every nodeid.startswith(<key>) fails. Result: no conditional mark is applied at all (Found match: 0, skipped: 0).

Practically, on a virtual-switch (asic_type: vs) DUT the platform_tests/api: skip if asic_type in ['vs'] rule stops firing, so those tests run and error with No module named 'sonic_platform' instead of skipping with "Unsupported platform API".

This PR adds a second normalization step: after stripping basename(rootpath), also strip a leading tests/ so nodeids match the tests/-relative rule keys regardless of where pytest resolved rootdir.

Type of change

  • Bug fix
  • Testbed and Framework (new/improvement)
  • New Test case
  • Test case enhancement
  • Skipped for non-supported platforms

Back port request

  • 202305
  • 202311
  • 202405
  • 202411
  • 202505
  • 202605

Tested branch

  • master
  • 202305
  • 202311
  • 202405
  • 202411
  • 202505
  • 202605
  • N/A

Test result

  • master: on a virtual-switch (asic_type: vs) testbed through run_tests.sh, the platform API cases changed from errors to the expected conditional skips/xfails.
  • 202605: testbed-bjw-can-720dt-3 (m0, Arista-720DT-G48S4) on SONiC.20260510.06; with this node-ID normalization change and the [route]: Skip warm reboot tests on m0/m1/mx #26340 conditional marks applied to the 202605 test branch, targeted tests/run_tests.sh completed with 3 skipped, 0 failures, exit 0 in 43.88 seconds. This standard-runner path previously retained the leading tests/ and bypassed the marks.

Approach

What is the motivation for this PR?

Conditional skips/xfails are silently ignored whenever pytest's rootdir resolves above tests/ (which happens with the standard run_tests.sh invocation that passes ../-relative paths). This causes false ERRORs for tests that are supposed to skip — most visibly the platform_tests/api suite on virtual-switch DUTs, but it affects every conditional rule in that run mode.

How did you do it?

In pytest_collection_modifyitems, after the existing basename(rootpath) strip, also strip a leading tests/ from the nodeid before matching against the condition keys.

How did you verify/test it?

On a virtual-switch (asic_type: vs) testbed via run_tests.sh (which passes --inventory ../ansible/veos_vtb, i.e. the rootdir-floats-up case):

Test Before After
platform_tests/api/test_watchdog.py 8 errors (No module named 'sonic_platform') 8 skipped ("Unsupported platform API")
platform_tests/api/test_psu.py errors 14 skipped ("Unsupported platform API")
platform_tests/sfp/test_sfputil.py errors asic_type in ['vs'] xfail rule fires (4 xfailed)

The sfp case exercises a different conditions file and an xfail (not skip) rule, confirming the fix restores conditional-mark matching globally rather than only for platform_tests/api.

flake8 --max-line-length=120 clean.

The 202605 target-branch validation used the standard test runner with the backported normalization change and confirmed that all three #26340 warm-reboot conditions matched and skipped before entering the reboot path.

Documentation

  • Yes
  • No

@mssonicbld

Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@nhegde-microsoft
nhegde-microsoft requested a review from lguohan July 6, 2026 21:38
@nhegde-microsoft nhegde-microsoft added bug csonic Issues related to cSONiC (docker-sonic-vs) neighbors in KVM testbed labels Jul 6, 2026
…ir floats up

conditional_mark's rule keys are relative to the tests/ directory (e.g.
"platform_tests/api"). To match them, pytest_collection_modifyitems normalizes
each item.nodeid by stripping basename(rootpath)+"/" (added for pytest 9.0+ in
PR sonic-net#22944).

That normalization is insufficient when pytest's rootdir is not the tests/
directory. When the test harness is invoked with a path argument that lives
outside tests/ (for example `--inventory ../ansible/veos_vtb`, as run_tests.sh
does), pytest 9.0 floats rootdir up to the sonic-mgmt checkout root. item.nodeid
then carries a leading "tests/" segment ("tests/platform_tests/api/..."), while
root_prefix is basename(checkout)+"/", which does not prefix it. The strip
no-ops, the "tests/" survives, and every `nodeid.startswith(<key>)` comparison
fails -> no conditional mark is ever applied (Found match: 0, skipped: 0).

The practical effect is that all conditional skips/xfails silently stop firing
in that invocation mode. For example on a virtual-switch (asic_type: vs) DUT the
`platform_tests/api: skip if asic_type in ['vs']` rule no longer applies, so the
platform-API tests run and error with "No module named 'sonic_platform'" instead
of skipping ("Unsupported platform API").

Fix: after the existing basename(rootpath) strip, also strip a leading "tests/"
so nodeids match the tests/-relative rule keys regardless of where pytest
resolved rootdir.

Verified on a virtual-switch testbed: platform_tests/api/test_watchdog.py goes
from 8 errors to 8 skipped, platform_tests/api/test_psu.py to 14 skipped (all
"Unsupported platform API"), and platform_tests/sfp/test_sfputil.py's
`asic_type in ['vs']` xfail rule fires as expected.

Signed-off-by: Nikhil Hegde <nikhilhegde@microsoft.com>
@nhegde-microsoft
nhegde-microsoft force-pushed the csonic-fix/conditional-mark-nodeid-tests-prefix branch from 0d9f535 to 404f943 Compare July 6, 2026 22:51
@mssonicbld

Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@nhegde-microsoft
nhegde-microsoft marked this pull request as ready for review July 6, 2026 23:39
Signed-off-by: Nikhil Hegde <nikhilhegde@microsoft.com>
@mssonicbld

Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@nhegde-microsoft

Copy link
Copy Markdown
Contributor Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@lguohan
lguohan merged commit 3cf07f4 into sonic-net:master Jul 8, 2026
26 checks passed
selldinesh pushed a commit to selldinesh/sonic-mgmt that referenced this pull request Jul 16, 2026
…ir floats above tests/ (sonic-net#25930)

Fixes sonic-net#25929

### Description of PR

`conditional_mark` matches each test's `item.nodeid` against the
tests-mark-conditions files, whose keys are relative to the `tests/`
directory (e.g. `platform_tests/api`). Before matching,
`pytest_collection_modifyitems` normalizes the nodeid by stripping
`basename(rootpath) + "/"` (added for pytest 9.0+ in sonic-net#22944).

That normalization breaks when pytest's `rootdir` is not the `tests/`
directory. When the harness is invoked with a path argument outside
`tests/` (e.g. `run_tests.sh` passes `--inventory ../ansible/veos_vtb`),
pytest 9.0 floats `rootdir` up to the sonic-mgmt checkout root, so
`item.nodeid` becomes `tests/platform_tests/api/...`. `root_prefix` is
then `basename(<checkout>)/`, which does not prefix `tests/...`; the
strip no-ops, the `tests/` survives, and every
`nodeid.startswith(<key>)` fails. Result: **no conditional mark is
applied at all** (`Found match: 0`, `skipped: 0`).

Practically, on a virtual-switch (`asic_type: vs`) DUT the
`platform_tests/api: skip if asic_type in ['vs']` rule stops firing, so
those tests run and error with `No module named 'sonic_platform'`
instead of skipping with "Unsupported platform API".

This PR adds a second normalization step: after stripping
`basename(rootpath)`, also strip a leading `tests/` so nodeids match the
`tests/`-relative rule keys regardless of where pytest resolved
`rootdir`.

#### Type of change

- [ ] Bug fix
- [ ] Testbed and Framework (new/improvement)
- [ ] New Test case
- [x] Test case enhancement
- [ ] Skipped for non-supported platforms

### Back port request

- [ ] 202305
- [ ] 202311
- [ ] 202405
- [ ] 202411
- [ ] 202505

### Approach

#### What is the motivation for this PR?

Conditional skips/xfails are silently ignored whenever pytest's
`rootdir` resolves above `tests/` (which happens with the standard
`run_tests.sh` invocation that passes `../`-relative paths). This causes
false ERRORs for tests that are supposed to skip — most visibly the
`platform_tests/api` suite on virtual-switch DUTs, but it affects every
conditional rule in that run mode.

#### How did you do it?

In `pytest_collection_modifyitems`, after the existing
`basename(rootpath)` strip, also strip a leading `tests/` from the
nodeid before matching against the condition keys.

#### How did you verify/test it?

On a virtual-switch (`asic_type: vs`) testbed via `run_tests.sh` (which
passes `--inventory ../ansible/veos_vtb`, i.e. the rootdir-floats-up
case):

| Test | Before | After |
| --- | --- | --- |
| `platform_tests/api/test_watchdog.py` | 8 errors (`No module named
'sonic_platform'`) | **8 skipped** ("Unsupported platform API") |
| `platform_tests/api/test_psu.py` | errors | **14 skipped**
("Unsupported platform API") |
| `platform_tests/sfp/test_sfputil.py` | errors | `asic_type in ['vs']`
**xfail** rule fires (4 xfailed) |

The `sfp` case exercises a different conditions file and an `xfail` (not
`skip`) rule, confirming the fix restores conditional-mark matching
globally rather than only for `platform_tests/api`.

`flake8 --max-line-length=120` clean.

### Documentation

- [ ] Yes
- [x] No

---------

Signed-off-by: Nikhil Hegde <nikhilhegde@microsoft.com>
Signed-off-by: selldinesh <dinesh.sellappan@keysight.com>
selldinesh pushed a commit to selldinesh/sonic-mgmt that referenced this pull request Jul 16, 2026
…ir floats above tests/ (sonic-net#25930)

Fixes sonic-net#25929

### Description of PR

`conditional_mark` matches each test's `item.nodeid` against the
tests-mark-conditions files, whose keys are relative to the `tests/`
directory (e.g. `platform_tests/api`). Before matching,
`pytest_collection_modifyitems` normalizes the nodeid by stripping
`basename(rootpath) + "/"` (added for pytest 9.0+ in sonic-net#22944).

That normalization breaks when pytest's `rootdir` is not the `tests/`
directory. When the harness is invoked with a path argument outside
`tests/` (e.g. `run_tests.sh` passes `--inventory ../ansible/veos_vtb`),
pytest 9.0 floats `rootdir` up to the sonic-mgmt checkout root, so
`item.nodeid` becomes `tests/platform_tests/api/...`. `root_prefix` is
then `basename(<checkout>)/`, which does not prefix `tests/...`; the
strip no-ops, the `tests/` survives, and every
`nodeid.startswith(<key>)` fails. Result: **no conditional mark is
applied at all** (`Found match: 0`, `skipped: 0`).

Practically, on a virtual-switch (`asic_type: vs`) DUT the
`platform_tests/api: skip if asic_type in ['vs']` rule stops firing, so
those tests run and error with `No module named 'sonic_platform'`
instead of skipping with "Unsupported platform API".

This PR adds a second normalization step: after stripping
`basename(rootpath)`, also strip a leading `tests/` so nodeids match the
`tests/`-relative rule keys regardless of where pytest resolved
`rootdir`.

#### Type of change

- [ ] Bug fix
- [ ] Testbed and Framework (new/improvement)
- [ ] New Test case
- [x] Test case enhancement
- [ ] Skipped for non-supported platforms

### Back port request

- [ ] 202305
- [ ] 202311
- [ ] 202405
- [ ] 202411
- [ ] 202505

### Approach

#### What is the motivation for this PR?

Conditional skips/xfails are silently ignored whenever pytest's
`rootdir` resolves above `tests/` (which happens with the standard
`run_tests.sh` invocation that passes `../`-relative paths). This causes
false ERRORs for tests that are supposed to skip — most visibly the
`platform_tests/api` suite on virtual-switch DUTs, but it affects every
conditional rule in that run mode.

#### How did you do it?

In `pytest_collection_modifyitems`, after the existing
`basename(rootpath)` strip, also strip a leading `tests/` from the
nodeid before matching against the condition keys.

#### How did you verify/test it?

On a virtual-switch (`asic_type: vs`) testbed via `run_tests.sh` (which
passes `--inventory ../ansible/veos_vtb`, i.e. the rootdir-floats-up
case):

| Test | Before | After |
| --- | --- | --- |
| `platform_tests/api/test_watchdog.py` | 8 errors (`No module named
'sonic_platform'`) | **8 skipped** ("Unsupported platform API") |
| `platform_tests/api/test_psu.py` | errors | **14 skipped**
("Unsupported platform API") |
| `platform_tests/sfp/test_sfputil.py` | errors | `asic_type in ['vs']`
**xfail** rule fires (4 xfailed) |

The `sfp` case exercises a different conditions file and an `xfail` (not
`skip`) rule, confirming the fix restores conditional-mark matching
globally rather than only for `platform_tests/api`.

`flake8 --max-line-length=120` clean.

### Documentation

- [ ] Yes
- [x] No

---------

Signed-off-by: Nikhil Hegde <nikhilhegde@microsoft.com>
Signed-off-by: selldinesh <dinesh.sellappan@keysight.com>
ssithaia-ebay pushed a commit to ssithaia-ebay/sflow-yang-sonic-mgmt that referenced this pull request Jul 21, 2026
…ir floats above tests/ (sonic-net#25930)

Fixes sonic-net#25929

### Description of PR

`conditional_mark` matches each test's `item.nodeid` against the
tests-mark-conditions files, whose keys are relative to the `tests/`
directory (e.g. `platform_tests/api`). Before matching,
`pytest_collection_modifyitems` normalizes the nodeid by stripping
`basename(rootpath) + "/"` (added for pytest 9.0+ in sonic-net#22944).

That normalization breaks when pytest's `rootdir` is not the `tests/`
directory. When the harness is invoked with a path argument outside
`tests/` (e.g. `run_tests.sh` passes `--inventory ../ansible/veos_vtb`),
pytest 9.0 floats `rootdir` up to the sonic-mgmt checkout root, so
`item.nodeid` becomes `tests/platform_tests/api/...`. `root_prefix` is
then `basename(<checkout>)/`, which does not prefix `tests/...`; the
strip no-ops, the `tests/` survives, and every
`nodeid.startswith(<key>)` fails. Result: **no conditional mark is
applied at all** (`Found match: 0`, `skipped: 0`).

Practically, on a virtual-switch (`asic_type: vs`) DUT the
`platform_tests/api: skip if asic_type in ['vs']` rule stops firing, so
those tests run and error with `No module named 'sonic_platform'`
instead of skipping with "Unsupported platform API".

This PR adds a second normalization step: after stripping
`basename(rootpath)`, also strip a leading `tests/` so nodeids match the
`tests/`-relative rule keys regardless of where pytest resolved
`rootdir`.

#### Type of change

- [ ] Bug fix
- [ ] Testbed and Framework (new/improvement)
- [ ] New Test case
- [x] Test case enhancement
- [ ] Skipped for non-supported platforms

### Back port request

- [ ] 202305
- [ ] 202311
- [ ] 202405
- [ ] 202411
- [ ] 202505

### Approach

#### What is the motivation for this PR?

Conditional skips/xfails are silently ignored whenever pytest's
`rootdir` resolves above `tests/` (which happens with the standard
`run_tests.sh` invocation that passes `../`-relative paths). This causes
false ERRORs for tests that are supposed to skip — most visibly the
`platform_tests/api` suite on virtual-switch DUTs, but it affects every
conditional rule in that run mode.

#### How did you do it?

In `pytest_collection_modifyitems`, after the existing
`basename(rootpath)` strip, also strip a leading `tests/` from the
nodeid before matching against the condition keys.

#### How did you verify/test it?

On a virtual-switch (`asic_type: vs`) testbed via `run_tests.sh` (which
passes `--inventory ../ansible/veos_vtb`, i.e. the rootdir-floats-up
case):

| Test | Before | After |
| --- | --- | --- |
| `platform_tests/api/test_watchdog.py` | 8 errors (`No module named
'sonic_platform'`) | **8 skipped** ("Unsupported platform API") |
| `platform_tests/api/test_psu.py` | errors | **14 skipped**
("Unsupported platform API") |
| `platform_tests/sfp/test_sfputil.py` | errors | `asic_type in ['vs']`
**xfail** rule fires (4 xfailed) |

The `sfp` case exercises a different conditions file and an `xfail` (not
`skip`) rule, confirming the fix restores conditional-mark matching
globally rather than only for `platform_tests/api`.

`flake8 --max-line-length=120` clean.

### Documentation

- [ ] Yes
- [x] No

---------

Signed-off-by: Nikhil Hegde <nikhilhegde@microsoft.com>
Signed-off-by: ssithaia-ebay <ssithaian@ebay.com>
StormLiangMS pushed a commit that referenced this pull request Jul 21, 2026
### Description of PR

Summary:
Skip `test_static_route_warmboot`, `test_static_route_ipv6_warmboot`,
and `test_static_route_ecmp_warmboot` on all m0, m1, and mx topologies
through centralized conditional marks. Preserve the existing dualtor
exclusions.

ADO: https://msazure.visualstudio.com/One/_workitems/edit/38862000

### Type of change

- [ ] Bug fix
- [ ] Testbed and Framework(new/improvement)
- [ ] New Test case
    - [ ] Skipped for non-supported platforms
- [x] Test case improvement


### Back port request

- [ ] 202311
- [ ] 202405
- [ ] 202411
- [ ] 202505
- [ ] 202511
- [ ] 202512
- [x] 202605

Tracking issue/work item for backport/cherry-pick request (GitHub issue
or Microsoft ADO):
https://msazure.visualstudio.com/One/_workitems/edit/38862000
Failure type: day-one topology applicability gap

### Tested branch

- [x] master
- [ ] 202311
- [ ] 202405
- [ ] 202411
- [ ] 202505
- [ ] 202511
- [ ] 202512
- [x] 202605
- [ ] N/A

### Test result

- master: the conditional-mark YAML loads successfully; direct condition
evaluation verifies all three cases skip for m0, m1, mx, and dualtor,
while remaining runnable on t1.
- 202605: `testbed-bjw-can-720dt-3` (m0, `Arista-720DT-G48S4`) on
`SONiC.20260510.06`; targeted `tests/run_tests.sh` validation is being
refreshed for the topology-wide condition.
- 202605 prerequisite: the backport must also include conditional-mark
node-ID normalization fix #25930 (`3cf07f4b6bf3`). Without it, standard
`run_tests.sh` can produce `tests/...` node IDs and silently bypass
centralized conditional marks.
- Nightly evidence:
https://elastictest.org/scheduler/testplan/6a5b5cb0b2ac8cdc8af95b7d
reported the three warm-reboot cases failing across all six 720DT mx
testbeds.

### Approach
#### What is the motivation for this PR?

Recent m0/mx nightlies reported failures for the three static-route
warm-reboot tests. Warm-reboot coverage is not applicable to m0, m1, or
mx topologies, so these cases should not enter the reboot path on those
topologies.

#### How did you do it?

Extended each existing dualtor conditional skip with an OR condition
matching `topo_type in ['m0', 'm1', 'mx']`.

#### How did you verify/test it?

Reviewed the recent 720DT m0/mx failures and confirmed these are the
three logical cases that invoke warm reboot. Validated the YAML and
evaluated the conditions for m0, m1, mx, dualtor, and t1. The 202605
physical validation uses the standard test runner with the required
#25930 prerequisite.

#### Any platform specific information?

The condition is topology-based and applies to every platform running
m0, m1, or mx.

#### Supported testbed topology if it's a new test case?

Not a new test case. The new exclusions are m0, m1, and mx; the existing
dualtor exclusions remain.

### Documentation

Not applicable.

---------

Signed-off-by: Xichen96 <lukelin0907@gmail.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@mssonicbld

Copy link
Copy Markdown
Collaborator

Cherry-pick PR to msft-202608: Azure/sonic-mgmt.msft#1328

@mssonicbld

Copy link
Copy Markdown
Collaborator

This PR has backport request label(s) for branch(es): msft-202608, but is missing required test information. Please make sure you tick the tested branch(es) in the Tested branch section and provide test evidence (e.g., 202608: <test result>) in the Test result section as well in your PR description.

---Powered by SONiC BuildBot

@mssonicbld

Copy link
Copy Markdown
Collaborator

Cherry-pick PR to 202605: #26518

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[conditional_mark] Conditional skips silently ignored when rootdir floats above tests/ (nodeid keeps 'tests/' prefix)

6 participants