mirror of
https://github.com/1f349/lotus.git
synced 2024-12-21 23:54:10 +00:00
Start writing tests
This commit is contained in:
parent
34244834b8
commit
b35b25c11c
@ -2,11 +2,11 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/1f349/lotus/imap"
|
"github.com/1f349/lotus/imap"
|
||||||
"github.com/1f349/lotus/smtp"
|
"github.com/1f349/lotus/sendmail"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Smtp interface {
|
type Smtp interface {
|
||||||
Send(mail *smtp.Mail) error
|
Send(mail *sendmail.Mail) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type Imap interface {
|
type Imap interface {
|
||||||
|
@ -5,7 +5,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
postfixLookup "github.com/1f349/lotus/postfix-lookup"
|
postfixLookup "github.com/1f349/lotus/postfix-lookup"
|
||||||
"github.com/1f349/lotus/smtp"
|
"github.com/1f349/lotus/sendmail"
|
||||||
"github.com/julienschmidt/httprouter"
|
"github.com/julienschmidt/httprouter"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -26,7 +26,7 @@ func MessageSender(send Smtp) func(rw http.ResponseWriter, req *http.Request, pa
|
|||||||
}
|
}
|
||||||
|
|
||||||
// parse json body
|
// parse json body
|
||||||
var j smtp.Json
|
var j sendmail.Json
|
||||||
err := json.NewDecoder(req.Body).Decode(&j)
|
err := json.NewDecoder(req.Body).Decode(&j)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiError(rw, http.StatusBadRequest, "Invalid JSON body")
|
apiError(rw, http.StatusBadRequest, "Invalid JSON body")
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
postfixLookup "github.com/1f349/lotus/postfix-lookup"
|
postfixLookup "github.com/1f349/lotus/postfix-lookup"
|
||||||
"github.com/1f349/lotus/smtp"
|
"github.com/1f349/lotus/sendmail"
|
||||||
"github.com/MrMelon54/mjwt/auth"
|
"github.com/MrMelon54/mjwt/auth"
|
||||||
"github.com/MrMelon54/mjwt/claims"
|
"github.com/MrMelon54/mjwt/claims"
|
||||||
|
"github.com/emersion/go-message/mail"
|
||||||
"github.com/golang-jwt/jwt/v4"
|
"github.com/golang-jwt/jwt/v4"
|
||||||
"github.com/julienschmidt/httprouter"
|
"github.com/julienschmidt/httprouter"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@ -37,16 +39,31 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type fakeSmtp struct {
|
type fakeSmtp struct {
|
||||||
from string
|
from *mail.Address
|
||||||
deliver []string
|
body []byte
|
||||||
body []byte
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fakeSmtp) Send(mail *smtp.Mail) error {
|
func (f *fakeSmtp) Send(mail *sendmail.Mail) error {
|
||||||
if mail.From != f.from {
|
// remove the Bcc header line
|
||||||
|
s := bufio.NewScanner(bytes.NewReader(mail.Body))
|
||||||
|
b := new(bytes.Buffer)
|
||||||
|
b.Grow(len(mail.Body))
|
||||||
|
for s.Scan() {
|
||||||
|
a := s.Text()
|
||||||
|
if strings.HasPrefix(a, "Bcc:") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
b.WriteString(a + "\r\n")
|
||||||
|
}
|
||||||
|
if err := s.Err(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// check values are the same
|
||||||
|
if mail.From.String() != f.from.String() {
|
||||||
return fmt.Errorf("test fail: invalid from address")
|
return fmt.Errorf("test fail: invalid from address")
|
||||||
}
|
}
|
||||||
if !slices.Equal(mail.Body, f.body) {
|
if !slices.Equal(b.Bytes(), f.body) {
|
||||||
return fmt.Errorf("test fail: invalid message body")
|
return fmt.Errorf("test fail: invalid message body")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -54,7 +71,7 @@ func (f *fakeSmtp) Send(mail *smtp.Mail) error {
|
|||||||
|
|
||||||
type fakeFailedSmtp struct{}
|
type fakeFailedSmtp struct{}
|
||||||
|
|
||||||
func (f *fakeFailedSmtp) Send(mail *smtp.Mail) error {
|
func (f *fakeFailedSmtp) Send(mail *sendmail.Mail) error {
|
||||||
return errors.New("sending failed")
|
return errors.New("sending failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,7 +102,7 @@ var messageSenderTestData = []struct {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
req: func() (*http.Request, error) {
|
req: func() (*http.Request, error) {
|
||||||
j, err := json.Marshal(smtp.Json{
|
j, err := json.Marshal(sendmail.Json{
|
||||||
From: "noreply2@example.com",
|
From: "noreply2@example.com",
|
||||||
ReplyTo: "admin@example.com",
|
ReplyTo: "admin@example.com",
|
||||||
To: "user@example.com",
|
To: "user@example.com",
|
||||||
@ -105,7 +122,7 @@ var messageSenderTestData = []struct {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
req: func() (*http.Request, error) {
|
req: func() (*http.Request, error) {
|
||||||
j, err := json.Marshal(smtp.Json{
|
j, err := json.Marshal(sendmail.Json{
|
||||||
From: "user@example.com",
|
From: "user@example.com",
|
||||||
ReplyTo: "admin@example.com",
|
ReplyTo: "admin@example.com",
|
||||||
To: "user@example.com",
|
To: "user@example.com",
|
||||||
@ -125,7 +142,7 @@ var messageSenderTestData = []struct {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
req: func() (*http.Request, error) {
|
req: func() (*http.Request, error) {
|
||||||
j, err := json.Marshal(smtp.Json{
|
j, err := json.Marshal(sendmail.Json{
|
||||||
From: "noreply@example.com, user2@example.com",
|
From: "noreply@example.com, user2@example.com",
|
||||||
ReplyTo: "admin@example.com",
|
ReplyTo: "admin@example.com",
|
||||||
To: "user@example.com",
|
To: "user@example.com",
|
||||||
@ -145,7 +162,7 @@ var messageSenderTestData = []struct {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
req: func() (*http.Request, error) {
|
req: func() (*http.Request, error) {
|
||||||
j, err := json.Marshal(smtp.Json{
|
j, err := json.Marshal(sendmail.Json{
|
||||||
From: "noreply@example.com",
|
From: "noreply@example.com",
|
||||||
ReplyTo: "admin@example.com",
|
ReplyTo: "admin@example.com",
|
||||||
To: "user@example.com",
|
To: "user@example.com",
|
||||||
@ -165,7 +182,7 @@ var messageSenderTestData = []struct {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
req: func() (*http.Request, error) {
|
req: func() (*http.Request, error) {
|
||||||
j, err := json.Marshal(smtp.Json{
|
j, err := json.Marshal(sendmail.Json{
|
||||||
From: "noreply@example.com",
|
From: "noreply@example.com",
|
||||||
ReplyTo: "admin@example.com",
|
ReplyTo: "admin@example.com",
|
||||||
To: "a <user@example.com",
|
To: "a <user@example.com",
|
||||||
@ -185,7 +202,7 @@ var messageSenderTestData = []struct {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
req: func() (*http.Request, error) {
|
req: func() (*http.Request, error) {
|
||||||
j, err := json.Marshal(smtp.Json{
|
j, err := json.Marshal(sendmail.Json{
|
||||||
From: "noreply@example.com",
|
From: "noreply@example.com",
|
||||||
ReplyTo: "admin@example.com",
|
ReplyTo: "admin@example.com",
|
||||||
To: "a <user>",
|
To: "a <user>",
|
||||||
@ -205,7 +222,7 @@ var messageSenderTestData = []struct {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
req: func() (*http.Request, error) {
|
req: func() (*http.Request, error) {
|
||||||
j, err := json.Marshal(smtp.Json{
|
j, err := json.Marshal(sendmail.Json{
|
||||||
From: "noreply@example.com",
|
From: "noreply@example.com",
|
||||||
ReplyTo: "admin@example.com",
|
ReplyTo: "admin@example.com",
|
||||||
To: "user@example.com",
|
To: "user@example.com",
|
||||||
@ -225,7 +242,7 @@ var messageSenderTestData = []struct {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
req: func() (*http.Request, error) {
|
req: func() (*http.Request, error) {
|
||||||
j, err := json.Marshal(smtp.Json{
|
j, err := json.Marshal(sendmail.Json{
|
||||||
From: "noreply@example.com",
|
From: "noreply@example.com",
|
||||||
ReplyTo: "admin@example.com",
|
ReplyTo: "admin@example.com",
|
||||||
To: "user@example.com",
|
To: "user@example.com",
|
||||||
@ -241,8 +258,7 @@ var messageSenderTestData = []struct {
|
|||||||
return http.NewRequest(http.MethodPost, "https://api.example.com/v1/mail/message", bytes.NewReader(j))
|
return http.NewRequest(http.MethodPost, "https://api.example.com/v1/mail/message", bytes.NewReader(j))
|
||||||
},
|
},
|
||||||
smtp: &fakeSmtp{
|
smtp: &fakeSmtp{
|
||||||
from: "noreply@example.com",
|
from: &mail.Address{Address: "noreply@example.com"},
|
||||||
deliver: []string{"user@example.com", "user2@example.com", "user3@example.com"},
|
|
||||||
body: []byte("Mime-Version: 1.0\r\n" +
|
body: []byte("Mime-Version: 1.0\r\n" +
|
||||||
"Content-Type: text/plain; charset=utf-8\r\n" +
|
"Content-Type: text/plain; charset=utf-8\r\n" +
|
||||||
"Cc: <user2@example.com>\r\n" +
|
"Cc: <user2@example.com>\r\n" +
|
||||||
@ -252,7 +268,7 @@ var messageSenderTestData = []struct {
|
|||||||
"Subject: Test Subject\r\n" +
|
"Subject: Test Subject\r\n" +
|
||||||
"Date: Sat, 01 Jan 2000 00:00:00 +0000\r\n" +
|
"Date: Sat, 01 Jan 2000 00:00:00 +0000\r\n" +
|
||||||
"\r\n" +
|
"\r\n" +
|
||||||
"Some plain text"),
|
"Some plain text\r\n"),
|
||||||
},
|
},
|
||||||
claims: makeFakeAuthClaims("admin@example.com"),
|
claims: makeFakeAuthClaims("admin@example.com"),
|
||||||
status: http.StatusAccepted,
|
status: http.StatusAccepted,
|
||||||
|
@ -2,12 +2,12 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/1f349/lotus/imap"
|
"github.com/1f349/lotus/imap"
|
||||||
"github.com/1f349/lotus/smtp"
|
"github.com/1f349/lotus/sendmail"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Conf struct {
|
type Conf struct {
|
||||||
Listen string `yaml:"listen"`
|
Listen string `yaml:"listen"`
|
||||||
Audience string `yaml:"audience"`
|
Audience string `yaml:"audience"`
|
||||||
Smtp *smtp.Smtp `yaml:"smtp"`
|
Smtp *sendmail.Smtp `yaml:"sendmail"`
|
||||||
Imap *imap.Imap `yaml:"imap"`
|
Imap *imap.Imap `yaml:"imap"`
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package smtp
|
package sendmail
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
@ -1,4 +1,4 @@
|
|||||||
package smtp
|
package sendmail
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/emersion/go-message/mail"
|
"github.com/emersion/go-message/mail"
|
||||||
@ -6,7 +6,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Smtp struct {
|
type Smtp struct {
|
||||||
Server string `yaml:"server"`
|
SendMailCommand string `json:"send_mail_command"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Mail struct {
|
type Mail struct {
|
||||||
@ -14,13 +14,14 @@ type Mail struct {
|
|||||||
Body []byte
|
Body []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
var execSendMail = func(from string) *exec.Cmd {
|
var execCommand = exec.Command
|
||||||
return exec.Command("/usr/lib/sendmail", "-f", from, "-t")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Smtp) Send(mail *Mail) error {
|
func (s *Smtp) Send(mail *Mail) error {
|
||||||
// start sendmail caller
|
// start sendmail caller
|
||||||
sendMail := execSendMail(mail.From.String())
|
if s.SendMailCommand == "" {
|
||||||
|
s.SendMailCommand = "/usr/sbin/sendmail"
|
||||||
|
}
|
||||||
|
sendMail := execCommand(s.SendMailCommand, "-f", mail.From.Address, "-t")
|
||||||
inPipe, err := sendMail.StdinPipe()
|
inPipe, err := sendMail.StdinPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -36,5 +37,6 @@ func (s *Smtp) Send(mail *Mail) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// run command
|
||||||
return sendMail.Run()
|
return sendMail.Run()
|
||||||
}
|
}
|
67
sendmail/sendmail_test.go
Normal file
67
sendmail/sendmail_test.go
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
package sendmail
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"github.com/emersion/go-message"
|
||||||
|
"github.com/emersion/go-message/mail"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var sendTestMessage []byte
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
var h mail.Header
|
||||||
|
h.SetDate(time.Date(2000, time.January, 1, 0, 0, 0, 0, time.Local))
|
||||||
|
h.SetSubject("Happy Millennium")
|
||||||
|
h.SetAddressList("From", []*mail.Address{{Name: "Test", Address: "test@localhost"}})
|
||||||
|
h.SetAddressList("To", []*mail.Address{{Name: "A", Address: "a@localhost"}})
|
||||||
|
h.Set("Content-Type", "text/plain; charset=utf-8")
|
||||||
|
entity, err := message.New(h.Header, strings.NewReader("Thanks"))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
out := new(bytes.Buffer)
|
||||||
|
if entity.WriteTo(out) != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
sendTestMessage = out.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSmtp_Send(t *testing.T) {
|
||||||
|
execCommand = func(name string, arg ...string) *exec.Cmd {
|
||||||
|
cs := append([]string{"-test.run=TestHelperProcess", "--", name}, arg...)
|
||||||
|
cmd := exec.Command(os.Args[0], cs...)
|
||||||
|
cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
defer func() { execCommand = exec.Command }()
|
||||||
|
|
||||||
|
m := &Mail{From: &mail.Address{Address: "test@localhost"}, Body: sendTestMessage}
|
||||||
|
|
||||||
|
temp, err := os.CreateTemp("", "sendmail")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
addr, err := net.ResolveUnixAddr("")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
listen, err := net.ListenUnix("", addr)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
s := &Smtp{SendMailCommand: "/tmp/sendmailXXXXX"}
|
||||||
|
assert.NoError(t, s.Send(m))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSmtpHelperProcess(t *testing.T) {
|
||||||
|
if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,74 +0,0 @@
|
|||||||
package smtp
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"github.com/1f349/lotus/smtp/fake"
|
|
||||||
"github.com/emersion/go-message"
|
|
||||||
"github.com/emersion/go-message/mail"
|
|
||||||
"github.com/emersion/go-smtp"
|
|
||||||
"github.com/hydrogen18/memlistener"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"log"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var sendTestMessage []byte
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
var h mail.Header
|
|
||||||
h.SetDate(time.Date(2000, time.January, 1, 0, 0, 0, 0, time.Local))
|
|
||||||
h.SetSubject("Happy Millennium")
|
|
||||||
h.SetAddressList("From", []*mail.Address{{Name: "Test", Address: "test@localhost"}})
|
|
||||||
h.SetAddressList("To", []*mail.Address{{Name: "A", Address: "a@localhost"}})
|
|
||||||
h.Set("Content-Type", "text/plain; charset=utf-8")
|
|
||||||
entity, err := message.New(h.Header, strings.NewReader("Thanks"))
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
out := new(bytes.Buffer)
|
|
||||||
if entity.WriteTo(out) != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
sendTestMessage = out.Bytes()
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSmtp_Send(t *testing.T) {
|
|
||||||
listener := memlistener.NewMemoryListener()
|
|
||||||
serverData := make(chan []byte, 4)
|
|
||||||
server := smtp.NewServer(&fake.SmtpBackend{Debug: serverData})
|
|
||||||
go func() {
|
|
||||||
_ = server.Serve(listener)
|
|
||||||
}()
|
|
||||||
|
|
||||||
defaultDialer = func(addr string) (*smtp.Client, error) {
|
|
||||||
dial, err := listener.Dial("", "")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return smtp.NewClient(dial, "localhost")
|
|
||||||
}
|
|
||||||
|
|
||||||
s := &Smtp{Server: "localhost:25"}
|
|
||||||
err := s.Send(&Mail{From: "test@localhost", Deliver: []string{"a@localhost", "b@localhost"}, Body: sendTestMessage})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, []byte("MAIL test@localhost\n"), <-serverData)
|
|
||||||
assert.Equal(t, []byte("RCPT a@localhost\n"), <-serverData)
|
|
||||||
assert.Equal(t, []byte("RCPT b@localhost\n"), <-serverData)
|
|
||||||
assert.Equal(t, append(sendTestMessage, '\r', '\n'), <-serverData)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCreateSenderSlice(t *testing.T) {
|
|
||||||
a := []*mail.Address{{Address: "a@example.com"}, {Address: "b@example.com"}}
|
|
||||||
b := []*mail.Address{{Address: "a@example.com"}, {Address: "c@example.com"}}
|
|
||||||
c := []*mail.Address{{Address: "a@example.com"}, {Address: "d@example.com"}}
|
|
||||||
assert.Equal(t, []string{
|
|
||||||
"a@example.com",
|
|
||||||
"b@example.com",
|
|
||||||
"a@example.com",
|
|
||||||
"c@example.com",
|
|
||||||
"a@example.com",
|
|
||||||
"d@example.com",
|
|
||||||
}, CreateSenderSlice(a, b, c))
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user