go.etcd.io/etcd@v3.3.27+incompatible/etcdserver/api/v2http/http_test.go (about)

     1  // Copyright 2015 The etcd Authors
     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  
    15  package v2http
    16  
    17  import (
    18  	"context"
    19  	"errors"
    20  	"net/http"
    21  	"net/http/httptest"
    22  	"sort"
    23  	"testing"
    24  
    25  	etcdErr "github.com/coreos/etcd/error"
    26  	"github.com/coreos/etcd/etcdserver"
    27  	"github.com/coreos/etcd/etcdserver/etcdserverpb"
    28  	"github.com/coreos/etcd/etcdserver/membership"
    29  	"github.com/coreos/etcd/pkg/types"
    30  	"github.com/coreos/etcd/raft/raftpb"
    31  
    32  	"github.com/coreos/go-semver/semver"
    33  )
    34  
    35  type fakeCluster struct {
    36  	id         uint64
    37  	clientURLs []string
    38  	members    map[uint64]*membership.Member
    39  }
    40  
    41  func (c *fakeCluster) ID() types.ID         { return types.ID(c.id) }
    42  func (c *fakeCluster) ClientURLs() []string { return c.clientURLs }
    43  func (c *fakeCluster) Members() []*membership.Member {
    44  	var ms membership.MembersByID
    45  	for _, m := range c.members {
    46  		ms = append(ms, m)
    47  	}
    48  	sort.Sort(ms)
    49  	return []*membership.Member(ms)
    50  }
    51  func (c *fakeCluster) Member(id types.ID) *membership.Member { return c.members[uint64(id)] }
    52  func (c *fakeCluster) Version() *semver.Version              { return nil }
    53  
    54  // errServer implements the etcd.Server interface for testing.
    55  // It returns the given error from any Do/Process/AddMember/RemoveMember calls.
    56  type errServer struct {
    57  	err error
    58  	fakeServer
    59  }
    60  
    61  func (fs *errServer) Do(ctx context.Context, r etcdserverpb.Request) (etcdserver.Response, error) {
    62  	return etcdserver.Response{}, fs.err
    63  }
    64  func (fs *errServer) Process(ctx context.Context, m raftpb.Message) error {
    65  	return fs.err
    66  }
    67  func (fs *errServer) AddMember(ctx context.Context, m membership.Member) ([]*membership.Member, error) {
    68  	return nil, fs.err
    69  }
    70  func (fs *errServer) RemoveMember(ctx context.Context, id uint64) ([]*membership.Member, error) {
    71  	return nil, fs.err
    72  }
    73  func (fs *errServer) UpdateMember(ctx context.Context, m membership.Member) ([]*membership.Member, error) {
    74  	return nil, fs.err
    75  }
    76  
    77  func TestWriteError(t *testing.T) {
    78  	// nil error should not panic
    79  	rec := httptest.NewRecorder()
    80  	r := new(http.Request)
    81  	writeError(rec, r, nil)
    82  	h := rec.Header()
    83  	if len(h) > 0 {
    84  		t.Fatalf("unexpected non-empty headers: %#v", h)
    85  	}
    86  	b := rec.Body.String()
    87  	if len(b) > 0 {
    88  		t.Fatalf("unexpected non-empty body: %q", b)
    89  	}
    90  
    91  	tests := []struct {
    92  		err   error
    93  		wcode int
    94  		wi    string
    95  	}{
    96  		{
    97  			etcdErr.NewError(etcdErr.EcodeKeyNotFound, "/foo/bar", 123),
    98  			http.StatusNotFound,
    99  			"123",
   100  		},
   101  		{
   102  			etcdErr.NewError(etcdErr.EcodeTestFailed, "/foo/bar", 456),
   103  			http.StatusPreconditionFailed,
   104  			"456",
   105  		},
   106  		{
   107  			err:   errors.New("something went wrong"),
   108  			wcode: http.StatusInternalServerError,
   109  		},
   110  	}
   111  
   112  	for i, tt := range tests {
   113  		rw := httptest.NewRecorder()
   114  		writeError(rw, r, tt.err)
   115  		if code := rw.Code; code != tt.wcode {
   116  			t.Errorf("#%d: code=%d, want %d", i, code, tt.wcode)
   117  		}
   118  		if idx := rw.Header().Get("X-Etcd-Index"); idx != tt.wi {
   119  			t.Errorf("#%d: X-Etcd-Index=%q, want %q", i, idx, tt.wi)
   120  		}
   121  	}
   122  }
   123  
   124  func TestAllowMethod(t *testing.T) {
   125  	tests := []struct {
   126  		m  string
   127  		ms []string
   128  		w  bool
   129  		wh string
   130  	}{
   131  		// Accepted methods
   132  		{
   133  			m:  "GET",
   134  			ms: []string{"GET", "POST", "PUT"},
   135  			w:  true,
   136  		},
   137  		{
   138  			m:  "POST",
   139  			ms: []string{"POST"},
   140  			w:  true,
   141  		},
   142  		// Made-up methods no good
   143  		{
   144  			m:  "FAKE",
   145  			ms: []string{"GET", "POST", "PUT"},
   146  			w:  false,
   147  			wh: "GET,POST,PUT",
   148  		},
   149  		// Empty methods no good
   150  		{
   151  			m:  "",
   152  			ms: []string{"GET", "POST"},
   153  			w:  false,
   154  			wh: "GET,POST",
   155  		},
   156  		// Empty accepted methods no good
   157  		{
   158  			m:  "GET",
   159  			ms: []string{""},
   160  			w:  false,
   161  			wh: "",
   162  		},
   163  		// No methods accepted
   164  		{
   165  			m:  "GET",
   166  			ms: []string{},
   167  			w:  false,
   168  			wh: "",
   169  		},
   170  	}
   171  
   172  	for i, tt := range tests {
   173  		rw := httptest.NewRecorder()
   174  		g := allowMethod(rw, tt.m, tt.ms...)
   175  		if g != tt.w {
   176  			t.Errorf("#%d: got allowMethod()=%t, want %t", i, g, tt.w)
   177  		}
   178  		if !tt.w {
   179  			if rw.Code != http.StatusMethodNotAllowed {
   180  				t.Errorf("#%d: code=%d, want %d", i, rw.Code, http.StatusMethodNotAllowed)
   181  			}
   182  			gh := rw.Header().Get("Allow")
   183  			if gh != tt.wh {
   184  				t.Errorf("#%d: Allow header=%q, want %q", i, gh, tt.wh)
   185  			}
   186  		}
   187  	}
   188  }