Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] Race condition detected when run in test files #124

Closed
4 tasks done
benjamin-rood opened this issue Nov 10, 2022 · 11 comments · Fixed by #127
Closed
4 tasks done

[BUG] Race condition detected when run in test files #124

benjamin-rood opened this issue Nov 10, 2022 · 11 comments · Fixed by #127
Assignees
Labels
bug Something isn't working

Comments

@benjamin-rood
Copy link
Collaborator

benjamin-rood commented Nov 10, 2022

New bug checklist

Bug description

Race condition detected when running tests in file

Test file:

package mailer

import (
	"fmt"
	"log"
	"net/smtp"
	"testing"
	"time"

	"bitbucket.org/vadacom/commander/pkg/logging"
	smtpmock "github.com/mocktools/go-smtp-mock"
)

func last[E any](s []E) E {
	return s[len(s)-1]
}

var (
	smtpmockServer        *smtpmock.Server
	smtpmockServerAddress string
)

func TestMain(m *testing.M) {
	// You can pass empty smtpmock.ConfigurationAttr{}. It means that smtpmock will use default settings
	smtpmockServer = smtpmock.New(smtpmock.ConfigurationAttr{
		LogToStdout:       true,
		LogServerActivity: true,
	})

	// To start server use Start() method
	if err := smtpmockServer.Start(); err != nil {
		log.Panic(err)
	}
	defer smtpmockServer.Stop()
	// Server's port will be assigned dynamically after server.Start()
	// for case when portNumber wasn't specified
	hostAddress, portNumber := "127.0.0.1", smtpmockServer.PortNumber

	// Possible SMTP-client stuff for iteration with mock server
	smtpmockServerAddress = fmt.Sprintf("%s:%d", hostAddress, portNumber)

	exit := m.Run()
	log.Print(exit)
}

func TestSMTPTransport_Send(t *testing.T) {
	l := logging.TestingStructuredNop(t)
	mailTransport, err := NewSMTPTransport(
		l,
		smtpmockServerAddress,
		smtp.Auth(nil),
		30*time.Second,  // dial timeout
		30*time.Second,  // command timeout
		300*time.Second, // DATA timeout
	)
	if err != nil {
		t.Fatal(err)
	}

	const (
		someoneEmailAddress = "someone@example.org"
		peanutEmailAddress  = "peanut@butter.invalid"
		benEmailAddress     = "ben@vadacom.testing.invalid"
		mailFromTmpl        = "MAIL FROM:<%v>"
		rcptToTmpl          = "RCPT TO:<%v>"
		msgBodyFooter       = "\r\n"
	)
	emptyFromAddressErr := fmt.Errorf("from address ('') parsing failed: mail: no address")
	emptyToAddressErr := fmt.Errorf("to address ('') parsing failed: mail: no address")
	missingToAddresses := fmt.Errorf("missing email to addressees")
	missingEmailMsg := fmt.Errorf("missing email message body")
	helloEmailMsg := []byte("Hello World")

	type args struct {
		email_from_address string
		email_to_addresses []string
		email_msg          []byte
	}
	tests := []struct {
		name    string
		args    args
		wantErr error
	}{
		{name: "MUST FAIL: empty from address", args: args{"", []string{someoneEmailAddress}, nil}, wantErr: emptyFromAddressErr},
		{name: "MUST FAIL: empty to address", args: args{someoneEmailAddress, []string{""}, nil}, wantErr: emptyToAddressErr},
		{name: "MUST FAIL: nil list of to addresses", args: args{someoneEmailAddress, nil, nil}, wantErr: missingToAddresses},
		{name: "MUST FAIL: empty list of to addresses", args: args{someoneEmailAddress, []string{}, nil}, wantErr: missingToAddresses},
		{name: "MUST FAIL: nil message body", args: args{someoneEmailAddress, []string{someoneEmailAddress}, nil}, wantErr: missingEmailMsg},
		{name: "MUST FAIL: empty message body", args: args{someoneEmailAddress, []string{someoneEmailAddress}, []byte{}}, wantErr: missingEmailMsg},
		{name: "hello world email from someone to someone", args: args{someoneEmailAddress, []string{someoneEmailAddress}, helloEmailMsg}, wantErr: nil},
		{name: "hello world email from ben to someone", args: args{benEmailAddress, []string{someoneEmailAddress}, helloEmailMsg}, wantErr: nil},
		{name: "hello world email from someone to multiple addresses", args: args{someoneEmailAddress, []string{benEmailAddress, peanutEmailAddress}, helloEmailMsg}, wantErr: nil},
		{name: "hello world email from ben to multiple addresses", args: args{benEmailAddress, []string{peanutEmailAddress, someoneEmailAddress}, helloEmailMsg}, wantErr: nil},
		{name: "hello world email from peanut to multiple addresses", args: args{peanutEmailAddress, []string{someoneEmailAddress, benEmailAddress}, helloEmailMsg}, wantErr: nil},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := mailTransport.Send(tt.args.email_from_address, tt.args.email_to_addresses, tt.args.email_msg)
			if err != tt.wantErr {
				if err != nil && tt.wantErr != nil {
					if err.Error() != tt.wantErr.Error() {
						t.Errorf("smtp transport send failed unexpectedly, expected: %v, got: %v", tt.wantErr, err)
						return
					}
				} else {
					t.Errorf("smtp transport send failed unexpectedly, expected: %v, got: %v", tt.wantErr, err)
					return
				}
			}
			if tt.wantErr == nil {
				// check result of last email send
				messagesFromMockSmtpServer := smtpmockServer.Messages()
				message := last(messagesFromMockSmtpServer)
				expectedMailFrom := fmt.Sprintf(mailFromTmpl, tt.args.email_from_address)
				actualMailFrom := message.MailfromRequest()
				if expectedMailFrom != actualMailFrom {
					t.Errorf("unexpected email message sender, expected: %q, got: %q", expectedMailFrom, actualMailFrom)
					return
				}
				// FIXME: go-smtp-mock implementation is broken, only records last recipient address per message
				// see github issue: https://github.com/mocktools/go-smtp-mock/issues/120
				expectedMailRcpt := fmt.Sprintf(rcptToTmpl, last(tt.args.email_to_addresses))
				actualMailRcpt := message.RcpttoRequest()
				if expectedMailRcpt != actualMailRcpt {
					t.Errorf("unexpected email message recipient, expected: %q, got: %q", expectedMailRcpt, actualMailRcpt)
					return
				}
				// "\r\n" added automatically in sending process
				expectedMsgBody := string(tt.args.email_msg) + msgBodyFooter
				actualMsgBody := message.MsgRequest()
				if expectedMsgBody != actualMsgBody {
					t.Errorf("unexpected email message body, expected: %q, got: %q", expectedMsgBody, actualMsgBody)
					return
				}
			}
		})
	}
}

// EOF
Complete output when running smtpmock, including the stack trace and command used
❯ go test -race /w/v/r/C/internal/mailer
INFO: 2022/11/10 17:05:50.796925 SMTP mock server started on port: 43145
INFO: 2022/11/10 17:05:50.838546 SMTP session started
INFO: 2022/11/10 17:05:50.838594 SMTP response: 220 Welcome
INFO: 2022/11/10 17:05:50.849022 SMTP session started
INFO: 2022/11/10 17:05:50.849099 SMTP response: 220 Welcome
INFO: 2022/11/10 17:05:50.859598 SMTP session started
INFO: 2022/11/10 17:05:50.859691 SMTP response: 220 Welcome
INFO: 2022/11/10 17:05:50.859791 SMTP request: EHLO localhost
INFO: 2022/11/10 17:05:50.863678 SMTP response: 250 Received
INFO: 2022/11/10 17:05:50.863719 SMTP request: MAIL FROM:<someone@example.org>
INFO: 2022/11/10 17:05:50.866715 SMTP response: 250 Received
INFO: 2022/11/10 17:05:50.866744 SMTP request: RCPT TO:<someone@example.org>
INFO: 2022/11/10 17:05:50.871119 SMTP response: 250 Received
INFO: 2022/11/10 17:05:50.871142 SMTP request: DATA
INFO: 2022/11/10 17:05:50.871240 SMTP response: 354 Ready for receive message. End data with <CR><LF>.<CR><LF>
INFO: 2022/11/10 17:05:50.871267 SMTP request: message binary data portion
INFO: 2022/11/10 17:05:50.871275 SMTP request: message binary data portion
INFO: 2022/11/10 17:05:50.871288 SMTP response: 250 Received
INFO: 2022/11/10 17:05:50.871308 SMTP request: QUIT
INFO: 2022/11/10 17:05:50.871391 SMTP response: 221 Closing connection
INFO: 2022/11/10 17:05:50.871418 SMTP session finished
INFO: 2022/11/10 17:05:50.881919 SMTP session started
==================
WARNING: DATA RACE
Write at 0x00c0001d8ac8 by goroutine 27:
  github.com/mocktools/go-smtp-mock.(*messages).append()
      /home/br/go/pkg/mod/github.com/mocktools/go-smtp-mock@v1.10.0/message.go:139 +0x164
  github.com/mocktools/go-smtp-mock.(*Server).newMessage()
      /home/br/go/pkg/mod/github.com/mocktools/go-smtp-mock@v1.10.0/server.go:127 +0xfd
  github.com/mocktools/go-smtp-mock.(*Server).handleSession()
      /home/br/go/pkg/mod/github.com/mocktools/go-smtp-mock@v1.10.0/server.go:170 +0xfe
  github.com/mocktools/go-smtp-mock.(*Server).Start.func1.1()
      /home/br/go/pkg/mod/github.com/mocktools/go-smtp-mock@v1.10.0/server.go:80 +0x7b

Previous read at 0x00c0001d8ac8 by goroutine 21:
  github.com/mocktools/go-smtp-mock.(*Server).Messages()
      /home/br/go/pkg/mod/github.com/mocktools/go-smtp-mock@v1.10.0/server.go:121 +0x2d6
  bitbucket.org/vxxxxxxx/cxxxxxxxx/internal/mailer.TestSMTPTransport_Send.func1()
      /wrk/vada/r/CMDR/internal/mailer/smtp_transport_test.go:119 +0x292
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:1439 +0x213
  testing.(*T).Run.func1()
      /usr/local/go/src/testing/testing.go:1486 +0x47

Goroutine 27 (running) created at:
  github.com/mocktools/go-smtp-mock.(*Server).Start.func1()
      /home/br/go/pkg/mod/github.com/mocktools/go-smtp-mock@v1.10.0/server.go:79 +0xae

Goroutine 21 (finished) created at:
  testing.(*T).Run()
      /usr/local/go/src/testing/testing.go:1486 +0x724
  bitbucket.org/vxxxxxxx/cxxxxxxxx/internal/mailer.TestSMTPTransport_Send()
      /wrk/vada/r/CMDR/internal/mailer/smtp_transport_test.go:99 +0xec4
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:1439 +0x213
  testing.(*T).Run.func1()
      /usr/local/go/src/testing/testing.go:1486 +0x47
==================
INFO: 2022/11/10 17:05:50.882110 SMTP response: 220 Welcome
INFO: 2022/11/10 17:05:50.882191 SMTP request: EHLO localhost
INFO: 2022/11/10 17:05:50.885873 SMTP response: 250 Received
INFO: 2022/11/10 17:05:50.885935 SMTP request: MAIL FROM:<ben@vxxxxxx.testing.invalid>
ERROR: 2022/11/10 17:05:50.889121 read tcp 127.0.0.1:43145->127.0.0.1:49552: read: connection reset by peer
==================
WARNING: DATA RACE
Read at 0x00c0000b87e0 by goroutine 16:
  github.com/mocktools/go-smtp-mock.(*eventLogger).error()
      /home/br/go/pkg/mod/github.com/mocktools/go-smtp-mock@v1.10.0/logger.go:78 +0x64
  github.com/mocktools/go-smtp-mock.(*session).readRequest()
      /home/br/go/pkg/mod/github.com/mocktools/go-smtp-mock@v1.10.0/session.go:119 +0xe7
  github.com/mocktools/go-smtp-mock.(*Server).handleSession()
      /home/br/go/pkg/mod/github.com/mocktools/go-smtp-mock@v1.10.0/server.go:179 +0x204
  github.com/mocktools/go-smtp-mock.(*Server).Start.func1.1()
      /home/br/go/pkg/mod/github.com/mocktools/go-smtp-mock@v1.10.0/server.go:80 +0x7b

INFO: 2022/11/10 17:05:50.889147 SMTP session finished
Previous write at 0x00c0000b87e0 by goroutine 19:
  github.com/mocktools/go-smtp-mock.(*eventLogger).error()
      /home/br/go/pkg/mod/github.com/mocktools/go-smtp-mock@v1.10.0/logger.go:79 +0x204
  github.com/mocktools/go-smtp-mock.(*session).readRequest()
      /home/br/go/pkg/mod/github.com/mocktools/go-smtp-mock@v1.10.0/session.go:119 +0xe7
  github.com/mocktools/go-smtp-mock.(*Server).handleSession()
      /home/br/go/pkg/mod/github.com/mocktools/go-smtp-mock@v1.10.0/server.go:179 +0x204
  github.com/mocktools/go-smtp-mock.(*Server).Start.func1.1()
      /home/br/go/pkg/mod/github.com/mocktools/go-smtp-mock@v1.10.0/server.go:80 +0x7b

Goroutine 16 (running) created at:
  github.com/mocktools/go-smtp-mock.(*Server).Start.func1()
      /home/br/go/pkg/mod/github.com/mocktools/go-smtp-mock@v1.10.0/server.go:79 +0xae

Goroutine 19 (running) created at:
  github.com/mocktools/go-smtp-mock.(*Server).Start.func1()
      /home/br/go/pkg/mod/github.com/mocktools/go-smtp-mock@v1.10.0/server.go:79 +0xae
==================
==================
WARNING: DATA RACE
Read at 0x00c0003300e8 by goroutine 16:
  sync/atomic.LoadInt32()
      /usr/local/go/src/runtime/race_amd64.s:200 +0xb
  sync/atomic.LoadInt32()
      <autogenerated>:1 +0x16
  github.com/mocktools/go-smtp-mock.(*eventLogger).error()
      /home/br/go/pkg/mod/github.com/mocktools/go-smtp-mock@v1.10.0/logger.go:82 +0x284
  github.com/mocktools/go-smtp-mock.(*session).readRequest()
      /home/br/go/pkg/mod/github.com/mocktools/go-smtp-mock@v1.10.0/session.go:119 +0xe7
  github.com/mocktools/go-smtp-mock.(*Server).handleSession()
      /home/br/go/pkg/mod/github.com/mocktools/go-smtp-mock@v1.10.0/server.go:179 +0x204
  github.com/mocktools/go-smtp-mock.(*Server).Start.func1.1()
      /home/br/go/pkg/mod/github.com/mocktools/go-smtp-mock@v1.10.0/server.go:80 +0x7b

Previous write at 0x00c0003300e8 by goroutine 19:
  log.New()
      /usr/local/go/src/log/log.go:68 +0xc6
  github.com/mocktools/go-smtp-mock.(*eventLogger).error()
      /home/br/go/pkg/mod/github.com/mocktools/go-smtp-mock@v1.10.0/logger.go:79 +0x75
  github.com/mocktools/go-smtp-mock.(*session).readRequest()
      /home/br/go/pkg/mod/github.com/mocktools/go-smtp-mock@v1.10.0/session.go:119 +0xe7
  github.com/mocktools/go-smtp-mock.(*Server).handleSession()
      /home/br/go/pkg/mod/github.com/mocktools/go-smtp-mock@v1.10.0/server.go:179 +0x204
  github.com/mocktools/go-smtp-mock.(*Server).Start.func1.1()
      /home/br/go/pkg/mod/github.com/mocktools/go-smtp-mock@v1.10.0/server.go:80 +0x7b

Goroutine 16 (running) created at:
  github.com/mocktools/go-smtp-mock.(*Server).Start.func1()
      /home/br/go/pkg/mod/github.com/mocktools/go-smtp-mock@v1.10.0/server.go:79 +0xae

Goroutine 19 (finished) created at:
  github.com/mocktools/go-smtp-mock.(*Server).Start.func1()
      /home/br/go/pkg/mod/github.com/mocktools/go-smtp-mock@v1.10.0/server.go:79 +0xae
==================
==================
WARNING: DATA RACE
Write at 0x00c0003300a0 by goroutine 16:
  sync/atomic.CompareAndSwapInt32()
      /usr/local/go/src/runtime/race_amd64.s:308 +0xb
  sync/atomic.CompareAndSwapInt32()
      <autogenerated>:1 +0x1e
  log.(*Logger).Output()
      /usr/local/go/src/log/log.go:176 +0x88
  log.(*Logger).Println()
      /usr/local/go/src/log/log.go:223 +0x84
  github.com/mocktools/go-smtp-mock.(*eventLogger).error()
      /home/br/go/pkg/mod/github.com/mocktools/go-smtp-mock@v1.10.0/logger.go:82 +0x284
  github.com/mocktools/go-smtp-mock.(*session).readRequest()
      /home/br/go/pkg/mod/github.com/mocktools/go-smtp-mock@v1.10.0/session.go:119 +0xe7
  github.com/mocktools/go-smtp-mock.(*Server).handleSession()
      /home/br/go/pkg/mod/github.com/mocktools/go-smtp-mock@v1.10.0/server.go:179 +0x204
  github.com/mocktools/go-smtp-mock.(*Server).Start.func1.1()
      /home/br/go/pkg/mod/github.com/mocktools/go-smtp-mock@v1.10.0/server.go:80 +0x7b

Previous write at 0x00c0003300a0 by goroutine 19:
  log.New()
      /usr/local/go/src/log/log.go:68 +0xc6
  github.com/mocktools/go-smtp-mock.(*eventLogger).error()
      /home/br/go/pkg/mod/github.com/mocktools/go-smtp-mock@v1.10.0/logger.go:79 +0x75
  github.com/mocktools/go-smtp-mock.(*session).readRequest()
      /home/br/go/pkg/mod/github.com/mocktools/go-smtp-mock@v1.10.0/session.go:119 +0xe7
  github.com/mocktools/go-smtp-mock.(*Server).handleSession()
      /home/br/go/pkg/mod/github.com/mocktools/go-smtp-mock@v1.10.0/server.go:179 +0x204
  github.com/mocktools/go-smtp-mock.(*Server).Start.func1.1()
      /home/br/go/pkg/mod/github.com/mocktools/go-smtp-mock@v1.10.0/server.go:80 +0x7b

Goroutine 16 (running) created at:
  github.com/mocktools/go-smtp-mock.(*Server).Start.func1()
      /home/br/go/pkg/mod/github.com/mocktools/go-smtp-mock@v1.10.0/server.go:79 +0xae

Goroutine 19 (finished) created at:
  github.com/mocktools/go-smtp-mock.(*Server).Start.func1()
      /home/br/go/pkg/mod/github.com/mocktools/go-smtp-mock@v1.10.0/server.go:79 +0xae
==================
ERROR: 2022/11/10 17:05:50.889228 read tcp 127.0.0.1:43145->127.0.0.1:49546: read: connection reset by peer
INFO: 2022/11/10 17:05:50.889303 SMTP session finished
INFO: 2022/11/10 17:05:50.890609 SMTP response: 250 Received
INFO: 2022/11/10 17:05:50.890655 SMTP request: RCPT TO:<someone@example.org>
INFO: 2022/11/10 17:05:50.895050 SMTP response: 250 Received
INFO: 2022/11/10 17:05:50.895092 SMTP request: DATA
INFO: 2022/11/10 17:05:50.895190 SMTP response: 354 Ready for receive message. End data with <CR><LF>.<CR><LF>
INFO: 2022/11/10 17:05:50.895226 SMTP request: message binary data portion
INFO: 2022/11/10 17:05:50.895236 SMTP request: message binary data portion
INFO: 2022/11/10 17:05:50.895250 SMTP response: 250 Received
INFO: 2022/11/10 17:05:50.895284 SMTP request: QUIT
INFO: 2022/11/10 17:05:50.895368 SMTP response: 221 Closing connection
INFO: 2022/11/10 17:05:50.895387 SMTP session finished
INFO: 2022/11/10 17:05:50.905903 SMTP session started
INFO: 2022/11/10 17:05:50.905951 SMTP response: 220 Welcome
INFO: 2022/11/10 17:05:50.906008 SMTP request: EHLO localhost
INFO: 2022/11/10 17:05:50.909605 SMTP response: 250 Received
INFO: 2022/11/10 17:05:50.909655 SMTP request: MAIL FROM:<someone@example.org>
INFO: 2022/11/10 17:05:50.912594 SMTP response: 250 Received
INFO: 2022/11/10 17:05:50.912629 SMTP request: RCPT TO:<ben@vxxxxxx.testing.invalid>
INFO: 2022/11/10 17:05:50.916907 SMTP response: 250 Received
INFO: 2022/11/10 17:05:50.916953 SMTP request: RCPT TO:<peanut@butter.invalid>
INFO: 2022/11/10 17:05:50.921127 SMTP response: 250 Received
INFO: 2022/11/10 17:05:50.921170 SMTP request: DATA
INFO: 2022/11/10 17:05:50.921270 SMTP response: 354 Ready for receive message. End data with <CR><LF>.<CR><LF>
INFO: 2022/11/10 17:05:50.921296 SMTP request: message binary data portion
INFO: 2022/11/10 17:05:50.921306 SMTP request: message binary data portion
INFO: 2022/11/10 17:05:50.921318 SMTP response: 250 Received
INFO: 2022/11/10 17:05:50.921348 SMTP request: QUIT
INFO: 2022/11/10 17:05:50.921426 SMTP response: 221 Closing connection
INFO: 2022/11/10 17:05:50.921442 SMTP session finished
INFO: 2022/11/10 17:05:50.931890 SMTP session started
INFO: 2022/11/10 17:05:50.931967 SMTP response: 220 Welcome
INFO: 2022/11/10 17:05:50.932040 SMTP request: EHLO localhost
INFO: 2022/11/10 17:05:50.936743 SMTP response: 250 Received
INFO: 2022/11/10 17:05:50.936792 SMTP request: MAIL FROM:<ben@vxxxxxx.testing.invalid>
INFO: 2022/11/10 17:05:50.941325 SMTP response: 250 Received
INFO: 2022/11/10 17:05:50.941369 SMTP request: RCPT TO:<peanut@butter.invalid>
INFO: 2022/11/10 17:05:50.947843 SMTP response: 250 Received
INFO: 2022/11/10 17:05:50.947883 SMTP request: RCPT TO:<someone@example.org>
INFO: 2022/11/10 17:05:50.954301 SMTP response: 250 Received
INFO: 2022/11/10 17:05:50.954346 SMTP request: DATA
INFO: 2022/11/10 17:05:50.954527 SMTP response: 354 Ready for receive message. End data with <CR><LF>.<CR><LF>
INFO: 2022/11/10 17:05:50.954566 SMTP request: message binary data portion
INFO: 2022/11/10 17:05:50.954579 SMTP request: message binary data portion
INFO: 2022/11/10 17:05:50.954599 SMTP response: 250 Received
INFO: 2022/11/10 17:05:50.954634 SMTP request: QUIT
INFO: 2022/11/10 17:05:50.954759 SMTP response: 221 Closing connection
INFO: 2022/11/10 17:05:50.954802 SMTP session finished
INFO: 2022/11/10 17:05:50.965330 SMTP session started
INFO: 2022/11/10 17:05:50.965423 SMTP response: 220 Welcome
INFO: 2022/11/10 17:05:50.965479 SMTP request: EHLO localhost
INFO: 2022/11/10 17:05:50.971722 SMTP response: 250 Received
INFO: 2022/11/10 17:05:50.971760 SMTP request: MAIL FROM:<peanut@butter.invalid>
INFO: 2022/11/10 17:05:50.977719 SMTP response: 250 Received
INFO: 2022/11/10 17:05:50.977756 SMTP request: RCPT TO:<someone@example.org>
INFO: 2022/11/10 17:05:50.987160 SMTP response: 250 Received
INFO: 2022/11/10 17:05:50.987220 SMTP request: RCPT TO:<ben@vxxxxxx.testing.invalid>
INFO: 2022/11/10 17:05:50.996182 SMTP response: 250 Received
INFO: 2022/11/10 17:05:50.996260 SMTP request: DATA
INFO: 2022/11/10 17:05:50.996443 SMTP response: 354 Ready for receive message. End data with <CR><LF>.<CR><LF>
INFO: 2022/11/10 17:05:50.996507 SMTP request: message binary data portion
INFO: 2022/11/10 17:05:50.996523 SMTP request: message binary data portion
INFO: 2022/11/10 17:05:50.996551 SMTP response: 250 Received
INFO: 2022/11/10 17:05:50.996608 SMTP request: QUIT
INFO: 2022/11/10 17:05:50.996802 SMTP response: 221 Closing connection
INFO: 2022/11/10 17:05:50.996861 SMTP session finished
--- FAIL: TestSMTPTransport_Send (0.21s)
    --- FAIL: TestSMTPTransport_Send/hello_world_email_from_ben_to_someone (0.02s)
        testing.go:1312: race detected during execution of test
    testing.go:1312: race detected during execution of test
FAIL
2022/11/10 17:05:51 1
WARNING: 2022/11/10 17:05:51.047892 SMTP mock server is in the shutdown mode and won't accept new connections
INFO: 2022/11/10 17:05:51.047984 SMTP mock server was stopped successfully
FAIL	bitbucket.org/vxxxxxxx/cxxxxxxxx/internal/mailer	0.262s
FAIL
@benjamin-rood benjamin-rood added the bug Something isn't working label Nov 10, 2022
@bestwebua
Copy link
Member

bestwebua commented Nov 10, 2022

@benjamin-rood Hello! Good catch 👍 Thanks for your report. Seems like it an urgent issue, I'll take a look as soon as possible. I will be grateful for suggestions.

@benjamin-rood
Copy link
Collaborator Author

benjamin-rood commented Nov 11, 2022

Thanks for your prompt acknowledgement, Vladislav. Yes, it's very urgent, I think!

I will be grateful for suggestions.

To begin with, can you tell me: Am I doing it the correct way, by creating a mock server instance in TestMain?

Secondly, is this the first time you have encountered any reports of race conditions?

The only possible issue I can notice on the caller side—i.e. my code, SMTPTransport.Send(...) being tested—is that on encountering an error I'm not sending a signal to the server to finish the session before bailing out and returning an error. So, I will fix that in my code to rule out that as a cause, but, at a minimum you will need to use the sync.RWMutex in any reads as well as part of the writes. The lock doesn't automagically work, readers and writers both need to use it.

@benjamin-rood
Copy link
Collaborator Author

benjamin-rood commented Nov 11, 2022

Just cloned this repo and ran the tests with the -race flag. Race condition detected, so we can rule out my use of the library as the cause.

❯ go test -race ./...
==================
WARNING: DATA RACE
Read at 0x00c0001a6708 by goroutine 46:
  github.com/mocktools/go-smtp-mock.TestServerStop.func1()
      /wrk/github.com/mocktools/go-smtp-mock/server_test.go:407 +0x553
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:1439 +0x213
  testing.(*T).Run.func1()
      /usr/local/go/src/testing/testing.go:1486 +0x47

Previous write at 0x00c0001a6708 by goroutine 49:
  github.com/mocktools/go-smtp-mock.(*Server).Stop.func1()
      /wrk/github.com/mocktools/go-smtp-mock/server.go:101 +0x94

Goroutine 46 (running) created at:
  testing.(*T).Run()
      /usr/local/go/src/testing/testing.go:1486 +0x724
  github.com/mocktools/go-smtp-mock.TestServerStop()
      /wrk/github.com/mocktools/go-smtp-mock/server_test.go:391 +0x44
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:1439 +0x213
  testing.(*T).Run.func1()
      /usr/local/go/src/testing/testing.go:1486 +0x47

Goroutine 49 (running) created at:
  github.com/mocktools/go-smtp-mock.(*Server).Stop()
      /wrk/github.com/mocktools/go-smtp-mock/server.go:98 +0x11d
  github.com/mocktools/go-smtp-mock.TestServerStop.func1()
      /wrk/github.com/mocktools/go-smtp-mock/server_test.go:406 +0x524
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:1439 +0x213
  testing.(*T).Run.func1()
      /usr/local/go/src/testing/testing.go:1486 +0x47
==================
--- FAIL: TestServerStop (1.00s)
    --- FAIL: TestServerStop/when_server_active_stops_current_server,_graceful_shutdown_case (0.00s)
        testing.go:1312: race detected during execution of test
    testing.go:1312: race detected during execution of test
==================
WARNING: DATA RACE
Read at 0x00c00060f488 by goroutine 25:
  github.com/mocktools/go-smtp-mock.TestNew.func3()
      /wrk/github.com/mocktools/go-smtp-mock/smtpmock_test.go:158 +0x3f7
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:1439 +0x213
  testing.(*T).Run.func1()
      /usr/local/go/src/testing/testing.go:1486 +0x47

Previous write at 0x00c00060f488 by goroutine 21:
  github.com/mocktools/go-smtp-mock.(*Server).Stop.func1()
      /wrk/github.com/mocktools/go-smtp-mock/server.go:101 +0x94

Goroutine 25 (running) created at:
  testing.(*T).Run()
      /usr/local/go/src/testing/testing.go:1486 +0x724
  github.com/mocktools/go-smtp-mock.TestNew()
      /wrk/github.com/mocktools/go-smtp-mock/smtpmock_test.go:141 +0x84
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:1439 +0x213
  testing.(*T).Run.func1()
      /usr/local/go/src/testing/testing.go:1486 +0x47

Goroutine 21 (finished) created at:
  github.com/mocktools/go-smtp-mock.(*Server).Stop()
      /wrk/github.com/mocktools/go-smtp-mock/server.go:98 +0x11d
  github.com/mocktools/go-smtp-mock.TestNew.func3()
      /wrk/github.com/mocktools/go-smtp-mock/smtpmock_test.go:154 +0x351
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:1439 +0x213
  testing.(*T).Run.func1()
      /usr/local/go/src/testing/testing.go:1486 +0x47
==================
--- FAIL: TestNew (0.03s)
    --- FAIL: TestNew/successful_iteration_with_new_server (0.03s)
        testing.go:1312: race detected during execution of test
    testing.go:1312: race detected during execution of test
FAIL
FAIL	github.com/mocktools/go-smtp-mock	1.373s
ok  	github.com/mocktools/go-smtp-mock/cmd	0.028s
?   	github.com/mocktools/go-smtp-mock/cmd/version	[no test files]
FAIL

Full verbose output:

❯ go test -race -v ./...
=== RUN   TestNewConfiguration
=== RUN   TestNewConfiguration/creates_new_configuration_with_default_settings
=== RUN   TestNewConfiguration/creates_new_configuration_with_custom_settings
--- PASS: TestNewConfiguration (0.00s)
    --- PASS: TestNewConfiguration/creates_new_configuration_with_default_settings (0.00s)
    --- PASS: TestNewConfiguration/creates_new_configuration_with_custom_settings (0.00s)
=== RUN   TestConfigurationAttrAssignDefaultValues
=== RUN   TestConfigurationAttrAssignDefaultValues/assignes_default_values
--- PASS: TestConfigurationAttrAssignDefaultValues (0.00s)
    --- PASS: TestConfigurationAttrAssignDefaultValues/assignes_default_values (0.00s)
=== RUN   TestNewHandlerData
=== RUN   TestNewHandlerData/returns_new_handlerData
--- PASS: TestNewHandlerData (0.00s)
    --- PASS: TestNewHandlerData/returns_new_handlerData (0.00s)
=== RUN   TestHandlerDataRun
=== RUN   TestHandlerDataRun/when_successful_DATA_request
=== RUN   TestHandlerDataRun/when_failure_DATA_request,_invalid_command_sequence
=== RUN   TestHandlerDataRun/when_failure_DATA_request,_invalid_command
--- PASS: TestHandlerDataRun (0.00s)
    --- PASS: TestHandlerDataRun/when_successful_DATA_request (0.00s)
    --- PASS: TestHandlerDataRun/when_failure_DATA_request,_invalid_command_sequence (0.00s)
    --- PASS: TestHandlerDataRun/when_failure_DATA_request,_invalid_command (0.00s)
=== RUN   TestHandlerDataClearMessage
=== RUN   TestHandlerDataClearMessage/erases_all_handler_message_data_from_DATA_command
--- PASS: TestHandlerDataClearMessage (0.00s)
    --- PASS: TestHandlerDataClearMessage/erases_all_handler_message_data_from_DATA_command (0.00s)
=== RUN   TestHandlerDataProcessIncomingMessage
--- PASS: TestHandlerDataProcessIncomingMessage (0.00s)
=== RUN   TestHandlerDataWriteResult
=== RUN   TestHandlerDataWriteResult/when_successful_request_received
=== RUN   TestHandlerDataWriteResult/when_failed_request_received
--- PASS: TestHandlerDataWriteResult (0.00s)
    --- PASS: TestHandlerDataWriteResult/when_successful_request_received (0.00s)
    --- PASS: TestHandlerDataWriteResult/when_failed_request_received (0.00s)
=== RUN   TestHandlerDataIsInvalidCmdSequence
=== RUN   TestHandlerDataIsInvalidCmdSequence/when_none_of_the_previous_command_was_successful
=== RUN   TestHandlerDataIsInvalidCmdSequence/when_rcptto_previous_command_was_failure
=== RUN   TestHandlerDataIsInvalidCmdSequence/when_mailfrom,_rcptto_previous_commands_were_failure
=== RUN   TestHandlerDataIsInvalidCmdSequence/when_all_of_the_previous_commands_was_successful
--- PASS: TestHandlerDataIsInvalidCmdSequence (0.00s)
    --- PASS: TestHandlerDataIsInvalidCmdSequence/when_none_of_the_previous_command_was_successful (0.00s)
    --- PASS: TestHandlerDataIsInvalidCmdSequence/when_rcptto_previous_command_was_failure (0.00s)
    --- PASS: TestHandlerDataIsInvalidCmdSequence/when_mailfrom,_rcptto_previous_commands_were_failure (0.00s)
    --- PASS: TestHandlerDataIsInvalidCmdSequence/when_all_of_the_previous_commands_was_successful (0.00s)
=== RUN   TestHandlerDataIsInvalidCmd
=== RUN   TestHandlerDataIsInvalidCmd/when_request_includes_invalid_command_DATA
=== RUN   TestHandlerDataIsInvalidCmd/when_request_includes_valid_command_DATA
--- PASS: TestHandlerDataIsInvalidCmd (0.00s)
    --- PASS: TestHandlerDataIsInvalidCmd/when_request_includes_invalid_command_DATA (0.00s)
    --- PASS: TestHandlerDataIsInvalidCmd/when_request_includes_valid_command_DATA (0.00s)
=== RUN   TestHandlerDataIsInvalidRequest
=== RUN   TestHandlerDataIsInvalidRequest/when_request_includes_invalid_DATA_command_sequence
=== RUN   TestHandlerDataIsInvalidRequest/when_request_includes_invalid_command_DATA
=== RUN   TestHandlerDataIsInvalidRequest/when_valid_DATA_request
--- PASS: TestHandlerDataIsInvalidRequest (0.00s)
    --- PASS: TestHandlerDataIsInvalidRequest/when_request_includes_invalid_DATA_command_sequence (0.00s)
    --- PASS: TestHandlerDataIsInvalidRequest/when_request_includes_invalid_command_DATA (0.00s)
    --- PASS: TestHandlerDataIsInvalidRequest/when_valid_DATA_request (0.00s)
=== RUN   TestNewHandlerHelo
=== RUN   TestNewHandlerHelo/returns_new_handlerHelo
--- PASS: TestNewHandlerHelo (0.00s)
    --- PASS: TestNewHandlerHelo/returns_new_handlerHelo (0.00s)
=== RUN   TestHandlerHeloRun
=== RUN   TestHandlerHeloRun/when_successful_HELO_request
=== RUN   TestHandlerHeloRun/when_failure_HELO_request,_invalid_command_argument
=== RUN   TestHandlerHeloRun/when_failure_HELO_request,_blacklisted_HELO_domain
--- PASS: TestHandlerHeloRun (0.01s)
    --- PASS: TestHandlerHeloRun/when_successful_HELO_request (0.00s)
    --- PASS: TestHandlerHeloRun/when_failure_HELO_request,_invalid_command_argument (0.00s)
    --- PASS: TestHandlerHeloRun/when_failure_HELO_request,_blacklisted_HELO_domain (0.00s)
=== RUN   TestHandlerHeloClearMessage
=== RUN   TestHandlerHeloClearMessage/erases_all_handler_message_data
--- PASS: TestHandlerHeloClearMessage (0.00s)
    --- PASS: TestHandlerHeloClearMessage/erases_all_handler_message_data (0.00s)
=== RUN   TestHandlerHeloWriteResult
=== RUN   TestHandlerHeloWriteResult/when_successful_request_received
=== RUN   TestHandlerHeloWriteResult/when_failed_request_received
--- PASS: TestHandlerHeloWriteResult (0.00s)
    --- PASS: TestHandlerHeloWriteResult/when_successful_request_received (0.00s)
    --- PASS: TestHandlerHeloWriteResult/when_failed_request_received (0.00s)
=== RUN   TestHandlerHeloIsInvalidCmdArg
=== RUN   TestHandlerHeloIsInvalidCmdArg/when_request_includes_invalid_command_HELO_argument
=== RUN   TestHandlerHeloIsInvalidCmdArg/when_request_includes_valid_command_HELO_argument
=== RUN   TestHandlerHeloIsInvalidCmdArg/when_request_includes_localhost_HELO_argument
=== RUN   TestHandlerHeloIsInvalidCmdArg/when_request_includes_valid_ip_address_HELO_argument
=== RUN   TestHandlerHeloIsInvalidCmdArg/when_request_includes_valid_address_literal_HELO_argument
=== RUN   TestHandlerHeloIsInvalidCmdArg/when_request_includes_invalid_ip_address_HELO_argument
=== RUN   TestHandlerHeloIsInvalidCmdArg/when_request_includes_invalid_address_literal_HELO_argument
=== RUN   TestHandlerHeloIsInvalidCmdArg/when_request_includes_malformed_(left)_address_literal_HELO_argument
=== RUN   TestHandlerHeloIsInvalidCmdArg/when_request_includes_malformed_(right)_address_literal_HELO_argument
--- PASS: TestHandlerHeloIsInvalidCmdArg (0.02s)
    --- PASS: TestHandlerHeloIsInvalidCmdArg/when_request_includes_invalid_command_HELO_argument (0.00s)
    --- PASS: TestHandlerHeloIsInvalidCmdArg/when_request_includes_valid_command_HELO_argument (0.00s)
    --- PASS: TestHandlerHeloIsInvalidCmdArg/when_request_includes_localhost_HELO_argument (0.00s)
    --- PASS: TestHandlerHeloIsInvalidCmdArg/when_request_includes_valid_ip_address_HELO_argument (0.00s)
    --- PASS: TestHandlerHeloIsInvalidCmdArg/when_request_includes_valid_address_literal_HELO_argument (0.00s)
    --- PASS: TestHandlerHeloIsInvalidCmdArg/when_request_includes_invalid_ip_address_HELO_argument (0.00s)
    --- PASS: TestHandlerHeloIsInvalidCmdArg/when_request_includes_invalid_address_literal_HELO_argument (0.00s)
    --- PASS: TestHandlerHeloIsInvalidCmdArg/when_request_includes_malformed_(left)_address_literal_HELO_argument (0.00s)
    --- PASS: TestHandlerHeloIsInvalidCmdArg/when_request_includes_malformed_(right)_address_literal_HELO_argument (0.00s)
=== RUN   TestHandlerHeloHeloDomain
=== RUN   TestHandlerHeloHeloDomain/when_request_includes_valid_domain_name
=== RUN   TestHandlerHeloHeloDomain/when_request_includes_localhost
=== RUN   TestHandlerHeloHeloDomain/when_request_not_includes_valid_domain_name
--- PASS: TestHandlerHeloHeloDomain (0.01s)
    --- PASS: TestHandlerHeloHeloDomain/when_request_includes_valid_domain_name (0.00s)
    --- PASS: TestHandlerHeloHeloDomain/when_request_includes_localhost (0.00s)
    --- PASS: TestHandlerHeloHeloDomain/when_request_not_includes_valid_domain_name (0.00s)
=== RUN   TestHandlerHeloIsBlacklistedDomain
=== RUN   TestHandlerHeloIsBlacklistedDomain/when_request_includes_blacklisted_domain_name
=== RUN   TestHandlerHeloIsBlacklistedDomain/when_request_not_includes_blacklisted_domain_name
--- PASS: TestHandlerHeloIsBlacklistedDomain (0.00s)
    --- PASS: TestHandlerHeloIsBlacklistedDomain/when_request_includes_blacklisted_domain_name (0.00s)
    --- PASS: TestHandlerHeloIsBlacklistedDomain/when_request_not_includes_blacklisted_domain_name (0.00s)
=== RUN   TestHandlerHeloIsInvalidRequest
=== RUN   TestHandlerHeloIsInvalidRequest/when_request_includes_invalid_HELO_command_argument
=== RUN   TestHandlerHeloIsInvalidRequest/when_valid_HELO_request
=== RUN   TestHandlerHeloIsInvalidRequest/when_valid_HELO_request#01
=== RUN   TestHandlerHeloIsInvalidRequest/when_valid_HELO_request#02
=== RUN   TestHandlerHeloIsInvalidRequest/when_valid_HELO_request#03
=== RUN   TestHandlerHeloIsInvalidRequest/when_request_includes_blacklisted_HELO_domain
=== RUN   TestHandlerHeloIsInvalidRequest/when_request_includes_blacklisted_HELO_domain#01
=== RUN   TestHandlerHeloIsInvalidRequest/when_request_includes_blacklisted_HELO_domain#02
=== RUN   TestHandlerHeloIsInvalidRequest/when_request_includes_blacklisted_HELO_domain#03
--- PASS: TestHandlerHeloIsInvalidRequest (0.03s)
    --- PASS: TestHandlerHeloIsInvalidRequest/when_request_includes_invalid_HELO_command_argument (0.00s)
    --- PASS: TestHandlerHeloIsInvalidRequest/when_valid_HELO_request (0.00s)
    --- PASS: TestHandlerHeloIsInvalidRequest/when_valid_HELO_request#01 (0.00s)
    --- PASS: TestHandlerHeloIsInvalidRequest/when_valid_HELO_request#02 (0.00s)
    --- PASS: TestHandlerHeloIsInvalidRequest/when_valid_HELO_request#03 (0.00s)
    --- PASS: TestHandlerHeloIsInvalidRequest/when_request_includes_blacklisted_HELO_domain (0.00s)
    --- PASS: TestHandlerHeloIsInvalidRequest/when_request_includes_blacklisted_HELO_domain#01 (0.00s)
    --- PASS: TestHandlerHeloIsInvalidRequest/when_request_includes_blacklisted_HELO_domain#02 (0.00s)
    --- PASS: TestHandlerHeloIsInvalidRequest/when_request_includes_blacklisted_HELO_domain#03 (0.01s)
=== RUN   TestNewHandlerMailfrom
=== RUN   TestNewHandlerMailfrom/returns_new_handlerMailfrom
--- PASS: TestNewHandlerMailfrom (0.00s)
    --- PASS: TestNewHandlerMailfrom/returns_new_handlerMailfrom (0.00s)
=== RUN   TestHandlerMailfromRun
=== RUN   TestHandlerMailfromRun/when_successful_MAILFROM_request
=== RUN   TestHandlerMailfromRun/when_failure_MAILFROM_request,_invalid_command_sequence
=== RUN   TestHandlerMailfromRun/when_failure_MAILFROM_request,_invalid_command_argument
=== RUN   TestHandlerMailfromRun/when_failure_MAILFROM_request,_request_includes_blacklisted_MAILFROM_email
--- PASS: TestHandlerMailfromRun (0.01s)
    --- PASS: TestHandlerMailfromRun/when_successful_MAILFROM_request (0.00s)
    --- PASS: TestHandlerMailfromRun/when_failure_MAILFROM_request,_invalid_command_sequence (0.00s)
    --- PASS: TestHandlerMailfromRun/when_failure_MAILFROM_request,_invalid_command_argument (0.00s)
    --- PASS: TestHandlerMailfromRun/when_failure_MAILFROM_request,_request_includes_blacklisted_MAILFROM_email (0.01s)
=== RUN   TestHandlerMailfromClearMessage
=== RUN   TestHandlerMailfromClearMessage/erases_all_handler_message_data_from_MAILFROM_command
--- PASS: TestHandlerMailfromClearMessage (0.00s)
    --- PASS: TestHandlerMailfromClearMessage/erases_all_handler_message_data_from_MAILFROM_command (0.00s)
=== RUN   TestHandlerMailfromWriteResult
=== RUN   TestHandlerMailfromWriteResult/when_successful_request_received
=== RUN   TestHandlerMailfromWriteResult/when_failed_request_received
--- PASS: TestHandlerMailfromWriteResult (0.00s)
    --- PASS: TestHandlerMailfromWriteResult/when_successful_request_received (0.00s)
    --- PASS: TestHandlerMailfromWriteResult/when_failed_request_received (0.00s)
=== RUN   TestHandlerMailfromIsInvalidCmdSequence
=== RUN   TestHandlerMailfromIsInvalidCmdSequence/when_helo_previous_command_was_failure_
=== RUN   TestHandlerMailfromIsInvalidCmdSequence/when_helo_previous_command_was_successful_
--- PASS: TestHandlerMailfromIsInvalidCmdSequence (0.00s)
    --- PASS: TestHandlerMailfromIsInvalidCmdSequence/when_helo_previous_command_was_failure_ (0.00s)
    --- PASS: TestHandlerMailfromIsInvalidCmdSequence/when_helo_previous_command_was_successful_ (0.00s)
=== RUN   TestHandlerMaifromIsInvalidCmdArg
=== RUN   TestHandlerMaifromIsInvalidCmdArg/when_request_includes_invalid_command_MAILFROM_argument
=== RUN   TestHandlerMaifromIsInvalidCmdArg/when_request_includes_valid_command_MAILFROM_argument_without_<>_sign
=== RUN   TestHandlerMaifromIsInvalidCmdArg/when_request_includes_valid_command_MAILFROM_argument_without_<>_sign_without_space
=== RUN   TestHandlerMaifromIsInvalidCmdArg/when_request_includes_valid_command_MAILFROM_argument_with_<>_sign
=== RUN   TestHandlerMaifromIsInvalidCmdArg/when_request_includes_valid_command_MAILFROM_argument_with_<>_sign_without_space
--- PASS: TestHandlerMaifromIsInvalidCmdArg (0.01s)
    --- PASS: TestHandlerMaifromIsInvalidCmdArg/when_request_includes_invalid_command_MAILFROM_argument (0.00s)
    --- PASS: TestHandlerMaifromIsInvalidCmdArg/when_request_includes_valid_command_MAILFROM_argument_without_<>_sign (0.00s)
    --- PASS: TestHandlerMaifromIsInvalidCmdArg/when_request_includes_valid_command_MAILFROM_argument_without_<>_sign_without_space (0.00s)
    --- PASS: TestHandlerMaifromIsInvalidCmdArg/when_request_includes_valid_command_MAILFROM_argument_with_<>_sign (0.00s)
    --- PASS: TestHandlerMaifromIsInvalidCmdArg/when_request_includes_valid_command_MAILFROM_argument_with_<>_sign_without_space (0.00s)
=== RUN   TestHandlerMailfromMailfromEmail
=== RUN   TestHandlerMailfromMailfromEmail/when_request_includes_valid_email_address_without_<>_sign
=== RUN   TestHandlerMailfromMailfromEmail/when_request_includes_valid_email_address_with_<>_sign
=== RUN   TestHandlerMailfromMailfromEmail/when_request_includes_invalid_email_address
--- PASS: TestHandlerMailfromMailfromEmail (0.00s)
    --- PASS: TestHandlerMailfromMailfromEmail/when_request_includes_valid_email_address_without_<>_sign (0.00s)
    --- PASS: TestHandlerMailfromMailfromEmail/when_request_includes_valid_email_address_with_<>_sign (0.00s)
    --- PASS: TestHandlerMailfromMailfromEmail/when_request_includes_invalid_email_address (0.00s)
=== RUN   TestHandlerHeloIsBlacklistedEmail
=== RUN   TestHandlerHeloIsBlacklistedEmail/when_request_includes_blacklisted_domain_name
=== RUN   TestHandlerHeloIsBlacklistedEmail/when_request_not_includes_blacklisted_domain_name
--- PASS: TestHandlerHeloIsBlacklistedEmail (0.01s)
    --- PASS: TestHandlerHeloIsBlacklistedEmail/when_request_includes_blacklisted_domain_name (0.00s)
    --- PASS: TestHandlerHeloIsBlacklistedEmail/when_request_not_includes_blacklisted_domain_name (0.00s)
=== RUN   TestHandlerMailfromIsInvalidRequest
=== RUN   TestHandlerMailfromIsInvalidRequest/when_request_includes_invalid_MAILFROM_command_sequence,_the_previous_command_is_not_successful
=== RUN   TestHandlerMailfromIsInvalidRequest/when_request_includes_invalid_MAILFROM_command_argument
=== RUN   TestHandlerMailfromIsInvalidRequest/when_request_includes_blacklisted_MAILFROM_email
=== RUN   TestHandlerMailfromIsInvalidRequest/when_valid_MAILFROM_request
--- PASS: TestHandlerMailfromIsInvalidRequest (0.02s)
    --- PASS: TestHandlerMailfromIsInvalidRequest/when_request_includes_invalid_MAILFROM_command_sequence,_the_previous_command_is_not_successful (0.00s)
    --- PASS: TestHandlerMailfromIsInvalidRequest/when_request_includes_invalid_MAILFROM_command_argument (0.00s)
    --- PASS: TestHandlerMailfromIsInvalidRequest/when_request_includes_blacklisted_MAILFROM_email (0.01s)
    --- PASS: TestHandlerMailfromIsInvalidRequest/when_valid_MAILFROM_request (0.01s)
=== RUN   TestNewHandlerMessage
=== RUN   TestNewHandlerMessage/returns_new_handlerMessage
--- PASS: TestNewHandlerMessage (0.00s)
    --- PASS: TestNewHandlerMessage/returns_new_handlerMessage (0.00s)
=== RUN   TestHandlerMessageRun
=== RUN   TestHandlerMessageRun/when_read_request_error
=== RUN   TestHandlerMessageRun/when_message_size_limit_reached
=== RUN   TestHandlerMessageRun/when_message_received
--- PASS: TestHandlerMessageRun (0.00s)
    --- PASS: TestHandlerMessageRun/when_read_request_error (0.00s)
    --- PASS: TestHandlerMessageRun/when_message_size_limit_reached (0.00s)
    --- PASS: TestHandlerMessageRun/when_message_received (0.00s)
=== RUN   TestHandlerMessageWriteResult
=== RUN   TestHandlerMessageWriteResult/when_successful_request_received
=== RUN   TestHandlerMessageWriteResult/when_failed_request_received
--- PASS: TestHandlerMessageWriteResult (0.00s)
    --- PASS: TestHandlerMessageWriteResult/when_successful_request_received (0.00s)
    --- PASS: TestHandlerMessageWriteResult/when_failed_request_received (0.00s)
=== RUN   TestNewHandlerQuit
=== RUN   TestNewHandlerQuit/returns_new_handlerQuit
--- PASS: TestNewHandlerQuit (0.00s)
    --- PASS: TestNewHandlerQuit/returns_new_handlerQuit (0.00s)
=== RUN   TestHandlerQuitRun
=== RUN   TestHandlerQuitRun/when_successful_QUIT_request
=== RUN   TestHandlerQuitRun/when_failure_QUIT_request
--- PASS: TestHandlerQuitRun (0.00s)
    --- PASS: TestHandlerQuitRun/when_successful_QUIT_request (0.00s)
    --- PASS: TestHandlerQuitRun/when_failure_QUIT_request (0.00s)
=== RUN   TestHandlerQuitIsInvalidRequest
=== RUN   TestHandlerQuitIsInvalidRequest/when_request_includes_invalid_QUIT_command
=== RUN   TestHandlerQuitIsInvalidRequest/when_request_includes_valid_QUIT_command
--- PASS: TestHandlerQuitIsInvalidRequest (0.00s)
    --- PASS: TestHandlerQuitIsInvalidRequest/when_request_includes_invalid_QUIT_command (0.00s)
    --- PASS: TestHandlerQuitIsInvalidRequest/when_request_includes_valid_QUIT_command (0.00s)
=== RUN   TestNewHandlerRcptto
=== RUN   TestNewHandlerRcptto/returns_new_handlerRcptto
--- PASS: TestNewHandlerRcptto (0.00s)
    --- PASS: TestNewHandlerRcptto/returns_new_handlerRcptto (0.00s)
=== RUN   TestHandlerRcpttoRun
=== RUN   TestHandlerRcpttoRun/when_successful_RCPTTO_request
=== RUN   TestHandlerRcpttoRun/when_failure_RCPTTO_request,_invalid_command_sequence
=== RUN   TestHandlerRcpttoRun/when_failure_RCPTTO_request,_invalid_command_argument
=== RUN   TestHandlerRcpttoRun/when_failure_RCPTTO_request,_request_includes_blacklisted_RCPTTO_email
=== RUN   TestHandlerRcpttoRun/when_failure_RCPTTO_request,_request_includes_not_registered_RCPTTO_email
--- PASS: TestHandlerRcpttoRun (0.02s)
    --- PASS: TestHandlerRcpttoRun/when_successful_RCPTTO_request (0.01s)
    --- PASS: TestHandlerRcpttoRun/when_failure_RCPTTO_request,_invalid_command_sequence (0.00s)
    --- PASS: TestHandlerRcpttoRun/when_failure_RCPTTO_request,_invalid_command_argument (0.00s)
    --- PASS: TestHandlerRcpttoRun/when_failure_RCPTTO_request,_request_includes_blacklisted_RCPTTO_email (0.01s)
    --- PASS: TestHandlerRcpttoRun/when_failure_RCPTTO_request,_request_includes_not_registered_RCPTTO_email (0.01s)
=== RUN   TestHandlerRcpttoClearMessage
=== RUN   TestHandlerRcpttoClearMessage/erases_all_handler_message_data_from_RCPTTO_command
--- PASS: TestHandlerRcpttoClearMessage (0.00s)
    --- PASS: TestHandlerRcpttoClearMessage/erases_all_handler_message_data_from_RCPTTO_command (0.00s)
=== RUN   TestHandlerRcpttoWriteResult
=== RUN   TestHandlerRcpttoWriteResult/when_successful_request_received
=== RUN   TestHandlerRcpttoWriteResult/when_failed_request_received
--- PASS: TestHandlerRcpttoWriteResult (0.00s)
    --- PASS: TestHandlerRcpttoWriteResult/when_successful_request_received (0.00s)
    --- PASS: TestHandlerRcpttoWriteResult/when_failed_request_received (0.00s)
=== RUN   TestHandlerRcpttoIsInvalidCmdSequence
=== RUN   TestHandlerRcpttoIsInvalidCmdSequence/when_none_of_the_previous_command_was_successful
=== RUN   TestHandlerRcpttoIsInvalidCmdSequence/when_mailfrom_previous_command_was_failure
=== RUN   TestHandlerRcpttoIsInvalidCmdSequence/when_all_of_the_previous_commands_was_successful
--- PASS: TestHandlerRcpttoIsInvalidCmdSequence (0.00s)
    --- PASS: TestHandlerRcpttoIsInvalidCmdSequence/when_none_of_the_previous_command_was_successful (0.00s)
    --- PASS: TestHandlerRcpttoIsInvalidCmdSequence/when_mailfrom_previous_command_was_failure (0.00s)
    --- PASS: TestHandlerRcpttoIsInvalidCmdSequence/when_all_of_the_previous_commands_was_successful (0.00s)
=== RUN   TestHandlerRcpttoIsInvalidCmdArg
=== RUN   TestHandlerRcpttoIsInvalidCmdArg/when_request_includes_invalid_command_RCPTTO_argument
=== RUN   TestHandlerRcpttoIsInvalidCmdArg/when_request_includes_valid_command_RCPTTO_argument_without_<>_sign
=== RUN   TestHandlerRcpttoIsInvalidCmdArg/when_request_includes_valid_command_RCPTTO_argument_without_<>_sign_without_space
=== RUN   TestHandlerRcpttoIsInvalidCmdArg/when_request_includes_valid_command_RCPTTO_argument_with_<>_sign
=== RUN   TestHandlerRcpttoIsInvalidCmdArg/when_request_includes_valid_command_RCPTTO_argument_with_<>_sign_withoyt_space
--- PASS: TestHandlerRcpttoIsInvalidCmdArg (0.02s)
    --- PASS: TestHandlerRcpttoIsInvalidCmdArg/when_request_includes_invalid_command_RCPTTO_argument (0.00s)
    --- PASS: TestHandlerRcpttoIsInvalidCmdArg/when_request_includes_valid_command_RCPTTO_argument_without_<>_sign (0.00s)
    --- PASS: TestHandlerRcpttoIsInvalidCmdArg/when_request_includes_valid_command_RCPTTO_argument_without_<>_sign_without_space (0.00s)
    --- PASS: TestHandlerRcpttoIsInvalidCmdArg/when_request_includes_valid_command_RCPTTO_argument_with_<>_sign (0.00s)
    --- PASS: TestHandlerRcpttoIsInvalidCmdArg/when_request_includes_valid_command_RCPTTO_argument_with_<>_sign_withoyt_space (0.00s)
=== RUN   TestHandlerRcpttoRcpttoEmail
=== RUN   TestHandlerRcpttoRcpttoEmail/when_request_includes_valid_email_address_without_<>_sign
=== RUN   TestHandlerRcpttoRcpttoEmail/when_request_includes_valid_email_address_with_<>_sign
=== RUN   TestHandlerRcpttoRcpttoEmail/when_request_includes_invalid_email_address
--- PASS: TestHandlerRcpttoRcpttoEmail (0.01s)
    --- PASS: TestHandlerRcpttoRcpttoEmail/when_request_includes_valid_email_address_without_<>_sign (0.00s)
    --- PASS: TestHandlerRcpttoRcpttoEmail/when_request_includes_valid_email_address_with_<>_sign (0.00s)
    --- PASS: TestHandlerRcpttoRcpttoEmail/when_request_includes_invalid_email_address (0.00s)
=== RUN   TestHandlerRcpttoIsBlacklistedEmail
=== RUN   TestHandlerRcpttoIsBlacklistedEmail/when_request_includes_blacklisted_domain_name
=== RUN   TestHandlerRcpttoIsBlacklistedEmail/when_request_not_includes_blacklisted_domain_name
--- PASS: TestHandlerRcpttoIsBlacklistedEmail (0.00s)
    --- PASS: TestHandlerRcpttoIsBlacklistedEmail/when_request_includes_blacklisted_domain_name (0.00s)
    --- PASS: TestHandlerRcpttoIsBlacklistedEmail/when_request_not_includes_blacklisted_domain_name (0.00s)
=== RUN   TestHandlerRcpttoIsNotRegisteredEmail
=== RUN   TestHandlerRcpttoIsNotRegisteredEmail/when_request_includes_blacklisted_domain_name
=== RUN   TestHandlerRcpttoIsNotRegisteredEmail/when_request_not_includes_blacklisted_domain_name
--- PASS: TestHandlerRcpttoIsNotRegisteredEmail (0.01s)
    --- PASS: TestHandlerRcpttoIsNotRegisteredEmail/when_request_includes_blacklisted_domain_name (0.00s)
    --- PASS: TestHandlerRcpttoIsNotRegisteredEmail/when_request_not_includes_blacklisted_domain_name (0.00s)
=== RUN   TestHandlerRcpttoIsInvalidRequest
=== RUN   TestHandlerRcpttoIsInvalidRequest/when_request_includes_invalid_RCPTTO_command_sequence
=== RUN   TestHandlerRcpttoIsInvalidRequest/when_request_includes_invalid_RCPTTO_command_argument
=== RUN   TestHandlerRcpttoIsInvalidRequest/when_request_includes_blacklisted_RCPTTO_email
=== RUN   TestHandlerRcpttoIsInvalidRequest/when_request_includes_not_registered_RCPTTO_email
=== RUN   TestHandlerRcpttoIsInvalidRequest/when_valid_RCPTTO_request
--- PASS: TestHandlerRcpttoIsInvalidRequest (0.02s)
    --- PASS: TestHandlerRcpttoIsInvalidRequest/when_request_includes_invalid_RCPTTO_command_sequence (0.00s)
    --- PASS: TestHandlerRcpttoIsInvalidRequest/when_request_includes_invalid_RCPTTO_command_argument (0.00s)
    --- PASS: TestHandlerRcpttoIsInvalidRequest/when_request_includes_blacklisted_RCPTTO_email (0.01s)
    --- PASS: TestHandlerRcpttoIsInvalidRequest/when_request_includes_not_registered_RCPTTO_email (0.01s)
    --- PASS: TestHandlerRcpttoIsInvalidRequest/when_valid_RCPTTO_request (0.01s)
=== RUN   TestNewHandlerRset
=== RUN   TestNewHandlerRset/returns_new_handlerRset
--- PASS: TestNewHandlerRset (0.00s)
    --- PASS: TestNewHandlerRset/returns_new_handlerRset (0.00s)
=== RUN   TestHandlerRsetRun
=== RUN   TestHandlerRsetRun/when_successful_RSET_request
=== RUN   TestHandlerRsetRun/when_failure_RSET_request,_invalid_command_sequence
=== RUN   TestHandlerRsetRun/when_failure_RSET_request,_invalid_command
--- PASS: TestHandlerRsetRun (0.00s)
    --- PASS: TestHandlerRsetRun/when_successful_RSET_request (0.00s)
    --- PASS: TestHandlerRsetRun/when_failure_RSET_request,_invalid_command_sequence (0.00s)
    --- PASS: TestHandlerRsetRun/when_failure_RSET_request,_invalid_command (0.00s)
=== RUN   TestHandlerRsetClearMessage
=== RUN   TestHandlerRsetClearMessage/when_not_multiple_message_receiving_condition_erases_all_message_data_except_HELO/EHLO_command_context
=== RUN   TestHandlerRsetClearMessage/when_multiple_message_receiving_condition_does_not_updated_message
--- PASS: TestHandlerRsetClearMessage (0.00s)
    --- PASS: TestHandlerRsetClearMessage/when_not_multiple_message_receiving_condition_erases_all_message_data_except_HELO/EHLO_command_context (0.00s)
    --- PASS: TestHandlerRsetClearMessage/when_multiple_message_receiving_condition_does_not_updated_message (0.00s)
=== RUN   TestHandlerRsetWriteResult
=== RUN   TestHandlerRsetWriteResult/when_successful_request_received
=== RUN   TestHandlerRsetWriteResult/when_failed_request_received
--- PASS: TestHandlerRsetWriteResult (0.00s)
    --- PASS: TestHandlerRsetWriteResult/when_successful_request_received (0.00s)
    --- PASS: TestHandlerRsetWriteResult/when_failed_request_received (0.00s)
=== RUN   TestHandlerRsetIsInvalidCmdSequence
=== RUN   TestHandlerRsetIsInvalidCmdSequence/when_helo_previous_command_was_failure_
=== RUN   TestHandlerRsetIsInvalidCmdSequence/when_helo_previous_command_was_successful_
--- PASS: TestHandlerRsetIsInvalidCmdSequence (0.00s)
    --- PASS: TestHandlerRsetIsInvalidCmdSequence/when_helo_previous_command_was_failure_ (0.00s)
    --- PASS: TestHandlerRsetIsInvalidCmdSequence/when_helo_previous_command_was_successful_ (0.00s)
=== RUN   TestHandlerRsetIsInvalidCmdArg
=== RUN   TestHandlerRsetIsInvalidCmdArg/when_request_includes_invalid_RSET_command
=== RUN   TestHandlerRsetIsInvalidCmdArg/when_request_includes_valid_RSET_command
--- PASS: TestHandlerRsetIsInvalidCmdArg (0.00s)
    --- PASS: TestHandlerRsetIsInvalidCmdArg/when_request_includes_invalid_RSET_command (0.00s)
    --- PASS: TestHandlerRsetIsInvalidCmdArg/when_request_includes_valid_RSET_command (0.00s)
=== RUN   TestHandlerRsetIsInvalidRequest
=== RUN   TestHandlerRsetIsInvalidRequest/when_request_includes_invalid_RSET_command_sequence,_the_previous_command_is_not_successful
=== RUN   TestHandlerRsetIsInvalidRequest/when_request_includes_invalid_RSET_command
=== RUN   TestHandlerRsetIsInvalidRequest/when_valid_RSET_request
--- PASS: TestHandlerRsetIsInvalidRequest (0.00s)
    --- PASS: TestHandlerRsetIsInvalidRequest/when_request_includes_invalid_RSET_command_sequence,_the_previous_command_is_not_successful (0.00s)
    --- PASS: TestHandlerRsetIsInvalidRequest/when_request_includes_invalid_RSET_command (0.00s)
    --- PASS: TestHandlerRsetIsInvalidRequest/when_valid_RSET_request (0.00s)
=== RUN   TestHandlerClearError
=== RUN   TestHandlerClearError/erases_session_error
--- PASS: TestHandlerClearError (0.00s)
    --- PASS: TestHandlerClearError/erases_session_error (0.00s)
=== RUN   TestNewRegex
=== RUN   TestNewRegex/valid_regex_pattern
=== RUN   TestNewRegex/invalid_regex_pattern
--- PASS: TestNewRegex (0.00s)
    --- PASS: TestNewRegex/valid_regex_pattern (0.00s)
    --- PASS: TestNewRegex/invalid_regex_pattern (0.00s)
=== RUN   TestMatchRegex
=== RUN   TestMatchRegex/valid_regex_pattern,_matched_string
=== RUN   TestMatchRegex/valid_regex_pattern,_not_matched_string
=== RUN   TestMatchRegex/invalid_regex_pattern
--- PASS: TestMatchRegex (0.00s)
    --- PASS: TestMatchRegex/valid_regex_pattern,_matched_string (0.00s)
    --- PASS: TestMatchRegex/valid_regex_pattern,_not_matched_string (0.00s)
    --- PASS: TestMatchRegex/invalid_regex_pattern (0.00s)
=== RUN   TestRegexCaptureGroup
=== RUN   TestRegexCaptureGroup/returns_string_when_regex_capture_group_found
=== RUN   TestRegexCaptureGroup/returns_empty_string_when_regex_not_matched
=== RUN   TestRegexCaptureGroup/returns_empty_string_when_regex_capture_group_not_found
--- PASS: TestRegexCaptureGroup (0.00s)
    --- PASS: TestRegexCaptureGroup/returns_string_when_regex_capture_group_found (0.00s)
    --- PASS: TestRegexCaptureGroup/returns_empty_string_when_regex_not_matched (0.00s)
    --- PASS: TestRegexCaptureGroup/returns_empty_string_when_regex_capture_group_not_found (0.00s)
=== RUN   TestIsIncluded
=== RUN   TestIsIncluded/item_found_in_slice
=== RUN   TestIsIncluded/item_not_found_in_slice
--- PASS: TestIsIncluded (0.00s)
    --- PASS: TestIsIncluded/item_found_in_slice (0.00s)
    --- PASS: TestIsIncluded/item_not_found_in_slice (0.00s)
=== RUN   TestServerWithPortNumber
=== RUN   TestServerWithPortNumber/returns_server_with_port_number
--- PASS: TestServerWithPortNumber (0.00s)
    --- PASS: TestServerWithPortNumber/returns_server_with_port_number (0.00s)
=== RUN   TestNewLogger
=== RUN   TestNewLogger/when_log_to_stdout,_server_activity_enabled
=== RUN   TestNewLogger/when_log_to_stdout,_server_activity_disabled
--- PASS: TestNewLogger (0.00s)
    --- PASS: TestNewLogger/when_log_to_stdout,_server_activity_enabled (0.00s)
    --- PASS: TestNewLogger/when_log_to_stdout,_server_activity_disabled (0.00s)
=== RUN   TestEventLoggerInfoActivity
=== RUN   TestEventLoggerInfoActivity/when_log_to_stdout_and_server_activity_enabled
=== RUN   TestEventLoggerInfoActivity/when_log_to_stdout_disabled,_server_activity_enabled
=== RUN   TestEventLoggerInfoActivity/when_log_to_stdout_enabled,_server_activity_disabled
--- PASS: TestEventLoggerInfoActivity (0.00s)
    --- PASS: TestEventLoggerInfoActivity/when_log_to_stdout_and_server_activity_enabled (0.00s)
    --- PASS: TestEventLoggerInfoActivity/when_log_to_stdout_disabled,_server_activity_enabled (0.00s)
    --- PASS: TestEventLoggerInfoActivity/when_log_to_stdout_enabled,_server_activity_disabled (0.00s)
=== RUN   TestEventLoggerInfo
=== RUN   TestEventLoggerInfo/when_log_to_stdout_enabled
=== RUN   TestEventLoggerInfo/when_log_to_stdout_disabled
--- PASS: TestEventLoggerInfo (0.00s)
    --- PASS: TestEventLoggerInfo/when_log_to_stdout_enabled (0.00s)
    --- PASS: TestEventLoggerInfo/when_log_to_stdout_disabled (0.00s)
=== RUN   TestEventLoggerWarning
=== RUN   TestEventLoggerWarning/when_log_to_stdout_enabled
=== RUN   TestEventLoggerWarning/when_log_to_stdout_disabled
--- PASS: TestEventLoggerWarning (0.00s)
    --- PASS: TestEventLoggerWarning/when_log_to_stdout_enabled (0.00s)
    --- PASS: TestEventLoggerWarning/when_log_to_stdout_disabled (0.00s)
=== RUN   TestEventLoggerError
=== RUN   TestEventLoggerError/when_log_to_stdout_enabled
=== RUN   TestEventLoggerError/when_log_to_stdout_disabled
--- PASS: TestEventLoggerError (0.00s)
    --- PASS: TestEventLoggerError/when_log_to_stdout_enabled (0.00s)
    --- PASS: TestEventLoggerError/when_log_to_stdout_disabled (0.00s)
=== RUN   TestMessageHeloRequest
=== RUN   TestMessageHeloRequest/getter_for_heloRequest_field
--- PASS: TestMessageHeloRequest (0.00s)
    --- PASS: TestMessageHeloRequest/getter_for_heloRequest_field (0.00s)
=== RUN   TestMessageHeloResponse
=== RUN   TestMessageHeloResponse/getter_for_heloRequest_field
--- PASS: TestMessageHeloResponse (0.00s)
    --- PASS: TestMessageHeloResponse/getter_for_heloRequest_field (0.00s)
=== RUN   TestMessageHelo
=== RUN   TestMessageHelo/getter_for_helo_field
--- PASS: TestMessageHelo (0.00s)
    --- PASS: TestMessageHelo/getter_for_helo_field (0.00s)
=== RUN   TestMessageMailfromRequest
=== RUN   TestMessageMailfromRequest/getter_for_mailfromRequest_field
--- PASS: TestMessageMailfromRequest (0.00s)
    --- PASS: TestMessageMailfromRequest/getter_for_mailfromRequest_field (0.00s)
=== RUN   TestMessageMailfromResponse
=== RUN   TestMessageMailfromResponse/getter_for_mailfromResponse_field
--- PASS: TestMessageMailfromResponse (0.00s)
    --- PASS: TestMessageMailfromResponse/getter_for_mailfromResponse_field (0.00s)
=== RUN   TestMessageMailfrom
=== RUN   TestMessageMailfrom/getter_for_mailfrom_field
--- PASS: TestMessageMailfrom (0.00s)
    --- PASS: TestMessageMailfrom/getter_for_mailfrom_field (0.00s)
=== RUN   TestMessageRcpttoRequest
=== RUN   TestMessageRcpttoRequest/getter_for_rcpttoRequest_field
--- PASS: TestMessageRcpttoRequest (0.00s)
    --- PASS: TestMessageRcpttoRequest/getter_for_rcpttoRequest_field (0.00s)
=== RUN   TestMessageRcpttoResponse
=== RUN   TestMessageRcpttoResponse/getter_for_rcpttoResponse_field
--- PASS: TestMessageRcpttoResponse (0.00s)
    --- PASS: TestMessageRcpttoResponse/getter_for_rcpttoResponse_field (0.00s)
=== RUN   TestMessageRcptto
=== RUN   TestMessageRcptto/getter_for_rcptto_field
--- PASS: TestMessageRcptto (0.00s)
    --- PASS: TestMessageRcptto/getter_for_rcptto_field (0.00s)
=== RUN   TestMessageDataRequest
=== RUN   TestMessageDataRequest/getter_for_dataRequest_field
--- PASS: TestMessageDataRequest (0.00s)
    --- PASS: TestMessageDataRequest/getter_for_dataRequest_field (0.00s)
=== RUN   TestMessageDataResponse
=== RUN   TestMessageDataResponse/getter_for_dataResponse_field
--- PASS: TestMessageDataResponse (0.00s)
    --- PASS: TestMessageDataResponse/getter_for_dataResponse_field (0.00s)
=== RUN   TestMessageData
=== RUN   TestMessageData/getter_for_data_field
--- PASS: TestMessageData (0.00s)
    --- PASS: TestMessageData/getter_for_data_field (0.00s)
=== RUN   TestMessageMsgRequest
=== RUN   TestMessageMsgRequest/getter_for_msgRequest_field
--- PASS: TestMessageMsgRequest (0.00s)
    --- PASS: TestMessageMsgRequest/getter_for_msgRequest_field (0.00s)
=== RUN   TestMessageMsgResponse
=== RUN   TestMessageMsgResponse/getter_for_msgRequest_field
--- PASS: TestMessageMsgResponse (0.00s)
    --- PASS: TestMessageMsgResponse/getter_for_msgRequest_field (0.00s)
=== RUN   TestMessageMsg
=== RUN   TestMessageMsg/getter_for_msg_field
--- PASS: TestMessageMsg (0.00s)
    --- PASS: TestMessageMsg/getter_for_msg_field (0.00s)
=== RUN   TestMessageRsetRequest
=== RUN   TestMessageRsetRequest/getter_for_rsetRequest_field
--- PASS: TestMessageRsetRequest (0.00s)
    --- PASS: TestMessageRsetRequest/getter_for_rsetRequest_field (0.00s)
=== RUN   TestMessageRsetResponse
=== RUN   TestMessageRsetResponse/getter_for_rsetRequest_field
--- PASS: TestMessageRsetResponse (0.00s)
    --- PASS: TestMessageRsetResponse/getter_for_rsetRequest_field (0.00s)
=== RUN   TestMessageRset
=== RUN   TestMessageRset/getter_for_rset_field
--- PASS: TestMessageRset (0.00s)
    --- PASS: TestMessageRset/getter_for_rset_field (0.00s)
=== RUN   TestMessageQuitSent
=== RUN   TestMessageQuitSent/getter_for_quitSent_field
--- PASS: TestMessageQuitSent (0.00s)
    --- PASS: TestMessageQuitSent/getter_for_quitSent_field (0.00s)
=== RUN   TestMessageIsConsistent
=== RUN   TestMessageIsConsistent/when_consistent
=== RUN   TestMessageIsConsistent/when_not_consistent_MAILFROM
=== RUN   TestMessageIsConsistent/when_not_consistent_RCPTTO
=== RUN   TestMessageIsConsistent/when_not_consistent_DATA
=== RUN   TestMessageIsConsistent/when_not_consistent_MSG
--- PASS: TestMessageIsConsistent (0.00s)
    --- PASS: TestMessageIsConsistent/when_consistent (0.00s)
    --- PASS: TestMessageIsConsistent/when_not_consistent_MAILFROM (0.00s)
    --- PASS: TestMessageIsConsistent/when_not_consistent_RCPTTO (0.00s)
    --- PASS: TestMessageIsConsistent/when_not_consistent_DATA (0.00s)
    --- PASS: TestMessageIsConsistent/when_not_consistent_MSG (0.00s)
=== RUN   TestMessagesAppend
=== RUN   TestMessagesAppend/addes_message_pointer_into_items_slice
--- PASS: TestMessagesAppend (0.00s)
    --- PASS: TestMessagesAppend/addes_message_pointer_into_items_slice (0.00s)
=== RUN   TestNewServer
=== RUN   TestNewServer/creates_new_server
--- PASS: TestNewServer (0.00s)
    --- PASS: TestNewServer/creates_new_server (0.00s)
=== RUN   TestServerNewMessage
=== RUN   TestServerNewMessage/pushes_new_message_into_server.messages,_returns_this_message
--- PASS: TestServerNewMessage (0.00s)
    --- PASS: TestServerNewMessage/pushes_new_message_into_server.messages,_returns_this_message (0.00s)
=== RUN   TestServerNewMessageWithHeloContext
=== RUN   TestServerNewMessageWithHeloContext/pushes_new_message_into_server.messages_with_helo_context_from_other_message,_returns_this_message
--- PASS: TestServerNewMessageWithHeloContext (0.00s)
    --- PASS: TestServerNewMessageWithHeloContext/pushes_new_message_into_server.messages_with_helo_context_from_other_message,_returns_this_message (0.00s)
=== RUN   TestServerIsInvalidCmd
=== RUN   TestServerIsInvalidCmd/when_valid_command
=== RUN   TestServerIsInvalidCmd/when_valid_command#01
=== RUN   TestServerIsInvalidCmd/when_valid_command#02
=== RUN   TestServerIsInvalidCmd/when_valid_command#03
=== RUN   TestServerIsInvalidCmd/when_valid_command#04
=== RUN   TestServerIsInvalidCmd/when_valid_command#05
=== RUN   TestServerIsInvalidCmd/when_invalid_command
--- PASS: TestServerIsInvalidCmd (0.00s)
    --- PASS: TestServerIsInvalidCmd/when_valid_command (0.00s)
    --- PASS: TestServerIsInvalidCmd/when_valid_command#01 (0.00s)
    --- PASS: TestServerIsInvalidCmd/when_valid_command#02 (0.00s)
    --- PASS: TestServerIsInvalidCmd/when_valid_command#03 (0.00s)
    --- PASS: TestServerIsInvalidCmd/when_valid_command#04 (0.00s)
    --- PASS: TestServerIsInvalidCmd/when_valid_command#05 (0.00s)
    --- PASS: TestServerIsInvalidCmd/when_invalid_command (0.00s)
=== RUN   TestServerRecognizeCommand
=== RUN   TestServerRecognizeCommand/captures_the_first_word_divided_by_spaces,_converts_it_to_upper_case
--- PASS: TestServerRecognizeCommand (0.00s)
    --- PASS: TestServerRecognizeCommand/captures_the_first_word_divided_by_spaces,_converts_it_to_upper_case (0.00s)
=== RUN   TestServerAddToWaitGroup
=== RUN   TestServerAddToWaitGroup/increases_count_of_goroutines_by_one
--- PASS: TestServerAddToWaitGroup (0.00s)
    --- PASS: TestServerAddToWaitGroup/increases_count_of_goroutines_by_one (0.00s)
=== RUN   TestServerRemoveFromWaitGroup
=== RUN   TestServerRemoveFromWaitGroup/decreases_count_of_goroutines_by_one
--- PASS: TestServerRemoveFromWaitGroup (0.00s)
    --- PASS: TestServerRemoveFromWaitGroup/decreases_count_of_goroutines_by_one (0.00s)
=== RUN   TestServerIsAbleToEndSession
=== RUN   TestServerIsAbleToEndSession/when_quit_command_has_been_sent
=== RUN   TestServerIsAbleToEndSession/when_quit_command_has_not_been_sent,_error_has_been_found,_fail_fast_scenario_has_been_enabled
=== RUN   TestServerIsAbleToEndSession/when_quit_command_has_not_been_sent,_no_errors
=== RUN   TestServerIsAbleToEndSession/when_quit_command_has_not_been_sent,_error_has_been_found,_fail_fast_scenario_has_not_been_enabled
--- PASS: TestServerIsAbleToEndSession (0.00s)
    --- PASS: TestServerIsAbleToEndSession/when_quit_command_has_been_sent (0.00s)
    --- PASS: TestServerIsAbleToEndSession/when_quit_command_has_not_been_sent,_error_has_been_found,_fail_fast_scenario_has_been_enabled (0.00s)
    --- PASS: TestServerIsAbleToEndSession/when_quit_command_has_not_been_sent,_no_errors (0.00s)
    --- PASS: TestServerIsAbleToEndSession/when_quit_command_has_not_been_sent,_error_has_been_found,_fail_fast_scenario_has_not_been_enabled (0.00s)
=== RUN   TestServerHandleSession
=== RUN   TestServerHandleSession/when_complex_successful_session,_multiple_message_receiving_scenario_disabled
=== RUN   TestServerHandleSession/when_complex_successful_session,_multiple_message_receiving_scenario_enabled
=== RUN   TestServerHandleSession/when_invalid_command,_fail_fast_scenario_disabled
=== RUN   TestServerHandleSession/when_invalid_command,_session_error,_fail_fast_scenario_enabled
=== RUN   TestServerHandleSession/when_server_quit_channel_was_closed
=== RUN   TestServerHandleSession/when_read_request_session_error
--- PASS: TestServerHandleSession (0.10s)
    --- PASS: TestServerHandleSession/when_complex_successful_session,_multiple_message_receiving_scenario_disabled (0.04s)
    --- PASS: TestServerHandleSession/when_complex_successful_session,_multiple_message_receiving_scenario_enabled (0.05s)
    --- PASS: TestServerHandleSession/when_invalid_command,_fail_fast_scenario_disabled (0.00s)
    --- PASS: TestServerHandleSession/when_invalid_command,_session_error,_fail_fast_scenario_enabled (0.01s)
    --- PASS: TestServerHandleSession/when_server_quit_channel_was_closed (0.00s)
    --- PASS: TestServerHandleSession/when_read_request_session_error (0.00s)
=== RUN   TestServerStart
=== RUN   TestServerStart/when_no_errors_happens_during_starting_and_running_the_server_with_default_port
=== RUN   TestServerStart/when_no_errors_happens_during_starting_and_running_the_server_with_custom_port
=== RUN   TestServerStart/when_active_server_doesn't_start_current_server
=== RUN   TestServerStart/when_listener_error_happens_during_starting_the_server_doesn't_start_current_server
--- PASS: TestServerStart (0.01s)
    --- PASS: TestServerStart/when_no_errors_happens_during_starting_and_running_the_server_with_default_port (0.01s)
    --- PASS: TestServerStart/when_no_errors_happens_during_starting_and_running_the_server_with_custom_port (0.00s)
    --- PASS: TestServerStart/when_active_server_doesn't_start_current_server (0.00s)
    --- PASS: TestServerStart/when_listener_error_happens_during_starting_the_server_doesn't_start_current_server (0.00s)
=== RUN   TestServerStop
=== RUN   TestServerStop/when_server_active_stops_current_server,_graceful_shutdown_case
==================
WARNING: DATA RACE
Read at 0x00c0004a44c8 by goroutine 49:
  github.com/mocktools/go-smtp-mock.TestServerStop.func1()
      /wrk/github.com/mocktools/go-smtp-mock/server_test.go:407 +0x553
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:1439 +0x213
  testing.(*T).Run.func1()
      /usr/local/go/src/testing/testing.go:1486 +0x47

Previous write at 0x00c0004a44c8 by goroutine 45:
  github.com/mocktools/go-smtp-mock.(*Server).Stop.func1()
      /wrk/github.com/mocktools/go-smtp-mock/server.go:101 +0x94

Goroutine 49 (running) created at:
  testing.(*T).Run()
      /usr/local/go/src/testing/testing.go:1486 +0x724
  github.com/mocktools/go-smtp-mock.TestServerStop()
      /wrk/github.com/mocktools/go-smtp-mock/server_test.go:391 +0x44
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:1439 +0x213
  testing.(*T).Run.func1()
      /usr/local/go/src/testing/testing.go:1486 +0x47

Goroutine 45 (running) created at:
  github.com/mocktools/go-smtp-mock.(*Server).Stop()
      /wrk/github.com/mocktools/go-smtp-mock/server.go:98 +0x11d
  github.com/mocktools/go-smtp-mock.TestServerStop.func1()
      /wrk/github.com/mocktools/go-smtp-mock/server_test.go:406 +0x524
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:1439 +0x213
  testing.(*T).Run.func1()
      /usr/local/go/src/testing/testing.go:1486 +0x47
==================
    testing.go:1312: race detected during execution of test
=== RUN   TestServerStop/when_server_active_stops_current_server,_force_shutdown_case
=== RUN   TestServerStop/when_server_is_inactive_doesn't_stop_current_server
=== CONT  TestServerStop
    testing.go:1312: race detected during execution of test
--- FAIL: TestServerStop (1.00s)
    --- FAIL: TestServerStop/when_server_active_stops_current_server,_graceful_shutdown_case (0.00s)
    --- PASS: TestServerStop/when_server_active_stops_current_server,_force_shutdown_case (1.00s)
    --- PASS: TestServerStop/when_server_is_inactive_doesn't_stop_current_server (0.00s)
=== RUN   TestServerMessages
=== RUN   TestServerMessages/when_there_are_no_messages_on_the_server
=== RUN   TestServerMessages/when_there_are_messages_on_the_server
--- PASS: TestServerMessages (0.00s)
    --- PASS: TestServerMessages/when_there_are_no_messages_on_the_server (0.00s)
    --- PASS: TestServerMessages/when_there_are_messages_on_the_server (0.00s)
=== RUN   TestTimeNow
=== RUN   TestTimeNow/wrappes_time.Now()_in_function
--- PASS: TestTimeNow (0.00s)
    --- PASS: TestTimeNow/wrappes_time.Now()_in_function (0.00s)
=== RUN   TestTimeSleep
=== RUN   TestTimeSleep/wrappes_time.Sleep()_in_function,_returns_delay
--- PASS: TestTimeSleep (0.00s)
    --- PASS: TestTimeSleep/wrappes_time.Sleep()_in_function,_returns_delay (0.00s)
=== RUN   TestSessionIsErrorFound
=== RUN   TestSessionIsErrorFound/when_error_exists
=== RUN   TestSessionIsErrorFound/when_error_not_exists
--- PASS: TestSessionIsErrorFound (0.00s)
    --- PASS: TestSessionIsErrorFound/when_error_exists (0.00s)
    --- PASS: TestSessionIsErrorFound/when_error_not_exists (0.00s)
=== RUN   TestSessionAddError
=== RUN   TestSessionAddError/assigns_error_to_session.err
--- PASS: TestSessionAddError (0.00s)
    --- PASS: TestSessionAddError/assigns_error_to_session.err (0.00s)
=== RUN   TestSessionClearError
=== RUN   TestSessionClearError/clears_session.err
--- PASS: TestSessionClearError (0.00s)
    --- PASS: TestSessionClearError/clears_session.err (0.00s)
=== RUN   TestSessionSetTimeout
=== RUN   TestSessionSetTimeout/sets_connection_deadline_for_session
=== RUN   TestSessionSetTimeout/when_connection_error
--- PASS: TestSessionSetTimeout (0.00s)
    --- PASS: TestSessionSetTimeout/sets_connection_deadline_for_session (0.00s)
    --- PASS: TestSessionSetTimeout/when_connection_error (0.00s)
=== RUN   TestSessionDiscardBufin
=== RUN   TestSessionDiscardBufin/discardes_the_bufin_remnants
=== RUN   TestSessionDiscardBufin/discardes_the_bufin_remnants_with_error
--- PASS: TestSessionDiscardBufin (0.00s)
    --- PASS: TestSessionDiscardBufin/discardes_the_bufin_remnants (0.00s)
    --- PASS: TestSessionDiscardBufin/discardes_the_bufin_remnants_with_error (0.00s)
=== RUN   TestNewSession
=== RUN   TestNewSession/creates_new_SMTP_session
--- PASS: TestNewSession (0.00s)
    --- PASS: TestNewSession/creates_new_SMTP_session (0.00s)
=== RUN   TestSessionReadRequest
=== RUN   TestSessionReadRequest/extracts_trimmed_string_from_bufin_without_error
=== RUN   TestSessionReadRequest/extracts_string_from_bufin_with_error
--- PASS: TestSessionReadRequest (0.00s)
    --- PASS: TestSessionReadRequest/extracts_trimmed_string_from_bufin_without_error (0.00s)
    --- PASS: TestSessionReadRequest/extracts_string_from_bufin_with_error (0.00s)
=== RUN   TestSessionReadBytes
=== RUN   TestSessionReadBytes/extracts_line_in_bytes_from_bufin_without_error
=== RUN   TestSessionReadBytes/extracts_line_in_bytes_from_bufin_with_error
--- PASS: TestSessionReadBytes (0.00s)
    --- PASS: TestSessionReadBytes/extracts_line_in_bytes_from_bufin_without_error (0.00s)
    --- PASS: TestSessionReadBytes/extracts_line_in_bytes_from_bufin_with_error (0.00s)
=== RUN   TestSessionResponseDelay
=== RUN   TestSessionResponseDelay/when_default_session_response_delay
=== RUN   TestSessionResponseDelay/when_custom_session_response_delay
--- PASS: TestSessionResponseDelay (0.00s)
    --- PASS: TestSessionResponseDelay/when_default_session_response_delay (0.00s)
    --- PASS: TestSessionResponseDelay/when_custom_session_response_delay (0.00s)
=== RUN   TestSessionWriteResponse
=== RUN   TestSessionWriteResponse/writes_server_response_to_bufout_without_response_delay_and_error
=== RUN   TestSessionWriteResponse/writes_server_response_to_bufout_with_response_delay_and_without_error
=== RUN   TestSessionWriteResponse/writes_server_response_to_bufout_with_error
--- PASS: TestSessionWriteResponse (0.00s)
    --- PASS: TestSessionWriteResponse/writes_server_response_to_bufout_without_response_delay_and_error (0.00s)
    --- PASS: TestSessionWriteResponse/writes_server_response_to_bufout_with_response_delay_and_without_error (0.00s)
    --- PASS: TestSessionWriteResponse/writes_server_response_to_bufout_with_error (0.00s)
=== RUN   TestSessionFinish
=== RUN   TestSessionFinish/closes_session_connection_without_error
=== RUN   TestSessionFinish/closes_session_connection_with_error
--- PASS: TestSessionFinish (0.00s)
    --- PASS: TestSessionFinish/closes_session_connection_without_error (0.00s)
    --- PASS: TestSessionFinish/closes_session_connection_with_error (0.00s)
=== RUN   TestNew
=== RUN   TestNew/creates_new_server_with_default_configuration_settings
=== RUN   TestNew/creates_new_server_with_custom_configuration_settings
=== RUN   TestNew/successful_iteration_with_new_server
==================
WARNING: DATA RACE
Read at 0x00c0001a7c68 by goroutine 31:
  github.com/mocktools/go-smtp-mock.TestNew.func3()
      /wrk/github.com/mocktools/go-smtp-mock/smtpmock_test.go:158 +0x3f7
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:1439 +0x213
  testing.(*T).Run.func1()
      /usr/local/go/src/testing/testing.go:1486 +0x47

Previous write at 0x00c0001a7c68 by goroutine 27:
  github.com/mocktools/go-smtp-mock.(*Server).Stop.func1()
      /wrk/github.com/mocktools/go-smtp-mock/server.go:101 +0x94

Goroutine 31 (running) created at:
  testing.(*T).Run()
      /usr/local/go/src/testing/testing.go:1486 +0x724
  github.com/mocktools/go-smtp-mock.TestNew()
      /wrk/github.com/mocktools/go-smtp-mock/smtpmock_test.go:141 +0x84
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:1439 +0x213
  testing.(*T).Run.func1()
      /usr/local/go/src/testing/testing.go:1486 +0x47

Goroutine 27 (finished) created at:
  github.com/mocktools/go-smtp-mock.(*Server).Stop()
      /wrk/github.com/mocktools/go-smtp-mock/server.go:98 +0x11d
  github.com/mocktools/go-smtp-mock.TestNew.func3()
      /wrk/github.com/mocktools/go-smtp-mock/smtpmock_test.go:154 +0x351
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:1439 +0x213
  testing.(*T).Run.func1()
      /usr/local/go/src/testing/testing.go:1486 +0x47
==================
    testing.go:1312: race detected during execution of test
=== CONT  TestNew
    testing.go:1312: race detected during execution of test
--- FAIL: TestNew (0.03s)
    --- PASS: TestNew/creates_new_server_with_default_configuration_settings (0.00s)
    --- PASS: TestNew/creates_new_server_with_custom_configuration_settings (0.00s)
    --- FAIL: TestNew/successful_iteration_with_new_server (0.03s)
=== CONT  
    testing.go:1312: race detected during execution of test
FAIL
FAIL	github.com/mocktools/go-smtp-mock	1.399s
=== RUN   TestMain
=== RUN   TestMain/when_error_not_happened
=== RUN   TestMain/when_error_happened
--- PASS: TestMain (0.00s)
    --- PASS: TestMain/when_error_not_happened (0.00s)
    --- PASS: TestMain/when_error_happened (0.00s)
=== RUN   TestRun
=== RUN   TestRun/when_command_line_argument_error
invalid value "a" for flag -port: parse error
Usage of some-path-to-the-program:
  -blacklistedHeloDomains string
    	Blacklisted HELO domains, separated by commas
  -blacklistedMailfromEmails string
    	Blacklisted MAIL FROM emails, separated by commas
  -blacklistedRcpttoEmails string
    	Blacklisted RCPT TO emails, separated by commas
  -failFast
    	Enables fail fast scenario. Disabled by default
  -host string
    	Host address where smtpmock will run. It's equal to 127.0.0.1 by default
  -log
    	Enables log server activity. Disabled by default
  -msgDataReceived string
    	Custom DATA received message
  -msgGreeting string
    	Custom server greeting message
  -msgHeloBlacklistedDomain string
    	Custom HELO blacklisted domain message
  -msgHeloReceived string
    	Custom HELO received message
  -msgInvalidCmd string
    	Custom invalid command message
  -msgInvalidCmdDataSequence string
    	Custom invalid command DATA sequence message
  -msgInvalidCmdHeloArg string
    	Custom invalid command HELO argument message
  -msgInvalidCmdHeloSequence string
    	Custom invalid command HELO sequence message
  -msgInvalidCmdMailfromArg string
    	Custom invalid command MAIL FROM argument message
  -msgInvalidCmdMailfromSequence string
    	Custom invalid command MAIL FROM sequence message
  -msgInvalidCmdRcpttoArg string
    	Custom invalid command RCPT TO argument message
  -msgInvalidCmdRcpttoSequence string
    	Custom invalid command RCPT TO sequence message
  -msgInvalidCmdRsetArg string
    	Custom invalid command RSET message
  -msgInvalidCmdRsetSequence string
    	Custom invalid command RSET sequence message
  -msgMailfromBlacklistedEmail string
    	Custom MAIL FROM blacklisted email message
  -msgMailfromReceived string
    	Custom MAIL FROM received message
  -msgMsgReceived string
    	Custom received message body message
  -msgMsgSizeIsTooBig string
    	Custom size is too big message
  -msgQuitCmd string
    	Custom quit command message
  -msgRcpttoBlacklistedEmail string
    	Custom RCPT TO blacklisted email message
  -msgRcpttoNotRegisteredEmail string
    	Custom RCPT TO not registered email message
  -msgRcpttoReceived string
    	Custom RCPT TO received message
  -msgRsetReceived string
    	Custom RSET received message
  -msgSizeLimit int
    	Message body size limit in bytes. It's equal to 10485760 bytes
  -multipleMessageReceiving
    	Enables multiple message receiving scenario. Disabled by default
  -notRegisteredEmails string
    	Not registered (non-existent) RCPT TO emails, separated by commas
  -port int
    	Server port number. If not specified it will be assigned dynamically
  -responseDelayData int
    	DATA response delay in seconds. It runs immediately (equals to 0 seconds) by default
  -responseDelayHelo int
    	HELO response delay in seconds. It runs immediately (equals to 0 seconds) by default
  -responseDelayMailfrom int
    	MAIL FROM response delay in seconds. It runs immediately (equals to 0 seconds) by default
  -responseDelayMessage int
    	Message response delay in seconds. It runs immediately (equals to 0 seconds) by default
  -responseDelayQuit int
    	QUIT response delay in seconds. It runs immediately (equals to 0 seconds) by default
  -responseDelayRcptto int
    	RCPT TO response delay in seconds. It runs immediately (equals to 0 seconds) by default
  -responseDelayRset int
    	RSET response delay in seconds. It runs immediately (equals to 0 seconds) by default
  -sessionTimeout int
    	Session timeout in seconds. It's equal to 30 seconds by default
  -shutdownTimeout int
    	Graceful shutdown timeout in seconds. It's equal to 1 second by default
  -v	Prints current smtpmock version
=== RUN   TestRun/when_server_starting_error
=== RUN   TestRun/when_server_was_started_successfully,_interrupt_signal_(exit_2)_received
=== RUN   TestRun/when_server_was_started_successfully,_quit_signal_(exit_3)_received
=== RUN   TestRun/when_server_was_started_successfully,_terminated_signal_(exit_15)_received
=== RUN   TestRun/when_version_flag_passed
smtpmock: unknown-version
commit: unknown-commit
built at: unknown-buildtime
--- PASS: TestRun (0.00s)
    --- PASS: TestRun/when_command_line_argument_error (0.00s)
    --- PASS: TestRun/when_server_starting_error (0.00s)
    --- PASS: TestRun/when_server_was_started_successfully,_interrupt_signal_(exit_2)_received (0.00s)
    --- PASS: TestRun/when_server_was_started_successfully,_quit_signal_(exit_3)_received (0.00s)
    --- PASS: TestRun/when_server_was_started_successfully,_terminated_signal_(exit_15)_received (0.00s)
    --- PASS: TestRun/when_version_flag_passed (0.00s)
=== RUN   TestToSlice
=== RUN   TestToSlice/converts_string_separated_by_commas_to_slice_of_strings
--- PASS: TestToSlice (0.00s)
    --- PASS: TestToSlice/converts_string_separated_by_commas_to_slice_of_strings (0.00s)
=== RUN   TestPrintVersionData
=== RUN   TestPrintVersionData/#00
--- PASS: TestPrintVersionData (0.00s)
    --- PASS: TestPrintVersionData/#00 (0.00s)
=== RUN   TestAttrFromCommandLine
=== RUN   TestAttrFromCommandLine/when_known_flags_found_creates_pointer_to_ConfigurationAttr_based_on_passed_command_line_arguments
=== RUN   TestAttrFromCommandLine/when_unknown_flags_found_sends_exit_signal
flag provided but not defined: -notKnownFlag
Usage of some-path-to-the-program:
  -blacklistedHeloDomains string
    	Blacklisted HELO domains, separated by commas
  -blacklistedMailfromEmails string
    	Blacklisted MAIL FROM emails, separated by commas
  -blacklistedRcpttoEmails string
    	Blacklisted RCPT TO emails, separated by commas
  -failFast
    	Enables fail fast scenario. Disabled by default
  -host string
    	Host address where smtpmock will run. It's equal to 127.0.0.1 by default
  -log
    	Enables log server activity. Disabled by default
  -msgDataReceived string
    	Custom DATA received message
  -msgGreeting string
    	Custom server greeting message
  -msgHeloBlacklistedDomain string
    	Custom HELO blacklisted domain message
  -msgHeloReceived string
    	Custom HELO received message
  -msgInvalidCmd string
    	Custom invalid command message
  -msgInvalidCmdDataSequence string
    	Custom invalid command DATA sequence message
  -msgInvalidCmdHeloArg string
    	Custom invalid command HELO argument message
  -msgInvalidCmdHeloSequence string
    	Custom invalid command HELO sequence message
  -msgInvalidCmdMailfromArg string
    	Custom invalid command MAIL FROM argument message
  -msgInvalidCmdMailfromSequence string
    	Custom invalid command MAIL FROM sequence message
  -msgInvalidCmdRcpttoArg string
    	Custom invalid command RCPT TO argument message
  -msgInvalidCmdRcpttoSequence string
    	Custom invalid command RCPT TO sequence message
  -msgInvalidCmdRsetArg string
    	Custom invalid command RSET message
  -msgInvalidCmdRsetSequence string
    	Custom invalid command RSET sequence message
  -msgMailfromBlacklistedEmail string
    	Custom MAIL FROM blacklisted email message
  -msgMailfromReceived string
    	Custom MAIL FROM received message
  -msgMsgReceived string
    	Custom received message body message
  -msgMsgSizeIsTooBig string
    	Custom size is too big message
  -msgQuitCmd string
    	Custom quit command message
  -msgRcpttoBlacklistedEmail string
    	Custom RCPT TO blacklisted email message
  -msgRcpttoNotRegisteredEmail string
    	Custom RCPT TO not registered email message
  -msgRcpttoReceived string
    	Custom RCPT TO received message
  -msgRsetReceived string
    	Custom RSET received message
  -msgSizeLimit int
    	Message body size limit in bytes. It's equal to 10485760 bytes
  -multipleMessageReceiving
    	Enables multiple message receiving scenario. Disabled by default
  -notRegisteredEmails string
    	Not registered (non-existent) RCPT TO emails, separated by commas
  -port int
    	Server port number. If not specified it will be assigned dynamically
  -responseDelayData int
    	DATA response delay in seconds. It runs immediately (equals to 0 seconds) by default
  -responseDelayHelo int
    	HELO response delay in seconds. It runs immediately (equals to 0 seconds) by default
  -responseDelayMailfrom int
    	MAIL FROM response delay in seconds. It runs immediately (equals to 0 seconds) by default
  -responseDelayMessage int
    	Message response delay in seconds. It runs immediately (equals to 0 seconds) by default
  -responseDelayQuit int
    	QUIT response delay in seconds. It runs immediately (equals to 0 seconds) by default
  -responseDelayRcptto int
    	RCPT TO response delay in seconds. It runs immediately (equals to 0 seconds) by default
  -responseDelayRset int
    	RSET response delay in seconds. It runs immediately (equals to 0 seconds) by default
  -sessionTimeout int
    	Session timeout in seconds. It's equal to 30 seconds by default
  -shutdownTimeout int
    	Graceful shutdown timeout in seconds. It's equal to 1 second by default
  -v	Prints current smtpmock version
--- PASS: TestAttrFromCommandLine (0.00s)
    --- PASS: TestAttrFromCommandLine/when_known_flags_found_creates_pointer_to_ConfigurationAttr_based_on_passed_command_line_arguments (0.00s)
    --- PASS: TestAttrFromCommandLine/when_unknown_flags_found_sends_exit_signal (0.00s)
PASS
ok  	github.com/mocktools/go-smtp-mock/cmd	0.028s
?   	github.com/mocktools/go-smtp-mock/cmd/version	[no test files]
FAIL

@benjamin-rood
Copy link
Collaborator Author

I've played with the code and seemingly fixed the race conditions, at least as they occur in the repo's own tests. Will push it soon as a PR where we can discuss the approach.

@benjamin-rood
Copy link
Collaborator Author

PR: #125

@bestwebua
Copy link
Member

bestwebua commented Nov 11, 2022

@benjamin-rood First of all, thanks for your intention to improve smtpmock. I have spend a lot of time for creating this tool.

To begin with, can you tell me: Am I doing it the correct way, by creating a mock server instance in TestMain?

The main idea of using was start iteration with server instance (with predefined behaviour) during tests and terminate after:

server := smtpmock.New(smtpmock.ConfigurationAttr{})
server.Start()

hostAddress, portNumber := "127.0.0.1", server.PortNumber
connection, _ := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", hostAddress, portNumber), time.Duration(2) * time.Second)

client, _ := smtp.NewClient(connection, hostAddress)
client.Hello("example.com")
client.Quit()
client.Close()

// Each result of SMTP session will be saved as message.
// To get access to server messages use Messages() method
server.Messages()

server.Stop()

Secondly, is this the first time you have encountered any reports of race conditions?

Yeah, your report has been the first. I am ashamed 😟, but I forgot to add the task about passing tests with a race flag to the backlog.

I've played with the code and seemingly fixed the race conditions, at least as they occur in the repo's own tests. Will push it soon as a PR where we can discuss the approach.

Awesome, thanks 👍 I'll review it.

@dandare100
Copy link
Contributor

" I am ashamed 😟" - Never, don't be.
This project is awesome and it will only get better with these proposals

@bestwebua
Copy link
Member

" I am ashamed 😟" - Never, don't be. This project is awesome and it will only get better with these proposals

Thank you, Mark!

@bestwebua bestwebua linked a pull request Nov 16, 2022 that will close this issue
3 tasks
@bestwebua
Copy link
Member

@dandare100, @benjamin-rood Already in latest (2.0.0) release 🚀

@benjamin-rood
Copy link
Collaborator Author

benjamin-rood commented Nov 17, 2022 via email

@bestwebua
Copy link
Member

Fantastic turnaround time! 😎👏👏👏👏

I'm really appreciate your intention, report with extended comments and PR to get smtpmock better. Thank you, Benjamin! It was a pleasure to have a code-time with you 🍻

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Development

Successfully merging a pull request may close this issue.

3 participants