Merge branch 'develop' into session-filter

This commit is contained in:
Anker Jam 2021-01-03 22:14:56 +08:00
commit 7366b48a43
23 changed files with 482 additions and 176 deletions

View File

@ -74,7 +74,7 @@ func oldMiddlewareToNew(mws []MiddleWare) []web.MiddleWare {
// beego.Router("/api/update",&RestController{},"put:UpdateFood")
// beego.Router("/api/delete",&RestController{},"delete:DeleteFood")
func Router(rootpath string, c ControllerInterface, mappingMethods ...string) *App {
return (*App)(web.Router(rootpath, c, mappingMethods...))
return (*App)(web.Router(rootpath, c, web.SetRouterMethods(c, mappingMethods...)))
}
// UnregisterFixedRoute unregisters the route with the specified fixedRoute. It is particularly useful

View File

@ -87,7 +87,7 @@ func NewControllerRegister() *ControllerRegister {
// Add("/api",&RestController{},"get,post:ApiFunc"
// Add("/simple",&SimpleController{},"get:GetFunc;post:PostFunc")
func (p *ControllerRegister) Add(pattern string, c ControllerInterface, mappingMethods ...string) {
(*web.ControllerRegister)(p).Add(pattern, c, mappingMethods...)
(*web.ControllerRegister)(p).Add(pattern, c, web.SetRouterMethods(c, mappingMethods...))
}
// Include only when the Runmode is dev will generate router file in the router/auto.go from the controller

View File

@ -0,0 +1,36 @@
// Copyright 2020 beego
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package httplib
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestNewHttpResponseWithJsonBody(t *testing.T) {
// string
resp := NewHttpResponseWithJsonBody("{}")
assert.Equal(t, int64(2), resp.ContentLength)
resp = NewHttpResponseWithJsonBody([]byte("{}"))
assert.Equal(t, int64(2), resp.ContentLength)
resp = NewHttpResponseWithJsonBody(&user{
Name: "Tom",
})
assert.True(t, resp.ContentLength > 0)
}

View File

@ -44,49 +44,22 @@ import (
"mime/multipart"
"net"
"net/http"
"net/http/cookiejar"
"net/http/httputil"
"net/url"
"os"
"path"
"strings"
"sync"
"time"
"gopkg.in/yaml.v2"
)
var defaultSetting = BeegoHTTPSettings{
UserAgent: "beegoServer",
ConnectTimeout: 60 * time.Second,
ReadWriteTimeout: 60 * time.Second,
Gzip: true,
DumpBody: true,
FilterChains: []FilterChain{mockFilter.FilterChain},
}
var defaultCookieJar http.CookieJar
var settingMutex sync.Mutex
// it will be the last filter and execute request.Do
var doRequestFilter = func(ctx context.Context, req *BeegoHTTPRequest) (*http.Response, error) {
return req.doRequest(ctx)
}
// createDefaultCookie creates a global cookiejar to store cookies.
func createDefaultCookie() {
settingMutex.Lock()
defer settingMutex.Unlock()
defaultCookieJar, _ = cookiejar.New(nil)
}
// SetDefaultSetting overwrites default settings
func SetDefaultSetting(setting BeegoHTTPSettings) {
settingMutex.Lock()
defer settingMutex.Unlock()
defaultSetting = setting
}
// NewBeegoRequest returns *BeegoHttpRequest with specific method
func NewBeegoRequest(rawurl, method string) *BeegoHTTPRequest {
var resp http.Response
@ -137,23 +110,7 @@ func Head(url string) *BeegoHTTPRequest {
return NewBeegoRequest(url, "HEAD")
}
// BeegoHTTPSettings is the http.Client setting
type BeegoHTTPSettings struct {
ShowDebug bool
UserAgent string
ConnectTimeout time.Duration
ReadWriteTimeout time.Duration
TLSClientConfig *tls.Config
Proxy func(*http.Request) (*url.URL, error)
Transport http.RoundTripper
CheckRedirect func(req *http.Request, via []*http.Request) error
EnableCookie bool
Gzip bool
DumpBody bool
Retries int // if set to -1 means will retry forever
RetryDelay time.Duration
FilterChains []FilterChain
}
// BeegoHTTPRequest provides more useful methods than http.Request for requesting a url.
type BeegoHTTPRequest struct {
@ -362,6 +319,9 @@ func (b *BeegoHTTPRequest) XMLBody(obj interface{}) (*BeegoHTTPRequest, error) {
return b, err
}
b.req.Body = ioutil.NopCloser(bytes.NewReader(byts))
b.req.GetBody = func() (io.ReadCloser, error) {
return ioutil.NopCloser(bytes.NewReader(byts)), nil
}
b.req.ContentLength = int64(len(byts))
b.req.Header.Set("Content-Type", "application/xml")
}

View File

@ -300,3 +300,81 @@ func TestAddFilter(t *testing.T) {
r := Get("http://beego.me")
assert.Equal(t, 1, len(req.setting.FilterChains)-len(r.setting.FilterChains))
}
func TestHead(t *testing.T) {
req := Head("http://beego.me")
assert.NotNil(t, req)
assert.Equal(t, "HEAD", req.req.Method)
}
func TestDelete(t *testing.T) {
req := Delete("http://beego.me")
assert.NotNil(t, req)
assert.Equal(t, "DELETE", req.req.Method)
}
func TestPost(t *testing.T) {
req := Post("http://beego.me")
assert.NotNil(t, req)
assert.Equal(t, "POST", req.req.Method)
}
func TestNewBeegoRequest(t *testing.T) {
req := NewBeegoRequest("http://beego.me", "GET")
assert.NotNil(t, req)
assert.Equal(t, "GET", req.req.Method)
}
func TestPut(t *testing.T) {
req := Put("http://beego.me")
assert.NotNil(t, req)
assert.Equal(t, "PUT", req.req.Method)
}
func TestBeegoHTTPRequest_Header(t *testing.T) {
req := Post("http://beego.me")
key, value := "test-header", "test-header-value"
req.Header(key, value)
assert.Equal(t, value, req.req.Header.Get(key))
}
func TestBeegoHTTPRequest_SetHost(t *testing.T) {
req := Post("http://beego.me")
host := "test-hose"
req.SetHost(host)
assert.Equal(t, host, req.req.Host)
}
func TestBeegoHTTPRequest_Param(t *testing.T) {
req := Post("http://beego.me")
key, value := "test-param", "test-param-value"
req.Param(key, value)
assert.Equal(t, value, req.params[key][0])
value1 := "test-param-value-1"
req.Param(key, value1)
assert.Equal(t, value1, req.params[key][1])
}
func TestBeegoHTTPRequest_Body(t *testing.T) {
req := Post("http://beego.me")
body := `hello, world`
req.Body([]byte(body))
assert.Equal(t, int64(len(body)), req.req.ContentLength)
assert.NotNil(t, req.req.GetBody)
}
type user struct {
Name string `xml:"name"`
}
func TestBeegoHTTPRequest_XMLBody(t *testing.T) {
req := Post("http://beego.me")
body := &user{
Name: "Tom",
}
_, err := req.XMLBody(body)
assert.True(t, req.req.ContentLength > 0)
assert.Nil(t, err)
assert.NotNil(t, req.req.GetBody)
}

View File

@ -12,17 +12,22 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package httplib
package mock
import (
"context"
"net/http"
"github.com/beego/beego/v2/client/httplib"
"github.com/beego/beego/v2/core/logs"
)
const mockCtxKey = "beego-httplib-mock"
func init() {
InitMockSetting()
}
type Stub interface {
Mock(cond RequestCondition, resp *http.Response, err error)
Clear()
@ -31,6 +36,10 @@ type Stub interface {
var mockFilter = &MockResponseFilter{}
func InitMockSetting() {
httplib.AddDefaultFilter(mockFilter.FilterChain)
}
func StartMock() Stub {
return mockFilter
}

View File

@ -12,17 +12,19 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package httplib
package mock
import (
"context"
"encoding/json"
"net/textproto"
"regexp"
"github.com/beego/beego/v2/client/httplib"
)
type RequestCondition interface {
Match(ctx context.Context, req *BeegoHTTPRequest) bool
Match(ctx context.Context, req *httplib.BeegoHTTPRequest) bool
}
// reqCondition create condition
@ -54,7 +56,7 @@ func NewSimpleCondition(path string, opts ...simpleConditionOption) *SimpleCondi
return sc
}
func (sc *SimpleCondition) Match(ctx context.Context, req *BeegoHTTPRequest) bool {
func (sc *SimpleCondition) Match(ctx context.Context, req *httplib.BeegoHTTPRequest) bool {
res := true
if len(sc.path) > 0 {
res = sc.matchPath(ctx, req)
@ -70,12 +72,12 @@ func (sc *SimpleCondition) Match(ctx context.Context, req *BeegoHTTPRequest) boo
sc.matchBodyFields(ctx, req)
}
func (sc *SimpleCondition) matchPath(ctx context.Context, req *BeegoHTTPRequest) bool {
func (sc *SimpleCondition) matchPath(ctx context.Context, req *httplib.BeegoHTTPRequest) bool {
path := req.GetRequest().URL.Path
return path == sc.path
}
func (sc *SimpleCondition) matchPathReg(ctx context.Context, req *BeegoHTTPRequest) bool {
func (sc *SimpleCondition) matchPathReg(ctx context.Context, req *httplib.BeegoHTTPRequest) bool {
path := req.GetRequest().URL.Path
if b, err := regexp.Match(sc.pathReg, []byte(path)); err == nil {
return b
@ -83,7 +85,7 @@ func (sc *SimpleCondition) matchPathReg(ctx context.Context, req *BeegoHTTPReque
return false
}
func (sc *SimpleCondition) matchQuery(ctx context.Context, req *BeegoHTTPRequest) bool {
func (sc *SimpleCondition) matchQuery(ctx context.Context, req *httplib.BeegoHTTPRequest) bool {
qs := req.GetRequest().URL.Query()
for k, v := range sc.query {
if uv, ok := qs[k]; !ok || uv[0] != v {
@ -93,7 +95,7 @@ func (sc *SimpleCondition) matchQuery(ctx context.Context, req *BeegoHTTPRequest
return true
}
func (sc *SimpleCondition) matchHeader(ctx context.Context, req *BeegoHTTPRequest) bool {
func (sc *SimpleCondition) matchHeader(ctx context.Context, req *httplib.BeegoHTTPRequest) bool {
headers := req.GetRequest().Header
for k, v := range sc.header {
if uv, ok := headers[k]; !ok || uv[0] != v {
@ -103,7 +105,7 @@ func (sc *SimpleCondition) matchHeader(ctx context.Context, req *BeegoHTTPReques
return true
}
func (sc *SimpleCondition) matchBodyFields(ctx context.Context, req *BeegoHTTPRequest) bool {
func (sc *SimpleCondition) matchBodyFields(ctx context.Context, req *httplib.BeegoHTTPRequest) bool {
if len(sc.body) == 0 {
return true
}
@ -135,7 +137,7 @@ func (sc *SimpleCondition) matchBodyFields(ctx context.Context, req *BeegoHTTPRe
return true
}
func (sc *SimpleCondition) matchMethod(ctx context.Context, req *BeegoHTTPRequest) bool {
func (sc *SimpleCondition) matchMethod(ctx context.Context, req *httplib.BeegoHTTPRequest) bool {
if len(sc.method) > 0 {
return sc.method == req.GetRequest().Method
}

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package httplib
package mock
import (
"context"
@ -20,6 +20,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/beego/beego/v2/client/httplib"
)
func init() {
@ -28,37 +29,37 @@ func init() {
func TestSimpleCondition_MatchPath(t *testing.T) {
sc := NewSimpleCondition("/abc/s")
res := sc.Match(context.Background(), Get("http://localhost:8080/abc/s"))
res := sc.Match(context.Background(), httplib.Get("http://localhost:8080/abc/s"))
assert.True(t, res)
}
func TestSimpleCondition_MatchQuery(t *testing.T) {
k, v := "my-key", "my-value"
sc := NewSimpleCondition("/abc/s")
res := sc.Match(context.Background(), Get("http://localhost:8080/abc/s?my-key=my-value"))
res := sc.Match(context.Background(), httplib.Get("http://localhost:8080/abc/s?my-key=my-value"))
assert.True(t, res)
sc = NewSimpleCondition("/abc/s", WithQuery(k, v))
res = sc.Match(context.Background(), Get("http://localhost:8080/abc/s?my-key=my-value"))
res = sc.Match(context.Background(), httplib.Get("http://localhost:8080/abc/s?my-key=my-value"))
assert.True(t, res)
res = sc.Match(context.Background(), Get("http://localhost:8080/abc/s?my-key=my-valuesss"))
res = sc.Match(context.Background(), httplib.Get("http://localhost:8080/abc/s?my-key=my-valuesss"))
assert.False(t, res)
res = sc.Match(context.Background(), Get("http://localhost:8080/abc/s?my-key-a=my-value"))
res = sc.Match(context.Background(), httplib.Get("http://localhost:8080/abc/s?my-key-a=my-value"))
assert.False(t, res)
res = sc.Match(context.Background(), Get("http://localhost:8080/abc/s?my-key=my-value&abc=hello"))
res = sc.Match(context.Background(), httplib.Get("http://localhost:8080/abc/s?my-key=my-value&abc=hello"))
assert.True(t, res)
}
func TestSimpleCondition_MatchHeader(t *testing.T) {
k, v := "my-header", "my-header-value"
sc := NewSimpleCondition("/abc/s")
req := Get("http://localhost:8080/abc/s")
req := httplib.Get("http://localhost:8080/abc/s")
assert.True(t, sc.Match(context.Background(), req))
req = Get("http://localhost:8080/abc/s")
req = httplib.Get("http://localhost:8080/abc/s")
req.Header(k, v)
assert.True(t, sc.Match(context.Background(), req))
@ -73,7 +74,7 @@ func TestSimpleCondition_MatchHeader(t *testing.T) {
func TestSimpleCondition_MatchBodyField(t *testing.T) {
sc := NewSimpleCondition("/abc/s")
req := Post("http://localhost:8080/abc/s")
req := httplib.Post("http://localhost:8080/abc/s")
assert.True(t, sc.Match(context.Background(), req))
@ -102,7 +103,7 @@ func TestSimpleCondition_MatchBodyField(t *testing.T) {
func TestSimpleCondition_Match(t *testing.T) {
sc := NewSimpleCondition("/abc/s")
req := Post("http://localhost:8080/abc/s")
req := httplib.Post("http://localhost:8080/abc/s")
assert.True(t, sc.Match(context.Background(), req))
@ -115,9 +116,9 @@ func TestSimpleCondition_Match(t *testing.T) {
func TestSimpleCondition_MatchPathReg(t *testing.T) {
sc := NewSimpleCondition("", WithPathReg(`\/abc\/.*`))
req := Post("http://localhost:8080/abc/s")
req := httplib.Post("http://localhost:8080/abc/s")
assert.True(t, sc.Match(context.Background(), req))
req = Post("http://localhost:8080/abcd/s")
req = httplib.Post("http://localhost:8080/abcd/s")
assert.False(t, sc.Match(context.Background(), req))
}

View File

@ -12,12 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package httplib
package mock
import (
"context"
"fmt"
"net/http"
"github.com/beego/beego/v2/client/httplib"
)
// MockResponse will return mock response if find any suitable mock data
@ -32,13 +33,10 @@ func NewMockResponseFilter() *MockResponseFilter {
}
}
func (m *MockResponseFilter) FilterChain(next Filter) Filter {
return func(ctx context.Context, req *BeegoHTTPRequest) (*http.Response, error) {
func (m *MockResponseFilter) FilterChain(next httplib.Filter) httplib.Filter {
return func(ctx context.Context, req *httplib.BeegoHTTPRequest) (*http.Response, error) {
ms := mockFromCtx(ctx)
ms = append(ms, m.ms...)
fmt.Printf("url: %s, mock: %d \n", req.url, len(ms))
for _, mock := range ms {
if mock.cond.Match(ctx, req) {
return mock.resp, mock.err

View File

@ -12,20 +12,22 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package httplib
package mock
import (
"errors"
"testing"
"github.com/stretchr/testify/assert"
"github.com/beego/beego/v2/client/httplib"
)
func TestMockResponseFilter_FilterChain(t *testing.T) {
req := Get("http://localhost:8080/abc/s")
req := httplib.Get("http://localhost:8080/abc/s")
ft := NewMockResponseFilter()
expectedResp := NewHttpResponseWithJsonBody(`{}`)
expectedResp := httplib.NewHttpResponseWithJsonBody(`{}`)
expectedErr := errors.New("expected error")
ft.Mock(NewSimpleCondition("/abc/s"), expectedResp, expectedErr)
@ -35,16 +37,16 @@ func TestMockResponseFilter_FilterChain(t *testing.T) {
assert.Equal(t, expectedErr, err)
assert.Equal(t, expectedResp, resp)
req = Get("http://localhost:8080/abcd/s")
req = httplib.Get("http://localhost:8080/abcd/s")
req.AddFilters(ft.FilterChain)
resp, err = req.DoRequest()
assert.NotEqual(t, expectedErr, err)
assert.NotEqual(t, expectedResp, resp)
req = Get("http://localhost:8080/abc/s")
req = httplib.Get("http://localhost:8080/abc/s")
req.AddFilters(ft.FilterChain)
expectedResp1 := NewHttpResponseWithJsonBody(map[string]string{})
expectedResp1 := httplib.NewHttpResponseWithJsonBody(map[string]string{})
expectedErr1 := errors.New("expected error")
ft.Mock(NewSimpleCondition("/abc/abs/bbc"), expectedResp1, expectedErr1)
@ -52,7 +54,7 @@ func TestMockResponseFilter_FilterChain(t *testing.T) {
assert.Equal(t, expectedErr, err)
assert.Equal(t, expectedResp, resp)
req = Get("http://localhost:8080/abc/abs/bbc")
req = httplib.Get("http://localhost:8080/abc/abs/bbc")
req.AddFilters(ft.FilterChain)
ft.Mock(NewSimpleCondition("/abc/abs/bbc"), expectedResp1, expectedErr1)
resp, err = req.DoRequest()

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package httplib
package mock
import (
"context"
@ -21,16 +21,18 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/beego/beego/v2/client/httplib"
)
func TestStartMock(t *testing.T) {
defaultSetting.FilterChains = []FilterChain{mockFilter.FilterChain}
// httplib.defaultSetting.FilterChains = []httplib.FilterChain{mockFilter.FilterChain}
stub := StartMock()
// defer stub.Clear()
expectedResp := NewHttpResponseWithJsonBody([]byte(`{}`))
expectedResp := httplib.NewHttpResponseWithJsonBody([]byte(`{}`))
expectedErr := errors.New("expected err")
stub.Mock(NewSimpleCondition("/abc"), expectedResp, expectedErr)
@ -45,14 +47,14 @@ func TestStartMock(t *testing.T) {
// TestStartMock_Isolation Test StartMock that
// mock only work for this request
func TestStartMock_Isolation(t *testing.T) {
defaultSetting.FilterChains = []FilterChain{mockFilter.FilterChain}
// httplib.defaultSetting.FilterChains = []httplib.FilterChain{mockFilter.FilterChain}
// setup global stub
stub := StartMock()
globalMockResp := NewHttpResponseWithJsonBody([]byte(`{}`))
globalMockResp := httplib.NewHttpResponseWithJsonBody([]byte(`{}`))
globalMockErr := errors.New("expected err")
stub.Mock(NewSimpleCondition("/abc"), globalMockResp, globalMockErr)
expectedResp := NewHttpResponseWithJsonBody(struct {
expectedResp := httplib.NewHttpResponseWithJsonBody(struct {
A string `json:"a"`
}{
A: "aaa",
@ -67,9 +69,9 @@ func TestStartMock_Isolation(t *testing.T) {
}
func OriginnalCodeUsingHttplibPassCtx(ctx context.Context) (*http.Response, error) {
return Get("http://localhost:7777/abc").DoRequestWithCtx(ctx)
return httplib.Get("http://localhost:7777/abc").DoRequestWithCtx(ctx)
}
func OriginalCodeUsingHttplib() (*http.Response, error){
return Get("http://localhost:7777/abc").DoRequest()
return httplib.Get("http://localhost:7777/abc").DoRequest()
}

81
client/httplib/setting.go Normal file
View File

@ -0,0 +1,81 @@
// Copyright 2020 beego
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package httplib
import (
"crypto/tls"
"net/http"
"net/http/cookiejar"
"net/url"
"sync"
"time"
)
// BeegoHTTPSettings is the http.Client setting
type BeegoHTTPSettings struct {
ShowDebug bool
UserAgent string
ConnectTimeout time.Duration
ReadWriteTimeout time.Duration
TLSClientConfig *tls.Config
Proxy func(*http.Request) (*url.URL, error)
Transport http.RoundTripper
CheckRedirect func(req *http.Request, via []*http.Request) error
EnableCookie bool
Gzip bool
DumpBody bool
Retries int // if set to -1 means will retry forever
RetryDelay time.Duration
FilterChains []FilterChain
}
// createDefaultCookie creates a global cookiejar to store cookies.
func createDefaultCookie() {
settingMutex.Lock()
defer settingMutex.Unlock()
defaultCookieJar, _ = cookiejar.New(nil)
}
// SetDefaultSetting overwrites default settings
// Keep in mind that when you invoke the SetDefaultSetting
// some methods invoked before SetDefaultSetting
func SetDefaultSetting(setting BeegoHTTPSettings) {
settingMutex.Lock()
defer settingMutex.Unlock()
defaultSetting = setting
}
var defaultSetting = BeegoHTTPSettings{
UserAgent: "beegoServer",
ConnectTimeout: 60 * time.Second,
ReadWriteTimeout: 60 * time.Second,
Gzip: true,
DumpBody: true,
FilterChains: make([]FilterChain, 0, 4),
}
var defaultCookieJar http.CookieJar
var settingMutex sync.Mutex
// AddDefaultFilter add a new filter into defaultSetting
// Be careful about using this method if you invoke SetDefaultSetting somewhere
func AddDefaultFilter(fc FilterChain) {
settingMutex.Lock()
defer settingMutex.Unlock()
if defaultSetting.FilterChains == nil {
defaultSetting.FilterChains = make([]FilterChain, 0, 4)
}
defaultSetting.FilterChains = append(defaultSetting.FilterChains, fc)
}

View File

@ -69,8 +69,8 @@ func (p *PatternLogFormatter) ToString(lm *LogMsg) string {
'm': lm.Msg,
'n': strconv.Itoa(lm.LineNumber),
'l': strconv.Itoa(lm.Level),
't': levelPrefix[lm.Level-1],
'T': levelNames[lm.Level-1],
't': levelPrefix[lm.Level],
'T': levelNames[lm.Level],
'F': lm.FilePath,
}
_, m['f'] = path.Split(lm.FilePath)

View File

@ -88,7 +88,7 @@ func TestPatternLogFormatter(t *testing.T) {
}
got := tes.ToString(lm)
want := lm.FilePath + ":" + strconv.Itoa(lm.LineNumber) + "|" +
when.Format(tes.WhenFormat) + levelPrefix[lm.Level-1] + ">> " + lm.Msg
when.Format(tes.WhenFormat) + levelPrefix[lm.Level] + ">> " + lm.Msg
if got != want {
t.Errorf("want %s, got %s", want, got)
}

View File

@ -112,13 +112,13 @@ func registerAdmin() error {
HttpServer: NewHttpServerWithCfg(BConfig),
}
// keep in mind that all data should be html escaped to avoid XSS attack
beeAdminApp.Router("/", c, "get:AdminIndex")
beeAdminApp.Router("/qps", c, "get:QpsIndex")
beeAdminApp.Router("/prof", c, "get:ProfIndex")
beeAdminApp.Router("/healthcheck", c, "get:Healthcheck")
beeAdminApp.Router("/task", c, "get:TaskStatus")
beeAdminApp.Router("/listconf", c, "get:ListConf")
beeAdminApp.Router("/metrics", c, "get:PrometheusMetrics")
beeAdminApp.Router("/", c, SetRouterMethods(c, "get:AdminIndex"))
beeAdminApp.Router("/qps", c, SetRouterMethods(c, "get:QpsIndex"))
beeAdminApp.Router("/prof", c, SetRouterMethods(c, "get:ProfIndex"))
beeAdminApp.Router("/healthcheck", c, SetRouterMethods(c, "get:Healthcheck"))
beeAdminApp.Router("/task", c, SetRouterMethods(c, "get:TaskStatus"))
beeAdminApp.Router("/listconf", c, SetRouterMethods(c, "get:ListConf"))
beeAdminApp.Router("/metrics", c, SetRouterMethods(c, "get:PrometheusMetrics"))
go beeAdminApp.Run()
}

View File

@ -40,7 +40,7 @@ func TestFlashHeader(t *testing.T) {
// setup the handler
handler := NewControllerRegister()
handler.Add("/", &TestFlashController{}, "get:TestWriteFlash")
handler.Add("/", &TestFlashController{}, SetRouterMethods(&TestFlashController{}, "get:TestWriteFlash"))
handler.ServeHTTP(w, r)
// get the Set-Cookie value

View File

@ -99,7 +99,7 @@ func (n *Namespace) Filter(action string, filter ...FilterFunc) *Namespace {
// Router same as beego.Rourer
// refer: https://godoc.org/github.com/beego/beego/v2#Router
func (n *Namespace) Router(rootpath string, c ControllerInterface, mappingMethods ...string) *Namespace {
n.handlers.Add(rootpath, c, mappingMethods...)
n.handlers.Add(rootpath, c, SetRouterMethods(c, mappingMethods...))
return n
}

View File

@ -118,12 +118,27 @@ type ControllerInfo struct {
routerType int
initialize func() ControllerInterface
methodParams []*param.MethodParam
sessionOn bool
}
type ControllerOptions func(*ControllerInfo)
func (c *ControllerInfo) GetPattern() string {
return c.pattern
}
func SetRouterMethods(ctrlInterface ControllerInterface, mappingMethod ...string) ControllerOptions {
return func(c *ControllerInfo) {
c.methods = parseMappingMethods(ctrlInterface, mappingMethod)
}
}
func SetRouterSessionOn(sessionOn bool) ControllerOptions {
return func(c *ControllerInfo) {
c.sessionOn = sessionOn
}
}
// ControllerRegister containers registered router rules, controller handlers and filters.
type ControllerRegister struct {
routers map[string]*Tree
@ -171,40 +186,67 @@ func NewControllerRegisterWithCfg(cfg *Config) *ControllerRegister {
// Add("/api/delete",&RestController{},"delete:DeleteFood")
// Add("/api",&RestController{},"get,post:ApiFunc"
// Add("/simple",&SimpleController{},"get:GetFunc;post:PostFunc")
func (p *ControllerRegister) Add(pattern string, c ControllerInterface, mappingMethods ...string) {
p.addWithMethodParams(pattern, c, nil, mappingMethods...)
func (p *ControllerRegister) Add(pattern string, c ControllerInterface, opts ...ControllerOptions) {
p.addWithMethodParams(pattern, c, nil, opts...)
}
func (p *ControllerRegister) addWithMethodParams(pattern string, c ControllerInterface, methodParams []*param.MethodParam, mappingMethods ...string) {
func parseMappingMethods(c ControllerInterface, mappingMethods []string) map[string]string {
reflectVal := reflect.ValueOf(c)
t := reflect.Indirect(reflectVal).Type()
methods := make(map[string]string)
if len(mappingMethods) > 0 {
semi := strings.Split(mappingMethods[0], ";")
for _, v := range semi {
colon := strings.Split(v, ":")
if len(colon) != 2 {
panic("method mapping format is invalid")
if len(mappingMethods) == 0 {
return methods
}
semi := strings.Split(mappingMethods[0], ";")
for _, v := range semi {
colon := strings.Split(v, ":")
if len(colon) != 2 {
panic("method mapping format is invalid")
}
comma := strings.Split(colon[0], ",")
for _, m := range comma {
if m != "*" && !HTTPMETHOD[strings.ToUpper(m)] {
panic(v + " is an invalid method mapping. Method doesn't exist " + m)
}
comma := strings.Split(colon[0], ",")
for _, m := range comma {
if m == "*" || HTTPMETHOD[strings.ToUpper(m)] {
if val := reflectVal.MethodByName(colon[1]); val.IsValid() {
methods[strings.ToUpper(m)] = colon[1]
} else {
panic("'" + colon[1] + "' method doesn't exist in the controller " + t.Name())
}
} else {
panic(v + " is an invalid method mapping. Method doesn't exist " + m)
}
if val := reflectVal.MethodByName(colon[1]); val.IsValid() {
methods[strings.ToUpper(m)] = colon[1]
continue
}
panic("'" + colon[1] + "' method doesn't exist in the controller " + t.Name())
}
}
return methods
}
func (p *ControllerRegister) addRouterForMethod(route *ControllerInfo) {
if len(route.methods) == 0 {
for m := range HTTPMETHOD {
p.addToRouter(m, route.pattern, route)
}
return
}
for k := range route.methods {
if k != "*" {
p.addToRouter(k, route.pattern, route)
continue
}
for m := range HTTPMETHOD {
p.addToRouter(m, route.pattern, route)
}
}
}
func (p *ControllerRegister) addWithMethodParams(pattern string, c ControllerInterface, methodParams []*param.MethodParam, opts ...ControllerOptions) {
reflectVal := reflect.ValueOf(c)
t := reflect.Indirect(reflectVal).Type()
route := &ControllerInfo{}
route.pattern = pattern
route.methods = methods
route.routerType = routerTypeBeego
route.sessionOn = p.cfg.WebConfig.Session.SessionOn
route.controllerType = t
route.initialize = func() ControllerInterface {
vc := reflect.New(route.controllerType)
@ -229,23 +271,18 @@ func (p *ControllerRegister) addWithMethodParams(pattern string, c ControllerInt
return execController
}
route.methodParams = methodParams
if len(methods) == 0 {
for m := range HTTPMETHOD {
p.addToRouter(m, pattern, route)
}
} else {
for k := range methods {
if k == "*" {
for m := range HTTPMETHOD {
p.addToRouter(m, pattern, route)
}
} else {
p.addToRouter(k, pattern, route)
}
}
for i := range opts {
opts[i](route)
}
globalSessionOn := p.cfg.WebConfig.Session.SessionOn
if !globalSessionOn && route.sessionOn {
logs.Warn("global sessionOn is false, sessionOn of router [%s] can't be set to true", route.pattern)
route.sessionOn = globalSessionOn
}
p.addRouterForMethod(route)
}
func (p *ControllerRegister) addToRouter(method, pattern string, r *ControllerInfo) {
@ -273,7 +310,8 @@ func (p *ControllerRegister) Include(cList ...ControllerInterface) {
for _, f := range a.Filters {
p.InsertFilter(f.Pattern, f.Pos, f.Filter, WithReturnOnOutput(f.ReturnOnOutput), WithResetParams(f.ResetParams))
}
p.addWithMethodParams(a.Router, c, a.MethodParams, strings.Join(a.AllowHTTPMethods, ",")+":"+a.Method)
p.addWithMethodParams(a.Router, c, a.MethodParams, SetRouterMethods(c, strings.Join(a.AllowHTTPMethods, ",")+":"+a.Method))
}
}
}
@ -379,6 +417,7 @@ func (p *ControllerRegister) AddMethod(method, pattern string, f FilterFunc) {
route := &ControllerInfo{}
route.pattern = pattern
route.routerType = routerTypeRESTFul
route.sessionOn = p.cfg.WebConfig.Session.SessionOn
route.runFunction = f
methods := make(map[string]string)
if method == "*" {
@ -399,6 +438,7 @@ func (p *ControllerRegister) Handler(pattern string, h http.Handler, options ...
route := &ControllerInfo{}
route.pattern = pattern
route.routerType = routerTypeHandler
route.sessionOn = p.cfg.WebConfig.Session.SessionOn
route.handler = h
if len(options) > 0 {
if _, ok := options[0].(bool); ok {
@ -433,6 +473,7 @@ func (p *ControllerRegister) AddAutoPrefix(prefix string, c ControllerInterface)
if !utils.InSlice(rt.Method(i).Name, exceptMethod) {
route := &ControllerInfo{}
route.routerType = routerTypeBeego
route.sessionOn = p.cfg.WebConfig.Session.SessionOn
route.methods = map[string]string{"*": rt.Method(i).Name}
route.controllerType = ct
pattern := path.Join(prefix, strings.ToLower(controllerName), strings.ToLower(rt.Method(i).Name), "*")
@ -542,7 +583,7 @@ func (p *ControllerRegister) getURL(t *Tree, url, controllerName, methodName str
for _, l := range t.leaves {
if c, ok := l.runObject.(*ControllerInfo); ok {
if c.routerType == routerTypeBeego &&
strings.HasSuffix(path.Join(c.controllerType.PkgPath(), c.controllerType.Name()), controllerName) {
strings.HasSuffix(path.Join(c.controllerType.PkgPath(), c.controllerType.Name()), `/`+controllerName) {
find := false
if HTTPMETHOD[strings.ToUpper(methodName)] {
if len(c.methods) == 0 {
@ -664,12 +705,15 @@ func (p *ControllerRegister) serveHttp(ctx *beecontext.Context) {
r := ctx.Request
rw := ctx.ResponseWriter.ResponseWriter
var (
runRouter reflect.Type
findRouter bool
runMethod string
methodParams []*param.MethodParam
routerInfo *ControllerInfo
isRunnable bool
runRouter reflect.Type
findRouter bool
runMethod string
methodParams []*param.MethodParam
routerInfo *ControllerInfo
isRunnable bool
currentSessionOn bool
originRouterInfo *ControllerInfo
originFindRouter bool
)
if p.cfg.RecoverFunc != nil {
@ -735,7 +779,12 @@ func (p *ControllerRegister) serveHttp(ctx *beecontext.Context) {
}
// session init
if p.cfg.WebConfig.Session.SessionOn {
currentSessionOn = p.cfg.WebConfig.Session.SessionOn
originRouterInfo, originFindRouter = p.FindRouter(ctx)
if originFindRouter {
currentSessionOn = originRouterInfo.sessionOn
}
if currentSessionOn {
ctx.Input.CruSession, err = GlobalSessions.SessionStart(rw, r)
if err != nil {
logs.Error(err)

View File

@ -26,6 +26,14 @@ import (
"github.com/beego/beego/v2/server/web/context"
)
type PrefixTestController struct {
Controller
}
func (ptc *PrefixTestController) PrefixList() {
ptc.Ctx.Output.Body([]byte("i am list in prefix test"))
}
type TestController struct {
Controller
}
@ -87,10 +95,24 @@ func (jc *JSONController) Get() {
jc.Ctx.Output.Body([]byte("ok"))
}
func TestPrefixUrlFor(t *testing.T){
handler := NewControllerRegister()
handler.Add("/my/prefix/list", &PrefixTestController{}, "get:PrefixList")
if a := handler.URLFor(`PrefixTestController.PrefixList`); a != `/my/prefix/list` {
logs.Info(a)
t.Errorf("PrefixTestController.PrefixList must equal to /my/prefix/list")
}
if a := handler.URLFor(`TestController.PrefixList`); a != `` {
logs.Info(a)
t.Errorf("TestController.PrefixList must equal to empty string")
}
}
func TestUrlFor(t *testing.T) {
handler := NewControllerRegister()
handler.Add("/api/list", &TestController{}, "*:List")
handler.Add("/person/:last/:first", &TestController{}, "*:Param")
handler.Add("/api/list", &TestController{}, SetRouterMethods(&TestController{}, "*:List"))
handler.Add("/person/:last/:first", &TestController{}, SetRouterMethods(&TestController{}, "*:Param"))
if a := handler.URLFor("TestController.List"); a != "/api/list" {
logs.Info(a)
t.Errorf("TestController.List must equal to /api/list")
@ -113,9 +135,9 @@ func TestUrlFor3(t *testing.T) {
func TestUrlFor2(t *testing.T) {
handler := NewControllerRegister()
handler.Add("/v1/:v/cms_:id(.+)_:page(.+).html", &TestController{}, "*:List")
handler.Add("/v1/:username/edit", &TestController{}, "get:GetURL")
handler.Add("/v1/:v(.+)_cms/ttt_:id(.+)_:page(.+).html", &TestController{}, "*:Param")
handler.Add("/v1/:v/cms_:id(.+)_:page(.+).html", &TestController{}, SetRouterMethods(&TestController{}, "*:List"))
handler.Add("/v1/:username/edit", &TestController{}, SetRouterMethods(&TestController{}, "get:GetURL"))
handler.Add("/v1/:v(.+)_cms/ttt_:id(.+)_:page(.+).html", &TestController{}, SetRouterMethods(&TestController{}, "*:Param"))
handler.Add("/:year:int/:month:int/:title/:entid", &TestController{})
if handler.URLFor("TestController.GetURL", ":username", "astaxie") != "/v1/astaxie/edit" {
logs.Info(handler.URLFor("TestController.GetURL"))
@ -145,7 +167,7 @@ func TestUserFunc(t *testing.T) {
w := httptest.NewRecorder()
handler := NewControllerRegister()
handler.Add("/api/list", &TestController{}, "*:List")
handler.Add("/api/list", &TestController{}, SetRouterMethods(&TestController{}, "*:List"))
handler.ServeHTTP(w, r)
if w.Body.String() != "i am list" {
t.Errorf("user define func can't run")
@ -235,7 +257,7 @@ func TestRouteOk(t *testing.T) {
w := httptest.NewRecorder()
handler := NewControllerRegister()
handler.Add("/person/:last/:first", &TestController{}, "get:GetParams")
handler.Add("/person/:last/:first", &TestController{}, SetRouterMethods(&TestController{}, "get:GetParams"))
handler.ServeHTTP(w, r)
body := w.Body.String()
if body != "anderson+thomas+kungfu" {
@ -249,7 +271,7 @@ func TestManyRoute(t *testing.T) {
w := httptest.NewRecorder()
handler := NewControllerRegister()
handler.Add("/beego:id([0-9]+)-:page([0-9]+).html", &TestController{}, "get:GetManyRouter")
handler.Add("/beego:id([0-9]+)-:page([0-9]+).html", &TestController{}, SetRouterMethods(&TestController{}, "get:GetManyRouter"))
handler.ServeHTTP(w, r)
body := w.Body.String()
@ -266,7 +288,7 @@ func TestEmptyResponse(t *testing.T) {
w := httptest.NewRecorder()
handler := NewControllerRegister()
handler.Add("/beego-empty.html", &TestController{}, "get:GetEmptyBody")
handler.Add("/beego-empty.html", &TestController{}, SetRouterMethods(&TestController{}, "get:GetEmptyBody"))
handler.ServeHTTP(w, r)
if body := w.Body.String(); body != "" {
@ -750,3 +772,59 @@ func TestRouterEntityTooLargeCopyBody(t *testing.T) {
t.Errorf("TestRouterRequestEntityTooLarge can't run")
}
}
func TestRouterSessionSet(t *testing.T) {
oldGlobalSessionOn := BConfig.WebConfig.Session.SessionOn
defer func() {
BConfig.WebConfig.Session.SessionOn = oldGlobalSessionOn
}()
// global sessionOn = false, router sessionOn = false
r, _ := http.NewRequest("GET", "/user", nil)
w := httptest.NewRecorder()
handler := NewControllerRegister()
handler.Add("/user", &TestController{}, SetRouterMethods(&TestController{}, "get:Get"),
SetRouterSessionOn(false))
handler.ServeHTTP(w, r)
if w.Header().Get("Set-Cookie") != "" {
t.Errorf("TestRotuerSessionSet failed")
}
// global sessionOn = false, router sessionOn = true
r, _ = http.NewRequest("GET", "/user", nil)
w = httptest.NewRecorder()
handler = NewControllerRegister()
handler.Add("/user", &TestController{}, SetRouterMethods(&TestController{}, "get:Get"),
SetRouterSessionOn(true))
handler.ServeHTTP(w, r)
if w.Header().Get("Set-Cookie") != "" {
t.Errorf("TestRotuerSessionSet failed")
}
BConfig.WebConfig.Session.SessionOn = true
if err := registerSession(); err != nil {
t.Errorf("register session failed, error: %s", err.Error())
}
// global sessionOn = true, router sessionOn = false
r, _ = http.NewRequest("GET", "/user", nil)
w = httptest.NewRecorder()
handler = NewControllerRegister()
handler.Add("/user", &TestController{}, SetRouterMethods(&TestController{}, "get:Get"),
SetRouterSessionOn(false))
handler.ServeHTTP(w, r)
if w.Header().Get("Set-Cookie") != "" {
t.Errorf("TestRotuerSessionSet failed")
}
// global sessionOn = true, router sessionOn = true
r, _ = http.NewRequest("GET", "/user", nil)
w = httptest.NewRecorder()
handler = NewControllerRegister()
handler.Add("/user", &TestController{}, SetRouterMethods(&TestController{}, "get:Get"),
SetRouterSessionOn(true))
handler.ServeHTTP(w, r)
if w.Header().Get("Set-Cookie") == "" {
t.Errorf("TestRotuerSessionSet failed")
}
}

View File

@ -266,8 +266,8 @@ func (app *HttpServer) Run(addr string, mws ...MiddleWare) {
}
// Router see HttpServer.Router
func Router(rootpath string, c ControllerInterface, mappingMethods ...string) *HttpServer {
return BeeApp.Router(rootpath, c, mappingMethods...)
func Router(rootpath string, c ControllerInterface, opts ...ControllerOptions) *HttpServer {
return BeeApp.Router(rootpath, c, opts...)
}
// Router adds a patterned controller handler to BeeApp.
@ -286,8 +286,8 @@ func Router(rootpath string, c ControllerInterface, mappingMethods ...string) *H
// beego.Router("/api/create",&RestController{},"post:CreateFood")
// beego.Router("/api/update",&RestController{},"put:UpdateFood")
// beego.Router("/api/delete",&RestController{},"delete:DeleteFood")
func (app *HttpServer) Router(rootPath string, c ControllerInterface, mappingMethods ...string) *HttpServer {
app.Handlers.Add(rootPath, c, mappingMethods...)
func (app *HttpServer) Router(rootPath string, c ControllerInterface, opts ...ControllerOptions) *HttpServer {
app.Handlers.Add(rootPath, c, opts...)
return app
}

View File

@ -210,9 +210,9 @@ func (t *Tree) AddRouter(pattern string, runObject interface{}) {
func (t *Tree) addseg(segments []string, route interface{}, wildcards []string, reg string) {
if len(segments) == 0 {
if reg != "" {
t.leaves = append(t.leaves, &leafInfo{runObject: route, wildcards: wildcards, regexps: regexp.MustCompile("^" + reg + "$")})
t.leaves = append([]*leafInfo{{runObject: route, wildcards: wildcards, regexps: regexp.MustCompile("^" + reg + "$")}}, t.leaves...)
} else {
t.leaves = append(t.leaves, &leafInfo{runObject: route, wildcards: wildcards})
t.leaves = append([]*leafInfo{{runObject: route, wildcards: wildcards}}, t.leaves...)
}
} else {
seg := segments[0]

View File

@ -90,7 +90,17 @@ func init() {
routers = append(routers, matchTestInfo("/v1/:v(.+)_cms/ttt_:id(.+)_:page(.+).html", "/v1/2_cms/ttt_123_1.html", map[string]string{":v": "2", ":id": "123", ":page": "1"}))
routers = append(routers, matchTestInfo("/api/projects/:pid/members/?:mid", "/api/projects/1/members", map[string]string{":pid": "1"}))
routers = append(routers, matchTestInfo("/api/projects/:pid/members/?:mid", "/api/projects/1/members/2", map[string]string{":pid": "1", ":mid": "2"}))
routers = append(routers, matchTestInfo("/?:year/?:month/?:day", "/2020/11/10", map[string]string{":year": "2020", ":month": "11", ":day": "10"}))
routers = append(routers, matchTestInfo("/?:year/?:month/?:day", "/2020/11", map[string]string{":year": "2020", ":month": "11"}))
routers = append(routers, matchTestInfo("/?:year", "/2020", map[string]string{":year": "2020"}))
routers = append(routers, matchTestInfo("/?:year([0-9]+)/?:month([0-9]+)/mid/?:day([0-9]+)/?:hour([0-9]+)", "/2020/11/mid/10/24", map[string]string{":year": "2020", ":month": "11", ":day": "10", ":hour": "24"}))
routers = append(routers, matchTestInfo("/?:year/?:month/mid/?:day/?:hour", "/2020/mid/10", map[string]string{":year": "2020", ":day": "10"}))
routers = append(routers, matchTestInfo("/?:year/?:month/mid/?:day/?:hour", "/2020/11/mid", map[string]string{":year": "2020", ":month": "11"}))
routers = append(routers, matchTestInfo("/?:year/?:month/mid/?:day/?:hour", "/mid/10/24", map[string]string{":day": "10", ":hour": "24"}))
routers = append(routers, matchTestInfo("/?:year([0-9]+)/:month([0-9]+)/mid/:day([0-9]+)/?:hour([0-9]+)", "/2020/11/mid/10/24", map[string]string{":year": "2020", ":month": "11", ":day": "10", ":hour": "24"}))
routers = append(routers, matchTestInfo("/?:year/:month/mid/:day/?:hour", "/11/mid/10/24", map[string]string{":month": "11", ":day": "10"}))
routers = append(routers, matchTestInfo("/?:year/:month/mid/:day/?:hour", "/2020/11/mid/10", map[string]string{":year": "2020", ":month": "11", ":day": "10"}))
routers = append(routers, matchTestInfo("/?:year/:month/mid/:day/?:hour", "/11/mid/10", map[string]string{":month": "11", ":day": "10"}))
// not match example
// https://github.com/beego/beego/v2/issues/3865

View File

@ -75,9 +75,9 @@ func TestUnregisterFixedRouteRoot(t *testing.T) {
var method = "GET"
handler := NewControllerRegister()
handler.Add("/", &TestPreUnregController{}, "get:GetFixedRoot")
handler.Add("/level1", &TestPreUnregController{}, "get:GetFixedLevel1")
handler.Add("/level1/level2", &TestPreUnregController{}, "get:GetFixedLevel2")
handler.Add("/", &TestPreUnregController{}, SetRouterMethods(&TestPreUnregController{}, "get:GetFixedRoot"))
handler.Add("/level1", &TestPreUnregController{}, SetRouterMethods(&TestPreUnregController{}, "get:GetFixedLevel1"))
handler.Add("/level1/level2", &TestPreUnregController{}, SetRouterMethods(&TestPreUnregController{}, "get:GetFixedLevel2"))
// Test original root
testHelperFnContentCheck(t, handler, "Test original root",
@ -96,7 +96,7 @@ func TestUnregisterFixedRouteRoot(t *testing.T) {
// Replace the root path TestPreUnregController action with the action from
// TestPostUnregController
handler.Add("/", &TestPostUnregController{}, "get:GetFixedRoot")
handler.Add("/", &TestPostUnregController{}, SetRouterMethods(&TestPostUnregController{}, "get:GetFixedRoot"))
// Test replacement root (expect change)
testHelperFnContentCheck(t, handler, "Test replacement root (expect change)", method, "/", contentRootReplacement)
@ -117,9 +117,9 @@ func TestUnregisterFixedRouteLevel1(t *testing.T) {
var method = "GET"
handler := NewControllerRegister()
handler.Add("/", &TestPreUnregController{}, "get:GetFixedRoot")
handler.Add("/level1", &TestPreUnregController{}, "get:GetFixedLevel1")
handler.Add("/level1/level2", &TestPreUnregController{}, "get:GetFixedLevel2")
handler.Add("/", &TestPreUnregController{}, SetRouterMethods(&TestPreUnregController{}, "get:GetFixedRoot"))
handler.Add("/level1", &TestPreUnregController{}, SetRouterMethods(&TestPreUnregController{}, "get:GetFixedLevel1"))
handler.Add("/level1/level2", &TestPreUnregController{}, SetRouterMethods(&TestPreUnregController{}, "get:GetFixedLevel2"))
// Test original root
testHelperFnContentCheck(t, handler,
@ -146,7 +146,7 @@ func TestUnregisterFixedRouteLevel1(t *testing.T) {
// Replace the "level1" path TestPreUnregController action with the action from
// TestPostUnregController
handler.Add("/level1", &TestPostUnregController{}, "get:GetFixedLevel1")
handler.Add("/level1", &TestPostUnregController{}, SetRouterMethods(&TestPostUnregController{}, "get:GetFixedLevel1"))
// Test replacement root (expect no change from the original)
testHelperFnContentCheck(t, handler, "Test replacement root (expect no change from the original)", method, "/", contentRootOriginal)
@ -167,9 +167,9 @@ func TestUnregisterFixedRouteLevel2(t *testing.T) {
var method = "GET"
handler := NewControllerRegister()
handler.Add("/", &TestPreUnregController{}, "get:GetFixedRoot")
handler.Add("/level1", &TestPreUnregController{}, "get:GetFixedLevel1")
handler.Add("/level1/level2", &TestPreUnregController{}, "get:GetFixedLevel2")
handler.Add("/", &TestPreUnregController{}, SetRouterMethods(&TestPreUnregController{}, "get:GetFixedRoot"))
handler.Add("/level1", &TestPreUnregController{}, SetRouterMethods(&TestPreUnregController{}, "get:GetFixedLevel1"))
handler.Add("/level1/level2", &TestPreUnregController{}, SetRouterMethods(&TestPreUnregController{}, "get:GetFixedLevel2"))
// Test original root
testHelperFnContentCheck(t, handler,
@ -196,7 +196,7 @@ func TestUnregisterFixedRouteLevel2(t *testing.T) {
// Replace the "/level1/level2" path TestPreUnregController action with the action from
// TestPostUnregController
handler.Add("/level1/level2", &TestPostUnregController{}, "get:GetFixedLevel2")
handler.Add("/level1/level2", &TestPostUnregController{}, SetRouterMethods(&TestPostUnregController{}, "get:GetFixedLevel2"))
// Test replacement root (expect no change from the original)
testHelperFnContentCheck(t, handler, "Test replacement root (expect no change from the original)", method, "/", contentRootOriginal)