go.etcd.io/etcd@v3.3.27+incompatible/integration/embed_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  // +build !cluster_proxy
    16  
    17  // TODO: fix race conditions with setupLogging
    18  
    19  package integration
    20  
    21  import (
    22  	"context"
    23  	"fmt"
    24  	"net/url"
    25  	"os"
    26  	"path/filepath"
    27  	"strings"
    28  	"testing"
    29  	"time"
    30  
    31  	"github.com/coreos/etcd/clientv3"
    32  	"github.com/coreos/etcd/embed"
    33  )
    34  
    35  func TestEmbedEtcd(t *testing.T) {
    36  	tests := []struct {
    37  		cfg embed.Config
    38  
    39  		werr     string
    40  		wpeers   int
    41  		wclients int
    42  	}{
    43  		{werr: "multiple discovery"},
    44  		{werr: "advertise-client-urls is required"},
    45  		{werr: "should be at least"},
    46  		{werr: "is too long"},
    47  		{wpeers: 1, wclients: 1},
    48  		{wpeers: 2, wclients: 1},
    49  		{wpeers: 1, wclients: 2},
    50  		{werr: "expected IP"},
    51  		{werr: "expected IP"},
    52  	}
    53  
    54  	urls := newEmbedURLs(false, 10)
    55  
    56  	// setup defaults
    57  	for i := range tests {
    58  		tests[i].cfg = *embed.NewConfig()
    59  	}
    60  
    61  	tests[0].cfg.Durl = "abc"
    62  	setupEmbedCfg(&tests[1].cfg, []url.URL{urls[0]}, []url.URL{urls[1]})
    63  	tests[1].cfg.ACUrls = nil
    64  	tests[2].cfg.TickMs = tests[2].cfg.ElectionMs - 1
    65  	tests[3].cfg.ElectionMs = 999999
    66  	setupEmbedCfg(&tests[4].cfg, []url.URL{urls[2]}, []url.URL{urls[3]})
    67  	setupEmbedCfg(&tests[5].cfg, []url.URL{urls[4]}, []url.URL{urls[5], urls[6]})
    68  	setupEmbedCfg(&tests[6].cfg, []url.URL{urls[7], urls[8]}, []url.URL{urls[9]})
    69  
    70  	dnsURL, _ := url.Parse("http://whatever.test:12345")
    71  	tests[7].cfg.LCUrls = []url.URL{*dnsURL}
    72  	tests[8].cfg.LPUrls = []url.URL{*dnsURL}
    73  
    74  	dir := filepath.Join(os.TempDir(), fmt.Sprintf("embed-etcd"))
    75  	os.RemoveAll(dir)
    76  	defer os.RemoveAll(dir)
    77  
    78  	for i, tt := range tests {
    79  		tests[i].cfg.Dir = dir
    80  		e, err := embed.StartEtcd(&tests[i].cfg)
    81  		if e != nil {
    82  			<-e.Server.ReadyNotify() // wait for e.Server to join the cluster
    83  		}
    84  		if tt.werr != "" {
    85  			if err == nil || !strings.Contains(err.Error(), tt.werr) {
    86  				t.Errorf("%d: expected error with %q, got %v", i, tt.werr, err)
    87  			}
    88  			if e != nil {
    89  				e.Close()
    90  			}
    91  			continue
    92  		}
    93  		if err != nil {
    94  			t.Errorf("%d: expected success, got error %v", i, err)
    95  			continue
    96  		}
    97  		if len(e.Peers) != tt.wpeers {
    98  			t.Errorf("%d: expected %d peers, got %d", i, tt.wpeers, len(e.Peers))
    99  		}
   100  		if len(e.Clients) != tt.wclients {
   101  			t.Errorf("%d: expected %d clients, got %d", i, tt.wclients, len(e.Clients))
   102  		}
   103  		e.Close()
   104  		select {
   105  		case err := <-e.Err():
   106  			t.Errorf("#%d: unexpected error on close (%v)", i, err)
   107  		default:
   108  		}
   109  	}
   110  }
   111  
   112  func TestEmbedEtcdGracefulStopSecure(t *testing.T)   { testEmbedEtcdGracefulStop(t, true) }
   113  func TestEmbedEtcdGracefulStopInsecure(t *testing.T) { testEmbedEtcdGracefulStop(t, false) }
   114  
   115  // testEmbedEtcdGracefulStop ensures embedded server stops
   116  // cutting existing transports.
   117  func testEmbedEtcdGracefulStop(t *testing.T, secure bool) {
   118  	cfg := embed.NewConfig()
   119  	if secure {
   120  		cfg.ClientTLSInfo = testTLSInfo
   121  		cfg.PeerTLSInfo = testTLSInfo
   122  	}
   123  
   124  	urls := newEmbedURLs(secure, 2)
   125  	setupEmbedCfg(cfg, []url.URL{urls[0]}, []url.URL{urls[1]})
   126  
   127  	cfg.Dir = filepath.Join(os.TempDir(), fmt.Sprintf("embed-etcd"))
   128  	os.RemoveAll(cfg.Dir)
   129  	defer os.RemoveAll(cfg.Dir)
   130  
   131  	e, err := embed.StartEtcd(cfg)
   132  	if err != nil {
   133  		t.Fatal(err)
   134  	}
   135  	<-e.Server.ReadyNotify() // wait for e.Server to join the cluster
   136  
   137  	clientCfg := clientv3.Config{
   138  		Endpoints: []string{urls[0].String()},
   139  	}
   140  	if secure {
   141  		clientCfg.TLS, err = testTLSInfo.ClientConfig()
   142  		if err != nil {
   143  			t.Fatal(err)
   144  		}
   145  	}
   146  	cli, err := clientv3.New(clientCfg)
   147  	if err != nil {
   148  		t.Fatal(err)
   149  	}
   150  	defer cli.Close()
   151  
   152  	// open watch connection
   153  	cli.Watch(context.Background(), "foo")
   154  
   155  	donec := make(chan struct{})
   156  	go func() {
   157  		e.Close()
   158  		close(donec)
   159  	}()
   160  	select {
   161  	case err := <-e.Err():
   162  		t.Fatal(err)
   163  	case <-donec:
   164  	case <-time.After(2*time.Second + e.Server.Cfg.ReqTimeout()):
   165  		t.Fatalf("took too long to close server")
   166  	}
   167  }
   168  
   169  func newEmbedURLs(secure bool, n int) (urls []url.URL) {
   170  	scheme := "unix"
   171  	if secure {
   172  		scheme = "unixs"
   173  	}
   174  	for i := 0; i < n; i++ {
   175  		u, _ := url.Parse(fmt.Sprintf("%s://localhost:%d%06d", scheme, os.Getpid(), i))
   176  		urls = append(urls, *u)
   177  	}
   178  	return urls
   179  }
   180  
   181  func setupEmbedCfg(cfg *embed.Config, curls []url.URL, purls []url.URL) {
   182  	cfg.ClusterState = "new"
   183  	cfg.LCUrls, cfg.ACUrls = curls, curls
   184  	cfg.LPUrls, cfg.APUrls = purls, purls
   185  	cfg.InitialCluster = ""
   186  	for i := range purls {
   187  		cfg.InitialCluster += ",default=" + purls[i].String()
   188  	}
   189  	cfg.InitialCluster = cfg.InitialCluster[1:]
   190  }