"""Unit tests for the validate-ticket handler action.""" from typing import Any from unittest.mock import patch import pytest import requests from jira_client.app import handler from jira_client.constants import TicketValidation class MockResponse: """Minimal mock of requests.Response.""" def __init__(self, status_code: int = 200, json_data: Any = None) -> None: """Initialize the mock response.""" self.status_code = status_code self._json_data = json_data or {} def raise_for_status(self) -> None: """Raise HTTPError for non-2xx status codes.""" if not (200 <= self.status_code < 300): raise requests.HTTPError(f'{self.status_code} error', response=self) def json(self) -> Any: """Return the JSON data.""" return self._json_data def _make_fields( reporter_email: str = 'jira-email-reporter@sonymusic-pde.com', include_footer_sentinel: bool = True, include_footer_email: bool = True, ) -> dict: """Build the Jira fields dict returned by get_ticket_fields.""" footer_text = '' if include_footer_sentinel: email_part = ( TicketValidation.FOOTER_EMAIL if include_footer_email else 'other@example.com' ) footer_text = f'[{TicketValidation.FOOTER_SENTINEL}: "{email_part}"]' return { 'reporter': {'emailAddress': reporter_email}, 'description': { 'content': [ { 'type': 'paragraph', 'content': [ {'type': 'text', 'text': f'Some ticket body. {footer_text}'} ], } ] }, } def _jira_env(monkeypatch: pytest.MonkeyPatch) -> None: """Set minimal Jira env vars required by JiraConfig.""" monkeypatch.setenv('JIRA_BASE_URL', 'https://jira.example.com') monkeypatch.setenv('JIRA_API_TOKEN', 'tok') monkeypatch.setenv('JIRA_USER_EMAIL', 'bot@example.com') @pytest.fixture(autouse=True) def reset_app_singletons() -> None: """Reset module-level singletons between tests.""" import jira_client.app jira_client.app._config = None jira_client.app._client = None yield # type: ignore[misc] jira_client.app._config = None jira_client.app._client = None class TestValidateTicket: """Tests for the 'validate-ticket' handler action.""" def test_valid_ticket(self, monkeypatch: pytest.MonkeyPatch) -> None: """A ticket with expected reporter and footer is valid with no warnings.""" _jira_env(monkeypatch) fields = _make_fields() with patch( 'requests.Session.get', return_value=MockResponse(200, {'fields': fields}), ): result = handler({'action': 'validate-ticket', 'ticket_id': 'SYS-1'}, {}) assert result['ticket_id'] == 'SYS-1' assert result['valid'] is True assert result['warnings'] == [] def test_invalid_reporter(self, monkeypatch: pytest.MonkeyPatch) -> None: """A ticket with an unexpected reporter email produces a warning.""" _jira_env(monkeypatch) fields = _make_fields(reporter_email='bad-actor@evil.com') with patch( 'requests.Session.get', return_value=MockResponse(200, {'fields': fields}), ): result = handler({'action': 'validate-ticket', 'ticket_id': 'SYS-2'}, {}) assert result['valid'] is False assert len(result['warnings']) == 1 assert 'bad-actor@evil.com' in result['warnings'][0] def test_missing_footer_sentinel(self, monkeypatch: pytest.MonkeyPatch) -> None: """A ticket with no footer sentinel text produces a warning.""" _jira_env(monkeypatch) fields = _make_fields(include_footer_sentinel=False) with patch( 'requests.Session.get', return_value=MockResponse(200, {'fields': fields}), ): result = handler({'action': 'validate-ticket', 'ticket_id': 'SYS-3'}, {}) assert result['valid'] is False assert len(result['warnings']) == 1 assert TicketValidation.FOOTER_SENTINEL in result['warnings'][0] def test_footer_sentinel_present_but_wrong_email( self, monkeypatch: pytest.MonkeyPatch ) -> None: """Footer sentinel present but helpdesk email missing produces a warning.""" _jira_env(monkeypatch) fields = _make_fields(include_footer_sentinel=True, include_footer_email=False) with patch( 'requests.Session.get', return_value=MockResponse(200, {'fields': fields}), ): result = handler({'action': 'validate-ticket', 'ticket_id': 'SYS-4'}, {}) assert result['valid'] is False assert len(result['warnings']) == 1 assert TicketValidation.FOOTER_EMAIL in result['warnings'][0] def test_invalid_reporter_and_missing_footer( self, monkeypatch: pytest.MonkeyPatch ) -> None: """A ticket with both invalid reporter and missing footer produces two warnings.""" _jira_env(monkeypatch) fields = _make_fields( reporter_email='someone@unknown.com', include_footer_sentinel=False ) with patch( 'requests.Session.get', return_value=MockResponse(200, {'fields': fields}), ): result = handler({'action': 'validate-ticket', 'ticket_id': 'SYS-5'}, {}) assert result['valid'] is False assert len(result['warnings']) == 2 def test_missing_reporter_field(self, monkeypatch: pytest.MonkeyPatch) -> None: """A ticket where reporter is absent in the API response produces a warning.""" _jira_env(monkeypatch) fields = { 'description': { 'content': [ { 'type': 'paragraph', 'content': [ { 'type': 'text', 'text': ( f'[{TicketValidation.FOOTER_SENTINEL}: ' f'"{TicketValidation.FOOTER_EMAIL}"]' ), } ], } ] } } with patch( 'requests.Session.get', return_value=MockResponse(200, {'fields': fields}), ): result = handler({'action': 'validate-ticket', 'ticket_id': 'SYS-6'}, {}) assert result['valid'] is False assert any('allowlist' in w for w in result['warnings'])