github.com/go-email-validator/go-email-validator@v0.0.0-20230409163946-b8b9e6a0552e/pkg/ev/evsmtp/smtp_test.go (about)

     1  package evsmtp
     2  
     3  import (
     4  	"context"
     5  	"crypto/tls"
     6  	"errors"
     7  	"fmt"
     8  	"github.com/allegro/bigcache"
     9  	"github.com/eko/gocache/marshaler"
    10  	"github.com/eko/gocache/store"
    11  	"github.com/go-email-validator/go-email-validator/pkg/ev/evcache"
    12  	"github.com/go-email-validator/go-email-validator/pkg/ev/evmail"
    13  	"github.com/go-email-validator/go-email-validator/pkg/ev/evsmtp/smtpclient"
    14  	"github.com/go-email-validator/go-email-validator/pkg/ev/evtests"
    15  	"github.com/go-email-validator/go-email-validator/pkg/ev/utils"
    16  	mockevcache "github.com/go-email-validator/go-email-validator/test/mock/ev/evcache"
    17  	mockevmail "github.com/go-email-validator/go-email-validator/test/mock/ev/evmail"
    18  	"github.com/go-email-validator/go-email-validator/test/mock/ev/evsmtp"
    19  	"github.com/golang/mock/gomock"
    20  	"github.com/stretchr/testify/require"
    21  	"net"
    22  	"net/smtp"
    23  	"net/textproto"
    24  	"net/url"
    25  	"reflect"
    26  	"strconv"
    27  	"strings"
    28  	"testing"
    29  	"time"
    30  )
    31  
    32  func TestMain(m *testing.M) {
    33  	evtests.TestMain(m)
    34  }
    35  
    36  func dialFunc(t *testing.T, client smtpclient.SMTPClient, err error, wantCtx context.Context, wantAddr, wantProxy string, sleep time.Duration) DialFunc {
    37  	return func(ctx context.Context, addr, proxy string) (smtpclient.SMTPClient, error) {
    38  		require.Equal(t, utils.StructName(wantCtx), utils.StructName(ctx))
    39  		require.Equal(t, addr, wantAddr)
    40  		require.Equal(t, wantProxy, proxy)
    41  
    42  		time.Sleep(sleep)
    43  
    44  		return client, err
    45  	}
    46  }
    47  
    48  var (
    49  	localhost      = "127.0.0.1"
    50  	smtpLocalhost  = localhost + ":25"
    51  	errorSimple    = errors.New("errorSimple")
    52  	errorRandom    = errors.New("errorRandom")
    53  	mxs            = MXs{&net.MX{Host: localhost}}
    54  	emptyLocalName = ""
    55  	simpleClient   = &smtp.Client{}
    56  	emailFromStr   = "email@from.com"
    57  	emailFrom      = evmail.FromString(emailFromStr)
    58  	emailToStr     = "email@to.com"
    59  	emailTo        = evmail.FromString(emailToStr)
    60  	randomAddress  = getRandomAddress(emailTo)
    61  	validEmail     = mockevmail.GetValidTestEmail()
    62  	getMockKey     = func(t *testing.T, wantEmail evmail.Address, ret interface{}) func(email evmail.Address) interface{} {
    63  		return func(email evmail.Address) interface{} {
    64  			require.Equal(t, wantEmail, email)
    65  			return ret
    66  		}
    67  	}
    68  )
    69  
    70  func getRandomAddress(email evmail.Address) evmail.Address {
    71  	return evmail.FromString("random.which.did.not.exist@" + email.Domain())
    72  }
    73  
    74  func mockRandomEmail(t *testing.T, email evmail.Address, err error) RandomEmail {
    75  	return func(domain string) (evmail.Address, error) {
    76  		if domain != email.Domain() {
    77  			t.Errorf("domain of random email is not equal")
    78  		}
    79  
    80  		return email, err
    81  	}
    82  }
    83  
    84  func localIP() string {
    85  	addrs, err := net.InterfaceAddrs()
    86  	if err != nil {
    87  		return ""
    88  	}
    89  	for _, address := range addrs {
    90  		// check the address type and if it is not a loopback the display it
    91  		if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
    92  			if ipnet.IP.To4() != nil {
    93  				return ipnet.IP.String()
    94  			}
    95  		}
    96  	}
    97  	return ""
    98  }
    99  
   100  func Test_checker_Validate(t *testing.T) {
   101  	type fields struct {
   102  		sendMailFactory SendMailDialerFactory
   103  		randomEmail     RandomEmail
   104  		options         Options
   105  	}
   106  	type args struct {
   107  		mx    MXs
   108  		email evmail.Address
   109  	}
   110  
   111  	successDialFunc := dialFunc(t, simpleClient, nil, context.Background(), smtpLocalhost, "", 0)
   112  
   113  	ctxTimeout, cancel := context.WithTimeout(context.Background(), 0)
   114  	defer cancel()
   115  
   116  	errConnection := NewError(ConnectionStage, errors.New(ErrConnectionMsg))
   117  
   118  	tests := []struct {
   119  		name     string
   120  		fields   fields
   121  		args     args
   122  		wantErrs []error
   123  	}{
   124  		{
   125  			name:     "empty mx",
   126  			args:     args{},
   127  			wantErrs: utils.Errs(errConnection),
   128  		},
   129  		{
   130  			name: "cannot connection to mx",
   131  			fields: fields{
   132  				sendMailFactory: NewSendMailFactory(dialFunc(t, nil, errorSimple, context.Background(), smtpLocalhost, "", 0), nil),
   133  				options:         &options{},
   134  			},
   135  			args: args{
   136  				mx: mxs,
   137  			},
   138  			wantErrs: utils.Errs(errConnection),
   139  		},
   140  		{
   141  			name: "Bad hello with helloName",
   142  			fields: fields{
   143  				sendMailFactory: NewSendMailCustom(successDialFunc, nil,
   144  					func(client smtpclient.SMTPClient, tlsConfig *tls.Config) SendMail {
   145  						return &mockSendMail{
   146  							t:    t,
   147  							want: failWant(&sendMailWant{stage: smHello, message: smHello + helloName, ret: errorSimple}, true),
   148  						}
   149  					}),
   150  				options: &options{
   151  					helloName: helloName,
   152  				},
   153  			},
   154  			args: args{
   155  				mx: mxs,
   156  			},
   157  			wantErrs: utils.Errs(NewError(HelloStage, errorSimple)),
   158  		},
   159  		{
   160  			name: "Bad auth",
   161  			fields: fields{
   162  				sendMailFactory: NewSendMailCustom(successDialFunc, nil,
   163  					func(client smtpclient.SMTPClient, tlsConfig *tls.Config) SendMail {
   164  						return &mockSendMail{
   165  							t: t,
   166  							want: failWant(&sendMailWant{
   167  								stage:   smAuth,
   168  								message: smAuth,
   169  								ret:     []interface{}{nil, errorSimple},
   170  							}, true),
   171  						}
   172  					}),
   173  				options: &options{},
   174  			},
   175  			args: args{
   176  				mx: mxs,
   177  			},
   178  			wantErrs: utils.Errs(NewError(AuthStage, errorSimple)),
   179  		},
   180  		{
   181  			name: "Bad Mail stage",
   182  			fields: fields{
   183  				sendMailFactory: NewSendMailCustom(successDialFunc, nil,
   184  					func(client smtpclient.SMTPClient, tlsConfig *tls.Config) SendMail {
   185  						return &mockSendMail{
   186  							t: t,
   187  							want: failWant(&sendMailWant{
   188  								stage:   smMail,
   189  								message: smMail + emailFrom.String(),
   190  								ret:     errorSimple,
   191  							}, true),
   192  						}
   193  					}),
   194  				options: &options{
   195  					emailFrom: emailFrom,
   196  				},
   197  			},
   198  			args: args{
   199  				mx: mxs,
   200  			},
   201  			wantErrs: utils.Errs(NewError(MailStage, errorSimple)),
   202  		},
   203  		{
   204  			name: "Problem with generation Random email",
   205  			fields: fields{
   206  				sendMailFactory: NewSendMailCustom(successDialFunc, nil,
   207  					func(client smtpclient.SMTPClient, tlsConfig *tls.Config) SendMail {
   208  						return &mockSendMail{
   209  							t: t,
   210  							want: append(failWant(&sendMailWant{
   211  								stage:   smMail,
   212  								message: smMail + emailFrom.String(),
   213  								ret:     nil,
   214  							}, false),
   215  								sendMailWant{
   216  									stage:   smRCPTs,
   217  									message: smRCPTs + emailTo.String(),
   218  									ret:     errorSimple,
   219  								},
   220  								quitStageWant,
   221  								closeStageWant,
   222  							),
   223  						}
   224  					}),
   225  				randomEmail: mockRandomEmail(t, randomAddress, errorRandom),
   226  				options: &options{
   227  					emailFrom: emailFrom,
   228  				},
   229  			},
   230  			args: args{
   231  				mx:    mxs,
   232  				email: emailTo,
   233  			},
   234  			wantErrs: utils.Errs(
   235  				NewError(RandomRCPTStage, errorRandom),
   236  				NewError(RCPTsStage, errorSimple),
   237  			),
   238  		},
   239  		{
   240  			name: "Problem with RCPTs Random email",
   241  			fields: fields{
   242  				sendMailFactory: NewSendMailCustom(successDialFunc, nil,
   243  					func(client smtpclient.SMTPClient, tlsConfig *tls.Config) SendMail {
   244  						return &mockSendMail{
   245  							t: t,
   246  							want: append(failWant(&sendMailWant{
   247  								stage:   smRCPTs,
   248  								message: smRCPTs + randomAddress.String(),
   249  								ret:     errorSimple,
   250  							}, false),
   251  								sendMailWant{
   252  									stage:   smRCPTs,
   253  									message: smRCPTs + emailTo.String(),
   254  									ret:     errorSimple,
   255  								},
   256  								quitStageWant,
   257  								closeStageWant,
   258  							),
   259  						}
   260  					}),
   261  				randomEmail: mockRandomEmail(t, randomAddress, nil),
   262  				options: &options{
   263  					emailFrom: emailFrom,
   264  				},
   265  			},
   266  			args: args{
   267  				mx:    mxs,
   268  				email: emailTo,
   269  			},
   270  			wantErrs: utils.Errs(
   271  				NewError(RandomRCPTStage, errorSimple),
   272  				NewError(RCPTsStage, errorSimple),
   273  			),
   274  		},
   275  		{
   276  			name: "Quit problem",
   277  			fields: fields{
   278  				sendMailFactory: NewSendMailCustom(successDialFunc, nil,
   279  					func(client smtpclient.SMTPClient, tlsConfig *tls.Config) SendMail {
   280  						return &mockSendMail{
   281  							t: t,
   282  							want: failWant(&sendMailWant{
   283  								stage:   smQuit,
   284  								message: smQuit,
   285  								ret:     errorSimple,
   286  							}, true),
   287  						}
   288  					}),
   289  				randomEmail: mockRandomEmail(t, randomAddress, nil),
   290  				options: &options{
   291  					emailFrom: emailFrom,
   292  				},
   293  			},
   294  			args: args{
   295  				mx:    mxs,
   296  				email: emailTo,
   297  			},
   298  			wantErrs: utils.Errs(NewError(QuitStage, errorSimple)),
   299  		},
   300  		{
   301  			name: "Success",
   302  			fields: fields{
   303  				sendMailFactory: NewSendMailCustom(successDialFunc, nil,
   304  					func(client smtpclient.SMTPClient, tlsConfig *tls.Config) SendMail {
   305  						return &mockSendMail{
   306  							t:    t,
   307  							want: failWant(nil, true),
   308  						}
   309  					}),
   310  				randomEmail: mockRandomEmail(t, randomAddress, nil),
   311  				options: &options{
   312  					emailFrom: emailFrom,
   313  				},
   314  			},
   315  			args: args{
   316  				mx:    mxs,
   317  				email: emailTo,
   318  			},
   319  			wantErrs: []error{},
   320  		},
   321  		{
   322  			name: "with timeout success",
   323  			fields: fields{
   324  				sendMailFactory: NewSendMailCustom(
   325  					dialFunc(t, simpleClient, nil, ctxTimeout, smtpLocalhost, "", 0),
   326  					nil,
   327  					func(client smtpclient.SMTPClient, tlsConfig *tls.Config) SendMail {
   328  						return &mockSendMail{
   329  							t:    t,
   330  							want: failWant(nil, true),
   331  						}
   332  					}),
   333  				randomEmail: mockRandomEmail(t, randomAddress, nil),
   334  				options: &options{
   335  					emailFrom:   emailFrom,
   336  					timeoutCon:  5 * time.Second,
   337  					timeoutResp: 5 * time.Second,
   338  				},
   339  			},
   340  			args: args{
   341  				mx:    mxs,
   342  				email: emailTo,
   343  			},
   344  			wantErrs: []error{},
   345  		},
   346  		{
   347  			name: "with expired connection timeout",
   348  			fields: fields{
   349  				sendMailFactory: NewSendMailCustom(
   350  					dialFunc(t, simpleClient, nil, ctxTimeout, smtpLocalhost, "", 2*time.Millisecond),
   351  					nil,
   352  					func(client smtpclient.SMTPClient, tlsConfig *tls.Config) SendMail {
   353  						return &mockSendMail{
   354  							t:    t,
   355  							want: failWant(nil, true),
   356  						}
   357  					}),
   358  				randomEmail: mockRandomEmail(t, randomAddress, nil),
   359  				options: &options{
   360  					emailFrom:  emailFrom,
   361  					timeoutCon: 1,
   362  				},
   363  			},
   364  			args: args{
   365  				mx:    mxs,
   366  				email: emailTo,
   367  			},
   368  			wantErrs: utils.Errs(errConnection),
   369  		},
   370  		{
   371  			name: "with expired response timeout",
   372  			fields: fields{
   373  				sendMailFactory: NewSendMailCustom(successDialFunc, nil,
   374  					func(client smtpclient.SMTPClient, tlsConfig *tls.Config) SendMail {
   375  						return &mockSendMail{
   376  							t: t,
   377  							want: []sendMailWant{
   378  								{
   379  									sleep:   2 * time.Millisecond,
   380  									stage:   smHello,
   381  									message: smHelloLocalhost,
   382  									ret:     context.DeadlineExceeded,
   383  								},
   384  								closeStageWant,
   385  							},
   386  						}
   387  					}),
   388  				randomEmail: mockRandomEmail(t, randomAddress, nil),
   389  				options: &options{
   390  					emailFrom:   emailFrom,
   391  					timeoutResp: 1 * time.Millisecond,
   392  				},
   393  			},
   394  			args: args{
   395  				mx:    mxs,
   396  				email: emailTo,
   397  			},
   398  			wantErrs: utils.Errs(NewError(HelloStage, context.DeadlineExceeded)),
   399  		},
   400  	}
   401  	for _, tt := range tests {
   402  		t.Run(tt.name, func(t *testing.T) {
   403  			c := NewChecker(CheckerDTO{
   404  				SendMailFactory: tt.fields.sendMailFactory,
   405  				RandomEmail:     tt.fields.randomEmail,
   406  				Options:         tt.fields.options,
   407  			})
   408  			gotErrs := c.Validate(tt.args.mx, NewInput(tt.args.email, nil))
   409  			if !reflect.DeepEqual(gotErrs, tt.wantErrs) {
   410  				t.Errorf("Validate() = %v, want %v", gotErrs, tt.wantErrs)
   411  			}
   412  		})
   413  	}
   414  }
   415  
   416  func TestChecker_Validate_WithProxy_Local(t *testing.T) {
   417  	evtests.FunctionalSkip(t)
   418  
   419  	ctrl := gomock.NewController(t)
   420  	defer ctrl.Finish()
   421  
   422  	successWantSMTP := []string{
   423  		"EHLO helloName",
   424  		"HELO helloName",
   425  		"MAIL FROM:<user@example.org>",
   426  		"RCPT TO:<random.which.did.not.exist@tradepro.net>",
   427  		"RCPT TO:<asd@tradepro.net>",
   428  		"QUIT",
   429  		"",
   430  	}
   431  
   432  	type fields struct {
   433  		SendMailFactory SendMailDialerFactory
   434  		Auth            smtp.Auth
   435  		RandomEmail     RandomEmail
   436  		Server          []string
   437  		OptionsDTO      OptionsDTO
   438  	}
   439  	type args struct {
   440  		mxs   MXs
   441  		email evmail.Address
   442  	}
   443  
   444  	emailString := "asd@tradepro.net"
   445  
   446  	emailFrom := evmail.FromString(DefaultEmail)
   447  	emailTest := evmail.FromString(emailString)
   448  
   449  	tests := []struct {
   450  		name     string
   451  		fields   fields
   452  		args     args
   453  		wantErrs []error
   454  		wantSMTP []string
   455  	}{
   456  		{
   457  			name: "without proxy",
   458  			fields: fields{
   459  				SendMailFactory: NewSendMailFactory(DirectDial, nil),
   460  				Auth:            nil,
   461  				RandomEmail:     mockRandomEmail(t, getRandomAddress(emailTest), nil),
   462  				Server:          mockevsmtp.SuccessServer,
   463  				OptionsDTO: OptionsDTO{
   464  					EmailFrom: emailFrom,
   465  					HelloName: helloName,
   466  				},
   467  			},
   468  			args: args{
   469  				mxs:   mxs,
   470  				email: emailTest,
   471  			},
   472  			wantErrs: []error{NewError(RandomRCPTStage, &textproto.Error{
   473  				Code: 550,
   474  				Msg:  "address does not exist",
   475  			})},
   476  			wantSMTP: successWantSMTP,
   477  		},
   478  	}
   479  	for _, tt := range tests {
   480  		t.Run(tt.name, func(t *testing.T) {
   481  			addr, done := mockevsmtp.Server(t, tt.fields.Server, time.Second, "", false)
   482  
   483  			if tt.fields.OptionsDTO.Port == 0 {
   484  				u, _ := url.Parse("http://" + addr)
   485  				tt.fields.OptionsDTO.Port, _ = strconv.Atoi(u.Port())
   486  			}
   487  
   488  			c := checker{
   489  				sendMailFactory: tt.fields.SendMailFactory,
   490  				Auth:            tt.fields.Auth,
   491  				randomEmail:     tt.fields.RandomEmail,
   492  				options:         NewOptions(tt.fields.OptionsDTO),
   493  			}
   494  			mockRandomRCPT := NewMockRandomRCPT(ctrl)
   495  			mockRandomRCPT.EXPECT().Call(gomock.Any(), gomock.Any()).DoAndReturn(c.randomRCPT).Times(1)
   496  			c.RandomRCPT = mockRandomRCPT
   497  			//c.RandomRCPT = &ARandomRCPT{fn: c.randomRCPT}
   498  
   499  			gotErrs := c.Validate(tt.args.mxs, NewInput(tt.args.email, nil))
   500  			actualClient := <-done
   501  
   502  			wantSMTP := strings.Join(tt.wantSMTP, mockevsmtp.Separator)
   503  			if wantSMTP != actualClient {
   504  				t.Errorf("Got:\n%s\nExpected:\n%s", actualClient, wantSMTP)
   505  			}
   506  
   507  			if !reflect.DeepEqual(gotErrs, tt.wantErrs) {
   508  				t.Errorf("Validate() = %v, want %v", gotErrs, tt.wantErrs)
   509  			}
   510  		})
   511  	}
   512  }
   513  
   514  func Test_checkerCacheRandomRCPT_RandomRCPT(t *testing.T) {
   515  	ctrl := gomock.NewController(t)
   516  	defer ctrl.Finish()
   517  
   518  	type fields struct {
   519  		checkerWithRandomRPCT func() CheckerWithRandomRCPT
   520  		cache                 func() evcache.Interface
   521  		getKey                RandomCacheKeyGetter
   522  	}
   523  	type args struct {
   524  		email evmail.Address
   525  	}
   526  
   527  	errs := []error{errorSimple}
   528  	errsAlias := []AliasError{errorSimple}
   529  	emptyChecker := func() CheckerWithRandomRCPT {
   530  		mock := NewMockCheckerWithRandomRCPT(ctrl)
   531  		mock.EXPECT().get().Return(nil).Times(1)
   532  		mock.EXPECT().set(gomock.Any()).Times(1)
   533  
   534  		return mock
   535  	}
   536  
   537  	tests := []struct {
   538  		name     string
   539  		fields   fields
   540  		args     args
   541  		wantErrs []error
   542  	}{
   543  		{
   544  			name: "with cache",
   545  			fields: fields{
   546  				checkerWithRandomRPCT: emptyChecker,
   547  				cache: func() evcache.Interface {
   548  					mock := mockevcache.NewMockInterface(ctrl)
   549  					mock.EXPECT().Get(validEmail.Domain()).Return(&errs, nil).Times(1)
   550  
   551  					return mock
   552  				},
   553  				getKey: getMockKey(t, validEmail, validEmail.Domain()),
   554  			},
   555  			args: args{
   556  				email: validEmail,
   557  			},
   558  			wantErrs: errs,
   559  		},
   560  		{
   561  			name: "without cache",
   562  			fields: fields{
   563  				checkerWithRandomRPCT: func() CheckerWithRandomRCPT {
   564  					mock := NewMockCheckerWithRandomRCPT(ctrl)
   565  					mock.EXPECT().get().Return(mock.Call).Times(1)
   566  					mock.EXPECT().set(gomock.Any()).Times(1)
   567  					mock.EXPECT().Call(gomock.Any(), validEmail).Return(errs).Times(1)
   568  
   569  					return mock
   570  				},
   571  				cache: func() evcache.Interface {
   572  					mock := mockevcache.NewMockInterface(ctrl)
   573  					mock.EXPECT().Get(validEmail.Domain()).Return(nil, nil).Times(1)
   574  					mock.EXPECT().Set(validEmail.Domain(), errsAlias).Return(nil).Times(1)
   575  
   576  					return mock
   577  				},
   578  				getKey: getMockKey(t, validEmail, validEmail.Domain()),
   579  			},
   580  			args: args{
   581  				email: validEmail,
   582  			},
   583  			wantErrs: errs,
   584  		},
   585  	}
   586  	for _, tt := range tests {
   587  		t.Run(tt.name, func(t *testing.T) {
   588  			c := NewCheckerCacheRandomRCPT(tt.fields.checkerWithRandomRPCT(), tt.fields.cache(), tt.fields.getKey).(*checkerCacheRandomRCPT)
   589  			if gotErrs := c.RandomRCPT(nil, tt.args.email); !reflect.DeepEqual(gotErrs, tt.wantErrs) {
   590  				t.Errorf("RandomRCPT() = %v, want %v", gotErrs, tt.wantErrs)
   591  			}
   592  		})
   593  	}
   594  }
   595  
   596  func TestDefaultRandomCacheKeyGetter(t *testing.T) {
   597  	type args struct {
   598  		email evmail.Address
   599  	}
   600  	tests := []struct {
   601  		name string
   602  		args args
   603  		want interface{}
   604  	}{
   605  		{
   606  			name: "success",
   607  			args: args{
   608  				email: mockevmail.GetValidTestEmail(),
   609  			},
   610  			want: mockevmail.GetValidTestEmail().Domain(),
   611  		},
   612  	}
   613  	for _, tt := range tests {
   614  		t.Run(tt.name, func(t *testing.T) {
   615  			if got := DefaultRandomCacheKeyGetter(tt.args.email); !reflect.DeepEqual(got, tt.want) {
   616  				t.Errorf("DefaultRandomCacheKeyGetter() = %v, want %v", got, tt.want)
   617  			}
   618  		})
   619  	}
   620  }
   621  
   622  func TestNewCheckerCacheRandomRCPT(t *testing.T) {
   623  	ctrl := gomock.NewController(t)
   624  	defer ctrl.Finish()
   625  
   626  	type args struct {
   627  		checker func() CheckerWithRandomRCPT
   628  		cache   evcache.Interface
   629  		getKey  RandomCacheKeyGetter
   630  	}
   631  	tests := []struct {
   632  		name string
   633  		args args
   634  		want Checker
   635  	}{
   636  		{
   637  			name: "fill empty",
   638  			args: args{
   639  				checker: func() CheckerWithRandomRCPT {
   640  					mock := NewMockCheckerWithRandomRCPT(ctrl)
   641  					mock.EXPECT().get().Return(nil).Times(1)
   642  					mock.EXPECT().set(gomock.Any()).Times(1)
   643  
   644  					return mock
   645  				},
   646  				cache:  nil,
   647  				getKey: nil,
   648  			},
   649  			want: &checkerCacheRandomRCPT{
   650  				getKey:     DefaultRandomCacheKeyGetter,
   651  				randomRCPT: &ARandomRCPT{},
   652  			},
   653  		},
   654  	}
   655  	for _, tt := range tests {
   656  		t.Run(tt.name, func(t *testing.T) {
   657  			got := NewCheckerCacheRandomRCPT(tt.args.checker(), tt.args.cache, tt.args.getKey)
   658  
   659  			gotChecker := got.(*checkerCacheRandomRCPT)
   660  			gotGetKey := gotChecker.getKey
   661  			gotChecker.getKey = nil
   662  			gotChecker.CheckerWithRandomRCPT = nil
   663  			want := tt.want.(*checkerCacheRandomRCPT)
   664  			wantGetKey := want.getKey
   665  			want.getKey = nil
   666  
   667  			if !reflect.DeepEqual(got, tt.want) || fmt.Sprint(gotGetKey) != fmt.Sprint(wantGetKey) {
   668  				t.Errorf(
   669  					"NewCheckerCacheRandomRCPT() = %v, want %v\n gotGetKey = %v, wantGetKey %v",
   670  					got, tt.want, gotGetKey, wantGetKey)
   671  			}
   672  		})
   673  	}
   674  }
   675  
   676  var cacheErrs = []error{
   677  	NewError(1, &textproto.Error{Code: 505, Msg: "msg1"}),
   678  	NewError(1, errors.New("msg2")),
   679  }
   680  
   681  func Test_Cache(t *testing.T) {
   682  	bigCacheClient, err := bigcache.NewBigCache(bigcache.DefaultConfig(5 * time.Minute))
   683  	require.Nil(t, err)
   684  	bigCacheStore := store.NewBigcache(bigCacheClient, nil)
   685  
   686  	marshal := marshaler.New(bigCacheStore)
   687  
   688  	cache := evcache.NewCacheMarshaller(marshal, func() interface{} {
   689  		return new([]error)
   690  	}, nil)
   691  
   692  	key := "key"
   693  
   694  	err = cache.Set(key, ErrorsToEVSMTPErrors(cacheErrs))
   695  	require.Nil(t, err)
   696  
   697  	got, err := cache.Get(key)
   698  	require.Nil(t, err)
   699  	require.Equal(t, cacheErrs, *got.(*[]error))
   700  }
   701  
   702  func Test_checkerCacheRandomRCPT_RandomRCPT_RealCache(t *testing.T) {
   703  	ctrl := gomock.NewController(t)
   704  	defer ctrl.Finish()
   705  
   706  	type fields struct {
   707  		CheckerWithRandomRCPT func() CheckerWithRandomRCPT
   708  		randomRCPT            RandomRCPT
   709  		cache                 func() evcache.Interface
   710  	}
   711  	type args struct {
   712  		email evmail.Address
   713  	}
   714  	tests := []struct {
   715  		name     string
   716  		fields   fields
   717  		args     args
   718  		wantErrs []error
   719  	}{
   720  		{
   721  			name: "with cache",
   722  			fields: fields{
   723  				CheckerWithRandomRCPT: func() CheckerWithRandomRCPT {
   724  					mock := NewMockCheckerWithRandomRCPT(ctrl)
   725  					mock.EXPECT().get().Return(mock.Call).Times(1)
   726  					mock.EXPECT().set(gomock.Any()).Times(1)
   727  
   728  					return mock
   729  				},
   730  				cache: func() evcache.Interface {
   731  					bigCacheClient, err := bigcache.NewBigCache(bigcache.DefaultConfig(5 * time.Minute))
   732  					require.Nil(t, err)
   733  					bigCacheStore := store.NewBigcache(bigCacheClient, nil)
   734  
   735  					marshal := marshaler.New(bigCacheStore)
   736  
   737  					// Add value to cache
   738  					key := DefaultRandomCacheKeyGetter(validEmail)
   739  					err = marshal.Set(key, ErrorsToEVSMTPErrors(cacheErrs), nil)
   740  					require.Nil(t, err)
   741  
   742  					return evcache.NewCacheMarshaller(marshal, func() interface{} {
   743  						return new([]error)
   744  					}, nil)
   745  				},
   746  			},
   747  			args: args{
   748  				email: validEmail,
   749  			},
   750  			wantErrs: cacheErrs,
   751  		},
   752  	}
   753  	for _, tt := range tests {
   754  		t.Run(tt.name, func(t *testing.T) {
   755  			c := NewCheckerCacheRandomRCPT(tt.fields.CheckerWithRandomRCPT(), tt.fields.cache(), DefaultRandomCacheKeyGetter).(*checkerCacheRandomRCPT)
   756  			if gotErrs := c.RandomRCPT(nil, tt.args.email); !reflect.DeepEqual(gotErrs, tt.wantErrs) {
   757  				t.Errorf("RandomRCPT() = %v, want %v", gotErrs, tt.wantErrs)
   758  			}
   759  		})
   760  	}
   761  }