etcd_test.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. package etcd
  2. import (
  3. "fmt"
  4. "net/http"
  5. "net/http/httptest"
  6. "net/url"
  7. "runtime"
  8. "testing"
  9. "time"
  10. "github.com/coreos/etcd/config"
  11. )
  12. func TestMultipleNodes(t *testing.T) {
  13. tests := []int{1, 3, 5, 9, 11}
  14. for _, tt := range tests {
  15. es, hs := buildCluster(tt, false)
  16. waitCluster(t, es)
  17. for i := range es {
  18. es[len(es)-i-1].Stop()
  19. }
  20. for i := range hs {
  21. hs[len(hs)-i-1].Close()
  22. }
  23. }
  24. afterTest(t)
  25. }
  26. func TestMultipleTLSNodes(t *testing.T) {
  27. tests := []int{1, 3, 5}
  28. for _, tt := range tests {
  29. es, hs := buildCluster(tt, true)
  30. waitCluster(t, es)
  31. for i := range es {
  32. es[len(es)-i-1].Stop()
  33. }
  34. for i := range hs {
  35. hs[len(hs)-i-1].Close()
  36. }
  37. }
  38. afterTest(t)
  39. }
  40. func TestV2Redirect(t *testing.T) {
  41. es, hs := buildCluster(3, false)
  42. waitCluster(t, es)
  43. u := hs[1].URL
  44. ru := fmt.Sprintf("%s%s", hs[0].URL, "/v2/keys/foo")
  45. tc := NewTestClient()
  46. v := url.Values{}
  47. v.Set("value", "XXX")
  48. resp, _ := tc.PutForm(fmt.Sprintf("%s%s", u, "/v2/keys/foo"), v)
  49. if resp.StatusCode != http.StatusTemporaryRedirect {
  50. t.Errorf("status = %d, want %d", resp.StatusCode, http.StatusTemporaryRedirect)
  51. }
  52. location, err := resp.Location()
  53. if err != nil {
  54. t.Errorf("want err = %, want nil", err)
  55. }
  56. if location.String() != ru {
  57. t.Errorf("location = %v, want %v", location.String(), ru)
  58. }
  59. resp.Body.Close()
  60. for i := range es {
  61. es[len(es)-i-1].Stop()
  62. }
  63. for i := range hs {
  64. hs[len(hs)-i-1].Close()
  65. }
  66. afterTest(t)
  67. }
  68. func TestAdd(t *testing.T) {
  69. tests := []struct {
  70. size int
  71. round int
  72. }{
  73. {3, 5},
  74. {4, 5},
  75. {5, 5},
  76. {6, 5},
  77. }
  78. for _, tt := range tests {
  79. es := make([]*Server, tt.size)
  80. hs := make([]*httptest.Server, tt.size)
  81. for i := 0; i < tt.size; i++ {
  82. c := config.New()
  83. if i > 0 {
  84. c.Peers = []string{hs[0].URL}
  85. }
  86. es[i], hs[i] = initTestServer(c, int64(i), false)
  87. }
  88. go es[0].Bootstrap()
  89. for i := 1; i < tt.size; i++ {
  90. var index uint64
  91. for {
  92. lead := es[0].node.Leader()
  93. if lead != -1 {
  94. index = es[lead].Index()
  95. ne := es[i]
  96. if err := es[lead].Add(ne.id, ne.raftPubAddr, ne.pubAddr); err == nil {
  97. break
  98. }
  99. }
  100. runtime.Gosched()
  101. }
  102. go es[i].run()
  103. for j := 0; j <= i; j++ {
  104. w, err := es[j].Watch(v2machineKVPrefix, true, false, index+1)
  105. if err != nil {
  106. t.Errorf("#%d on %d: %v", i, j, err)
  107. break
  108. }
  109. v := <-w.EventChan
  110. ww := fmt.Sprintf("%s/%d", v2machineKVPrefix, i)
  111. if v.Node.Key != ww {
  112. t.Errorf("#%d on %d: path = %v, want %v", i, j, v.Node.Key, ww)
  113. }
  114. }
  115. }
  116. for i := range hs {
  117. es[len(hs)-i-1].Stop()
  118. }
  119. for i := range hs {
  120. hs[len(hs)-i-1].Close()
  121. }
  122. }
  123. afterTest(t)
  124. }
  125. func TestRemove(t *testing.T) {
  126. tests := []int{3, 4, 5, 6}
  127. for _, tt := range tests {
  128. es, hs := buildCluster(tt, false)
  129. waitCluster(t, es)
  130. // we don't remove the machine from 2-node cluster because it is
  131. // not 100 percent safe in our raft.
  132. // TODO(yichengq): improve it later.
  133. for i := 0; i < tt-2; i++ {
  134. id := int64(i)
  135. send := id
  136. for {
  137. send++
  138. if send > int64(tt-1) {
  139. send = id
  140. }
  141. lead := es[send].node.Leader()
  142. if lead == -1 {
  143. time.Sleep(defaultElection * 5 * time.Millisecond)
  144. continue
  145. }
  146. err := es[lead].Remove(id)
  147. if err == nil {
  148. break
  149. }
  150. switch err {
  151. case removeTmpErr:
  152. time.Sleep(defaultElection * 5 * time.Millisecond)
  153. case serverStopErr:
  154. if lead == id {
  155. break
  156. }
  157. default:
  158. t.Fatal(err)
  159. }
  160. }
  161. <-es[i].stop
  162. }
  163. for i := range es {
  164. es[len(hs)-i-1].Stop()
  165. }
  166. for i := range hs {
  167. hs[len(hs)-i-1].Close()
  168. }
  169. }
  170. afterTest(t)
  171. }
  172. func buildCluster(number int, tls bool) ([]*Server, []*httptest.Server) {
  173. bootstrapper := 0
  174. es := make([]*Server, number)
  175. hs := make([]*httptest.Server, number)
  176. var seed string
  177. for i := range es {
  178. c := config.New()
  179. c.Peers = []string{seed}
  180. es[i], hs[i] = initTestServer(c, int64(i), tls)
  181. if i == bootstrapper {
  182. seed = hs[i].URL
  183. go es[i].Bootstrap()
  184. } else {
  185. // wait for the previous configuration change to be committed
  186. // or this configuration request might be dropped
  187. w, err := es[0].Watch(v2machineKVPrefix, true, false, uint64(i))
  188. if err != nil {
  189. panic(err)
  190. }
  191. <-w.EventChan
  192. go es[i].Join()
  193. }
  194. }
  195. return es, hs
  196. }
  197. func initTestServer(c *config.Config, id int64, tls bool) (e *Server, h *httptest.Server) {
  198. e = New(c, id)
  199. e.SetTick(time.Millisecond * 5)
  200. m := http.NewServeMux()
  201. m.Handle("/", e)
  202. m.Handle("/raft", e.t)
  203. m.Handle("/raft/", e.t)
  204. if tls {
  205. h = httptest.NewTLSServer(m)
  206. } else {
  207. h = httptest.NewServer(m)
  208. }
  209. e.raftPubAddr = h.URL
  210. e.pubAddr = h.URL
  211. return
  212. }
  213. func waitCluster(t *testing.T, es []*Server) {
  214. n := len(es)
  215. for i, e := range es {
  216. var index uint64
  217. for k := 0; k < n; k++ {
  218. index++
  219. w, err := e.Watch(v2machineKVPrefix, true, false, index)
  220. if err != nil {
  221. panic(err)
  222. }
  223. v := <-w.EventChan
  224. // join command may appear several times due to retry
  225. // when timeout
  226. if k > 0 {
  227. pw := fmt.Sprintf("%s/%d", v2machineKVPrefix, k-1)
  228. if v.Node.Key == pw {
  229. continue
  230. }
  231. }
  232. ww := fmt.Sprintf("%s/%d", v2machineKVPrefix, k)
  233. if v.Node.Key != ww {
  234. t.Errorf("#%d path = %v, want %v", i, v.Node.Key, ww)
  235. }
  236. }
  237. }
  238. }