Merge branch 'develop' of https://github.com/beego/beego into develop

This commit is contained in:
holooooo 2021-05-16 14:20:31 +08:00
commit 9b418271cc
6 changed files with 109 additions and 25 deletions

View File

@ -1,5 +1,6 @@
# developing # developing
- Add http client and option func. [4455](https://github.com/beego/beego/issues/4455) - Add http client and option func. [4455](https://github.com/beego/beego/issues/4455)
- Add: Resp() method for web.Controller. [4588](https://github.com/beego/beego/pull/4588)
- Web mock and test support. [4565](https://github.com/beego/beego/pull/4565) [4574](https://github.com/beego/beego/pull/4574) - Web mock and test support. [4565](https://github.com/beego/beego/pull/4565) [4574](https://github.com/beego/beego/pull/4574)
- Error codes definition of cache module. [4493](https://github.com/beego/beego/pull/4493) - Error codes definition of cache module. [4493](https://github.com/beego/beego/pull/4493)
- Remove generateCommentRoute http hook. Using `bee generate routers` commands instead.[4486](https://github.com/beego/beego/pull/4486) [bee PR 762](https://github.com/beego/bee/pull/762) - Remove generateCommentRoute http hook. Using `bee generate routers` commands instead.[4486](https://github.com/beego/beego/pull/4486) [bee PR 762](https://github.com/beego/bee/pull/762)
@ -37,6 +38,7 @@
- Feature issue #4402 finish router get example. [4416](https://github.com/beego/beego/pull/4416) - Feature issue #4402 finish router get example. [4416](https://github.com/beego/beego/pull/4416)
- Proposal: Add Bind() method for `web.Controller` [4491](https://github.com/beego/beego/issues/4579) - Proposal: Add Bind() method for `web.Controller` [4491](https://github.com/beego/beego/issues/4579)
- Optimize AddAutoPrefix: only register one router in case-insensitive mode. [4582](https://github.com/beego/beego/pull/4582) - Optimize AddAutoPrefix: only register one router in case-insensitive mode. [4582](https://github.com/beego/beego/pull/4582)
- Init exceptMethod by using reflection. [4583](https://github.com/beego/beego/pull/4583)
## Fix Sonar ## Fix Sonar
- [4473](https://github.com/beego/beego/pull/4473) - [4473](https://github.com/beego/beego/pull/4473)

View File

@ -21,8 +21,6 @@ import (
"encoding/xml" "encoding/xml"
"errors" "errors"
"fmt" "fmt"
"github.com/gogo/protobuf/proto"
"gopkg.in/yaml.v2"
"html/template" "html/template"
"io" "io"
"mime/multipart" "mime/multipart"
@ -37,6 +35,8 @@ import (
"github.com/beego/beego/v2/server/web/context" "github.com/beego/beego/v2/server/web/context"
"github.com/beego/beego/v2/server/web/context/param" "github.com/beego/beego/v2/server/web/context/param"
"github.com/beego/beego/v2/server/web/session" "github.com/beego/beego/v2/server/web/session"
"github.com/gogo/protobuf/proto"
"gopkg.in/yaml.v2"
) )
var ( var (
@ -436,6 +436,22 @@ func (c *Controller) URLFor(endpoint string, values ...interface{}) string {
} }
return URLFor(endpoint, values...) return URLFor(endpoint, values...)
} }
// Resp sends response based on the Accept Header
// By default response will be in JSON
func (c *Controller) Resp(data interface{}) error {
accept := c.Ctx.Input.Header("Accept")
switch accept {
case context.ApplicationYAML:
c.Data["yaml"] = data
return c.ServeYAML()
case context.ApplicationXML, context.TextXML:
c.Data["xml"] = data
return c.ServeXML()
default:
c.Data["json"] = data
return c.ServeJSON()
}
}
// ServeJSON sends a json response with encoding charset. // ServeJSON sends a json response with encoding charset.
func (c *Controller) ServeJSON(encoding ...bool) error { func (c *Controller) ServeJSON(encoding ...bool) error {

View File

@ -15,16 +15,18 @@
package web package web
import ( import (
"github.com/stretchr/testify/assert" "io/ioutil"
"github.com/stretchr/testify/require"
"math" "math"
"net/http" "net/http"
"net/http/httptest"
"os" "os"
"path/filepath" "path/filepath"
"strconv" "strconv"
"testing" "testing"
"github.com/beego/beego/v2/server/web/context" "github.com/beego/beego/v2/server/web/context"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
func TestGetInt(t *testing.T) { func TestGetInt(t *testing.T) {
@ -244,3 +246,67 @@ func TestBindYAML(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, "FOO", s.Foo) assert.Equal(t, "FOO", s.Foo)
} }
type TestRespController struct {
Controller
}
func (t *TestRespController) TestResponse() {
type S struct {
Foo string `json:"foo" xml:"foo" yaml:"foo"`
}
bar := S{Foo: "bar"}
_ = t.Resp(bar)
}
type respTestCase struct {
Accept string
ExpectedContentLength int64
ExpectedResponse string
}
func TestControllerResp(t *testing.T) {
// test cases
tcs := []respTestCase{
{Accept: context.ApplicationJSON, ExpectedContentLength: 18, ExpectedResponse: "{\n \"foo\": \"bar\"\n}"},
{Accept: context.ApplicationXML, ExpectedContentLength: 25, ExpectedResponse: "<S>\n <foo>bar</foo>\n</S>"},
{Accept: context.ApplicationYAML, ExpectedContentLength: 9, ExpectedResponse: "foo: bar\n"},
{Accept: "OTHER", ExpectedContentLength: 18, ExpectedResponse: "{\n \"foo\": \"bar\"\n}"},
}
for _, tc := range tcs {
testControllerRespTestCases(t, tc)
}
}
func testControllerRespTestCases(t *testing.T, tc respTestCase) {
// create fake GET request
r, _ := http.NewRequest("GET", "/", nil)
r.Header.Set("Accept", tc.Accept)
w := httptest.NewRecorder()
// setup the handler
handler := NewControllerRegister()
handler.Add("/", &TestRespController{}, WithRouterMethods(&TestRespController{}, "get:TestResponse"))
handler.ServeHTTP(w, r)
response := w.Result()
if response.ContentLength != tc.ExpectedContentLength {
t.Errorf("TestResponse() unable to validate content length %d for %s", response.ContentLength, tc.Accept)
}
if response.StatusCode != http.StatusOK {
t.Errorf("TestResponse() failed to validate response code for %s", tc.Accept)
}
bodyBytes, err := ioutil.ReadAll(response.Body)
if err != nil {
t.Errorf("TestResponse() failed to parse response body for %s", tc.Accept)
}
bodyString := string(bodyBytes)
if bodyString != tc.ExpectedResponse {
t.Errorf("TestResponse() failed to validate response body '%s' for %s", bodyString, tc.Accept)
}
}

View File

@ -2,13 +2,12 @@ package web
import ( import (
"encoding/json" "encoding/json"
"mime"
"net/http"
"path/filepath"
"github.com/beego/beego/v2/core/logs" "github.com/beego/beego/v2/core/logs"
"github.com/beego/beego/v2/server/web/context" "github.com/beego/beego/v2/server/web/context"
"github.com/beego/beego/v2/server/web/session" "github.com/beego/beego/v2/server/web/session"
"mime"
"net/http"
"path/filepath"
) )
// register MIME type with content type // register MIME type with content type
@ -95,4 +94,4 @@ func registerGzip() error {
) )
} }
return nil return nil
} }

View File

@ -69,20 +69,8 @@ var (
"UNLOCK": true, "UNLOCK": true,
} }
// these web.Controller's methods shouldn't reflect to AutoRouter // these web.Controller's methods shouldn't reflect to AutoRouter
exceptMethod = []string{"Abort", "CheckXSRFCookie", "CustomAbort", "DelSession", // see registerControllerExceptMethods
"DestroySession", "Finish", "GetBool", "GetControllerAndAction", exceptMethod = initExceptMethod()
"GetFile", "GetFiles", "GetFloat", "GetInt", "GetInt16",
"GetInt32", "GetInt64", "GetInt8", "GetSecureCookie", "GetSession",
"GetString", "GetStrings", "GetUint16", "GetUint32", "GetUint64",
"GetUint8", "HandlerFunc", "Init", "Input",
"IsAjax", "Mapping", "ParseForm",
"Prepare", "Redirect", "Render", "RenderBytes",
"RenderString", "SaveToFile", "SaveToFileWithBuffer", "SaveToFileWithBuffer",
"ServeFormatted", "ServeJSON", "ServeJSONP", "ServeXML", "ServeYAML",
"SessionRegenerateID", "SetData", "SetSecureCookie", "SetSession", "StartSession",
"StopRun", "URLFor", "URLMapping", "XSRFFormHTML",
"XSRFToken",
}
urlPlaceholder = "{{placeholder}}" urlPlaceholder = "{{placeholder}}"
// DefaultAccessLogFilter will skip the accesslog if return true // DefaultAccessLogFilter will skip the accesslog if return true
@ -116,6 +104,17 @@ func ExceptMethodAppend(action string) {
exceptMethod = append(exceptMethod, action) exceptMethod = append(exceptMethod, action)
} }
func initExceptMethod() []string {
res := make([]string, 0, 32)
c := &Controller{}
t := reflect.TypeOf(c)
for i := 0; i < t.NumMethod(); i++ {
m := t.Method(i)
res = append(res, m.Name)
}
return res
}
// ControllerInfo holds information about the controller. // ControllerInfo holds information about the controller.
type ControllerInfo struct { type ControllerInfo struct {
pattern string pattern string

View File

@ -137,10 +137,12 @@ func TestUrlFor(t *testing.T) {
func TestUrlFor3(t *testing.T) { func TestUrlFor3(t *testing.T) {
handler := NewControllerRegister() handler := NewControllerRegister()
handler.AddAuto(&TestController{}) handler.AddAuto(&TestController{})
if a := handler.URLFor("TestController.Myext"); a != "/test/myext" && a != "/Test/Myext" { a := handler.URLFor("TestController.Myext")
if a != "/test/myext" && a != "/Test/Myext" {
t.Errorf("TestController.Myext must equal to /test/myext, but get " + a) t.Errorf("TestController.Myext must equal to /test/myext, but get " + a)
} }
if a := handler.URLFor("TestController.GetURL"); a != "/test/geturl" && a != "/Test/GetURL" { a = handler.URLFor("TestController.GetURL")
if a != "/test/geturl" && a != "/Test/GetURL" {
t.Errorf("TestController.GetURL must equal to /test/geturl, but get " + a) t.Errorf("TestController.GetURL must equal to /test/geturl, but get " + a)
} }
} }