func TestContentTypeCheckerMiddleware(t *testing.T) {

	api := NewApi()

	// the middleware to test
	api.Use(&ContentTypeCheckerMiddleware{})

	// a simple app
	api.SetApp(AppSimple(func(w ResponseWriter, r *Request) {
		w.WriteJson(map[string]string{"Id": "123"})
	}))

	// wrap all
	handler := api.MakeHandler()

	// no payload, no content length, no check
	recorded := test.RunRequest(t, handler, test.MakeSimpleRequest("GET", "http://localhost/", nil))
	recorded.CodeIs(200)

	// JSON payload with correct content type
	recorded = test.RunRequest(t, handler, test.MakeSimpleRequest("POST", "http://localhost/", map[string]string{"Id": "123"}))
	recorded.CodeIs(200)

	// JSON payload with correct content type specifying the utf-8 charset
	req := test.MakeSimpleRequest("POST", "http://localhost/", map[string]string{"Id": "123"})
	req.Header.Set("Content-Type", "application/json; charset=utf-8")
	recorded = test.RunRequest(t, handler, req)
	recorded.CodeIs(200)

	// JSON payload with incorrect content type
	req = test.MakeSimpleRequest("POST", "http://localhost/", map[string]string{"Id": "123"})
	req.Header.Set("Content-Type", "text/x-json")
	recorded = test.RunRequest(t, handler, req)
	recorded.CodeIs(415)
}
func TestAccessLogApacheMiddlewareMissingData(t *testing.T) {

	api := NewApi()

	// the uncomplete middlewares stack
	buffer := bytes.NewBufferString("")
	api.Use(&AccessLogApacheMiddleware{
		Logger:       log.New(buffer, "", 0),
		Format:       CommonLogFormat,
		textTemplate: nil,
	})

	// a simple app
	api.SetApp(AppSimple(func(w ResponseWriter, r *Request) {
		w.WriteJson(map[string]string{"Id": "123"})
	}))

	// wrap all
	handler := api.MakeHandler()

	req := test.MakeSimpleRequest("GET", "http://localhost/", nil)
	recorded := test.RunRequest(t, handler, req)
	recorded.CodeIs(200)
	recorded.ContentTypeIsJson()

	// not much to log when the Env data is missing, but this should still work
	apacheCommon := regexp.MustCompile(` - -  "GET / HTTP/1.1" 0 -`)

	if !apacheCommon.Match(buffer.Bytes()) {
		t.Errorf("Got: %s", buffer.String())
	}
}
func TestAccessLogApacheMiddleware(t *testing.T) {

	api := NewApi()

	// the middlewares stack
	buffer := bytes.NewBufferString("")
	api.Use(&AccessLogApacheMiddleware{
		Logger:       log.New(buffer, "", 0),
		Format:       CommonLogFormat,
		textTemplate: nil,
	})
	api.Use(&TimerMiddleware{})
	api.Use(&RecorderMiddleware{})

	// a simple app
	api.SetApp(AppSimple(func(w ResponseWriter, r *Request) {
		w.WriteJson(map[string]string{"Id": "123"})
	}))

	// wrap all
	handler := api.MakeHandler()

	req := test.MakeSimpleRequest("GET", "http://localhost/", nil)
	req.RemoteAddr = "127.0.0.1:1234"
	recorded := test.RunRequest(t, handler, req)
	recorded.CodeIs(200)
	recorded.ContentTypeIsJson()

	// log tests, eg: '127.0.0.1 - - 29/Nov/2014:22:28:34 +0000 "GET / HTTP/1.1" 200 12'
	apacheCommon := regexp.MustCompile(`127.0.0.1 - - \d{2}/\w{3}/\d{4}:\d{2}:\d{2}:\d{2} [+\-]\d{4}\ "GET / HTTP/1.1" 200 12`)

	if !apacheCommon.Match(buffer.Bytes()) {
		t.Errorf("Got: %s", buffer.String())
	}
}
func TestRecoverMiddleware(t *testing.T) {

	api := NewApi()

	// the middleware to test
	api.Use(&RecoverMiddleware{
		Logger:                   log.New(ioutil.Discard, "", 0),
		EnableLogAsJson:          false,
		EnableResponseStackTrace: true,
	})

	// a simple app that fails
	api.SetApp(AppSimple(func(w ResponseWriter, r *Request) {
		panic("test")
	}))

	// wrap all
	handler := api.MakeHandler()

	req := test.MakeSimpleRequest("GET", "http://localhost/", nil)
	recorded := test.RunRequest(t, handler, req)
	recorded.CodeIs(500)
	recorded.ContentTypeIsJson()

	// payload
	payload := map[string]string{}
	err := recorded.DecodeJsonPayload(&payload)
	if err != nil {
		t.Fatal(err)
	}
	if payload["Error"] == "" {
		t.Errorf("Expected an error message, got: %v", payload)
	}
}
Beispiel #5
0
func TestStatusMiddleware(t *testing.T) {

	api := NewApi()

	// the middlewares
	status := &StatusMiddleware{}
	api.Use(status)
	api.Use(&TimerMiddleware{})
	api.Use(&RecorderMiddleware{})

	// an app that return the Status
	api.SetApp(AppSimple(func(w ResponseWriter, r *Request) {
		w.WriteJson(status.GetStatus())
	}))

	// wrap all
	handler := api.MakeHandler()

	// one request
	recorded := test.RunRequest(t, handler, test.MakeSimpleRequest("GET", "http://localhost/1", nil))
	recorded.CodeIs(200)
	recorded.ContentTypeIsJson()

	// another request
	recorded = test.RunRequest(t, handler, test.MakeSimpleRequest("GET", "http://localhost/2", nil))
	recorded.CodeIs(200)
	recorded.ContentTypeIsJson()

	// payload
	payload := map[string]interface{}{}
	err := recorded.DecodeJsonPayload(&payload)
	if err != nil {
		t.Fatal(err)
	}

	if payload["Pid"] == nil {
		t.Error("Expected a non nil Pid")
	}

	if payload["TotalCount"].(float64) != 1 {
		t.Errorf("TotalCount 1 Expected, got: %f", payload["TotalCount"].(float64))
	}

	if payload["StatusCodeCount"].(map[string]interface{})["200"].(float64) != 1 {
		t.Errorf("StatusCodeCount 200 1 Expected, got: %f", payload["StatusCodeCount"].(map[string]interface{})["200"].(float64))
	}
}
Beispiel #6
0
func TestIfMiddleware(t *testing.T) {

	api := NewApi()

	// the middleware to test
	api.Use(&IfMiddleware{
		Condition: func(r *Request) bool {
			if r.URL.Path == "/true" {
				return true
			}
			return false
		},
		IfTrue: MiddlewareSimple(func(handler HandlerFunc) HandlerFunc {
			return func(w ResponseWriter, r *Request) {
				r.Env["TRUE_MIDDLEWARE"] = true
				handler(w, r)
			}
		}),
		IfFalse: MiddlewareSimple(func(handler HandlerFunc) HandlerFunc {
			return func(w ResponseWriter, r *Request) {
				r.Env["FALSE_MIDDLEWARE"] = true
				handler(w, r)
			}
		}),
	})

	// a simple app
	api.SetApp(AppSimple(func(w ResponseWriter, r *Request) {
		w.WriteJson(r.Env)
	}))

	// wrap all
	handler := api.MakeHandler()

	recorded := test.RunRequest(t, handler, test.MakeSimpleRequest("GET", "http://localhost/", nil))
	recorded.CodeIs(200)
	recorded.ContentTypeIsJson()
	recorded.BodyIs("{\"FALSE_MIDDLEWARE\":true}")

	recorded = test.RunRequest(t, handler, test.MakeSimpleRequest("GET", "http://localhost/true", nil))
	recorded.CodeIs(200)
	recorded.ContentTypeIsJson()
	recorded.BodyIs("{\"TRUE_MIDDLEWARE\":true}")
}
Beispiel #7
0
func TestJsonpMiddleware(t *testing.T) {

	api := NewApi()

	// the middleware to test
	api.Use(&JsonpMiddleware{})

	// router app with success and error paths
	router, err := MakeRouter(
		Get("/ok", func(w ResponseWriter, r *Request) {
			w.WriteJson(map[string]string{"Id": "123"})
		}),
		Get("/error", func(w ResponseWriter, r *Request) {
			Error(w, "jsonp error", 500)
		}),
	)
	if err != nil {
		t.Fatal(err)
	}

	api.SetApp(router)

	// wrap all
	handler := api.MakeHandler()

	recorded := test.RunRequest(t, handler, test.MakeSimpleRequest("GET", "http://localhost/ok?callback=parseResponse", nil))
	recorded.CodeIs(200)
	recorded.HeaderIs("Content-Type", "text/javascript")
	recorded.HeaderIs("Content-Disposition", "filename=f.txt")
	recorded.HeaderIs("X-Content-Type-Options", "nosniff")
	recorded.BodyIs("/**/parseResponse({\"Id\":\"123\"})")

	recorded = test.RunRequest(t, handler, test.MakeSimpleRequest("GET", "http://localhost/error?callback=parseResponse", nil))
	recorded.CodeIs(500)
	recorded.HeaderIs("Content-Type", "text/javascript")
	recorded.HeaderIs("Content-Disposition", "filename=f.txt")
	recorded.HeaderIs("X-Content-Type-Options", "nosniff")
	recorded.BodyIs("/**/parseResponse({\"Error\":\"jsonp error\"})")
}
Beispiel #8
0
func TestTimerMiddleware(t *testing.T) {

	api := NewApi()

	// a middleware carrying the Env tests
	api.Use(MiddlewareSimple(func(handler HandlerFunc) HandlerFunc {
		return func(w ResponseWriter, r *Request) {

			handler(w, r)

			if r.Env["ELAPSED_TIME"] == nil {
				t.Error("ELAPSED_TIME is nil")
			}
			elapsedTime := r.Env["ELAPSED_TIME"].(*time.Duration)
			if elapsedTime.Nanoseconds() <= 0 {
				t.Errorf(
					"ELAPSED_TIME is expected to be at least 1 nanosecond %d",
					elapsedTime.Nanoseconds(),
				)
			}

			if r.Env["START_TIME"] == nil {
				t.Error("START_TIME is nil")
			}
			start := r.Env["START_TIME"].(*time.Time)
			if start.After(time.Now()) {
				t.Errorf(
					"START_TIME is expected to be in the past %s",
					start.String(),
				)
			}
		}
	}))

	// the middleware to test
	api.Use(&TimerMiddleware{})

	// a simple app
	api.SetApp(AppSimple(func(w ResponseWriter, r *Request) {
		w.WriteJson(map[string]string{"Id": "123"})
	}))

	// wrap all
	handler := api.MakeHandler()

	req := test.MakeSimpleRequest("GET", "http://localhost/", nil)
	recorded := test.RunRequest(t, handler, req)
	recorded.CodeIs(200)
	recorded.ContentTypeIsJson()
}
Beispiel #9
0
func TestGzipEnabled(t *testing.T) {

	api := NewApi()

	// the middleware to test
	api.Use(&GzipMiddleware{})

	// router app with success and error paths
	router, err := MakeRouter(
		Get("/ok", func(w ResponseWriter, r *Request) {
			w.WriteJson(map[string]string{"Id": "123"})
		}),
		Get("/error", func(w ResponseWriter, r *Request) {
			Error(w, "gzipped error", 500)
		}),
	)
	if err != nil {
		t.Fatal(err)
	}

	api.SetApp(router)

	// wrap all
	handler := api.MakeHandler()

	recorded := test.RunRequest(t, handler, test.MakeSimpleRequest("GET", "http://localhost/ok", nil))
	recorded.CodeIs(200)
	recorded.ContentTypeIsJson()
	recorded.ContentEncodingIsGzip()
	recorded.HeaderIs("Vary", "Accept-Encoding")

	recorded = test.RunRequest(t, handler, test.MakeSimpleRequest("GET", "http://localhost/error", nil))
	recorded.CodeIs(500)
	recorded.ContentTypeIsJson()
	recorded.ContentEncodingIsGzip()
	recorded.HeaderIs("Vary", "Accept-Encoding")
}
Beispiel #10
0
func TestApiNoAppNoMiddleware(t *testing.T) {

	api := NewApi()
	if api == nil {
		t.Fatal("Api object must be instantiated")
	}

	handler := api.MakeHandler()
	if handler == nil {
		t.Fatal("the http.Handler must be have been create")
	}

	recorded := test.RunRequest(t, handler, test.MakeSimpleRequest("GET", "http://localhost/", nil))
	recorded.CodeIs(200)
}
Beispiel #11
0
func TestApiSimpleAppNoMiddleware(t *testing.T) {

	api := NewApi()
	api.SetApp(AppSimple(func(w ResponseWriter, r *Request) {
		w.WriteJson(map[string]string{"Id": "123"})
	}))

	handler := api.MakeHandler()
	if handler == nil {
		t.Fatal("the http.Handler must be have been create")
	}

	recorded := test.RunRequest(t, handler, test.MakeSimpleRequest("GET", "http://localhost/", nil))
	recorded.CodeIs(200)
	recorded.ContentTypeIsJson()
	recorded.BodyIs(`{"Id":"123"}`)
}
func TestRecorderMiddleware(t *testing.T) {

	api := NewApi()

	// a middleware carrying the Env tests
	api.Use(MiddlewareSimple(func(handler HandlerFunc) HandlerFunc {
		return func(w ResponseWriter, r *Request) {

			handler(w, r)

			if r.Env["STATUS_CODE"] == nil {
				t.Error("STATUS_CODE is nil")
			}
			statusCode := r.Env["STATUS_CODE"].(int)
			if statusCode != 200 {
				t.Errorf("STATUS_CODE = 200 expected, got %d", statusCode)
			}

			if r.Env["BYTES_WRITTEN"] == nil {
				t.Error("BYTES_WRITTEN is nil")
			}
			bytesWritten := r.Env["BYTES_WRITTEN"].(int64)
			// '{"Id":"123"}' => 12 chars
			if bytesWritten != 12 {
				t.Errorf("BYTES_WRITTEN 12 expected, got %d", bytesWritten)
			}
		}
	}))

	// the middleware to test
	api.Use(&RecorderMiddleware{})

	// a simple app
	api.SetApp(AppSimple(func(w ResponseWriter, r *Request) {
		w.WriteJson(map[string]string{"Id": "123"})
	}))

	// wrap all
	handler := api.MakeHandler()

	req := test.MakeSimpleRequest("GET", "http://localhost/", nil)
	recorded := test.RunRequest(t, handler, req)
	recorded.CodeIs(200)
	recorded.ContentTypeIsJson()
}
Beispiel #13
0
func TestProdStack(t *testing.T) {

	api := NewApi()
	api.Use(DefaultProdStack...)
	api.SetApp(AppSimple(func(w ResponseWriter, r *Request) {
		w.WriteJson(map[string]string{"Id": "123"})
	}))

	handler := api.MakeHandler()
	if handler == nil {
		t.Fatal("the http.Handler must be have been create")
	}

	recorded := test.RunRequest(t, handler, test.MakeSimpleRequest("GET", "http://localhost/", nil))
	recorded.CodeIs(200)
	recorded.ContentTypeIsJson()
	recorded.ContentEncodingIsGzip()
}
func TestAccessLogJsonMiddleware(t *testing.T) {

	api := NewApi()

	// the middlewares stack
	buffer := bytes.NewBufferString("")
	api.Use(&AccessLogJsonMiddleware{
		Logger: log.New(buffer, "", 0),
	})
	api.Use(&TimerMiddleware{})
	api.Use(&RecorderMiddleware{})

	// a simple app
	api.SetApp(AppSimple(func(w ResponseWriter, r *Request) {
		w.WriteJson(map[string]string{"Id": "123"})
	}))

	// wrap all
	handler := api.MakeHandler()

	req := test.MakeSimpleRequest("GET", "http://localhost/", nil)
	req.RemoteAddr = "127.0.0.1:1234"
	recorded := test.RunRequest(t, handler, req)
	recorded.CodeIs(200)
	recorded.ContentTypeIsJson()

	// log tests
	decoded := &AccessLogJsonRecord{}
	err := json.Unmarshal(buffer.Bytes(), decoded)
	if err != nil {
		t.Fatal(err)
	}

	if decoded.StatusCode != 200 {
		t.Errorf("StatusCode 200 expected, got %d", decoded.StatusCode)
	}
	if decoded.RequestURI != "/" {
		t.Errorf("RequestURI / expected, got %s", decoded.RequestURI)
	}
	if decoded.HttpMethod != "GET" {
		t.Errorf("HttpMethod GET expected, got %s", decoded.HttpMethod)
	}
}
func TestJsonIndentMiddleware(t *testing.T) {

	api := NewApi()

	// the middleware to test
	api.Use(&JsonIndentMiddleware{})

	// a simple app
	api.SetApp(AppSimple(func(w ResponseWriter, r *Request) {
		w.WriteJson(map[string]string{"Id": "123"})
	}))

	// wrap all
	handler := api.MakeHandler()

	req := test.MakeSimpleRequest("GET", "http://localhost/", nil)
	recorded := test.RunRequest(t, handler, req)
	recorded.CodeIs(200)
	recorded.ContentTypeIsJson()
	recorded.BodyIs("{\n  \"Id\": \"123\"\n}")
}
// See how many bytes are written when gzipping
func TestRecorderAndGzipMiddleware(t *testing.T) {

	api := NewApi()

	// a middleware carrying the Env tests
	api.Use(MiddlewareSimple(func(handler HandlerFunc) HandlerFunc {
		return func(w ResponseWriter, r *Request) {

			handler(w, r)

			if r.Env["BYTES_WRITTEN"] == nil {
				t.Error("BYTES_WRITTEN is nil")
			}
			bytesWritten := r.Env["BYTES_WRITTEN"].(int64)
			// Yes, the gzipped version actually takes more space.
			if bytesWritten != 28 {
				t.Errorf("BYTES_WRITTEN 28 expected, got %d", bytesWritten)
			}
		}
	}))

	// the middlewares to test
	api.Use(&RecorderMiddleware{})
	api.Use(&GzipMiddleware{})

	// a simple app
	api.SetApp(AppSimple(func(w ResponseWriter, r *Request) {
		w.WriteJson(map[string]string{"Id": "123"})
	}))

	// wrap all
	handler := api.MakeHandler()

	req := test.MakeSimpleRequest("GET", "http://localhost/", nil)
	// "Accept-Encoding", "gzip" is set by test.MakeSimpleRequest
	recorded := test.RunRequest(t, handler, req)
	recorded.CodeIs(200)
	recorded.ContentTypeIsJson()
}
func TestPoweredByMiddleware(t *testing.T) {

	api := NewApi()

	// the middleware to test
	api.Use(&PoweredByMiddleware{
		XPoweredBy: "test",
	})

	// a simple app
	api.SetApp(AppSimple(func(w ResponseWriter, r *Request) {
		w.WriteJson(map[string]string{"Id": "123"})
	}))

	// wrap all
	handler := api.MakeHandler()

	req := test.MakeSimpleRequest("GET", "http://localhost/", nil)
	recorded := test.RunRequest(t, handler, req)
	recorded.CodeIs(200)
	recorded.ContentTypeIsJson()
	recorded.HeaderIs("X-Powered-By", "test")
}
Beispiel #18
0
func TestGzipDisabled(t *testing.T) {

	api := NewApi()

	// router app with success and error paths
	router, err := MakeRouter(
		Get("/ok", func(w ResponseWriter, r *Request) {
			w.WriteJson(map[string]string{"Id": "123"})
		}),
	)
	if err != nil {
		t.Fatal(err)
	}

	api.SetApp(router)
	handler := api.MakeHandler()

	recorded := test.RunRequest(t, handler, test.MakeSimpleRequest("GET", "http://localhost/ok", nil))
	recorded.CodeIs(200)
	recorded.ContentTypeIsJson()
	recorded.HeaderIs("Content-Encoding", "")
	recorded.HeaderIs("Vary", "")
}
func TestAuthBasic(t *testing.T) {

	// the middleware to test
	authMiddleware := &AuthBasicMiddleware{
		Realm: "test zone",
		Authenticator: func(userId string, password string) bool {
			if userId == "admin" && password == "admin" {
				return true
			}
			return false
		},
		Authorizator: func(userId string, request *Request) bool {
			if request.Method == "GET" {
				return true
			}
			return false
		},
	}

	// api for testing failure
	apiFailure := NewApi()
	apiFailure.Use(authMiddleware)
	apiFailure.SetApp(AppSimple(func(w ResponseWriter, r *Request) {
		t.Error("Should never be executed")
	}))
	handler := apiFailure.MakeHandler()

	// simple request fails
	recorded := test.RunRequest(t, handler, test.MakeSimpleRequest("GET", "http://localhost/", nil))
	recorded.CodeIs(401)
	recorded.ContentTypeIsJson()

	// auth with wrong cred and right method fails
	wrongCredReq := test.MakeSimpleRequest("GET", "http://localhost/", nil)
	encoded := base64.StdEncoding.EncodeToString([]byte("admin:AdmIn"))
	wrongCredReq.Header.Set("Authorization", "Basic "+encoded)
	recorded = test.RunRequest(t, handler, wrongCredReq)
	recorded.CodeIs(401)
	recorded.ContentTypeIsJson()

	// auth with right cred and wrong method fails
	rightCredReq := test.MakeSimpleRequest("POST", "http://localhost/", nil)
	encoded = base64.StdEncoding.EncodeToString([]byte("admin:admin"))
	rightCredReq.Header.Set("Authorization", "Basic "+encoded)
	recorded = test.RunRequest(t, handler, rightCredReq)
	recorded.CodeIs(401)
	recorded.ContentTypeIsJson()

	// api for testing success
	apiSuccess := NewApi()
	apiSuccess.Use(authMiddleware)
	apiSuccess.SetApp(AppSimple(func(w ResponseWriter, r *Request) {
		if r.Env["REMOTE_USER"] == nil {
			t.Error("REMOTE_USER is nil")
		}
		user := r.Env["REMOTE_USER"].(string)
		if user != "admin" {
			t.Error("REMOTE_USER is expected to be 'admin'")
		}
		w.WriteJson(map[string]string{"Id": "123"})
	}))

	// auth with right cred and right method succeeds
	rightCredReq = test.MakeSimpleRequest("GET", "http://localhost/", nil)
	encoded = base64.StdEncoding.EncodeToString([]byte("admin:admin"))
	rightCredReq.Header.Set("Authorization", "Basic "+encoded)
	recorded = test.RunRequest(t, apiSuccess.MakeHandler(), rightCredReq)
	recorded.CodeIs(200)
	recorded.ContentTypeIsJson()
}
Beispiel #20
0
func TestHandler(t *testing.T) {

	handler := ResourceHandler{
		DisableJsonIndent: true,
		// make the test output less verbose by discarding the error log
		ErrorLogger: log.New(ioutil.Discard, "", 0),
	}
	handler.SetRoutes(
		Get("/r/:id", func(w ResponseWriter, r *Request) {
			id := r.PathParam("id")
			w.WriteJson(map[string]string{"Id": id})
		}),
		Post("/r/:id", func(w ResponseWriter, r *Request) {
			// JSON echo
			data := map[string]string{}
			err := r.DecodeJsonPayload(&data)
			if err != nil {
				t.Fatal(err)
			}
			w.WriteJson(data)
		}),
		Get("/auto-fails", func(w ResponseWriter, r *Request) {
			a := []int{}
			_ = a[0]
		}),
		Get("/user-error", func(w ResponseWriter, r *Request) {
			Error(w, "My error", 500)
		}),
		Get("/user-notfound", func(w ResponseWriter, r *Request) {
			NotFound(w, r)
		}),
	)

	// valid get resource
	recorded := test.RunRequest(t, &handler, test.MakeSimpleRequest("GET", "http://1.2.3.4/r/123", nil))
	recorded.CodeIs(200)
	recorded.ContentTypeIsJson()
	recorded.BodyIs(`{"Id":"123"}`)

	// valid post resource
	recorded = test.RunRequest(t, &handler, test.MakeSimpleRequest(
		"POST", "http://1.2.3.4/r/123", &map[string]string{"Test": "Test"}))
	recorded.CodeIs(200)
	recorded.ContentTypeIsJson()
	recorded.BodyIs(`{"Test":"Test"}`)

	// broken Content-Type post resource
	request := test.MakeSimpleRequest("POST", "http://1.2.3.4/r/123", &map[string]string{"Test": "Test"})
	request.Header.Set("Content-Type", "text/html")
	recorded = test.RunRequest(t, &handler, request)
	recorded.CodeIs(415)
	recorded.ContentTypeIsJson()
	recorded.BodyIs(`{"Error":"Bad Content-Type or charset, expected 'application/json'"}`)

	// broken Content-Type post resource
	request = test.MakeSimpleRequest("POST", "http://1.2.3.4/r/123", &map[string]string{"Test": "Test"})
	request.Header.Set("Content-Type", "application/json; charset=ISO-8859-1")
	recorded = test.RunRequest(t, &handler, request)
	recorded.CodeIs(415)
	recorded.ContentTypeIsJson()
	recorded.BodyIs(`{"Error":"Bad Content-Type or charset, expected 'application/json'"}`)

	// Content-Type post resource with charset
	request = test.MakeSimpleRequest("POST", "http://1.2.3.4/r/123", &map[string]string{"Test": "Test"})
	request.Header.Set("Content-Type", "application/json;charset=UTF-8")
	recorded = test.RunRequest(t, &handler, request)
	recorded.CodeIs(200)
	recorded.ContentTypeIsJson()
	recorded.BodyIs(`{"Test":"Test"}`)

	// auto 405 on undefined route (wrong method)
	recorded = test.RunRequest(t, &handler, test.MakeSimpleRequest("DELETE", "http://1.2.3.4/r/123", nil))
	recorded.CodeIs(405)
	recorded.ContentTypeIsJson()
	recorded.BodyIs(`{"Error":"Method not allowed"}`)

	// auto 404 on undefined route (wrong path)
	recorded = test.RunRequest(t, &handler, test.MakeSimpleRequest("GET", "http://1.2.3.4/s/123", nil))
	recorded.CodeIs(404)
	recorded.ContentTypeIsJson()
	recorded.BodyIs(`{"Error":"Resource not found"}`)

	// auto 500 on unhandled userecorder error
	recorded = test.RunRequest(t, &handler, test.MakeSimpleRequest("GET", "http://1.2.3.4/auto-fails", nil))
	recorded.CodeIs(500)
	recorded.ContentTypeIsJson()
	recorded.BodyIs(`{"Error":"Internal Server Error"}`)

	// userecorder error
	recorded = test.RunRequest(t, &handler, test.MakeSimpleRequest("GET", "http://1.2.3.4/user-error", nil))
	recorded.CodeIs(500)
	recorded.ContentTypeIsJson()
	recorded.BodyIs(`{"Error":"My error"}`)

	// userecorder notfound
	recorded = test.RunRequest(t, &handler, test.MakeSimpleRequest("GET", "http://1.2.3.4/user-notfound", nil))
	recorded.CodeIs(404)
	recorded.ContentTypeIsJson()
	recorded.BodyIs(`{"Error":"Resource not found"}`)
}