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 }