mirror of
https://github.com/jhd3197/ServerKit.git
synced 2026-11-02 10:07:29 +09:00
add_domain deduped with a raw substring test, so with sub.example.com already mapped, adding example.com was a no-op that still reported success and mail for the new domain never routed. remove_domain filtered alias lines with a bare `@domain in line` test, which also deleted example.com.br entries. Appends went through tee -a with no trailing-newline guard, so a truncated map glued the new entry onto the last line, corrupting both and making them unremovable. - add_domain dedupes on the line's domain field - remove_domain drops only lines whose address tokens are at exactly that domain (com.br superstrings and sub.example.com both survive) - map appends heal a missing trailing newline first Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
108 lines
4.1 KiB
Python
108 lines
4.1 KiB
Python
"""Postfix virtual-map add ↔ remove round trip (#117 bug class).
|
|
|
|
add_domain deduped with a raw substring test (`domain not in content`), so
|
|
with sub.example.com already mapped, adding example.com no-opped while still
|
|
reporting success; remove_domain filtered alias lines with `@{domain} in l`,
|
|
which also deleted example.com.br entries; and appends went through tee -a
|
|
with no trailing-newline guard, gluing entries onto a truncated last line.
|
|
These tests drive the maps through an in-memory privileged-file store and
|
|
assert the join both ways.
|
|
"""
|
|
import types
|
|
|
|
import pytest
|
|
|
|
from app.services import postfix_service as pf_module
|
|
from app.services.postfix_service import PostfixService
|
|
|
|
|
|
@pytest.fixture
|
|
def map_store(monkeypatch):
|
|
"""In-memory stand-in for the privileged read/write doors."""
|
|
store = {}
|
|
|
|
def fake_run(cmd, **kwargs):
|
|
if cmd[0] == 'cat':
|
|
return types.SimpleNamespace(
|
|
returncode=0, stdout=store.get(cmd[1], ''), stderr='')
|
|
# postmap / postfix reload are no-ops here
|
|
return types.SimpleNamespace(returncode=0, stdout='', stderr='')
|
|
|
|
def fake_write(path, content, append=False, **kwargs):
|
|
store[path] = (store.get(path, '') + content) if append else content
|
|
return {'success': True}
|
|
|
|
monkeypatch.setattr(pf_module, 'run_privileged', fake_run)
|
|
monkeypatch.setattr(pf_module, 'write_privileged_file', fake_write)
|
|
return store
|
|
|
|
|
|
def _domains(store):
|
|
return store.get(PostfixService.VIRTUAL_DOMAINS_FILE, '')
|
|
|
|
|
|
def test_add_domain_not_fooled_by_subdomain_substring(map_store):
|
|
assert PostfixService.add_domain('sub.example.com')['success']
|
|
assert PostfixService.add_domain('example.com')['success']
|
|
|
|
lines = _domains(map_store).split()
|
|
assert 'example.com' in lines
|
|
assert 'sub.example.com' in lines
|
|
|
|
|
|
def test_add_domain_dedupes_exact_domain(map_store):
|
|
PostfixService.add_domain('example.com')
|
|
PostfixService.add_domain('example.com')
|
|
assert _domains(map_store).count('example.com OK') == 1
|
|
|
|
|
|
def test_remove_domain_spares_superstring_domains(map_store):
|
|
PostfixService.add_alias('admin@example.com', 'root@example.com')
|
|
PostfixService.add_alias('admin@example.com.br', 'root@example.com.br')
|
|
PostfixService.add_mailbox('user@example.com', 'example.com', 'user')
|
|
PostfixService.add_mailbox('user@example.com.br', 'example.com.br', 'user')
|
|
|
|
assert PostfixService.remove_domain('example.com')['success']
|
|
|
|
aliases = map_store[PostfixService.VIRTUAL_ALIASES_FILE]
|
|
mailboxes = map_store[PostfixService.VIRTUAL_MAILBOXES_FILE]
|
|
assert 'admin@example.com ' not in aliases
|
|
assert 'admin@example.com.br' in aliases
|
|
assert 'user@example.com ' not in mailboxes
|
|
assert 'user@example.com.br' in mailboxes
|
|
|
|
|
|
def test_remove_domain_spares_subdomain_addresses(map_store):
|
|
PostfixService.add_mailbox('user@mail.example.com', 'mail.example.com', 'user')
|
|
PostfixService.add_mailbox('user@example.com', 'example.com', 'user')
|
|
|
|
PostfixService.remove_domain('example.com')
|
|
|
|
mailboxes = map_store[PostfixService.VIRTUAL_MAILBOXES_FILE]
|
|
assert 'user@mail.example.com' in mailboxes
|
|
assert 'user@example.com ' not in mailboxes
|
|
|
|
|
|
def test_append_heals_missing_trailing_newline(map_store):
|
|
# A map whose last line lost its newline must not have the next entry
|
|
# glued onto it — glued entries are unmatchable on removal.
|
|
map_store[PostfixService.VIRTUAL_ALIASES_FILE] = 'old@a.com dest@a.com'
|
|
|
|
PostfixService.add_alias('new@b.com', 'dest@b.com')
|
|
|
|
lines = map_store[PostfixService.VIRTUAL_ALIASES_FILE].splitlines()
|
|
assert 'old@a.com dest@a.com' in lines
|
|
assert 'new@b.com dest@b.com' in lines
|
|
|
|
|
|
def test_full_domain_lifecycle(map_store):
|
|
PostfixService.add_domain('shop.test')
|
|
PostfixService.add_mailbox('owner@shop.test', 'shop.test', 'owner')
|
|
PostfixService.add_alias('sales@shop.test', 'owner@shop.test')
|
|
|
|
assert PostfixService.remove_domain('shop.test')['success']
|
|
|
|
assert 'shop.test' not in _domains(map_store)
|
|
assert 'shop.test' not in map_store[PostfixService.VIRTUAL_MAILBOXES_FILE]
|
|
assert 'shop.test' not in map_store[PostfixService.VIRTUAL_ALIASES_FILE]
|