From ad81d0ce7c278b9d8a16a2af19443e8368661d19 Mon Sep 17 00:00:00 2001 From: Ming Deng Date: Mon, 19 Apr 2021 23:37:05 +0800 Subject: [PATCH 1/8] init exceptMethod --- CHANGELOG.md | 1 + server/web/hooks.go | 9 ++++----- server/web/router.go | 27 +++++++++++++-------------- server/web/router_test.go | 6 ++++-- 4 files changed, 22 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8dbe15d0..fb51c215 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,7 @@ - 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) - 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 - [4473](https://github.com/beego/beego/pull/4473) diff --git a/server/web/hooks.go b/server/web/hooks.go index 0f72e711..6176586e 100644 --- a/server/web/hooks.go +++ b/server/web/hooks.go @@ -2,13 +2,12 @@ package web import ( "encoding/json" - "mime" - "net/http" - "path/filepath" - "github.com/beego/beego/v2/core/logs" "github.com/beego/beego/v2/server/web/context" "github.com/beego/beego/v2/server/web/session" + "mime" + "net/http" + "path/filepath" ) // register MIME type with content type @@ -95,4 +94,4 @@ func registerGzip() error { ) } return nil -} +} \ No newline at end of file diff --git a/server/web/router.go b/server/web/router.go index 7a578e4b..0f6db6de 100644 --- a/server/web/router.go +++ b/server/web/router.go @@ -69,20 +69,8 @@ var ( "UNLOCK": true, } // these web.Controller's methods shouldn't reflect to AutoRouter - exceptMethod = []string{"Abort", "CheckXSRFCookie", "CustomAbort", "DelSession", - "DestroySession", "Finish", "GetBool", "GetControllerAndAction", - "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", - } + // see registerControllerExceptMethods + exceptMethod = initExceptMethod() urlPlaceholder = "{{placeholder}}" // DefaultAccessLogFilter will skip the accesslog if return true @@ -116,6 +104,17 @@ func ExceptMethodAppend(action string) { 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. type ControllerInfo struct { pattern string diff --git a/server/web/router_test.go b/server/web/router_test.go index 3633aee7..e8b823d2 100644 --- a/server/web/router_test.go +++ b/server/web/router_test.go @@ -137,10 +137,12 @@ func TestUrlFor(t *testing.T) { func TestUrlFor3(t *testing.T) { handler := NewControllerRegister() 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) } - 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) } } From d9415524aa50e87f91890a2cfa644721bfb0774d Mon Sep 17 00:00:00 2001 From: Maneesh Babu M Date: Fri, 23 Apr 2021 02:53:53 +0000 Subject: [PATCH 2/8] Add Resp response format for controller --- server/web/controller.go | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/server/web/controller.go b/server/web/controller.go index 6a29c79e..2648a544 100644 --- a/server/web/controller.go +++ b/server/web/controller.go @@ -21,8 +21,6 @@ import ( "encoding/xml" "errors" "fmt" - "github.com/gogo/protobuf/proto" - "gopkg.in/yaml.v2" "html/template" "io" "mime/multipart" @@ -37,6 +35,8 @@ import ( "github.com/beego/beego/v2/server/web/context" "github.com/beego/beego/v2/server/web/context/param" "github.com/beego/beego/v2/server/web/session" + "github.com/gogo/protobuf/proto" + "gopkg.in/yaml.v2" ) var ( @@ -436,6 +436,22 @@ func (c *Controller) URLFor(endpoint string, values ...interface{}) string { } 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. func (c *Controller) ServeJSON(encoding ...bool) error { From 6158de13efb63c6d4380583dde1522139e026774 Mon Sep 17 00:00:00 2001 From: Maneesh Babu M Date: Fri, 23 Apr 2021 02:54:07 +0000 Subject: [PATCH 3/8] Add tests --- server/web/controller_test.go | 70 ++++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 2 deletions(-) diff --git a/server/web/controller_test.go b/server/web/controller_test.go index 8a52f097..ea7d2786 100644 --- a/server/web/controller_test.go +++ b/server/web/controller_test.go @@ -15,16 +15,18 @@ package web import ( - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" + "io/ioutil" "math" "net/http" + "net/http/httptest" "os" "path/filepath" "strconv" "testing" "github.com/beego/beego/v2/server/web/context" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestGetInt(t *testing.T) { @@ -244,3 +246,67 @@ func TestBindYAML(t *testing.T) { require.NoError(t, err) 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: 13, ExpectedResponse: `{"foo":"bar"}`}, + {Accept: context.ApplicationXML, ExpectedContentLength: 21, ExpectedResponse: `bar`}, + {Accept: context.ApplicationYAML, ExpectedContentLength: 9, ExpectedResponse: "foo: bar\n"}, + {Accept: "OTHER", ExpectedContentLength: 13, ExpectedResponse: `{"foo":"bar"}`}, + } + + 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 for %s", 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 for %s", tc.Accept) + } +} From 6d2bfb776c2d97af82c04e6a5fe699ca408c2188 Mon Sep 17 00:00:00 2001 From: Maneesh Babu M Date: Fri, 23 Apr 2021 02:56:19 +0000 Subject: [PATCH 4/8] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fb51c215..31eaaa0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ # developing +- 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) - 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) From 5e7f9465b26aa35057d9186f1dc8750414622791 Mon Sep 17 00:00:00 2001 From: Maneesh Babu M Date: Fri, 23 Apr 2021 03:16:12 +0000 Subject: [PATCH 5/8] Update test response --- server/web/controller_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/web/controller_test.go b/server/web/controller_test.go index ea7d2786..38123864 100644 --- a/server/web/controller_test.go +++ b/server/web/controller_test.go @@ -294,7 +294,7 @@ func testControllerRespTestCases(t *testing.T, tc respTestCase) { response := w.Result() if response.ContentLength != tc.ExpectedContentLength { - t.Errorf("TestResponse() unable to validate content length for %s", tc.Accept) + t.Errorf("TestResponse() unable to validate content length %d for %s", response.ContentLength, tc.Accept) } if response.StatusCode != http.StatusOK { @@ -307,6 +307,6 @@ func testControllerRespTestCases(t *testing.T, tc respTestCase) { } bodyString := string(bodyBytes) if bodyString != tc.ExpectedResponse { - t.Errorf("TestResponse() failed to validate response body for %s", tc.Accept) + t.Errorf("TestResponse() failed to validate response body '%s' for %s", bodyString, tc.Accept) } } From 3a58f9dc8a1e3791ac4a82510fe6a7020b3f1876 Mon Sep 17 00:00:00 2001 From: Maneesh Babu M Date: Fri, 23 Apr 2021 03:28:55 +0000 Subject: [PATCH 6/8] Update tests --- server/web/controller_test.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/server/web/controller_test.go b/server/web/controller_test.go index 38123864..6aab31ae 100644 --- a/server/web/controller_test.go +++ b/server/web/controller_test.go @@ -270,10 +270,16 @@ type respTestCase struct { func TestControllerResp(t *testing.T) { // test cases tcs := []respTestCase{ - {Accept: context.ApplicationJSON, ExpectedContentLength: 13, ExpectedResponse: `{"foo":"bar"}`}, - {Accept: context.ApplicationXML, ExpectedContentLength: 21, ExpectedResponse: `bar`}, + {Accept: context.ApplicationJSON, ExpectedContentLength: 18, ExpectedResponse: `{ + "foo": "bar" + }`}, + {Accept: context.ApplicationXML, ExpectedContentLength: 25, ExpectedResponse: ` + bar + `}, {Accept: context.ApplicationYAML, ExpectedContentLength: 9, ExpectedResponse: "foo: bar\n"}, - {Accept: "OTHER", ExpectedContentLength: 13, ExpectedResponse: `{"foo":"bar"}`}, + {Accept: "OTHER", ExpectedContentLength: 18, ExpectedResponse: `{ + "foo": "bar" + }`}, } for _, tc := range tcs { From b622125a76695d0fe8f87295cf6feba8f52a550b Mon Sep 17 00:00:00 2001 From: Maneesh Babu M Date: Fri, 23 Apr 2021 03:41:31 +0000 Subject: [PATCH 7/8] Update tests --- server/web/controller_test.go | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/server/web/controller_test.go b/server/web/controller_test.go index 6aab31ae..2377ddf3 100644 --- a/server/web/controller_test.go +++ b/server/web/controller_test.go @@ -270,16 +270,10 @@ type respTestCase struct { func TestControllerResp(t *testing.T) { // test cases tcs := []respTestCase{ - {Accept: context.ApplicationJSON, ExpectedContentLength: 18, ExpectedResponse: `{ - "foo": "bar" - }`}, - {Accept: context.ApplicationXML, ExpectedContentLength: 25, ExpectedResponse: ` - bar - `}, + {Accept: context.ApplicationJSON, ExpectedContentLength: 18, ExpectedResponse: "{\n \"foo\": \"bar\"\n}"}, + {Accept: context.ApplicationXML, ExpectedContentLength: 25, ExpectedResponse: "\n bar\n"}, {Accept: context.ApplicationYAML, ExpectedContentLength: 9, ExpectedResponse: "foo: bar\n"}, - {Accept: "OTHER", ExpectedContentLength: 18, ExpectedResponse: `{ - "foo": "bar" - }`}, + {Accept: "OTHER", ExpectedContentLength: 18, ExpectedResponse: "{\n \"foo\": \"bar\"\n}"}, } for _, tc := range tcs { From 378ba975248aecfb82e64996ee387d11d0562561 Mon Sep 17 00:00:00 2001 From: Maneesh Babu M Date: Sat, 24 Apr 2021 15:20:26 +0000 Subject: [PATCH 8/8] Fix golang ci lint error --- server/web/controller_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/web/controller_test.go b/server/web/controller_test.go index 2377ddf3..7f810c1f 100644 --- a/server/web/controller_test.go +++ b/server/web/controller_test.go @@ -258,7 +258,7 @@ func (t *TestRespController) TestResponse() { bar := S{Foo: "bar"} - t.Resp(bar) + _ = t.Resp(bar) } type respTestCase struct {