github.com/angenalZZZ/gofunc@v0.0.0-20210507121333-48ff1be3917b/net/net_test.go (about)

     1  package net
     2  
     3  import (
     4  	"bufio"
     5  	"encoding/binary"
     6  	"fmt"
     7  	"io"
     8  	"log"
     9  	"math/rand"
    10  	nt "net"
    11  	"os"
    12  	"runtime"
    13  	"sync/atomic"
    14  	"testing"
    15  	"time"
    16  
    17  	"github.com/angenalZZZ/gofunc/net/pool/bytebuffer"
    18  	"github.com/angenalZZZ/gofunc/net/pool/goroutine"
    19  	"github.com/valyala/bytebufferpool"
    20  )
    21  
    22  func TestCodecServe(t *testing.T) {
    23  	// start a server
    24  	// connect 10 clients
    25  	// each client will pipe random data for 1-3 seconds.
    26  	// the writes to the server will be random sizes. 0KB - 1MB.
    27  	// the server will echo back the data.
    28  	// waits for graceful connection closing.
    29  	t.Run("poll", func(t *testing.T) {
    30  		t.Run("tcp", func(t *testing.T) {
    31  			t.Run("1-loop-LineBasedFrameCodec", func(t *testing.T) {
    32  				testCodecServe("tcp", ":9991", false, false, 10, false, new(LineBasedFrameCodec))
    33  			})
    34  			t.Run("1-loop-DelimiterBasedFrameCodec", func(t *testing.T) {
    35  				testCodecServe("tcp", ":9992", false, false, 10, false, NewDelimiterBasedFrameCodec('|'))
    36  			})
    37  			t.Run("1-loop-FixedLengthFrameCodec", func(t *testing.T) {
    38  				testCodecServe("tcp", ":9993", false, false, 10, false, NewFixedLengthFrameCodec(64))
    39  			})
    40  			t.Run("1-loop-LengthFieldBasedFrameCodec", func(t *testing.T) {
    41  				testCodecServe("tcp", ":9994", false, false, 10, false, nil)
    42  			})
    43  			t.Run("N-loop-LineBasedFrameCodec", func(t *testing.T) {
    44  				testCodecServe("tcp", ":9995", true, false, 10, false, new(LineBasedFrameCodec))
    45  			})
    46  			t.Run("N-loop-DelimiterBasedFrameCodec", func(t *testing.T) {
    47  				testCodecServe("tcp", ":9996", true, false, 10, false, NewDelimiterBasedFrameCodec('|'))
    48  			})
    49  			t.Run("N-loop-FixedLengthFrameCodec", func(t *testing.T) {
    50  				testCodecServe("tcp", ":9997", true, false, 10, false, NewFixedLengthFrameCodec(64))
    51  			})
    52  			t.Run("N-loop-LengthFieldBasedFrameCodec", func(t *testing.T) {
    53  				testCodecServe("tcp", ":9998", true, false, 10, false, nil)
    54  			})
    55  		})
    56  		t.Run("tcp-async", func(t *testing.T) {
    57  			t.Run("1-loop-LineBasedFrameCodec", func(t *testing.T) {
    58  				testCodecServe("tcp", ":9991", false, true, 10, false, new(LineBasedFrameCodec))
    59  			})
    60  			t.Run("1-loop-DelimiterBasedFrameCodec", func(t *testing.T) {
    61  				testCodecServe("tcp", ":9992", false, true, 10, false, NewDelimiterBasedFrameCodec('|'))
    62  			})
    63  			t.Run("1-loop-FixedLengthFrameCodec", func(t *testing.T) {
    64  				testCodecServe("tcp", ":9993", false, true, 10, false, NewFixedLengthFrameCodec(64))
    65  			})
    66  			t.Run("1-loop-LengthFieldBasedFrameCodec", func(t *testing.T) {
    67  				testCodecServe("tcp", ":9994", false, true, 10, false, nil)
    68  			})
    69  			t.Run("N-loop-LineBasedFrameCodec", func(t *testing.T) {
    70  				testCodecServe("tcp", ":9995", true, true, 10, false, new(LineBasedFrameCodec))
    71  			})
    72  			t.Run("N-loop-DelimiterBasedFrameCodec", func(t *testing.T) {
    73  				testCodecServe("tcp", ":9996", true, true, 10, false, NewDelimiterBasedFrameCodec('|'))
    74  			})
    75  			t.Run("N-loop-FixedLengthFrameCodec", func(t *testing.T) {
    76  				testCodecServe("tcp", ":9997", true, true, 10, false, NewFixedLengthFrameCodec(64))
    77  			})
    78  			t.Run("N-loop-LengthFieldBasedFrameCodec", func(t *testing.T) {
    79  				testCodecServe("tcp", ":9998", true, true, 10, false, nil)
    80  			})
    81  		})
    82  	})
    83  	t.Run("poll-reuseport", func(t *testing.T) {
    84  		t.Run("tcp", func(t *testing.T) {
    85  			t.Run("1-loop-LineBasedFrameCodec", func(t *testing.T) {
    86  				testCodecServe("tcp", ":9991", false, false, 10, true, new(LineBasedFrameCodec))
    87  			})
    88  			t.Run("1-loop-DelimiterBasedFrameCodec", func(t *testing.T) {
    89  				testCodecServe("tcp", ":9992", false, false, 10, true, NewDelimiterBasedFrameCodec('|'))
    90  			})
    91  			t.Run("1-loop-FixedLengthFrameCodec", func(t *testing.T) {
    92  				testCodecServe("tcp", ":9993", false, false, 10, true, NewFixedLengthFrameCodec(64))
    93  			})
    94  			t.Run("1-loop-LengthFieldBasedFrameCodec", func(t *testing.T) {
    95  				testCodecServe("tcp", ":9994", false, false, 10, true, nil)
    96  			})
    97  			t.Run("N-loop-LineBasedFrameCodec", func(t *testing.T) {
    98  				testCodecServe("tcp", ":9995", true, false, 10, true, new(LineBasedFrameCodec))
    99  			})
   100  			t.Run("N-loop-DelimiterBasedFrameCodec", func(t *testing.T) {
   101  				testCodecServe("tcp", ":9996", true, false, 10, true, NewDelimiterBasedFrameCodec('|'))
   102  			})
   103  			t.Run("N-loop-FixedLengthFrameCodec", func(t *testing.T) {
   104  				testCodecServe("tcp", ":9997", true, false, 10, true, NewFixedLengthFrameCodec(64))
   105  			})
   106  			t.Run("N-loop-LengthFieldBasedFrameCodec", func(t *testing.T) {
   107  				testCodecServe("tcp", ":9998", true, false, 10, true, nil)
   108  			})
   109  		})
   110  		t.Run("tcp-async", func(t *testing.T) {
   111  			t.Run("1-loop-LineBasedFrameCodec", func(t *testing.T) {
   112  				testCodecServe("tcp", ":9991", false, true, 10, true, new(LineBasedFrameCodec))
   113  			})
   114  			t.Run("1-loop-DelimiterBasedFrameCodec", func(t *testing.T) {
   115  				testCodecServe("tcp", ":9992", false, true, 10, true, NewDelimiterBasedFrameCodec('|'))
   116  			})
   117  			t.Run("1-loop-FixedLengthFrameCodec", func(t *testing.T) {
   118  				testCodecServe("tcp", ":9993", false, true, 10, true, NewFixedLengthFrameCodec(64))
   119  			})
   120  			t.Run("1-loop-LengthFieldBasedFrameCodec", func(t *testing.T) {
   121  				testCodecServe("tcp", ":9994", false, true, 10, true, nil)
   122  			})
   123  			t.Run("N-loop-LineBasedFrameCodec", func(t *testing.T) {
   124  				testCodecServe("tcp", ":9995", true, true, 10, true, new(LineBasedFrameCodec))
   125  			})
   126  			t.Run("N-loop-DelimiterBasedFrameCodec", func(t *testing.T) {
   127  				testCodecServe("tcp", ":9996", true, true, 10, true, NewDelimiterBasedFrameCodec('|'))
   128  			})
   129  			t.Run("N-loop-FixedLengthFrameCodec", func(t *testing.T) {
   130  				testCodecServe("tcp", ":9997", true, true, 10, true, NewFixedLengthFrameCodec(64))
   131  			})
   132  			t.Run("N-loop-LengthFieldBasedFrameCodec", func(t *testing.T) {
   133  				testCodecServe("tcp", ":9998", true, true, 10, true, nil)
   134  			})
   135  		})
   136  	})
   137  }
   138  
   139  type testCodecServer struct {
   140  	*EventServer
   141  	network      string
   142  	addr         string
   143  	multicore    bool
   144  	async        bool
   145  	nclients     int
   146  	started      int32
   147  	connected    int32
   148  	disconnected int32
   149  	codec        ICodec
   150  	workerPool   *goroutine.Pool
   151  }
   152  
   153  func (s *testCodecServer) OnOpened(c Conn) (out []byte, action Action) {
   154  	c.SetContext(c)
   155  	atomic.AddInt32(&s.connected, 1)
   156  	out = []byte("sweetness\r\n")
   157  	if c.LocalAddr() == nil {
   158  		panic("nil local addr")
   159  	}
   160  	if c.RemoteAddr() == nil {
   161  		panic("nil local addr")
   162  	}
   163  	return
   164  }
   165  func (s *testCodecServer) OnClosed(c Conn, err error) (action Action) {
   166  	if c.Context() != c {
   167  		panic("invalid context")
   168  	}
   169  
   170  	atomic.AddInt32(&s.disconnected, 1)
   171  	if atomic.LoadInt32(&s.connected) == atomic.LoadInt32(&s.disconnected) &&
   172  		atomic.LoadInt32(&s.disconnected) == int32(s.nclients) {
   173  		action = Shutdown
   174  	}
   175  
   176  	return
   177  }
   178  func (s *testCodecServer) React(frame []byte, c Conn) (out []byte, action Action) {
   179  	if s.async {
   180  		if frame != nil {
   181  			data := append([]byte{}, frame...)
   182  			_ = s.workerPool.Submit(func() {
   183  				_ = c.AsyncWrite(data)
   184  			})
   185  		}
   186  		return
   187  	}
   188  	out = frame
   189  	return
   190  }
   191  func (s *testCodecServer) Tick() (delay time.Duration, action Action) {
   192  	if atomic.LoadInt32(&s.started) == 0 {
   193  		for i := 0; i < s.nclients; i++ {
   194  			go func() {
   195  				startCodecClient(s.network, s.addr, s.multicore, s.async, s.codec)
   196  			}()
   197  		}
   198  		atomic.StoreInt32(&s.started, 1)
   199  	}
   200  	delay = time.Second / 5
   201  	return
   202  }
   203  
   204  var (
   205  	n            = 0
   206  	fieldLengths = []int{1, 2, 3, 4, 8}
   207  )
   208  
   209  func testCodecServe(network, addr string, multicore, async bool, nclients int, reuseport bool, codec ICodec) {
   210  	var err error
   211  	fieldLength := fieldLengths[n]
   212  	if codec == nil {
   213  		encoderConfig := EncoderConfig{
   214  			ByteOrder:                       binary.BigEndian,
   215  			LengthFieldLength:               fieldLength,
   216  			LengthAdjustment:                0,
   217  			LengthIncludesLengthFieldLength: false,
   218  		}
   219  		decoderConfig := DecoderConfig{
   220  			ByteOrder:           binary.BigEndian,
   221  			LengthFieldOffset:   0,
   222  			LengthFieldLength:   fieldLength,
   223  			LengthAdjustment:    0,
   224  			InitialBytesToStrip: fieldLength,
   225  		}
   226  		codec = NewLengthFieldBasedFrameCodec(encoderConfig, decoderConfig)
   227  	}
   228  	n++
   229  	if n > 4 {
   230  		n = 0
   231  	}
   232  	ts := &testCodecServer{network: network, addr: addr, multicore: multicore, async: async, nclients: nclients,
   233  		codec: codec, workerPool: goroutine.Default()}
   234  	if reuseport {
   235  		err = Serve(ts, network+"://"+addr, WithMulticore(multicore), WithTicker(true),
   236  			WithTCPKeepAlive(time.Minute*5), WithCodec(codec), WithReusePort(true))
   237  	} else {
   238  		err = Serve(ts, network+"://"+addr, WithMulticore(multicore), WithTicker(true),
   239  			WithTCPKeepAlive(time.Minute*5), WithCodec(codec))
   240  	}
   241  	if err != nil {
   242  		panic(err)
   243  	}
   244  }
   245  
   246  func startCodecClient(network, addr string, multicore, async bool, codec ICodec) {
   247  	rand.Seed(time.Now().UnixNano())
   248  	c, err := nt.Dial(network, addr)
   249  	if err != nil {
   250  		panic(err)
   251  	}
   252  	defer c.Close()
   253  	rd := bufio.NewReader(c)
   254  	msg, err := rd.ReadBytes('\n')
   255  	if err != nil {
   256  		panic(err)
   257  	}
   258  	if string(msg) != "sweetness\r\n" {
   259  		panic("bad header")
   260  	}
   261  	duration := time.Duration((rand.Float64()*2+1)*float64(time.Second)) / 8
   262  	start := time.Now()
   263  	for time.Since(start) < duration {
   264  		//data := []byte("Hello, World")
   265  		data := make([]byte, 1024)
   266  		rand.Read(data)
   267  		encodedData, _ := codec.Encode(nil, data)
   268  		if _, err := c.Write(encodedData); err != nil {
   269  			panic(err)
   270  		}
   271  		data2 := make([]byte, len(encodedData))
   272  		if _, err := io.ReadFull(rd, data2); err != nil {
   273  			panic(err)
   274  		}
   275  		if string(encodedData) != string(data2) && !async {
   276  			//panic(fmt.Sprintf("mismatch %s/multi-core:%t: %d vs %d bytes, %s:%s", network, multicore,
   277  			//	len(encodedData), len(data2), string(encodedData), string(data2)))
   278  			panic(fmt.Sprintf("mismatch %s/multi-core:%t: %d vs %d bytes", network, multicore, len(encodedData), len(data2)))
   279  		}
   280  	}
   281  }
   282  
   283  func TestServe(t *testing.T) {
   284  	// start a server
   285  	// connect 10 clients
   286  	// each client will pipe random data for 1-3 seconds.
   287  	// the writes to the server will be random sizes. 0KB - 1MB.
   288  	// the server will echo back the data.
   289  	// waits for graceful connection closing.
   290  	t.Run("poll", func(t *testing.T) {
   291  		t.Run("tcp", func(t *testing.T) {
   292  			t.Run("1-loop", func(t *testing.T) {
   293  				testServe("tcp", ":9991", false, false, false, 10, RoundRobin)
   294  			})
   295  			t.Run("N-loop", func(t *testing.T) {
   296  				testServe("tcp", ":9992", false, true, false, 10, LeastConnections)
   297  			})
   298  		})
   299  		t.Run("tcp-async", func(t *testing.T) {
   300  			t.Run("1-loop", func(t *testing.T) {
   301  				testServe("tcp", ":9991", false, false, true, 10, RoundRobin)
   302  			})
   303  			t.Run("N-loop", func(t *testing.T) {
   304  				testServe("tcp", ":9992", false, true, true, 10, LeastConnections)
   305  			})
   306  		})
   307  		t.Run("udp", func(t *testing.T) {
   308  			t.Run("1-loop", func(t *testing.T) {
   309  				testServe("udp", ":9991", false, false, false, 10, RoundRobin)
   310  			})
   311  			t.Run("N-loop", func(t *testing.T) {
   312  				testServe("udp", ":9992", false, true, false, 10, LeastConnections)
   313  			})
   314  		})
   315  		t.Run("udp-async", func(t *testing.T) {
   316  			t.Run("1-loop", func(t *testing.T) {
   317  				testServe("udp", ":9991", false, false, true, 10, RoundRobin)
   318  			})
   319  			t.Run("N-loop", func(t *testing.T) {
   320  				testServe("udp", ":9992", false, true, true, 10, LeastConnections)
   321  			})
   322  		})
   323  		t.Run("unix", func(t *testing.T) {
   324  			t.Run("1-loop", func(t *testing.T) {
   325  				testServe("unix", "gnet1.sock", false, false, false, 10, RoundRobin)
   326  			})
   327  			t.Run("N-loop", func(t *testing.T) {
   328  				testServe("unix", "gnet2.sock", false, true, false, 10, SourceAddrHash)
   329  			})
   330  		})
   331  		t.Run("unix-async", func(t *testing.T) {
   332  			t.Run("1-loop", func(t *testing.T) {
   333  				testServe("unix", "gnet1.sock", false, false, true, 10, RoundRobin)
   334  			})
   335  			t.Run("N-loop", func(t *testing.T) {
   336  				testServe("unix", "gnet2.sock", false, true, true, 10, SourceAddrHash)
   337  			})
   338  		})
   339  	})
   340  
   341  	t.Run("poll-reuseport", func(t *testing.T) {
   342  		t.Run("tcp", func(t *testing.T) {
   343  			t.Run("1-loop", func(t *testing.T) {
   344  				testServe("tcp", ":9991", true, false, false, 10, RoundRobin)
   345  			})
   346  			t.Run("N-loop", func(t *testing.T) {
   347  				testServe("tcp", ":9992", true, true, false, 10, LeastConnections)
   348  			})
   349  		})
   350  		t.Run("tcp-async", func(t *testing.T) {
   351  			t.Run("1-loop", func(t *testing.T) {
   352  				testServe("tcp", ":9991", true, false, true, 10, RoundRobin)
   353  			})
   354  			t.Run("N-loop", func(t *testing.T) {
   355  				testServe("tcp", ":9992", true, true, false, 10, LeastConnections)
   356  			})
   357  		})
   358  		t.Run("udp", func(t *testing.T) {
   359  			t.Run("1-loop", func(t *testing.T) {
   360  				testServe("udp", ":9991", true, false, false, 10, RoundRobin)
   361  			})
   362  			t.Run("N-loop", func(t *testing.T) {
   363  				testServe("udp", ":9992", true, true, false, 10, LeastConnections)
   364  			})
   365  		})
   366  		t.Run("udp-async", func(t *testing.T) {
   367  			t.Run("1-loop", func(t *testing.T) {
   368  				testServe("udp", ":9991", true, false, false, 10, RoundRobin)
   369  			})
   370  			t.Run("N-loop", func(t *testing.T) {
   371  				testServe("udp", ":9992", true, true, true, 10, LeastConnections)
   372  			})
   373  		})
   374  		t.Run("unix", func(t *testing.T) {
   375  			t.Run("1-loop", func(t *testing.T) {
   376  				testServe("unix", "gnet1.sock", true, false, false, 10, RoundRobin)
   377  			})
   378  			t.Run("N-loop", func(t *testing.T) {
   379  				testServe("unix", "gnet2.sock", true, true, false, 10, LeastConnections)
   380  			})
   381  		})
   382  		t.Run("unix-async", func(t *testing.T) {
   383  			t.Run("1-loop", func(t *testing.T) {
   384  				testServe("unix", "gnet1.sock", true, false, true, 10, RoundRobin)
   385  			})
   386  			t.Run("N-loop", func(t *testing.T) {
   387  				testServe("unix", "gnet2.sock", true, true, true, 10, LeastConnections)
   388  			})
   389  		})
   390  	})
   391  }
   392  
   393  type testServer struct {
   394  	*EventServer
   395  	svr          Server
   396  	network      string
   397  	addr         string
   398  	multicore    bool
   399  	async        bool
   400  	nclients     int
   401  	started      int32
   402  	connected    int32
   403  	clientActive int32
   404  	disconnected int32
   405  	workerPool   *goroutine.Pool
   406  	bytesList    []*bytebufferpool.ByteBuffer
   407  }
   408  
   409  func (s *testServer) OnInitComplete(svr Server) (action Action) {
   410  	s.svr = svr
   411  	return
   412  }
   413  
   414  func (s *testServer) OnOpened(c Conn) (out []byte, action Action) {
   415  	c.SetContext(c)
   416  	atomic.AddInt32(&s.connected, 1)
   417  	out = []byte("sweetness\r\n")
   418  	if c.LocalAddr() == nil {
   419  		panic("nil local addr")
   420  	}
   421  	if c.RemoteAddr() == nil {
   422  		panic("nil local addr")
   423  	}
   424  	return
   425  }
   426  func (s *testServer) OnClosed(c Conn, err error) (action Action) {
   427  	if err != nil {
   428  		fmt.Printf("error occurred on closed, %v\n", err)
   429  	}
   430  	if c.Context() != c {
   431  		panic("invalid context")
   432  	}
   433  
   434  	atomic.AddInt32(&s.disconnected, 1)
   435  	if atomic.LoadInt32(&s.connected) == atomic.LoadInt32(&s.disconnected) &&
   436  		atomic.LoadInt32(&s.disconnected) == int32(s.nclients) {
   437  		action = Shutdown
   438  		for i := range s.bytesList {
   439  			bytebuffer.Put(s.bytesList[i])
   440  		}
   441  		s.workerPool.Release()
   442  	}
   443  
   444  	return
   445  }
   446  func (s *testServer) React(frame []byte, c Conn) (out []byte, action Action) {
   447  	if s.async {
   448  		if s.network == "tcp" || s.network == "unix" {
   449  			_ = c.BufferLength()
   450  			buf := bytebuffer.Get()
   451  			_, _ = buf.Write(frame)
   452  			s.bytesList = append(s.bytesList, buf)
   453  			// just for test
   454  			c.ShiftN(1)
   455  			_ = s.workerPool.Submit(
   456  				func() {
   457  					_ = c.AsyncWrite(buf.Bytes())
   458  				})
   459  			return
   460  		}
   461  		if s.network == "udp" {
   462  			_ = s.workerPool.Submit(
   463  				func() {
   464  					_ = c.SendTo(frame)
   465  				})
   466  			return
   467  		}
   468  		return
   469  	}
   470  	out = frame
   471  	return
   472  }
   473  func (s *testServer) Tick() (delay time.Duration, action Action) {
   474  	if atomic.LoadInt32(&s.started) == 0 {
   475  		for i := 0; i < s.nclients; i++ {
   476  			atomic.AddInt32(&s.clientActive, 1)
   477  			go func() {
   478  				startClient(s.network, s.addr, s.multicore, s.async)
   479  				atomic.AddInt32(&s.clientActive, -1)
   480  			}()
   481  		}
   482  		atomic.StoreInt32(&s.started, 1)
   483  	}
   484  	fmt.Printf("active connections: %d\n", s.svr.CountConnections())
   485  	if s.network == "udp" && atomic.LoadInt32(&s.clientActive) == 0 {
   486  		action = Shutdown
   487  		return
   488  	}
   489  	delay = time.Second / 5
   490  	return
   491  }
   492  
   493  func testServe(network, addr string, reuseport, multicore, async bool, nclients int, lb LoadBalancing) {
   494  	ts := &testServer{
   495  		network:    network,
   496  		addr:       addr,
   497  		multicore:  multicore,
   498  		async:      async,
   499  		nclients:   nclients,
   500  		workerPool: goroutine.Default()}
   501  	must(Serve(ts, network+"://"+addr, WithMulticore(multicore), WithReusePort(reuseport), WithTicker(true),
   502  		WithTCPKeepAlive(time.Minute*1), WithLoadBalancing(lb)))
   503  }
   504  
   505  func startClient(network, addr string, multicore, async bool) {
   506  	rand.Seed(time.Now().UnixNano())
   507  	c, err := nt.Dial(network, addr)
   508  	if err != nil {
   509  		panic(err)
   510  	}
   511  	defer c.Close()
   512  	rd := bufio.NewReader(c)
   513  	if network != "udp" {
   514  		msg, err := rd.ReadBytes('\n')
   515  		if err != nil {
   516  			panic(err)
   517  		}
   518  		if string(msg) != "sweetness\r\n" {
   519  			panic("bad header")
   520  		}
   521  	}
   522  	duration := time.Duration((rand.Float64()*2+1)*float64(time.Second)) / 8
   523  	start := time.Now()
   524  	for time.Since(start) < duration {
   525  		//sz := rand.Intn(10) * (1024 * 1024)
   526  		sz := 1024 * 1024
   527  		data := make([]byte, sz)
   528  		if network == "udp" || network == "unix" {
   529  			n := 1024
   530  			data = data[:n]
   531  		}
   532  		if _, err := rand.Read(data); err != nil {
   533  			panic(err)
   534  		}
   535  		if _, err := c.Write(data); err != nil {
   536  			panic(err)
   537  		}
   538  		data2 := make([]byte, len(data))
   539  		if _, err := io.ReadFull(rd, data2); err != nil {
   540  			panic(err)
   541  		}
   542  		if string(data) != string(data2) && !async {
   543  			panic(fmt.Sprintf("mismatch %s/multi-core:%t: %d vs %d bytes\n", network, multicore, len(data), len(data2)))
   544  		}
   545  	}
   546  }
   547  
   548  func must(err error) {
   549  	if err != nil && err != ErrUnsupportedProtocol {
   550  		panic(err)
   551  	}
   552  }
   553  
   554  func TestDefaultGnetServer(t *testing.T) {
   555  	svr := EventServer{}
   556  	svr.OnInitComplete(Server{})
   557  	svr.OnOpened(nil)
   558  	svr.OnClosed(nil, nil)
   559  	svr.PreWrite()
   560  	svr.React(nil, nil)
   561  	svr.Tick()
   562  }
   563  
   564  func TestTick(t *testing.T) {
   565  	testTick("tcp4", ":9991", t)
   566  }
   567  
   568  type testTickServer struct {
   569  	*EventServer
   570  	count int
   571  }
   572  
   573  func (t *testTickServer) Tick() (delay time.Duration, action Action) {
   574  	if t.count == 25 {
   575  		action = Shutdown
   576  		return
   577  	}
   578  	t.count++
   579  	delay = time.Millisecond * 10
   580  	return
   581  }
   582  
   583  func testTick(network, addr string, t *testing.T) {
   584  	events := &testTickServer{}
   585  	start := time.Now()
   586  	opts := Options{Ticker: true}
   587  	must(Serve(events, network+"://"+addr, WithOptions(opts)))
   588  	dur := time.Since(start)
   589  	if dur < 250&time.Millisecond || dur > time.Second {
   590  		t.Logf("bad ticker timing: %d", dur)
   591  	}
   592  }
   593  
   594  func TestWakeConn(t *testing.T) {
   595  	testWakeConn("tcp", ":9000")
   596  }
   597  
   598  type testWakeConnServer struct {
   599  	*EventServer
   600  	network string
   601  	addr    string
   602  	conn    Conn
   603  	wake    bool
   604  }
   605  
   606  func (t *testWakeConnServer) OnOpened(c Conn) (out []byte, action Action) {
   607  	t.conn = c
   608  	return
   609  }
   610  func (t *testWakeConnServer) OnClosed(c Conn, err error) (action Action) {
   611  	action = Shutdown
   612  	return
   613  }
   614  func (t *testWakeConnServer) React(frame []byte, c Conn) (out []byte, action Action) {
   615  	out = []byte("Waking up.")
   616  	action = -1
   617  	return
   618  }
   619  func (t *testWakeConnServer) Tick() (delay time.Duration, action Action) {
   620  	if !t.wake {
   621  		t.wake = true
   622  		delay = time.Millisecond * 100
   623  		go func() {
   624  			conn, err := nt.Dial(t.network, t.addr)
   625  			must(err)
   626  			defer conn.Close()
   627  			r := make([]byte, 10)
   628  			_, err = conn.Read(r)
   629  			if err != nil {
   630  				panic(err)
   631  			}
   632  			fmt.Println(string(r))
   633  		}()
   634  		return
   635  	}
   636  	_ = t.conn.Wake()
   637  	delay = time.Millisecond * 100
   638  	return
   639  }
   640  
   641  func testWakeConn(network, addr string) {
   642  	svr := &testWakeConnServer{network: network, addr: addr}
   643  	must(Serve(svr, network+"://"+addr, WithTicker(true), WithNumEventLoop(2*runtime.NumCPU()),
   644  		WithLogger(log.New(os.Stderr, "", log.LstdFlags))))
   645  }
   646  
   647  func TestShutdown(t *testing.T) {
   648  	testShutdown("tcp", ":9991")
   649  }
   650  
   651  type testShutdownServer struct {
   652  	*EventServer
   653  	network string
   654  	addr    string
   655  	count   int
   656  	clients int64
   657  	N       int
   658  }
   659  
   660  func (t *testShutdownServer) OnOpened(c Conn) (out []byte, action Action) {
   661  	atomic.AddInt64(&t.clients, 1)
   662  	return
   663  }
   664  func (t *testShutdownServer) OnClosed(c Conn, err error) (action Action) {
   665  	atomic.AddInt64(&t.clients, -1)
   666  	return
   667  }
   668  func (t *testShutdownServer) Tick() (delay time.Duration, action Action) {
   669  	if t.count == 0 {
   670  		// start clients
   671  		for i := 0; i < t.N; i++ {
   672  			go func() {
   673  				conn, err := nt.Dial(t.network, t.addr)
   674  				must(err)
   675  				defer conn.Close()
   676  				_, err = conn.Read([]byte{0})
   677  				if err == nil {
   678  					panic("expected error")
   679  				}
   680  			}()
   681  		}
   682  	} else {
   683  		if int(atomic.LoadInt64(&t.clients)) == t.N {
   684  			action = Shutdown
   685  		}
   686  	}
   687  	t.count++
   688  	delay = time.Second / 20
   689  	return
   690  }
   691  
   692  func testShutdown(network, addr string) {
   693  	events := &testShutdownServer{network: network, addr: addr, N: 10}
   694  	must(Serve(events, network+"://"+addr, WithTicker(true)))
   695  	if events.clients != 0 {
   696  		panic("did not call close on all clients")
   697  	}
   698  }
   699  
   700  type testBadAddrServer struct {
   701  	*EventServer
   702  }
   703  
   704  func (t *testBadAddrServer) OnInitComplete(srv Server) (action Action) {
   705  	return Shutdown
   706  }
   707  
   708  func TestBadAddresses(t *testing.T) {
   709  	events := new(testBadAddrServer)
   710  	if err := Serve(events, "tulip://howdy"); err == nil {
   711  		t.Fatalf("expected error")
   712  	}
   713  	if err := Serve(events, "howdy"); err == nil {
   714  		t.Fatalf("expected error")
   715  	}
   716  	if err := Serve(events, "tcp://"); err != nil {
   717  		t.Fatalf("expected nil, got '%v'", err)
   718  	}
   719  }
   720  
   721  func TestCloseActionError(t *testing.T) {
   722  	testCloseActionError("tcp", ":9991")
   723  }
   724  
   725  type testCloseActionErrorServer struct {
   726  	*EventServer
   727  	network, addr string
   728  	action        bool
   729  }
   730  
   731  func (t *testCloseActionErrorServer) OnClosed(c Conn, err error) (action Action) {
   732  	action = Shutdown
   733  	return
   734  }
   735  func (t *testCloseActionErrorServer) React(frame []byte, c Conn) (out []byte, action Action) {
   736  	out = frame
   737  	action = Close
   738  	return
   739  }
   740  func (t *testCloseActionErrorServer) Tick() (delay time.Duration, action Action) {
   741  	if !t.action {
   742  		t.action = true
   743  		delay = time.Millisecond * 100
   744  		go func() {
   745  			conn, err := nt.Dial(t.network, t.addr)
   746  			must(err)
   747  			defer conn.Close()
   748  			data := []byte("Hello World!")
   749  			_, _ = conn.Write(data)
   750  			_, err = conn.Read(data)
   751  			if err != nil {
   752  				panic(err)
   753  			}
   754  			fmt.Println(string(data))
   755  		}()
   756  		return
   757  	}
   758  	delay = time.Millisecond * 100
   759  	return
   760  }
   761  
   762  func testCloseActionError(network, addr string) {
   763  	events := &testCloseActionErrorServer{network: network, addr: addr}
   764  	must(Serve(events, network+"://"+addr, WithTicker(true)))
   765  }
   766  
   767  func TestShutdownActionError(t *testing.T) {
   768  	testShutdownActionError("tcp", ":9991")
   769  }
   770  
   771  type testShutdownActionErrorServer struct {
   772  	*EventServer
   773  	network, addr string
   774  	action        bool
   775  }
   776  
   777  func (t *testShutdownActionErrorServer) React(frame []byte, c Conn) (out []byte, action Action) {
   778  	c.ReadN(-1) // just for test
   779  	out = frame
   780  	action = Shutdown
   781  	return
   782  }
   783  func (t *testShutdownActionErrorServer) Tick() (delay time.Duration, action Action) {
   784  	if !t.action {
   785  		t.action = true
   786  		delay = time.Millisecond * 100
   787  		go func() {
   788  			conn, err := nt.Dial(t.network, t.addr)
   789  			must(err)
   790  			defer conn.Close()
   791  			data := []byte("Hello World!")
   792  			_, _ = conn.Write(data)
   793  			_, err = conn.Read(data)
   794  			if err != nil {
   795  				panic(err)
   796  			}
   797  			fmt.Println(string(data))
   798  		}()
   799  		return
   800  	}
   801  	delay = time.Millisecond * 100
   802  	return
   803  }
   804  
   805  func testShutdownActionError(network, addr string) {
   806  	events := &testShutdownActionErrorServer{network: network, addr: addr}
   807  	must(Serve(events, network+"://"+addr, WithTicker(true)))
   808  }
   809  
   810  func TestCloseActionOnOpen(t *testing.T) {
   811  	testCloseActionOnOpen("tcp", ":9991")
   812  }
   813  
   814  type testCloseActionOnOpenServer struct {
   815  	*EventServer
   816  	network, addr string
   817  	action        bool
   818  }
   819  
   820  func (t *testCloseActionOnOpenServer) OnOpened(c Conn) (out []byte, action Action) {
   821  	action = Close
   822  	return
   823  }
   824  func (t *testCloseActionOnOpenServer) OnClosed(c Conn, err error) (action Action) {
   825  	action = Shutdown
   826  	return
   827  }
   828  func (t *testCloseActionOnOpenServer) Tick() (delay time.Duration, action Action) {
   829  	if !t.action {
   830  		t.action = true
   831  		delay = time.Millisecond * 100
   832  		go func() {
   833  			conn, err := nt.Dial(t.network, t.addr)
   834  			must(err)
   835  			defer conn.Close()
   836  		}()
   837  		return
   838  	}
   839  	delay = time.Millisecond * 100
   840  	return
   841  }
   842  
   843  func testCloseActionOnOpen(network, addr string) {
   844  	events := &testCloseActionOnOpenServer{network: network, addr: addr}
   845  	must(Serve(events, network+"://"+addr, WithTicker(true)))
   846  }
   847  
   848  func TestShutdownActionOnOpen(t *testing.T) {
   849  	testShutdownActionOnOpen("tcp", ":9991")
   850  }
   851  
   852  type testShutdownActionOnOpenServer struct {
   853  	*EventServer
   854  	network, addr string
   855  	action        bool
   856  }
   857  
   858  func (t *testShutdownActionOnOpenServer) OnOpened(c Conn) (out []byte, action Action) {
   859  	action = Shutdown
   860  	return
   861  }
   862  func (t *testShutdownActionOnOpenServer) Tick() (delay time.Duration, action Action) {
   863  	if !t.action {
   864  		t.action = true
   865  		delay = time.Millisecond * 100
   866  		go func() {
   867  			conn, err := nt.Dial(t.network, t.addr)
   868  			must(err)
   869  			defer conn.Close()
   870  		}()
   871  		return
   872  	}
   873  	delay = time.Millisecond * 100
   874  	return
   875  }
   876  
   877  func testShutdownActionOnOpen(network, addr string) {
   878  	events := &testShutdownActionOnOpenServer{network: network, addr: addr}
   879  	must(Serve(events, network+"://"+addr, WithTicker(true)))
   880  }
   881  
   882  func TestUDPShutdown(t *testing.T) {
   883  	testUDPShutdown("udp4", ":9000")
   884  }
   885  
   886  type testUDPShutdownServer struct {
   887  	*EventServer
   888  	network string
   889  	addr    string
   890  	tick    bool
   891  }
   892  
   893  func (t *testUDPShutdownServer) React(frame []byte, c Conn) (out []byte, action Action) {
   894  	out = frame
   895  	action = Shutdown
   896  	return
   897  }
   898  func (t *testUDPShutdownServer) Tick() (delay time.Duration, action Action) {
   899  	if !t.tick {
   900  		t.tick = true
   901  		delay = time.Millisecond * 100
   902  		go func() {
   903  			conn, err := nt.Dial(t.network, t.addr)
   904  			must(err)
   905  			defer conn.Close()
   906  			data := []byte("Hello World!")
   907  			if _, err = conn.Write(data); err != nil {
   908  				panic(err)
   909  			}
   910  			if _, err = conn.Read(data); err != nil {
   911  				panic(err)
   912  			}
   913  			fmt.Println(string(data))
   914  		}()
   915  		return
   916  	}
   917  	delay = time.Millisecond * 100
   918  	return
   919  }
   920  
   921  func testUDPShutdown(network, addr string) {
   922  	svr := &testUDPShutdownServer{network: network, addr: addr}
   923  	must(Serve(svr, network+"://"+addr, WithTicker(true)))
   924  }
   925  
   926  func TestCloseConnection(t *testing.T) {
   927  	testCloseConnection("tcp", ":9991")
   928  }
   929  
   930  type testCloseConnectionServer struct {
   931  	*EventServer
   932  	network, addr string
   933  	action        bool
   934  }
   935  
   936  func (t *testCloseConnectionServer) OnClosed(c Conn, err error) (action Action) {
   937  	action = Shutdown
   938  	return
   939  }
   940  func (t *testCloseConnectionServer) React(frame []byte, c Conn) (out []byte, action Action) {
   941  	out = frame
   942  	go func() {
   943  		time.Sleep(time.Second)
   944  		_ = c.Close()
   945  	}()
   946  	return
   947  }
   948  func (t *testCloseConnectionServer) Tick() (delay time.Duration, action Action) {
   949  	if !t.action {
   950  		t.action = true
   951  		delay = time.Millisecond * 100
   952  		go func() {
   953  			conn, err := nt.Dial(t.network, t.addr)
   954  			must(err)
   955  			defer conn.Close()
   956  			data := []byte("Hello World!")
   957  			_, _ = conn.Write(data)
   958  			_, err = conn.Read(data)
   959  			if err != nil {
   960  				panic(err)
   961  			}
   962  			fmt.Println(string(data))
   963  			// waiting the server shutdown.
   964  			_, err = conn.Read(data)
   965  			if err == nil {
   966  				panic(err)
   967  			}
   968  		}()
   969  		return
   970  	}
   971  	delay = time.Millisecond * 100
   972  	return
   973  }
   974  
   975  func testCloseConnection(network, addr string) {
   976  	events := &testCloseConnectionServer{network: network, addr: addr}
   977  	must(Serve(events, network+"://"+addr, WithTicker(true)))
   978  }