bmc_hub/tests/test_email_sender_create.py
Christian 1fb5b4a191 Add comprehensive tests for email and drift functionalities
- Introduced tests for drift operations UI and backend to ensure proper handling of ignore rules and UI elements.
- Added tests for email identity API to validate email linking and identity retrieval without updates.
- Implemented tests for email purchase link service to verify correct handling of purchase mail links and conflict scenarios.
- Created tests for email reply automation to ensure proper routing and processing of replies based on classification.
- Developed tests for email sender creation to validate suggestions and handling of existing contacts and companies.
- Added tests for email sender identity to ensure correct matching of contacts and domains.
- Implemented tests for work desk functionalities to validate task management, meeting registrations, and timer functionalities.
2026-11-03 01:16:12 +01:00

116 lines
4.8 KiB
Python

from contextlib import contextmanager
import asyncio
import pytest
from fastapi import HTTPException
from app.services import email_sender_create as service
def test_suggestions_use_sender_and_newest_signature_only():
draft = service.sender_suggestions({
'sender_name': 'Anna Jensen',
'sender_email': 'Anna.Jensen@firma.dk',
'body_text': '''Hej\n\nAnna Jensen\nFirma ApS\nStilling: Projektleder\nMobil: +45 20 30 40 50\nGade 12\n8000 Aarhus C\nCVR: 12345678\n\nFra: Gammel Person\nGammelt A/S\nCVR: 87654321''',
'body_html': '',
})
assert draft['contact']['email'] == 'anna.jensen@firma.dk'
assert draft['contact']['first_name'] == 'Anna'
assert draft['contact']['last_name'] == 'Jensen'
assert draft['contact']['mobile'] == '+45 20 30 40 50'
assert draft['company'] == {
'name': 'Firma ApS', 'cvr_number': '12345678', 'address': 'Gade 12',
'postal_code': '8000', 'city': 'Aarhus C',
}
assert 'Gammelt A/S' not in draft['evidence']
def test_suggestions_do_not_invent_company_from_email_domain():
draft = service.sender_suggestions({
'sender_name': 'Anna Jensen', 'sender_email': 'anna@ukendt-example.dk',
'body_text': 'Hej\nMvh Anna', 'body_html': '',
})
assert draft['company'].get('name', '') == ''
assert draft['contact']['email'] == 'anna@ukendt-example.dk'
@pytest.fixture
def db(monkeypatch):
state = {'writes': [], 'mail': {'id': 7, 'customer_id': None, 'supplier_id': None},
'previous': None, 'company': {'id': 12, 'name': 'Firma ApS'},
'contacts': [], 'contact': None}
@contextmanager
def transaction():
try:
yield
state['committed'] = True
except Exception:
state['rolled_back'] = True
raise
def one(sql, params):
if 'FROM email_messages' in sql: return state['mail']
if 'FROM email_activity_log' in sql: return state['previous']
if 'pg_advisory_xact_lock' in sql: return {'locked': None}
if 'FROM customers' in sql or 'FROM vendors' in sql: return state['company']
if 'FROM contacts WHERE id=' in sql: return state['contact'] or {'id': params[0]}
if 'INSERT INTO contacts' in sql: return {'id': 31}
raise AssertionError(sql)
def many(sql, params):
if 'FROM contacts WHERE LOWER' in sql: return state['contacts']
if 'FROM customers' in sql or 'FROM vendors' in sql: return []
raise AssertionError(sql)
monkeypatch.setattr(service, 'atomic_transaction', transaction)
monkeypatch.setattr(service, 'execute_query_single', one)
monkeypatch.setattr(service, 'execute_query', many)
monkeypatch.setattr(service, 'execute_update', lambda sql, params: state['writes'].append((sql, params)))
return state
def test_existing_company_and_contact_are_related_without_overwrite(db):
payload = service.SenderCreateRequest(
kind='customer', company={'existing_id': 12},
contact={'existing_id': 30, 'first_name': '', 'last_name': '', 'email': ''},
)
result = asyncio.run(service.create_sender(7, payload, user_id=4))
assert result['company_id'] == 12 and result['contact_id'] == 30
assert result['reused_contact'] is True and db['committed']
assert any('INSERT INTO contact_companies' in sql for sql, _ in db['writes'])
assert not any('INSERT INTO contacts' in sql for sql, _ in db['writes'])
assert any('UPDATE email_messages SET customer_id' in sql for sql, _ in db['writes'])
def test_duplicate_company_blocks_all_writes_and_rolls_back(db, monkeypatch):
db['company'] = None
monkeypatch.setattr(service, 'execute_query', lambda sql, params: [{'id': 99, 'name': 'Firma ApS'}]
if 'FROM customers' in sql else [])
payload = service.SenderCreateRequest(
kind='customer', company={'name': 'Firma ApS'},
contact={'first_name': 'Anna', 'last_name': 'Jensen', 'email': 'anna@firma.dk'},
)
with pytest.raises(HTTPException) as error:
asyncio.run(service.create_sender(7, payload))
assert error.value.status_code == 409
assert db['rolled_back'] and not db['writes']
def test_failure_after_relation_rolls_back_whole_command(db, monkeypatch):
calls = 0
def fail_on_mail_update(sql, params):
nonlocal calls
calls += 1
if 'UPDATE email_messages' in sql:
raise RuntimeError('database failed')
db['writes'].append((sql, params))
monkeypatch.setattr(service, 'execute_update', fail_on_mail_update)
payload = service.SenderCreateRequest(
kind='customer', company={'existing_id': 12},
contact={'existing_id': 30, 'first_name': '', 'last_name': '', 'email': ''},
)
with pytest.raises(RuntimeError):
asyncio.run(service.create_sender(7, payload))
assert calls == 2 and db['rolled_back'] and not db.get('committed')