discovery_test.go 11 KB

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