78 lines
2.5 KiB
Python
78 lines
2.5 KiB
Python
from __future__ import annotations
|
|
|
|
import os
|
|
|
|
import pytest
|
|
|
|
from opensquilla.execution_status import execution_status_for_tool_result
|
|
from opensquilla.tools.builtin import shell
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("command", "output"),
|
|
[
|
|
(
|
|
"pytest -q 2>&1 | head -50",
|
|
"FAILED tests/test_api.py::test_bad - AssertionError\n",
|
|
),
|
|
(
|
|
"pytest -q 2>&1 | tail -50",
|
|
"=========================== 2 failed, 10 passed in 1.2s ===========================\n",
|
|
),
|
|
(
|
|
"python -m unittest 2>&1 | head",
|
|
"FAILED (failures=1, errors=1)\n",
|
|
),
|
|
(
|
|
"npm test 2>&1 | head -100",
|
|
(
|
|
"Test Suites: 1 failed, 4 passed, 5 total\n"
|
|
"Tests: 2 failed, 20 passed, 22 total\n"
|
|
),
|
|
),
|
|
(
|
|
"npm test 2>&1 | head -100",
|
|
"FAIL src/auth.test.ts\n login\n Expected true to be false\n",
|
|
),
|
|
],
|
|
)
|
|
def test_masked_pipeline_detects_common_test_failure_summaries(
|
|
command: str,
|
|
output: str,
|
|
) -> None:
|
|
assert shell._looks_like_masked_pipeline_failure(command, 0, output)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
@pytest.mark.skipif(os.name != "posix", reason="pipeline semantics are POSIX-specific")
|
|
async def test_exec_command_warns_when_pipeline_masks_failure() -> None:
|
|
result = await shell.exec_command(
|
|
"sh -c 'echo BUILD FAILURE; exit 1' 2>&1 | head -20"
|
|
)
|
|
|
|
assert result.startswith("exit_code=0\n[shell_warning:masked_pipeline_failure]")
|
|
assert "Treat this result as failed" in result
|
|
status = execution_status_for_tool_result("exec_command", result)
|
|
assert status is not None
|
|
assert status["status"] == "error"
|
|
assert status["exit_code"] == 0
|
|
assert status["reason"] == "masked_pipeline_failure"
|
|
assert status["preservation_class"] == "diagnostic"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
@pytest.mark.skipif(os.name != "posix", reason="pipeline semantics are POSIX-specific")
|
|
async def test_exec_command_does_not_warn_for_intentional_shell_fallback(tmp_path) -> None:
|
|
haystack = tmp_path / "haystack.txt"
|
|
haystack.write_text("present\n", encoding="utf-8")
|
|
|
|
result = await shell.exec_command(
|
|
f"grep definitely-missing {haystack} || echo 'File not found'"
|
|
)
|
|
|
|
assert result == "exit_code=0\nFile not found\n"
|
|
status = execution_status_for_tool_result("exec_command", result)
|
|
assert status is not None
|
|
assert status["status"] == "success"
|
|
assert status["reason"] is None
|