github.com/msales/pkg/v3@v3.24.0/httpx/httptest/server.go (about)

     1  package httptest
     2  
     3  import (
     4  	"net/http"
     5  	"net/http/httptest"
     6  	"testing"
     7  
     8  	"github.com/ryanuber/go-glob"
     9  )
    10  
    11  const (
    12  	// Anything is used where the expectation should not be considered.
    13  	Anything = "httpx/httptest.Anything"
    14  )
    15  
    16  // Expectation represents an http request expectation.
    17  type Expectation struct {
    18  	method string
    19  	path   string
    20  
    21  	fn http.HandlerFunc
    22  
    23  	headers []string
    24  	body    []byte
    25  	status  int
    26  
    27  	times int
    28  }
    29  
    30  // Times sets the number of times the request can be made.
    31  func (e *Expectation) Times(times int) *Expectation {
    32  	e.times = times
    33  
    34  	return e
    35  }
    36  
    37  // Header sets the HTTP headers that should be returned.
    38  func (e *Expectation) Header(k, v string) *Expectation {
    39  	e.headers = append(e.headers, k, v)
    40  
    41  	return e
    42  }
    43  
    44  // Handle sets the HTTP handler function to be run on the request.
    45  func (e *Expectation) Handle(fn http.HandlerFunc) {
    46  	e.fn = fn
    47  }
    48  
    49  // ReturnsStatus sets the HTTP stats code to return.
    50  func (e *Expectation) ReturnsStatus(status int) {
    51  	e.body = []byte{}
    52  	e.status = status
    53  }
    54  
    55  // Returns sets the HTTP stats and body bytes to return.
    56  func (e *Expectation) Returns(status int, body []byte) {
    57  	e.body = body
    58  	e.status = status
    59  }
    60  
    61  // ReturnsString sets the HTTP stats and body string to return.
    62  func (e *Expectation) ReturnsString(status int, body string) {
    63  	e.body = []byte(body)
    64  	e.status = status
    65  }
    66  
    67  // Server represents a mock http server.
    68  type Server struct {
    69  	t   *testing.T
    70  	srv *httptest.Server
    71  
    72  	expect []*Expectation
    73  }
    74  
    75  // NewServer creates a new mock http server.
    76  func NewServer(t *testing.T) *Server {
    77  	srv := &Server{
    78  		t: t,
    79  	}
    80  	srv.srv = httptest.NewServer(http.HandlerFunc(srv.handler))
    81  
    82  	return srv
    83  }
    84  
    85  // URL returns the url of the mock server.
    86  func (s *Server) URL() string {
    87  	return s.srv.URL
    88  }
    89  
    90  func (s *Server) handler(w http.ResponseWriter, r *http.Request) {
    91  	method := r.Method
    92  	path := r.URL.Path
    93  	for i, exp := range s.expect {
    94  		if exp.method != method && exp.method != Anything {
    95  			continue
    96  		}
    97  
    98  		if exp.path != Anything && !glob.Glob(exp.path, path) {
    99  			continue
   100  		}
   101  
   102  		for i := 0; i < len(exp.headers); i += 2 {
   103  			w.Header().Add(exp.headers[i], exp.headers[i+1])
   104  		}
   105  
   106  		if exp.fn != nil {
   107  			exp.fn(w, r)
   108  		} else {
   109  			w.WriteHeader(exp.status)
   110  			if len(exp.body) > 0 {
   111  				w.Write(exp.body)
   112  			}
   113  		}
   114  
   115  		exp.times--
   116  		if exp.times == 0 {
   117  			s.expect = append(s.expect[:i], s.expect[i+1:]...)
   118  		}
   119  		return
   120  	}
   121  
   122  	s.t.Errorf("Unexpected call to %s %s", method, path)
   123  }
   124  
   125  // On creates an expectation of a request on the server.
   126  func (s *Server) On(method, path string) *Expectation {
   127  	exp := &Expectation{
   128  		method: method,
   129  		path:   path,
   130  		times:  -1,
   131  		status: 200,
   132  	}
   133  	s.expect = append(s.expect, exp)
   134  
   135  	return exp
   136  }
   137  
   138  // AssertExpectations asserts all expectations have been met.
   139  func (s *Server) AssertExpectations() {
   140  	for _, exp := range s.expect {
   141  		if exp.times > 0 || exp.times == -1 {
   142  			s.t.Errorf("mock: server: Expected a call to %s %s but got none", exp.method, exp.path)
   143  		}
   144  	}
   145  }
   146  
   147  // Close closes the server.
   148  func (s *Server) Close() {
   149  	s.srv.Close()
   150  }