http_test.go 3.8 KB

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