Skip to content

Commit

Permalink
wrap endpoints, test bindings, assure calls
Browse files Browse the repository at this point in the history
  • Loading branch information
Jesse Michael committed Aug 22, 2017
1 parent 02786fa commit 1e20981
Show file tree
Hide file tree
Showing 8 changed files with 396 additions and 118 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ endif
ALL_PACKAGES = \
bindings \
endpoints \
assured \

LDFLAGS = -ldflags '-X main.gitSHA=$(shell git rev-parse HEAD)'

Expand Down
9 changes: 2 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
_________ ___ ______________ ___ __________ _____ _______
/ ___/ __ \ / _ \/ __/ __/_ __/ / _ | / __/ __/ / / / _ \/ __/ _ \
/ (_ / /_/ / / , _/ _/_\ \ / / / __ |_\ \_\ \/ /_/ / , _/ _// // /
\___/\____/ /_/|_/___/___/ /_/ /_/ |_/___/___/\____/_/|_/___/____/


=====================================================================
GO REST ASSURED
===============


Running
Expand Down
26 changes: 26 additions & 0 deletions assured/assured_call.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package assured

import (
"fmt"
)

// Call is a structure containing a request that is stubbed or made
type Call struct {
Path string
Method string
StatusCode int
Response []byte
}

// ID is used as a key when managing stubbed and made calls
func (c Call) ID() string {
return fmt.Sprintf("%s:%s", c.Method, c.Path)
}

// String converts a Call's Response into a string
func (c Call) String() string {
rawString := string(c.Response)

// TODO: implement string replacements for special cases
return rawString
}
36 changes: 36 additions & 0 deletions assured/assured_call_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package assured

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestCallID(t *testing.T) {
call := Call{
Path: "/given/test/assured",
Method: "GET",
}

require.Equal(t, "GET:/given/test/assured", call.ID())
}

func TestCallIDNil(t *testing.T) {
call := Call{}

require.Equal(t, ":", call.ID())
}

func TestCallString(t *testing.T) {
call := Call{
Response: []byte("GO assured is one way to GO"),
}

require.Equal(t, "GO assured is one way to GO", call.String())
}

func TestCallStringNil(t *testing.T) {
call := Call{}

require.Equal(t, "", call.String())
}
38 changes: 23 additions & 15 deletions bindings/assured_bindings.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ package bindings
import (
"context"
"encoding/json"
"io/ioutil"
"net/http"
"strconv"

kitlog "github.com/go-kit/kit/log"
kithttp "github.com/go-kit/kit/transport/http"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"github.com/jesse0michael/go-rest-assured/assured"
"github.com/jesse0michael/go-rest-assured/endpoints"
)

Expand Down Expand Up @@ -42,7 +44,7 @@ func createApplicationRouter(ctx context.Context, logger kitlog.Logger) *mux.Rou
router.Handle(
"/given/{path:.*}",
kithttp.NewServer(
e.GivenEndpoint,
e.WrappedEndpoint(e.GivenEndpoint),
decodeAssuredCall,
encodeAssuredCall,
kithttp.ServerErrorLogger(logger),
Expand All @@ -53,7 +55,7 @@ func createApplicationRouter(ctx context.Context, logger kitlog.Logger) *mux.Rou
router.Handle(
"/when/{path:.*}",
kithttp.NewServer(
e.WhenEndpoint,
e.WrappedEndpoint(e.WhenEndpoint),
decodeAssuredCall,
encodeAssuredCall,
kithttp.ServerErrorLogger(logger),
Expand All @@ -64,9 +66,9 @@ func createApplicationRouter(ctx context.Context, logger kitlog.Logger) *mux.Rou
router.Handle(
"/then/{path:.*}",
kithttp.NewServer(
e.ThenEndpoint,
e.WrappedEndpoint(e.ThenEndpoint),
decodeAssuredCall,
encodeAssuredCall,
encodeJSONResponse,
kithttp.ServerErrorLogger(logger),
kithttp.ServerAfter(kithttp.SetResponseHeader("Access-Control-Allow-Origin", "*")),
kithttp.ServerErrorEncoder(errorEncoder)),
Expand All @@ -75,7 +77,7 @@ func createApplicationRouter(ctx context.Context, logger kitlog.Logger) *mux.Rou
router.Handle(
"/clear/{path:.*}",
kithttp.NewServer(
e.ClearEndpoint,
e.WrappedEndpoint(e.ClearEndpoint),
decodeAssuredCall,
encodeAssuredCall,
kithttp.ServerErrorLogger(logger),
Expand All @@ -97,11 +99,11 @@ func createApplicationRouter(ctx context.Context, logger kitlog.Logger) *mux.Rou
return router
}

// decodeAssuredCall converts an http request into an assured Call object
func decodeAssuredCall(ctx context.Context, req *http.Request) (interface{}, error) {
urlParams := mux.Vars(req)

ac := endpoints.AssuredCall{
Path: urlParams["path"],
ac := assured.Call{
Path: req.URL.Path,
Method: req.Method,
StatusCode: http.StatusOK,
}
if statusCode, err := strconv.ParseInt(req.Header.Get("Assured-Status"), 10, 64); err == nil {
Expand All @@ -110,23 +112,29 @@ func decodeAssuredCall(ctx context.Context, req *http.Request) (interface{}, err

if req.Body != nil {
defer req.Body.Close()
json.NewDecoder(req.Body).Decode(ac.Response)
if bytes, err := ioutil.ReadAll(req.Body); err == nil {
ac.Response = bytes
}
}

return &ac, nil
}

// encodeAssuredCall writes the assured Call to the http response as it is intended to be stubbed
func encodeAssuredCall(ctx context.Context, w http.ResponseWriter, i interface{}) error {
if call, ok := i.(*endpoints.AssuredCall); ok {
if call, ok := i.(*assured.Call); ok {
w.WriteHeader(call.StatusCode)
if call.Response != nil {
w.Header().Set("Content-Type", "application/json") // Content-Type needs to be set before WriteHeader https://golang.org/pkg/net/http/#ResponseWriter
return json.NewEncoder(w).Encode(call.Response)
}
w.Write([]byte(call.String()))
}
return nil
}

// encodeJSONResponse writes to the http response as JSON
func encodeJSONResponse(ctx context.Context, w http.ResponseWriter, i interface{}) error {
w.Header().Set("Content-Type", "application/json")
return json.NewEncoder(w).Encode(i)
}

func errorEncoder(ctx context.Context, err error, w http.ResponseWriter) {

}
187 changes: 187 additions & 0 deletions bindings/assured_bindings_test.go
Original file line number Diff line number Diff line change
@@ -1 +1,188 @@
package bindings

import (
"bytes"
"context"
"io/ioutil"
"net/http"
"net/http/httptest"
"testing"

kitlog "github.com/go-kit/kit/log"
"github.com/jesse0michael/go-rest-assured/assured"
"github.com/stretchr/testify/require"
)

func TestApplicationRouterGivenBinding(t *testing.T) {
router := createApplicationRouter(ctx, kitlog.NewLogfmtLogger(ioutil.Discard))

for _, verb := range verbs {
req, err := http.NewRequest(verb, "/given/rest/assured", nil)
require.NoError(t, err)
resp := httptest.NewRecorder()
router.ServeHTTP(resp, req)
require.Equal(t, http.StatusOK, resp.Code)
require.Equal(t, "*", resp.Header().Get("Access-Control-Allow-Origin"))
}
}

func TestApplicationRouterWhenBinding(t *testing.T) {
router := createApplicationRouter(ctx, kitlog.NewLogfmtLogger(ioutil.Discard))

for _, verb := range verbs {
req, err := http.NewRequest(verb, "/given/rest/assured", bytes.NewBuffer([]byte(`{"assured": true}`)))
require.NoError(t, err)
resp := httptest.NewRecorder()
router.ServeHTTP(resp, req)

req, err = http.NewRequest(verb, "/when/rest/assured", nil)
require.NoError(t, err)
resp = httptest.NewRecorder()
router.ServeHTTP(resp, req)
require.Equal(t, http.StatusOK, resp.Code)
require.Equal(t, "*", resp.Header().Get("Access-Control-Allow-Origin"))
}
}

func TestApplicationRouterThenBinding(t *testing.T) {
router := createApplicationRouter(ctx, kitlog.NewLogfmtLogger(ioutil.Discard))

for _, verb := range verbs {
req, err := http.NewRequest(verb, "/then/rest/assured", nil)
require.NoError(t, err)
resp := httptest.NewRecorder()
router.ServeHTTP(resp, req)
require.Equal(t, http.StatusOK, resp.Code)
require.Equal(t, "*", resp.Header().Get("Access-Control-Allow-Origin"))
}
}

func TestApplicationRouterClearBinding(t *testing.T) {
router := createApplicationRouter(ctx, kitlog.NewLogfmtLogger(ioutil.Discard))

req, err := http.NewRequest(http.MethodDelete, "/clear/rest/assured", nil)
require.NoError(t, err)
resp := httptest.NewRecorder()
router.ServeHTTP(resp, req)
require.Equal(t, http.StatusOK, resp.Code)
require.Equal(t, "*", resp.Header().Get("Access-Control-Allow-Origin"))
}

func TestApplicationRouterClearAllBinding(t *testing.T) {
router := createApplicationRouter(ctx, kitlog.NewLogfmtLogger(ioutil.Discard))

req, err := http.NewRequest(http.MethodDelete, "/clear", nil)
require.NoError(t, err)
resp := httptest.NewRecorder()
router.ServeHTTP(resp, req)
require.Equal(t, http.StatusOK, resp.Code)
require.Equal(t, "*", resp.Header().Get("Access-Control-Allow-Origin"))
}

func TestApplicationRouterFailure(t *testing.T) {
router := createApplicationRouter(ctx, kitlog.NewLogfmtLogger(ioutil.Discard))

req, err := http.NewRequest(http.MethodGet, "/trouble", nil)
require.NoError(t, err)
resp := httptest.NewRecorder()
router.ServeHTTP(resp, req)
require.Equal(t, http.StatusNotFound, resp.Code)
}

func TestDecodeAssuredCall(t *testing.T) {
req, err := http.NewRequest(http.MethodPost, "/then/test/assured?test=positive", bytes.NewBuffer([]byte(`{"assured": true}`)))
require.NoError(t, err)
expected := &assured.Call{
Path: "/then/test/assured",
StatusCode: http.StatusOK,
Method: http.MethodPost,
Response: []byte(`{"assured": true}`),
}

c, err := decodeAssuredCall(ctx, req)

require.NoError(t, err)
require.Equal(t, expected, c)
}

func TestDecodeAssuredCallNilBody(t *testing.T) {
req, err := http.NewRequest(http.MethodDelete, "/when/test/assured", nil)
require.NoError(t, err)
expected := &assured.Call{
Path: "/when/test/assured",
StatusCode: http.StatusOK,
Method: http.MethodDelete,
}

c, err := decodeAssuredCall(ctx, req)

require.NoError(t, err)
require.Equal(t, expected, c)
}

func TestDecodeAssuredCallStatus(t *testing.T) {
req, err := http.NewRequest(http.MethodGet, "/given/test/assured", nil)
require.NoError(t, err)
req.Header.Set("Assured-Status", "403")
expected := &assured.Call{
Path: "/given/test/assured",
StatusCode: http.StatusForbidden,
Method: http.MethodGet,
}

c, err := decodeAssuredCall(ctx, req)

require.NoError(t, err)
require.Equal(t, expected, c)
}

func TestDecodeAssuredCallStatusFailure(t *testing.T) {
req, err := http.NewRequest(http.MethodGet, "/given/test/assured", nil)
require.NoError(t, err)
req.Header.Set("Assured-Status", "four oh three")
expected := &assured.Call{
Path: "/given/test/assured",
StatusCode: http.StatusOK,
Method: http.MethodGet,
}

c, err := decodeAssuredCall(ctx, req)

require.NoError(t, err)
require.Equal(t, expected, c)
}

func TestEncodeAssuredCall(t *testing.T) {
call := &assured.Call{
Path: "/then/test/assured",
StatusCode: http.StatusCreated,
Method: http.MethodPost,
Response: []byte(`{"assured": true}`),
}
resp := httptest.NewRecorder()

err := encodeAssuredCall(ctx, resp, call)

require.NoError(t, err)
require.Equal(t, http.StatusCreated, resp.Code)
require.Equal(t, `{"assured": true}`, resp.Body.String())
}

var (
ctx = context.Background()
verbs = []string{
http.MethodGet,
http.MethodHead,
http.MethodPost,
http.MethodPut,
http.MethodPatch,
http.MethodDelete,
http.MethodConnect,
http.MethodOptions,
}
paths = []string{
"/given/test/assured",
"/when/test/assured",
"/then/test/assured",
}
)
Loading

0 comments on commit 1e20981

Please sign in to comment.