github.com/DerekStrickland/consul@v1.4.5/connect/proxy/testing.go (about)

     1  package proxy
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"log"
     7  	"net"
     8  	"sync/atomic"
     9  	"time"
    10  
    11  	"github.com/hashicorp/consul/connect"
    12  	"github.com/hashicorp/consul/lib/freeport"
    13  	"github.com/mitchellh/go-testing-interface"
    14  	"github.com/stretchr/testify/require"
    15  )
    16  
    17  // TestLocalAddr makes a localhost address on the given port
    18  func TestLocalAddr(port int) string {
    19  	return fmt.Sprintf("localhost:%d", port)
    20  }
    21  
    22  // TestTCPServer is a simple TCP echo server for use during tests.
    23  type TestTCPServer struct {
    24  	l                        net.Listener
    25  	stopped                  int32
    26  	accepted, closed, active int32
    27  }
    28  
    29  // NewTestTCPServer opens as a listening socket on the given address and returns
    30  // a TestTCPServer serving requests to it. The server is already started and can
    31  // be stopped by calling Close().
    32  func NewTestTCPServer(t testing.T) *TestTCPServer {
    33  	port := freeport.GetT(t, 1)
    34  	addr := TestLocalAddr(port[0])
    35  
    36  	l, err := net.Listen("tcp", addr)
    37  	require.NoError(t, err)
    38  
    39  	log.Printf("test tcp server listening on %s", addr)
    40  	s := &TestTCPServer{
    41  		l: l,
    42  	}
    43  	go s.accept()
    44  
    45  	return s
    46  }
    47  
    48  // Close stops the server
    49  func (s *TestTCPServer) Close() {
    50  	atomic.StoreInt32(&s.stopped, 1)
    51  	if s.l != nil {
    52  		s.l.Close()
    53  	}
    54  }
    55  
    56  // Addr returns the address that this server is listening on.
    57  func (s *TestTCPServer) Addr() net.Addr {
    58  	return s.l.Addr()
    59  }
    60  
    61  func (s *TestTCPServer) accept() error {
    62  	for {
    63  		conn, err := s.l.Accept()
    64  		if err != nil {
    65  			if atomic.LoadInt32(&s.stopped) == 1 {
    66  				log.Printf("test tcp echo server %s stopped", s.l.Addr())
    67  				return nil
    68  			}
    69  			log.Printf("test tcp echo server %s failed: %s", s.l.Addr(), err)
    70  			return err
    71  		}
    72  
    73  		atomic.AddInt32(&s.accepted, 1)
    74  		atomic.AddInt32(&s.active, 1)
    75  
    76  		go func(c net.Conn) {
    77  			io.Copy(c, c)
    78  			atomic.AddInt32(&s.closed, 1)
    79  			atomic.AddInt32(&s.active, -1)
    80  		}(conn)
    81  	}
    82  }
    83  
    84  // TestEchoConn attempts to write some bytes to conn and expects to read them
    85  // back within a short timeout (10ms). If prefix is not empty we expect it to be
    86  // poresent at the start of all echoed responses (for example to distinguish
    87  // between multiple echo server instances).
    88  func TestEchoConn(t testing.T, conn net.Conn, prefix string) {
    89  	t.Helper()
    90  
    91  	// Write some bytes and read them back
    92  	n, err := conn.Write([]byte("Hello World"))
    93  	require.Equal(t, 11, n)
    94  	require.Nil(t, err)
    95  
    96  	expectLen := 11 + len(prefix)
    97  
    98  	buf := make([]byte, expectLen)
    99  	// read until our buffer is full - it might be separate packets if prefix is
   100  	// in use.
   101  	got := 0
   102  	for got < expectLen {
   103  		n, err = conn.Read(buf[got:])
   104  		require.Nilf(t, err, "err: %s", err)
   105  		got += n
   106  	}
   107  	require.Equal(t, expectLen, got)
   108  	require.Equal(t, prefix+"Hello World", string(buf[:]))
   109  
   110  	// Addresses test flakiness around returning before Write or Read finish
   111  	// see PR #4498
   112  	time.Sleep(time.Millisecond)
   113  }
   114  
   115  // TestStaticUpstreamResolverFunc returns a function that will return a static
   116  // resolver for testing UpstreamListener.
   117  func TestStaticUpstreamResolverFunc(r connect.Resolver) func(UpstreamConfig) (connect.Resolver, error) {
   118  	return func(UpstreamConfig) (connect.Resolver, error) {
   119  		return r, nil
   120  	}
   121  }