Files
selfpost/internal/store/inbound_test.go
T
mix 656c4d4d7f release: 1.4.0: Optional inbound relay (backup-MX) on port 25
Optional inbound relay (backup-MX / forwarder) on port 25, off by default. Mail is accepted only for domains configured in the panel and forwarded to an upstream; there are still no mailboxes. A dedicated security review of the inbound path is still open on the plan (Fable).
Added:
  - `INBOUND_RELAY_ENABLE` (default `false`): when true, Postfix listens on
  - Panel **Inbound** pages (global administrator): domains, upstream host/port
  - Optional `INBOUND_ANTISPAM_MILTER` on the inbound listener only, plus
  - Inbound rate limit (`INBOUND_RATE_LIMIT_MESSAGES_PER_IP`, default 20) and
Changed:
  - Compose publishes host port 25 even when the flag is off (nothing listens
  - Full-backup restore Resync also rebuilds inbound maps when the flag is on.

Full detail: CHANGELOG.md (1.4.0).
2026-09-22 15:24:52 +03:00

102 lines
3.2 KiB
Go

package store
import (
"errors"
"testing"
)
func TestInboundDomainCRUD(t *testing.T) {
st := openTestStore(t)
d, err := st.AddInboundDomain("lists.example.com")
if err != nil {
t.Fatalf("AddInboundDomain: %v", err)
}
if d.ID == 0 || d.Name != "lists.example.com" || d.RecipientMode != RecipientModeList {
t.Fatalf("unexpected domain: %+v", d)
}
if d.Port != 25 || d.TLSMode != TLSModeMay || d.Host != "" {
t.Fatalf("unexpected default transport: %+v", d)
}
if _, err := st.AddInboundDomain("lists.example.com"); !errors.Is(err, ErrInboundDomainExists) {
t.Fatalf("duplicate error = %v, want ErrInboundDomainExists", err)
}
if err := st.UpdateInboundTransport(d.ID, "10.0.0.8", 25, TLSModeEncrypt); err != nil {
t.Fatalf("UpdateInboundTransport: %v", err)
}
addrs := []string{"staff@lists.example.com", "postmaster@lists.example.com"}
if err := st.UpdateInboundRecipients(d.ID, RecipientModeList, addrs); err != nil {
t.Fatalf("UpdateInboundRecipients: %v", err)
}
got, err := st.GetInboundDomain(d.ID)
if err != nil {
t.Fatalf("GetInboundDomain: %v", err)
}
if got.Host != "10.0.0.8" || got.TLSMode != TLSModeEncrypt || got.RecipientCount != 2 {
t.Fatalf("get after update: %+v", got)
}
if len(got.Recipients) != 2 || got.Recipients[0] != "postmaster@lists.example.com" {
t.Fatalf("recipients not sorted: %v", got.Recipients)
}
list, err := st.ListInboundDomains()
if err != nil {
t.Fatalf("ListInboundDomains: %v", err)
}
if len(list) != 1 || list[0].RecipientCount != 2 {
t.Fatalf("list: %+v", list)
}
if err := st.UpdateInboundRecipients(d.ID, RecipientModeAny, nil); err != nil {
t.Fatalf("switch to any: %v", err)
}
got, err = st.GetInboundDomain(d.ID)
if err != nil {
t.Fatal(err)
}
if got.RecipientMode != RecipientModeAny || got.RecipientCount != 0 || len(got.Recipients) != 0 {
t.Fatalf("any mode should clear the list: %+v", got)
}
if err := st.DeleteInboundDomain(d.ID); err != nil {
t.Fatalf("DeleteInboundDomain: %v", err)
}
assertCount(t, st, "inbound_domains", 0)
assertCount(t, st, "inbound_transports", 0)
assertCount(t, st, "inbound_recipients", 0)
if _, err := st.GetInboundDomain(d.ID); !errors.Is(err, ErrInboundDomainNotFound) {
t.Fatalf("Get after delete = %v, want ErrInboundDomainNotFound", err)
}
}
func TestInboundDomainNotFound(t *testing.T) {
st := openTestStore(t)
if _, err := st.GetInboundDomain(99); !errors.Is(err, ErrInboundDomainNotFound) {
t.Fatalf("GetInboundDomain(missing) = %v", err)
}
if err := st.UpdateInboundTransport(99, "10.0.0.1", 25, TLSModeNone); !errors.Is(err, ErrInboundDomainNotFound) {
t.Fatalf("UpdateInboundTransport(missing) = %v", err)
}
if err := st.DeleteInboundDomain(99); !errors.Is(err, ErrInboundDomainNotFound) {
t.Fatalf("DeleteInboundDomain(missing) = %v", err)
}
}
func TestInboundDeleteCascadesRecipients(t *testing.T) {
st := openTestStore(t)
d, err := st.AddInboundDomain("backup.example.net")
if err != nil {
t.Fatal(err)
}
if err := st.UpdateInboundRecipients(d.ID, RecipientModeList, []string{"a@backup.example.net"}); err != nil {
t.Fatal(err)
}
if err := st.DeleteInboundDomain(d.ID); err != nil {
t.Fatal(err)
}
assertCount(t, st, "inbound_recipients", 0)
}