Skip to content

Commit

Permalink
Merge pull request #193 from mocktools/develop
Browse files Browse the repository at this point in the history
Golang smtpmock v2.3.3
  • Loading branch information
bestwebua authored Nov 17, 2024
2 parents 5df633f + eedc86d commit 33d763a
Show file tree
Hide file tree
Showing 12 changed files with 66 additions and 30 deletions.
2 changes: 1 addition & 1 deletion .circleci/.goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ version: 2

builds:
- id: "smtpmock-build"
dir: cmd
dir: cmd/smtpmock
binary: smtpmock
env:
- CGO_ENABLED=0
Expand Down
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.3.3] - 2024-11-17

### Fixed

- Fixed issue with [invalid name with email address parsing](https://github.com/mocktools/go-smtp-mock/issues/153) for `MAIL FROM` and `RCPT TO` commands
- Fixed flaky tests

### Updated

- Updated `cmd` namespace
- Updated `goreleaser` config

## [2.3.2] - 2024-11-14

### Fixed
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
22 changes: 11 additions & 11 deletions consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,20 +53,20 @@ const (
// Regex patterns
availableCmdsRegexPattern = `(?i)helo|ehlo|mail from:|rcpt to:|data|rset|noop|quit`
domainRegexPattern = `(?i)([\p{L}0-9]+([\-.]{1}[\p{L}0-9]+)*\.\p{L}{2,63}|localhost)`
emailRegexPattern = `(?i)<?([\p{L}0-9][\p{L}0-9\-.]*[\p{L}0-9]+@` + domainRegexPattern + `)>?`
emailRegexPattern = `(?i)(?:[\p{L}\p{N}\s]*?<?)*?([a-zA-Z0-9][-a-zA-Z0-9.]*[a-zA-Z0-9]@` + domainRegexPattern + `)>*`
ipAddressRegexPattern = `(\b25[0-5]|\b2[0-4][0-9]|\b[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}`
addressLiteralRegexPattern = `|\[` + ipAddressRegexPattern + `\]`

validHeloCmdsRegexPattern = `(?i)helo|ehlo`
validMailfromCmdRegexPattern = `(?i)mail from:`
validRcpttoCmdRegexPattern = `(?i)rcpt to:`
validDataCmdRegexPattern = `\A(?i)data\z`
validRsetCmdRegexPattern = `\A(?i)rset\z`
validNoopCmdRegexPattern = `\A(?i)noop\z`
validQuitCmdRegexPattern = `\A(?i)quit\z`
validHeloComplexCmdRegexPattern = `\A(` + validHeloCmdsRegexPattern + `) (` + domainRegexPattern + `|` + ipAddressRegexPattern + addressLiteralRegexPattern + `)\z`
validMailromComplexCmdRegexPattern = `\A(` + validMailfromCmdRegexPattern + `) ?(` + emailRegexPattern + `)\z`
validRcpttoComplexCmdRegexPattern = `\A(` + validRcpttoCmdRegexPattern + `) ?(` + emailRegexPattern + `)\z`
validHeloCmdsRegexPattern = `(?i)helo|ehlo`
validMailfromCmdRegexPattern = `(?i)mail from:`
validRcpttoCmdRegexPattern = `(?i)rcpt to:`
validDataCmdRegexPattern = `\A(?i)data\z`
validRsetCmdRegexPattern = `\A(?i)rset\z`
validNoopCmdRegexPattern = `\A(?i)noop\z`
validQuitCmdRegexPattern = `\A(?i)quit\z`
validHeloComplexCmdRegexPattern = `\A(` + validHeloCmdsRegexPattern + `) (` + domainRegexPattern + `|` + ipAddressRegexPattern + addressLiteralRegexPattern + `)\z`
validMailfromComplexCmdRegexPattern = `\A(` + validMailfromCmdRegexPattern + `)\s*` + emailRegexPattern + `\z`
validRcpttoComplexCmdRegexPattern = `\A(` + validRcpttoCmdRegexPattern + `)\s*` + emailRegexPattern + `\z`

// Helpers
emptyString = ""
Expand Down
4 changes: 2 additions & 2 deletions handler_mailfrom.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func (handler *handlerMailfrom) isInvalidCmdSequence(request string) bool {
// Invalid MAILFROM command argument predicate. Returns true and writes result for case when
// MAILFROM command argument is invalid, otherwise returns false
func (handler *handlerMailfrom) isInvalidCmdArg(request string) bool {
if !matchRegex(request, validMailromComplexCmdRegexPattern) {
if !matchRegex(request, validMailfromComplexCmdRegexPattern) {
return handler.writeResult(false, request, handler.configuration.msgInvalidCmdMailfromArg)
}

Expand All @@ -71,7 +71,7 @@ func (handler *handlerMailfrom) isInvalidCmdArg(request string) bool {

// Returns email from MAILFROM request
func (handler *handlerMailfrom) mailfromEmail(request string) string {
return regexCaptureGroup(request, validMailromComplexCmdRegexPattern, 3)
return regexCaptureGroup(request, validMailfromComplexCmdRegexPattern, 2)
}

// Custom behavior for MAILFROM email. Returns true and writes result for case when
Expand Down
18 changes: 13 additions & 5 deletions handler_mailfrom_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,20 +226,28 @@ func TestHandlerMaifromIsInvalidCmdArg(t *testing.T) {
}

func TestHandlerMailfromMailfromEmail(t *testing.T) {
handler := new(handlerMailfrom)
validEmail, handler := "[email protected]", new(handlerMailfrom)

t.Run("when request includes valid email address without <> sign", func(t *testing.T) {
validEmail := "[email protected]"

assert.Equal(t, validEmail, handler.mailfromEmail("MAIL FROM: "+validEmail))
})

t.Run("when request includes valid email address with <> sign", func(t *testing.T) {
validEmail := "[email protected]"

assert.Equal(t, validEmail, handler.mailfromEmail("MAIL FROM: "+"<"+validEmail+">"))
})

t.Run("when request includes valid email address without <> sign, with name", func(t *testing.T) {
assert.Equal(t, validEmail, handler.mailfromEmail("MAIL FROM: John Doe <"+validEmail+">"))
})

t.Run("when request includes valid email address with <> sign, name with space", func(t *testing.T) {
assert.Equal(t, validEmail, handler.mailfromEmail("MAIL FROM: "+"<John Doe <"+validEmail+">>"))
})

t.Run("when request includes valid email address with <> sign and name without space", func(t *testing.T) {
assert.Equal(t, validEmail, handler.mailfromEmail("MAIL FROM: "+"<JohnDoe<"+validEmail+">>"))
})

t.Run("when request includes invalid email address", func(t *testing.T) {
invalidEmail := "user@invalid"

Expand Down
2 changes: 1 addition & 1 deletion handler_rcptto.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func (handler *handlerRcptto) isInvalidCmdArg(request string) bool {

// Returns email from RCPTTO request
func (handler *handlerRcptto) rcpttoEmail(request string) string {
return regexCaptureGroup(request, validRcpttoComplexCmdRegexPattern, 3)
return regexCaptureGroup(request, validRcpttoComplexCmdRegexPattern, 2)
}

// Custom behavior for RCPTTO email. Returns true and writes result for case when
Expand Down
18 changes: 13 additions & 5 deletions handler_rcptto_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -326,20 +326,28 @@ func TestHandlerRcpttoIsInvalidCmdArg(t *testing.T) {
}

func TestHandlerRcpttoRcpttoEmail(t *testing.T) {
handler := new(handlerRcptto)
validEmail, handler := "[email protected]", new(handlerRcptto)

t.Run("when request includes valid email address without <> sign", func(t *testing.T) {
validEmail := "[email protected]"

assert.Equal(t, validEmail, handler.rcpttoEmail("RCPT TO: "+validEmail))
})

t.Run("when request includes valid email address with <> sign", func(t *testing.T) {
validEmail := "[email protected]"

assert.Equal(t, validEmail, handler.rcpttoEmail("RCPT TO: "+"<"+validEmail+">"))
})

t.Run("when request includes valid email address without <> sign, with name", func(t *testing.T) {
assert.Equal(t, validEmail, handler.rcpttoEmail("RCPT TO: John Doe <"+validEmail+">"))
})

t.Run("when request includes valid email address with <> sign, name with space", func(t *testing.T) {
assert.Equal(t, validEmail, handler.rcpttoEmail("RCPT TO: "+"<John Doe <"+validEmail+">>"))
})

t.Run("when request includes valid email address with <> sign and name without space", func(t *testing.T) {
assert.Equal(t, validEmail, handler.rcpttoEmail("RCPT TO: "+"<JohnDoe<"+validEmail+">>"))
})

t.Run("when request includes invalid email address", func(t *testing.T) {
invalidEmail := "user@invalid"

Expand Down
10 changes: 8 additions & 2 deletions helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package smtpmock
import (
"fmt"
"regexp"
"time"
)

// Regex builder
Expand All @@ -20,8 +21,8 @@ func matchRegex(strContext, regexPattern string) bool {
return regex.MatchString(strContext)
}

// Returns string by regex pattern capture group index. For cases when regex not matched or
// capture group not found returns empty string
// Returns string by regex pattern capture group index.
// For cases when regex not matched or capture group not found returns empty string
func regexCaptureGroup(str string, regexPattern string, captureGroup int) (capturedString string) {
var regex *regexp.Regexp
defer func() { _ = recover() }()
Expand All @@ -47,3 +48,8 @@ func isIncluded(slice []string, target string) bool {
func serverWithPortNumber(server string, portNumber int) string {
return fmt.Sprintf("%s:%d", server, portNumber)
}

// Sleeps for the given duration in milliseconds
func sleepMilliseconds(duration int) {
time.Sleep(time.Duration(duration) * time.Millisecond)
}
8 changes: 5 additions & 3 deletions smtpmock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package smtpmock
import (
"fmt"
"testing"
"time"

"github.com/stretchr/testify/assert"
)
Expand Down Expand Up @@ -154,9 +153,12 @@ func TestNew(t *testing.T) {
assert.False(t, server.isStarted())

assert.NoError(t, server.Start())
sleepMilliseconds(100)
assert.True(t, server.isStarted())
_ = runSuccessfulSMTPSession(configuration.hostAddress, server.PortNumber(), true, 0)
sleepMilliseconds(100)
_ = server.Stop()
sleepMilliseconds(100)

assert.Equal(t, 2, len(server.Messages()))
assert.NotNil(t, server.quit)
Expand Down Expand Up @@ -221,11 +223,11 @@ func TestServerMessagesRaceCondition(t *testing.T) {
}()

// ensure that server.MessagesAndPurge() doesn't touch messages from active SMTP-session
time.Sleep(5 * time.Millisecond)
sleepMilliseconds(5)
assert.Empty(t, server.MessagesAndPurge())

// ensure that messages appears after SMTP-session
time.Sleep(100 * time.Millisecond)
sleepMilliseconds(100)
assert.Len(t, server.Messages(), 1)

if err := server.Stop(); err != nil {
Expand Down

0 comments on commit 33d763a

Please sign in to comment.