github.com/craicoverflow/tyk@v2.9.6-rc3+incompatible/tcp/tcp_test.go (about)

     1  package tcp
     2  
     3  import (
     4  	"crypto/tls"
     5  	"net"
     6  	"reflect"
     7  	"testing"
     8  
     9  	"github.com/TykTechnologies/tyk/test"
    10  )
    11  
    12  func TestProxyModifier(t *testing.T) {
    13  	// Echoing
    14  	upstream := test.TcpMock(false, func(in []byte, err error) (out []byte) {
    15  		return in
    16  	})
    17  	defer upstream.Close()
    18  
    19  	t.Run("Without modifier", func(t *testing.T) {
    20  		proxy := &Proxy{}
    21  		proxy.AddDomainHandler("", upstream.Addr().String(), nil)
    22  
    23  		testRunner(t, proxy, "", false, []test.TCPTestCase{
    24  			{Action: "write", Payload: "ping"},
    25  			{Action: "read", Payload: "ping"},
    26  		}...)
    27  	})
    28  
    29  	t.Run("Modify response", func(t *testing.T) {
    30  		proxy := &Proxy{}
    31  		proxy.AddDomainHandler("", upstream.Addr().String(), &Modifier{
    32  			ModifyResponse: func(src, dst net.Conn, data []byte) ([]byte, error) {
    33  				return []byte("pong"), nil
    34  			},
    35  		})
    36  
    37  		testRunner(t, proxy, "", false, []test.TCPTestCase{
    38  			{Action: "write", Payload: "ping"},
    39  			{Action: "read", Payload: "pong"},
    40  		}...)
    41  	})
    42  
    43  	t.Run("Mock request", func(t *testing.T) {
    44  		proxy := &Proxy{}
    45  		proxy.AddDomainHandler("", upstream.Addr().String(), &Modifier{
    46  			ModifyRequest: func(src, dst net.Conn, data []byte) ([]byte, error) {
    47  				return []byte("pong"), nil
    48  			},
    49  		})
    50  
    51  		testRunner(t, proxy, "", false, []test.TCPTestCase{
    52  			{Action: "write", Payload: "ping"},
    53  			{Action: "read", Payload: "pong"},
    54  		}...)
    55  	})
    56  }
    57  func TestProxySyncStats(t *testing.T) {
    58  	t.Skip()
    59  	// Echoing
    60  	upstream := test.TcpMock(false, func(in []byte, err error) (out []byte) {
    61  		return in
    62  	})
    63  	defer upstream.Close()
    64  	stats := make(chan Stat)
    65  	proxy := &Proxy{SyncStats: func(s Stat) {
    66  		stats <- s
    67  		if s.State == Closed {
    68  			close(stats)
    69  		}
    70  	}}
    71  	proxy.AddDomainHandler("", upstream.Addr().String(), nil)
    72  
    73  	testRunner(t, proxy, "", false, []test.TCPTestCase{
    74  		{Action: "write", Payload: "ping"},
    75  		{Action: "read", Payload: "ping"},
    76  	}...)
    77  	var c []Stat
    78  	for s := range stats {
    79  		c = append(c, s)
    80  	}
    81  	expect := []Stat{
    82  		{State: Open},
    83  		{State: Closed, BytesIn: 4, BytesOut: 4},
    84  	}
    85  	if len(c) != len(expect) {
    86  		t.Fatalf("expected %d stats got %d stats", len(expect), len(c))
    87  	}
    88  	if !reflect.DeepEqual(c, expect) {
    89  		t.Errorf("expected %#v got %#v", expect, c)
    90  	}
    91  }
    92  
    93  func TestProxyMultiTarget(t *testing.T) {
    94  	target1 := test.TcpMock(false, func(in []byte, err error) (out []byte) {
    95  		return []byte("first")
    96  	})
    97  	defer target1.Close()
    98  
    99  	target2 := test.TcpMock(false, func(in []byte, err error) (out []byte) {
   100  		return []byte("second")
   101  	})
   102  	defer target2.Close()
   103  
   104  	t.Run("Single_target, no SNI", func(t *testing.T) {
   105  		proxy := &Proxy{}
   106  		proxy.AddDomainHandler("", target1.Addr().String(), nil)
   107  
   108  		testRunner(t, proxy, "", true, []test.TCPTestCase{
   109  			{Action: "write", Payload: "ping"},
   110  			{Action: "read", Payload: "first"},
   111  		}...)
   112  	})
   113  
   114  	t.Run("Single target, SNI, without domain", func(t *testing.T) {
   115  		proxy := &Proxy{}
   116  		proxy.AddDomainHandler("", target1.Addr().String(), nil)
   117  
   118  		testRunner(t, proxy, "localhost", true, []test.TCPTestCase{
   119  			{Action: "write", Payload: "ping"},
   120  			{Action: "read", Payload: "first"},
   121  		}...)
   122  	})
   123  
   124  	t.Run("Single target, SNI, domain match", func(t *testing.T) {
   125  		proxy := &Proxy{}
   126  		proxy.AddDomainHandler("localhost", target1.Addr().String(), nil)
   127  
   128  		testRunner(t, proxy, "localhost", true, []test.TCPTestCase{
   129  			{Action: "write", Payload: "ping"},
   130  			{Action: "read", Payload: "first"},
   131  		}...)
   132  	})
   133  
   134  	t.Run("Single target, SNI, domain not match", func(t *testing.T) {
   135  		proxy := &Proxy{}
   136  		proxy.AddDomainHandler("localhost", target1.Addr().String(), nil)
   137  
   138  		// Should cause `Can't detect service based on provided SNI information: example.com`
   139  		testRunner(t, proxy, "example.com", true, []test.TCPTestCase{
   140  			{Action: "write", Payload: "ping"},
   141  			{Action: "read", ErrorMatch: "EOF"},
   142  		}...)
   143  	})
   144  
   145  	t.Run("Multiple targets, No SNI", func(t *testing.T) {
   146  		proxy := &Proxy{}
   147  		proxy.AddDomainHandler("localhost", target1.Addr().String(), nil)
   148  		proxy.AddDomainHandler("example.com", target2.Addr().String(), nil)
   149  
   150  		// Should cause `Multiple services on different domains running on the same port, but no SNI (domain) information from client
   151  		testRunner(t, proxy, "", true, []test.TCPTestCase{
   152  			{Action: "write", Payload: "ping"},
   153  			{Action: "read", ErrorMatch: "EOF"},
   154  		}...)
   155  	})
   156  
   157  	t.Run("Multiple targets, SNI", func(t *testing.T) {
   158  		proxy := &Proxy{}
   159  		proxy.AddDomainHandler("localhost", target1.Addr().String(), nil)
   160  		proxy.AddDomainHandler("example.com", target2.Addr().String(), nil)
   161  
   162  		testRunner(t, proxy, "localhost", true, []test.TCPTestCase{
   163  			{Action: "write", Payload: "ping"},
   164  			{Action: "read", Payload: "first"},
   165  		}...)
   166  
   167  		testRunner(t, proxy, "example.com", true, []test.TCPTestCase{
   168  			{Action: "write", Payload: "ping"},
   169  			{Action: "read", Payload: "second"},
   170  		}...)
   171  
   172  		testRunner(t, proxy, "wrong", true, []test.TCPTestCase{
   173  			{Action: "write", Payload: "ping"},
   174  			{Action: "read", ErrorMatch: "EOF"},
   175  		}...)
   176  	})
   177  
   178  	t.Run("Multiple targets, SNI with fallback", func(t *testing.T) {
   179  		proxy := &Proxy{}
   180  		proxy.AddDomainHandler("", target1.Addr().String(), nil)
   181  		proxy.AddDomainHandler("example.com", target2.Addr().String(), nil)
   182  
   183  		testRunner(t, proxy, "example.com", true, []test.TCPTestCase{
   184  			{Action: "write", Payload: "ping"},
   185  			{Action: "read", Payload: "second"},
   186  		}...)
   187  
   188  		// Should fallback to target defined with empty domain
   189  		testRunner(t, proxy, "wrong", true, []test.TCPTestCase{
   190  			{Action: "write", Payload: "ping"},
   191  			{Action: "read", Payload: "first"},
   192  		}...)
   193  	})
   194  }
   195  
   196  func testRunner(t *testing.T, proxy *Proxy, hostname string, useSSL bool, testCases ...test.TCPTestCase) {
   197  	var proxyLn net.Listener
   198  	var err error
   199  
   200  	if useSSL {
   201  		tlsConfig := &tls.Config{
   202  			Certificates:       []tls.Certificate{test.Cert("localhost")},
   203  			InsecureSkipVerify: true,
   204  		}
   205  		tlsConfig.BuildNameToCertificate()
   206  		proxyLn, err = tls.Listen("tcp", ":0", tlsConfig)
   207  
   208  		if err != nil {
   209  			t.Fatalf(err.Error())
   210  			return
   211  		}
   212  	} else {
   213  		proxyLn, _ = net.Listen("tcp", ":0")
   214  	}
   215  	defer proxyLn.Close()
   216  
   217  	go proxy.Serve(proxyLn)
   218  
   219  	runner := test.TCPTestRunner{
   220  		Target:   proxyLn.Addr().String(),
   221  		UseSSL:   useSSL,
   222  		Hostname: hostname,
   223  	}
   224  	runner.Run(t, testCases...)
   225  }