github.com/alpe/etcd@v0.1.2-0.20130915230056-09f31af88aeb/etcd_test.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "math/rand" 6 "net/http" 7 "net/http/httptest" 8 "net/url" 9 "os" 10 "strconv" 11 "strings" 12 "testing" 13 "time" 14 15 "github.com/coreos/etcd/test" 16 "github.com/coreos/go-etcd/etcd" 17 ) 18 19 // Create a single node and try to set value 20 func TestSingleNode(t *testing.T) { 21 procAttr := new(os.ProcAttr) 22 procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr} 23 args := []string{"etcd", "-n=node1", "-f", "-d=/tmp/node1"} 24 25 process, err := os.StartProcess("etcd", args, procAttr) 26 if err != nil { 27 t.Fatal("start process failed:" + err.Error()) 28 return 29 } 30 defer process.Kill() 31 32 time.Sleep(time.Second) 33 34 c := etcd.NewClient() 35 36 c.SyncCluster() 37 // Test Set 38 result, err := c.Set("foo", "bar", 100) 39 40 if err != nil || result.Key != "/foo" || result.Value != "bar" || result.TTL < 95 { 41 if err != nil { 42 t.Fatal(err) 43 } 44 45 t.Fatalf("Set 1 failed with %s %s %v", result.Key, result.Value, result.TTL) 46 } 47 48 time.Sleep(time.Second) 49 50 result, err = c.Set("foo", "bar", 100) 51 52 if err != nil || result.Key != "/foo" || result.Value != "bar" || result.PrevValue != "bar" || result.TTL != 99 { 53 if err != nil { 54 t.Fatal(err) 55 } 56 t.Fatalf("Set 2 failed with %s %s %v", result.Key, result.Value, result.TTL) 57 } 58 59 // Add a test-and-set test 60 61 // First, we'll test we can change the value if we get it write 62 result, match, err := c.TestAndSet("foo", "bar", "foobar", 100) 63 64 if err != nil || result.Key != "/foo" || result.Value != "foobar" || result.PrevValue != "bar" || result.TTL != 99 || !match { 65 if err != nil { 66 t.Fatal(err) 67 } 68 t.Fatalf("Set 3 failed with %s %s %v", result.Key, result.Value, result.TTL) 69 } 70 71 // Next, we'll make sure we can't set it without the correct prior value 72 _, _, err = c.TestAndSet("foo", "bar", "foofoo", 100) 73 74 if err == nil { 75 t.Fatalf("Set 4 expecting error when setting key with incorrect previous value") 76 } 77 78 // Finally, we'll make sure a blank previous value still counts as a test-and-set and still has to match 79 _, _, err = c.TestAndSet("foo", "", "barbar", 100) 80 81 if err == nil { 82 t.Fatalf("Set 5 expecting error when setting key with blank (incorrect) previous value") 83 } 84 } 85 86 // TestInternalVersionFail will ensure that etcd does not come up if the internal raft 87 // versions do not match. 88 func TestInternalVersionFail(t *testing.T) { 89 checkedVersion := false 90 testMux := http.NewServeMux() 91 92 testMux.HandleFunc("/version", func(w http.ResponseWriter, r *http.Request) { 93 fmt.Fprintln(w, "This is not a version number") 94 checkedVersion = true 95 }) 96 97 testMux.HandleFunc("/join", func(w http.ResponseWriter, r *http.Request) { 98 t.Fatal("should not attempt to join!") 99 }) 100 101 ts := httptest.NewServer(testMux) 102 defer ts.Close() 103 104 fakeURL, _ := url.Parse(ts.URL) 105 106 procAttr := new(os.ProcAttr) 107 procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr} 108 args := []string{"etcd", "-n=node1", "-f", "-d=/tmp/node1", "-vv", "-C=" + fakeURL.Host} 109 110 process, err := os.StartProcess("etcd", args, procAttr) 111 if err != nil { 112 t.Fatal("start process failed:" + err.Error()) 113 return 114 } 115 defer process.Kill() 116 117 time.Sleep(time.Second) 118 119 _, err = http.Get("http://127.0.0.1:4001") 120 121 if err == nil { 122 t.Fatal("etcd node should not be up") 123 return 124 } 125 126 if checkedVersion == false { 127 t.Fatal("etcd did not check the version") 128 return 129 } 130 } 131 132 // This test creates a single node and then set a value to it. 133 // Then this test kills the node and restart it and tries to get the value again. 134 func TestSingleNodeRecovery(t *testing.T) { 135 procAttr := new(os.ProcAttr) 136 procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr} 137 args := []string{"etcd", "-n=node1", "-d=/tmp/node1"} 138 139 process, err := os.StartProcess("etcd", append(args, "-f"), procAttr) 140 if err != nil { 141 t.Fatal("start process failed:" + err.Error()) 142 return 143 } 144 145 time.Sleep(time.Second) 146 147 c := etcd.NewClient() 148 149 c.SyncCluster() 150 // Test Set 151 result, err := c.Set("foo", "bar", 100) 152 153 if err != nil || result.Key != "/foo" || result.Value != "bar" || result.TTL < 95 { 154 if err != nil { 155 t.Fatal(err) 156 } 157 158 t.Fatalf("Set 1 failed with %s %s %v", result.Key, result.Value, result.TTL) 159 } 160 161 time.Sleep(time.Second) 162 163 process.Kill() 164 165 process, err = os.StartProcess("etcd", args, procAttr) 166 defer process.Kill() 167 if err != nil { 168 t.Fatal("start process failed:" + err.Error()) 169 return 170 } 171 172 time.Sleep(time.Second) 173 174 results, err := c.Get("foo") 175 if err != nil { 176 t.Fatal("get fail: " + err.Error()) 177 return 178 } 179 180 result = results[0] 181 182 if err != nil || result.Key != "/foo" || result.Value != "bar" || result.TTL > 99 { 183 if err != nil { 184 t.Fatal(err) 185 } 186 t.Fatalf("Recovery Get failed with %s %s %v", result.Key, result.Value, result.TTL) 187 } 188 } 189 190 // Create a three nodes and try to set value 191 func templateTestSimpleMultiNode(t *testing.T, tls bool) { 192 procAttr := new(os.ProcAttr) 193 procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr} 194 195 clusterSize := 3 196 197 _, etcds, err := test.CreateCluster(clusterSize, procAttr, tls) 198 199 if err != nil { 200 t.Fatal("cannot create cluster") 201 } 202 203 defer test.DestroyCluster(etcds) 204 205 time.Sleep(time.Second) 206 207 c := etcd.NewClient() 208 209 c.SyncCluster() 210 211 // Test Set 212 result, err := c.Set("foo", "bar", 100) 213 214 if err != nil || result.Key != "/foo" || result.Value != "bar" || result.TTL < 95 { 215 if err != nil { 216 t.Fatal(err) 217 } 218 219 t.Fatalf("Set 1 failed with %s %s %v", result.Key, result.Value, result.TTL) 220 } 221 222 time.Sleep(time.Second) 223 224 result, err = c.Set("foo", "bar", 100) 225 226 if err != nil || result.Key != "/foo" || result.Value != "bar" || result.PrevValue != "bar" || result.TTL != 99 { 227 if err != nil { 228 t.Fatal(err) 229 } 230 t.Fatalf("Set 2 failed with %s %s %v", result.Key, result.Value, result.TTL) 231 } 232 233 } 234 235 func TestSimpleMultiNode(t *testing.T) { 236 templateTestSimpleMultiNode(t, false) 237 } 238 239 func TestSimpleMultiNodeTls(t *testing.T) { 240 templateTestSimpleMultiNode(t, true) 241 } 242 243 // Create a five nodes 244 // Kill all the nodes and restart 245 func TestMultiNodeKillAllAndRecovery(t *testing.T) { 246 procAttr := new(os.ProcAttr) 247 procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr} 248 249 clusterSize := 5 250 argGroup, etcds, err := test.CreateCluster(clusterSize, procAttr, false) 251 252 if err != nil { 253 t.Fatal("cannot create cluster") 254 } 255 256 c := etcd.NewClient() 257 258 c.SyncCluster() 259 260 time.Sleep(time.Second) 261 262 // send 10 commands 263 for i := 0; i < 10; i++ { 264 // Test Set 265 _, err := c.Set("foo", "bar", 0) 266 if err != nil { 267 panic(err) 268 } 269 } 270 271 time.Sleep(time.Second) 272 273 // kill all 274 test.DestroyCluster(etcds) 275 276 time.Sleep(time.Second) 277 278 stop := make(chan bool) 279 leaderChan := make(chan string, 1) 280 all := make(chan bool, 1) 281 282 time.Sleep(time.Second) 283 284 for i := 0; i < clusterSize; i++ { 285 etcds[i], err = os.StartProcess("etcd", argGroup[i], procAttr) 286 } 287 288 go test.Monitor(clusterSize, 1, leaderChan, all, stop) 289 290 <-all 291 <-leaderChan 292 293 result, err := c.Set("foo", "bar", 0) 294 295 if err != nil { 296 panic(err) 297 } 298 299 if result.Index != 18 { 300 t.Fatalf("recovery failed! [%d/18]", result.Index) 301 } 302 303 // kill all 304 test.DestroyCluster(etcds) 305 } 306 307 // Create a five nodes 308 // Randomly kill one of the node and keep on sending set command to the cluster 309 func TestMultiNodeKillOne(t *testing.T) { 310 procAttr := new(os.ProcAttr) 311 procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr} 312 313 clusterSize := 5 314 argGroup, etcds, err := test.CreateCluster(clusterSize, procAttr, false) 315 316 if err != nil { 317 t.Fatal("cannot create cluster") 318 } 319 320 defer test.DestroyCluster(etcds) 321 322 time.Sleep(2 * time.Second) 323 324 c := etcd.NewClient() 325 326 c.SyncCluster() 327 328 stop := make(chan bool) 329 // Test Set 330 go test.Set(stop) 331 332 for i := 0; i < 10; i++ { 333 num := rand.Int() % clusterSize 334 fmt.Println("kill node", num+1) 335 336 // kill 337 etcds[num].Kill() 338 etcds[num].Release() 339 time.Sleep(time.Second) 340 341 // restart 342 etcds[num], err = os.StartProcess("etcd", argGroup[num], procAttr) 343 if err != nil { 344 panic(err) 345 } 346 time.Sleep(time.Second) 347 } 348 fmt.Println("stop") 349 stop <- true 350 <-stop 351 } 352 353 // This test will kill the current leader and wait for the etcd cluster to elect a new leader for 200 times. 354 // It will print out the election time and the average election time. 355 func TestKillLeader(t *testing.T) { 356 procAttr := new(os.ProcAttr) 357 procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr} 358 359 clusterSize := 5 360 argGroup, etcds, err := test.CreateCluster(clusterSize, procAttr, false) 361 362 if err != nil { 363 t.Fatal("cannot create cluster") 364 } 365 366 defer test.DestroyCluster(etcds) 367 368 stop := make(chan bool) 369 leaderChan := make(chan string, 1) 370 all := make(chan bool, 1) 371 372 time.Sleep(time.Second) 373 374 go test.Monitor(clusterSize, 1, leaderChan, all, stop) 375 376 var totalTime time.Duration 377 378 leader := "http://127.0.0.1:7001" 379 380 for i := 0; i < clusterSize; i++ { 381 fmt.Println("leader is ", leader) 382 port, _ := strconv.Atoi(strings.Split(leader, ":")[2]) 383 num := port - 7001 384 fmt.Println("kill server ", num) 385 etcds[num].Kill() 386 etcds[num].Release() 387 388 start := time.Now() 389 for { 390 newLeader := <-leaderChan 391 if newLeader != leader { 392 leader = newLeader 393 break 394 } 395 } 396 take := time.Now().Sub(start) 397 398 totalTime += take 399 avgTime := totalTime / (time.Duration)(i+1) 400 401 fmt.Println("Leader election time is ", take, "with election timeout", ElectionTimeout) 402 fmt.Println("Leader election time average is", avgTime, "with election timeout", ElectionTimeout) 403 etcds[num], err = os.StartProcess("etcd", argGroup[num], procAttr) 404 } 405 stop <- true 406 } 407 408 // TestKillRandom kills random machines in the cluster and 409 // restart them after all other machines agree on the same leader 410 func TestKillRandom(t *testing.T) { 411 procAttr := new(os.ProcAttr) 412 procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr} 413 414 clusterSize := 9 415 argGroup, etcds, err := test.CreateCluster(clusterSize, procAttr, false) 416 417 if err != nil { 418 t.Fatal("cannot create cluster") 419 } 420 421 defer test.DestroyCluster(etcds) 422 423 stop := make(chan bool) 424 leaderChan := make(chan string, 1) 425 all := make(chan bool, 1) 426 427 time.Sleep(3 * time.Second) 428 429 go test.Monitor(clusterSize, 4, leaderChan, all, stop) 430 431 toKill := make(map[int]bool) 432 433 for i := 0; i < 20; i++ { 434 fmt.Printf("TestKillRandom Round[%d/20]\n", i) 435 436 j := 0 437 for { 438 439 r := rand.Int31n(9) 440 if _, ok := toKill[int(r)]; !ok { 441 j++ 442 toKill[int(r)] = true 443 } 444 445 if j > 3 { 446 break 447 } 448 449 } 450 451 for num, _ := range toKill { 452 err := etcds[num].Kill() 453 if err != nil { 454 panic(err) 455 } 456 etcds[num].Wait() 457 } 458 459 time.Sleep(ElectionTimeout) 460 461 <-leaderChan 462 463 for num, _ := range toKill { 464 etcds[num], err = os.StartProcess("etcd", argGroup[num], procAttr) 465 } 466 467 toKill = make(map[int]bool) 468 <-all 469 } 470 471 stop <- true 472 } 473 474 // remove the node and node rejoin with previous log 475 func TestRemoveNode(t *testing.T) { 476 procAttr := new(os.ProcAttr) 477 procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr} 478 479 clusterSize := 3 480 argGroup, etcds, _ := test.CreateCluster(clusterSize, procAttr, false) 481 482 time.Sleep(time.Second) 483 484 c := etcd.NewClient() 485 486 c.SyncCluster() 487 488 rmReq, _ := http.NewRequest("DELETE", "http://127.0.0.1:7001/remove/node3", nil) 489 490 client := &http.Client{} 491 for i := 0; i < 2; i++ { 492 for i := 0; i < 2; i++ { 493 client.Do(rmReq) 494 495 etcds[2].Wait() 496 497 resp, err := c.Get("_etcd/machines") 498 499 if err != nil { 500 panic(err) 501 } 502 503 if len(resp) != 2 { 504 t.Fatal("cannot remove machine") 505 } 506 507 if i == 1 { 508 // rejoin with log 509 etcds[2], err = os.StartProcess("etcd", argGroup[2], procAttr) 510 } else { 511 // rejoin without log 512 etcds[2], err = os.StartProcess("etcd", append(argGroup[2], "-f"), procAttr) 513 } 514 515 if err != nil { 516 panic(err) 517 } 518 519 time.Sleep(time.Second) 520 521 resp, err = c.Get("_etcd/machines") 522 523 if err != nil { 524 panic(err) 525 } 526 527 if len(resp) != 3 { 528 t.Fatal("add machine fails") 529 } 530 } 531 532 // first kill the node, then remove it, then add it back 533 for i := 0; i < 2; i++ { 534 etcds[2].Kill() 535 etcds[2].Wait() 536 537 client.Do(rmReq) 538 539 resp, err := c.Get("_etcd/machines") 540 541 if err != nil { 542 panic(err) 543 } 544 545 if len(resp) != 2 { 546 t.Fatal("cannot remove machine") 547 } 548 549 if i == 1 { 550 // rejoin with log 551 etcds[2], err = os.StartProcess("etcd", append(argGroup[2]), procAttr) 552 } else { 553 // rejoin without log 554 etcds[2], err = os.StartProcess("etcd", append(argGroup[2], "-f"), procAttr) 555 } 556 557 if err != nil { 558 panic(err) 559 } 560 561 time.Sleep(time.Second) 562 563 resp, err = c.Get("_etcd/machines") 564 565 if err != nil { 566 panic(err) 567 } 568 569 if len(resp) != 3 { 570 t.Fatal("add machine fails") 571 } 572 } 573 } 574 test.DestroyCluster(etcds) 575 576 } 577 578 func templateBenchmarkEtcdDirectCall(b *testing.B, tls bool) { 579 procAttr := new(os.ProcAttr) 580 procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr} 581 582 clusterSize := 3 583 _, etcds, _ := test.CreateCluster(clusterSize, procAttr, tls) 584 585 defer test.DestroyCluster(etcds) 586 587 time.Sleep(time.Second) 588 589 b.ResetTimer() 590 for i := 0; i < b.N; i++ { 591 resp, _ := http.Get("http://127.0.0.1:4001/test/speed") 592 resp.Body.Close() 593 } 594 595 } 596 597 func BenchmarkEtcdDirectCall(b *testing.B) { 598 templateBenchmarkEtcdDirectCall(b, false) 599 } 600 601 func BenchmarkEtcdDirectCallTls(b *testing.B) { 602 templateBenchmarkEtcdDirectCall(b, true) 603 }