Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion nac_test/robot/pabot.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# Copyright (c) 2025 Daniel Schmidt

import logging
import sysconfig
from pathlib import Path

import pabot.pabot
Expand Down Expand Up @@ -52,7 +53,22 @@ def run_pabot(
include = include or []
exclude = exclude or []
robot_args: list[str] = []
pabot_args = ["--pabotlib", "--pabotlibport", "0"]
# Resolve robot binary from the current venv's scripts directory so that pabot
# finds the correct robot installation inside the current (possibly isolated)
# virtual environment, rather than relying on a bare `robot` on PATH.
robot_path = Path(sysconfig.get_path("scripts")) / "robot"
if not robot_path.exists():
raise RuntimeError(
"robot executable not found - ensure robotframework is installed in the same environment as nac-test"
)
pabot_args = [
"--command",
str(robot_path),
"--end-command",
"--pabotlib",
"--pabotlibport",
"0",
]

if ordering_file and ordering_file.exists():
pabot_args.extend(["--testlevelsplit", "--ordering", str(ordering_file)])
Expand Down
46 changes: 46 additions & 0 deletions tests/unit/robot/test_pabot_error_handling.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,52 @@ def test_run_pabot_unexpected_exception(self, mock_main_program: MagicMock) -> N
run_pabot(output_path)


# --- Robot executable resolution tests ---


class TestRunPabotRobotExecutableResolution:
"""Test that run_pabot resolves the robot binary via sysconfig."""

@patch("nac_test.robot.pabot.pabot.pabot.main_program")
def test_run_pabot_resolves_robot_using_sysconfig(
self, mock_main_program: MagicMock, tmp_path: Path
) -> None:
"""Test that robot executable is resolved using sysconfig.get_path('scripts')."""
fake_scripts_dir = tmp_path / "scripts"
fake_scripts_dir.mkdir()
fake_robot_executable = fake_scripts_dir / "robot"
fake_robot_executable.touch()
mock_main_program.return_value = 0

with patch(
"nac_test.robot.pabot.sysconfig.get_path",
return_value=str(fake_scripts_dir),
):
run_pabot(tmp_path)

call_args = mock_main_program.call_args[0][0]
assert "--command" in call_args
command_idx = call_args.index("--command")
assert call_args[command_idx + 1] == str(fake_robot_executable)

@patch("nac_test.robot.pabot.pabot.pabot.main_program")
def test_run_pabot_raises_runtime_error_when_robot_not_found(
self, mock_main_program: MagicMock, tmp_path: Path
) -> None:
"""Test that RuntimeError is raised when robot executable does not exist."""
fake_scripts_dir = tmp_path / "scripts"
fake_scripts_dir.mkdir()

with patch(
"nac_test.robot.pabot.sysconfig.get_path",
return_value=str(fake_scripts_dir),
):
with pytest.raises(RuntimeError, match="robot executable not found"):
run_pabot(tmp_path)

mock_main_program.assert_not_called()


class TestValidateExtraArgsDataError:
"""Test DataError handling in validate_extra_args."""

Expand Down
Loading