|
| 1 | +import sys |
| 2 | + |
| 3 | +import pytest |
| 4 | + |
1 | 5 | from socketsecurity.core.classes import Diff, Package |
| 6 | +from socketsecurity import socketcli |
2 | 7 | from socketsecurity.socketcli import build_license_artifact_payload |
3 | 8 |
|
4 | 9 |
|
| 10 | +# --------------------------------------------------------------------------- |
| 11 | +# Exit-code-on-api-error (flag-only, non-breaking for 2.3.x). |
| 12 | +# |
| 13 | +# Default behavior is unchanged from prior releases: unexpected errors exit 3, |
| 14 | +# and --disable-blocking forces exit 0 for everything. The flag only changes |
| 15 | +# the code when explicitly set, and --disable-blocking still takes precedence. |
| 16 | +# --------------------------------------------------------------------------- |
| 17 | + |
| 18 | + |
| 19 | +def _run_cli_expecting_exit(monkeypatch, argv, boom=None): |
| 20 | + def fail_main_code(): |
| 21 | + raise (boom or RuntimeError("infra boom")) |
| 22 | + |
| 23 | + monkeypatch.setattr(socketcli, "main_code", fail_main_code) |
| 24 | + monkeypatch.setattr(sys, "argv", argv) |
| 25 | + with pytest.raises(SystemExit) as exc_info: |
| 26 | + socketcli.cli() |
| 27 | + return exc_info.value.code |
| 28 | + |
| 29 | + |
| 30 | +def test_unexpected_error_exits_3_by_default(monkeypatch): |
| 31 | + code = _run_cli_expecting_exit(monkeypatch, ["socketcli", "--api-token", "test"]) |
| 32 | + assert code == 3 |
| 33 | + |
| 34 | + |
| 35 | +def test_exit_code_on_api_error_remaps_failure(monkeypatch): |
| 36 | + code = _run_cli_expecting_exit( |
| 37 | + monkeypatch, |
| 38 | + ["socketcli", "--api-token", "test", "--exit-code-on-api-error", "100"], |
| 39 | + ) |
| 40 | + assert code == 100 |
| 41 | + |
| 42 | + |
| 43 | +def test_disable_blocking_overrides_exit_code_on_api_error(monkeypatch): |
| 44 | + # The documented interaction: --disable-blocking forces exit 0 for ALL |
| 45 | + # outcomes and therefore overrides --exit-code-on-api-error. A user who |
| 46 | + # sets both gets 0, NOT 100 -- this guards against silently regressing |
| 47 | + # that precedence (which would break the documented soft_fail guidance). |
| 48 | + code = _run_cli_expecting_exit( |
| 49 | + monkeypatch, |
| 50 | + [ |
| 51 | + "socketcli", "--api-token", "test", |
| 52 | + "--exit-code-on-api-error", "100", |
| 53 | + "--disable-blocking", |
| 54 | + ], |
| 55 | + ) |
| 56 | + assert code == 0 |
| 57 | + |
| 58 | + |
| 59 | +def test_keyboard_interrupt_still_exits_2(monkeypatch): |
| 60 | + code = _run_cli_expecting_exit( |
| 61 | + monkeypatch, ["socketcli", "--api-token", "test"], boom=KeyboardInterrupt() |
| 62 | + ) |
| 63 | + assert code == 2 |
| 64 | + |
| 65 | + |
| 66 | +# --------------------------------------------------------------------------- |
| 67 | +# Buildkite-aware infrastructure error formatting. |
| 68 | +# --------------------------------------------------------------------------- |
| 69 | + |
| 70 | + |
| 71 | +def test_emit_infra_error_no_buildkite_has_no_markers(monkeypatch, capsys, caplog): |
| 72 | + monkeypatch.setattr(socketcli, "IS_BUILDKITE", False) |
| 73 | + with caplog.at_level("ERROR", logger="socketcli"): |
| 74 | + socketcli._emit_infrastructure_error("something failed") |
| 75 | + out = capsys.readouterr().out |
| 76 | + assert "^^^ +++" not in out |
| 77 | + assert "--- :warning:" not in out |
| 78 | + assert "soft_fail" not in "\n".join(r.getMessage() for r in caplog.records) |
| 79 | + |
| 80 | + |
| 81 | +def test_emit_infra_error_buildkite_emits_markers(monkeypatch, capsys, caplog): |
| 82 | + monkeypatch.setattr(socketcli, "IS_BUILDKITE", True) |
| 83 | + with caplog.at_level("ERROR", logger="socketcli"): |
| 84 | + socketcli._emit_infrastructure_error("something failed") |
| 85 | + out = capsys.readouterr().out |
| 86 | + assert "^^^ +++" in out |
| 87 | + assert "--- :warning: Socket infrastructure error" in out |
| 88 | + assert "soft_fail" in "\n".join(r.getMessage() for r in caplog.records) |
| 89 | + |
| 90 | + |
| 91 | +def test_emit_infra_error_traceback_gated(monkeypatch, capsys): |
| 92 | + monkeypatch.setattr(socketcli, "IS_BUILDKITE", False) |
| 93 | + try: |
| 94 | + raise ValueError("boom") |
| 95 | + except ValueError: |
| 96 | + socketcli._emit_infrastructure_error("wrapped", include_traceback=True) |
| 97 | + err = capsys.readouterr().err |
| 98 | + assert "Traceback" in err and "ValueError: boom" in err |
| 99 | + |
| 100 | + |
5 | 101 | def test_build_license_artifact_payload_without_packages_returns_empty_dict(): |
6 | 102 | diff = Diff() |
7 | 103 |
|
|
0 commit comments