...

Source file src/k8s.io/apimachinery/pkg/util/net/util_test.go

Documentation: k8s.io/apimachinery/pkg/util/net

     1  /*
     2  Copyright 2016 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package net
    18  
    19  import (
    20  	"fmt"
    21  	"io"
    22  	"net"
    23  	"net/http"
    24  	"net/http/httptest"
    25  	"net/url"
    26  	"os"
    27  	"sync/atomic"
    28  	"syscall"
    29  	"testing"
    30  	"time"
    31  
    32  	"golang.org/x/net/http2"
    33  
    34  	netutils "k8s.io/utils/net"
    35  )
    36  
    37  func getIPNet(cidr string) *net.IPNet {
    38  	_, ipnet, _ := netutils.ParseCIDRSloppy(cidr)
    39  	return ipnet
    40  }
    41  
    42  func TestIPNetEqual(t *testing.T) {
    43  	testCases := []struct {
    44  		ipnet1 *net.IPNet
    45  		ipnet2 *net.IPNet
    46  		expect bool
    47  	}{
    48  		// null case
    49  		{
    50  			getIPNet("10.0.0.1/24"),
    51  			getIPNet(""),
    52  			false,
    53  		},
    54  		{
    55  			getIPNet("10.0.0.0/24"),
    56  			getIPNet("10.0.0.0/24"),
    57  			true,
    58  		},
    59  		{
    60  			getIPNet("10.0.0.0/24"),
    61  			getIPNet("10.0.0.1/24"),
    62  			true,
    63  		},
    64  		{
    65  			getIPNet("10.0.0.0/25"),
    66  			getIPNet("10.0.0.0/24"),
    67  			false,
    68  		},
    69  		{
    70  			getIPNet("10.0.1.0/24"),
    71  			getIPNet("10.0.0.0/24"),
    72  			false,
    73  		},
    74  	}
    75  
    76  	for _, tc := range testCases {
    77  		if tc.expect != IPNetEqual(tc.ipnet1, tc.ipnet2) {
    78  			t.Errorf("Expect equality of %s and %s be to %v", tc.ipnet1.String(), tc.ipnet2.String(), tc.expect)
    79  		}
    80  	}
    81  }
    82  
    83  func TestIsConnectionRefused(t *testing.T) {
    84  	testCases := []struct {
    85  		err    error
    86  		expect bool
    87  	}{
    88  		{
    89  			&url.Error{Err: &net.OpError{Err: syscall.ECONNRESET}},
    90  			false,
    91  		},
    92  		{
    93  			&url.Error{Err: &net.OpError{Err: syscall.ECONNREFUSED}},
    94  			true,
    95  		},
    96  		{&url.Error{Err: &net.OpError{Err: &os.SyscallError{Err: syscall.ECONNREFUSED}}},
    97  			true,
    98  		},
    99  	}
   100  
   101  	for _, tc := range testCases {
   102  		if result := IsConnectionRefused(tc.err); result != tc.expect {
   103  			t.Errorf("Expect to be %v, but actual is %v", tc.expect, result)
   104  		}
   105  	}
   106  }
   107  
   108  type tcpLB struct {
   109  	t         *testing.T
   110  	ln        net.Listener
   111  	serverURL string
   112  	dials     int32
   113  }
   114  
   115  func (lb *tcpLB) handleConnection(in net.Conn, stopCh chan struct{}) {
   116  	out, err := net.Dial("tcp", lb.serverURL)
   117  	if err != nil {
   118  		lb.t.Log(err)
   119  		return
   120  	}
   121  	go io.Copy(out, in)
   122  	go io.Copy(in, out)
   123  	<-stopCh
   124  	if err := out.Close(); err != nil {
   125  		lb.t.Fatalf("failed to close connection: %v", err)
   126  	}
   127  }
   128  
   129  func (lb *tcpLB) serve(stopCh chan struct{}) {
   130  	conn, err := lb.ln.Accept()
   131  	if err != nil {
   132  		lb.t.Fatalf("failed to accept: %v", err)
   133  	}
   134  	atomic.AddInt32(&lb.dials, 1)
   135  	go lb.handleConnection(conn, stopCh)
   136  }
   137  
   138  func newLB(t *testing.T, serverURL string) *tcpLB {
   139  	ln, err := net.Listen("tcp", "127.0.0.1:0")
   140  	if err != nil {
   141  		t.Fatalf("failed to bind: %v", err)
   142  	}
   143  	lb := tcpLB{
   144  		serverURL: serverURL,
   145  		ln:        ln,
   146  		t:         t,
   147  	}
   148  	return &lb
   149  }
   150  
   151  func TestIsConnectionReset(t *testing.T) {
   152  	ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   153  		fmt.Fprintf(w, "Hello, %s", r.Proto)
   154  	}))
   155  	ts.EnableHTTP2 = true
   156  	ts.StartTLS()
   157  	defer ts.Close()
   158  
   159  	u, err := url.Parse(ts.URL)
   160  	if err != nil {
   161  		t.Fatalf("failed to parse URL from %q: %v", ts.URL, err)
   162  	}
   163  	lb := newLB(t, u.Host)
   164  	defer lb.ln.Close()
   165  	stopCh := make(chan struct{})
   166  	go lb.serve(stopCh)
   167  
   168  	c := ts.Client()
   169  	transport, ok := ts.Client().Transport.(*http.Transport)
   170  	if !ok {
   171  		t.Fatalf("failed to assert *http.Transport")
   172  	}
   173  	t2, err := http2.ConfigureTransports(transport)
   174  	if err != nil {
   175  		t.Fatalf("failed to configure *http.Transport: %+v", err)
   176  	}
   177  	t2.ReadIdleTimeout = time.Second
   178  	t2.PingTimeout = time.Second
   179  	// Create an HTTP2 connection to reuse later
   180  	resp, err := c.Get("https://" + lb.ln.Addr().String())
   181  	if err != nil {
   182  		t.Fatalf("unexpected error: %+v", err)
   183  	}
   184  	defer resp.Body.Close()
   185  	data, err := io.ReadAll(resp.Body)
   186  	if err != nil {
   187  		t.Fatalf("unexpected error: %+v", err)
   188  	}
   189  	if string(data) != "Hello, HTTP/2.0" {
   190  		t.Fatalf("unexpected response: %s", data)
   191  	}
   192  
   193  	// Deliberately let the LB stop proxying traffic for the current
   194  	// connection. This mimics a broken TCP connection that's not properly
   195  	// closed.
   196  	close(stopCh)
   197  	_, err = c.Get("https://" + lb.ln.Addr().String())
   198  	if !IsHTTP2ConnectionLost(err) {
   199  		t.Fatalf("expected HTTP2ConnectionLost error, got %v", err)
   200  	}
   201  }
   202  

View as plain text