github.com/cmd-stream/base-go@v0.0.0-20230813145615-dd6ac24c16f5/server/conn_receiver_test.go (about)

     1  package server
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"net"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/cmd-stream/base-go/testdata/mock"
    11  	"github.com/ymz-ncnk/mok"
    12  )
    13  
    14  func TestConnReceiver(t *testing.T) {
    15  
    16  	t.Run("Conf.FirstConnTimeout should be applied only to the first conn + if Listener.SetDeadline failed with an error, Run should return it",
    17  		func(t *testing.T) {
    18  			var (
    19  				wantErr   = errors.New("SetDeadline error")
    20  				startTime = time.Now()
    21  				conf      = ConnReceiverConf{FirstConnTimeout: time.Second}
    22  				listener  = mock.NewListener().RegisterSetDeadline(
    23  					func(deadline time.Time) (err error) {
    24  						wantDeadline := startTime.Add(conf.FirstConnTimeout)
    25  						if !SameTime(deadline, wantDeadline) {
    26  							return fmt.Errorf("unexpected deadline, want '%v' actual '%v'",
    27  								wantDeadline,
    28  								deadline)
    29  						}
    30  						return wantErr
    31  					},
    32  				)
    33  				mocks    = []*mok.Mock{listener.Mock}
    34  				receiver = NewConnReceiver(conf, listener, make(chan net.Conn))
    35  			)
    36  			testConnReceiver(receiver, wantErr, mocks, t)
    37  		})
    38  
    39  	t.Run("If accepting of the first conn failed with an error, Run should return it",
    40  		func(t *testing.T) {
    41  			var (
    42  				wantErr  = errors.New("accept error")
    43  				listener = mock.NewListener().RegisterAccept(
    44  					func() (net.Conn, error) { return nil, wantErr },
    45  				)
    46  				conns    = make(chan net.Conn)
    47  				mocks    = []*mok.Mock{listener.Mock}
    48  				receiver = NewConnReceiver(ConnReceiverConf{}, listener, conns)
    49  			)
    50  			testConnReceiver(receiver, wantErr, mocks, t)
    51  		})
    52  
    53  	t.Run("Conf.FirstConnTimeout should be applied to only first conn + if cancelation of the first conn deadline failed with an error, Run should return it",
    54  		func(t *testing.T) {
    55  			var (
    56  				wantErr  = errors.New("set deadline error")
    57  				wantConn = mock.NewConn().RegisterClose(
    58  					func() (err error) { return nil },
    59  				)
    60  				startTime = time.Now()
    61  				conf      = ConnReceiverConf{FirstConnTimeout: time.Second}
    62  				listener  = mock.NewListener().RegisterSetDeadline(
    63  					func(deadline time.Time) (err error) {
    64  						wantDeadline := startTime.Add(conf.FirstConnTimeout)
    65  						if !SameTime(deadline, wantDeadline) {
    66  							return fmt.Errorf("unexpected deadline, want '%v' actual '%v'",
    67  								wantDeadline,
    68  								deadline)
    69  						}
    70  						return
    71  					},
    72  				).RegisterAccept(
    73  					func() (conn net.Conn, err error) {
    74  						return wantConn, nil
    75  					},
    76  				).RegisterSetDeadline(
    77  					func(deadline time.Time) (err error) {
    78  						if !deadline.IsZero() {
    79  							return fmt.Errorf("unexpected deadline, want '%v' actual '%v'",
    80  								time.Time{},
    81  								deadline)
    82  						}
    83  						return wantErr
    84  					},
    85  				)
    86  				mocks    = []*mok.Mock{wantConn.Mock, listener.Mock}
    87  				receiver = NewConnReceiver(conf, listener, make(chan net.Conn, 1))
    88  			)
    89  			testConnReceiver(receiver, wantErr, mocks, t)
    90  		})
    91  
    92  	t.Run("If Listener.Accept for the first conn failed with an error, Run should return it",
    93  		func(t *testing.T) {
    94  			var (
    95  				wantErr = errors.New("set deadline error")
    96  
    97  				listener = mock.NewListener().RegisterAccept(
    98  					func() (conn net.Conn, err error) {
    99  						return nil, wantErr
   100  					},
   101  				)
   102  				mocks    = []*mok.Mock{listener.Mock}
   103  				receiver = NewConnReceiver(ConnReceiverConf{}, listener, make(chan net.Conn, 1))
   104  			)
   105  			testConnReceiver(receiver, wantErr, mocks, t)
   106  		})
   107  
   108  	t.Run("If Listener.Accept for the second conn failed with an error, Run should return it",
   109  		func(t *testing.T) {
   110  			var (
   111  				wantErr  = errors.New("set deadline error")
   112  				wantConn = mock.NewConn().RegisterClose(
   113  					func() (err error) { return nil },
   114  				)
   115  				listener = mock.NewListener().RegisterAccept(
   116  					func() (conn net.Conn, err error) {
   117  						return wantConn, nil
   118  					},
   119  				).RegisterAccept(
   120  					func() (conn net.Conn, err error) {
   121  						return nil, wantErr
   122  					},
   123  				)
   124  				mocks    = []*mok.Mock{wantConn.Mock, listener.Mock}
   125  				receiver = NewConnReceiver(ConnReceiverConf{}, listener, make(chan net.Conn, 1))
   126  			)
   127  			testConnReceiver(receiver, wantErr, mocks, t)
   128  		})
   129  
   130  	t.Run("ConnReceiver should be able to accept several connections",
   131  		func(t *testing.T) {
   132  			var (
   133  				// wantErr  = errors.New("done")
   134  				done     = make(chan struct{})
   135  				conn1    = mock.NewConn()
   136  				conn2    = mock.NewConn()
   137  				listener = mock.NewListener().RegisterAccept(
   138  					func() (net.Conn, error) { return conn1, nil },
   139  				).RegisterAccept(
   140  					func() (net.Conn, error) { return conn2, nil },
   141  				).RegisterAccept(
   142  					func() (net.Conn, error) {
   143  						<-done
   144  						return nil, errors.New("done")
   145  					},
   146  				).RegisterClose(
   147  					func() error { close(done); return nil },
   148  				)
   149  				conns    = make(chan net.Conn, 2)
   150  				mocks    = []*mok.Mock{conn1.Mock, conn2.Mock, listener.Mock}
   151  				receiver = NewConnReceiver(ConnReceiverConf{}, listener, conns)
   152  			)
   153  			go func() {
   154  				i := 0
   155  				for {
   156  					select {
   157  					case <-conns:
   158  						i++
   159  						if i == 2 {
   160  							goto Stop
   161  						}
   162  					case <-time.NewTimer(200 * time.Millisecond).C:
   163  						panic("test lasts too long")
   164  					}
   165  				}
   166  			Stop:
   167  				if err := receiver.Stop(); err != nil {
   168  					t.Error(err)
   169  				}
   170  			}()
   171  			testConnReceiver(receiver, ErrClosed, mocks, t)
   172  		})
   173  
   174  	t.Run("We should be able to close the ConnHandler while Listener.Accept",
   175  		func(t *testing.T) {
   176  			testStopWhileAccept(false, t)
   177  		})
   178  
   179  	t.Run("We should be able to shutdown the ConnHandler while Listener.Accept",
   180  		func(t *testing.T) {
   181  			testStopWhileAccept(true, t)
   182  		})
   183  
   184  	t.Run("We should be able to close the ConnHandler while it adds conn to queue",
   185  		func(t *testing.T) {
   186  			testStopWhileQueueConn(false, t)
   187  		})
   188  
   189  	t.Run("We should be able to shutdown the ConnHandler while it adds conn to queue",
   190  		func(t *testing.T) {
   191  			testStopWhileQueueConn(true, t)
   192  		})
   193  
   194  }
   195  
   196  func RunConnReceiver(r *ConnReceiver) (errs chan error) {
   197  	errs = make(chan error, 1)
   198  	go func() {
   199  		if err := r.Run(); err != nil {
   200  			errs <- err
   201  		}
   202  		close(errs)
   203  	}()
   204  	return
   205  }
   206  
   207  func testConnReceiver(r *ConnReceiver, wantErr error, mocks []*mok.Mock,
   208  	t *testing.T) {
   209  	errs := RunConnReceiver(r)
   210  	testAsyncErr(wantErr, errs, mocks, t)
   211  }
   212  
   213  func testStopWhileAccept(shutdown bool, t *testing.T) {
   214  	// wantErr := errors.New("accept failed, cause close")
   215  	wantErr := ErrClosed
   216  	if shutdown {
   217  		wantErr = nil
   218  	}
   219  	var (
   220  		listener = func() mock.Listener {
   221  			done := make(chan error)
   222  			return mock.NewListener().RegisterAccept(
   223  				func() (net.Conn, error) {
   224  					<-done
   225  					if shutdown {
   226  						return nil, errors.New("accept failed, cause shutdown")
   227  					}
   228  					return nil, wantErr
   229  				},
   230  			).RegisterClose(
   231  				func() error { close(done); return nil },
   232  			)
   233  		}()
   234  		conns = make(chan net.Conn)
   235  		mocks = []*mok.Mock{listener.Mock}
   236  	)
   237  	receiver := NewConnReceiver(ConnReceiverConf{}, listener, conns)
   238  	go func() {
   239  		time.Sleep(100 * time.Millisecond)
   240  		if shutdown {
   241  			receiver.Shutdown()
   242  		} else {
   243  			receiver.Stop()
   244  		}
   245  	}()
   246  	testConnReceiver(receiver, wantErr, mocks, t)
   247  	_, more := <-conns
   248  	if more {
   249  		t.Error("conns chan is not closed")
   250  	}
   251  }
   252  
   253  func testStopWhileQueueConn(shutdown bool, t *testing.T) {
   254  	wantErr := ErrClosed
   255  	if shutdown {
   256  		wantErr = nil
   257  	}
   258  	var (
   259  		done = make(chan error)
   260  		conn = func() mock.Conn {
   261  			conn := mock.NewConn().RegisterClose(
   262  				func() (err error) { return nil },
   263  			)
   264  			return conn
   265  		}()
   266  		listener = mock.NewListener().RegisterAccept(
   267  			func() (net.Conn, error) {
   268  				return conn, nil
   269  			},
   270  		).RegisterClose(
   271  			func() error { close(done); return nil },
   272  		)
   273  		conns    = make(chan net.Conn)
   274  		mocks    = []*mok.Mock{conn.Mock, listener.Mock}
   275  		receiver = NewConnReceiver(ConnReceiverConf{}, listener, conns)
   276  	)
   277  	go func() {
   278  		time.Sleep(100 * time.Millisecond)
   279  		if shutdown {
   280  			receiver.Shutdown()
   281  		} else {
   282  			receiver.Stop()
   283  		}
   284  	}()
   285  	testConnReceiver(receiver, wantErr, mocks, t)
   286  	_, more := <-conns
   287  	if more {
   288  		t.Error("conns chan is not closed")
   289  	}
   290  }