diff --git a/CHANGELOG.md b/CHANGELOG.md index f97cef8..80d81f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Tideland Go REST Server Library +## 2017-02-10 + +- Extended *Request* and *Response* of *restaudit* with some + convenience methods for easier testing +- Adopted *restaudit* changes in *rest* tests + ## 2017-01-19 - Renamed type *Query* to *Values* diff --git a/LICENSE b/LICENSE index 6ff86e4..0801e5d 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2009-2016, Frank Mueller / Tideland / Oldenburg / Germany +Copyright (c) 2009-2017, Frank Mueller / Tideland / Oldenburg / Germany All rights reserved. Redistribution and use in source and binary forms, with or without modification, diff --git a/README.md b/README.md index 15cdac9..71bf50b 100644 --- a/README.md +++ b/README.md @@ -14,35 +14,35 @@ I hope you like it. ;) ## Version -Version 2.10.0 +Version 2.11.0 ## Packages -#### REST +### REST RESTful web request handling. [![GoDoc](https://godoc.org/github.com/tideland/gorest/rest?status.svg)](https://godoc.org/github.com/tideland/gorest/rest) -#### Request +### Request Convenient client requests to RESTful web services. [![GoDoc](https://godoc.org/github.com/tideland/gorest/request?status.svg)](https://godoc.org/github.com/tideland/gorest/request) -#### Handlers +### Handlers Some general purpose handlers for the library. [![GoDoc](https://godoc.org/github.com/tideland/gorest/handlers?status.svg)](https://godoc.org/github.com/tideland/gorest/handlers) -#### JSON Web Token +### JSON Web Token JWT package for secure authentication and information exchange like claims. [![GoDoc](https://godoc.org/github.com/tideland/gorest/jwt?status.svg)](https://godoc.org/github.com/tideland/gorest/jwt) -#### REST Audit +### REST Audit Helpers for the unit tests of the Go REST Server Library. diff --git a/handlers/audit.go b/handlers/audit.go index fd49bf9..2ab2a04 100644 --- a/handlers/audit.go +++ b/handlers/audit.go @@ -1,6 +1,6 @@ // Tideland Go REST Server Library - Handlers - Audit Handler // -// Copyright (C) 2009-2016 Frank Mueller / Tideland / Oldenburg / Germany +// Copyright (C) 2009-2017 Frank Mueller / Tideland / Oldenburg / Germany // // All rights reserved. Use of this source code is governed // by the new BSD license. diff --git a/handlers/doc.go b/handlers/doc.go index 96ab2cc..37ec7af 100644 --- a/handlers/doc.go +++ b/handlers/doc.go @@ -1,11 +1,11 @@ // Tideland Go REST Server Library - Handlers // -// Copyright (C) 2009-2016 Frank Mueller / Tideland / Oldenburg / Germany +// Copyright (C) 2009-2017 Frank Mueller / Tideland / Oldenburg / Germany // // All rights reserved. Use of this source code is governed // by the new BSD license. -// The Tideland Go REST Server Library handlers package defines +// Package handlers of the Tideland Go REST Server Library implements // some initial resource handlers to integrate into own solutions. package handlers diff --git a/handlers/errors.go b/handlers/errors.go index 4e9fb51..f37b7cf 100644 --- a/handlers/errors.go +++ b/handlers/errors.go @@ -1,6 +1,6 @@ // Tideland Go REST Server Library - Handlers - Errors // -// Copyright (C) 2009-2016 Frank Mueller / Tideland / Oldenburg / Germany +// Copyright (C) 2009-2017 Frank Mueller / Tideland / Oldenburg / Germany // // All rights reserved. Use of this source code is governed // by the new BSD license. diff --git a/handlers/fileserve.go b/handlers/fileserve.go index 39bce5e..92b6530 100644 --- a/handlers/fileserve.go +++ b/handlers/fileserve.go @@ -1,6 +1,6 @@ // Tideland Go REST Server Library - Handlers - File Serve // -// Copyright (C) 2009-2016 Frank Mueller / Tideland / Oldenburg / Germany +// Copyright (C) 2009-2017 Frank Mueller / Tideland / Oldenburg / Germany // // All rights reserved. Use of this source code is governed // by the new BSD license. diff --git a/handlers/fileupload.go b/handlers/fileupload.go index 79f2696..195f5b7 100644 --- a/handlers/fileupload.go +++ b/handlers/fileupload.go @@ -1,6 +1,6 @@ // Tideland Go REST Server Library - Handlers - File Upload // -// Copyright (C) 2009-2016 Frank Mueller / Tideland / Oldenburg / Germany +// Copyright (C) 2009-2017 Frank Mueller / Tideland / Oldenburg / Germany // // All rights reserved. Use of this source code is governed // by the new BSD license. diff --git a/handlers/handlers_test.go b/handlers/handlers_test.go index 8f86674..2034978 100644 --- a/handlers/handlers_test.go +++ b/handlers/handlers_test.go @@ -1,6 +1,6 @@ // Tideland Go REST Server Library - Handlers - Unit Tests // -// Copyright (C) 2009-2016 Frank Mueller / Tideland / Oldenburg / Germany +// Copyright (C) 2009-2017 Frank Mueller / Tideland / Oldenburg / Germany // // All rights reserved. Use of this source code is governed // by the new BSD license. diff --git a/handlers/jwtauth.go b/handlers/jwtauth.go index cb07a52..4d5b2cb 100644 --- a/handlers/jwtauth.go +++ b/handlers/jwtauth.go @@ -1,6 +1,6 @@ // Tideland Go REST Server Library - Handlers - JWT Authorization // -// Copyright (C) 2009-2016 Frank Mueller / Tideland / Oldenburg / Germany +// Copyright (C) 2009-2017 Frank Mueller / Tideland / Oldenburg / Germany // // All rights reserved. Use of this source code is governed // by the new BSD license. diff --git a/handlers/wrapper.go b/handlers/wrapper.go index 6561e28..2336520 100644 --- a/handlers/wrapper.go +++ b/handlers/wrapper.go @@ -1,6 +1,6 @@ // Tideland Go REST Server Library - Handlers - Wrapper // -// Copyright (C) 2009-2016 Frank Mueller / Tideland / Oldenburg / Germany +// Copyright (C) 2009-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/algorithm.go b/jwt/algorithm.go index 100a0a4..76dfe84 100644 --- a/jwt/algorithm.go +++ b/jwt/algorithm.go @@ -1,6 +1,6 @@ // Tideland Go REST Server Library - JSON Web Token - Algorithm // -// 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/cache.go b/jwt/cache.go index 2ec224e..3a58c1c 100644 --- a/jwt/cache.go +++ b/jwt/cache.go @@ -1,6 +1,6 @@ // Tideland Go REST Server Library - JSON Web Token - Cache // -// 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/cache_test.go b/jwt/cache_test.go index c3b5435..35fdea1 100644 --- a/jwt/cache_test.go +++ b/jwt/cache_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. diff --git a/jwt/claims.go b/jwt/claims.go index fb2de23..343c4f1 100644 --- a/jwt/claims.go +++ b/jwt/claims.go @@ -1,6 +1,6 @@ // Tideland Go REST Server Library - JSON Web Token - Claims // -// 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/claims_test.go b/jwt/claims_test.go index d3a2a6e..d07e3b2 100644 --- a/jwt/claims_test.go +++ b/jwt/claims_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. diff --git a/jwt/doc.go b/jwt/doc.go index 881d1d2..4ee79e8 100644 --- a/jwt/doc.go +++ b/jwt/doc.go @@ -1,11 +1,11 @@ // Tideland Go REST Server Library - JSON Web Token // -// 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. -// The Tideland Go REST Server Library jwt provides the generation, +// Package jwt of the Tideland Go REST Server Library provides the generation, // verification, and analyzing of JSON Web Tokens. package jwt diff --git a/request/doc.go b/request/doc.go index 33d3429..b814174 100644 --- a/request/doc.go +++ b/request/doc.go @@ -1,12 +1,13 @@ // Tideland Go REST Server Library - Request // -// Copyright (C) 2009-2016 Frank Mueller / Tideland / Oldenburg / Germany +// Copyright (C) 2009-2017 Frank Mueller / Tideland / Oldenburg / Germany // // All rights reserved. Use of this source code is governed // by the new BSD license. -// The request package provides a simple way to handle cross-server -// requests in the Tideland REST ecosystem. +// Package request of the Tideland Go REST Server Library provides +// a simple way to handle cross-server requests in the Tideland +// REST ecosystem. package request //-------------------- diff --git a/request/errors.go b/request/errors.go index e749079..afd1979 100644 --- a/request/errors.go +++ b/request/errors.go @@ -1,6 +1,6 @@ // Tideland Go REST Server Library - Request - Errors // -// Copyright (C) 2009-2016 Frank Mueller / Tideland / Oldenburg / Germany +// Copyright (C) 2009-2017 Frank Mueller / Tideland / Oldenburg / Germany // // All rights reserved. Use of this source code is governed // by the new BSD license. diff --git a/request/request.go b/request/request.go index 4136c8f..bc421a9 100644 --- a/request/request.go +++ b/request/request.go @@ -1,6 +1,6 @@ // Tideland Go REST Server Library - Request // -// Copyright (C) 2009-2016 Frank Mueller / Tideland / Oldenburg / Germany +// Copyright (C) 2009-2017 Frank Mueller / Tideland / Oldenburg / Germany // // All rights reserved. Use of this source code is governed // by the new BSD license. diff --git a/request/request_test.go b/request/request_test.go index cc4856c..bdad5a4 100644 --- a/request/request_test.go +++ b/request/request_test.go @@ -1,6 +1,6 @@ // Tideland Go REST Server Library - Request - Unit Tests // -// Copyright (C) 2009-2016 Frank Mueller / Tideland / Oldenburg / Germany +// Copyright (C) 2009-2017 Frank Mueller / Tideland / Oldenburg / Germany // // All rights reserved. Use of this source code is governed // by the new BSD license. diff --git a/rest/doc.go b/rest/doc.go index e240f93..9f8af58 100644 --- a/rest/doc.go +++ b/rest/doc.go @@ -5,8 +5,8 @@ // All rights reserved. Use of this source code is governed // by the new BSD license. -// The Tideland Go REST Server Library provides the package rest for the -// implementation of servers with a RESTful API. The business has to +// Package rest of the Tideland Go REST Server Library provides types for +// the implementation of servers with a RESTful API. The business has to // be implemented in types fullfilling the ResourceHandler interface. // This basic interface only allows the initialization of the handler. // More interesting are the other interfaces like GetResourceHandler diff --git a/rest/rest_test.go b/rest/rest_test.go index 5d4c2ae..efa5e88 100644 --- a/rest/rest_test.go +++ b/rest/rest_test.go @@ -12,11 +12,7 @@ package rest_test //-------------------- import ( - "bytes" "context" - "encoding/gob" - "encoding/json" - "encoding/xml" "testing" "github.com/tideland/golib/audit" @@ -50,17 +46,13 @@ func TestGetJSON(t *testing.T) { err := mux.Register("test", "json", NewTestHandler("json", assert)) assert.Nil(err) // Perform test requests. - resp := ts.DoRequest(&restaudit.Request{ - Method: "GET", - Path: "/base/test/json/4711?foo=0815", - Header: restaudit.KeyValues{"Accept": "application/json"}, - }) - var data TestRequestData - err = json.Unmarshal(resp.Body, &data) - assert.Nil(err) - assert.Equal(data.ResourceID, "4711") - assert.Equal(data.Query, "0815") - assert.Equal(data.Context, "foo") + req := restaudit.NewRequest("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".*`) } // TestPutJSON tests the PUT command with a JSON payload and result. @@ -73,18 +65,14 @@ 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") reqData := TestRequestData{"foo", "bar", "4711", "0815", ""} - reqBuf, _ := json.Marshal(reqData) - resp := ts.DoRequest(&restaudit.Request{ - Method: "PUT", - Path: "/base/test/json/4711", - Header: restaudit.KeyValues{"Content-Type": "application/json", "Accept": "application/json"}, - Body: reqBuf, - }) - var recvData TestRequestData - err = json.Unmarshal(resp.Body, &recvData) - assert.Nil(err) - assert.Equal(recvData, reqData) + req.SetContent(assert, restaudit.ApplicationJSON, reqData) + resp := ts.DoRequest(req) + resp.AssertStatus(assert, 200) + respData := TestRequestData{} + resp.AssertContent(assert, &respData) + assert.Equal(respData, reqData) } // TestGetXML tests the GET command with an XML result. @@ -97,12 +85,11 @@ func TestGetXML(t *testing.T) { err := mux.Register("test", "xml", NewTestHandler("xml", assert)) assert.Nil(err) // Perform test requests. - resp := ts.DoRequest(&restaudit.Request{ - Method: "GET", - Path: "/base/test/xml/4711", - Header: restaudit.KeyValues{"Accept": "application/xml"}, - }) - assert.Substring("4711", string(resp.Body)) + req := restaudit.NewRequest("GET", "/base/test/xml/4711") + req.AddHeader(restaudit.HeaderAccept, restaudit.ApplicationXML) + resp := ts.DoRequest(req) + resp.AssertStatus(assert, 200) + resp.AssertContentMatch(assert, `.*4711.*`) } // TestPutXML tests the PUT command with a XML payload and result. @@ -115,18 +102,14 @@ 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") reqData := TestRequestData{"foo", "bar", "4711", "0815", ""} - reqBuf, _ := xml.Marshal(reqData) - resp := ts.DoRequest(&restaudit.Request{ - Method: "PUT", - Path: "/base/test/xml/4711", - Header: restaudit.KeyValues{"Content-Type": "application/xml", "Accept": "application/xml"}, - Body: reqBuf, - }) - var recvData TestRequestData - err = xml.Unmarshal(resp.Body, &recvData) - assert.Nil(err) - assert.Equal(recvData, reqData) + req.SetContent(assert, restaudit.ApplicationXML, reqData) + resp := ts.DoRequest(req) + resp.AssertStatus(assert, 200) + respData := TestRequestData{} + resp.AssertContent(assert, &respData) + assert.Equal(respData, reqData) } // TestPutGOB tests the PUT command with a GOB payload and result. @@ -139,21 +122,14 @@ 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") reqData := TestCounterData{"test", 4711} - reqBuf := new(bytes.Buffer) - err = gob.NewEncoder(reqBuf).Encode(reqData) - assert.Nil(err, "GOB encode.") - resp := ts.DoRequest(&restaudit.Request{ - Method: "POST", - Path: "/base/test/gob", - Header: restaudit.KeyValues{"Content-Type": "application/vnd.tideland.gob"}, - Body: reqBuf.Bytes(), - }) - var respData TestCounterData - err = gob.NewDecoder(bytes.NewBuffer(resp.Body)).Decode(&respData) - assert.Nil(err) - assert.Equal(respData.ID, "test") - assert.Equal(respData.Count, int64(4711)) + req.SetContent(assert, restaudit.ApplicationGOB, reqData) + resp := ts.DoRequest(req) + resp.AssertStatus(assert, 200) + respData := TestCounterData{} + resp.AssertContent(assert, &respData) + assert.Equal(respData, reqData) } // TestLongPath tests the setting of long path tail as resource ID. @@ -166,11 +142,9 @@ func TestLongPath(t *testing.T) { err := mux.Register("content", "blog", NewTestHandler("default", assert)) assert.Nil(err) // Perform test requests. - resp := ts.DoRequest(&restaudit.Request{ - Method: "GET", - Path: "/base/content/blog/2014/09/30/just-a-test", - }) - assert.Substring("
  • Resource ID: 2014/09/30/just-a-test
  • ", string(resp.Body)) + req := restaudit.NewRequest("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.*`) } // TestFallbackDefault tests the fallback to default. @@ -183,11 +157,9 @@ func TestFallbackDefault(t *testing.T) { err := mux.Register("testing", "index", NewTestHandler("default", assert)) assert.Nil(err) // Perform test requests. - resp := ts.DoRequest(&restaudit.Request{ - Method: "GET", - Path: "/base/x/y", - }) - assert.Substring("
  • Resource: y
  • ", string(resp.Body)) + req := restaudit.NewRequest("GET", "/base/x/y") + resp := ts.DoRequest(req) + resp.AssertContentMatch(assert, `.*Resource: y.*`) } // TestHandlerStack tests a complete handler stack. @@ -204,25 +176,17 @@ func TestHandlerStack(t *testing.T) { }) assert.Nil(err) // Perform test requests. - resp := ts.DoRequest(&restaudit.Request{ - Method: "GET", - Path: "/base/test/stack", - }) - token := resp.Header["Token"] + req := restaudit.NewRequest("GET", "/base/test/stack") + resp := ts.DoRequest(req) + resp.AssertContentMatch(assert, ".*Resource: token.*") + token := resp.AssertHeader(assert, "Token") assert.Equal(token, "foo") - assert.Substring("
  • Resource: token
  • ", string(resp.Body)) - resp = ts.DoRequest(&restaudit.Request{ - Method: "GET", - Path: "/base/test/stack", - Header: restaudit.KeyValues{"token": "foo"}, - }) - assert.Substring("
  • Resource: stack
  • ", string(resp.Body)) - resp = ts.DoRequest(&restaudit.Request{ - Method: "GET", - Path: "/base/test/stack", - Header: restaudit.KeyValues{"token": "foo"}, - }) - assert.Substring("
  • Resource: stack
  • ", string(resp.Body)) + req = restaudit.NewRequest("GET", "/base/test/stack") + req.AddHeader("token", "foo") + resp = ts.DoRequest(req) + resp.AssertContentMatch(assert, ".*Resource: stack.*") + resp = ts.DoRequest(req) + resp.AssertContentMatch(assert, ".*Resource: stack.*") } // TestVersion tests request and response version. @@ -235,34 +199,27 @@ func TestVersion(t *testing.T) { err := mux.Register("test", "json", NewTestHandler("json", assert)) assert.Nil(err) // Perform test requests. - resp := ts.DoRequest(&restaudit.Request{ - Method: "GET", - Path: "/base/test/json/4711?foo=0815", - Header: restaudit.KeyValues{ - "Accept": "application/json", - }, - }) - vsn := resp.Header["Version"] + req := restaudit.NewRequest("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 = ts.DoRequest(&restaudit.Request{ - Method: "GET", - Path: "/base/test/json/4711?foo=0815", - Header: restaudit.KeyValues{ - "Accept": "application/json", - "Version": "2", - }, - }) - vsn = resp.Header["Version"] + + 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.AssertStatus(assert, 200) + vsn = resp.AssertHeader(assert, "Version") assert.Equal(vsn, "2.0.0") - resp = ts.DoRequest(&restaudit.Request{ - Method: "GET", - Path: "/base/test/json/4711?foo=0815", - Header: restaudit.KeyValues{ - "Accept": "application/json", - "Version": "3.0", - }, - }) - vsn = resp.Header["Version"] + + 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) + resp.AssertStatus(assert, 200) + vsn = resp.AssertHeader(assert, "Version") assert.Equal(vsn, "4.0.0-alpha") } @@ -318,11 +275,9 @@ func TestMethodNotSupported(t *testing.T) { err := mux.Register("test", "method", NewTestHandler("method", assert)) assert.Nil(err) // Perform test requests. - resp := ts.DoRequest(&restaudit.Request{ - Method: "OPTION", - Path: "/base/test/method", - }) - assert.Substring("OPTION", string(resp.Body)) + req := restaudit.NewRequest("OPTION", "/base/test/method") + resp := ts.DoRequest(req) + resp.AssertContentMatch(assert, ".*OPTION.*") } //-------------------- diff --git a/restaudit/doc.go b/restaudit/doc.go index 69140b1..7f24a15 100644 --- a/restaudit/doc.go +++ b/restaudit/doc.go @@ -1,13 +1,15 @@ // Tideland Go REST Server Library - REST Audit // -// Copyright (C) 2009-2016 Frank Mueller / Tideland / Oldenburg / Germany +// Copyright (C) 2009-2017 Frank Mueller / Tideland / Oldenburg / Germany // // All rights reserved. Use of this source code is governed // by the new BSD license. -// The Tideland Go REST Server Library restaudit package is a little +// Package restaudit of the Tideland Go REST Server Library is a little // helper package for the unit testing of the rest package and the -// resource handlers. +// 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. package restaudit // EOF diff --git a/restaudit/restaudit.go b/restaudit/restaudit.go index 3d19e8f..6adc8a3 100644 --- a/restaudit/restaudit.go +++ b/restaudit/restaudit.go @@ -1,6 +1,6 @@ // Tideland Go REST Server Library - REST Audit // -// Copyright (C) 2009-2016 Frank Mueller / Tideland / Oldenburg / Germany +// Copyright (C) 2009-2017 Frank Mueller / Tideland / Oldenburg / Germany // // All rights reserved. Use of this source code is governed // by the new BSD license. @@ -13,23 +13,45 @@ package restaudit import ( "bytes" + "encoding/gob" + "encoding/json" + "encoding/xml" + "html/template" "io" "io/ioutil" "mime/multipart" "net/http" "net/http/httptest" + "regexp" "strings" "github.com/tideland/golib/audit" ) //-------------------- -// TEST TOOLS +// CONSTENTS +//-------------------- + +const ( + HeaderAccept = "Accept" + HeaderContentType = "Content-Type" + + ApplicationGOB = "application/vnd.tideland.gob" + ApplicationJSON = "application/json" + ApplicationXML = "application/xml" +) + +//-------------------- +// TEST TYPES //-------------------- // KeyValues handles keys and values for request headers and cookies. type KeyValues map[string]string +//-------------------- +// REQUEST +//-------------------- + // Request wraps all infos for a test request. type Request struct { Method string @@ -40,6 +62,91 @@ type Request struct { RequestProcessor func(req *http.Request) *http.Request } +// NewRequest creates a new test request with the given method +// and path. +func NewRequest(method, path string) *Request { + return &Request{ + Method: method, + Path: path, + } +} + +// AddHeader adds or overwrites a request header. +func (r *Request) AddHeader(key, value string) *Request { + if r.Header == nil { + r.Header = KeyValues{} + } + r.Header[key] = value + return r +} + +// AddCookie adds or overwrites a request header. +func (r *Request) AddCookie(key, value string) *Request { + if r.Cookies == nil { + r.Cookies = KeyValues{} + } + r.Cookies[key] = value + return r +} + +// SetContent sets the request content based on the type and +// the marshalled data. +func (r *Request) SetContent( + assert audit.Assertion, + 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.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.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.Body = body + r.AddHeader(HeaderContentType, ApplicationXML) + r.AddHeader(HeaderAccept, ApplicationXML) + } + return r +} + +// 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 { + // Render template. + t, err := template.New(r.Path).Parse(templateSource) + assert.Nil(err, "cannot parse template") + body := &bytes.Buffer{} + err = t.Execute(body, data) + assert.Nil(err, "cannot render template") + r.Body = body.Bytes() + // Set content type. + r.AddHeader(HeaderContentType, contentType) + r.AddHeader(HeaderAccept, contentType) + return r +} + +//-------------------- +// RESPONSE +//-------------------- + // Response wraps all infos of a test response. type Response struct { Status int @@ -48,10 +155,62 @@ type Response struct { 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") +} + +// 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") + value, ok := r.Header[key] + assert.True(ok, "header '"+key+"' not found") + return value +} + +// 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") + value, ok := r.Cookies[key] + assert.True(ok, "cookie '"+key+"' not found") + return value +} + +// AssertContent retrieves the content based on the content type +// and unmarshals it accordingly. +func (r *Response) AssertContent(assert audit.Assertion, data interface{}) { + contentType, ok := r.Header[HeaderContentType] + 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") + case ApplicationJSON: + err := json.Unmarshal(r.Body, data) + assert.Nil(err, "cannot unmarshal JSON body") + case ApplicationXML: + err := xml.Unmarshal(r.Body, data) + assert.Nil(err, "cannot unmarshal XML body") + default: + assert.Fail("unknown content type: " + contentType) + } +} + +// AssertContentMatch checks if the content matches a regular expression. +func (r *Response) AssertContentMatch(assert audit.Assertion, 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") +} + //-------------------- // TEST SERVER //-------------------- +// TestServer defines the test server with methods for requests +// and uploads. type TestServer interface { // Close shuts down the server and blocks until all outstanding // requests have completed. @@ -78,12 +237,12 @@ func StartServer(handler http.Handler, assert audit.Assertion) TestServer { } } -// Close is specified on the TestServer interface. +// Close implements the TestServer interface. func (ts *testServer) Close() { ts.server.Close() } -// DoRequest is specified on the TestServer interface. +// DoRequest implements the TestServer interface. func (ts *testServer) DoRequest(req *Request) *Response { // First prepare it. transport := &http.Transport{} @@ -115,7 +274,7 @@ func (ts *testServer) DoRequest(req *Request) *Response { return ts.response(resp) } -// DoUpload is specified on the TestServer interface. +// DoUpload implements the TestServer interface. func (ts *testServer) DoUpload(path, fieldname, filename, data string) *Response { // Prepare request. transport := &http.Transport{}