From 992d429d2a969868ca66002744c9faf61a4229f2 Mon Sep 17 00:00:00 2001 From: Frank Mueller Date: Sat, 11 Feb 2017 22:56:07 +0100 Subject: [PATCH 1/3] Started with version 2.12.0 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 71bf50b..4b3616c 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ I hope you like it. ;) ## Version -Version 2.11.0 +Version 2.12.0 ## Packages From 76b132d6bb18704b617bfc1c0bf43a3ee07a6996 Mon Sep 17 00:00:00 2001 From: Frank Mueller Date: Sat, 11 Feb 2017 23:51:35 +0100 Subject: [PATCH 2/3] Made testing with restaudit more simple --- rest/rest_test.go | 86 ++++++++++++++++----------------- restaudit/restaudit.go | 107 ++++++++++++++++++++++++++--------------- 2 files changed, 110 insertions(+), 83 deletions(-) diff --git a/rest/rest_test.go b/rest/rest_test.go index efa5e88..a950692 100644 --- a/rest/rest_test.go +++ b/rest/rest_test.go @@ -46,13 +46,13 @@ func TestGetJSON(t *testing.T) { err := mux.Register("test", "json", NewTestHandler("json", assert)) assert.Nil(err) // Perform test requests. - req := restaudit.NewRequest("GET", "/base/test/json/4711?foo=0815") + req := restaudit.NewRequest(assert, "GET", "/base/test/json/4711?foo=0815") req.AddHeader(restaudit.HeaderAccept, restaudit.ApplicationJSON) resp := ts.DoRequest(req) - resp.AssertStatus(assert, 200) - resp.AssertContentMatch(assert, `.*"ResourceID":"4711".*`) - resp.AssertContentMatch(assert, `.*"Query":"0815".*`) - resp.AssertContentMatch(assert, `.*"Context":"foo".*`) + resp.AssertStatusEquals(200) + resp.AssertBodyContains(`"ResourceID":"4711"`) + resp.AssertBodyContains(`"Query":"0815"`) + resp.AssertBodyContains(`"Context":"foo"`) } // TestPutJSON tests the PUT command with a JSON payload and result. @@ -65,13 +65,13 @@ func TestPutJSON(t *testing.T) { err := mux.Register("test", "json", NewTestHandler("json", assert)) assert.Nil(err) // Perform test requests. - req := restaudit.NewRequest("PUT", "/base/test/json/4711") + req := restaudit.NewRequest(assert, "PUT", "/base/test/json/4711") reqData := TestRequestData{"foo", "bar", "4711", "0815", ""} - req.SetContent(assert, restaudit.ApplicationJSON, reqData) + req.SetBody(restaudit.ApplicationJSON, reqData) resp := ts.DoRequest(req) - resp.AssertStatus(assert, 200) + resp.AssertStatusEquals(200) respData := TestRequestData{} - resp.AssertContent(assert, &respData) + resp.AssertBody(&respData) assert.Equal(respData, reqData) } @@ -85,11 +85,11 @@ func TestGetXML(t *testing.T) { err := mux.Register("test", "xml", NewTestHandler("xml", assert)) assert.Nil(err) // Perform test requests. - req := restaudit.NewRequest("GET", "/base/test/xml/4711") + req := restaudit.NewRequest(assert, "GET", "/base/test/xml/4711") req.AddHeader(restaudit.HeaderAccept, restaudit.ApplicationXML) resp := ts.DoRequest(req) - resp.AssertStatus(assert, 200) - resp.AssertContentMatch(assert, `.*4711.*`) + resp.AssertStatusEquals(200) + resp.AssertBodyContains(`4711`) } // TestPutXML tests the PUT command with a XML payload and result. @@ -102,13 +102,13 @@ func TestPutXML(t *testing.T) { err := mux.Register("test", "xml", NewTestHandler("xml", assert)) assert.Nil(err) // Perform test requests. - req := restaudit.NewRequest("PUT", "/base/test/xml/4711") + req := restaudit.NewRequest(assert, "PUT", "/base/test/xml/4711") reqData := TestRequestData{"foo", "bar", "4711", "0815", ""} - req.SetContent(assert, restaudit.ApplicationXML, reqData) + req.SetBody(restaudit.ApplicationXML, reqData) resp := ts.DoRequest(req) - resp.AssertStatus(assert, 200) + resp.AssertStatusEquals(200) respData := TestRequestData{} - resp.AssertContent(assert, &respData) + resp.AssertBody(&respData) assert.Equal(respData, reqData) } @@ -122,13 +122,13 @@ func TestPutGOB(t *testing.T) { err := mux.Register("test", "gob", NewTestHandler("putgob", assert)) assert.Nil(err) // Perform test requests. - req := restaudit.NewRequest("POST", "/base/test/gob") + req := restaudit.NewRequest(assert, "POST", "/base/test/gob") reqData := TestCounterData{"test", 4711} - req.SetContent(assert, restaudit.ApplicationGOB, reqData) + req.SetBody(restaudit.ApplicationGOB, reqData) resp := ts.DoRequest(req) - resp.AssertStatus(assert, 200) + resp.AssertStatusEquals(200) respData := TestCounterData{} - resp.AssertContent(assert, &respData) + resp.AssertBody(&respData) assert.Equal(respData, reqData) } @@ -142,9 +142,9 @@ func TestLongPath(t *testing.T) { err := mux.Register("content", "blog", NewTestHandler("default", assert)) assert.Nil(err) // Perform test requests. - req := restaudit.NewRequest("GET", "/base/content/blog/2014/09/30/just-a-test") + req := restaudit.NewRequest(assert, "GET", "/base/content/blog/2014/09/30/just-a-test") resp := ts.DoRequest(req) - resp.AssertContentMatch(assert, `.*Resource ID: 2014/09/30/just-a-test.*`) + resp.AssertBodyContains(`Resource ID: 2014/09/30/just-a-test`) } // TestFallbackDefault tests the fallback to default. @@ -157,9 +157,9 @@ func TestFallbackDefault(t *testing.T) { err := mux.Register("testing", "index", NewTestHandler("default", assert)) assert.Nil(err) // Perform test requests. - req := restaudit.NewRequest("GET", "/base/x/y") + req := restaudit.NewRequest(assert, "GET", "/base/x/y") resp := ts.DoRequest(req) - resp.AssertContentMatch(assert, `.*Resource: y.*`) + resp.AssertBodyContains(`Resource: y`) } // TestHandlerStack tests a complete handler stack. @@ -176,17 +176,16 @@ func TestHandlerStack(t *testing.T) { }) assert.Nil(err) // Perform test requests. - req := restaudit.NewRequest("GET", "/base/test/stack") + req := restaudit.NewRequest(assert, "GET", "/base/test/stack") resp := ts.DoRequest(req) - resp.AssertContentMatch(assert, ".*Resource: token.*") - token := resp.AssertHeader(assert, "Token") - assert.Equal(token, "foo") - req = restaudit.NewRequest("GET", "/base/test/stack") + resp.AssertBodyContains("Resource: token") + resp.AssertHeaderEquals("Token", "foo") + req = restaudit.NewRequest(assert, "GET", "/base/test/stack") req.AddHeader("token", "foo") resp = ts.DoRequest(req) - resp.AssertContentMatch(assert, ".*Resource: stack.*") + resp.AssertBodyContains("Resource: stack") resp = ts.DoRequest(req) - resp.AssertContentMatch(assert, ".*Resource: stack.*") + resp.AssertBodyContains("Resource: stack") } // TestVersion tests request and response version. @@ -199,28 +198,25 @@ func TestVersion(t *testing.T) { err := mux.Register("test", "json", NewTestHandler("json", assert)) assert.Nil(err) // Perform test requests. - req := restaudit.NewRequest("GET", "/base/test/json/4711?foo=0815") + req := restaudit.NewRequest(assert, "GET", "/base/test/json/4711?foo=0815") req.AddHeader(restaudit.HeaderAccept, restaudit.ApplicationJSON) resp := ts.DoRequest(req) - resp.AssertStatus(assert, 200) - vsn := resp.AssertHeader(assert, "Version") - assert.Equal(vsn, "1.0.0") + resp.AssertStatusEquals(200) + resp.AssertHeaderEquals("Version", "1.0.0") - req = restaudit.NewRequest("GET", "/base/test/json/4711?foo=0815") + req = restaudit.NewRequest(assert, "GET", "/base/test/json/4711?foo=0815") req.AddHeader(restaudit.HeaderAccept, restaudit.ApplicationJSON) req.AddHeader("Version", "2") resp = ts.DoRequest(req) - resp.AssertStatus(assert, 200) - vsn = resp.AssertHeader(assert, "Version") - assert.Equal(vsn, "2.0.0") + resp.AssertStatusEquals(200) + resp.AssertHeaderEquals("Version", "2.0.0") - req = restaudit.NewRequest("GET", "/base/test/json/4711?foo=0815") + req = restaudit.NewRequest(assert, "GET", "/base/test/json/4711?foo=0815") req.AddHeader(restaudit.HeaderAccept, restaudit.ApplicationJSON) req.AddHeader("Version", "3.0") resp = ts.DoRequest(req) - resp.AssertStatus(assert, 200) - vsn = resp.AssertHeader(assert, "Version") - assert.Equal(vsn, "4.0.0-alpha") + resp.AssertStatusEquals(200) + resp.AssertHeaderEquals("Version", "4.0.0-alpha") } // TestDeregister tests the different possibilities to stop handlers. @@ -275,9 +271,9 @@ func TestMethodNotSupported(t *testing.T) { err := mux.Register("test", "method", NewTestHandler("method", assert)) assert.Nil(err) // Perform test requests. - req := restaudit.NewRequest("OPTION", "/base/test/method") + req := restaudit.NewRequest(assert, "OPTION", "/base/test/method") resp := ts.DoRequest(req) - resp.AssertContentMatch(assert, ".*OPTION.*") + resp.AssertBodyContains("OPTION") } //-------------------- diff --git a/restaudit/restaudit.go b/restaudit/restaudit.go index 6adc8a3..7278d92 100644 --- a/restaudit/restaudit.go +++ b/restaudit/restaudit.go @@ -54,6 +54,7 @@ type KeyValues map[string]string // Request wraps all infos for a test request. type Request struct { + Assert audit.Assertion Method string Path string Header KeyValues @@ -64,8 +65,9 @@ type Request struct { // NewRequest creates a new test request with the given method // and path. -func NewRequest(method, path string) *Request { +func NewRequest(assert audit.Assertion, method, path string) *Request { return &Request{ + Assert: assert, Method: method, Path: path, } @@ -89,31 +91,27 @@ func (r *Request) AddCookie(key, value string) *Request { return r } -// SetContent sets the request content based on the type and +// SetBody sets the request content based on the type and // the marshalled data. -func (r *Request) SetContent( - assert audit.Assertion, - contentType string, - data interface{}, -) *Request { +func (r *Request) SetBody(contentType string, data interface{}) *Request { switch contentType { case ApplicationGOB: body := &bytes.Buffer{} enc := gob.NewEncoder(body) err := enc.Encode(data) - assert.Nil(err, "cannot encode data to GOB") + r.Assert.Nil(err, "cannot encode data to GOB") r.Body = body.Bytes() r.AddHeader(HeaderContentType, ApplicationGOB) r.AddHeader(HeaderAccept, ApplicationGOB) case ApplicationJSON: body, err := json.Marshal(data) - assert.Nil(err, "cannot marshal data to JSON") + r.Assert.Nil(err, "cannot marshal data to JSON") r.Body = body r.AddHeader(HeaderContentType, ApplicationJSON) r.AddHeader(HeaderAccept, ApplicationJSON) case ApplicationXML: body, err := xml.Marshal(data) - assert.Nil(err, "cannot marshal data to XML") + r.Assert.Nil(err, "cannot marshal data to XML") r.Body = body r.AddHeader(HeaderContentType, ApplicationXML) r.AddHeader(HeaderAccept, ApplicationXML) @@ -124,18 +122,13 @@ func (r *Request) SetContent( // RenderTemplate renders the passed data into the template // and assigns it to the request body. The content type // will be set too. -func (r *Request) RenderTemplate( - assert audit.Assertion, - contentType string, - templateSource string, - data interface{}, -) *Request { +func (r *Request) RenderTemplate(contentType string, templateSource string, data interface{}) *Request { // Render template. t, err := template.New(r.Path).Parse(templateSource) - assert.Nil(err, "cannot parse template") + r.Assert.Nil(err, "cannot parse template") body := &bytes.Buffer{} err = t.Execute(body, data) - assert.Nil(err, "cannot render template") + r.Assert.Nil(err, "cannot render template") r.Body = body.Bytes() // Set content type. r.AddHeader(HeaderContentType, contentType) @@ -149,60 +142,94 @@ func (r *Request) RenderTemplate( // Response wraps all infos of a test response. type Response struct { + Assert audit.Assertion Status int Header KeyValues Cookies KeyValues Body []byte } -// AssertStatus checks if the status is the expected one. -func (r *Response) AssertStatus(assert audit.Assertion, status int) { - assert.Equal(r.Status, status, "response status differs") +// AssertStatusEquals checks if the status is the expected one. +func (r *Response) AssertStatusEquals(expected int) { + r.Assert.Equal(r.Status, expected, "response status differs") } // AssertHeader checks if a header exists and retrieves it. -func (r *Response) AssertHeader(assert audit.Assertion, key string) string { - assert.NotEmpty(r.Header, "response contains no header") +func (r *Response) AssertHeader(key string) string { + r.Assert.NotEmpty(r.Header, "response contains no header") value, ok := r.Header[key] - assert.True(ok, "header '"+key+"' not found") + r.Assert.True(ok, "header '"+key+"' not found") return value } +// AssertHeaderEquals checks if a header exists and compares +// it to an expected one. +func (r *Response) AssertHeaderEquals(key, expected string) { + value := r.AssertHeader(key) + r.Assert.Equal(value, expected, "header value is not equal to expected") +} + +// AssertHeaderContains checks if a header exists and looks for +// an expected part. +func (r *Response) AssertHeaderContains(key, expected string) { + value := r.AssertHeader(key) + r.Assert.Substring(expected, value, "header value does not contain expected") +} + // AssertCookie checks if a cookie exists and retrieves it. -func (r *Response) AssertCookie(assert audit.Assertion, key string) string { - assert.NotEmpty(r.Cookies, "response contains no cookies") +func (r *Response) AssertCookie(key string) string { + r.Assert.NotEmpty(r.Cookies, "response contains no cookies") value, ok := r.Cookies[key] - assert.True(ok, "cookie '"+key+"' not found") + r.Assert.True(ok, "cookie '"+key+"' not found") return value } -// AssertContent retrieves the content based on the content type +// AssertCookieEquals checks if a cookie exists and compares +// it to an expected one. +func (r *Response) AssertCookieEquals(key, expected string) { + value := r.AssertCookie(key) + r.Assert.Equal(value, expected, "cookie value is not equal to expected") +} + +// AssertCookieContains checks if a cookie exists and looks for +// an expected part. +func (r *Response) AssertCookieContains(key, expected string) { + value := r.AssertCookie(key) + r.Assert.Substring(expected, value, "cookie value does not contain expected") +} + +// AssertBody retrieves the body based on the content type // and unmarshals it accordingly. -func (r *Response) AssertContent(assert audit.Assertion, data interface{}) { +func (r *Response) AssertBody(data interface{}) { contentType, ok := r.Header[HeaderContentType] - assert.True(ok) + r.Assert.True(ok) switch contentType { case ApplicationGOB: body := bytes.NewBuffer(r.Body) dec := gob.NewDecoder(body) err := dec.Decode(data) - assert.Nil(err, "cannot decode GOB body") + r.Assert.Nil(err, "cannot decode GOB body") case ApplicationJSON: err := json.Unmarshal(r.Body, data) - assert.Nil(err, "cannot unmarshal JSON body") + r.Assert.Nil(err, "cannot unmarshal JSON body") case ApplicationXML: err := xml.Unmarshal(r.Body, data) - assert.Nil(err, "cannot unmarshal XML body") + r.Assert.Nil(err, "cannot unmarshal XML body") default: - assert.Fail("unknown content type: " + contentType) + r.Assert.Fail("unknown content type: " + contentType) } } -// AssertContentMatch checks if the content matches a regular expression. -func (r *Response) AssertContentMatch(assert audit.Assertion, pattern string) { +// AssertBodyMatches checks if the body matches a regular expression. +func (r *Response) AssertBodyMatches(pattern string) { ok, err := regexp.MatchString(pattern, string(r.Body)) - assert.Nil(err, "illegal content match pattern") - assert.True(ok, "body doesn't match pattern") + r.Assert.Nil(err, "illegal content match pattern") + r.Assert.True(ok, "body doesn't match pattern") +} + +// AssertBodyContains checks if the body contains a string. +func (r *Response) AssertBodyContains(expected string) { + r.Assert.Contents(expected, r.Body, "body doesn't contains expected") } //-------------------- @@ -249,6 +276,9 @@ func (ts *testServer) DoRequest(req *Request) *Response { c := &http.Client{Transport: transport} url := ts.server.URL + req.Path var bodyReader io.Reader + if req.Assert == nil { + req.Assert = ts.assert + } if req.Body != nil { bodyReader = ioutil.NopCloser(bytes.NewBuffer(req.Body)) } @@ -309,6 +339,7 @@ func (ts *testServer) response(hr *http.Response) *Response { ts.assert.Nil(err, "cannot read response") defer hr.Body.Close() return &Response{ + Assert: ts.assert, Status: hr.StatusCode, Header: respHeader, Cookies: respCookies, From 793116752c76ee86720fb5945e13d21688f1e303 Mon Sep 17 00:00:00 2001 From: Frank Mueller Date: Sun, 12 Feb 2017 19:40:11 +0100 Subject: [PATCH 3/3] More convenience and documentation --- CHANGELOG.md | 10 ++++ handlers/handlers_test.go | 39 ++++++---------- jwt/errors.go | 2 +- jwt/header_test.go | 96 ++++++++++++++------------------------- rest/handler.go | 15 +++--- rest/rest_test.go | 38 ++++++++-------- restaudit/doc.go | 38 ++++++++++++++++ restaudit/restaudit.go | 87 ++++++++++++++++++++--------------- 8 files changed, 175 insertions(+), 150 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 80d81f3..47b8dd7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Tideland Go REST Server Library +## 2017-02-12 + +- Some renamings in *Request* and *Response*, sadly + to the previous minor release +- More convenience helpers for testing +- Adopted new testing to more packages +- Using http package constants instead of own + plain strings +- Added documentation to restaudit + ## 2017-02-10 - Extended *Request* and *Response* of *restaudit* with some diff --git a/handlers/handlers_test.go b/handlers/handlers_test.go index 2034978..a063217 100644 --- a/handlers/handlers_test.go +++ b/handlers/handlers_test.go @@ -51,11 +51,9 @@ func TestWrapperHandler(t *testing.T) { err := mux.Register("test", "wrapper", handlers.NewWrapperHandler("wrapper", handler)) assert.Nil(err) // Perform test requests. - resp := ts.DoRequest(&restaudit.Request{ - Method: "GET", - Path: "/test/wrapper", - }) - assert.Equal(string(resp.Body), data) + req := restaudit.NewRequest("GET", "/test/wrapper") + resp := ts.DoRequest(req) + resp.AssertBodyContains(data) } // TestFileServeHandler tests the serving of files. @@ -81,16 +79,12 @@ func TestFileServeHandler(t *testing.T) { err = mux.Register("test", "files", handlers.NewFileServeHandler("files", dir)) assert.Nil(err) // Perform test requests. - resp := ts.DoRequest(&restaudit.Request{ - Method: "GET", - Path: "/test/files/foo.txt", - }) - assert.Equal(string(resp.Body), data) - resp = ts.DoRequest(&restaudit.Request{ - Method: "GET", - Path: "/test/files/does.not.exist", - }) - assert.Equal(string(resp.Body), "404 page not found\n") + req := restaudit.NewRequest("GET", "/test/files/foo.txt") + resp := ts.DoRequest(req) + resp.AssertBodyContains(data) + req = restaudit.NewRequest("GET", "/test/files/does.not.exist") + resp = ts.DoRequest(req) + resp.AssertBodyContains("404 page not found") } // TestFileUploadHandler tests the uploading of files. @@ -247,11 +241,12 @@ func TestJWTAuthorizationHandler(t *testing.T) { err := mux.Register("jwt", test.id, handlers.NewAuditHandler("audit", assert, test.auditf)) assert.Nil(err) } - var requestProcessor func(req *http.Request) *http.Request + // Create request. + req := restaudit.NewRequest("GET", "/jwt/"+test.id+"/1234567890") if test.tokener != nil { - requestProcessor = func(req *http.Request) *http.Request { + req.SetRequestProcessor(func(req *http.Request) *http.Request { return jwt.AddTokenToRequest(req, test.tokener()) - } + }) } // Make request(s). runs := 1 @@ -259,12 +254,8 @@ func TestJWTAuthorizationHandler(t *testing.T) { runs = test.runs } for i := 0; i < runs; i++ { - resp := ts.DoRequest(&restaudit.Request{ - Method: "GET", - Path: "/jwt/" + test.id + "/1234567890", - RequestProcessor: requestProcessor, - }) - assert.Equal(resp.Status, test.status) + resp := ts.DoRequest(req) + resp.AssertStatusEquals(test.status) } } } diff --git a/jwt/errors.go b/jwt/errors.go index fb33d47..c385c64 100644 --- a/jwt/errors.go +++ b/jwt/errors.go @@ -1,6 +1,6 @@ // Tideland Go REST Server Library - JSON Web Token - Errors // -// Copyright (C) 2016 Frank Mueller / Tideland / Oldenburg / Germany +// Copyright (C) 2016-2017 Frank Mueller / Tideland / Oldenburg / Germany // // All rights reserved. Use of this source code is governed // by the new BSD license. diff --git a/jwt/header_test.go b/jwt/header_test.go index 07be705..94ecdf1 100644 --- a/jwt/header_test.go +++ b/jwt/header_test.go @@ -1,6 +1,6 @@ // Tideland Go REST Server Library - JSON Web Token - Unit Tests // -// Copyright (C) 2016 Frank Mueller / Tideland / Oldenburg / Germany +// Copyright (C) 2016-2017 Frank Mueller / Tideland / Oldenburg / Germany // // All rights reserved. Use of this source code is governed // by the new BSD license. @@ -13,7 +13,6 @@ package jwt_test import ( "context" - "encoding/json" "net/http" "testing" "time" @@ -46,17 +45,14 @@ func TestDecodeRequest(t *testing.T) { err = mux.Register("test", "jwt", NewTestHandler("jwt", assert, nil, false)) assert.Nil(err) // Perform test request. - resp := ts.DoRequest(&restaudit.Request{ - Method: "GET", - Path: "/test/jwt/1234567890", - Header: restaudit.KeyValues{"Accept": "application/json"}, - RequestProcessor: func(req *http.Request) *http.Request { - return jwt.AddTokenToRequest(req, jwtIn) - }, + req := restaudit.NewRequest("GET", "/test/jwt/1234567890") + req.AddHeader(restaudit.HeaderAccept, restaudit.ApplicationJSON) + req.SetRequestProcessor(func(req *http.Request) *http.Request { + return jwt.AddTokenToRequest(req, jwtIn) }) - var claimsOut jwt.Claims - err = json.Unmarshal(resp.Body, &claimsOut) - assert.Nil(err) + resp := ts.DoRequest(req) + claimsOut := jwt.Claims{} + resp.AssertUnmarshalledBody(&claimsOut) assert.Equal(claimsOut, claimsIn) } @@ -76,29 +72,19 @@ func TestDecodeCachedRequest(t *testing.T) { err = mux.Register("test", "jwt", NewTestHandler("jwt", assert, nil, true)) assert.Nil(err) // Perform first test request. - resp := ts.DoRequest(&restaudit.Request{ - Method: "GET", - Path: "/test/jwt/1234567890", - Header: restaudit.KeyValues{"Accept": "application/json"}, - RequestProcessor: func(req *http.Request) *http.Request { - return jwt.AddTokenToRequest(req, jwtIn) - }, + req := restaudit.NewRequest("GET", "/test/jwt/1234567890") + req.AddHeader(restaudit.HeaderAccept, restaudit.ApplicationJSON) + req.SetRequestProcessor(func(req *http.Request) *http.Request { + return jwt.AddTokenToRequest(req, jwtIn) }) - var claimsOut jwt.Claims - err = json.Unmarshal(resp.Body, &claimsOut) - assert.Nil(err) + resp := ts.DoRequest(req) + claimsOut := jwt.Claims{} + resp.AssertUnmarshalledBody(&claimsOut) assert.Equal(claimsOut, claimsIn) // Perform second test request. - resp = ts.DoRequest(&restaudit.Request{ - Method: "GET", - Path: "/test/jwt/1234567890", - Header: restaudit.KeyValues{"Accept": "application/json"}, - RequestProcessor: func(req *http.Request) *http.Request { - return jwt.AddTokenToRequest(req, jwtIn) - }, - }) - err = json.Unmarshal(resp.Body, &claimsOut) - assert.Nil(err) + resp = ts.DoRequest(req) + claimsOut = jwt.Claims{} + resp.AssertUnmarshalledBody(&claimsOut) assert.Equal(claimsOut, claimsIn) } @@ -118,17 +104,14 @@ func TestVerifyRequest(t *testing.T) { err = mux.Register("test", "jwt", NewTestHandler("jwt", assert, key, false)) assert.Nil(err) // Perform test request. - resp := ts.DoRequest(&restaudit.Request{ - Method: "GET", - Path: "/test/jwt/1234567890", - Header: restaudit.KeyValues{"Accept": "application/json"}, - RequestProcessor: func(req *http.Request) *http.Request { - return jwt.AddTokenToRequest(req, jwtIn) - }, + req := restaudit.NewRequest("GET", "/test/jwt/1234567890") + req.AddHeader(restaudit.HeaderAccept, restaudit.ApplicationJSON) + req.SetRequestProcessor(func(req *http.Request) *http.Request { + return jwt.AddTokenToRequest(req, jwtIn) }) - var claimsOut jwt.Claims - err = json.Unmarshal(resp.Body, &claimsOut) - assert.Nil(err) + resp := ts.DoRequest(req) + claimsOut := jwt.Claims{} + resp.AssertUnmarshalledBody(&claimsOut) assert.Equal(claimsOut, claimsIn) } @@ -148,29 +131,18 @@ func TestVerifyCachedRequest(t *testing.T) { err = mux.Register("test", "jwt", NewTestHandler("jwt", assert, key, true)) assert.Nil(err) // Perform first test request. - resp := ts.DoRequest(&restaudit.Request{ - Method: "GET", - Path: "/test/jwt/1234567890", - Header: restaudit.KeyValues{"Accept": "application/json"}, - RequestProcessor: func(req *http.Request) *http.Request { - return jwt.AddTokenToRequest(req, jwtIn) - }, + req := restaudit.NewRequest("GET", "/test/jwt/1234567890") + req.AddHeader(restaudit.HeaderAccept, restaudit.ApplicationJSON) + req.SetRequestProcessor(func(req *http.Request) *http.Request { + return jwt.AddTokenToRequest(req, jwtIn) }) - var claimsOut jwt.Claims - err = json.Unmarshal(resp.Body, &claimsOut) - assert.Nil(err) + resp := ts.DoRequest(req) + claimsOut := jwt.Claims{} + resp.AssertUnmarshalledBody(&claimsOut) assert.Equal(claimsOut, claimsIn) // Perform second test request. - resp = ts.DoRequest(&restaudit.Request{ - Method: "GET", - Path: "/test/jwt/1234567890", - Header: restaudit.KeyValues{"Accept": "application/json"}, - RequestProcessor: func(req *http.Request) *http.Request { - return jwt.AddTokenToRequest(req, jwtIn) - }, - }) - err = json.Unmarshal(resp.Body, &claimsOut) - assert.Nil(err) + resp = ts.DoRequest(req) + resp.AssertUnmarshalledBody(&claimsOut) assert.Equal(claimsOut, claimsIn) } diff --git a/rest/handler.go b/rest/handler.go index cbb5ae3..bf8f780 100644 --- a/rest/handler.go +++ b/rest/handler.go @@ -13,6 +13,7 @@ package rest import ( "fmt" + "net/http" "github.com/tideland/golib/errors" ) @@ -83,43 +84,43 @@ func handleJob(handler ResourceHandler, job Job) (bool, error) { return fmt.Sprintf("%s@%s/%s", handler.ID(), job.Domain(), job.Resource()) } switch job.Request().Method { - case "GET": + case http.MethodGet: grh, ok := handler.(GetResourceHandler) if !ok { return false, errors.New(ErrNoGetHandler, errorMessages, id()) } return grh.Get(job) - case "HEAD": + case http.MethodHead: hrh, ok := handler.(HeadResourceHandler) if !ok { return false, errors.New(ErrNoHeadHandler, errorMessages, id()) } return hrh.Head(job) - case "PUT": + case http.MethodPut: prh, ok := handler.(PutResourceHandler) if !ok { return false, errors.New(ErrNoPutHandler, errorMessages, id()) } return prh.Put(job) - case "POST": + case http.MethodPost: prh, ok := handler.(PostResourceHandler) if !ok { return false, errors.New(ErrNoPostHandler, errorMessages, id()) } return prh.Post(job) - case "PATCH": + case http.MethodPatch: prh, ok := handler.(PatchResourceHandler) if !ok { return false, errors.New(ErrNoPatchHandler, errorMessages, id()) } return prh.Patch(job) - case "DELETE": + case http.MethodDelete: drh, ok := handler.(DeleteResourceHandler) if !ok { return false, errors.New(ErrNoDeleteHandler, errorMessages, id()) } return drh.Delete(job) - case "OPTIONS": + case http.MethodOptions: orh, ok := handler.(OptionsResourceHandler) if !ok { return false, errors.New(ErrNoOptionsHandler, errorMessages, id()) diff --git a/rest/rest_test.go b/rest/rest_test.go index a950692..2f92c5d 100644 --- a/rest/rest_test.go +++ b/rest/rest_test.go @@ -46,7 +46,7 @@ func TestGetJSON(t *testing.T) { err := mux.Register("test", "json", NewTestHandler("json", assert)) assert.Nil(err) // Perform test requests. - req := restaudit.NewRequest(assert, "GET", "/base/test/json/4711?foo=0815") + req := restaudit.NewRequest("GET", "/base/test/json/4711?foo=0815") req.AddHeader(restaudit.HeaderAccept, restaudit.ApplicationJSON) resp := ts.DoRequest(req) resp.AssertStatusEquals(200) @@ -65,13 +65,13 @@ func TestPutJSON(t *testing.T) { err := mux.Register("test", "json", NewTestHandler("json", assert)) assert.Nil(err) // Perform test requests. - req := restaudit.NewRequest(assert, "PUT", "/base/test/json/4711") + req := restaudit.NewRequest("PUT", "/base/test/json/4711") reqData := TestRequestData{"foo", "bar", "4711", "0815", ""} - req.SetBody(restaudit.ApplicationJSON, reqData) + req.MarshalBody(assert, restaudit.ApplicationJSON, reqData) resp := ts.DoRequest(req) resp.AssertStatusEquals(200) respData := TestRequestData{} - resp.AssertBody(&respData) + resp.AssertUnmarshalledBody(&respData) assert.Equal(respData, reqData) } @@ -85,7 +85,7 @@ func TestGetXML(t *testing.T) { err := mux.Register("test", "xml", NewTestHandler("xml", assert)) assert.Nil(err) // Perform test requests. - req := restaudit.NewRequest(assert, "GET", "/base/test/xml/4711") + req := restaudit.NewRequest("GET", "/base/test/xml/4711") req.AddHeader(restaudit.HeaderAccept, restaudit.ApplicationXML) resp := ts.DoRequest(req) resp.AssertStatusEquals(200) @@ -102,13 +102,13 @@ func TestPutXML(t *testing.T) { err := mux.Register("test", "xml", NewTestHandler("xml", assert)) assert.Nil(err) // Perform test requests. - req := restaudit.NewRequest(assert, "PUT", "/base/test/xml/4711") + req := restaudit.NewRequest("PUT", "/base/test/xml/4711") reqData := TestRequestData{"foo", "bar", "4711", "0815", ""} - req.SetBody(restaudit.ApplicationXML, reqData) + req.MarshalBody(assert, restaudit.ApplicationXML, reqData) resp := ts.DoRequest(req) resp.AssertStatusEquals(200) respData := TestRequestData{} - resp.AssertBody(&respData) + resp.AssertUnmarshalledBody(&respData) assert.Equal(respData, reqData) } @@ -122,13 +122,13 @@ func TestPutGOB(t *testing.T) { err := mux.Register("test", "gob", NewTestHandler("putgob", assert)) assert.Nil(err) // Perform test requests. - req := restaudit.NewRequest(assert, "POST", "/base/test/gob") + req := restaudit.NewRequest("POST", "/base/test/gob") reqData := TestCounterData{"test", 4711} - req.SetBody(restaudit.ApplicationGOB, reqData) + req.MarshalBody(assert, restaudit.ApplicationGOB, reqData) resp := ts.DoRequest(req) resp.AssertStatusEquals(200) respData := TestCounterData{} - resp.AssertBody(&respData) + resp.AssertUnmarshalledBody(&respData) assert.Equal(respData, reqData) } @@ -142,7 +142,7 @@ func TestLongPath(t *testing.T) { err := mux.Register("content", "blog", NewTestHandler("default", assert)) assert.Nil(err) // Perform test requests. - req := restaudit.NewRequest(assert, "GET", "/base/content/blog/2014/09/30/just-a-test") + req := restaudit.NewRequest("GET", "/base/content/blog/2014/09/30/just-a-test") resp := ts.DoRequest(req) resp.AssertBodyContains(`Resource ID: 2014/09/30/just-a-test`) } @@ -157,7 +157,7 @@ func TestFallbackDefault(t *testing.T) { err := mux.Register("testing", "index", NewTestHandler("default", assert)) assert.Nil(err) // Perform test requests. - req := restaudit.NewRequest(assert, "GET", "/base/x/y") + req := restaudit.NewRequest("GET", "/base/x/y") resp := ts.DoRequest(req) resp.AssertBodyContains(`Resource: y`) } @@ -176,11 +176,11 @@ func TestHandlerStack(t *testing.T) { }) assert.Nil(err) // Perform test requests. - req := restaudit.NewRequest(assert, "GET", "/base/test/stack") + req := restaudit.NewRequest("GET", "/base/test/stack") resp := ts.DoRequest(req) resp.AssertBodyContains("Resource: token") resp.AssertHeaderEquals("Token", "foo") - req = restaudit.NewRequest(assert, "GET", "/base/test/stack") + req = restaudit.NewRequest("GET", "/base/test/stack") req.AddHeader("token", "foo") resp = ts.DoRequest(req) resp.AssertBodyContains("Resource: stack") @@ -198,20 +198,20 @@ func TestVersion(t *testing.T) { err := mux.Register("test", "json", NewTestHandler("json", assert)) assert.Nil(err) // Perform test requests. - req := restaudit.NewRequest(assert, "GET", "/base/test/json/4711?foo=0815") + req := restaudit.NewRequest("GET", "/base/test/json/4711?foo=0815") req.AddHeader(restaudit.HeaderAccept, restaudit.ApplicationJSON) resp := ts.DoRequest(req) resp.AssertStatusEquals(200) resp.AssertHeaderEquals("Version", "1.0.0") - req = restaudit.NewRequest(assert, "GET", "/base/test/json/4711?foo=0815") + req = restaudit.NewRequest("GET", "/base/test/json/4711?foo=0815") req.AddHeader(restaudit.HeaderAccept, restaudit.ApplicationJSON) req.AddHeader("Version", "2") resp = ts.DoRequest(req) resp.AssertStatusEquals(200) resp.AssertHeaderEquals("Version", "2.0.0") - req = restaudit.NewRequest(assert, "GET", "/base/test/json/4711?foo=0815") + req = restaudit.NewRequest("GET", "/base/test/json/4711?foo=0815") req.AddHeader(restaudit.HeaderAccept, restaudit.ApplicationJSON) req.AddHeader("Version", "3.0") resp = ts.DoRequest(req) @@ -271,7 +271,7 @@ func TestMethodNotSupported(t *testing.T) { err := mux.Register("test", "method", NewTestHandler("method", assert)) assert.Nil(err) // Perform test requests. - req := restaudit.NewRequest(assert, "OPTION", "/base/test/method") + req := restaudit.NewRequest("OPTION", "/base/test/method") resp := ts.DoRequest(req) resp.AssertBodyContains("OPTION") } diff --git a/restaudit/doc.go b/restaudit/doc.go index 7f24a15..fd22a84 100644 --- a/restaudit/doc.go +++ b/restaudit/doc.go @@ -10,6 +10,44 @@ // resource handlers. Requests can easily be created, marshalling data // based on the content-type is done automatically. Response also // provides assert methods for the tests. +// +// So first step is to create a test server and register the handler(s) +// to test. Could best be done with a little helper function, depending +// on own needs, e.g. when the context shall contain more information. +// +// assert := audit.NewTestingAssertion(t, true) +// cfgStr := "{etc {basepath /}{default-domain testing}{default-resource index}}" +// cfg, err := etc.ReadString(cfgStr) +// assert.Nil(err) +// mux := rest.NewMultiplexer(context.Background(), cfg) +// ts := restaudit.StartServer(mux, assert) +// defer ts.Close() +// err := mux.Register("my-domain", "my-resource", NewMyHandler()) +// assert.Nil(err) +// +// During the tests you create the requests with +// +// req := restaudit.NewRequest("GET", "/my-domain/my-resource/4711") +// req.AddHeader(restaudit.HeaderAccept, restaudit.ApplicationJSON) +// +// The request the is done with +// +// resp := ts.DoRequest(req) +// resp.AssertStatusEquals(200) +// rest.AssertHeaderContains(restaudit.HeaderContentType, restaudit.ApplicationJSON) +// resp.AssertBodyContains(`"ResourceID":"4711"`) +// +// Also data can be marshalled including setting the content type +// and the response can be unmarshalled based on that type. +// +// req.MarshalBody(assert, restaudit.ApplicationJSON, myInData) +// ... +// var myOutData MyType +// resp.AssertUnmarshalledBody(&myOutData) +// assert.Equal(myOutData.MyField, "foo") +// +// There are more helpers for a convenient test, but the fields of +// Request and Response can also be accessed directly. package restaudit // EOF diff --git a/restaudit/restaudit.go b/restaudit/restaudit.go index 7278d92..bf1adf9 100644 --- a/restaudit/restaudit.go +++ b/restaudit/restaudit.go @@ -52,22 +52,23 @@ type KeyValues map[string]string // REQUEST //-------------------- +// RequestProcessor is for pre-processing HTTP requests. +type RequestProcessor func(req *http.Request) *http.Request + // Request wraps all infos for a test request. type Request struct { - Assert audit.Assertion Method string Path string Header KeyValues Cookies KeyValues Body []byte - RequestProcessor func(req *http.Request) *http.Request + RequestProcessor RequestProcessor } // NewRequest creates a new test request with the given method // and path. -func NewRequest(assert audit.Assertion, method, path string) *Request { +func NewRequest(method, path string) *Request { return &Request{ - Assert: assert, Method: method, Path: path, } @@ -91,27 +92,37 @@ func (r *Request) AddCookie(key, value string) *Request { return r } -// SetBody sets the request content based on the type and +// SetRequestProcessor sets the pre-processor. +func (r *Request) SetRequestProcessor(processor RequestProcessor) *Request { + r.RequestProcessor = processor + return r +} + +// MarshalBody sets the request body based on the type and // the marshalled data. -func (r *Request) SetBody(contentType string, data interface{}) *Request { +func (r *Request) MarshalBody( + assert audit.Assertion, + contentType string, + data interface{}, +) *Request { switch contentType { case ApplicationGOB: body := &bytes.Buffer{} enc := gob.NewEncoder(body) err := enc.Encode(data) - r.Assert.Nil(err, "cannot encode data to GOB") + assert.Nil(err, "cannot encode data to GOB") r.Body = body.Bytes() r.AddHeader(HeaderContentType, ApplicationGOB) r.AddHeader(HeaderAccept, ApplicationGOB) case ApplicationJSON: body, err := json.Marshal(data) - r.Assert.Nil(err, "cannot marshal data to JSON") + assert.Nil(err, "cannot marshal data to JSON") r.Body = body r.AddHeader(HeaderContentType, ApplicationJSON) r.AddHeader(HeaderAccept, ApplicationJSON) case ApplicationXML: body, err := xml.Marshal(data) - r.Assert.Nil(err, "cannot marshal data to XML") + assert.Nil(err, "cannot marshal data to XML") r.Body = body r.AddHeader(HeaderContentType, ApplicationXML) r.AddHeader(HeaderAccept, ApplicationXML) @@ -122,13 +133,18 @@ func (r *Request) SetBody(contentType string, data interface{}) *Request { // RenderTemplate renders the passed data into the template // and assigns it to the request body. The content type // will be set too. -func (r *Request) RenderTemplate(contentType string, templateSource string, data interface{}) *Request { +func (r *Request) RenderTemplate( + assert audit.Assertion, + contentType string, + templateSource string, + data interface{}, +) *Request { // Render template. t, err := template.New(r.Path).Parse(templateSource) - r.Assert.Nil(err, "cannot parse template") + assert.Nil(err, "cannot parse template") body := &bytes.Buffer{} err = t.Execute(body, data) - r.Assert.Nil(err, "cannot render template") + assert.Nil(err, "cannot render template") r.Body = body.Bytes() // Set content type. r.AddHeader(HeaderContentType, contentType) @@ -142,7 +158,7 @@ func (r *Request) RenderTemplate(contentType string, templateSource string, data // Response wraps all infos of a test response. type Response struct { - Assert audit.Assertion + assert audit.Assertion Status int Header KeyValues Cookies KeyValues @@ -151,14 +167,14 @@ type Response struct { // AssertStatusEquals checks if the status is the expected one. func (r *Response) AssertStatusEquals(expected int) { - r.Assert.Equal(r.Status, expected, "response status differs") + r.assert.Equal(r.Status, expected, "response status differs") } // AssertHeader checks if a header exists and retrieves it. func (r *Response) AssertHeader(key string) string { - r.Assert.NotEmpty(r.Header, "response contains no header") + r.assert.NotEmpty(r.Header, "response contains no header") value, ok := r.Header[key] - r.Assert.True(ok, "header '"+key+"' not found") + r.assert.True(ok, "header '"+key+"' not found") return value } @@ -166,21 +182,21 @@ func (r *Response) AssertHeader(key string) string { // it to an expected one. func (r *Response) AssertHeaderEquals(key, expected string) { value := r.AssertHeader(key) - r.Assert.Equal(value, expected, "header value is not equal to expected") + r.assert.Equal(value, expected, "header value is not equal to expected") } // AssertHeaderContains checks if a header exists and looks for // an expected part. func (r *Response) AssertHeaderContains(key, expected string) { value := r.AssertHeader(key) - r.Assert.Substring(expected, value, "header value does not contain expected") + r.assert.Substring(expected, value, "header value does not contain expected") } // AssertCookie checks if a cookie exists and retrieves it. func (r *Response) AssertCookie(key string) string { - r.Assert.NotEmpty(r.Cookies, "response contains no cookies") + r.assert.NotEmpty(r.Cookies, "response contains no cookies") value, ok := r.Cookies[key] - r.Assert.True(ok, "cookie '"+key+"' not found") + r.assert.True(ok, "cookie '"+key+"' not found") return value } @@ -188,48 +204,48 @@ func (r *Response) AssertCookie(key string) string { // it to an expected one. func (r *Response) AssertCookieEquals(key, expected string) { value := r.AssertCookie(key) - r.Assert.Equal(value, expected, "cookie value is not equal to expected") + r.assert.Equal(value, expected, "cookie value is not equal to expected") } // AssertCookieContains checks if a cookie exists and looks for // an expected part. func (r *Response) AssertCookieContains(key, expected string) { value := r.AssertCookie(key) - r.Assert.Substring(expected, value, "cookie value does not contain expected") + r.assert.Substring(expected, value, "cookie value does not contain expected") } -// AssertBody retrieves the body based on the content type +// AssertUnmarshalledBody retrieves the body based on the content type // and unmarshals it accordingly. -func (r *Response) AssertBody(data interface{}) { +func (r *Response) AssertUnmarshalledBody(data interface{}) { contentType, ok := r.Header[HeaderContentType] - r.Assert.True(ok) + r.assert.True(ok) switch contentType { case ApplicationGOB: body := bytes.NewBuffer(r.Body) dec := gob.NewDecoder(body) err := dec.Decode(data) - r.Assert.Nil(err, "cannot decode GOB body") + r.assert.Nil(err, "cannot decode GOB body") case ApplicationJSON: err := json.Unmarshal(r.Body, data) - r.Assert.Nil(err, "cannot unmarshal JSON body") + r.assert.Nil(err, "cannot unmarshal JSON body") case ApplicationXML: err := xml.Unmarshal(r.Body, data) - r.Assert.Nil(err, "cannot unmarshal XML body") + r.assert.Nil(err, "cannot unmarshal XML body") default: - r.Assert.Fail("unknown content type: " + contentType) + r.assert.Fail("unknown content type: " + contentType) } } // AssertBodyMatches checks if the body matches a regular expression. func (r *Response) AssertBodyMatches(pattern string) { ok, err := regexp.MatchString(pattern, string(r.Body)) - r.Assert.Nil(err, "illegal content match pattern") - r.Assert.True(ok, "body doesn't match pattern") + r.assert.Nil(err, "illegal content match pattern") + r.assert.True(ok, "body doesn't match pattern") } // AssertBodyContains checks if the body contains a string. func (r *Response) AssertBodyContains(expected string) { - r.Assert.Contents(expected, r.Body, "body doesn't contains expected") + r.assert.Contents(expected, r.Body, "body doesn't contains expected") } //-------------------- @@ -276,9 +292,6 @@ func (ts *testServer) DoRequest(req *Request) *Response { c := &http.Client{Transport: transport} url := ts.server.URL + req.Path var bodyReader io.Reader - if req.Assert == nil { - req.Assert = ts.assert - } if req.Body != nil { bodyReader = ioutil.NopCloser(bytes.NewBuffer(req.Body)) } @@ -294,7 +307,7 @@ func (ts *testServer) DoRequest(req *Request) *Response { } httpReq.AddCookie(cookie) } - // Check if request shall be processed before performed. + // Check if request shall be pre-processed before performed. if req.RequestProcessor != nil { httpReq = req.RequestProcessor(httpReq) } @@ -339,7 +352,7 @@ func (ts *testServer) response(hr *http.Response) *Response { ts.assert.Nil(err, "cannot read response") defer hr.Body.Close() return &Response{ - Assert: ts.assert, + assert: ts.assert, Status: hr.StatusCode, Header: respHeader, Cookies: respCookies,