Skip to content

Support path-based test references in scenario files - #994

Open
shreyaskommuri wants to merge 2 commits into
NVIDIA:mainfrom
shreyaskommuri:issue/path-based-test-references
Open

Support path-based test references in scenario files#994
shreyaskommuri wants to merge 2 commits into
NVIDIA:mainfrom
shreyaskommuri:issue/path-based-test-references

Conversation

@shreyaskommuri

Copy link
Copy Markdown
Contributor

Summary

  • Adds an optional path field on TestRunModel, an alternative to test_name for referencing a test in a scenario file, resolved relative to the scenario file's own directory (confirmed shape in Support relative-path test references and lazy-load only referenced test/hook tomls #985).
  • test_name and path are mutually exclusive, same rules test_name already has with test_template_name.
  • TestScenarioParser._prepare_tdef gets a new branch: when path is set, it loads that toml file directly instead of doing a name lookup against test_mapping, then merges scenario-level overrides the same way the test_name branch already does.
  • Raises a clear TestScenarioParsingError if the resolved path does not exist.
  • This is PR1 of the two-PR plan discussed in Support relative-path test references and lazy-load only referenced test/hook tomls #985. PR2 (skip eager glob-and-parse of --tests-dir/hooks when a scenario's tests are all path-referenced) depends on this one and is not included here, keeping this PR small and reviewable on its own.
  • Fully backward compatible: test_name and fully-inline (test_template_name + name + description) scenarios are unaffected.

Test Plan

7 new tests in tests/test_test_scenario.py (TestPathReference), covering: path/test_name mutual exclusion, path/test_template_name mutual exclusion, relative-path resolution against the scenario file's directory, scenario-level override merging over the referenced file, a missing-file error, and a full scenario TOML parsed end to end with a path reference.

$ uv run pytest tests/test_test_scenario.py -q -k "TestPathReference"
.......
7 passed, 74 deselected in 0.04s

$ uv run pytest -q -m "not ci_only"
1848 passed, 5 skipped, 511 deselected in 4.47s

$ uv run pre-commit run --all-files
check for added large files..............................................Passed
check python ast.........................................................Passed
check for merge conflicts.................................................Passed
check toml................................................................Passed
check yaml.................................................................Passed
debug statements (python)..................................................Passed
fix end of files...........................................................Passed
mixed line ending..........................................................Passed
trim trailing whitespace...................................................Passed
pyright.....................................................................Passed
ruff check...................................................................Passed
ruff format...................................................................Passed
vulture.......................................................................Passed
import-linter..................................................................Passed
taplo...........................................................................Passed

Also updated the wording of two pre-existing validation error messages (in models/scenario.py) that referenced only test_name, so they stay accurate now that path is a second way to satisfy the same requirement. Updated the two existing tests in tests/test_test_scenario.py that asserted on the old wording.

Additional Notes

Design confirmed in #985 before writing any code, per CONTRIBUTING.md's "communicate with the main developers before starting work." Not touching the eager-loading behavior itself, sweeping, or anything unrelated, this PR is purely additive.

Add an optional 'path' field on TestRunModel, mutually exclusive with
'test_name', resolved relative to the scenario file's own directory.
When set, _prepare_tdef loads that file directly instead of doing a
name lookup against test_mapping, with the same scenario-level
override merging test_name already supports.

Ref: NVIDIA#985
Signed-off-by: shreyaskommuri <shreyaskommuri@gmail.com>
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

TestRunModel now accepts a scenario-relative TOML path as an alternative test reference. The parser resolves the path, loads the definition, applies scenario overrides, and reports missing files. Tests cover validation, loading, merging, and end-to-end parsing.

Changes

Scenario test path references

Layer / File(s) Summary
Test reference contract
src/cloudai/models/scenario.py, tests/test_test_scenario.py
TestRunModel adds the optional path field. Validation prevents conflicting references and updates inline-definition and template-name rules.
Path loading and validation
src/cloudai/test_scenario_parser.py, tests/test_test_scenario.py
TestScenarioParser resolves and loads scenario-relative test TOML files, merges overrides, and raises TestScenarioParsingError for missing files. Tests cover path resolution, merging, errors, and full scenario parsing.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Suggested reviewers: podkidyshev, jj10306

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: adding path-based test references in scenario files.
Description check ✅ Passed The description directly explains the path field, parser behavior, validation, tests, and backward compatibility.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/cloudai/models/scenario.py`:
- Around line 74-80: Update the Optional path field in TestRunModel to enforce
min_length=1, rejecting empty strings during validation while preserving None as
valid. Add a regression test covering path="" and verify validation fails before
_prepare_tdef is reached.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 5c512b3e-96c4-4630-84b6-898ffd08b847

📥 Commits

Reviewing files that changed from the base of the PR and between 5b5c0f7 and 1b62b6c.

📒 Files selected for processing (3)
  • src/cloudai/models/scenario.py
  • src/cloudai/test_scenario_parser.py
  • tests/test_test_scenario.py

Comment thread src/cloudai/models/scenario.py
Field(min_length=1) rejects path="" at validation time instead of
letting it through as a truthy-looking value that would otherwise
resolve to the scenario file's own directory.

Signed-off-by: shreyaskommuri <shreyaskommuri@gmail.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
tests/test_test_scenario.py (1)

1006-1032: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Exercise the public scenario parser in the end-to-end test.

At Lines 1027-1030, the test manually validates the TOML and calls private _prepare_tdef(). This verifies the helper and the model, but not the parser's public scenario-loading flow. If this test must provide end-to-end coverage, use the public parser entry point and assert the resulting scenario test. Otherwise, rename the test to indicate helper-level coverage.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_test_scenario.py` around lines 1006 - 1032, Update
test_full_scenario_toml_with_path_reference to exercise TestScenarioParser’s
public scenario-loading entry point instead of manually calling
TestScenarioModel.model_validate and private _prepare_tdef. Assert the resulting
parsed scenario test still has name "nccl", preserving end-to-end coverage of
the path reference flow.
src/cloudai/models/scenario.py (1)

159-159: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Reject an empty test_template_name with a path.

if self.test_template_name treats "" as unset. Therefore, TestRunModel(id="1", path="nccl.toml", test_template_name="") passes validation, although path and test_template_name are mutually exclusive. tdef_model_dump() retains the empty string, so _prepare_tdef() can merge it over the referenced definition. Use an is not None check and add a regression test.

Proposed validation fix
         else:
-            if self.test_template_name:
+            if self.test_template_name is not None:
                 raise ValueError("'test_template_name' must not be set if 'test_name' or 'path' is set.")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cloudai/models/scenario.py` at line 159, Update the validation involving
test_template_name in TestRunModel so an empty string is treated as explicitly
set when path or test_name is provided, using an is not None check rather than
truthiness; add a regression test covering path with test_template_name="".
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/test_test_scenario.py`:
- Around line 944-947: Update test_empty_path_is_rejected to pass the expected
error-message pattern directly via pytest.raises, and remove the separate
exc_info.match assertion.

---

Outside diff comments:
In `@src/cloudai/models/scenario.py`:
- Line 159: Update the validation involving test_template_name in TestRunModel
so an empty string is treated as explicitly set when path or test_name is
provided, using an is not None check rather than truthiness; add a regression
test covering path with test_template_name="".

In `@tests/test_test_scenario.py`:
- Around line 1006-1032: Update test_full_scenario_toml_with_path_reference to
exercise TestScenarioParser’s public scenario-loading entry point instead of
manually calling TestScenarioModel.model_validate and private _prepare_tdef.
Assert the resulting parsed scenario test still has name "nccl", preserving
end-to-end coverage of the path reference flow.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 171803a1-2257-46ce-b0ea-5491d6e62d78

📥 Commits

Reviewing files that changed from the base of the PR and between 1b62b6c and 7a17452.

📒 Files selected for processing (2)
  • src/cloudai/models/scenario.py
  • tests/test_test_scenario.py

Comment on lines +944 to +947
def test_empty_path_is_rejected(self):
with pytest.raises(ValueError) as exc_info:
TestRunModel(id="1", path="")
assert exc_info.match("String should have at least 1 character")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- target test ---'
sed -n '930,955p' tests/test_test_scenario.py

printf '%s\n' '--- Ruff configuration and PT011 references ---'
rg -n --hidden -g '!*.lock' -g '!node_modules' -g '!dist' \
  'PT011|flake8-pytest|pytest.raises|ruff' pyproject.toml setup.cfg tox.ini .ruff.toml ruff.toml tests 2>/dev/null || true

printf '%s\n' '--- Ruff availability ---'
if command -v ruff >/dev/null 2>&1; then
  ruff --version
  ruff check --select PT011 tests/test_test_scenario.py
else
  echo 'ruff is not available'
fi

Repository: NVIDIA/cloudai

Length of output: 24029


Pass the message to pytest.raises.

Ruff PT011 flags this test. Move the message match into pytest.raises and remove the separate assertion.

🧰 Tools
🪛 Ruff (0.16.1)

[warning] 945-945: pytest.raises(ValueError) is too broad, set the match parameter or use a more specific exception

(PT011)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_test_scenario.py` around lines 944 - 947, Update
test_empty_path_is_rejected to pass the expected error-message pattern directly
via pytest.raises, and remove the separate exc_info.match assertion.

Source: Linters/SAST tools

@shreyaskommuri

Copy link
Copy Markdown
Contributor Author

@podkidyshev the empty-path issue from CodeRabbit is resolved, min_length=1 pushed and confirmed rejecting "" while still allowing None/real paths (see reply on the review thread above), plus a regression test. All CI green on the latest commit. Let me know if there's anything else you'd like changed.

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.

2 participants