discovery_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  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", in, g, w)
  75. }
  76. }
  77. }
  78. func TestCheckCluster(t *testing.T) {
  79. cluster := "/prefix/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.Node{
  89. {Key: "/1000/_config/size", Value: "3", CreatedIndex: 1},
  90. {Key: "/1000/_config/"},
  91. {Key: self, CreatedIndex: 2},
  92. {Key: "/1000/2", CreatedIndex: 3},
  93. {Key: "/1000/3", CreatedIndex: 4},
  94. {Key: "/1000/4", CreatedIndex: 5},
  95. },
  96. nil,
  97. 3,
  98. },
  99. {
  100. // self is in the size range
  101. []*client.Node{
  102. {Key: "/1000/_config/size", Value: "3", CreatedIndex: 1},
  103. {Key: "/1000/_config/"},
  104. {Key: "/1000/2", CreatedIndex: 2},
  105. {Key: "/1000/3", CreatedIndex: 3},
  106. {Key: self, CreatedIndex: 4},
  107. {Key: "/1000/4", CreatedIndex: 5},
  108. },
  109. nil,
  110. 3,
  111. },
  112. {
  113. // self is out of the size range
  114. []*client.Node{
  115. {Key: "/1000/_config/size", Value: "3", CreatedIndex: 1},
  116. {Key: "/1000/_config/"},
  117. {Key: "/1000/2", CreatedIndex: 2},
  118. {Key: "/1000/3", CreatedIndex: 3},
  119. {Key: "/1000/4", CreatedIndex: 4},
  120. {Key: self, CreatedIndex: 5},
  121. },
  122. ErrFullCluster,
  123. 3,
  124. },
  125. {
  126. // self is not in the cluster
  127. []*client.Node{
  128. {Key: "/1000/_config/size", Value: "3", CreatedIndex: 1},
  129. {Key: "/1000/_config/"},
  130. {Key: "/1000/2", CreatedIndex: 2},
  131. {Key: "/1000/3", CreatedIndex: 3},
  132. },
  133. nil,
  134. 3,
  135. },
  136. {
  137. []*client.Node{
  138. {Key: "/1000/_config/size", Value: "3", CreatedIndex: 1},
  139. {Key: "/1000/_config/"},
  140. {Key: "/1000/2", CreatedIndex: 2},
  141. {Key: "/1000/3", CreatedIndex: 3},
  142. {Key: "/1000/4", CreatedIndex: 4},
  143. },
  144. ErrFullCluster,
  145. 3,
  146. },
  147. {
  148. // bad size key
  149. []*client.Node{
  150. {Key: "/1000/_config/size", Value: "bad", CreatedIndex: 1},
  151. },
  152. ErrBadSizeKey,
  153. 0,
  154. },
  155. {
  156. // no size key
  157. []*client.Node{},
  158. ErrSizeNotFound,
  159. 0,
  160. },
  161. }
  162. for i, tt := range tests {
  163. rs := make([]*client.Response, 0)
  164. if len(tt.nodes) > 0 {
  165. rs = append(rs, &client.Response{Node: tt.nodes[0]})
  166. rs = append(rs, &client.Response{
  167. Node: &client.Node{
  168. Key: cluster,
  169. Nodes: tt.nodes[1:],
  170. },
  171. })
  172. }
  173. c := &clientWithResp{rs: rs}
  174. d := discovery{cluster: cluster, id: 1, c: c}
  175. cRetry := &clientWithRetry{failTimes: 3}
  176. cRetry.rs = rs
  177. fc := clockwork.NewFakeClock()
  178. dRetry := discovery{cluster: cluster, id: 1, c: cRetry, clock: fc}
  179. for _, d := range []discovery{d, dRetry} {
  180. go func() {
  181. for i := uint(1); i <= nRetries; i++ {
  182. fc.BlockUntil(1)
  183. fc.Advance(time.Second * (0x1 << i))
  184. }
  185. }()
  186. ns, size, err := d.checkCluster()
  187. if err != tt.werr {
  188. t.Errorf("#%d: err = %v, want %v", i, err, tt.werr)
  189. }
  190. if reflect.DeepEqual(ns, tt.nodes) {
  191. t.Errorf("#%d: nodes = %v, want %v", i, ns, tt.nodes)
  192. }
  193. if size != tt.wsize {
  194. t.Errorf("#%d: size = %v, want %d", i, size, tt.wsize)
  195. }
  196. }
  197. }
  198. }
  199. func TestWaitNodes(t *testing.T) {
  200. all := client.Nodes{
  201. 0: {Key: "/1000/1", CreatedIndex: 2},
  202. 1: {Key: "/1000/2", CreatedIndex: 3},
  203. 2: {Key: "/1000/3", CreatedIndex: 4},
  204. }
  205. tests := []struct {
  206. nodes client.Nodes
  207. rs []*client.Response
  208. }{
  209. {
  210. all,
  211. []*client.Response{},
  212. },
  213. {
  214. all[:1],
  215. []*client.Response{
  216. {Node: &client.Node{Key: "/1000/2", CreatedIndex: 3}},
  217. {Node: &client.Node{Key: "/1000/3", CreatedIndex: 4}},
  218. },
  219. },
  220. {
  221. all[:2],
  222. []*client.Response{
  223. {Node: &client.Node{Key: "/1000/3", CreatedIndex: 4}},
  224. },
  225. },
  226. {
  227. append(all, &client.Node{Key: "/1000/4", CreatedIndex: 5}),
  228. []*client.Response{
  229. {Node: &client.Node{Key: "/1000/3", CreatedIndex: 4}},
  230. },
  231. },
  232. }
  233. for i, tt := range tests {
  234. // Basic case
  235. c := &clientWithResp{nil, &watcherWithResp{tt.rs}}
  236. d := &discovery{cluster: "1000", c: c}
  237. // Retry case
  238. retryScanResp := make([]*client.Response, 0)
  239. if len(tt.nodes) > 0 {
  240. retryScanResp = append(retryScanResp, &client.Response{
  241. Node: &client.Node{
  242. Key: "1000",
  243. Value: strconv.Itoa(3),
  244. },
  245. })
  246. retryScanResp = append(retryScanResp, &client.Response{
  247. Node: &client.Node{
  248. Nodes: tt.nodes,
  249. },
  250. })
  251. }
  252. cRetry := &clientWithResp{
  253. rs: retryScanResp,
  254. w: &watcherWithRetry{rs: tt.rs, failTimes: 2},
  255. }
  256. fc := clockwork.NewFakeClock()
  257. dRetry := &discovery{
  258. cluster: "1000",
  259. c: cRetry,
  260. clock: fc,
  261. }
  262. for _, d := range []*discovery{d, dRetry} {
  263. go func() {
  264. for i := uint(1); i <= nRetries; i++ {
  265. fc.BlockUntil(1)
  266. fc.Advance(time.Second * (0x1 << i))
  267. }
  268. }()
  269. g, err := d.waitNodes(tt.nodes, 3)
  270. if err != nil {
  271. t.Errorf("#%d: err = %v, want %v", i, err, nil)
  272. }
  273. if !reflect.DeepEqual(g, all) {
  274. t.Errorf("#%d: all = %v, want %v", i, g, all)
  275. }
  276. }
  277. }
  278. }
  279. func TestCreateSelf(t *testing.T) {
  280. rs := []*client.Response{{Node: &client.Node{Key: "1000/1", CreatedIndex: 2}}}
  281. w := &watcherWithResp{rs}
  282. errw := &watcherWithErr{errors.New("watch err")}
  283. c := &clientWithResp{rs, w}
  284. errc := &clientWithErr{errors.New("create err"), w}
  285. errwc := &clientWithResp{rs, errw}
  286. tests := []struct {
  287. c client.KeysAPI
  288. werr error
  289. }{
  290. // no error
  291. {c, nil},
  292. // client.create returns an error
  293. {errc, errc.err},
  294. // watcher.next retuens an error
  295. {errwc, errw.err},
  296. }
  297. for i, tt := range tests {
  298. d := discovery{cluster: "1000", c: tt.c}
  299. if err := d.createSelf(); err != tt.werr {
  300. t.Errorf("#%d: err = %v, want %v", i, err, nil)
  301. }
  302. }
  303. }
  304. func TestNodesToCluster(t *testing.T) {
  305. nodes := client.Nodes{
  306. 0: {Key: "/1000/1", Value: "1=1.1.1.1", CreatedIndex: 1},
  307. 1: {Key: "/1000/2", Value: "2=2.2.2.2", CreatedIndex: 2},
  308. 2: {Key: "/1000/3", Value: "3=3.3.3.3", CreatedIndex: 3},
  309. }
  310. w := "1=1.1.1.1,2=2.2.2.2,3=3.3.3.3"
  311. cluster := nodesToCluster(nodes)
  312. if !reflect.DeepEqual(cluster, w) {
  313. t.Errorf("cluster = %v, want %v", cluster, w)
  314. }
  315. }
  316. func TestSortableNodes(t *testing.T) {
  317. ns := client.Nodes{
  318. 0: {CreatedIndex: 5},
  319. 1: {CreatedIndex: 1},
  320. 2: {CreatedIndex: 3},
  321. 3: {CreatedIndex: 4},
  322. }
  323. // add some randomness
  324. for i := 0; i < 10000; i++ {
  325. ns = append(ns, &client.Node{CreatedIndex: uint64(rand.Int31())})
  326. }
  327. sns := sortableNodes{ns}
  328. sort.Sort(sns)
  329. cis := make([]int, 0)
  330. for _, n := range sns.Nodes {
  331. cis = append(cis, int(n.CreatedIndex))
  332. }
  333. if sort.IntsAreSorted(cis) != true {
  334. t.Errorf("isSorted = %v, want %v", sort.IntsAreSorted(cis), true)
  335. }
  336. cis = make([]int, 0)
  337. for _, n := range ns {
  338. cis = append(cis, int(n.CreatedIndex))
  339. }
  340. if sort.IntsAreSorted(cis) != true {
  341. t.Errorf("isSorted = %v, want %v", sort.IntsAreSorted(cis), true)
  342. }
  343. }
  344. func TestRetryFailure(t *testing.T) {
  345. cluster := "1000"
  346. c := &clientWithRetry{failTimes: 4}
  347. fc := clockwork.NewFakeClock()
  348. d := discovery{
  349. cluster: cluster,
  350. id: 1,
  351. c: c,
  352. clock: fc,
  353. }
  354. go func() {
  355. for i := uint(1); i <= nRetries; i++ {
  356. fc.BlockUntil(1)
  357. fc.Advance(time.Second * (0x1 << i))
  358. }
  359. }()
  360. if _, _, err := d.checkCluster(); err != ErrTooManyRetries {
  361. t.Errorf("err = %v, want %v", err, ErrTooManyRetries)
  362. }
  363. }
  364. type clientWithResp struct {
  365. rs []*client.Response
  366. w client.Watcher
  367. }
  368. func (c *clientWithResp) Create(key string, value string, ttl time.Duration) (*client.Response, error) {
  369. if len(c.rs) == 0 {
  370. return &client.Response{}, nil
  371. }
  372. r := c.rs[0]
  373. c.rs = c.rs[1:]
  374. return r, nil
  375. }
  376. func (c *clientWithResp) Get(key string) (*client.Response, error) {
  377. if len(c.rs) == 0 {
  378. return &client.Response{}, client.ErrKeyNoExist
  379. }
  380. r := c.rs[0]
  381. c.rs = append(c.rs[1:], r)
  382. return r, nil
  383. }
  384. func (c *clientWithResp) Watch(key string, waitIndex uint64) client.Watcher {
  385. return c.w
  386. }
  387. func (c *clientWithResp) RecursiveWatch(key string, waitIndex uint64) client.Watcher {
  388. return c.w
  389. }
  390. type clientWithErr struct {
  391. err error
  392. w client.Watcher
  393. }
  394. func (c *clientWithErr) Create(key string, value string, ttl time.Duration) (*client.Response, error) {
  395. return &client.Response{}, c.err
  396. }
  397. func (c *clientWithErr) Get(key string) (*client.Response, error) {
  398. return &client.Response{}, c.err
  399. }
  400. func (c *clientWithErr) Watch(key string, waitIndex uint64) client.Watcher {
  401. return c.w
  402. }
  403. func (c *clientWithErr) RecursiveWatch(key string, waitIndex uint64) client.Watcher {
  404. return c.w
  405. }
  406. type watcherWithResp struct {
  407. rs []*client.Response
  408. }
  409. func (w *watcherWithResp) Next() (*client.Response, error) {
  410. if len(w.rs) == 0 {
  411. return &client.Response{}, nil
  412. }
  413. r := w.rs[0]
  414. w.rs = w.rs[1:]
  415. return r, nil
  416. }
  417. type watcherWithErr struct {
  418. err error
  419. }
  420. func (w *watcherWithErr) Next() (*client.Response, error) {
  421. return &client.Response{}, w.err
  422. }
  423. // clientWithRetry will timeout all requests up to failTimes
  424. type clientWithRetry struct {
  425. clientWithResp
  426. failCount int
  427. failTimes int
  428. }
  429. func (c *clientWithRetry) Create(key string, value string, ttl time.Duration) (*client.Response, error) {
  430. if c.failCount < c.failTimes {
  431. c.failCount++
  432. return nil, client.ErrTimeout
  433. }
  434. return c.clientWithResp.Create(key, value, ttl)
  435. }
  436. func (c *clientWithRetry) Get(key string) (*client.Response, error) {
  437. if c.failCount < c.failTimes {
  438. c.failCount++
  439. return nil, client.ErrTimeout
  440. }
  441. return c.clientWithResp.Get(key)
  442. }
  443. // watcherWithRetry will timeout all requests up to failTimes
  444. type watcherWithRetry struct {
  445. rs []*client.Response
  446. failCount int
  447. failTimes int
  448. }
  449. func (w *watcherWithRetry) Next() (*client.Response, error) {
  450. if w.failCount < w.failTimes {
  451. w.failCount++
  452. return nil, client.ErrTimeout
  453. }
  454. if len(w.rs) == 0 {
  455. return &client.Response{}, nil
  456. }
  457. r := w.rs[0]
  458. w.rs = w.rs[1:]
  459. return r, nil
  460. }