#!/usr/bin/env python3 from __future__ import annotations import tempfile import unittest from pathlib import Path from redmine_ticket_drafts import ( KIND_CUSTOMER_EMAIL, KIND_INTERNAL_NOTE, add_draft, assert_write_target_allowed, host_is_safe_for_writes, kind_label, list_drafts, load_draft, mark_draft_applied, normalize_kind, ) class DraftKindsTest(unittest.TestCase): def test_normalize_legacy(self): self.assertEqual(KIND_INTERNAL_NOTE, normalize_kind("note")) self.assertEqual(KIND_CUSTOMER_EMAIL, normalize_kind("helpdesk_reply")) def test_customer_email_cannot_be_private(self): with tempfile.TemporaryDirectory() as td: with self.assertRaises(ValueError): add_draft(Path(td), issue_id=1, kind=KIND_CUSTOMER_EMAIL, body="hi", private=True) def test_labels_are_explicit(self): self.assertIn("NOT email", kind_label(KIND_INTERNAL_NOTE)) self.assertIn("WILL email", kind_label(KIND_CUSTOMER_EMAIL)) def test_queue_and_list(self): with tempfile.TemporaryDirectory() as td: root = Path(td) p = add_draft(root, issue_id=42, kind=KIND_INTERNAL_NOTE, body="staff only", private=True) self.assertTrue(p.is_file()) items = list_drafts(root, status="pending") self.assertEqual(1, len(items)) self.assertFalse(items[0].get("emails_customer")) p2 = add_draft(root, issue_id=43, kind=KIND_CUSTOMER_EMAIL, body="hello customer") items = list_drafts(root, status="pending") self.assertEqual(2, len(items)) cust = [i for i in items if i["kind"] == KIND_CUSTOMER_EMAIL][0] self.assertTrue(cust.get("emails_customer")) mark_draft_applied(root, cust["id"], result={"ok": True}) pending = list_drafts(root, status="pending") self.assertEqual(1, len(pending)) def test_write_target_safety(self): self.assertTrue(host_is_safe_for_writes("http://192.168.50.170/")) self.assertTrue(host_is_safe_for_writes("http://retired.int.ldrprep.com")) self.assertFalse(host_is_safe_for_writes("https://rm.ldrprep.com")) with self.assertRaises(RuntimeError): assert_write_target_allowed("https://rm.ldrprep.com", allow_prod_writes=False) assert_write_target_allowed("https://rm.ldrprep.com", allow_prod_writes=True) assert_write_target_allowed("http://192.168.50.170", allow_prod_writes=False) class CliParseSafetyTest(unittest.TestCase): def test_customer_email_requires_confirm_flag(self): from redmine_tickets import build_parser, inject_default_sync_command parser = build_parser() # Missing mandatory confirm flag should fail parse with self.assertRaises(SystemExit): parser.parse_args( inject_default_sync_command( [ "--project", "customer-service", "customer-email", "--issue-id", "1", "--body", "hi", ] ) ) def test_note_command_exists(self): from redmine_tickets import build_parser, inject_default_sync_command args = build_parser().parse_args( inject_default_sync_command( [ "--project", "customer-service", "note", "--issue-id", "1", "--body", "internal only", "--private", ] ) ) self.assertEqual("note", args.command) self.assertTrue(args.private) self.assertFalse(args.apply) if __name__ == "__main__": unittest.main()