mirror of
https://github.com/wneessen/go-mail.git
synced 2024-11-14 18:02:55 +01:00
Refactor SMTP server test setup to use serverProps struct
Consolidate server configuration properties into a new serverProps struct for better code clarity and future extensibility. This change involves updating simpleSMTPServer and test cases to use the new struct, allowing more control over server behavior during tests.
This commit is contained in:
parent
8a6cd2b448
commit
12695385e8
1 changed files with 93 additions and 25 deletions
118
client_test.go
118
client_test.go
|
@ -1100,7 +1100,7 @@ func TestClient_SetDebugLog(t *testing.T) {
|
||||||
serverPort := int(TestServerPortBase + PortAdder.Load())
|
serverPort := int(TestServerPortBase + PortAdder.Load())
|
||||||
featureSet := "250-AUTH PLAIN\r\n250-8BITMIME\r\n250-DSN\r\n250 SMTPUTF8"
|
featureSet := "250-AUTH PLAIN\r\n250-8BITMIME\r\n250-DSN\r\n250 SMTPUTF8"
|
||||||
go func() {
|
go func() {
|
||||||
if err := simpleSMTPServer(ctx, featureSet, false, serverPort); err != nil {
|
if err := simpleSMTPServer(ctx, &serverProps{FeatureSet: featureSet, ListenPort: serverPort}); err != nil {
|
||||||
t.Errorf("failed to start test server: %s", err)
|
t.Errorf("failed to start test server: %s", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1482,20 +1482,23 @@ func TestClient_SetLogAuthData(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestClient_Close(t *testing.T) {
|
func TestClient_Close(t *testing.T) {
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
|
||||||
defer cancel()
|
|
||||||
PortAdder.Add(1)
|
|
||||||
serverPort := int(TestServerPortBase + PortAdder.Load())
|
|
||||||
featureSet := "250-AUTH PLAIN\r\n250-8BITMIME\r\n250-DSN\r\n250 SMTPUTF8"
|
|
||||||
go func() {
|
|
||||||
if err := simpleSMTPServer(ctx, featureSet, false, serverPort); err != nil {
|
|
||||||
t.Errorf("failed to start test server: %s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
time.Sleep(time.Millisecond * 300)
|
|
||||||
|
|
||||||
t.Run("connect and close the Client", func(t *testing.T) {
|
t.Run("connect and close the Client", func(t *testing.T) {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
PortAdder.Add(1)
|
||||||
|
serverPort := int(TestServerPortBase + PortAdder.Load())
|
||||||
|
featureSet := "250-AUTH PLAIN\r\n250-8BITMIME\r\n250-DSN\r\n250 SMTPUTF8"
|
||||||
|
go func() {
|
||||||
|
if err := simpleSMTPServer(ctx, &serverProps{
|
||||||
|
FeatureSet: featureSet,
|
||||||
|
ListenPort: serverPort,
|
||||||
|
}); err != nil {
|
||||||
|
t.Errorf("failed to start test server: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
time.Sleep(time.Millisecond * 300)
|
||||||
|
|
||||||
ctxDial, cancelDial := context.WithTimeout(ctx, time.Millisecond*500)
|
ctxDial, cancelDial := context.WithTimeout(ctx, time.Millisecond*500)
|
||||||
t.Cleanup(cancelDial)
|
t.Cleanup(cancelDial)
|
||||||
|
|
||||||
|
@ -1514,6 +1517,22 @@ func TestClient_Close(t *testing.T) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
t.Run("connect and double close the Client", func(t *testing.T) {
|
t.Run("connect and double close the Client", func(t *testing.T) {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
PortAdder.Add(1)
|
||||||
|
serverPort := int(TestServerPortBase + PortAdder.Load())
|
||||||
|
featureSet := "250-AUTH PLAIN\r\n250-8BITMIME\r\n250-DSN\r\n250 SMTPUTF8"
|
||||||
|
go func() {
|
||||||
|
if err := simpleSMTPServer(ctx, &serverProps{
|
||||||
|
FeatureSet: featureSet,
|
||||||
|
ListenPort: serverPort,
|
||||||
|
}); err != nil {
|
||||||
|
t.Errorf("failed to start test server: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
time.Sleep(time.Millisecond * 300)
|
||||||
|
|
||||||
ctxDial, cancelDial := context.WithTimeout(ctx, time.Millisecond*500)
|
ctxDial, cancelDial := context.WithTimeout(ctx, time.Millisecond*500)
|
||||||
t.Cleanup(cancelDial)
|
t.Cleanup(cancelDial)
|
||||||
|
|
||||||
|
@ -1534,6 +1553,41 @@ func TestClient_Close(t *testing.T) {
|
||||||
t.Errorf("failed to close the client: %s", err)
|
t.Errorf("failed to close the client: %s", err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
t.Run("test server will let close fail", func(t *testing.T) {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
PortAdder.Add(1)
|
||||||
|
serverPort := int(TestServerPortBase + PortAdder.Load())
|
||||||
|
featureSet := "250-AUTH PLAIN\r\n250-8BITMIME\r\n250-DSN\r\n250 SMTPUTF8"
|
||||||
|
go func() {
|
||||||
|
if err := simpleSMTPServer(ctx, &serverProps{
|
||||||
|
FailOnQuit: true,
|
||||||
|
FeatureSet: featureSet,
|
||||||
|
ListenPort: serverPort,
|
||||||
|
}); err != nil {
|
||||||
|
t.Errorf("failed to start test server: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
time.Sleep(time.Millisecond * 300)
|
||||||
|
|
||||||
|
ctxDial, cancelDial := context.WithTimeout(ctx, time.Millisecond*500)
|
||||||
|
t.Cleanup(cancelDial)
|
||||||
|
|
||||||
|
client, err := NewClient(DefaultHost, WithPort(serverPort), WithTLSPolicy(NoTLS))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create new client: %s", err)
|
||||||
|
}
|
||||||
|
if err = client.DialWithContext(ctxDial); err != nil {
|
||||||
|
t.Fatalf("failed to connect to the test server: %s", err)
|
||||||
|
}
|
||||||
|
if !client.smtpClient.HasConnection() {
|
||||||
|
t.Fatalf("client has no connection")
|
||||||
|
}
|
||||||
|
if err = client.Close(); err == nil {
|
||||||
|
t.Errorf("close was supposed to fail, but didn't")
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestClient_DialWithContext(t *testing.T) {
|
func TestClient_DialWithContext(t *testing.T) {
|
||||||
|
@ -1543,7 +1597,7 @@ func TestClient_DialWithContext(t *testing.T) {
|
||||||
serverPort := int(TestServerPortBase + PortAdder.Load())
|
serverPort := int(TestServerPortBase + PortAdder.Load())
|
||||||
featureSet := "250-AUTH PLAIN\r\n250-8BITMIME\r\n250-DSN\r\n250 SMTPUTF8"
|
featureSet := "250-AUTH PLAIN\r\n250-8BITMIME\r\n250-DSN\r\n250 SMTPUTF8"
|
||||||
go func() {
|
go func() {
|
||||||
if err := simpleSMTPServer(ctx, featureSet, false, serverPort); err != nil {
|
if err := simpleSMTPServer(ctx, &serverProps{FeatureSet: featureSet, ListenPort: serverPort}); err != nil {
|
||||||
t.Errorf("failed to start test server: %s", err)
|
t.Errorf("failed to start test server: %s", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -3630,11 +3684,21 @@ func parseJSONLog(t *testing.T, buf *bytes.Buffer) logData {
|
||||||
return logdata
|
return logdata
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type serverProps struct {
|
||||||
|
FailOnReset bool
|
||||||
|
FailOnQuit bool
|
||||||
|
FeatureSet string
|
||||||
|
ListenPort int
|
||||||
|
}
|
||||||
|
|
||||||
// simpleSMTPServer starts a simple TCP server that resonds to SMTP commands.
|
// simpleSMTPServer starts a simple TCP server that resonds to SMTP commands.
|
||||||
// The provided featureSet represents in what the server responds to EHLO command
|
// The provided featureSet represents in what the server responds to EHLO command
|
||||||
// failReset controls if a RSET succeeds
|
// failReset controls if a RSET succeeds
|
||||||
func simpleSMTPServer(ctx context.Context, featureSet string, failReset bool, port int) error {
|
func simpleSMTPServer(ctx context.Context, props *serverProps) error {
|
||||||
listener, err := net.Listen(TestServerProto, fmt.Sprintf("%s:%d", TestServerAddr, port))
|
if props == nil {
|
||||||
|
return fmt.Errorf("no server properties provided")
|
||||||
|
}
|
||||||
|
listener, err := net.Listen(TestServerProto, fmt.Sprintf("%s:%d", TestServerAddr, props.ListenPort))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to listen on %s://%s: %w", TestServerProto, TestServerAddr, err)
|
return fmt.Errorf("unable to listen on %s://%s: %w", TestServerProto, TestServerAddr, err)
|
||||||
}
|
}
|
||||||
|
@ -3659,12 +3723,12 @@ func simpleSMTPServer(ctx context.Context, featureSet string, failReset bool, po
|
||||||
}
|
}
|
||||||
return fmt.Errorf("unable to accept connection: %w", err)
|
return fmt.Errorf("unable to accept connection: %w", err)
|
||||||
}
|
}
|
||||||
handleTestServerConnection(connection, featureSet, failReset)
|
handleTestServerConnection(connection, props)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleTestServerConnection(connection net.Conn, featureSet string, failReset bool) {
|
func handleTestServerConnection(connection net.Conn, props *serverProps) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := connection.Close(); err != nil {
|
if err := connection.Close(); err != nil {
|
||||||
fmt.Printf("unable to close connection: %s\n", err)
|
fmt.Printf("unable to close connection: %s\n", err)
|
||||||
|
@ -3698,7 +3762,7 @@ func handleTestServerConnection(connection net.Conn, featureSet string, failRese
|
||||||
fmt.Printf("expected EHLO, got %q", data)
|
fmt.Printf("expected EHLO, got %q", data)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err = writeLine("250-localhost.localdomain\r\n" + featureSet); err != nil {
|
if err = writeLine("250-localhost.localdomain\r\n" + props.FeatureSet); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3748,19 +3812,19 @@ func handleTestServerConnection(connection net.Conn, featureSet string, failRese
|
||||||
var username, password string
|
var username, password string
|
||||||
userResp := "VXNlcm5hbWU6"
|
userResp := "VXNlcm5hbWU6"
|
||||||
passResp := "UGFzc3dvcmQ6"
|
passResp := "UGFzc3dvcmQ6"
|
||||||
if strings.Contains(featureSet, "250-X-MOX-LOGIN") {
|
if strings.Contains(props.FeatureSet, "250-X-MOX-LOGIN") {
|
||||||
userResp = ""
|
userResp = ""
|
||||||
passResp = "UGFzc3dvcmQ="
|
passResp = "UGFzc3dvcmQ="
|
||||||
}
|
}
|
||||||
if strings.Contains(featureSet, "250-X-NULLBYTE-LOGIN") {
|
if strings.Contains(props.FeatureSet, "250-X-NULLBYTE-LOGIN") {
|
||||||
userResp = "VXNlciBuYW1lAA=="
|
userResp = "VXNlciBuYW1lAA=="
|
||||||
passResp = "UGFzc3dvcmQA"
|
passResp = "UGFzc3dvcmQA"
|
||||||
}
|
}
|
||||||
if strings.Contains(featureSet, "250-X-BOGUS-LOGIN") {
|
if strings.Contains(props.FeatureSet, "250-X-BOGUS-LOGIN") {
|
||||||
userResp = "Qm9ndXM="
|
userResp = "Qm9ndXM="
|
||||||
passResp = "Qm9ndXM="
|
passResp = "Qm9ndXM="
|
||||||
}
|
}
|
||||||
if strings.Contains(featureSet, "250-X-EMPTY-LOGIN") {
|
if strings.Contains(props.FeatureSet, "250-X-EMPTY-LOGIN") {
|
||||||
userResp = ""
|
userResp = ""
|
||||||
passResp = ""
|
passResp = ""
|
||||||
}
|
}
|
||||||
|
@ -3816,12 +3880,16 @@ func handleTestServerConnection(connection net.Conn, featureSet string, failRese
|
||||||
strings.EqualFold(data, "vrfy"):
|
strings.EqualFold(data, "vrfy"):
|
||||||
writeOK()
|
writeOK()
|
||||||
case strings.EqualFold(data, "rset"):
|
case strings.EqualFold(data, "rset"):
|
||||||
if failReset {
|
if props.FailOnReset {
|
||||||
_ = writeLine("500 5.1.2 Error: reset failed")
|
_ = writeLine("500 5.1.2 Error: reset failed")
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
writeOK()
|
writeOK()
|
||||||
case strings.EqualFold(data, "quit"):
|
case strings.EqualFold(data, "quit"):
|
||||||
|
if props.FailOnQuit {
|
||||||
|
_ = writeLine("500 5.1.2 Error: quit failed")
|
||||||
|
break
|
||||||
|
}
|
||||||
_ = writeLine("221 2.0.0 Bye")
|
_ = writeLine("221 2.0.0 Bye")
|
||||||
default:
|
default:
|
||||||
_ = writeLine("500 5.5.2 Error: bad syntax")
|
_ = writeLine("500 5.5.2 Error: bad syntax")
|
||||||
|
|
Loading…
Reference in a new issue