golib/net/formmailer/run_test.go

129 lines
3.4 KiB
Go

package formmailer
import (
"context"
"io"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"strings"
"testing"
"time"
)
// captureStdout runs fn while capturing everything written to os.Stdout,
// returning the captured text.
func captureStdout(t *testing.T, fn func()) string {
t.Helper()
orig := os.Stdout
r, w, err := os.Pipe()
if err != nil {
t.Fatalf("pipe: %v", err)
}
os.Stdout = w
done := make(chan string, 1)
go func() {
b, _ := io.ReadAll(r)
done <- string(b)
}()
fn()
_ = w.Close()
os.Stdout = orig
return <-done
}
// runOnce starts a FormMailer with a context that expires quickly so Run
// returns immediately after selecting and logging its GeoIP mode. It must not
// require network (BlocklistRepo is empty) and binds an ephemeral port.
func runOnce(t *testing.T, fm *FormMailer) string {
t.Helper()
fm.ListenAddr = "127.0.0.1:0"
fm.RefreshInterval = time.Minute
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
return captureStdout(t, func() {
_ = fm.Run(ctx)
})
}
// TestRunGeoModeSelection sanity-checks the hybrid GeoIP mode selection:
// - conf present -> download mode
// - conf absent + populated -> poll mode
// - conf absent + empty dir -> disabled
func TestRunGeoModeSelection(t *testing.T) {
t.Run("download", func(t *testing.T) {
dir := t.TempDir()
conf := filepath.Join(dir, "GeoIP.conf")
if err := os.WriteFile(conf, []byte(
"AccountID 123456\nLicenseKey testkey\nEditionIDs GeoLite2-City GeoLite2-ASN\n"), 0o600); err != nil {
t.Fatal(err)
}
// 500 server so the owned download loop fails fast; the mode is
// selected and logged before serving regardless.
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.Error(w, "nope", http.StatusInternalServerError)
}))
defer srv.Close()
out := runOnce(t, &FormMailer{
CacheDir: dir,
GeoIPConfPath: conf,
GeoIPBaseURL: srv.URL,
SMTPHost: "localhost:25",
SMTPFrom: "a@example.com",
SMTPTo: []string{"b@example.com"},
})
if !strings.Contains(out, "GeoIP: download mode") {
t.Fatalf("missing download mode line; stdout:\n%s", out)
}
})
t.Run("poll", func(t *testing.T) {
// Point HOME at a temp dir so the default conf discovery can't find a
// real ~/.config/maxmind/GeoIP.conf.
home := t.TempDir()
t.Setenv("HOME", home)
archive := filepath.Join(t.TempDir(), "maxmind")
if err := os.MkdirAll(archive, 0o755); err != nil {
t.Fatal(err)
}
// Any entry makes the dir "populated" -> poll mode.
if err := os.WriteFile(filepath.Join(archive, "keep"), []byte("x"), 0o600); err != nil {
t.Fatal(err)
}
out := runOnce(t, &FormMailer{
CacheDir: home,
GeoIPDir: archive,
SMTPHost: "localhost:25",
SMTPFrom: "a@example.com",
SMTPTo: []string{"b@example.com"},
})
if !strings.Contains(out, "GeoIP: poll mode") {
t.Fatalf("missing poll mode line; stdout:\n%s", out)
}
})
t.Run("disabled", func(t *testing.T) {
home := t.TempDir()
t.Setenv("HOME", home)
empty := filepath.Join(home, "maxmind")
if err := os.MkdirAll(empty, 0o755); err != nil {
t.Fatal(err)
}
out := runOnce(t, &FormMailer{
CacheDir: home,
GeoIPDir: empty,
SMTPHost: "localhost:25",
SMTPFrom: "a@example.com",
SMTPTo: []string{"b@example.com"},
})
if strings.Contains(out, "GeoIP:") {
t.Fatalf("expected GeoIP disabled; stdout:\n%s", out)
}
})
}