smtp_test.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. package gold
  2. import (
  3. "bytes"
  4. "crypto/tls"
  5. "errors"
  6. "fmt"
  7. "io"
  8. "net"
  9. "strings"
  10. "testing"
  11. "time"
  12. "github.com/stretchr/testify/assert"
  13. )
  14. var (
  15. tlsConfig = &tls.Config{
  16. NextProtos: []string{"http/1.1"},
  17. }
  18. tlsTestCert = []byte(`-----BEGIN CERTIFICATE-----
  19. MIIB4TCCAUygAwIBAgIBADALBgkqhkiG9w0BAQUwEjEQMA4GA1UEChMHQWNtZSBD
  20. bzAeFw0xNDAxMzAyMzUyMTlaFw0yNDAxMjgyMzUyMTlaMBIxEDAOBgNVBAoTB0Fj
  21. bWUgQ28wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMs8NmXX55GqvTRcIE2K
  22. 8ZoElA7xRuiIYPXFl6Zlt/xCYUzcxEEz2pKOX3jgYEzx4wG0hQ5bcNQMJWPftZ7K
  23. 6QBvDRWs8wVgrbeN8o9LelPDrPl40Zk96howpgek/nPd5AUt6y0/hV4CNVt07y+D
  24. 13BxZSEj1E8ZTwCwhQ9uGltPAgMBAAGjSzBJMA4GA1UdDwEB/wQEAwIAoDATBgNV
  25. HSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMBQGA1UdEQQNMAuCCWxvY2Fs
  26. aG9zdDALBgkqhkiG9w0BAQUDgYEAawZEY85RZAKrROH3t1xuGLI+MIWmiFH5Z/aQ
  27. 3kA/v5YHLlygjbgxedgFEe9TodiMk9M7kUTmAM6vS2qYf+apAj2QHFFyR8xc/BZ2
  28. YHpBjeARoeg1ctbzCWeISB4BN7hOAQOojKcgaqbP49S5WG+ONfF6GuRE3oBJPJZf
  29. 1bRSET8=
  30. -----END CERTIFICATE-----`)
  31. tlsTestKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
  32. MIICXQIBAAKBgQDLPDZl1+eRqr00XCBNivGaBJQO8UboiGD1xZemZbf8QmFM3MRB
  33. M9qSjl944GBM8eMBtIUOW3DUDCVj37WeyukAbw0VrPMFYK23jfKPS3pTw6z5eNGZ
  34. PeoaMKYHpP5z3eQFLestP4VeAjVbdO8vg9dwcWUhI9RPGU8AsIUPbhpbTwIDAQAB
  35. AoGAc00U25CzCvxf3V3K4dNLIIMqcJPIE9KTl7vjPn8E87PBOfchzJAbl/v4BD7f
  36. w6eTj3sX5b5Q86x0ZgYcJxudNiLJK8XrrYqpe9yMoQ4PsN2mL77VtxwiiDrINnW+
  37. eWX5eavIXFd1d6cNbudPy/vS4MpOAMid/g/m53tH8V/ZPUkCQQD7DGcW5ra05dK7
  38. qpcj+TRQACe2VSgo78Li9DoifoU9vdx3pWWNxthdGfUlMXuAyl29sFXsxVE/ve47
  39. k7jf/YSTAkEAzz5j+F28XwRkC+2HEQFTk+CBDsV3iNFNcRFeQiaYXwI6OCmQQXDA
  40. pdmcjFqUzcKh7Wtx3G/Fz8hyifzr4/Xf1QJBAJgSjEP4H8b2zK93h7R32bN4VJYD
  41. gZ9ClYhLLwgEIgwjfXBQlXLLd/b1qWUNU2XRr/Ue4v3ZDP2SvMQEGOI+PNcCQQCF
  42. j3PmEKLhqXbAqSeusegnGTyTRHew2RLLl6Hjh/QS5uCWaVLqmbvOJtxZJ9dWc+Tf
  43. masboX0eV9RZUYLEuySxAkBLfEizykRCZ1CYkIUtKsq6HOtj+ELPBVtVPMCx3O10
  44. LMEOXuCrAMT/nApK629bgSlTU6P9PZd+05yRbHt4Ds1S
  45. -----END RSA PRIVATE KEY-----`)
  46. )
  47. type smtpServer struct {
  48. //array of commands
  49. Commands map[string]func(payload []byte) ([]byte, error)
  50. //function to be called, when no corresponding command is found
  51. CatchAll func(payload []byte) ([]byte, error)
  52. //error reporting function
  53. ErrorReporter func(err error) []byte
  54. //separator between command and payload
  55. Separator []byte
  56. }
  57. // Listen creates a server that listens for incoming SMTP connections
  58. func (srv *smtpServer) Listen(network, address string, secure bool) error {
  59. var l net.Listener
  60. var err error
  61. if secure {
  62. tlsConfig.Certificates = make([]tls.Certificate, 1)
  63. tlsConfig.Certificates[0], err = tls.X509KeyPair(tlsTestCert, tlsTestKey)
  64. if err != nil {
  65. return err
  66. }
  67. var tcpL net.Listener
  68. tcpL, err = net.Listen("tcp", address)
  69. if err != nil {
  70. return err
  71. }
  72. l = tls.NewListener(tcpL, tlsConfig)
  73. defer l.Close()
  74. } else {
  75. l, err = net.Listen(network, address)
  76. if err != nil {
  77. return err
  78. }
  79. defer l.Close()
  80. }
  81. for {
  82. conn, err := l.Accept()
  83. if err != nil {
  84. return err
  85. }
  86. go func(c net.Conn) {
  87. defer func() {
  88. e := recover()
  89. if e != nil {
  90. errorRecovered := e.(string)
  91. if errorRecovered != "" {
  92. fmt.Println(errorRecovered)
  93. c.Write(srv.ErrorReporter(errors.New(errorRecovered)))
  94. c.Close()
  95. }
  96. }
  97. }()
  98. c.Write([]byte("Commands available: \n"))
  99. for command := range srv.Commands {
  100. c.Write([]byte("# "))
  101. c.Write([]byte(command))
  102. c.Write([]byte(" [payload] \n"))
  103. }
  104. c.Write([]byte("What to do? ...\n"))
  105. //reading
  106. buf := make([]byte, 0, 4096)
  107. tmp := make([]byte, 256)
  108. for {
  109. n, err := conn.Read(tmp)
  110. if err != nil {
  111. if err != io.EOF {
  112. panic(err.Error())
  113. }
  114. break
  115. }
  116. buf = append(buf, tmp[:n]...)
  117. }
  118. parsed := bytes.Split(buf, srv.Separator)
  119. command := strings.ToLower(string(parsed[0]))
  120. payload := bytes.Join(parsed[1:], srv.Separator)
  121. action, ok := srv.Commands[command]
  122. if !ok {
  123. action = srv.CatchAll
  124. }
  125. answer, err := action(payload)
  126. if err != nil {
  127. panic(err.Error())
  128. } else {
  129. c.Write(answer)
  130. c.Close()
  131. }
  132. }(conn)
  133. }
  134. }
  135. func catchAllFunc(payload []byte) ([]byte, error) {
  136. return []byte(fmt.Sprintf("Catch all command with payload of %v", string(payload))), nil
  137. }
  138. func helloFunc(payload []byte) ([]byte, error) {
  139. return []byte(fmt.Sprintf("Hello command with payload of %v", string(payload))), nil
  140. }
  141. func badFunc(payload []byte) ([]byte, error) {
  142. return []byte(fmt.Sprintf("Bad command with payload of %v", string(payload))), errors.New("Ups, sorry!")
  143. }
  144. func errorReporter(err error) []byte {
  145. return []byte("Error processing the command: " + err.Error())
  146. }
  147. func TestStartFakeSMTPServer(t *testing.T) {
  148. t.Parallel()
  149. var commands = make(map[string](func(payload []byte) ([]byte, error)))
  150. commands["hello"] = helloFunc
  151. commands["bad"] = badFunc
  152. separator := []byte(" ")
  153. go func() {
  154. serv := smtpServer{commands, catchAllFunc, errorReporter, separator}
  155. err := serv.Listen("tcp", ":3000", false)
  156. assert.NoError(t, err)
  157. }()
  158. }
  159. func TestStartFakeSecureSMTPServer(t *testing.T) {
  160. t.Parallel()
  161. var commands = make(map[string](func(payload []byte) ([]byte, error)))
  162. commands["hello"] = helloFunc
  163. commands["bad"] = badFunc
  164. separator := []byte(" ")
  165. go func() {
  166. serv := smtpServer{commands, catchAllFunc, errorReporter, separator}
  167. err := serv.Listen("tcp", ":3030", true)
  168. assert.NoError(t, err)
  169. }()
  170. }
  171. func TestFakeSMTPDial(t *testing.T) {
  172. t.Parallel()
  173. // give the server some time to start
  174. time.Sleep(200 * time.Millisecond)
  175. _, err := net.Dial("tcp", "localhost:3000")
  176. assert.NoError(t, err)
  177. }
  178. //func TestFakeSMTPSecureDial(t *testing.T) {
  179. // t.Parallel()
  180. // // give the server some time to start
  181. // time.Sleep(200 * time.Millisecond)
  182. // tlsconfig := &tls.Config{
  183. // InsecureSkipVerify: true,
  184. // ServerName: "localhost",
  185. // }
  186. // _, err := tls.Dial("tcp", "localhost:3030", tlsconfig)
  187. // assert.NoError(t, err)
  188. //}