github.com/go-email-validator/go-email-validator@v0.0.0-20230409163946-b8b9e6a0552e/test/mock/ev/evsmtp/server.go (about)

     1  package mockevsmtp
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"net"
     7  	"net/textproto"
     8  	"sync"
     9  	"testing"
    10  	"time"
    11  )
    12  
    13  // Separator separate mock message of Server
    14  const Separator = "\r\n"
    15  
    16  // SuccessServer contents success smtp server response
    17  var SuccessServer = []string{
    18  	"220 hello world",
    19  	"502 EH?",
    20  	"250 mx.google.com at your service",
    21  	"250 Sender ok",
    22  	"550 address does not exist",
    23  	"250 Receiver ok",
    24  	"221 Goodbye",
    25  }
    26  
    27  // Server to testing SMTP
    28  // Partial copy of TestSendMail  from smtp.TestSendMail
    29  func Server(
    30  	t testing.TB,
    31  	server []string,
    32  	timeout time.Duration,
    33  	addr string,
    34  	infinite bool,
    35  ) (string, chan string) {
    36  	var cmdbuf bytes.Buffer
    37  	bcmdbuf := bufio.NewWriter(&cmdbuf)
    38  
    39  	if addr == "" {
    40  		addr = "0.0.0.0:0"
    41  	}
    42  
    43  	l, err := net.Listen("tcp", addr)
    44  	if err != nil {
    45  		t.Fatalf("Unable to create listener: %v", err)
    46  	}
    47  
    48  	var done = make(chan string)
    49  	closedMu := &sync.Mutex{}
    50  	closed := false
    51  	closeServer := func() {
    52  		closedMu.Lock()
    53  		if !closed {
    54  			closed = true
    55  			bcmdbuf.Flush()
    56  			done <- cmdbuf.String()
    57  			close(done)
    58  			l.Close()
    59  		}
    60  		closedMu.Unlock()
    61  	}
    62  	go func(data []string) {
    63  		defer closeServer()
    64  
    65  		if len(data) == 0 {
    66  			return
    67  		}
    68  		for {
    69  			func() {
    70  				conn, err := l.Accept()
    71  				if err != nil {
    72  					t.Errorf("Accept error: %v", err)
    73  					return
    74  				}
    75  				defer conn.Close()
    76  
    77  				tc := textproto.NewConn(conn)
    78  
    79  				for i := 0; i < len(data) && data[i] != ""; i++ {
    80  					tc.PrintfLine(data[i])
    81  					for len(data[i]) >= 4 && data[i][3] == '-' {
    82  						i++
    83  						tc.PrintfLine(data[i])
    84  					}
    85  					if data[i] == "221 Goodbye" {
    86  						return
    87  					}
    88  					read := false
    89  					for !read || data[i] == "354 Go ahead" {
    90  						msg, err := tc.ReadLine()
    91  						bcmdbuf.Write([]byte(msg + Separator))
    92  						read = true
    93  						if err != nil {
    94  							t.Errorf("Read error: %v", err)
    95  							return
    96  						}
    97  						if data[i] == "354 Go ahead" && msg == "." {
    98  							break
    99  						}
   100  					}
   101  				}
   102  			}()
   103  
   104  			if !infinite {
   105  				break
   106  			}
   107  		}
   108  	}(server)
   109  
   110  	go func() {
   111  		if timeout > 0 {
   112  			time.Sleep(timeout)
   113  			closeServer()
   114  		}
   115  	}()
   116  
   117  	return l.Addr().String(), done
   118  }