maddy

Fork https://github.com/foxcpp/maddy

git clone git://git.lin.moe/go/maddy.git

  1/*
  2Maddy Mail Server - Composable all-in-one email server.
  3Copyright © 2019-2020 Max Mazurov <fox.cpp@disroot.org>, Maddy Mail Server contributors
  4
  5This program is free software: you can redistribute it and/or modify
  6it under the terms of the GNU General Public License as published by
  7the Free Software Foundation, either version 3 of the License, or
  8(at your option) any later version.
  9
 10This program is distributed in the hope that it will be useful,
 11but WITHOUT ANY WARRANTY; without even the implied warranty of
 12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 13GNU General Public License for more details.
 14
 15You should have received a copy of the GNU General Public License
 16along with this program.  If not, see <https://www.gnu.org/licenses/>.
 17*/
 18
 19package testutils
 20
 21import (
 22	"bufio"
 23	"context"
 24	"crypto/sha1"
 25	"encoding/hex"
 26	"io"
 27	"strconv"
 28	"strings"
 29	"testing"
 30
 31	"github.com/emersion/go-message/textproto"
 32	"github.com/emersion/go-smtp"
 33	"github.com/foxcpp/maddy/framework/buffer"
 34	"github.com/foxcpp/maddy/framework/module"
 35)
 36
 37// Empirically observed "around average" values.
 38const (
 39	MessageBodySize             = 100 * 1024
 40	ExtraMessageHeaderFields    = 10
 41	ExtraMessageHeaderFieldSize = 50
 42)
 43
 44const testHeaderString = "Content-Type: multipart/mixed; boundary=message-boundary\r\n" +
 45	"Date: Sat, 19 Jun 2016 12:00:00 +0900\r\n" +
 46	"From: Mitsuha Miyamizu <mitsuha.miyamizu@example.org>\r\n" +
 47	"Reply-To: Mitsuha Miyamizu <mitsuha.miyamizu+replyto@example.org>\r\n" +
 48	"Message-Id: 42@example.org\r\n" +
 49	"MIME-Version: 1.0\r\n" +
 50	"Content-Transfer-Encoding: 8but\r\n" +
 51	"Subject: Your Name.\r\n" +
 52	"To: Taki Tachibana <taki.tachibana@example.org>\r\n" +
 53	"\r\n"
 54
 55const testAltHeaderString = "Content-Type: multipart/alternative; boundary=b2\r\n" +
 56	"\r\n"
 57
 58const testTextHeaderString = "Content-Disposition: inline\r\n" +
 59	"Content-Type: text/plain\r\n" +
 60	"\r\n"
 61
 62const testTextBodyString = "What's your name?"
 63
 64const testTextString = testTextHeaderString + testTextBodyString
 65
 66const testHTMLHeaderString = "Content-Disposition: inline\r\n" +
 67	"Content-Type: text/html\r\n" +
 68	"\r\n"
 69
 70const testHTMLBodyString = "<div>What's <i>your</i> name?</div>"
 71
 72const testHTMLString = testHTMLHeaderString + testHTMLBodyString
 73
 74const testAttachmentHeaderString = "Content-Disposition: attachment; filename=note.txt\r\n" +
 75	"Content-Type: text/plain\r\n" +
 76	"\r\n"
 77
 78const testAttachmentBodyString = "My name is Mitsuha."
 79
 80const testAttachmentString = testAttachmentHeaderString + testAttachmentBodyString
 81
 82const testBodyString = "--message-boundary\r\n" +
 83	testAltHeaderString +
 84	"\r\n--b2\r\n" +
 85	testTextString +
 86	"\r\n--b2\r\n" +
 87	testHTMLString +
 88	"\r\n--b2--\r\n" +
 89	"\r\n--message-boundary\r\n" +
 90	testAttachmentString +
 91	"\r\n--message-boundary--\r\n"
 92
 93var testMailString = testHeaderString + testBodyString + strings.Repeat("A", MessageBodySize)
 94
 95func RandomMsg(b *testing.B) (module.MsgMetadata, textproto.Header, buffer.Buffer) {
 96	IDRaw := sha1.Sum([]byte(b.Name()))
 97	encodedID := hex.EncodeToString(IDRaw[:])
 98
 99	body := bufio.NewReader(strings.NewReader(testMailString))
100	hdr, _ := textproto.ReadHeader(body)
101	for i := 0; i < ExtraMessageHeaderFields; i++ {
102		hdr.Add("AAAAAAAAAAAA-"+strconv.Itoa(i), strings.Repeat("A", ExtraMessageHeaderFieldSize))
103	}
104	bodyBlob, _ := io.ReadAll(body)
105
106	return module.MsgMetadata{
107		DontTraceSender: true,
108		ID:              encodedID,
109	}, hdr, buffer.MemoryBuffer{Slice: bodyBlob}
110}
111
112func BenchDelivery(b *testing.B, target module.DeliveryTarget, sender string, recipientTemplates []string) {
113	meta, header, body := RandomMsg(b)
114
115	benchCtx := context.Background()
116
117	b.ReportAllocs()
118	b.ResetTimer()
119	for i := 0; i < b.N; i++ {
120		delivery, err := target.Start(benchCtx, &meta, sender)
121		if err != nil {
122			b.Fatal(err)
123		}
124
125		for i, rcptTemplate := range recipientTemplates {
126			rcpt := strings.Replace(rcptTemplate, "X", strconv.Itoa(i), -1)
127
128			if err := delivery.AddRcpt(benchCtx, rcpt, smtp.RcptOptions{}); err != nil {
129				b.Fatal(err)
130			}
131		}
132
133		if err := delivery.Body(benchCtx, header, body); err != nil {
134			b.Fatal(err)
135		}
136
137		if err := delivery.Commit(benchCtx); err != nil {
138			b.Fatal(err)
139		}
140	}
141}