http_test.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080
  1. package etcdhttp
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "errors"
  6. "io"
  7. "net/http"
  8. "net/http/httptest"
  9. "net/url"
  10. "path"
  11. "reflect"
  12. "strings"
  13. "sync"
  14. "testing"
  15. "time"
  16. etcdErr "github.com/coreos/etcd/error"
  17. "github.com/coreos/etcd/etcdserver"
  18. "github.com/coreos/etcd/etcdserver/etcdserverpb"
  19. "github.com/coreos/etcd/raft/raftpb"
  20. "github.com/coreos/etcd/store"
  21. "github.com/coreos/etcd/third_party/code.google.com/p/go.net/context"
  22. )
  23. func boolp(b bool) *bool { return &b }
  24. func mustNewURL(t *testing.T, s string) *url.URL {
  25. u, err := url.Parse(s)
  26. if err != nil {
  27. t.Fatalf("error creating URL from %q: %v", s, err)
  28. }
  29. return u
  30. }
  31. // mustNewRequest takes a path, appends it to the standard keysPrefix, and constructs
  32. // a GET *http.Request referencing the resulting URL
  33. func mustNewRequest(t *testing.T, p string) *http.Request {
  34. return &http.Request{
  35. Method: "GET",
  36. URL: mustNewURL(t, path.Join(keysPrefix, p)),
  37. }
  38. }
  39. // mustNewForm takes a set of Values and constructs a PUT *http.Request,
  40. // with a URL constructed from appending the given path to the standard keysPrefix
  41. func mustNewForm(t *testing.T, p string, vals url.Values) *http.Request {
  42. u := mustNewURL(t, path.Join(keysPrefix, p))
  43. req, err := http.NewRequest("PUT", u.String(), strings.NewReader(vals.Encode()))
  44. req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
  45. if err != nil {
  46. t.Fatalf("error creating new request: %v", err)
  47. }
  48. return req
  49. }
  50. func TestBadParseRequest(t *testing.T) {
  51. tests := []struct {
  52. in *http.Request
  53. wcode int
  54. }{
  55. {
  56. // parseForm failure
  57. &http.Request{
  58. Body: nil,
  59. Method: "PUT",
  60. },
  61. etcdErr.EcodeInvalidForm,
  62. },
  63. {
  64. // bad key prefix
  65. &http.Request{
  66. URL: mustNewURL(t, "/badprefix/"),
  67. },
  68. etcdErr.EcodeInvalidForm,
  69. },
  70. // bad values for prevIndex, waitIndex, ttl
  71. {
  72. mustNewForm(t, "foo", url.Values{"prevIndex": []string{"garbage"}}),
  73. etcdErr.EcodeIndexNaN,
  74. },
  75. {
  76. mustNewForm(t, "foo", url.Values{"prevIndex": []string{"1.5"}}),
  77. etcdErr.EcodeIndexNaN,
  78. },
  79. {
  80. mustNewForm(t, "foo", url.Values{"prevIndex": []string{"-1"}}),
  81. etcdErr.EcodeIndexNaN,
  82. },
  83. {
  84. mustNewForm(t, "foo", url.Values{"waitIndex": []string{"garbage"}}),
  85. etcdErr.EcodeIndexNaN,
  86. },
  87. {
  88. mustNewForm(t, "foo", url.Values{"waitIndex": []string{"??"}}),
  89. etcdErr.EcodeIndexNaN,
  90. },
  91. {
  92. mustNewForm(t, "foo", url.Values{"ttl": []string{"-1"}}),
  93. etcdErr.EcodeTTLNaN,
  94. },
  95. // bad values for recursive, sorted, wait, prevExists
  96. {
  97. mustNewForm(t, "foo", url.Values{"recursive": []string{"hahaha"}}),
  98. etcdErr.EcodeInvalidField,
  99. },
  100. {
  101. mustNewForm(t, "foo", url.Values{"recursive": []string{"1234"}}),
  102. etcdErr.EcodeInvalidField,
  103. },
  104. {
  105. mustNewForm(t, "foo", url.Values{"recursive": []string{"?"}}),
  106. etcdErr.EcodeInvalidField,
  107. },
  108. {
  109. mustNewForm(t, "foo", url.Values{"sorted": []string{"?"}}),
  110. etcdErr.EcodeInvalidField,
  111. },
  112. {
  113. mustNewForm(t, "foo", url.Values{"sorted": []string{"x"}}),
  114. etcdErr.EcodeInvalidField,
  115. },
  116. {
  117. mustNewForm(t, "foo", url.Values{"wait": []string{"?!"}}),
  118. etcdErr.EcodeInvalidField,
  119. },
  120. {
  121. mustNewForm(t, "foo", url.Values{"wait": []string{"yes"}}),
  122. etcdErr.EcodeInvalidField,
  123. },
  124. {
  125. mustNewForm(t, "foo", url.Values{"prevExists": []string{"yes"}}),
  126. etcdErr.EcodeInvalidField,
  127. },
  128. {
  129. mustNewForm(t, "foo", url.Values{"prevExists": []string{"#2"}}),
  130. etcdErr.EcodeInvalidField,
  131. },
  132. // query values are considered
  133. {
  134. mustNewRequest(t, "foo?prevExists=wrong"),
  135. etcdErr.EcodeInvalidField,
  136. },
  137. {
  138. mustNewRequest(t, "foo?ttl=wrong"),
  139. etcdErr.EcodeTTLNaN,
  140. },
  141. // but body takes precedence if both are specified
  142. {
  143. mustNewForm(
  144. t,
  145. "foo?ttl=12",
  146. url.Values{"ttl": []string{"garbage"}},
  147. ),
  148. etcdErr.EcodeTTLNaN,
  149. },
  150. {
  151. mustNewForm(
  152. t,
  153. "foo?prevExists=false",
  154. url.Values{"prevExists": []string{"yes"}},
  155. ),
  156. etcdErr.EcodeInvalidField,
  157. },
  158. }
  159. for i, tt := range tests {
  160. got, err := parseRequest(tt.in, 1234)
  161. if err == nil {
  162. t.Errorf("#%d: unexpected nil error!", i)
  163. continue
  164. }
  165. ee, ok := err.(*etcdErr.Error)
  166. if !ok {
  167. t.Errorf("#%d: err is not etcd.Error!", i)
  168. continue
  169. }
  170. if ee.ErrorCode != tt.wcode {
  171. t.Errorf("#%d: code=%d, want %v", i, ee.ErrorCode, tt.wcode)
  172. t.Logf("cause: %#v", ee.Cause)
  173. }
  174. if !reflect.DeepEqual(got, etcdserverpb.Request{}) {
  175. t.Errorf("#%d: unexpected non-empty Request: %#v", i, got)
  176. }
  177. }
  178. }
  179. func TestGoodParseRequest(t *testing.T) {
  180. tests := []struct {
  181. in *http.Request
  182. w etcdserverpb.Request
  183. }{
  184. {
  185. // good prefix, all other values default
  186. mustNewRequest(t, "foo"),
  187. etcdserverpb.Request{
  188. Id: 1234,
  189. Method: "GET",
  190. Path: "/foo",
  191. },
  192. },
  193. {
  194. // value specified
  195. mustNewForm(
  196. t,
  197. "foo",
  198. url.Values{"value": []string{"some_value"}},
  199. ),
  200. etcdserverpb.Request{
  201. Id: 1234,
  202. Method: "PUT",
  203. Val: "some_value",
  204. Path: "/foo",
  205. },
  206. },
  207. {
  208. // prevIndex specified
  209. mustNewForm(
  210. t,
  211. "foo",
  212. url.Values{"prevIndex": []string{"98765"}},
  213. ),
  214. etcdserverpb.Request{
  215. Id: 1234,
  216. Method: "PUT",
  217. PrevIndex: 98765,
  218. Path: "/foo",
  219. },
  220. },
  221. {
  222. // recursive specified
  223. mustNewForm(
  224. t,
  225. "foo",
  226. url.Values{"recursive": []string{"true"}},
  227. ),
  228. etcdserverpb.Request{
  229. Id: 1234,
  230. Method: "PUT",
  231. Recursive: true,
  232. Path: "/foo",
  233. },
  234. },
  235. {
  236. // sorted specified
  237. mustNewForm(
  238. t,
  239. "foo",
  240. url.Values{"sorted": []string{"true"}},
  241. ),
  242. etcdserverpb.Request{
  243. Id: 1234,
  244. Method: "PUT",
  245. Sorted: true,
  246. Path: "/foo",
  247. },
  248. },
  249. {
  250. // wait specified
  251. mustNewForm(
  252. t,
  253. "foo",
  254. url.Values{"wait": []string{"true"}},
  255. ),
  256. etcdserverpb.Request{
  257. Id: 1234,
  258. Method: "PUT",
  259. Wait: true,
  260. Path: "/foo",
  261. },
  262. },
  263. {
  264. // prevExists should be non-null if specified
  265. mustNewForm(
  266. t,
  267. "foo",
  268. url.Values{"prevExists": []string{"true"}},
  269. ),
  270. etcdserverpb.Request{
  271. Id: 1234,
  272. Method: "PUT",
  273. PrevExists: boolp(true),
  274. Path: "/foo",
  275. },
  276. },
  277. {
  278. // prevExists should be non-null if specified
  279. mustNewForm(
  280. t,
  281. "foo",
  282. url.Values{"prevExists": []string{"false"}},
  283. ),
  284. etcdserverpb.Request{
  285. Id: 1234,
  286. Method: "PUT",
  287. PrevExists: boolp(false),
  288. Path: "/foo",
  289. },
  290. },
  291. // mix various fields
  292. {
  293. mustNewForm(
  294. t,
  295. "foo",
  296. url.Values{
  297. "value": []string{"some value"},
  298. "prevExists": []string{"true"},
  299. "prevValue": []string{"previous value"},
  300. },
  301. ),
  302. etcdserverpb.Request{
  303. Id: 1234,
  304. Method: "PUT",
  305. PrevExists: boolp(true),
  306. PrevValue: "previous value",
  307. Val: "some value",
  308. Path: "/foo",
  309. },
  310. },
  311. // query parameters should be used if given
  312. {
  313. mustNewForm(
  314. t,
  315. "foo?prevValue=woof",
  316. url.Values{},
  317. ),
  318. etcdserverpb.Request{
  319. Id: 1234,
  320. Method: "PUT",
  321. PrevValue: "woof",
  322. Path: "/foo",
  323. },
  324. },
  325. // but form values should take precedence over query parameters
  326. {
  327. mustNewForm(
  328. t,
  329. "foo?prevValue=woof",
  330. url.Values{
  331. "prevValue": []string{"miaow"},
  332. },
  333. ),
  334. etcdserverpb.Request{
  335. Id: 1234,
  336. Method: "PUT",
  337. PrevValue: "miaow",
  338. Path: "/foo",
  339. },
  340. },
  341. }
  342. for i, tt := range tests {
  343. got, err := parseRequest(tt.in, 1234)
  344. if err != nil {
  345. t.Errorf("#%d: err = %v, want %v", i, err, nil)
  346. }
  347. if !reflect.DeepEqual(got, tt.w) {
  348. t.Errorf("#%d: request=%#v, want %#v", i, got, tt.w)
  349. }
  350. }
  351. }
  352. // eventingWatcher immediately returns a simple event of the given action on its channel
  353. type eventingWatcher struct {
  354. action string
  355. }
  356. func (w *eventingWatcher) EventChan() chan *store.Event {
  357. ch := make(chan *store.Event)
  358. go func() {
  359. ch <- &store.Event{
  360. Action: w.action,
  361. Node: &store.NodeExtern{},
  362. }
  363. }()
  364. return ch
  365. }
  366. func (w *eventingWatcher) Remove() {}
  367. func TestWriteError(t *testing.T) {
  368. // nil error should not panic
  369. rw := httptest.NewRecorder()
  370. writeError(rw, nil)
  371. h := rw.Header()
  372. if len(h) > 0 {
  373. t.Fatalf("unexpected non-empty headers: %#v", h)
  374. }
  375. b := rw.Body.String()
  376. if len(b) > 0 {
  377. t.Fatalf("unexpected non-empty body: %q", b)
  378. }
  379. tests := []struct {
  380. err error
  381. wcode int
  382. wi string
  383. }{
  384. {
  385. etcdErr.NewError(etcdErr.EcodeKeyNotFound, "/foo/bar", 123),
  386. http.StatusNotFound,
  387. "123",
  388. },
  389. {
  390. etcdErr.NewError(etcdErr.EcodeTestFailed, "/foo/bar", 456),
  391. http.StatusPreconditionFailed,
  392. "456",
  393. },
  394. {
  395. err: errors.New("something went wrong"),
  396. wcode: http.StatusInternalServerError,
  397. },
  398. }
  399. for i, tt := range tests {
  400. rw := httptest.NewRecorder()
  401. writeError(rw, tt.err)
  402. if code := rw.Code; code != tt.wcode {
  403. t.Errorf("#%d: code=%d, want %d", i, code, tt.wcode)
  404. }
  405. if idx := rw.Header().Get("X-Etcd-Index"); idx != tt.wi {
  406. t.Errorf("#%d: X-Etcd-Index=%q, want %q", i, idx, tt.wi)
  407. }
  408. }
  409. }
  410. func TestWriteEvent(t *testing.T) {
  411. // nil event should not panic
  412. rw := httptest.NewRecorder()
  413. writeEvent(rw, nil)
  414. h := rw.Header()
  415. if len(h) > 0 {
  416. t.Fatalf("unexpected non-empty headers: %#v", h)
  417. }
  418. b := rw.Body.String()
  419. if len(b) > 0 {
  420. t.Fatalf("unexpected non-empty body: %q", b)
  421. }
  422. tests := []struct {
  423. ev *store.Event
  424. idx string
  425. code int
  426. err error
  427. }{
  428. // standard case, standard 200 response
  429. {
  430. &store.Event{
  431. Action: store.Get,
  432. Node: &store.NodeExtern{},
  433. PrevNode: &store.NodeExtern{},
  434. },
  435. "0",
  436. http.StatusOK,
  437. nil,
  438. },
  439. // check new nodes return StatusCreated
  440. {
  441. &store.Event{
  442. Action: store.Create,
  443. Node: &store.NodeExtern{},
  444. PrevNode: &store.NodeExtern{},
  445. },
  446. "0",
  447. http.StatusCreated,
  448. nil,
  449. },
  450. }
  451. for i, tt := range tests {
  452. rw := httptest.NewRecorder()
  453. writeEvent(rw, tt.ev)
  454. if gct := rw.Header().Get("Content-Type"); gct != "application/json" {
  455. t.Errorf("case %d: bad Content-Type: got %q, want application/json", i, gct)
  456. }
  457. if gei := rw.Header().Get("X-Etcd-Index"); gei != tt.idx {
  458. t.Errorf("case %d: bad X-Etcd-Index header: got %s, want %s", i, gei, tt.idx)
  459. }
  460. if rw.Code != tt.code {
  461. t.Errorf("case %d: bad response code: got %d, want %v", i, rw.Code, tt.code)
  462. }
  463. }
  464. }
  465. type dummyWatcher struct {
  466. echan chan *store.Event
  467. }
  468. func (w *dummyWatcher) EventChan() chan *store.Event {
  469. return w.echan
  470. }
  471. func (w *dummyWatcher) Remove() {}
  472. type dummyResponseWriter struct {
  473. cnchan chan bool
  474. http.ResponseWriter
  475. }
  476. func (rw *dummyResponseWriter) CloseNotify() <-chan bool {
  477. return rw.cnchan
  478. }
  479. func TestWaitForEventChan(t *testing.T) {
  480. ctx := context.Background()
  481. ec := make(chan *store.Event)
  482. dw := &dummyWatcher{
  483. echan: ec,
  484. }
  485. w := httptest.NewRecorder()
  486. var wg sync.WaitGroup
  487. var ev *store.Event
  488. var err error
  489. wg.Add(1)
  490. go func() {
  491. ev, err = waitForEvent(ctx, w, dw)
  492. wg.Done()
  493. }()
  494. ec <- &store.Event{
  495. Action: store.Get,
  496. Node: &store.NodeExtern{
  497. Key: "/foo/bar",
  498. ModifiedIndex: 12345,
  499. },
  500. }
  501. wg.Wait()
  502. want := &store.Event{
  503. Action: store.Get,
  504. Node: &store.NodeExtern{
  505. Key: "/foo/bar",
  506. ModifiedIndex: 12345,
  507. },
  508. }
  509. if !reflect.DeepEqual(ev, want) {
  510. t.Fatalf("bad event: got %#v, want %#v", ev, want)
  511. }
  512. if err != nil {
  513. t.Fatalf("unexpected error: %v", err)
  514. }
  515. }
  516. func TestWaitForEventCloseNotify(t *testing.T) {
  517. ctx := context.Background()
  518. dw := &dummyWatcher{}
  519. cnchan := make(chan bool)
  520. w := &dummyResponseWriter{
  521. cnchan: cnchan,
  522. }
  523. var wg sync.WaitGroup
  524. var ev *store.Event
  525. var err error
  526. wg.Add(1)
  527. go func() {
  528. ev, err = waitForEvent(ctx, w, dw)
  529. wg.Done()
  530. }()
  531. close(cnchan)
  532. wg.Wait()
  533. if ev != nil {
  534. t.Fatalf("non-nil Event returned with CloseNotifier: %v", ev)
  535. }
  536. if err == nil {
  537. t.Fatalf("nil err returned with CloseNotifier!")
  538. }
  539. }
  540. func TestWaitForEventCancelledContext(t *testing.T) {
  541. cctx, cancel := context.WithCancel(context.Background())
  542. dw := &dummyWatcher{}
  543. w := httptest.NewRecorder()
  544. var wg sync.WaitGroup
  545. var ev *store.Event
  546. var err error
  547. wg.Add(1)
  548. go func() {
  549. ev, err = waitForEvent(cctx, w, dw)
  550. wg.Done()
  551. }()
  552. cancel()
  553. wg.Wait()
  554. if ev != nil {
  555. t.Fatalf("non-nil Event returned with cancelled context: %v", ev)
  556. }
  557. if err == nil {
  558. t.Fatalf("nil err returned with cancelled context!")
  559. }
  560. }
  561. func TestV2MachinesEndpoint(t *testing.T) {
  562. tests := []struct {
  563. method string
  564. wcode int
  565. }{
  566. {"GET", http.StatusOK},
  567. {"HEAD", http.StatusOK},
  568. {"POST", http.StatusMethodNotAllowed},
  569. }
  570. m := NewHandler(nil, Peers{}, time.Hour)
  571. s := httptest.NewServer(m)
  572. defer s.Close()
  573. for _, tt := range tests {
  574. req, err := http.NewRequest(tt.method, s.URL+machinesPrefix, nil)
  575. if err != nil {
  576. t.Fatal(err)
  577. }
  578. resp, err := http.DefaultClient.Do(req)
  579. if err != nil {
  580. t.Fatal(err)
  581. }
  582. if resp.StatusCode != tt.wcode {
  583. t.Errorf("StatusCode = %d, expected %d", resp.StatusCode, tt.wcode)
  584. }
  585. }
  586. }
  587. func TestServeMachines(t *testing.T) {
  588. peers := Peers{}
  589. peers.Set("0xBEEF0=localhost:8080&0xBEEF1=localhost:8081&0xBEEF2=localhost:8082")
  590. writer := httptest.NewRecorder()
  591. req, err := http.NewRequest("GET", "", nil)
  592. if err != nil {
  593. t.Fatal(err)
  594. }
  595. h := &serverHandler{peers: peers}
  596. h.serveMachines(writer, req)
  597. w := "http://localhost:8080, http://localhost:8081, http://localhost:8082"
  598. if g := writer.Body.String(); g != w {
  599. t.Errorf("body = %s, want %s", g, w)
  600. }
  601. if writer.Code != http.StatusOK {
  602. t.Errorf("header = %d, want %d", writer.Code, http.StatusOK)
  603. }
  604. }
  605. func TestPeersEndpoints(t *testing.T) {
  606. tests := []struct {
  607. peers Peers
  608. endpoints []string
  609. }{
  610. // single peer with a single address
  611. {
  612. peers: Peers(map[int64][]string{
  613. 1: []string{"192.0.2.1"},
  614. }),
  615. endpoints: []string{"http://192.0.2.1"},
  616. },
  617. // single peer with a single address with a port
  618. {
  619. peers: Peers(map[int64][]string{
  620. 1: []string{"192.0.2.1:8001"},
  621. }),
  622. endpoints: []string{"http://192.0.2.1:8001"},
  623. },
  624. // several peers explicitly unsorted
  625. {
  626. peers: Peers(map[int64][]string{
  627. 2: []string{"192.0.2.3", "192.0.2.4"},
  628. 3: []string{"192.0.2.5", "192.0.2.6"},
  629. 1: []string{"192.0.2.1", "192.0.2.2"},
  630. }),
  631. endpoints: []string{"http://192.0.2.1", "http://192.0.2.2", "http://192.0.2.3", "http://192.0.2.4", "http://192.0.2.5", "http://192.0.2.6"},
  632. },
  633. // no peers
  634. {
  635. peers: Peers(map[int64][]string{}),
  636. endpoints: []string{},
  637. },
  638. // peer with no endpoints
  639. {
  640. peers: Peers(map[int64][]string{
  641. 3: []string{},
  642. }),
  643. endpoints: []string{},
  644. },
  645. }
  646. for i, tt := range tests {
  647. endpoints := tt.peers.Endpoints()
  648. if !reflect.DeepEqual(tt.endpoints, endpoints) {
  649. t.Errorf("#%d: peers.Endpoints() incorrect: want=%#v got=%#v", i, tt.endpoints, endpoints)
  650. }
  651. }
  652. }
  653. func TestAllowMethod(t *testing.T) {
  654. tests := []struct {
  655. m string
  656. ms []string
  657. w bool
  658. wh string
  659. }{
  660. // Accepted methods
  661. {
  662. m: "GET",
  663. ms: []string{"GET", "POST", "PUT"},
  664. w: true,
  665. },
  666. {
  667. m: "POST",
  668. ms: []string{"POST"},
  669. w: true,
  670. },
  671. // Made-up methods no good
  672. {
  673. m: "FAKE",
  674. ms: []string{"GET", "POST", "PUT"},
  675. w: false,
  676. wh: "GET,POST,PUT",
  677. },
  678. // Empty methods no good
  679. {
  680. m: "",
  681. ms: []string{"GET", "POST"},
  682. w: false,
  683. wh: "GET,POST",
  684. },
  685. // Empty accepted methods no good
  686. {
  687. m: "GET",
  688. ms: []string{""},
  689. w: false,
  690. wh: "",
  691. },
  692. // No methods accepted
  693. {
  694. m: "GET",
  695. ms: []string{},
  696. w: false,
  697. wh: "",
  698. },
  699. }
  700. for i, tt := range tests {
  701. rw := httptest.NewRecorder()
  702. g := allowMethod(rw, tt.m, tt.ms...)
  703. if g != tt.w {
  704. t.Errorf("#%d: got allowMethod()=%t, want %t", i, g, tt.w)
  705. }
  706. if !tt.w {
  707. if rw.Code != http.StatusMethodNotAllowed {
  708. t.Errorf("#%d: code=%d, want %d", i, rw.Code, http.StatusMethodNotAllowed)
  709. }
  710. gh := rw.Header().Get("Allow")
  711. if gh != tt.wh {
  712. t.Errorf("#%d: Allow header=%q, want %q", i, gh, tt.wh)
  713. }
  714. }
  715. }
  716. }
  717. // errServer implements the etcd.Server interface for testing.
  718. // It returns the given error from any Do/Process calls.
  719. type errServer struct {
  720. err error
  721. }
  722. func (fs *errServer) Do(ctx context.Context, r etcdserverpb.Request) (etcdserver.Response, error) {
  723. return etcdserver.Response{}, fs.err
  724. }
  725. func (fs *errServer) Process(ctx context.Context, m raftpb.Message) error {
  726. return fs.err
  727. }
  728. func (fs *errServer) Start() {}
  729. func (fs *errServer) Stop() {}
  730. // errReader implements io.Reader to facilitate a broken request.
  731. type errReader struct{}
  732. func (er *errReader) Read(_ []byte) (int, error) { return 0, errors.New("some error") }
  733. func mustMarshalMsg(t *testing.T, m raftpb.Message) []byte {
  734. json, err := m.Marshal()
  735. if err != nil {
  736. t.Fatalf("error marshalling raft Message: %#v", err)
  737. }
  738. return json
  739. }
  740. func TestServeRaft(t *testing.T) {
  741. testCases := []struct {
  742. method string
  743. body io.Reader
  744. serverErr error
  745. wcode int
  746. }{
  747. {
  748. // bad method
  749. "GET",
  750. bytes.NewReader(
  751. mustMarshalMsg(
  752. t,
  753. raftpb.Message{},
  754. ),
  755. ),
  756. nil,
  757. http.StatusMethodNotAllowed,
  758. },
  759. {
  760. // bad method
  761. "PUT",
  762. bytes.NewReader(
  763. mustMarshalMsg(
  764. t,
  765. raftpb.Message{},
  766. ),
  767. ),
  768. nil,
  769. http.StatusMethodNotAllowed,
  770. },
  771. {
  772. // bad method
  773. "DELETE",
  774. bytes.NewReader(
  775. mustMarshalMsg(
  776. t,
  777. raftpb.Message{},
  778. ),
  779. ),
  780. nil,
  781. http.StatusMethodNotAllowed,
  782. },
  783. {
  784. // bad request body
  785. "POST",
  786. &errReader{},
  787. nil,
  788. http.StatusBadRequest,
  789. },
  790. {
  791. // bad request JSON
  792. "POST",
  793. strings.NewReader("malformed garbage"),
  794. nil,
  795. http.StatusBadRequest,
  796. },
  797. {
  798. // good request, etcdserver.Server error
  799. "POST",
  800. bytes.NewReader(
  801. mustMarshalMsg(
  802. t,
  803. raftpb.Message{},
  804. ),
  805. ),
  806. errors.New("some error"),
  807. http.StatusInternalServerError,
  808. },
  809. {
  810. // good request
  811. "POST",
  812. bytes.NewReader(
  813. mustMarshalMsg(
  814. t,
  815. raftpb.Message{},
  816. ),
  817. ),
  818. nil,
  819. http.StatusNoContent,
  820. },
  821. }
  822. for i, tt := range testCases {
  823. req, err := http.NewRequest(tt.method, "foo", tt.body)
  824. if err != nil {
  825. t.Fatalf("#%d: could not create request: %#v", i, err)
  826. }
  827. h := &serverHandler{
  828. timeout: time.Hour,
  829. server: &errServer{tt.serverErr},
  830. peers: nil,
  831. }
  832. rw := httptest.NewRecorder()
  833. h.serveRaft(rw, req)
  834. if rw.Code != tt.wcode {
  835. t.Errorf("#%d: got code=%d, want %d", i, rw.Code, tt.wcode)
  836. }
  837. }
  838. }
  839. // resServer implements the etcd.Server interface for testing.
  840. // It returns the given responsefrom any Do calls, and nil error
  841. type resServer struct {
  842. res etcdserver.Response
  843. }
  844. func (rs *resServer) Do(ctx context.Context, r etcdserverpb.Request) (etcdserver.Response, error) {
  845. return rs.res, nil
  846. }
  847. func (rs *resServer) Process(ctx context.Context, m raftpb.Message) error {
  848. return nil
  849. }
  850. func (rs *resServer) Start() {}
  851. func (rs *resServer) Stop() {}
  852. func mustMarshalEvent(t *testing.T, ev *store.Event) string {
  853. b := new(bytes.Buffer)
  854. if err := json.NewEncoder(b).Encode(ev); err != nil {
  855. t.Fatalf("error marshalling event %#v: #v", ev, err)
  856. }
  857. return b.String()
  858. }
  859. func TestBadServeKeys(t *testing.T) {
  860. testBadCases := []struct {
  861. req *http.Request
  862. server etcdserver.Server
  863. wcode int
  864. }{
  865. {
  866. // bad method
  867. &http.Request{
  868. Method: "CONNECT",
  869. },
  870. &resServer{},
  871. http.StatusMethodNotAllowed,
  872. },
  873. {
  874. // bad method
  875. &http.Request{
  876. Method: "TRACE",
  877. },
  878. &resServer{},
  879. http.StatusMethodNotAllowed,
  880. },
  881. {
  882. // parseRequest error
  883. &http.Request{
  884. Body: nil,
  885. Method: "PUT",
  886. },
  887. &resServer{},
  888. http.StatusBadRequest,
  889. },
  890. {
  891. // etcdserver.Server error
  892. mustNewRequest(t, "foo"),
  893. &errServer{
  894. errors.New("blah"),
  895. },
  896. http.StatusInternalServerError,
  897. },
  898. {
  899. // timeout waiting for event (watcher never returns)
  900. mustNewRequest(t, "foo"),
  901. &resServer{
  902. etcdserver.Response{
  903. Watcher: &dummyWatcher{},
  904. },
  905. },
  906. http.StatusGatewayTimeout,
  907. },
  908. {
  909. // non-event/watcher response from etcdserver.Server
  910. mustNewRequest(t, "foo"),
  911. &resServer{
  912. etcdserver.Response{},
  913. },
  914. http.StatusInternalServerError,
  915. },
  916. }
  917. for i, tt := range testBadCases {
  918. h := &serverHandler{
  919. timeout: 0, // context times out immediately
  920. server: tt.server,
  921. peers: nil,
  922. }
  923. rw := httptest.NewRecorder()
  924. h.serveKeys(rw, tt.req)
  925. if rw.Code != tt.wcode {
  926. t.Errorf("#%d: got code=%d, want %d", i, rw.Code, tt.wcode)
  927. }
  928. }
  929. }
  930. func TestServeKeysEvent(t *testing.T) {
  931. req := mustNewRequest(t, "foo")
  932. server := &resServer{
  933. etcdserver.Response{
  934. Event: &store.Event{
  935. Action: store.Get,
  936. Node: &store.NodeExtern{
  937. Key: "foo",
  938. ModifiedIndex: 2,
  939. },
  940. },
  941. },
  942. }
  943. h := &serverHandler{
  944. timeout: time.Hour,
  945. server: server,
  946. peers: nil,
  947. }
  948. rw := httptest.NewRecorder()
  949. h.serveKeys(rw, req)
  950. wcode := http.StatusOK
  951. wbody := mustMarshalEvent(
  952. t,
  953. &store.Event{
  954. Action: store.Get,
  955. Node: &store.NodeExtern{
  956. Key: "foo",
  957. ModifiedIndex: 2,
  958. },
  959. },
  960. )
  961. if rw.Code != wcode {
  962. t.Errorf("got code=%d, want %d", rw.Code, wcode)
  963. }
  964. g := rw.Body.String()
  965. if g != wbody {
  966. t.Errorf("got body=%#v, want %#v", g, wbody)
  967. }
  968. }
  969. func TestServeKeysWatch(t *testing.T) {
  970. req := mustNewRequest(t, "/foo/bar")
  971. ec := make(chan *store.Event)
  972. dw := &dummyWatcher{
  973. echan: ec,
  974. }
  975. server := &resServer{
  976. etcdserver.Response{
  977. Watcher: dw,
  978. },
  979. }
  980. h := &serverHandler{
  981. timeout: time.Hour,
  982. server: server,
  983. peers: nil,
  984. }
  985. go func() {
  986. ec <- &store.Event{
  987. Action: store.Get,
  988. Node: &store.NodeExtern{
  989. Key: "/foo/bar",
  990. ModifiedIndex: 12345,
  991. },
  992. }
  993. }()
  994. rw := httptest.NewRecorder()
  995. h.serveKeys(rw, req)
  996. wcode := http.StatusOK
  997. wbody := mustMarshalEvent(
  998. t,
  999. &store.Event{
  1000. Action: store.Get,
  1001. Node: &store.NodeExtern{
  1002. Key: "/foo/bar",
  1003. ModifiedIndex: 12345,
  1004. },
  1005. },
  1006. )
  1007. if rw.Code != wcode {
  1008. t.Errorf("got code=%d, want %d", rw.Code, wcode)
  1009. }
  1010. g := rw.Body.String()
  1011. if g != wbody {
  1012. t.Errorf("got body=%#v, want %#v", g, wbody)
  1013. }
  1014. }