initial commit
This commit is contained in:
137
internal/httpclient/httpclient.go
Normal file
137
internal/httpclient/httpclient.go
Normal file
@@ -0,0 +1,137 @@
|
||||
package httpclient
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"net"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// HTTPClient is an interface for initializing the http client library.
|
||||
type HTTPClient struct {
|
||||
Client *http.Client
|
||||
Data *bytes.Buffer
|
||||
Headers map[string]string
|
||||
|
||||
Username string
|
||||
Password string
|
||||
}
|
||||
|
||||
// DefaultClient is a function for defining a basic HTTP client with standard timeouts.
|
||||
func DefaultClient() *HTTPClient {
|
||||
return &HTTPClient{
|
||||
Client: &http.Client{
|
||||
Timeout: 60 * time.Second,
|
||||
Transport: &http.Transport{
|
||||
Dial: (&net.Dialer{
|
||||
Timeout: 5 * time.Second,
|
||||
}).Dial,
|
||||
TLSHandshakeTimeout: 5 * time.Second,
|
||||
IdleConnTimeout: 300 * time.Second,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewClient Create an HTTPClient with a user-provided net/http.Client
|
||||
func NewClient(httpClient *http.Client) *HTTPClient {
|
||||
return &HTTPClient{Client: httpClient}
|
||||
}
|
||||
|
||||
// SetBasicAuth is a chaining function to set the username and password for basic
|
||||
// authentication
|
||||
func (c *HTTPClient) SetBasicAuth(username, password string) *HTTPClient {
|
||||
c.Username = username
|
||||
c.Password = password
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// SetPostData is a chaining function to set POST/PUT/PATCH data
|
||||
func (c *HTTPClient) SetPostData(data string) *HTTPClient {
|
||||
c.Data = bytes.NewBufferString(data)
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// SetHeader is a chaining function to set arbitrary HTTP Headers
|
||||
func (c *HTTPClient) SetHeader(label string, value string) *HTTPClient {
|
||||
if c.Headers == nil {
|
||||
c.Headers = map[string]string{}
|
||||
}
|
||||
|
||||
c.Headers[label] = value
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// Get calls the net.http GET operation
|
||||
func (c *HTTPClient) Get(url string) ([]byte, error) {
|
||||
return c.do(url, http.MethodGet)
|
||||
}
|
||||
|
||||
// Patch calls the net.http PATCH operation
|
||||
func (c *HTTPClient) Patch(url string) ([]byte, error) {
|
||||
return c.do(url, http.MethodPatch)
|
||||
}
|
||||
|
||||
// Post calls the net.http POST operation
|
||||
func (c *HTTPClient) Post(url string) ([]byte, error) {
|
||||
return c.do(url, http.MethodPost)
|
||||
}
|
||||
|
||||
// Put calls the net.http PUT operation
|
||||
func (c *HTTPClient) Put(url string) ([]byte, error) {
|
||||
return c.do(url, http.MethodPut)
|
||||
}
|
||||
|
||||
func (c *HTTPClient) do(url string, method string) ([]byte, error) {
|
||||
var (
|
||||
req *http.Request
|
||||
res *http.Response
|
||||
output []byte
|
||||
err error
|
||||
)
|
||||
|
||||
// NewRequest knows that c.data is typed *bytes.Buffer and will SEGFAULT
|
||||
// if c.data is nil. So we create a request using nil when c.data is nil
|
||||
if c.Data != nil {
|
||||
req, err = http.NewRequest(method, url, c.Data)
|
||||
} else {
|
||||
req, err = http.NewRequest(method, url, nil)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if (len(c.Username) > 0) && (len(c.Password) > 0) {
|
||||
req.SetBasicAuth(c.Username, c.Password)
|
||||
}
|
||||
|
||||
if c.Headers != nil {
|
||||
for label, value := range c.Headers {
|
||||
req.Header.Set(label, value)
|
||||
}
|
||||
}
|
||||
|
||||
if res, err = c.Client.Do(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer res.Body.Close()
|
||||
|
||||
if output, err = ioutil.ReadAll(res.Body); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// check status
|
||||
if res.StatusCode < 200 || res.StatusCode >= 300 {
|
||||
return nil, errors.New("non-successful status code received [" + strconv.Itoa(res.StatusCode) + "]")
|
||||
}
|
||||
|
||||
return output, nil
|
||||
}
|
281
internal/httpclient/httpclient_test.go
Normal file
281
internal/httpclient/httpclient_test.go
Normal file
@@ -0,0 +1,281 @@
|
||||
package httpclient
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
)
|
||||
|
||||
type Data struct {
|
||||
Greeting string `json:"greeting"`
|
||||
Headers map[string]string `json:"headers"`
|
||||
Method string `json:"method"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
PostData string `json:"postdata"`
|
||||
}
|
||||
|
||||
var (
|
||||
greeting = "Hello world"
|
||||
postData = "Test data"
|
||||
authUser = "testuser"
|
||||
authPass = "testpass"
|
||||
headerLabel = "Test-Header"
|
||||
headerValue = "Test-Value"
|
||||
)
|
||||
|
||||
func httpTestHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
b []byte
|
||||
user string
|
||||
pass string
|
||||
body []byte
|
||||
)
|
||||
|
||||
data := Data{
|
||||
Greeting: greeting,
|
||||
Headers: map[string]string{},
|
||||
Method: r.Method,
|
||||
}
|
||||
|
||||
user, pass, ok := r.BasicAuth()
|
||||
if ok {
|
||||
data.Username = user
|
||||
data.Password = pass
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
fmt.Fprint(w, "ioutil.ReadAll failed")
|
||||
}
|
||||
data.PostData = string(body)
|
||||
|
||||
for h := range r.Header {
|
||||
data.Headers[h] = r.Header.Get(h)
|
||||
}
|
||||
|
||||
b, err = json.MarshalIndent(data, "", " ")
|
||||
if err != nil {
|
||||
fmt.Fprint(w, "Json marshal failed somehow")
|
||||
}
|
||||
fmt.Fprint(w, string(b))
|
||||
}
|
||||
|
||||
func checkMethod(t *testing.T, data Data, method string) {
|
||||
if data.Method != method {
|
||||
t.Errorf("data.Method(%s) != method(%s)", data.Method, method)
|
||||
}
|
||||
t.Log("checkMethod() success")
|
||||
}
|
||||
|
||||
func checkGreeting(t *testing.T, data Data) {
|
||||
if data.Greeting != greeting {
|
||||
t.Errorf("data.Greeting(%s) != greeting(%s)", data.Greeting, greeting)
|
||||
}
|
||||
t.Log("checkGreeting() success")
|
||||
}
|
||||
|
||||
func checkBasicAuth(t *testing.T, data Data) {
|
||||
if data.Username != authUser {
|
||||
t.Errorf("data.Username(%s) != authUser(%s)", data.Username, authUser)
|
||||
}
|
||||
if data.Password != authPass {
|
||||
t.Errorf("data.Password(%s) != authPass(%s)", data.Password, authPass)
|
||||
}
|
||||
t.Log("checkBasicAuth() success")
|
||||
}
|
||||
|
||||
func checkPostData(t *testing.T, data Data) {
|
||||
if data.PostData != postData {
|
||||
t.Errorf("data.PostData(%s) != postData(%s)", data.PostData, postData)
|
||||
}
|
||||
t.Log("checkPostData() success")
|
||||
}
|
||||
|
||||
func TestGet(t *testing.T) {
|
||||
var data Data
|
||||
|
||||
ts := httptest.NewServer(http.HandlerFunc(httpTestHandler))
|
||||
defer ts.Close()
|
||||
|
||||
output, err := DefaultClient().Get(ts.URL)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(output, &data); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
checkMethod(t, data, http.MethodGet)
|
||||
checkGreeting(t, data)
|
||||
}
|
||||
|
||||
func TestGetAuth(t *testing.T) {
|
||||
var data Data
|
||||
|
||||
ts := httptest.NewServer(http.HandlerFunc(httpTestHandler))
|
||||
defer ts.Close()
|
||||
|
||||
output, err := DefaultClient().SetBasicAuth(authUser, authPass).Get(ts.URL)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(output, &data); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
checkMethod(t, data, http.MethodGet)
|
||||
checkGreeting(t, data)
|
||||
checkBasicAuth(t, data)
|
||||
}
|
||||
|
||||
func TestPut(t *testing.T) {
|
||||
var data Data
|
||||
|
||||
ts := httptest.NewServer(http.HandlerFunc(httpTestHandler))
|
||||
defer ts.Close()
|
||||
|
||||
output, err := DefaultClient().SetPostData(postData).Put(ts.URL)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(output, &data); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
checkMethod(t, data, http.MethodPut)
|
||||
checkGreeting(t, data)
|
||||
checkPostData(t, data)
|
||||
}
|
||||
|
||||
func TestPutAuth(t *testing.T) {
|
||||
var data Data
|
||||
|
||||
ts := httptest.NewServer(http.HandlerFunc(httpTestHandler))
|
||||
defer ts.Close()
|
||||
|
||||
output, err := DefaultClient().SetBasicAuth(authUser, authPass).SetPostData(postData).Put(ts.URL)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(output, &data); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
checkMethod(t, data, http.MethodPut)
|
||||
checkGreeting(t, data)
|
||||
checkBasicAuth(t, data)
|
||||
checkPostData(t, data)
|
||||
}
|
||||
|
||||
func TestPost(t *testing.T) {
|
||||
var data Data
|
||||
|
||||
ts := httptest.NewServer(http.HandlerFunc(httpTestHandler))
|
||||
defer ts.Close()
|
||||
|
||||
output, err := DefaultClient().SetPostData(postData).Post(ts.URL)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(output, &data); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
checkMethod(t, data, http.MethodPost)
|
||||
checkGreeting(t, data)
|
||||
checkPostData(t, data)
|
||||
}
|
||||
|
||||
func TestPostAuth(t *testing.T) {
|
||||
var data Data
|
||||
|
||||
ts := httptest.NewServer(http.HandlerFunc(httpTestHandler))
|
||||
defer ts.Close()
|
||||
|
||||
output, err := DefaultClient().SetBasicAuth(authUser, authPass).SetPostData(postData).Post(ts.URL)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(output, &data); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
checkMethod(t, data, http.MethodPost)
|
||||
checkGreeting(t, data)
|
||||
checkBasicAuth(t, data)
|
||||
checkPostData(t, data)
|
||||
}
|
||||
|
||||
func TestPatch(t *testing.T) {
|
||||
var data Data
|
||||
|
||||
ts := httptest.NewServer(http.HandlerFunc(httpTestHandler))
|
||||
defer ts.Close()
|
||||
|
||||
output, err := DefaultClient().SetPostData(postData).Patch(ts.URL)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(output, &data); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
checkMethod(t, data, http.MethodPatch)
|
||||
checkGreeting(t, data)
|
||||
checkPostData(t, data)
|
||||
}
|
||||
|
||||
func TestPatchAuth(t *testing.T) {
|
||||
var data Data
|
||||
|
||||
ts := httptest.NewServer(http.HandlerFunc(httpTestHandler))
|
||||
defer ts.Close()
|
||||
|
||||
output, err := DefaultClient().SetBasicAuth(authUser, authPass).SetPostData(postData).Patch(ts.URL)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(output, &data); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
checkMethod(t, data, http.MethodPatch)
|
||||
checkGreeting(t, data)
|
||||
checkBasicAuth(t, data)
|
||||
checkPostData(t, data)
|
||||
}
|
||||
|
||||
func TestSetHeader(t *testing.T) {
|
||||
var data Data
|
||||
|
||||
ts := httptest.NewServer(http.HandlerFunc(httpTestHandler))
|
||||
defer ts.Close()
|
||||
|
||||
output, err := DefaultClient().SetHeader(headerLabel, headerValue).Get(ts.URL)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(output, &data); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
checkMethod(t, data, http.MethodGet)
|
||||
checkGreeting(t, data)
|
||||
if data.Headers[headerLabel] != headerValue {
|
||||
t.Errorf("SetHeader values not set in header: %+v", data.Headers)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user