github.com/go-email-validator/go-email-validator@v0.0.0-20230409163946-b8b9e6a0552e/pkg/ev/evsmtp/mock_test.go (about) 1 package evsmtp 2 3 import ( 4 "bytes" 5 "github.com/go-email-validator/go-email-validator/pkg/ev/evsmtp/smtpclient" 6 "github.com/go-email-validator/go-email-validator/pkg/ev/evtests" 7 "github.com/stretchr/testify/require" 8 "io" 9 "net/smtp" 10 "reflect" 11 "strings" 12 "sync" 13 "testing" 14 "time" 15 ) 16 17 const ( 18 helloName = "helloName" 19 20 smClient = "Client" 21 smHello = "Hello " 22 smHelloLocalhost = "Hello localhost" 23 smAuth = "Auth" 24 smMail = "Mail " 25 smRCPTs = "Rcpts " 26 smData = "Data" 27 smWrite = "Write" 28 smQuit = "Quit" 29 smClose = "Close" 30 smWriteMessage = "Write message" 31 smWCloseWriter = "Close writer" 32 ) 33 34 var ( 35 testUser = "testUser" 36 testPwd = "testPwd" 37 testHost = "testHost" 38 testAuth = smtp.PlainAuth("", testUser, testPwd, testHost) 39 testMsg = "msg" 40 mockWriterInstance = &mockWriter{} 41 ) 42 43 func stringsJoin(strs []string) string { 44 return strings.Join(strs, ",") 45 } 46 47 // TODO create mock by gomock 48 type sendMailWant struct { 49 stage string 50 message string 51 sleep time.Duration 52 ret interface{} 53 } 54 55 type mockSendMail struct { 56 mu sync.Mutex 57 t *testing.T 58 i int 59 want []sendMailWant 60 } 61 62 func (s *mockSendMail) Client() smtpclient.SMTPClient { 63 return s.do(smClient).(smtpclient.SMTPClient) 64 } 65 66 func (s *mockSendMail) Hello(localName string) error { 67 return evtests.ToError(s.do(smHello + localName)) 68 } 69 70 func (s *mockSendMail) Auth(a smtp.Auth) error { 71 ret := s.do(smAuth).([]interface{}) 72 if !reflect.DeepEqual(a, ret[0]) { 73 s.t.Errorf("Invalid auth, got %#v, want %#v", a, testAuth) 74 } 75 return evtests.ToError(ret[1]) 76 } 77 78 func (s *mockSendMail) Mail(from string) error { 79 return evtests.ToError(s.do(smMail + from)) 80 } 81 82 func (s *mockSendMail) RCPTs(addr []string) map[string]error { 83 err := s.do(smRCPTs + stringsJoin(addr)) 84 85 if err == nil { 86 return nil 87 } 88 89 return map[string]error{ 90 addr[0]: evtests.ToError(err), 91 } 92 } 93 94 func (s *mockSendMail) Data() (io.WriteCloser, error) { 95 return &mockWriter{s: s, want: testMsg}, evtests.ToError(s.do(smData)) 96 } 97 98 func (s *mockSendMail) Write(w io.WriteCloser, msg []byte) error { 99 w.Write(msg) 100 w.Close() 101 102 return evtests.ToError(s.do(smWrite)) 103 } 104 105 func (s *mockSendMail) Quit() error { 106 return evtests.ToError(s.do(smQuit)) 107 } 108 109 func (s *mockSendMail) Close() error { 110 return evtests.ToError(s.do(smClose)) 111 } 112 113 func (s *mockSendMail) do(cmd string) interface{} { 114 s.mu.Lock() 115 defer s.mu.Unlock() 116 if s.i >= len(s.want) { 117 s.t.Fatalf("Invalid command %q", cmd) 118 } 119 120 want := s.want[s.i] 121 if cmd != want.message { 122 s.t.Fatalf("Invalid command, got %q, want %q", cmd, want.message) 123 } 124 s.i++ 125 126 time.Sleep(want.sleep) 127 128 return want.ret 129 } 130 131 type mockWriter struct { 132 want string 133 s *mockSendMail 134 buf bytes.Buffer 135 } 136 137 func (w *mockWriter) Write(p []byte) (int, error) { 138 if w.buf.Len() == 0 { 139 w.s.do(smWriteMessage) 140 } 141 w.buf.Write(p) 142 return len(p), nil 143 } 144 145 func (w *mockWriter) Close() error { 146 require.Equal(w.s.t, w.buf.String(), w.want) 147 w.s.do(smWCloseWriter) 148 return nil 149 } 150 151 var defaultWantMap = map[string]sendMailWant{ 152 smHello: { 153 message: smHelloLocalhost, 154 }, 155 smAuth: { 156 message: smAuth, 157 ret: []interface{}{nil, nil}, 158 }, 159 smMail: { 160 message: smMail + emailFrom.String(), 161 ret: nil, 162 }, 163 smRCPTs: { 164 message: smRCPTs + randomAddress.String(), 165 ret: nil, 166 }, 167 } 168 169 var quitStageWant = sendMailWant{ 170 message: smQuit, 171 ret: nil, 172 } 173 174 var closeStageWant = sendMailWant{ 175 message: smClose, 176 ret: nil, 177 } 178 179 var wantSuccessList = []string{ 180 smHello, 181 smAuth, 182 smMail, 183 smRCPTs, // only random email call rcpt 184 smQuit, 185 } 186 187 func failWant(failStage *sendMailWant, withClose bool) []sendMailWant { 188 wants := make([]sendMailWant, 0) 189 for _, stage := range wantSuccessList { 190 191 var want sendMailWant 192 want, ok := defaultWantMap[stage] 193 if !ok { 194 want = sendMailWant{message: stage} 195 } 196 197 if failStage != nil && stage == failStage.stage { 198 wants = append(wants, *failStage) 199 break 200 } 201 wants = append(wants, want) 202 } 203 204 if withClose { 205 wants = append(wants, closeStageWant) 206 } 207 208 return wants 209 }