discovery_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. /*
  2. Copyright 2014 CoreOS, Inc.
  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. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package discovery
  14. import (
  15. "errors"
  16. "math/rand"
  17. "net/http"
  18. "os"
  19. "sort"
  20. "strconv"
  21. "reflect"
  22. "testing"
  23. "time"
  24. "github.com/coreos/etcd/Godeps/_workspace/src/github.com/jonboulle/clockwork"
  25. "github.com/coreos/etcd/client"
  26. )
  27. func TestProxyFuncFromEnvUnset(t *testing.T) {
  28. os.Setenv(DiscoveryProxyEnv, "")
  29. pf, err := proxyFuncFromEnv()
  30. if pf != nil {
  31. t.Fatal("unexpected non-nil proxyFunc")
  32. }
  33. if err != nil {
  34. t.Fatalf("unexpected non-nil err: %v", err)
  35. }
  36. }
  37. func TestProxyFuncFromEnvBad(t *testing.T) {
  38. tests := []string{
  39. "%%",
  40. "http://foo.com/%1",
  41. }
  42. for i, in := range tests {
  43. os.Setenv(DiscoveryProxyEnv, in)
  44. pf, err := proxyFuncFromEnv()
  45. if pf != nil {
  46. t.Errorf("#%d: unexpected non-nil proxyFunc", i)
  47. }
  48. if err == nil {
  49. t.Errorf("#%d: unexpected nil err", i)
  50. }
  51. }
  52. }
  53. func TestProxyFuncFromEnv(t *testing.T) {
  54. tests := map[string]string{
  55. "bar.com": "http://bar.com",
  56. "http://disco.foo.bar": "http://disco.foo.bar",
  57. }
  58. for in, w := range tests {
  59. os.Setenv(DiscoveryProxyEnv, in)
  60. pf, err := proxyFuncFromEnv()
  61. if pf == nil {
  62. t.Errorf("%s: unexpected nil proxyFunc", in)
  63. continue
  64. }
  65. if err != nil {
  66. t.Errorf("%s: unexpected non-nil err: %v", in, err)
  67. continue
  68. }
  69. g, err := pf(&http.Request{})
  70. if err != nil {
  71. t.Errorf("%s: unexpected non-nil err: %v", in, err)
  72. }
  73. if g.String() != w {
  74. t.Errorf("%s: proxyURL=%q, want %q", g, w)
  75. }
  76. }
  77. }
  78. func TestCheckCluster(t *testing.T) {
  79. cluster := "1000"
  80. self := "/1000/1"
  81. tests := []struct {
  82. nodes []*client.Node
  83. werr error
  84. wsize int
  85. }{
  86. {
  87. // self is in the size range
  88. client.Nodes{
  89. {Key: "/1000/_config/size", Value: "3", CreatedIndex: 1},
  90. {Key: self, CreatedIndex: 2},
  91. {Key: "/1000/2", CreatedIndex: 3},
  92. {Key: "/1000/3", CreatedIndex: 4},
  93. {Key: "/1000/4", CreatedIndex: 5},
  94. },
  95. nil,
  96. 3,
  97. },
  98. {
  99. // self is in the size range
  100. client.Nodes{
  101. {Key: "/1000/_config/size", Value: "3", CreatedIndex: 1},
  102. {Key: "/1000/2", CreatedIndex: 2},
  103. {Key: "/1000/3", CreatedIndex: 3},
  104. {Key: self, CreatedIndex: 4},
  105. {Key: "/1000/4", CreatedIndex: 5},
  106. },
  107. nil,
  108. 3,
  109. },
  110. {
  111. // self is out of the size range
  112. client.Nodes{
  113. {Key: "/1000/_config/size", Value: "3", CreatedIndex: 1},
  114. {Key: "/1000/2", CreatedIndex: 2},
  115. {Key: "/1000/3", CreatedIndex: 3},
  116. {Key: "/1000/4", CreatedIndex: 4},
  117. {Key: self, CreatedIndex: 5},
  118. },
  119. ErrFullCluster,
  120. 3,
  121. },
  122. {
  123. // self is not in the cluster
  124. client.Nodes{
  125. {Key: "/1000/_config/size", Value: "3", CreatedIndex: 1},
  126. {Key: "/1000/2", CreatedIndex: 2},
  127. {Key: "/1000/3", CreatedIndex: 3},
  128. },
  129. nil,
  130. 3,
  131. },
  132. {
  133. client.Nodes{
  134. {Key: "/1000/_config/size", Value: "3", CreatedIndex: 1},
  135. {Key: "/1000/2", CreatedIndex: 2},
  136. {Key: "/1000/3", CreatedIndex: 3},
  137. {Key: "/1000/4", CreatedIndex: 4},
  138. },
  139. ErrFullCluster,
  140. 3,
  141. },
  142. {
  143. // bad size key
  144. client.Nodes{
  145. {Key: "/1000/_config/size", Value: "bad", CreatedIndex: 1},
  146. },
  147. ErrBadSizeKey,
  148. 0,
  149. },
  150. {
  151. // no size key
  152. client.Nodes{},
  153. ErrSizeNotFound,
  154. 0,
  155. },
  156. }
  157. for i, tt := range tests {
  158. rs := make([]*client.Response, 0)
  159. if len(tt.nodes) > 0 {
  160. rs = append(rs, &client.Response{Node: tt.nodes[0]})
  161. rs = append(rs, &client.Response{
  162. Node: &client.Node{
  163. Key: cluster,
  164. Nodes: tt.nodes,
  165. },
  166. })
  167. }
  168. c := &clientWithResp{rs: rs}
  169. d := discovery{cluster: cluster, id: 1, c: c}
  170. cRetry := &clientWithRetry{failTimes: 3}
  171. cRetry.rs = rs
  172. fc := clockwork.NewFakeClock()
  173. dRetry := discovery{cluster: cluster, id: 1, c: cRetry, clock: fc}
  174. for _, d := range []discovery{d, dRetry} {
  175. go func() {
  176. for i := uint(1); i <= nRetries; i++ {
  177. fc.BlockUntil(1)
  178. fc.Advance(time.Second * (0x1 << i))
  179. }
  180. }()
  181. ns, size, err := d.checkCluster()
  182. if err != tt.werr {
  183. t.Errorf("#%d: err = %v, want %v", i, err, tt.werr)
  184. }
  185. if reflect.DeepEqual(ns, tt.nodes) {
  186. t.Errorf("#%d: nodes = %v, want %v", i, ns, tt.nodes)
  187. }
  188. if size != tt.wsize {
  189. t.Errorf("#%d: size = %v, want %d", i, size, tt.wsize)
  190. }
  191. }
  192. }
  193. }
  194. func TestWaitNodes(t *testing.T) {
  195. all := client.Nodes{
  196. {Key: "/1000/1", CreatedIndex: 2},
  197. {Key: "/1000/2", CreatedIndex: 3},
  198. {Key: "/1000/3", CreatedIndex: 4},
  199. }
  200. tests := []struct {
  201. nodes client.Nodes
  202. rs []*client.Response
  203. }{
  204. {
  205. all,
  206. []*client.Response{},
  207. },
  208. {
  209. all[:1],
  210. []*client.Response{
  211. {Node: &client.Node{Key: "/1000/2", CreatedIndex: 3}},
  212. {Node: &client.Node{Key: "/1000/3", CreatedIndex: 4}},
  213. },
  214. },
  215. {
  216. all[:2],
  217. []*client.Response{
  218. {Node: &client.Node{Key: "/1000/3", CreatedIndex: 4}},
  219. },
  220. },
  221. {
  222. append(all, &client.Node{Key: "/1000/4", CreatedIndex: 5}),
  223. []*client.Response{
  224. {Node: &client.Node{Key: "/1000/3", CreatedIndex: 4}},
  225. },
  226. },
  227. }
  228. for i, tt := range tests {
  229. // Basic case
  230. c := &clientWithResp{nil, &watcherWithResp{tt.rs}}
  231. d := &discovery{cluster: "1000", c: c}
  232. // Retry case
  233. retryScanResp := make([]*client.Response, 0)
  234. if len(tt.nodes) > 0 {
  235. retryScanResp = append(retryScanResp, &client.Response{
  236. Node: &client.Node{
  237. Key: "1000",
  238. Value: strconv.Itoa(3),
  239. },
  240. })
  241. retryScanResp = append(retryScanResp, &client.Response{
  242. Node: &client.Node{
  243. Nodes: tt.nodes,
  244. },
  245. })
  246. }
  247. cRetry := &clientWithResp{
  248. rs: retryScanResp,
  249. w: &watcherWithRetry{rs: tt.rs, failTimes: 2},
  250. }
  251. fc := clockwork.NewFakeClock()
  252. dRetry := &discovery{
  253. cluster: "1000",
  254. c: cRetry,
  255. clock: fc,
  256. }
  257. for _, d := range []*discovery{d, dRetry} {
  258. go func() {
  259. for i := uint(1); i <= nRetries; i++ {
  260. fc.BlockUntil(1)
  261. fc.Advance(time.Second * (0x1 << i))
  262. }
  263. }()
  264. g, err := d.waitNodes(tt.nodes, 3)
  265. if err != nil {
  266. t.Errorf("#%d: err = %v, want %v", i, err, nil)
  267. }
  268. if !reflect.DeepEqual(g, all) {
  269. t.Errorf("#%d: all = %v, want %v", i, g, all)
  270. }
  271. }
  272. }
  273. }
  274. func TestCreateSelf(t *testing.T) {
  275. rs := []*client.Response{{Node: &client.Node{Key: "1000/1", CreatedIndex: 2}}}
  276. w := &watcherWithResp{rs}
  277. errw := &watcherWithErr{errors.New("watch err")}
  278. c := &clientWithResp{rs, w}
  279. errc := &clientWithErr{errors.New("create err"), w}
  280. errwc := &clientWithResp{rs, errw}
  281. tests := []struct {
  282. c client.Client
  283. werr error
  284. }{
  285. // no error
  286. {c, nil},
  287. // client.create returns an error
  288. {errc, errc.err},
  289. // watcher.next retuens an error
  290. {errwc, errw.err},
  291. }
  292. for i, tt := range tests {
  293. d := discovery{cluster: "1000", c: tt.c}
  294. if err := d.createSelf(); err != tt.werr {
  295. t.Errorf("#%d: err = %v, want %v", i, err, nil)
  296. }
  297. }
  298. }
  299. func TestNodesToCluster(t *testing.T) {
  300. nodes := client.Nodes{
  301. {Key: "/1000/1", Value: "1=1.1.1.1", CreatedIndex: 1},
  302. {Key: "/1000/2", Value: "2=2.2.2.2", CreatedIndex: 2},
  303. {Key: "/1000/3", Value: "3=3.3.3.3", CreatedIndex: 3},
  304. }
  305. w := "1=1.1.1.1,2=2.2.2.2,3=3.3.3.3"
  306. cluster := nodesToCluster(nodes)
  307. if !reflect.DeepEqual(cluster, w) {
  308. t.Errorf("cluster = %v, want %v", cluster, w)
  309. }
  310. }
  311. func TestSortableNodes(t *testing.T) {
  312. ns := client.Nodes{
  313. {CreatedIndex: 5},
  314. {CreatedIndex: 1},
  315. {CreatedIndex: 3},
  316. {CreatedIndex: 4},
  317. }
  318. // add some randomness
  319. for i := 0; i < 10000; i++ {
  320. ns = append(ns, &client.Node{CreatedIndex: uint64(rand.Int31())})
  321. }
  322. sns := sortableNodes{ns}
  323. sort.Sort(sns)
  324. cis := make([]int, 0)
  325. for _, n := range sns.Nodes {
  326. cis = append(cis, int(n.CreatedIndex))
  327. }
  328. if sort.IntsAreSorted(cis) != true {
  329. t.Errorf("isSorted = %v, want %v", sort.IntsAreSorted(cis), true)
  330. }
  331. cis = make([]int, 0)
  332. for _, n := range ns {
  333. cis = append(cis, int(n.CreatedIndex))
  334. }
  335. if sort.IntsAreSorted(cis) != true {
  336. t.Errorf("isSorted = %v, want %v", sort.IntsAreSorted(cis), true)
  337. }
  338. }
  339. func TestRetryFailure(t *testing.T) {
  340. cluster := "1000"
  341. c := &clientWithRetry{failTimes: 4}
  342. fc := clockwork.NewFakeClock()
  343. d := discovery{
  344. cluster: cluster,
  345. id: 1,
  346. c: c,
  347. clock: fc,
  348. }
  349. go func() {
  350. for i := uint(1); i <= nRetries; i++ {
  351. fc.BlockUntil(1)
  352. fc.Advance(time.Second * (0x1 << i))
  353. }
  354. }()
  355. if _, _, err := d.checkCluster(); err != ErrTooManyRetries {
  356. t.Errorf("err = %v, want %v", err, ErrTooManyRetries)
  357. }
  358. }
  359. type clientWithResp struct {
  360. rs []*client.Response
  361. w client.Watcher
  362. }
  363. func (c *clientWithResp) Create(key string, value string, ttl time.Duration) (*client.Response, error) {
  364. if len(c.rs) == 0 {
  365. return &client.Response{}, nil
  366. }
  367. r := c.rs[0]
  368. c.rs = c.rs[1:]
  369. return r, nil
  370. }
  371. func (c *clientWithResp) Get(key string) (*client.Response, error) {
  372. if len(c.rs) == 0 {
  373. return &client.Response{}, client.ErrKeyNoExist
  374. }
  375. r := c.rs[0]
  376. c.rs = append(c.rs[1:], r)
  377. return r, nil
  378. }
  379. func (c *clientWithResp) Watch(key string, waitIndex uint64) client.Watcher {
  380. return c.w
  381. }
  382. func (c *clientWithResp) RecursiveWatch(key string, waitIndex uint64) client.Watcher {
  383. return c.w
  384. }
  385. type clientWithErr struct {
  386. err error
  387. w client.Watcher
  388. }
  389. func (c *clientWithErr) Create(key string, value string, ttl time.Duration) (*client.Response, error) {
  390. return &client.Response{}, c.err
  391. }
  392. func (c *clientWithErr) Get(key string) (*client.Response, error) {
  393. return &client.Response{}, c.err
  394. }
  395. func (c *clientWithErr) Watch(key string, waitIndex uint64) client.Watcher {
  396. return c.w
  397. }
  398. func (c *clientWithErr) RecursiveWatch(key string, waitIndex uint64) client.Watcher {
  399. return c.w
  400. }
  401. type watcherWithResp struct {
  402. rs []*client.Response
  403. }
  404. func (w *watcherWithResp) Next() (*client.Response, error) {
  405. if len(w.rs) == 0 {
  406. return &client.Response{}, nil
  407. }
  408. r := w.rs[0]
  409. w.rs = w.rs[1:]
  410. return r, nil
  411. }
  412. type watcherWithErr struct {
  413. err error
  414. }
  415. func (w *watcherWithErr) Next() (*client.Response, error) {
  416. return &client.Response{}, w.err
  417. }
  418. // clientWithRetry will timeout all requests up to failTimes
  419. type clientWithRetry struct {
  420. clientWithResp
  421. failCount int
  422. failTimes int
  423. }
  424. func (c *clientWithRetry) Create(key string, value string, ttl time.Duration) (*client.Response, error) {
  425. if c.failCount < c.failTimes {
  426. c.failCount++
  427. return nil, client.ErrTimeout
  428. }
  429. return c.clientWithResp.Create(key, value, ttl)
  430. }
  431. func (c *clientWithRetry) Get(key string) (*client.Response, error) {
  432. if c.failCount < c.failTimes {
  433. c.failCount++
  434. return nil, client.ErrTimeout
  435. }
  436. return c.clientWithResp.Get(key)
  437. }
  438. // watcherWithRetry will timeout all requests up to failTimes
  439. type watcherWithRetry struct {
  440. rs []*client.Response
  441. failCount int
  442. failTimes int
  443. }
  444. func (w *watcherWithRetry) Next() (*client.Response, error) {
  445. if w.failCount < w.failTimes {
  446. w.failCount++
  447. return nil, client.ErrTimeout
  448. }
  449. if len(w.rs) == 0 {
  450. return &client.Response{}, nil
  451. }
  452. r := w.rs[0]
  453. w.rs = w.rs[1:]
  454. return r, nil
  455. }