Skip to content

Commit

Permalink
Merge pull request #13 from steinfletcher/feature/cookies-issue-6
Browse files Browse the repository at this point in the history
Consolidate cookies into one method for request and response
  • Loading branch information
fergusstrange authored Jan 14, 2019
2 parents 9b32992 + babd54b commit a5fcf87
Show file tree
Hide file tree
Showing 10 changed files with 354 additions and 80 deletions.
13 changes: 5 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,15 +103,12 @@ func TestApi(t *testing.T) {
Patch("/hello").
Expect(t).
Status(http.StatusOK).
Cookies(map[string]string{
"ABC": "12345",
"DEF": "67890",
}).
Cookies(ExpectedCookie"ABC").Value("12345")).
CookiePresent("Session-Token").
CookieNotPresent("XXX").
HttpCookies([]http.Cookie{
{Name: "HIJ", Value: "12345"},
}).
Cookies(
ExpectedCookie"ABC").Value("12345"),
ExpectedCookie"DEF").Value("67890")).
End()
}
```
Expand Down Expand Up @@ -151,7 +148,7 @@ func TestApi(t *testing.T) {
apitest.New().
Handler(handler).
Get("/hello").
Cookies(map[string]string{"Cookie1": "Yummy"}).
Cookies(ExpectedCookie"ABC").Value("12345")).
Expect(t).
Status(http.StatusOK).
End()
Expand Down
79 changes: 21 additions & 58 deletions apitest.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package apitest

import (
"bufio"
"bytes"
"encoding/json"
"fmt"
Expand Down Expand Up @@ -71,7 +70,7 @@ type Request struct {
query map[string]string
queryCollection map[string][]string
headers map[string]string
cookies map[string]string
cookies []*expectedCookie
basicAuth string
apiTest *APITest
}
Expand Down Expand Up @@ -177,7 +176,7 @@ func (r *Request) Headers(h map[string]string) *Request {
}

// Cookies is a builder method to set the request cookies
func (r *Request) Cookies(c map[string]string) *Request {
func (r *Request) Cookies(c ...*expectedCookie) *Request {
r.cookies = c
return r
}
Expand All @@ -200,10 +199,9 @@ type Response struct {
status int
body string
headers map[string]string
cookies map[string]string
cookies []*expectedCookie
cookiesPresent []string
cookiesNotPresent []string
httpCookies []http.Cookie
jsonPathExpression string
jsonPathAssert func(interface{})
apiTest *APITest
Expand All @@ -220,17 +218,11 @@ func (r *Response) Body(b string) *Response {
}

// Cookies is the expected response cookies
func (r *Response) Cookies(cookies map[string]string) *Response {
func (r *Response) Cookies(cookies ...*expectedCookie) *Response {
r.cookies = cookies
return r
}

// HttpCookies is the expected response cookies
func (r *Response) HttpCookies(cookies []http.Cookie) *Response {
r.httpCookies = cookies
return r
}

// CookiePresent is used to assert that a cookie is present in the response,
// regardless of its value
func (r *Response) CookiePresent(cookieName string) *Response {
Expand Down Expand Up @@ -326,9 +318,8 @@ func (a *APITest) BuildRequest() *http.Request {
req.Header.Set(k, v)
}

for k, v := range a.request.cookies {
cookie := &http.Cookie{Name: k, Value: v}
req.AddCookie(cookie)
for _, cookie := range a.request.cookies {
req.AddCookie(cookie.ToHttpCookie())
}

if a.request.basicAuth != "" {
Expand Down Expand Up @@ -368,77 +359,49 @@ func (a *APITest) assertResponse(res *httptest.ResponseRecorder) {
}

func (a *APITest) assertCookies(response *httptest.ResponseRecorder) {
if a.response.cookies != nil {
for name, value := range a.response.cookies {
if len(a.response.cookies) > 0 {
for _, expectedCookie := range a.response.cookies {
var mismatchedFields []string
foundCookie := false
for _, cookie := range getResponseCookies(response) {
if cookie.Name == name && cookie.Value == value {
for _, actualCookie := range responseCookies(response) {
cookieFound, errors := compareCookies(expectedCookie, actualCookie)
if cookieFound {
foundCookie = true
mismatchedFields = append(mismatchedFields, errors...)
}
}
assertEqual(a.t, true, foundCookie, "Cookie not found - "+name)
assertEqual(a.t, true, foundCookie, "ExpectedCookie not found - "+*expectedCookie.name)
assertEqual(a.t, 0, len(mismatchedFields), mismatchedFields...)
}
}

if len(a.response.cookiesPresent) > 0 {
for _, cookieName := range a.response.cookiesPresent {
foundCookie := false
for _, cookie := range getResponseCookies(response) {
for _, cookie := range responseCookies(response) {
if cookie.Name == cookieName {
foundCookie = true
}
}
assertEqual(a.t, true, foundCookie, "Cookie not found - "+cookieName)
assertEqual(a.t, true, foundCookie, "ExpectedCookie not found - "+cookieName)
}
}

if len(a.response.cookiesNotPresent) > 0 {
for _, cookieName := range a.response.cookiesNotPresent {
foundCookie := false
for _, cookie := range getResponseCookies(response) {
for _, cookie := range responseCookies(response) {
if cookie.Name == cookieName {
foundCookie = true
}
}
assertEqual(a.t, false, foundCookie, "Cookie found - "+cookieName)
assertEqual(a.t, false, foundCookie, "ExpectedCookie found - "+cookieName)
}
}

if len(a.response.httpCookies) > 0 {
for _, httpCookie := range a.response.httpCookies {
foundCookie := false
for _, cookie := range getResponseCookies(response) {
if compareHttpCookies(cookie, &httpCookie) {
foundCookie = true
}
}
assertEqual(a.t, true, foundCookie, "Cookie not found - "+httpCookie.Name)
}
}
}

// only compare a subset of fields for flexibility
func compareHttpCookies(l *http.Cookie, r *http.Cookie) bool {
return l.Name == r.Name &&
l.Value == r.Value &&
l.Domain == r.Domain &&
l.Expires == r.Expires &&
l.MaxAge == r.MaxAge &&
l.Secure == r.Secure &&
l.HttpOnly == r.HttpOnly &&
l.SameSite == r.SameSite
}

func getResponseCookies(response *httptest.ResponseRecorder) []*http.Cookie {
for _, rawCookieString := range response.Result().Header["Set-Cookie"] {
rawRequest := fmt.Sprintf("GET / HTTP/1.0\r\nCookie: %s\r\n\r\n", rawCookieString)
req, err := http.ReadRequest(bufio.NewReader(strings.NewReader(rawRequest)))
if err != nil {
panic("failed to parse response cookies. error: " + err.Error())
}
return req.Cookies()
}
return []*http.Cookie{}
func responseCookies(response *httptest.ResponseRecorder) []*http.Cookie {
return response.Result().Cookies()
}

func (a *APITest) assertHeaders(res *httptest.ResponseRecorder) {
Expand Down
82 changes: 70 additions & 12 deletions apitest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"net/http"
"reflect"
"testing"
"time"
)

func TestApiTest_AddsJSONBodyToRequest(t *testing.T) {
Expand Down Expand Up @@ -141,7 +142,8 @@ func TestApiTest_AddsCookiesToRequest(t *testing.T) {
Handler(handler).
Method(http.MethodGet).
URL("/hello").
Cookies(map[string]string{"Cookie1": "Yummy"}).
Cookies(ExpectedCookie("Cookie1").
Value("Yummy")).
Expect(t).
Status(http.StatusOK).
End()
Expand Down Expand Up @@ -214,7 +216,24 @@ func TestApiTest_MatchesTextResponseBody(t *testing.T) {
func TestApiTest_MatchesResponseCookies(t *testing.T) {
handler := http.NewServeMux()
handler.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Set-Cookie", "ABC=12345; DEF=67890; XXX=1fsadg235; VVV=9ig32g34g")
w.Header().Set("Set-ExpectedCookie", "ABC=12345; DEF=67890; XXX=1fsadg235; VVV=9ig32g34g")
http.SetCookie(w, &http.Cookie{
Name: "ABC",
Value: "12345",
})
http.SetCookie(w, &http.Cookie{
Name: "DEF",
Value: "67890",
})
http.SetCookie(w, &http.Cookie{
Name: "XXX",
Value: "1fsadg235",
})
http.SetCookie(w, &http.Cookie{
Name: "VVV",
Value: "9ig32g34g",
})

w.WriteHeader(http.StatusOK)
})

Expand All @@ -223,31 +242,70 @@ func TestApiTest_MatchesResponseCookies(t *testing.T) {
Patch("/hello").
Expect(t).
Status(http.StatusOK).
Cookies(map[string]string{
"ABC": "12345",
"DEF": "67890",
}).
Cookies(
ExpectedCookie("ABC").Value("12345"),
ExpectedCookie("DEF").Value("67890")).
CookiePresent("XXX").
CookiePresent("VVV").
CookieNotPresent("ZZZ").
CookieNotPresent("TomBeer").
End()
}

func TestApiTest_MatchesResponseHttpCookies(t *testing.T) {
handler := http.NewServeMux()
handler.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Set-Cookie", "ABC=12345; DEF=67890;")
http.SetCookie(w, &http.Cookie{
Name: "ABC",
Value: "12345",
})
http.SetCookie(w, &http.Cookie{
Name: "DEF",
Value: "67890",
})
w.WriteHeader(http.StatusOK)
})

New().
Handler(handler).
Get("/hello").
Expect(t).
HttpCookies([]http.Cookie{
{Name: "ABC", Value: "12345"},
{Name: "DEF", Value: "67890"},
}).
Cookies(
ExpectedCookie("ABC").Value("12345"),
ExpectedCookie("DEF").Value("67890")).
End()
}

func TestApiTest_MatchesResponseHttpCookies_OnlySuppliedFields(t *testing.T) {
parsedDateTime, err := time.Parse(time.RFC3339, "2019-01-26T23:19:02Z")
if err != nil {
t.Fatalf("%s", err)
}

handler := http.NewServeMux()
handler.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
http.SetCookie(w, &http.Cookie{
Name: "session_id",
Value: "pdsanjdna_8e8922",
Path: "/",
Expires: parsedDateTime,
Secure: true,
HttpOnly: true,
})
w.WriteHeader(http.StatusOK)
})

New().
Handler(handler).
Get("/hello").
Expect(t).
Cookies(
ExpectedCookie("session_id").
Value("pdsanjdna_8e8922").
Path("/").
Expires(parsedDateTime).
Secure(true).
HttpOnly(true)).
End()
}

Expand All @@ -274,7 +332,7 @@ func TestApiTest_MatchesResponseHeaders(t *testing.T) {
func TestApiTest_CustomAssert(t *testing.T) {
handler := http.NewServeMux()
handler.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Set-Cookie", "ABC=12345; DEF=67890; XXX=1fsadg235; VVV=9ig32g34g")
w.Header().Set("Set-ExpectedCookie", "ABC=12345; DEF=67890; XXX=1fsadg235; VVV=9ig32g34g")
w.WriteHeader(http.StatusOK)
})

Expand Down
4 changes: 2 additions & 2 deletions assert.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ var IsServerError Assert = func(response *http.Response, request *http.Request)
func assertEqual(t *testing.T, expected, actual interface{}, message ...string) {
if !objectsAreEqual(expected, actual) {
if len(message) > 0 {
t.Fatalf(strings.Join(message, ","))
t.Fatalf(strings.Join(message, ", "))
} else {
t.Fatalf("Expected %s but recevied %s", expected, actual)
t.Fatalf("Expected %+v but recevied %+v", expected, actual)
}
}
}
Expand Down
Loading

0 comments on commit a5fcf87

Please sign in to comment.