http_test.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  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 rafthttp
  14. import (
  15. "bytes"
  16. "errors"
  17. "io"
  18. "net/http"
  19. "net/http/httptest"
  20. "strings"
  21. "testing"
  22. "github.com/coreos/etcd/pkg/pbutil"
  23. "github.com/coreos/etcd/pkg/types"
  24. "github.com/coreos/etcd/raft/raftpb"
  25. "github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
  26. )
  27. func TestServeRaft(t *testing.T) {
  28. testCases := []struct {
  29. method string
  30. body io.Reader
  31. p Processor
  32. clusterID string
  33. wcode int
  34. }{
  35. {
  36. // bad method
  37. "GET",
  38. bytes.NewReader(
  39. pbutil.MustMarshal(&raftpb.Message{}),
  40. ),
  41. &nopProcessor{},
  42. "0",
  43. http.StatusMethodNotAllowed,
  44. },
  45. {
  46. // bad method
  47. "PUT",
  48. bytes.NewReader(
  49. pbutil.MustMarshal(&raftpb.Message{}),
  50. ),
  51. &nopProcessor{},
  52. "0",
  53. http.StatusMethodNotAllowed,
  54. },
  55. {
  56. // bad method
  57. "DELETE",
  58. bytes.NewReader(
  59. pbutil.MustMarshal(&raftpb.Message{}),
  60. ),
  61. &nopProcessor{},
  62. "0",
  63. http.StatusMethodNotAllowed,
  64. },
  65. {
  66. // bad request body
  67. "POST",
  68. &errReader{},
  69. &nopProcessor{},
  70. "0",
  71. http.StatusBadRequest,
  72. },
  73. {
  74. // bad request protobuf
  75. "POST",
  76. strings.NewReader("malformed garbage"),
  77. &nopProcessor{},
  78. "0",
  79. http.StatusBadRequest,
  80. },
  81. {
  82. // good request, wrong cluster ID
  83. "POST",
  84. bytes.NewReader(
  85. pbutil.MustMarshal(&raftpb.Message{}),
  86. ),
  87. &nopProcessor{},
  88. "1",
  89. http.StatusPreconditionFailed,
  90. },
  91. {
  92. // good request, Processor failure
  93. "POST",
  94. bytes.NewReader(
  95. pbutil.MustMarshal(&raftpb.Message{}),
  96. ),
  97. &errProcessor{
  98. err: &resWriterToError{code: http.StatusForbidden},
  99. },
  100. "0",
  101. http.StatusForbidden,
  102. },
  103. {
  104. // good request, Processor failure
  105. "POST",
  106. bytes.NewReader(
  107. pbutil.MustMarshal(&raftpb.Message{}),
  108. ),
  109. &errProcessor{
  110. err: &resWriterToError{code: http.StatusInternalServerError},
  111. },
  112. "0",
  113. http.StatusInternalServerError,
  114. },
  115. {
  116. // good request, Processor failure
  117. "POST",
  118. bytes.NewReader(
  119. pbutil.MustMarshal(&raftpb.Message{}),
  120. ),
  121. &errProcessor{err: errors.New("blah")},
  122. "0",
  123. http.StatusInternalServerError,
  124. },
  125. {
  126. // good request
  127. "POST",
  128. bytes.NewReader(
  129. pbutil.MustMarshal(&raftpb.Message{}),
  130. ),
  131. &nopProcessor{},
  132. "0",
  133. http.StatusNoContent,
  134. },
  135. }
  136. for i, tt := range testCases {
  137. req, err := http.NewRequest(tt.method, "foo", tt.body)
  138. if err != nil {
  139. t.Fatalf("#%d: could not create request: %#v", i, err)
  140. }
  141. req.Header.Set("X-Etcd-Cluster-ID", tt.clusterID)
  142. rw := httptest.NewRecorder()
  143. h := NewHandler(tt.p, types.ID(0))
  144. h.ServeHTTP(rw, req)
  145. if rw.Code != tt.wcode {
  146. t.Errorf("#%d: got code=%d, want %d", i, rw.Code, tt.wcode)
  147. }
  148. }
  149. }
  150. // errReader implements io.Reader to facilitate a broken request.
  151. type errReader struct{}
  152. func (er *errReader) Read(_ []byte) (int, error) { return 0, errors.New("some error") }
  153. type nopProcessor struct{}
  154. func (p *nopProcessor) Process(ctx context.Context, m raftpb.Message) error { return nil }
  155. type errProcessor struct {
  156. err error
  157. }
  158. func (p *errProcessor) Process(ctx context.Context, m raftpb.Message) error { return p.err }
  159. type resWriterToError struct {
  160. code int
  161. }
  162. func (e *resWriterToError) Error() string { return "" }
  163. func (e *resWriterToError) WriteTo(w http.ResponseWriter) { w.WriteHeader(e.code) }