mirror of
https://github.com/mjl-/mox.git
synced 2024-12-26 16:33:47 +03:00
more integration tests: start "mox localserve" and submit a message with smtpclient and with "mox sendmail", check that we receive it
This commit is contained in:
parent
7facf9d446
commit
1469b7293e
7 changed files with 104 additions and 28 deletions
2
Makefile
2
Makefile
|
@ -3,7 +3,7 @@ default: build
|
|||
build:
|
||||
# build early to catch syntax errors
|
||||
CGO_ENABLED=0 go build
|
||||
CGO_ENABLED=0 go vet -tags integration ./...
|
||||
CGO_ENABLED=0 go vet -tags integration
|
||||
CGO_ENABLED=0 go vet -tags quickstart quickstart_test.go
|
||||
./gendoc.sh
|
||||
(cd http && CGO_ENABLED=0 go run ../vendor/github.com/mjl-/sherpadoc/cmd/sherpadoc/*.go -adjust-function-names none Admin) >http/adminapi.json
|
||||
|
|
2
doc.go
2
doc.go
|
@ -329,6 +329,8 @@ during those commands instead of during "data".
|
|||
usage: mox localserve
|
||||
-dir string
|
||||
configuration storage directory (default "$userconfigdir/mox-localserve")
|
||||
-ip string
|
||||
serve on this ip instead of default 127.0.0.1 and ::1. only used when writing configuration, at first launch.
|
||||
|
||||
# mox help
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ services:
|
|||
volumes:
|
||||
- ./.go:/.go
|
||||
- ./testdata/integration/resolv.conf:/etc/resolv.conf
|
||||
- ./testdata/integration/moxsubmit.conf:/etc/moxsubmit.conf
|
||||
- .:/mox
|
||||
environment:
|
||||
GOCACHE: /.go/.cache/go-build
|
||||
|
@ -23,6 +24,8 @@ services:
|
|||
condition: service_healthy
|
||||
postfixmail:
|
||||
condition: service_healthy
|
||||
localserve:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
mailnet1:
|
||||
ipv4_address: 172.28.1.10
|
||||
|
@ -53,6 +56,31 @@ services:
|
|||
mailnet1:
|
||||
ipv4_address: 172.28.1.20
|
||||
|
||||
localserve:
|
||||
hostname: localserve.mox1.example
|
||||
domainname: mox1.example
|
||||
build:
|
||||
dockerfile: Dockerfile.moxmail
|
||||
context: testdata/integration
|
||||
command: ["sh", "-c", "set -e; chmod o+r /etc/resolv.conf; go run . -- localserve -ip 172.28.1.50"]
|
||||
volumes:
|
||||
- ./.go:/.go
|
||||
- ./testdata/integration/resolv.conf:/etc/resolv.conf
|
||||
- .:/mox
|
||||
environment:
|
||||
GOCACHE: /.go/.cache/go-build
|
||||
healthcheck:
|
||||
test: netstat -nlt | grep ':1025 '
|
||||
interval: 1s
|
||||
timeout: 1s
|
||||
retries: 10
|
||||
depends_on:
|
||||
dns:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
mailnet1:
|
||||
ipv4_address: 172.28.1.50
|
||||
|
||||
dns:
|
||||
hostname: dns.example
|
||||
build:
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
@ -36,6 +37,7 @@ func tcheck(t *testing.T, err error, msg string) {
|
|||
// We check if we receive the message.
|
||||
func TestDeliver(t *testing.T) {
|
||||
mlog.Logfmt = true
|
||||
log := mlog.New("test")
|
||||
|
||||
// Remove state.
|
||||
os.RemoveAll("testdata/integration/data")
|
||||
|
@ -79,16 +81,16 @@ func TestDeliver(t *testing.T) {
|
|||
err error
|
||||
}
|
||||
|
||||
deliver := func(username, desthost, mailfrom, password, rcptto, imapuser string) {
|
||||
testDeliver := func(checkTime bool, imapaddr, imapuser, imappass string, fn func()) {
|
||||
t.Helper()
|
||||
|
||||
// Make IMAP connection, we'll wait for a delivery notification with IDLE.
|
||||
imapconn, err := net.Dial("tcp", "moxmail1.mox1.example:143")
|
||||
imapconn, err := net.Dial("tcp", imapaddr)
|
||||
tcheck(t, err, "dial imap server")
|
||||
defer imapconn.Close()
|
||||
client, err := imapclient.New(imapconn, false)
|
||||
tcheck(t, err, "new imapclient")
|
||||
_, _, err = client.Login(imapuser, "pass1234")
|
||||
_, _, err = client.Login(imapuser, imappass)
|
||||
tcheck(t, err, "imap client login")
|
||||
_, _, err = client.Select("inbox")
|
||||
tcheck(t, err, "imap select inbox")
|
||||
|
@ -114,7 +116,27 @@ func TestDeliver(t *testing.T) {
|
|||
tcheck(t, err, "aborting idle")
|
||||
}()
|
||||
|
||||
conn, err := net.Dial("tcp", desthost+":587")
|
||||
t0 := time.Now()
|
||||
fn()
|
||||
|
||||
// Wait for notification of delivery.
|
||||
select {
|
||||
case resp := <-idle:
|
||||
tcheck(t, resp.err, "idle notification")
|
||||
_, ok := resp.untagged.(imapclient.UntaggedExists)
|
||||
if !ok {
|
||||
t.Fatalf("got idle %#v, expected untagged exists", resp.untagged)
|
||||
}
|
||||
if d := time.Since(t0); checkTime && d < 1*time.Second {
|
||||
t.Fatalf("delivery took %v, but should have taken at least 1 second, the first-time sender delay", d)
|
||||
}
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Fatalf("timeout after 5s waiting for IMAP IDLE notification of new message, should take about 1 second")
|
||||
}
|
||||
}
|
||||
|
||||
submit := func(smtphost, smtpport, mailfrom, password, rcptto string) {
|
||||
conn, err := net.Dial("tcp", net.JoinHostPort(smtphost, smtpport))
|
||||
tcheck(t, err, "dial submission")
|
||||
defer conn.Close()
|
||||
|
||||
|
@ -126,30 +148,36 @@ This is the message.
|
|||
`, mailfrom, rcptto)
|
||||
msg = strings.ReplaceAll(msg, "\n", "\r\n")
|
||||
auth := []sasl.Client{sasl.NewClientPlain(mailfrom, password)}
|
||||
c, err := smtpclient.New(mox.Context, mlog.New("test"), conn, smtpclient.TLSOpportunistic, mox.Conf.Static.HostnameDomain, dns.Domain{ASCII: desthost}, auth)
|
||||
c, err := smtpclient.New(mox.Context, log, conn, smtpclient.TLSOpportunistic, mox.Conf.Static.HostnameDomain, dns.Domain{ASCII: smtphost}, auth)
|
||||
tcheck(t, err, "smtp hello")
|
||||
t0 := time.Now()
|
||||
err = c.Deliver(mox.Context, mailfrom, rcptto, int64(len(msg)), strings.NewReader(msg), false, false)
|
||||
tcheck(t, err, "deliver with smtp")
|
||||
err = c.Close()
|
||||
tcheck(t, err, "close smtpclient")
|
||||
|
||||
// Wait for notification of delivery.
|
||||
select {
|
||||
case resp := <-idle:
|
||||
tcheck(t, resp.err, "idle notification")
|
||||
_, ok := resp.untagged.(imapclient.UntaggedExists)
|
||||
if !ok {
|
||||
t.Fatalf("got idle %#v, expected untagged exists", resp.untagged)
|
||||
}
|
||||
if d := time.Since(t0); d < 1*time.Second {
|
||||
t.Fatalf("delivery took %v, bt should have taken at least 1 second, the first-time sender delay", d)
|
||||
}
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Fatalf("timeout after 5s waiting for IMAP IDLE notification of new message, should take about 1 second")
|
||||
}
|
||||
}
|
||||
|
||||
deliver("moxtest1", "moxmail1.mox1.example", "moxtest1@mox1.example", "pass1234", "root@postfix.example", "moxtest1@mox1.example")
|
||||
deliver("moxtest3", "moxmail2.mox2.example", "moxtest2@mox2.example", "pass1234", "moxtest3@mox3.example", "moxtest3@mox3.example")
|
||||
testDeliver(true, "moxmail1.mox1.example:143", "moxtest1@mox1.example", "pass1234", func() {
|
||||
submit("moxmail1.mox1.example", "587", "moxtest1@mox1.example", "pass1234", "root@postfix.example")
|
||||
})
|
||||
testDeliver(true, "moxmail1.mox1.example:143", "moxtest3@mox3.example", "pass1234", func() {
|
||||
submit("moxmail2.mox2.example", "587", "moxtest2@mox2.example", "pass1234", "moxtest3@mox3.example")
|
||||
})
|
||||
|
||||
testDeliver(false, "localserve.mox1.example:1143", "mox@localhost", "moxmoxmox", func() {
|
||||
submit("localserve.mox1.example", "1587", "mox@localhost", "moxmoxmox", "any@any.example")
|
||||
})
|
||||
|
||||
testDeliver(false, "localserve.mox1.example:1143", "mox@localhost", "moxmoxmox", func() {
|
||||
cmd := exec.Command("go", "run", ".", "sendmail", "mox@localhost")
|
||||
const msg = `Subject: test
|
||||
|
||||
a message.
|
||||
`
|
||||
cmd.Stdin = strings.NewReader(msg)
|
||||
var out strings.Builder
|
||||
cmd.Stdout = &out
|
||||
err := cmd.Run()
|
||||
log.Print("sendmail", mlog.Field("output", out.String()))
|
||||
tcheck(t, err, "sendmail")
|
||||
})
|
||||
}
|
||||
|
|
|
@ -65,8 +65,9 @@ during those commands instead of during "data".
|
|||
userConfDir = "."
|
||||
}
|
||||
|
||||
var dir string
|
||||
var dir, ip string
|
||||
c.flag.StringVar(&dir, "dir", filepath.Join(userConfDir, "mox-localserve"), "configuration storage directory")
|
||||
c.flag.StringVar(&ip, "ip", "", "serve on this ip instead of default 127.0.0.1 and ::1. only used when writing configuration, at first launch.")
|
||||
args := c.Parse()
|
||||
if len(args) != 0 {
|
||||
c.Usage()
|
||||
|
@ -78,7 +79,7 @@ during those commands instead of during "data".
|
|||
|
||||
// Load config, creating a new one if needed.
|
||||
if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
|
||||
err := writeLocalConfig(log, dir)
|
||||
err := writeLocalConfig(log, dir, ip)
|
||||
if err != nil {
|
||||
log.Fatalx("creating mox localserve config", err, mlog.Field("dir", dir))
|
||||
}
|
||||
|
@ -86,6 +87,8 @@ during those commands instead of during "data".
|
|||
log.Fatalx("stat config dir", err, mlog.Field("dir", dir))
|
||||
} else if err := localLoadConfig(log, dir); err != nil {
|
||||
log.Fatalx("loading mox localserve config (hint: when creating a new config with -dir, the directory must not yet exist)", err, mlog.Field("dir", dir))
|
||||
} else if ip != "" {
|
||||
log.Fatal("can only use -ip when writing a new config file")
|
||||
}
|
||||
|
||||
if level, ok := mlog.Levels[loglevel]; loglevel != "" && ok {
|
||||
|
@ -181,7 +184,7 @@ during those commands instead of during "data".
|
|||
}
|
||||
}
|
||||
|
||||
func writeLocalConfig(log *mlog.Log, dir string) (rerr error) {
|
||||
func writeLocalConfig(log *mlog.Log, dir, ip string) (rerr error) {
|
||||
defer func() {
|
||||
x := recover()
|
||||
if x != nil {
|
||||
|
@ -257,9 +260,13 @@ func writeLocalConfig(log *mlog.Log, dir string) (rerr error) {
|
|||
xcheck(err, "writing adminpasswd file")
|
||||
|
||||
// Write mox.conf.
|
||||
ips := []string{"127.0.0.1", "::1"}
|
||||
if ip != "" {
|
||||
ips = []string{ip}
|
||||
}
|
||||
|
||||
local := config.Listener{
|
||||
IPs: []string{"127.0.0.1", "::1"},
|
||||
IPs: ips,
|
||||
TLS: &config.TLS{
|
||||
KeyCerts: []config.KeyCert{
|
||||
{
|
||||
|
|
1
testdata/integration/example.zone
vendored
1
testdata/integration/example.zone
vendored
|
@ -10,6 +10,7 @@ moxmail2.mox2 IN A 172.28.2.10
|
|||
moxmail3.mox3 IN A 172.28.3.10
|
||||
postfixmail.postfix IN A 172.28.1.20
|
||||
dns IN A 172.28.1.30
|
||||
localserve.mox1 IN A 172.28.1.50
|
||||
|
||||
mox1 MX 10 moxmail1.mox1.example.
|
||||
mox2 MX 10 moxmail2.mox2.example.
|
||||
|
|
10
testdata/integration/moxsubmit.conf
vendored
Normal file
10
testdata/integration/moxsubmit.conf
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
LocalHostname: localhost
|
||||
Host: localserve.mox1.example
|
||||
Port: 1587
|
||||
TLS: false
|
||||
STARTTLS: false
|
||||
Username: mox@localhost
|
||||
Password: moxmoxmox
|
||||
AuthMethod: PLAIN
|
||||
From: mox@localhost
|
||||
DefaultDestination: mox@localhost
|
Loading…
Reference in a new issue