112 lines
4.6 KiB
Python
112 lines
4.6 KiB
Python
"""Tests for the TUI re-issue workflow (CursesApp._process_cert).
|
|
|
|
Uses the same mock-curses approach as test_dialogs.py — no real terminal
|
|
needed. _msg()/_error() swallow curses.error, so a MagicMock stdscr is enough
|
|
as long as getmaxyx() returns real ints.
|
|
"""
|
|
from unittest.mock import MagicMock, patch
|
|
import curses as _curses
|
|
|
|
# Stub curses constants/callables before importing the module under test.
|
|
_curses.color_pair = lambda x: 0
|
|
_curses.A_BOLD = 0
|
|
_curses.A_UNDERLINE = 0
|
|
_curses.curs_set = lambda x: None
|
|
|
|
from openvpncertupdate import CursesApp, CertFormResult
|
|
|
|
|
|
def _stdscr():
|
|
s = MagicMock()
|
|
s.getmaxyx.return_value = (24, 80) # `sh - 2` needs a real int
|
|
s.getch.return_value = ord("q")
|
|
return s
|
|
|
|
|
|
def _patch_workflow(monkeypatch, cert_file_present):
|
|
"""Patch everything _process_cert touches after the form is confirmed."""
|
|
monkeypatch.setattr(
|
|
"openvpncertupdate.show_cert_form",
|
|
MagicMock(return_value=CertFormResult(
|
|
cn="y.kuts", email="", password="Testpass1234567890abcdefgh",
|
|
confirmed=True)))
|
|
monkeypatch.setattr("openvpncertupdate.has_issued_cert",
|
|
MagicMock(return_value=cert_file_present))
|
|
for name, retval in (
|
|
("revoke_issued", None),
|
|
("gen_crl", None),
|
|
("copy_crl", None),
|
|
("build_client_full", None),
|
|
("build_ovpn", "/out/y.kuts_2026-08-15_01/client.ovpn"),
|
|
("create_note", "https://cg.example.com/note/abc#deadbeef"),
|
|
):
|
|
monkeypatch.setattr(f"openvpncertupdate.{name}",
|
|
MagicMock(return_value=retval))
|
|
import openvpncertupdate as m
|
|
return {n: getattr(m, n) for n in (
|
|
"revoke_issued", "gen_crl", "copy_crl", "build_client_full")}
|
|
|
|
|
|
def test_tui_reissue_skips_revoke_when_cert_file_missing(monkeypatch):
|
|
# The bug as reported: the TUI offered renewal for a CN whose .crt was
|
|
# never carried over from the older EasyRSA install, and revoke-issued
|
|
# failed. There is nothing to revoke — build the replacement instead.
|
|
mocks = _patch_workflow(monkeypatch, cert_file_present=False)
|
|
app = CursesApp()
|
|
assert app._process_cert(_stdscr(), "y.kuts", "", is_renewal=True) is True
|
|
mocks["revoke_issued"].assert_not_called()
|
|
mocks["gen_crl"].assert_not_called()
|
|
mocks["copy_crl"].assert_not_called()
|
|
mocks["build_client_full"].assert_called_once()
|
|
assert mocks["build_client_full"].call_args.args[2] == "y.kuts"
|
|
|
|
|
|
def test_tui_reissue_logs_the_skip(monkeypatch):
|
|
_patch_workflow(monkeypatch, cert_file_present=False)
|
|
app = CursesApp()
|
|
app._process_cert(_stdscr(), "y.kuts", "", is_renewal=True)
|
|
assert any("revoke skipped" in e for e in app._session_log)
|
|
|
|
|
|
def test_tui_reissue_revokes_when_cert_file_present(monkeypatch):
|
|
mocks = _patch_workflow(monkeypatch, cert_file_present=True)
|
|
app = CursesApp()
|
|
assert app._process_cert(_stdscr(), "y.kuts", "", is_renewal=True) is True
|
|
mocks["revoke_issued"].assert_called_once()
|
|
mocks["gen_crl"].assert_called_once()
|
|
mocks["copy_crl"].assert_called_once()
|
|
mocks["build_client_full"].assert_called_once()
|
|
|
|
|
|
def test_tui_skipped_revoke_build_failure_does_not_claim_revocation(monkeypatch):
|
|
# Nothing was revoked, so the "has been revoked" warning would be a lie.
|
|
import openvpncertupdate as m
|
|
_patch_workflow(monkeypatch, cert_file_present=False)
|
|
monkeypatch.setattr("openvpncertupdate.build_client_full",
|
|
MagicMock(side_effect=m.EasyRSAError("boom")))
|
|
app = CursesApp()
|
|
shown = []
|
|
monkeypatch.setattr(CursesApp, "_error",
|
|
lambda self, stdscr, text: shown.append(text))
|
|
app._process_cert(_stdscr(), "y.kuts", "", is_renewal=True)
|
|
assert shown and "has been revoked" not in shown[0]
|
|
|
|
|
|
def test_tui_seeds_days_field_from_cert_days(monkeypatch):
|
|
import openvpncertupdate as m
|
|
_patch_workflow(monkeypatch, cert_file_present=True)
|
|
monkeypatch.setattr("openvpncertupdate.CERT_DAYS", "90")
|
|
CursesApp()._process_cert(_stdscr(), "y.kuts", "", is_renewal=True)
|
|
assert m.show_cert_form.call_args.kwargs["days"] == "90"
|
|
|
|
|
|
def test_tui_forwards_form_days_to_build_client_full(monkeypatch):
|
|
mocks = _patch_workflow(monkeypatch, cert_file_present=True)
|
|
monkeypatch.setattr(
|
|
"openvpncertupdate.show_cert_form",
|
|
MagicMock(return_value=CertFormResult(
|
|
cn="y.kuts", email="", password="Testpass1234567890abcdefgh",
|
|
days="30", confirmed=True)))
|
|
CursesApp()._process_cert(_stdscr(), "y.kuts", "", is_renewal=True)
|
|
assert mocks["build_client_full"].call_args.kwargs["days"] == "30"
|