github.com/macb/etcd@v0.3.1-0.20140227003422-a60481c6b1a0/tests/functional/discovery_test.go (about) 1 package test 2 3 import ( 4 "errors" 5 "fmt" 6 "net/http" 7 "net/http/httptest" 8 "net/url" 9 "strings" 10 "testing" 11 "time" 12 13 "github.com/coreos/etcd/third_party/github.com/stretchr/testify/assert" 14 15 etcdtest "github.com/coreos/etcd/tests" 16 "github.com/coreos/etcd/server" 17 goetcd "github.com/coreos/etcd/third_party/github.com/coreos/go-etcd/etcd" 18 ) 19 20 type garbageHandler struct { 21 t *testing.T 22 success bool 23 } 24 25 func (g *garbageHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 26 fmt.Fprintln(w, "Hello, client") 27 if r.URL.String() != "/v2/keys/_etcd/registry/1/node1" { 28 g.t.Fatalf("Unexpected web request") 29 } 30 g.success = true 31 } 32 33 // TestDiscoveryDownNoBackupPeers ensures that etcd stops if it is started with a 34 // bad discovery URL and no backups. 35 func TestDiscoveryDownNoBackupPeers(t *testing.T) { 36 g := garbageHandler{t: t} 37 ts := httptest.NewServer(&g) 38 defer ts.Close() 39 40 discover := ts.URL + "/v2/keys/_etcd/registry/1" 41 proc, err := startServer([]string{"-discovery", discover}) 42 43 if err != nil { 44 t.Fatal(err.Error()) 45 } 46 defer stopServer(proc) 47 48 client := http.Client{} 49 err = assertServerNotUp(client, "http") 50 if err != nil { 51 t.Fatal(err.Error()) 52 } 53 54 if !g.success { 55 t.Fatal("Discovery server never called") 56 } 57 } 58 59 // TestDiscoveryDownWithBackupPeers ensures that etcd runs if it is started with a 60 // bad discovery URL and a peer list. 61 func TestDiscoveryDownWithBackupPeers(t *testing.T) { 62 etcdtest.RunServer(func(s *server.Server) { 63 g := garbageHandler{t: t} 64 ts := httptest.NewServer(&g) 65 defer ts.Close() 66 67 discover := ts.URL + "/v2/keys/_etcd/registry/1" 68 u, ok := s.PeerHost("ETCDTEST") 69 if !ok { 70 t.Fatalf("Couldn't find the URL") 71 } 72 proc, err := startServer([]string{"-discovery", discover, "-peers", u}) 73 74 if err != nil { 75 t.Fatal(err.Error()) 76 } 77 defer stopServer(proc) 78 79 client := http.Client{} 80 err = assertServerFunctional(client, "http") 81 if err != nil { 82 t.Fatal(err.Error()) 83 } 84 85 if !g.success { 86 t.Fatal("Discovery server never called") 87 } 88 }) 89 } 90 91 // TestDiscoveryNoWithBackupPeers ensures that etcd runs if it is started with 92 // no discovery URL and a peer list. 93 func TestDiscoveryNoWithBackupPeers(t *testing.T) { 94 etcdtest.RunServer(func(s *server.Server) { 95 u, ok := s.PeerHost("ETCDTEST") 96 if !ok { 97 t.Fatalf("Couldn't find the URL") 98 } 99 proc, err := startServer([]string{"-peers", u}) 100 101 if err != nil { 102 t.Fatal(err.Error()) 103 } 104 defer stopServer(proc) 105 106 client := http.Client{} 107 err = assertServerFunctional(client, "http") 108 if err != nil { 109 t.Fatal(err.Error()) 110 } 111 }) 112 } 113 114 // TestDiscoveryDownNoBackupPeersWithDataDir ensures that etcd runs if it is 115 // started with a bad discovery URL, no backups and valid data dir. 116 func TestDiscoveryDownNoBackupPeersWithDataDir(t *testing.T) { 117 etcdtest.RunServer(func(s *server.Server) { 118 u, ok := s.PeerHost("ETCDTEST") 119 if !ok { 120 t.Fatalf("Couldn't find the URL") 121 } 122 123 // run etcd and connect to ETCDTEST server 124 proc, err := startServer([]string{"-peers", u}) 125 if err != nil { 126 t.Fatal(err.Error()) 127 } 128 129 // check it runs well 130 client := http.Client{} 131 err = assertServerFunctional(client, "http") 132 if err != nil { 133 t.Fatal(err.Error()) 134 } 135 136 // stop etcd, and leave valid data dir for later usage 137 stopServer(proc) 138 139 g := garbageHandler{t: t} 140 ts := httptest.NewServer(&g) 141 defer ts.Close() 142 143 discover := ts.URL + "/v2/keys/_etcd/registry/1" 144 // connect to ETCDTEST server again with previous data dir 145 proc, err = startServerWithDataDir([]string{"-discovery", discover}) 146 if err != nil { 147 t.Fatal(err.Error()) 148 } 149 defer stopServer(proc) 150 151 // TODO(yichengq): it needs some time to do leader election 152 // improve to get rid of it 153 time.Sleep(1 * time.Second) 154 155 client = http.Client{} 156 err = assertServerFunctional(client, "http") 157 if err != nil { 158 t.Fatal(err.Error()) 159 } 160 161 if !g.success { 162 t.Fatal("Discovery server never called") 163 } 164 }) 165 } 166 167 // TestDiscoveryFirstPeer ensures that etcd starts as the leader if it 168 // registers as the first peer. 169 func TestDiscoveryFirstPeer(t *testing.T) { 170 etcdtest.RunServer(func(s *server.Server) { 171 proc, err := startServer([]string{"-discovery", s.URL() + "/v2/keys/_etcd/registry/2"}) 172 if err != nil { 173 t.Fatal(err.Error()) 174 } 175 defer stopServer(proc) 176 177 client := http.Client{} 178 err = assertServerFunctional(client, "http") 179 if err != nil { 180 t.Fatal(err.Error()) 181 } 182 }) 183 } 184 185 // TestDiscoverySecondPeerFirstDown ensures that etcd stops if it is started with a 186 // correct discovery URL but no active machines are found. 187 func TestDiscoverySecondPeerFirstDown(t *testing.T) { 188 etcdtest.RunServer(func(s *server.Server) { 189 v := url.Values{} 190 v.Set("value", "started") 191 resp, err := etcdtest.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/_etcd/registry/2/_state"), v) 192 assert.Equal(t, resp.StatusCode, http.StatusCreated) 193 194 proc, err := startServer([]string{"-discovery", s.URL() + "/v2/keys/_etcd/registry/2"}) 195 if err != nil { 196 t.Fatal(err.Error()) 197 } 198 defer stopServer(proc) 199 200 client := http.Client{} 201 err = assertServerNotUp(client, "http") 202 if err != nil { 203 t.Fatal(err.Error()) 204 } 205 }) 206 } 207 208 // TestDiscoverySecondPeerFirstNoResponse ensures that if the first etcd 209 // machine stops after heartbeating that the second machine fails too. 210 func TestDiscoverySecondPeerFirstNoResponse(t *testing.T) { 211 etcdtest.RunServer(func(s *server.Server) { 212 v := url.Values{} 213 v.Set("value", "started") 214 resp, err := etcdtest.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/_etcd/registry/2/_state"), v) 215 assert.Equal(t, resp.StatusCode, http.StatusCreated) 216 217 v = url.Values{} 218 v.Set("value", "http://127.0.0.1:49151") 219 resp, err = etcdtest.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/_etcd/registry/2/ETCDTEST"), v) 220 assert.Equal(t, resp.StatusCode, http.StatusCreated) 221 222 proc, err := startServer([]string{"-retry-interval", "0.2", "-discovery", s.URL() + "/v2/keys/_etcd/registry/2"}) 223 if err != nil { 224 t.Fatal(err.Error()) 225 } 226 defer stopServer(proc) 227 228 // TODO(bp): etcd will take 30 seconds to shutdown, figure this 229 // out instead 230 time.Sleep(1 * time.Second) 231 232 client := http.Client{} 233 _, err = client.Get("/") 234 if err != nil && strings.Contains(err.Error(), "connection reset by peer") { 235 t.Fatal(err.Error()) 236 } 237 }) 238 } 239 240 // TestDiscoverySecondPeerUp ensures that a second peer joining a discovery 241 // cluster works. 242 func TestDiscoverySecondPeerUp(t *testing.T) { 243 etcdtest.RunServer(func(s *server.Server) { 244 v := url.Values{} 245 v.Set("value", "started") 246 resp, err := etcdtest.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/_etcd/registry/3/_state"), v) 247 assert.Equal(t, resp.StatusCode, http.StatusCreated) 248 249 u, ok := s.PeerURL("ETCDTEST") 250 if !ok { 251 t.Fatalf("Couldn't find the URL") 252 } 253 254 wc := goetcd.NewClient([]string{s.URL()}) 255 testResp, err := wc.Set("test", "0", 0) 256 257 if err != nil { 258 t.Fatalf("Couldn't set a test key on the leader %v", err) 259 } 260 261 v = url.Values{} 262 v.Set("value", u) 263 resp, err = etcdtest.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/_etcd/registry/3/ETCDTEST"), v) 264 assert.Equal(t, resp.StatusCode, http.StatusCreated) 265 266 proc, err := startServer([]string{"-discovery", s.URL() + "/v2/keys/_etcd/registry/3"}) 267 if err != nil { 268 t.Fatal(err.Error()) 269 } 270 defer stopServer(proc) 271 272 watch := fmt.Sprintf("%s%s%d", s.URL(), "/v2/keys/_etcd/registry/3/node1?wait=true&waitIndex=", testResp.EtcdIndex) 273 resp, err = http.Get(watch) 274 if err != nil { 275 t.Fatal(err.Error()) 276 } 277 278 // TODO(bp): need to have a better way of knowing a machine is up 279 for i := 0; i < 10; i++ { 280 time.Sleep(1 * time.Second) 281 282 etcdc := goetcd.NewClient(nil) 283 _, err = etcdc.Set("foobar", "baz", 0) 284 if err == nil { 285 break 286 } 287 } 288 289 if err != nil { 290 t.Fatal(err.Error()) 291 } 292 }) 293 } 294 295 func assertServerNotUp(client http.Client, scheme string) error { 296 path := fmt.Sprintf("%s://127.0.0.1:4001/v2/keys/foo", scheme) 297 fields := url.Values(map[string][]string{"value": []string{"bar"}}) 298 299 for i := 0; i < 10; i++ { 300 time.Sleep(1 * time.Second) 301 302 _, err := client.PostForm(path, fields) 303 if err == nil { 304 return errors.New("Expected error during POST, got nil") 305 } else { 306 errString := err.Error() 307 if strings.Contains(errString, "connection refused") { 308 return nil 309 } else { 310 return err 311 } 312 } 313 } 314 315 return nil 316 }