go.etcd.io/etcd@v3.3.27+incompatible/clientv3/client_test.go (about)

     1  // Copyright 2016 The etcd Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package clientv3
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"net"
    21  	"testing"
    22  	"time"
    23  
    24  	"github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes"
    25  	"github.com/coreos/etcd/pkg/testutil"
    26  	"google.golang.org/grpc"
    27  )
    28  
    29  func TestDialCancel(t *testing.T) {
    30  	defer testutil.AfterTest(t)
    31  
    32  	// accept first connection so client is created with dial timeout
    33  	ln, err := net.Listen("unix", "dialcancel:12345")
    34  	if err != nil {
    35  		t.Fatal(err)
    36  	}
    37  	defer ln.Close()
    38  
    39  	ep := "unix://dialcancel:12345"
    40  	cfg := Config{
    41  		Endpoints:   []string{ep},
    42  		DialTimeout: 30 * time.Second}
    43  	c, err := New(cfg)
    44  	if err != nil {
    45  		t.Fatal(err)
    46  	}
    47  
    48  	// connect to ipv4 black hole so dial blocks
    49  	c.SetEndpoints("http://254.0.0.1:12345")
    50  
    51  	// issue Get to force redial attempts
    52  	getc := make(chan struct{})
    53  	go func() {
    54  		defer close(getc)
    55  		// Get may hang forever on grpc's Stream.Header() if its
    56  		// context is never canceled.
    57  		c.Get(c.Ctx(), "abc")
    58  	}()
    59  
    60  	// wait a little bit so client close is after dial starts
    61  	time.Sleep(100 * time.Millisecond)
    62  
    63  	donec := make(chan struct{})
    64  	go func() {
    65  		defer close(donec)
    66  		c.Close()
    67  	}()
    68  
    69  	select {
    70  	case <-time.After(5 * time.Second):
    71  		t.Fatalf("failed to close")
    72  	case <-donec:
    73  	}
    74  	select {
    75  	case <-time.After(5 * time.Second):
    76  		t.Fatalf("get failed to exit")
    77  	case <-getc:
    78  	}
    79  }
    80  
    81  func TestDialTimeout(t *testing.T) {
    82  	defer testutil.AfterTest(t)
    83  
    84  	testCfgs := []Config{
    85  		{
    86  			Endpoints:   []string{"http://254.0.0.1:12345"},
    87  			DialOptions: []grpc.DialOption{grpc.WithBlock()},
    88  			DialTimeout: 2 * time.Second,
    89  		},
    90  		{
    91  			Endpoints:   []string{"http://254.0.0.1:12345"},
    92  			DialTimeout: time.Second,
    93  			DialOptions: []grpc.DialOption{grpc.WithBlock()},
    94  			Username:    "abc",
    95  			Password:    "def",
    96  		},
    97  	}
    98  
    99  	for i, cfg := range testCfgs {
   100  		donec := make(chan error)
   101  		go func() {
   102  			// without timeout, dial continues forever on ipv4 black hole
   103  			c, err := New(cfg)
   104  			if c != nil || err == nil {
   105  				t.Errorf("#%d: new client should fail", i)
   106  			}
   107  			donec <- err
   108  		}()
   109  
   110  		time.Sleep(10 * time.Millisecond)
   111  
   112  		select {
   113  		case err := <-donec:
   114  			t.Errorf("#%d: dial didn't wait (%v)", i, err)
   115  		default:
   116  		}
   117  
   118  		select {
   119  		case <-time.After(5 * time.Second):
   120  			t.Errorf("#%d: failed to timeout dial on time", i)
   121  		case err := <-donec:
   122  			if err != context.DeadlineExceeded {
   123  				t.Errorf("#%d: unexpected error %v, want %v", i, err, context.DeadlineExceeded)
   124  			}
   125  		}
   126  	}
   127  }
   128  
   129  func TestDialNoTimeout(t *testing.T) {
   130  	cfg := Config{Endpoints: []string{"127.0.0.1:12345"}}
   131  	c, err := New(cfg)
   132  	if c == nil || err != nil {
   133  		t.Fatalf("new client with DialNoWait should succeed, got %v", err)
   134  	}
   135  	c.Close()
   136  }
   137  
   138  func TestIsHaltErr(t *testing.T) {
   139  	if !isHaltErr(nil, fmt.Errorf("etcdserver: some etcdserver error")) {
   140  		t.Errorf(`error prefixed with "etcdserver: " should be Halted by default`)
   141  	}
   142  	if isHaltErr(nil, rpctypes.ErrGRPCStopped) {
   143  		t.Errorf("error %v should not halt", rpctypes.ErrGRPCStopped)
   144  	}
   145  	if isHaltErr(nil, rpctypes.ErrGRPCNoLeader) {
   146  		t.Errorf("error %v should not halt", rpctypes.ErrGRPCNoLeader)
   147  	}
   148  	ctx, cancel := context.WithCancel(context.TODO())
   149  	if isHaltErr(ctx, nil) {
   150  		t.Errorf("no error and active context should not be Halted")
   151  	}
   152  	cancel()
   153  	if !isHaltErr(ctx, nil) {
   154  		t.Errorf("cancel on context should be Halted")
   155  	}
   156  }