imap-migration-tools/test/conftest.py
Javier Callico caf83d60c5 Add comprehensive tests for IMAP email counting, migration, and common functionalities
- Implement tests for counting emails in single and multiple folders, including handling of empty folders and error scenarios in `test_count_imap_emails.py`.
- Create tests for environment variable verification, IMAP connection handling, folder normalization, MIME header decoding, and message details extraction in `test_imap_common.py`.
- Develop tests for email migration, including duplicate detection, deletion from source after migration, folder creation on destination, and handling of multiple folders in `test_migrate_imap_emails.py`.
- Introduce a mock IMAP server to facilitate testing of IMAP functionalities in `tools/mock_imap_server.py`.
2026-01-25 11:59:34 -05:00

131 lines
3.3 KiB
Python

"""
Shared pytest fixtures and utilities for IMAP migration tools tests.
"""
import imaplib
import os
import socket
import sys
import time
import pytest
# Ensure src/tools are in path
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../src")))
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../tools")))
from mock_imap_server import start_server_thread
def get_free_port():
"""Get a free port on localhost."""
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind(("", 0))
return s.getsockname()[1]
def create_server_pair(src_data=None, dest_data=None):
"""Create a pair of mock IMAP servers with given initial data."""
p1 = get_free_port()
p2 = get_free_port()
while p2 == p1:
p2 = get_free_port()
src_t, src_s = start_server_thread(p1, src_data)
dest_t, dest_s = start_server_thread(p2, dest_data)
time.sleep(0.3)
return (src_t, src_s, p1), (dest_t, dest_s, p2)
def shutdown_server_pair(src_tuple, dest_tuple):
"""Shutdown a pair of mock servers."""
src_t, src_s, _ = src_tuple
dest_t, dest_s, _ = dest_tuple
src_s.shutdown()
dest_s.shutdown()
src_t.join(timeout=2)
dest_t.join(timeout=2)
@pytest.fixture
def mock_server_factory():
"""
Factory fixture that creates mock IMAP server pairs.
Automatically cleans up all servers after the test.
"""
servers = []
def _create(src_data=None, dest_data=None):
src_tuple, dest_tuple = create_server_pair(src_data, dest_data)
servers.append((src_tuple, dest_tuple))
src_server = src_tuple[1]
dest_server = dest_tuple[1]
src_port = src_tuple[2]
dest_port = dest_tuple[2]
return src_server, dest_server, src_port, dest_port
yield _create
for src_tuple, dest_tuple in servers:
shutdown_server_pair(src_tuple, dest_tuple)
@pytest.fixture
def single_mock_server():
"""
Creates a single mock IMAP server for testing scripts that only need one server.
"""
servers = []
def _create(initial_data=None):
port = get_free_port()
thread, server = start_server_thread(port, initial_data)
time.sleep(0.3)
servers.append((thread, server))
return server, port
yield _create
for thread, server in servers:
server.shutdown()
thread.join(timeout=2)
@pytest.fixture(autouse=True)
def clean_sys_argv(monkeypatch):
"""Ensure sys.argv is clean for all tests."""
monkeypatch.setattr(sys, "argv", ["test_script.py"])
def make_mock_connection(src_port, dest_port, src_user="src_user", dest_user="dest_user"):
"""
Creates a mock connection function that routes to the correct server based on username.
"""
def mock_conn(host, user, pwd):
if user == src_user:
port = src_port
elif user == dest_user:
port = dest_port
else:
raise ValueError(f"Unknown user: {user}")
c = imaplib.IMAP4("localhost", port)
c.login(user, pwd)
return c
return mock_conn
def make_single_mock_connection(port):
"""
Creates a mock connection function for a single server.
"""
def mock_conn(host, user, pwd):
c = imaplib.IMAP4("localhost", port)
c.login(user, pwd)
return c
return mock_conn