github.com/cli/cli@v1.14.1-0.20210902173923-1af6a669e342/pkg/httpmock/stub.go (about)

     1  package httpmock
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"io"
     7  	"io/ioutil"
     8  	"net/http"
     9  	"os"
    10  	"regexp"
    11  	"strings"
    12  )
    13  
    14  type Matcher func(req *http.Request) bool
    15  type Responder func(req *http.Request) (*http.Response, error)
    16  
    17  type Stub struct {
    18  	matched   bool
    19  	Matcher   Matcher
    20  	Responder Responder
    21  }
    22  
    23  func MatchAny(*http.Request) bool {
    24  	return true
    25  }
    26  
    27  func REST(method, p string) Matcher {
    28  	return func(req *http.Request) bool {
    29  		if !strings.EqualFold(req.Method, method) {
    30  			return false
    31  		}
    32  		if req.URL.Path != "/"+p {
    33  			return false
    34  		}
    35  		return true
    36  	}
    37  }
    38  
    39  func GraphQL(q string) Matcher {
    40  	re := regexp.MustCompile(q)
    41  
    42  	return func(req *http.Request) bool {
    43  		if !strings.EqualFold(req.Method, "POST") {
    44  			return false
    45  		}
    46  		if req.URL.Path != "/graphql" && req.URL.Path != "/api/graphql" {
    47  			return false
    48  		}
    49  
    50  		var bodyData struct {
    51  			Query string
    52  		}
    53  		_ = decodeJSONBody(req, &bodyData)
    54  
    55  		return re.MatchString(bodyData.Query)
    56  	}
    57  }
    58  
    59  func readBody(req *http.Request) ([]byte, error) {
    60  	bodyCopy := &bytes.Buffer{}
    61  	r := io.TeeReader(req.Body, bodyCopy)
    62  	req.Body = ioutil.NopCloser(bodyCopy)
    63  	return ioutil.ReadAll(r)
    64  }
    65  
    66  func decodeJSONBody(req *http.Request, dest interface{}) error {
    67  	b, err := readBody(req)
    68  	if err != nil {
    69  		return err
    70  	}
    71  	return json.Unmarshal(b, dest)
    72  }
    73  
    74  func StringResponse(body string) Responder {
    75  	return func(req *http.Request) (*http.Response, error) {
    76  		return httpResponse(200, req, bytes.NewBufferString(body)), nil
    77  	}
    78  }
    79  
    80  func StatusStringResponse(status int, body string) Responder {
    81  	return func(req *http.Request) (*http.Response, error) {
    82  		return httpResponse(status, req, bytes.NewBufferString(body)), nil
    83  	}
    84  }
    85  
    86  func JSONResponse(body interface{}) Responder {
    87  	return func(req *http.Request) (*http.Response, error) {
    88  		b, _ := json.Marshal(body)
    89  		return httpResponse(200, req, bytes.NewBuffer(b)), nil
    90  	}
    91  }
    92  
    93  func FileResponse(filename string) Responder {
    94  	return func(req *http.Request) (*http.Response, error) {
    95  		f, err := os.Open(filename)
    96  		if err != nil {
    97  			return nil, err
    98  		}
    99  		return httpResponse(200, req, f), nil
   100  	}
   101  }
   102  
   103  func RESTPayload(responseStatus int, responseBody string, cb func(payload map[string]interface{})) Responder {
   104  	return func(req *http.Request) (*http.Response, error) {
   105  		bodyData := make(map[string]interface{})
   106  		err := decodeJSONBody(req, &bodyData)
   107  		if err != nil {
   108  			return nil, err
   109  		}
   110  		cb(bodyData)
   111  		return httpResponse(responseStatus, req, bytes.NewBufferString(responseBody)), nil
   112  	}
   113  }
   114  func GraphQLMutation(body string, cb func(map[string]interface{})) Responder {
   115  	return func(req *http.Request) (*http.Response, error) {
   116  		var bodyData struct {
   117  			Variables struct {
   118  				Input map[string]interface{}
   119  			}
   120  		}
   121  		err := decodeJSONBody(req, &bodyData)
   122  		if err != nil {
   123  			return nil, err
   124  		}
   125  		cb(bodyData.Variables.Input)
   126  
   127  		return httpResponse(200, req, bytes.NewBufferString(body)), nil
   128  	}
   129  }
   130  
   131  func GraphQLQuery(body string, cb func(string, map[string]interface{})) Responder {
   132  	return func(req *http.Request) (*http.Response, error) {
   133  		var bodyData struct {
   134  			Query     string
   135  			Variables map[string]interface{}
   136  		}
   137  		err := decodeJSONBody(req, &bodyData)
   138  		if err != nil {
   139  			return nil, err
   140  		}
   141  		cb(bodyData.Query, bodyData.Variables)
   142  
   143  		return httpResponse(200, req, bytes.NewBufferString(body)), nil
   144  	}
   145  }
   146  
   147  func ScopesResponder(scopes string) func(*http.Request) (*http.Response, error) {
   148  	return func(req *http.Request) (*http.Response, error) {
   149  		return &http.Response{
   150  			StatusCode: 200,
   151  			Request:    req,
   152  			Header: map[string][]string{
   153  				"X-Oauth-Scopes": {scopes},
   154  			},
   155  			Body: ioutil.NopCloser(bytes.NewBufferString("")),
   156  		}, nil
   157  	}
   158  }
   159  
   160  func httpResponse(status int, req *http.Request, body io.Reader) *http.Response {
   161  	return &http.Response{
   162  		StatusCode: status,
   163  		Request:    req,
   164  		Body:       ioutil.NopCloser(body),
   165  	}
   166  }