go.etcd.io/etcd@v3.3.27+incompatible/clientv3/integration/dial_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 integration
    16  
    17  import (
    18  	"context"
    19  	"math/rand"
    20  	"strings"
    21  	"testing"
    22  	"time"
    23  
    24  	"github.com/coreos/etcd/clientv3"
    25  	pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
    26  	"github.com/coreos/etcd/integration"
    27  	"github.com/coreos/etcd/pkg/testutil"
    28  	"github.com/coreos/etcd/pkg/transport"
    29  	"google.golang.org/grpc"
    30  )
    31  
    32  var (
    33  	testTLSInfo = transport.TLSInfo{
    34  		KeyFile:        "../../integration/fixtures/server.key.insecure",
    35  		CertFile:       "../../integration/fixtures/server.crt",
    36  		TrustedCAFile:  "../../integration/fixtures/ca.crt",
    37  		ClientCertAuth: true,
    38  	}
    39  
    40  	testTLSInfoExpired = transport.TLSInfo{
    41  		KeyFile:        "../../integration/fixtures-expired/server-key.pem",
    42  		CertFile:       "../../integration/fixtures-expired/server.pem",
    43  		TrustedCAFile:  "../../integration/fixtures-expired/etcd-root-ca.pem",
    44  		ClientCertAuth: true,
    45  	}
    46  )
    47  
    48  // TestDialTLSExpired tests client with expired certs fails to dial.
    49  func TestDialTLSExpired(t *testing.T) {
    50  	defer testutil.AfterTest(t)
    51  	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1, PeerTLS: &testTLSInfo, ClientTLS: &testTLSInfo, SkipCreatingClient: true})
    52  	defer clus.Terminate(t)
    53  
    54  	tls, err := testTLSInfoExpired.ClientConfig()
    55  	if err != nil {
    56  		t.Fatal(err)
    57  	}
    58  	// expect remote errors "tls: bad certificate"
    59  	_, err = clientv3.New(clientv3.Config{
    60  		Endpoints:   []string{clus.Members[0].GRPCAddr()},
    61  		DialTimeout: 3 * time.Second,
    62  		DialOptions: []grpc.DialOption{grpc.WithBlock()},
    63  		TLS:         tls,
    64  	})
    65  	if !isClientTimeout(err) {
    66  		t.Fatalf("expected dial timeout error, got %v", err)
    67  	}
    68  }
    69  
    70  // TestDialTLSNoConfig ensures the client fails to dial / times out
    71  // when TLS endpoints (https, unixs) are given but no tls config.
    72  func TestDialTLSNoConfig(t *testing.T) {
    73  	defer testutil.AfterTest(t)
    74  	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1, ClientTLS: &testTLSInfo, SkipCreatingClient: true})
    75  	defer clus.Terminate(t)
    76  	// expect "signed by unknown authority"
    77  	c, err := clientv3.New(clientv3.Config{
    78  		Endpoints:   []string{clus.Members[0].GRPCAddr()},
    79  		DialTimeout: time.Second,
    80  		DialOptions: []grpc.DialOption{grpc.WithBlock()},
    81  	})
    82  	defer func() {
    83  		if c != nil {
    84  			c.Close()
    85  		}
    86  	}()
    87  	if !isClientTimeout(err) {
    88  		t.Fatalf("expected dial timeout error, got %v", err)
    89  	}
    90  }
    91  
    92  // TestDialSetEndpointsBeforeFail ensures SetEndpoints can replace unavailable
    93  // endpoints with available ones.
    94  func TestDialSetEndpointsBeforeFail(t *testing.T) {
    95  	testDialSetEndpoints(t, true)
    96  }
    97  
    98  func TestDialSetEndpointsAfterFail(t *testing.T) {
    99  	testDialSetEndpoints(t, false)
   100  }
   101  
   102  // testDialSetEndpoints ensures SetEndpoints can replace unavailable endpoints with available ones.
   103  func testDialSetEndpoints(t *testing.T, setBefore bool) {
   104  	defer testutil.AfterTest(t)
   105  	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3, SkipCreatingClient: true})
   106  	defer clus.Terminate(t)
   107  
   108  	// get endpoint list
   109  	eps := make([]string, 3)
   110  	for i := range eps {
   111  		eps[i] = clus.Members[i].GRPCAddr()
   112  	}
   113  	toKill := rand.Intn(len(eps))
   114  
   115  	cfg := clientv3.Config{
   116  		Endpoints:   []string{eps[toKill]},
   117  		DialTimeout: 1 * time.Second,
   118  		DialOptions: []grpc.DialOption{grpc.WithBlock()},
   119  	}
   120  	cli, err := clientv3.New(cfg)
   121  	if err != nil {
   122  		t.Fatal(err)
   123  	}
   124  	defer cli.Close()
   125  
   126  	if setBefore {
   127  		cli.SetEndpoints(eps[toKill%3], eps[(toKill+1)%3])
   128  	}
   129  	// make a dead node
   130  	clus.Members[toKill].Stop(t)
   131  	clus.WaitLeader(t)
   132  
   133  	if !setBefore {
   134  		cli.SetEndpoints(eps[toKill%3], eps[(toKill+1)%3])
   135  	}
   136  	time.Sleep(time.Second * 2)
   137  	ctx, cancel := context.WithTimeout(context.Background(), integration.RequestWaitTimeout)
   138  	if _, err = cli.Get(ctx, "foo", clientv3.WithSerializable()); err != nil {
   139  		t.Fatal(err)
   140  	}
   141  	cancel()
   142  }
   143  
   144  // TestSwitchSetEndpoints ensures SetEndpoints can switch one endpoint
   145  // with a new one that doesn't include original endpoint.
   146  func TestSwitchSetEndpoints(t *testing.T) {
   147  	defer testutil.AfterTest(t)
   148  	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
   149  	defer clus.Terminate(t)
   150  
   151  	// get non partitioned members endpoints
   152  	eps := []string{clus.Members[1].GRPCAddr(), clus.Members[2].GRPCAddr()}
   153  
   154  	cli := clus.Client(0)
   155  	clus.Members[0].InjectPartition(t, clus.Members[1:]...)
   156  
   157  	cli.SetEndpoints(eps...)
   158  	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
   159  	defer cancel()
   160  	if _, err := cli.Get(ctx, "foo"); err != nil {
   161  		t.Fatal(err)
   162  	}
   163  }
   164  
   165  func TestRejectOldCluster(t *testing.T) {
   166  	defer testutil.AfterTest(t)
   167  	// 2 endpoints to test multi-endpoint Status
   168  	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 2, SkipCreatingClient: true})
   169  	defer clus.Terminate(t)
   170  
   171  	cfg := clientv3.Config{
   172  		Endpoints:        []string{clus.Members[0].GRPCAddr(), clus.Members[1].GRPCAddr()},
   173  		DialTimeout:      5 * time.Second,
   174  		DialOptions:      []grpc.DialOption{grpc.WithBlock()},
   175  		RejectOldCluster: true,
   176  	}
   177  	cli, err := clientv3.New(cfg)
   178  	if err != nil {
   179  		t.Fatal(err)
   180  	}
   181  	cli.Close()
   182  }
   183  
   184  // TestDialForeignEndpoint checks an endpoint that is not registered
   185  // with the balancer can be dialed.
   186  func TestDialForeignEndpoint(t *testing.T) {
   187  	defer testutil.AfterTest(t)
   188  	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 2})
   189  	defer clus.Terminate(t)
   190  
   191  	conn, err := clus.Client(0).Dial(clus.Client(1).Endpoints()[0])
   192  	if err != nil {
   193  		t.Fatal(err)
   194  	}
   195  	defer conn.Close()
   196  
   197  	// grpc can return a lazy connection that's not connected yet; confirm
   198  	// that it can communicate with the cluster.
   199  	kvc := clientv3.NewKVFromKVClient(pb.NewKVClient(conn), clus.Client(0))
   200  	ctx, cancel := context.WithTimeout(context.TODO(), 5*time.Second)
   201  	defer cancel()
   202  	if _, gerr := kvc.Get(ctx, "abc"); gerr != nil {
   203  		t.Fatal(err)
   204  	}
   205  }
   206  
   207  // TestSetEndpointAndPut checks that a Put following a SetEndpoints
   208  // to a working endpoint will always succeed.
   209  func TestSetEndpointAndPut(t *testing.T) {
   210  	defer testutil.AfterTest(t)
   211  	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 2})
   212  	defer clus.Terminate(t)
   213  
   214  	clus.Client(1).SetEndpoints(clus.Members[0].GRPCAddr())
   215  	_, err := clus.Client(1).Put(context.TODO(), "foo", "bar")
   216  	if err != nil && !strings.Contains(err.Error(), "closing") {
   217  		t.Fatal(err)
   218  	}
   219  }