From 9bd3a27e803f122b57ded9a479a49a7ac8ba5dcb Mon Sep 17 00:00:00 2001 From: michuan Date: Tue, 25 Aug 2020 23:36:15 +0800 Subject: [PATCH 01/29] fix #3776 --- go.mod | 3 ++- go.sum | 11 ++--------- orm/models_test.go | 20 ++++++++++++++------ orm/orm_raw.go | 22 ++++++++++++++++++++-- orm/orm_test.go | 14 ++++++++++++++ 5 files changed, 52 insertions(+), 18 deletions(-) diff --git a/go.mod b/go.mod index ec500f51..6d4da958 100644 --- a/go.mod +++ b/go.mod @@ -22,6 +22,7 @@ require ( github.com/lib/pq v1.0.0 github.com/mattn/go-sqlite3 v2.0.3+incompatible github.com/pelletier/go-toml v1.2.0 // indirect + github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.7.0 github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec @@ -29,7 +30,7 @@ require ( github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c // indirect github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b // indirect golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 - golang.org/x/tools v0.0.0-20200117065230-39095c1d176c + golang.org/x/net v0.0.0-20190620200207-3b0461eec859 // indirect gopkg.in/yaml.v2 v2.2.8 ) diff --git a/go.sum b/go.sum index c7b861ac..55c926cf 100644 --- a/go.sum +++ b/go.sum @@ -53,7 +53,6 @@ github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8w github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-yaml/yaml v0.0.0-20180328195020-5420a8b6744d h1:xy93KVe+KrIIwWDEAfQBdIfsiHJkepbYsDr+VY3g9/o= github.com/go-yaml/yaml v0.0.0-20180328195020-5420a8b6744d/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -114,11 +113,10 @@ github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9 github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/peterh/liner v1.0.1-0.20171122030339-3681c2a91233/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= -github.com/pingcap/tidb v2.0.11+incompatible/go.mod h1:I8C6jrPINP2rrVunTRd7C9fRRhQrtR43S1/CL5ix/yQ= -github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -164,9 +162,7 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a h1:gOpx8G595UYyvj8UK4+OFyY4rx037g3fmfhe5SasG3U= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -175,7 +171,6 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -189,8 +184,6 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/tools v0.0.0-20200117065230-39095c1d176c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= diff --git a/orm/models_test.go b/orm/models_test.go index e3a635f2..05f438ea 100644 --- a/orm/models_test.go +++ b/orm/models_test.go @@ -53,18 +53,24 @@ func (e *SliceStringField) FieldType() int { } func (e *SliceStringField) SetRaw(value interface{}) error { - switch d := value.(type) { - case []string: - e.Set(d) - case string: - if len(d) > 0 { - parts := strings.Split(d, ",") + f := func(str string) { + if len(str) > 0 { + parts := strings.Split(str, ",") v := make([]string, 0, len(parts)) for _, p := range parts { v = append(v, strings.TrimSpace(p)) } e.Set(v) } + } + + switch d := value.(type) { + case []string: + e.Set(d) + case string: + f(d) + case []byte: + f(string(d)) default: return fmt.Errorf(" unknown value `%v`", value) } @@ -96,6 +102,8 @@ func (e *JSONFieldTest) SetRaw(value interface{}) error { switch d := value.(type) { case string: return json.Unmarshal([]byte(d), e) + case []byte: + return json.Unmarshal(d, e) default: return fmt.Errorf(" unknown value `%v`", value) } diff --git a/orm/orm_raw.go b/orm/orm_raw.go index 3325a7ea..1bdefc78 100644 --- a/orm/orm_raw.go +++ b/orm/orm_raw.go @@ -19,6 +19,8 @@ import ( "fmt" "reflect" "time" + + "github.com/pkg/errors" ) // raw sql string prepared statement @@ -368,7 +370,15 @@ func (o *rawSet) QueryRow(containers ...interface{}) error { field.Set(mf) field = mf.Elem().FieldByIndex(fi.relModelInfo.fields.pk.fieldIndex) } - o.setFieldValue(field, value) + if fi.isFielder { + fd := field.Addr().Interface().(Fielder) + err := fd.SetRaw(value) + if err != nil { + return errors.Errorf("set raw error:%s", err) + } + } else { + o.setFieldValue(field, value) + } } } } else { @@ -509,7 +519,15 @@ func (o *rawSet) QueryRows(containers ...interface{}) (int64, error) { field.Set(mf) field = mf.Elem().FieldByIndex(fi.relModelInfo.fields.pk.fieldIndex) } - o.setFieldValue(field, value) + if fi.isFielder { + fd := field.Addr().Interface().(Fielder) + err := fd.SetRaw(value) + if err != nil { + return 0, errors.Errorf("set raw error:%s", err) + } + } else { + o.setFieldValue(field, value) + } } } } else { diff --git a/orm/orm_test.go b/orm/orm_test.go index bdb430b6..f96fb941 100644 --- a/orm/orm_test.go +++ b/orm/orm_test.go @@ -769,6 +769,20 @@ func TestCustomField(t *testing.T) { throwFailNow(t, AssertIs(user.Extra.Name, "beego")) throwFailNow(t, AssertIs(user.Extra.Data, "orm")) + + var users []User + Q := dDbBaser.TableQuote() + n, err := dORM.Raw(fmt.Sprintf("SELECT * FROM %suser%s where id=?", Q, Q), 2).QueryRows(&users) + throwFailNow(t, err) + throwFailNow(t, AssertIs(n, 1)) + throwFailNow(t, AssertIs(users[0].Extra.Name, "beego")) + throwFailNow(t, AssertIs(users[0].Extra.Data, "orm")) + + user = User{} + err = dORM.Raw(fmt.Sprintf("SELECT * FROM %suser%s where id=?", Q, Q), 2).QueryRow(&user) + throwFailNow(t, err) + throwFailNow(t, AssertIs(user.Extra.Name, "beego")) + throwFailNow(t, AssertIs(user.Extra.Data, "orm")) } func TestExpr(t *testing.T) { From 8736ffaf6ff87334153ed38591af30136fadd76c Mon Sep 17 00:00:00 2001 From: CadenGuo <411189077@qq.com> Date: Sun, 30 Aug 2020 23:38:52 +0800 Subject: [PATCH 02/29] use 'BINARY' key word for exact operator for mysql db --- orm/db_mysql.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/orm/db_mysql.go b/orm/db_mysql.go index 6e99058e..ff6516b7 100644 --- a/orm/db_mysql.go +++ b/orm/db_mysql.go @@ -22,7 +22,7 @@ import ( // mysql operators. var mysqlOperators = map[string]string{ - "exact": "= ?", + "exact": "= BINARY ?", "iexact": "LIKE ?", "contains": "LIKE BINARY ?", "icontains": "LIKE ?", From 60bb0577839444a0944d39e4a4456155a4f5124a Mon Sep 17 00:00:00 2001 From: CadenGuo <411189077@qq.com> Date: Mon, 31 Aug 2020 03:40:18 +0000 Subject: [PATCH 03/29] add a new mysql operator for force case sensitie query --- orm/db.go | 11 ++++++----- orm/db_mysql.go | 9 +++++---- orm/orm_test.go | 8 ++++++++ 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/orm/db.go b/orm/db.go index 9a1827e8..7536a422 100644 --- a/orm/db.go +++ b/orm/db.go @@ -36,10 +36,11 @@ var ( var ( operators = map[string]bool{ - "exact": true, - "iexact": true, - "contains": true, - "icontains": true, + "exact": true, + "iexact": true, + "strictexact": true, + "contains": true, + "icontains": true, // "regex": true, // "iregex": true, "gt": true, @@ -1202,7 +1203,7 @@ func (d *dbBase) GenerateOperatorSQL(mi *modelInfo, fi *fieldInfo, operator stri } sql = d.ins.OperatorSQL(operator) switch operator { - case "exact": + case "exact", "strictexact": if arg == nil { params[0] = "IS NULL" } diff --git a/orm/db_mysql.go b/orm/db_mysql.go index ff6516b7..8dd1e755 100644 --- a/orm/db_mysql.go +++ b/orm/db_mysql.go @@ -22,10 +22,11 @@ import ( // mysql operators. var mysqlOperators = map[string]string{ - "exact": "= BINARY ?", - "iexact": "LIKE ?", - "contains": "LIKE BINARY ?", - "icontains": "LIKE ?", + "exact": "= ?", + "iexact": "LIKE ?", + "strictexact": "= BINARY ?", + "contains": "LIKE BINARY ?", + "icontains": "LIKE ?", // "regex": "REGEXP BINARY ?", // "iregex": "REGEXP ?", "gt": "> ?", diff --git a/orm/orm_test.go b/orm/orm_test.go index f96fb941..18e48288 100644 --- a/orm/orm_test.go +++ b/orm/orm_test.go @@ -822,6 +822,14 @@ func TestOperators(t *testing.T) { throwFail(t, err) throwFail(t, AssertIs(num, 1)) + num, err = qs.Filter("user_name__strictexact", "Slene").Count() + throwFail(t, err) + throwFail(t, AssertIs(num, 0)) + + num, err = qs.Filter("user_name__strictexact", "slene").Count() + throwFail(t, err) + throwFail(t, AssertIs(num, 1)) + num, err = qs.Filter("user_name__contains", "e").Count() throwFail(t, err) throwFail(t, AssertIs(num, 2)) From ff53e12191a6ab4ec27ec5cbbb301c2e6046d6fd Mon Sep 17 00:00:00 2001 From: CadenGuo <411189077@qq.com> Date: Mon, 31 Aug 2020 15:29:48 +0000 Subject: [PATCH 04/29] skip strictexact operator test for db drivers other than mysql --- orm/orm_test.go | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/orm/orm_test.go b/orm/orm_test.go index 18e48288..b18a7082 100644 --- a/orm/orm_test.go +++ b/orm/orm_test.go @@ -822,13 +822,16 @@ func TestOperators(t *testing.T) { throwFail(t, err) throwFail(t, AssertIs(num, 1)) - num, err = qs.Filter("user_name__strictexact", "Slene").Count() - throwFail(t, err) - throwFail(t, AssertIs(num, 0)) + if dORM.Driver().Name() == "mysql" { + // Now only mysql support `strictexact` + num, err = qs.Filter("user_name__strictexact", "Slene").Count() + throwFail(t, err) + throwFail(t, AssertIs(num, 0)) - num, err = qs.Filter("user_name__strictexact", "slene").Count() - throwFail(t, err) - throwFail(t, AssertIs(num, 1)) + num, err = qs.Filter("user_name__strictexact", "slene").Count() + throwFail(t, err) + throwFail(t, AssertIs(num, 1)) + } num, err = qs.Filter("user_name__contains", "e").Count() throwFail(t, err) From 91410be72279e01e4acd82a369663cf714130f28 Mon Sep 17 00:00:00 2001 From: CadenGuo <411189077@qq.com> Date: Mon, 31 Aug 2020 15:47:37 +0000 Subject: [PATCH 05/29] orm_test:use predefined variable to check db driver --- orm/orm_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/orm/orm_test.go b/orm/orm_test.go index b18a7082..93668235 100644 --- a/orm/orm_test.go +++ b/orm/orm_test.go @@ -822,7 +822,7 @@ func TestOperators(t *testing.T) { throwFail(t, err) throwFail(t, AssertIs(num, 1)) - if dORM.Driver().Name() == "mysql" { + if IsMysql { // Now only mysql support `strictexact` num, err = qs.Filter("user_name__strictexact", "Slene").Count() throwFail(t, err) From 26208a53e6e6443674c68dac3fb27bf79d0de76a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcio=20Augusto?= Date: Tue, 15 Sep 2020 18:05:33 -0300 Subject: [PATCH 06/29] session: adds CookieSameSite to ManagerConfig --- session/session.go | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/session/session.go b/session/session.go index eb85360a..4532a959 100644 --- a/session/session.go +++ b/session/session.go @@ -92,20 +92,21 @@ func GetProvider(name string) (Provider, error) { // ManagerConfig define the session config type ManagerConfig struct { - CookieName string `json:"cookieName"` - EnableSetCookie bool `json:"enableSetCookie,omitempty"` - Gclifetime int64 `json:"gclifetime"` - Maxlifetime int64 `json:"maxLifetime"` - DisableHTTPOnly bool `json:"disableHTTPOnly"` - Secure bool `json:"secure"` - CookieLifeTime int `json:"cookieLifeTime"` - ProviderConfig string `json:"providerConfig"` - Domain string `json:"domain"` - SessionIDLength int64 `json:"sessionIDLength"` - EnableSidInHTTPHeader bool `json:"EnableSidInHTTPHeader"` - SessionNameInHTTPHeader string `json:"SessionNameInHTTPHeader"` - EnableSidInURLQuery bool `json:"EnableSidInURLQuery"` - SessionIDPrefix string `json:"sessionIDPrefix"` + CookieName string `json:"cookieName"` + EnableSetCookie bool `json:"enableSetCookie,omitempty"` + Gclifetime int64 `json:"gclifetime"` + Maxlifetime int64 `json:"maxLifetime"` + DisableHTTPOnly bool `json:"disableHTTPOnly"` + Secure bool `json:"secure"` + CookieLifeTime int `json:"cookieLifeTime"` + ProviderConfig string `json:"providerConfig"` + Domain string `json:"domain"` + SessionIDLength int64 `json:"sessionIDLength"` + EnableSidInHTTPHeader bool `json:"EnableSidInHTTPHeader"` + SessionNameInHTTPHeader string `json:"SessionNameInHTTPHeader"` + EnableSidInURLQuery bool `json:"EnableSidInURLQuery"` + SessionIDPrefix string `json:"sessionIDPrefix"` + CookieSameSite http.SameSite `json:"cookieSameSite"` } // Manager contains Provider and its configuration. @@ -232,6 +233,7 @@ func (manager *Manager) SessionStart(w http.ResponseWriter, r *http.Request) (se HttpOnly: !manager.config.DisableHTTPOnly, Secure: manager.isSecure(r), Domain: manager.config.Domain, + SameSite: manager.config.CookieSameSite, } if manager.config.CookieLifeTime > 0 { cookie.MaxAge = manager.config.CookieLifeTime @@ -271,7 +273,9 @@ func (manager *Manager) SessionDestroy(w http.ResponseWriter, r *http.Request) { HttpOnly: !manager.config.DisableHTTPOnly, Expires: expiration, MaxAge: -1, - Domain: manager.config.Domain} + Domain: manager.config.Domain, + SameSite: manager.config.CookieSameSite, + } http.SetCookie(w, cookie) } @@ -306,6 +310,7 @@ func (manager *Manager) SessionRegenerateID(w http.ResponseWriter, r *http.Reque HttpOnly: !manager.config.DisableHTTPOnly, Secure: manager.isSecure(r), Domain: manager.config.Domain, + SameSite: manager.config.CookieSameSite, } } else { oldsid, _ := url.QueryUnescape(cookie.Value) From 6ffbc0a2b8e1e2edd2bce59a1d2ac357f9004de8 Mon Sep 17 00:00:00 2001 From: "Allen.M" Date: Wed, 30 Sep 2020 15:50:40 +0800 Subject: [PATCH 07/29] testing: fix temporary create failed on Windows We are creating temporary files on the root directory of beego now This PR using system temporary directory for testing. Fixes #4243 --- controller_test.go | 4 ++-- template_test.go | 10 +++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/controller_test.go b/controller_test.go index 1e53416d..215a7411 100644 --- a/controller_test.go +++ b/controller_test.go @@ -125,8 +125,8 @@ func TestGetUint64(t *testing.T) { } func TestAdditionalViewPaths(t *testing.T) { - dir1 := "_beeTmp" - dir2 := "_beeTmp2" + dir1 := tmpDir("TestAdditionalViewPaths1") + dir2 := tmpDir("TestAdditionalViewPaths2") defer os.RemoveAll(dir1) defer os.RemoveAll(dir2) diff --git a/template_test.go b/template_test.go index 287faadc..049655db 100644 --- a/template_test.go +++ b/template_test.go @@ -45,8 +45,12 @@ var block = `{{define "block"}}

Hello, blocks!

{{end}}` +func tmpDir(s string) string { + return filepath.Join(os.TempDir(), s) +} + func TestTemplate(t *testing.T) { - dir := "_beeTmp" + dir := tmpDir("TestTemplate") files := []string{ "header.tpl", "index.tpl", @@ -107,7 +111,7 @@ var user = ` ` func TestRelativeTemplate(t *testing.T) { - dir := "_beeTmp" + dir := tmpDir("TestRelativeTemplate") //Just add dir to known viewPaths if err := AddViewPath(dir); err != nil { @@ -218,7 +222,7 @@ var output = ` ` func TestTemplateLayout(t *testing.T) { - dir := "_beeTmp" + dir := tmpDir("TestTemplateLayout") files := []string{ "add.tpl", "layout_blog.tpl", From d66321fe4ed35864e86bb7ebdc9f0e49b25631d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcio=20Augusto?= Date: Mon, 5 Oct 2020 11:39:20 -0300 Subject: [PATCH 08/29] session: adds CookieSameSite config to hooks.go#registerSession --- config.go | 7 +++++-- hooks.go | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/config.go b/config.go index 0c995293..bd5bf2a1 100644 --- a/config.go +++ b/config.go @@ -15,13 +15,14 @@ package beego import ( + "crypto/tls" "fmt" + "net/http" "os" "path/filepath" "reflect" "runtime" "strings" - "crypto/tls" "github.com/astaxie/beego/config" "github.com/astaxie/beego/context" @@ -108,6 +109,7 @@ type SessionConfig struct { SessionEnableSidInHTTPHeader bool // enable store/get the sessionId into/from http headers SessionNameInHTTPHeader string SessionEnableSidInURLQuery bool // enable get the sessionId from Url Query params + SessionCookieSameSite http.SameSite } // LogConfig holds Log related config @@ -153,7 +155,7 @@ func init() { } appConfigPath = filepath.Join(WorkPath, "conf", filename) if configPath := os.Getenv("BEEGO_CONFIG_PATH"); configPath != "" { - appConfigPath = configPath + appConfigPath = configPath } if !utils.FileExists(appConfigPath) { appConfigPath = filepath.Join(AppPath, "conf", filename) @@ -267,6 +269,7 @@ func newBConfig() *Config { SessionEnableSidInHTTPHeader: false, // enable store/get the sessionId into/from http headers SessionNameInHTTPHeader: "Beegosessionid", SessionEnableSidInURLQuery: false, // enable get the sessionId from Url Query params + SessionCookieSameSite: http.SameSiteDefaultMode, }, }, Log: LogConfig{ diff --git a/hooks.go b/hooks.go index 49c42d5a..0a51e0da 100644 --- a/hooks.go +++ b/hooks.go @@ -61,6 +61,7 @@ func registerSession() error { conf.EnableSidInHTTPHeader = BConfig.WebConfig.Session.SessionEnableSidInHTTPHeader conf.SessionNameInHTTPHeader = BConfig.WebConfig.Session.SessionNameInHTTPHeader conf.EnableSidInURLQuery = BConfig.WebConfig.Session.SessionEnableSidInURLQuery + conf.CookieSameSite = BConfig.WebConfig.Session.SessionCookieSameSite } else { if err = json.Unmarshal([]byte(sessionConfig), conf); err != nil { return err From 91e18996bd0c04bee848502398b52547360a4d8d Mon Sep 17 00:00:00 2001 From: sc0vu Date: Tue, 6 Oct 2020 18:20:06 +0800 Subject: [PATCH 09/29] Fix typo --- admin_test.go | 2 +- config/ini_test.go | 4 ++-- httplib/httplib.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/admin_test.go b/admin_test.go index 3f3612e4..c5f6eeaf 100644 --- a/admin_test.go +++ b/admin_test.go @@ -154,7 +154,7 @@ func TestBuildHealthCheckResponseList(t *testing.T) { []string{ "error", "Database", - "Error occured whie starting the db", + "Error occurred while starting the db", }, []string{ "success", diff --git a/config/ini_test.go b/config/ini_test.go index ffcdb294..60f1febd 100644 --- a/config/ini_test.go +++ b/config/ini_test.go @@ -145,7 +145,7 @@ httpport = 8080 # enable db [dbinfo] # db type name -# suport mysql,sqlserver +# support mysql,sqlserver name = mysql ` @@ -161,7 +161,7 @@ httpport=8080 # enable db [dbinfo] # db type name -# suport mysql,sqlserver +# support mysql,sqlserver name=mysql ` ) diff --git a/httplib/httplib.go b/httplib/httplib.go index 60aa4e8b..17493970 100644 --- a/httplib/httplib.go +++ b/httplib/httplib.go @@ -518,7 +518,7 @@ func (b *BeegoHTTPRequest) DoRequest() (resp *http.Response, err error) { // retries default value is 0, it will run once. // retries equal to -1, it will run forever until success // retries is setted, it will retries fixed times. - // Sleeps for a 400ms inbetween calls to reduce spam + // Sleeps for a 400ms in between calls to reduce spam for i := 0; b.setting.Retries == -1 || i <= b.setting.Retries; i++ { resp, err = client.Do(b.req) if err == nil { From 1dffa20435c6f5fc4f2d4e49923249acd0cdf07e Mon Sep 17 00:00:00 2001 From: Ming Deng Date: Sat, 10 Oct 2020 21:34:02 +0800 Subject: [PATCH 10/29] make stmt cache smaller --- build_info.go | 8 ++--- cache/redis/redis.go | 5 ++-- config/yaml/yaml.go | 2 +- context/param/parsers_test.go | 8 +++-- controller_test.go | 3 +- logs/accesslog.go | 2 +- logs/file.go | 30 +++++++++---------- logs/file_test.go | 30 +++++++++---------- metric/prometheus.go | 6 ++-- orm/cmd_utils.go | 6 ++-- orm/db_alias.go | 9 ++++-- orm/orm_log.go | 2 +- plugins/authz/authz.go | 3 +- plugins/authz/authz_test.go | 7 +++-- session/redis_cluster/redis_cluster.go | 16 +++++----- session/redis_sentinel/sess_redis_sentinel.go | 5 ++-- session/sess_file_test.go | 5 ++-- staticfile.go | 2 +- template_test.go | 5 ++-- templatefunc.go | 2 +- testdata/bindata.go | 3 +- validation/util.go | 2 +- validation/validators.go | 3 +- 23 files changed, 89 insertions(+), 75 deletions(-) diff --git a/build_info.go b/build_info.go index 6dc2835e..c31152ea 100644 --- a/build_info.go +++ b/build_info.go @@ -15,11 +15,11 @@ package beego var ( - BuildVersion string + BuildVersion string BuildGitRevision string - BuildStatus string - BuildTag string - BuildTime string + BuildStatus string + BuildTag string + BuildTime string GoVersion string diff --git a/cache/redis/redis.go b/cache/redis/redis.go index 56faf211..dde760ea 100644 --- a/cache/redis/redis.go +++ b/cache/redis/redis.go @@ -38,8 +38,9 @@ import ( "github.com/gomodule/redigo/redis" - "github.com/astaxie/beego/cache" "strings" + + "github.com/astaxie/beego/cache" ) var ( @@ -57,7 +58,7 @@ type Cache struct { maxIdle int //the timeout to a value less than the redis server's timeout. - timeout time.Duration + timeout time.Duration } // NewRedisCache create new redis cache with default collection name. diff --git a/config/yaml/yaml.go b/config/yaml/yaml.go index 5def2da3..a5644c7b 100644 --- a/config/yaml/yaml.go +++ b/config/yaml/yaml.go @@ -296,7 +296,7 @@ func (c *ConfigContainer) getData(key string) (interface{}, error) { case map[string]interface{}: { tmpData = v.(map[string]interface{}) - if idx == len(keys) - 1 { + if idx == len(keys)-1 { return tmpData, nil } } diff --git a/context/param/parsers_test.go b/context/param/parsers_test.go index 7065a28e..81a821f1 100644 --- a/context/param/parsers_test.go +++ b/context/param/parsers_test.go @@ -1,8 +1,10 @@ package param -import "testing" -import "reflect" -import "time" +import ( + "reflect" + "testing" + "time" +) type testDefinition struct { strValue string diff --git a/controller_test.go b/controller_test.go index 215a7411..a5888f62 100644 --- a/controller_test.go +++ b/controller_test.go @@ -19,9 +19,10 @@ import ( "strconv" "testing" - "github.com/astaxie/beego/context" "os" "path/filepath" + + "github.com/astaxie/beego/context" ) func TestGetInt(t *testing.T) { diff --git a/logs/accesslog.go b/logs/accesslog.go index 3ff9e20f..9011b602 100644 --- a/logs/accesslog.go +++ b/logs/accesslog.go @@ -16,9 +16,9 @@ package logs import ( "bytes" - "strings" "encoding/json" "fmt" + "strings" "time" ) diff --git a/logs/file.go b/logs/file.go index 222db989..40a3572a 100644 --- a/logs/file.go +++ b/logs/file.go @@ -373,21 +373,21 @@ func (w *fileLogWriter) deleteOldLog() { if info == nil { return } - if w.Hourly { - if !info.IsDir() && info.ModTime().Add(1 * time.Hour * time.Duration(w.MaxHours)).Before(time.Now()) { - if strings.HasPrefix(filepath.Base(path), filepath.Base(w.fileNameOnly)) && - strings.HasSuffix(filepath.Base(path), w.suffix) { - os.Remove(path) - } - } - } else if w.Daily { - if !info.IsDir() && info.ModTime().Add(24 * time.Hour * time.Duration(w.MaxDays)).Before(time.Now()) { - if strings.HasPrefix(filepath.Base(path), filepath.Base(w.fileNameOnly)) && - strings.HasSuffix(filepath.Base(path), w.suffix) { - os.Remove(path) - } - } - } + if w.Hourly { + if !info.IsDir() && info.ModTime().Add(1*time.Hour*time.Duration(w.MaxHours)).Before(time.Now()) { + if strings.HasPrefix(filepath.Base(path), filepath.Base(w.fileNameOnly)) && + strings.HasSuffix(filepath.Base(path), w.suffix) { + os.Remove(path) + } + } + } else if w.Daily { + if !info.IsDir() && info.ModTime().Add(24*time.Hour*time.Duration(w.MaxDays)).Before(time.Now()) { + if strings.HasPrefix(filepath.Base(path), filepath.Base(w.fileNameOnly)) && + strings.HasSuffix(filepath.Base(path), w.suffix) { + os.Remove(path) + } + } + } return }) } diff --git a/logs/file_test.go b/logs/file_test.go index e7c2ca9a..385eac43 100644 --- a/logs/file_test.go +++ b/logs/file_test.go @@ -186,7 +186,7 @@ func TestFileDailyRotate_06(t *testing.T) { //test file mode func TestFileHourlyRotate_01(t *testing.T) { log := NewLogger(10000) - log.SetLogger("file", `{"filename":"test3.log","hourly":true,"maxlines":4}`) + log.SetLogger("file", `{"filename":"test3.log","hourly":true,"maxlines":4}`) log.Debug("debug") log.Info("info") log.Notice("notice") @@ -237,7 +237,7 @@ func TestFileHourlyRotate_05(t *testing.T) { func TestFileHourlyRotate_06(t *testing.T) { //test file mode log := NewLogger(10000) - log.SetLogger("file", `{"filename":"test3.log", "hourly":true, "maxlines":4}`) + log.SetLogger("file", `{"filename":"test3.log", "hourly":true, "maxlines":4}`) log.Debug("debug") log.Info("info") log.Notice("notice") @@ -269,19 +269,19 @@ func testFileRotate(t *testing.T, fn1, fn2 string, daily, hourly bool) { RotatePerm: "0440", } - if daily { - fw.Init(fmt.Sprintf(`{"filename":"%v","maxdays":1}`, fn1)) - fw.dailyOpenTime = time.Now().Add(-24 * time.Hour) - fw.dailyOpenDate = fw.dailyOpenTime.Day() - } + if daily { + fw.Init(fmt.Sprintf(`{"filename":"%v","maxdays":1}`, fn1)) + fw.dailyOpenTime = time.Now().Add(-24 * time.Hour) + fw.dailyOpenDate = fw.dailyOpenTime.Day() + } - if hourly { - fw.Init(fmt.Sprintf(`{"filename":"%v","maxhours":1}`, fn1)) - fw.hourlyOpenTime = time.Now().Add(-1 * time.Hour) - fw.hourlyOpenDate = fw.hourlyOpenTime.Day() - } + if hourly { + fw.Init(fmt.Sprintf(`{"filename":"%v","maxhours":1}`, fn1)) + fw.hourlyOpenTime = time.Now().Add(-1 * time.Hour) + fw.hourlyOpenDate = fw.hourlyOpenTime.Day() + } - fw.WriteMsg(time.Now(), "this is a msg for test", LevelDebug) + fw.WriteMsg(time.Now(), "this is a msg for test", LevelDebug) for _, file := range []string{fn1, fn2} { _, err := os.Stat(file) @@ -328,8 +328,8 @@ func testFileDailyRotate(t *testing.T, fn1, fn2 string) { func testFileHourlyRotate(t *testing.T, fn1, fn2 string) { fw := &fileLogWriter{ - Hourly: true, - MaxHours: 168, + Hourly: true, + MaxHours: 168, Rotate: true, Level: LevelTrace, Perm: "0660", diff --git a/metric/prometheus.go b/metric/prometheus.go index 7722240b..86e2c1b1 100644 --- a/metric/prometheus.go +++ b/metric/prometheus.go @@ -57,15 +57,15 @@ func registerBuildInfo() { Subsystem: "build_info", Help: "The building information", ConstLabels: map[string]string{ - "appname": beego.BConfig.AppName, + "appname": beego.BConfig.AppName, "build_version": beego.BuildVersion, "build_revision": beego.BuildGitRevision, "build_status": beego.BuildStatus, "build_tag": beego.BuildTag, - "build_time": strings.Replace(beego.BuildTime, "--", " ", 1), + "build_time": strings.Replace(beego.BuildTime, "--", " ", 1), "go_version": beego.GoVersion, "git_branch": beego.GitBranch, - "start_time": time.Now().Format("2006-01-02 15:04:05"), + "start_time": time.Now().Format("2006-01-02 15:04:05"), }, }, []string{}) diff --git a/orm/cmd_utils.go b/orm/cmd_utils.go index 61f17346..692a079f 100644 --- a/orm/cmd_utils.go +++ b/orm/cmd_utils.go @@ -197,9 +197,9 @@ func getDbCreateSQL(al *alias) (sqls []string, tableIndexes map[string][]dbIndex if strings.Contains(column, "%COL%") { column = strings.Replace(column, "%COL%", fi.column, -1) } - - if fi.description != "" && al.Driver!=DRSqlite { - column += " " + fmt.Sprintf("COMMENT '%s'",fi.description) + + if fi.description != "" && al.Driver != DRSqlite { + column += " " + fmt.Sprintf("COMMENT '%s'", fi.description) } columns = append(columns, column) diff --git a/orm/db_alias.go b/orm/db_alias.go index bf6c350c..369802a7 100644 --- a/orm/db_alias.go +++ b/orm/db_alias.go @@ -18,10 +18,11 @@ import ( "context" "database/sql" "fmt" - lru "github.com/hashicorp/golang-lru" "reflect" "sync" "time" + + lru "github.com/hashicorp/golang-lru" ) // DriverType database driver constant int. @@ -424,7 +425,7 @@ func GetDB(aliasNames ...string) (*sql.DB, error) { } type stmtDecorator struct { - wg sync.WaitGroup + wg sync.WaitGroup stmt *sql.Stmt } @@ -459,7 +460,9 @@ func newStmtDecorator(sqlStmt *sql.Stmt) *stmtDecorator { } func newStmtDecoratorLruWithEvict() *lru.Cache { - cache, _ := lru.NewWithEvict(1000, func(key interface{}, value interface{}) { + // temporarily solution + // we fixed this problem in v2.x + cache, _ := lru.NewWithEvict(50, func(key interface{}, value interface{}) { value.(*stmtDecorator).destroy() }) return cache diff --git a/orm/orm_log.go b/orm/orm_log.go index f107bb59..5bb3a24f 100644 --- a/orm/orm_log.go +++ b/orm/orm_log.go @@ -61,7 +61,7 @@ func debugLogQueies(alias *alias, operaton, query string, t time.Time, err error con += " - " + err.Error() } logMap["sql"] = fmt.Sprintf("%s-`%s`", query, strings.Join(cons, "`, `")) - if LogFunc != nil{ + if LogFunc != nil { LogFunc(logMap) } DebugLog.Println(con) diff --git a/plugins/authz/authz.go b/plugins/authz/authz.go index 9dc0db76..879fdea6 100644 --- a/plugins/authz/authz.go +++ b/plugins/authz/authz.go @@ -40,10 +40,11 @@ package authz import ( + "net/http" + "github.com/astaxie/beego" "github.com/astaxie/beego/context" "github.com/casbin/casbin" - "net/http" ) // NewAuthorizer returns the authorizer. diff --git a/plugins/authz/authz_test.go b/plugins/authz/authz_test.go index 49aed84c..e9d397a2 100644 --- a/plugins/authz/authz_test.go +++ b/plugins/authz/authz_test.go @@ -15,13 +15,14 @@ package authz import ( + "net/http" + "net/http/httptest" + "testing" + "github.com/astaxie/beego" "github.com/astaxie/beego/context" "github.com/astaxie/beego/plugins/auth" "github.com/casbin/casbin" - "net/http" - "net/http/httptest" - "testing" ) func testRequest(t *testing.T, handler *beego.ControllerRegister, user string, path string, method string, code int) { diff --git a/session/redis_cluster/redis_cluster.go b/session/redis_cluster/redis_cluster.go index 2fe300df..802c1c39 100644 --- a/session/redis_cluster/redis_cluster.go +++ b/session/redis_cluster/redis_cluster.go @@ -31,14 +31,16 @@ // // more docs: http://beego.me/docs/module/session.md package redis_cluster + import ( "net/http" "strconv" "strings" "sync" + "time" + "github.com/astaxie/beego/session" rediss "github.com/go-redis/redis" - "time" ) var redispder = &Provider{} @@ -101,7 +103,7 @@ func (rs *SessionStore) SessionRelease(w http.ResponseWriter) { return } c := rs.p - c.Set(rs.sid, string(b), time.Duration(rs.maxlifetime) * time.Second) + c.Set(rs.sid, string(b), time.Duration(rs.maxlifetime)*time.Second) } // Provider redis_cluster session provider @@ -146,10 +148,10 @@ func (rp *Provider) SessionInit(maxlifetime int64, savePath string) error { } else { rp.dbNum = 0 } - + rp.poollist = rediss.NewClusterClient(&rediss.ClusterOptions{ Addrs: strings.Split(rp.savePath, ";"), - Password: rp.password, + Password: rp.password, PoolSize: rp.poolsize, }) return rp.poollist.Ping().Err() @@ -186,15 +188,15 @@ func (rp *Provider) SessionExist(sid string) bool { // SessionRegenerate generate new sid for redis_cluster session func (rp *Provider) SessionRegenerate(oldsid, sid string) (session.Store, error) { c := rp.poollist - + if existed, err := c.Exists(oldsid).Result(); err != nil || existed == 0 { // oldsid doesn't exists, set the new sid directly // ignore error here, since if it return error // the existed value will be 0 - c.Set(sid, "", time.Duration(rp.maxlifetime) * time.Second) + c.Set(sid, "", time.Duration(rp.maxlifetime)*time.Second) } else { c.Rename(oldsid, sid) - c.Expire(sid, time.Duration(rp.maxlifetime) * time.Second) + c.Expire(sid, time.Duration(rp.maxlifetime)*time.Second) } return rp.SessionRead(sid) } diff --git a/session/redis_sentinel/sess_redis_sentinel.go b/session/redis_sentinel/sess_redis_sentinel.go index 6ecb2977..29284d03 100644 --- a/session/redis_sentinel/sess_redis_sentinel.go +++ b/session/redis_sentinel/sess_redis_sentinel.go @@ -33,13 +33,14 @@ package redis_sentinel import ( - "github.com/astaxie/beego/session" - "github.com/go-redis/redis" "net/http" "strconv" "strings" "sync" "time" + + "github.com/astaxie/beego/session" + "github.com/go-redis/redis" ) var redispder = &Provider{} diff --git a/session/sess_file_test.go b/session/sess_file_test.go index 0cf021db..021c43fc 100644 --- a/session/sess_file_test.go +++ b/session/sess_file_test.go @@ -369,8 +369,7 @@ func TestFileSessionStore_SessionRelease(t *testing.T) { t.Error(err) } - - s.Set(i,i) + s.Set(i, i) s.SessionRelease(nil) } @@ -384,4 +383,4 @@ func TestFileSessionStore_SessionRelease(t *testing.T) { t.Error() } } -} \ No newline at end of file +} diff --git a/staticfile.go b/staticfile.go index 84e9aa7b..e26776c5 100644 --- a/staticfile.go +++ b/staticfile.go @@ -202,7 +202,7 @@ func searchFile(ctx *context.Context) (string, os.FileInfo, error) { if !strings.Contains(requestPath, prefix) { continue } - if prefix != "/" && len(requestPath) > len(prefix) && requestPath[len(prefix)] != '/' { + if prefix != "/" && len(requestPath) > len(prefix) && requestPath[len(prefix)] != '/' { continue } filePath := path.Join(staticDir, requestPath[len(prefix):]) diff --git a/template_test.go b/template_test.go index 049655db..b688c8a0 100644 --- a/template_test.go +++ b/template_test.go @@ -16,12 +16,13 @@ package beego import ( "bytes" - "github.com/astaxie/beego/testdata" - "github.com/elazarl/go-bindata-assetfs" "net/http" "os" "path/filepath" "testing" + + "github.com/astaxie/beego/testdata" + "github.com/elazarl/go-bindata-assetfs" ) var header = `{{define "header"}} diff --git a/templatefunc.go b/templatefunc.go index ba1ec5eb..6f02b8d6 100644 --- a/templatefunc.go +++ b/templatefunc.go @@ -362,7 +362,7 @@ func parseFormToStruct(form url.Values, objT reflect.Type, objV reflect.Value) e value = value[:25] t, err = time.ParseInLocation(time.RFC3339, value, time.Local) } else if strings.HasSuffix(strings.ToUpper(value), "Z") { - t, err = time.ParseInLocation(time.RFC3339, value, time.Local) + t, err = time.ParseInLocation(time.RFC3339, value, time.Local) } else if len(value) >= 19 { if strings.Contains(value, "T") { value = value[:19] diff --git a/testdata/bindata.go b/testdata/bindata.go index beade103..ccfb51d4 100644 --- a/testdata/bindata.go +++ b/testdata/bindata.go @@ -11,13 +11,14 @@ import ( "bytes" "compress/gzip" "fmt" - "github.com/elazarl/go-bindata-assetfs" "io" "io/ioutil" "os" "path/filepath" "strings" "time" + + "github.com/elazarl/go-bindata-assetfs" ) func bindataRead(data []byte, name string) ([]byte, error) { diff --git a/validation/util.go b/validation/util.go index 82206f4f..918b206c 100644 --- a/validation/util.go +++ b/validation/util.go @@ -213,7 +213,7 @@ func parseFunc(vfunc, key string, label string) (v ValidFunc, err error) { return } - tParams, err := trim(name, key+"."+ name + "." + label, params) + tParams, err := trim(name, key+"."+name+"."+label, params) if err != nil { return } diff --git a/validation/validators.go b/validation/validators.go index 38b6f1aa..a0e4bcbb 100644 --- a/validation/validators.go +++ b/validation/validators.go @@ -16,13 +16,14 @@ package validation import ( "fmt" - "github.com/astaxie/beego/logs" "reflect" "regexp" "strings" "sync" "time" "unicode/utf8" + + "github.com/astaxie/beego/logs" ) // CanSkipFuncs will skip valid if RequiredFirst is true and the struct field's value is empty From b2a96234ab3ebd10989bb2f5a16c3a4b860467c5 Mon Sep 17 00:00:00 2001 From: Ming Deng Date: Tue, 3 Nov 2020 22:21:32 +0800 Subject: [PATCH 11/29] Upgrade version --- beego.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beego.go b/beego.go index 8ebe0bab..44184c25 100644 --- a/beego.go +++ b/beego.go @@ -23,7 +23,7 @@ import ( const ( // VERSION represent beego web framework version. - VERSION = "1.12.2" + VERSION = "1.12.3" // DEV is for develop DEV = "dev" From 2a6fadb9ae85e2ee586bd9c82ce7d54cc989bded Mon Sep 17 00:00:00 2001 From: Ming Deng Date: Mon, 9 Nov 2020 22:43:49 +0800 Subject: [PATCH 12/29] Fix 4138 --- core/logs/slack.go | 14 +++++++------ core/logs/slack_test.go | 44 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 6 deletions(-) create mode 100644 core/logs/slack_test.go diff --git a/core/logs/slack.go b/core/logs/slack.go index b6e2f170..ce892a1b 100644 --- a/core/logs/slack.go +++ b/core/logs/slack.go @@ -1,10 +1,10 @@ package logs import ( + "bytes" "encoding/json" "fmt" "net/http" - "net/url" "github.com/pkg/errors" ) @@ -25,8 +25,8 @@ func newSLACKWriter() Logger { } func (s *SLACKWriter) Format(lm *LogMsg) string { - text := fmt.Sprintf("{\"text\": \"%s %s\"}", lm.When.Format("2006-01-02 15:04:05"), lm.OldStyleFormat()) - return text + // text := fmt.Sprintf("{\"text\": \"%s\"}", msg) + return lm.When.Format("2006-01-02 15:04:05") + " " + lm.OldStyleFormat() } func (s *SLACKWriter) SetFormatter(f LogFormatter) { @@ -55,10 +55,12 @@ func (s *SLACKWriter) WriteMsg(lm *LogMsg) error { return nil } msg := s.Format(lm) - form := url.Values{} - form.Add("payload", msg) + m := make(map[string]string, 1) + m["text"] = msg - resp, err := http.PostForm(s.WebhookURL, form) + body, _ := json.Marshal(m) + // resp, err := http.PostForm(s.WebhookURL, form) + resp, err := http.Post(s.WebhookURL, "application/json", bytes.NewReader(body)) if err != nil { return err } diff --git a/core/logs/slack_test.go b/core/logs/slack_test.go new file mode 100644 index 00000000..31f5cf97 --- /dev/null +++ b/core/logs/slack_test.go @@ -0,0 +1,44 @@ +// Copyright 2020 +// +// 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 logs + +// func TestSLACKWriter_WriteMsg(t *testing.T) { +// sc := ` +// { +// "webhookurl":"", +// "level":7 +// } +// ` +// l := newSLACKWriter() +// err := l.Init(sc) +// if err != nil { +// Debug(err) +// } +// +// err = l.WriteMsg(&LogMsg{ +// Level: 7, +// Msg: `{ "abs"`, +// When: time.Now(), +// FilePath: "main.go", +// LineNumber: 100, +// enableFullFilePath: true, +// enableFuncCallDepth: true, +// }) +// +// if err != nil { +// Debug(err) +// } +// +// } From b3474b20b9488e8580ea1dc98429d0c012c8950f Mon Sep 17 00:00:00 2001 From: AllenX2018 Date: Tue, 10 Nov 2020 15:45:34 +0800 Subject: [PATCH 13/29] fix issue 4282 --- core/logs/log.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/core/logs/log.go b/core/logs/log.go index d5953dfb..2c1b4dd1 100644 --- a/core/logs/log.go +++ b/core/logs/log.go @@ -764,9 +764,7 @@ func formatLog(f interface{}, v ...interface{}) string { if len(v) == 0 { return msg } - if strings.Contains(msg, "%") && !strings.Contains(msg, "%%") { - // format string - } else { + if !strings.Contains(msg, "%") { // do not contain format char msg += strings.Repeat(" %v", len(v)) } From 0b3bcbd3ec2f335e8b101cdcafaba93fe8d149cc Mon Sep 17 00:00:00 2001 From: Ming Deng Date: Tue, 10 Nov 2020 23:30:24 +0800 Subject: [PATCH 14/29] Fix 4298 --- client/orm/orm_conds.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client/orm/orm_conds.go b/client/orm/orm_conds.go index f3fd66f0..b4e1ce7a 100644 --- a/client/orm/orm_conds.go +++ b/client/orm/orm_conds.go @@ -76,10 +76,13 @@ func (c Condition) AndNot(expr string, args ...interface{}) *Condition { // AndCond combine a condition to current condition func (c *Condition) AndCond(cond *Condition) *Condition { - c = c.clone() + if c == cond { panic(fmt.Errorf(" cannot use self as sub cond")) } + + c = c.clone() + if cond != nil { c.params = append(c.params, condValue{cond: cond, isCond: true}) } From 8f3fd317dac97965a6b5763b4154b6aaeb2a01c4 Mon Sep 17 00:00:00 2001 From: cruis Date: Wed, 11 Nov 2020 16:12:57 +0800 Subject: [PATCH 15/29] Fix 4298 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Condition的clone方法,params存在共享内存,导致isCond死循环。 --- client/orm/orm_conds.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client/orm/orm_conds.go b/client/orm/orm_conds.go index b4e1ce7a..5409406e 100644 --- a/client/orm/orm_conds.go +++ b/client/orm/orm_conds.go @@ -152,5 +152,8 @@ func (c *Condition) IsEmpty() bool { // clone clone a condition func (c Condition) clone() *Condition { + params := make([]condValue, len(c.params)) + copy(params, c.params) + c.params = params return &c } From aad80ba4fad57dcd124203fe0128f662af52cf91 Mon Sep 17 00:00:00 2001 From: AllenX2018 Date: Wed, 11 Nov 2020 17:14:05 +0800 Subject: [PATCH 16/29] fix issue#4305: add write lock for map adminTaskList iteration and modify --- task/task.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/task/task.go b/task/task.go index 8f25a0f3..00cbbfa7 100644 --- a/task/task.go +++ b/task/task.go @@ -452,9 +452,11 @@ func (m *taskManager) StartTask() { func (m *taskManager) run() { now := time.Now().Local() + m.taskLock.Lock() for _, t := range m.adminTaskList { t.SetNext(nil, now) } + m.taskLock.Unlock() for { // we only use RLock here because NewMapSorter copy the reference, do not change any thing From 647e21b0c401833c3cbf5143e072c07bb195894f Mon Sep 17 00:00:00 2001 From: cruis Date: Fri, 13 Nov 2020 00:13:35 +0800 Subject: [PATCH 17/29] =?UTF-8?q?=E6=B7=BB=E5=8A=A0Condition=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/orm/orm_test.go | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/client/orm/orm_test.go b/client/orm/orm_test.go index 565f6c60..8bea63d9 100644 --- a/client/orm/orm_test.go +++ b/client/orm/orm_test.go @@ -2668,3 +2668,45 @@ func TestPSQueryBuilder(t *testing.T) { throwFailNow(t, AssertIs(l[0].UserName, "astaxie")) throwFailNow(t, AssertIs(l[0].Age, 30)) } + +func TestCondition(t *testing.T) { + // test Condition whether to include yourself + cond := NewCondition() + cond = cond.AndCond(cond.Or("id", 1)) + cond = cond.AndCond(cond.Or("id", 2)) + cond = cond.AndCond(cond.Or("id", 3)) + cond = cond.AndCond(cond.Or("id", 4)) + + cycleFlag := false + var hasCycle func(*Condition) + hasCycle = func(c *Condition) { + if nil == c || cycleFlag { + return + } + condPointMap := make(map[string]bool) + condPointMap[fmt.Sprintf("%p", c)] = true + for _, p := range c.params { + if p.isCond { + adr := fmt.Sprintf("%p", p.cond) + if condPointMap[adr] { + // self as sub cond was cycle + cycleFlag = true + return + } else { + condPointMap[adr] = true + } + } + } + for _, p := range c.params { + if p.isCond { + // check next cond + hasCycle(p.cond) + } + } + return + } + hasCycle(cond) + // cycleFlag was true,meaning use self as sub cond + throwFail(t, AssertIs(!cycleFlag, true)) + return +} From 0a852912b4280d58369f5f66967e438c3d55a4dd Mon Sep 17 00:00:00 2001 From: cruis Date: Fri, 13 Nov 2020 07:25:21 +0800 Subject: [PATCH 18/29] =?UTF-8?q?=E8=B0=83=E6=95=B4CI=E8=AD=A6=E5=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/orm/orm_test.go | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/client/orm/orm_test.go b/client/orm/orm_test.go index 8bea63d9..46863190 100644 --- a/client/orm/orm_test.go +++ b/client/orm/orm_test.go @@ -2672,10 +2672,10 @@ func TestPSQueryBuilder(t *testing.T) { func TestCondition(t *testing.T) { // test Condition whether to include yourself cond := NewCondition() - cond = cond.AndCond(cond.Or("id", 1)) - cond = cond.AndCond(cond.Or("id", 2)) - cond = cond.AndCond(cond.Or("id", 3)) - cond = cond.AndCond(cond.Or("id", 4)) + cond = cond.AndCond(cond.Or("ID", 1)) + cond = cond.AndCond(cond.Or("ID", 2)) + cond = cond.AndCond(cond.Or("ID", 3)) + cond = cond.AndCond(cond.Or("ID", 4)) cycleFlag := false var hasCycle func(*Condition) @@ -2691,12 +2691,15 @@ func TestCondition(t *testing.T) { if condPointMap[adr] { // self as sub cond was cycle cycleFlag = true - return - } else { - condPointMap[adr] = true + break } + condPointMap[adr] = true + } } + if cycleFlag { + return + } for _, p := range c.params { if p.isCond { // check next cond From 663e5d728c1ccd89c02535bc07df4c7702d5b5e6 Mon Sep 17 00:00:00 2001 From: AllenX2018 Date: Fri, 13 Nov 2020 16:47:22 +0800 Subject: [PATCH 19/29] fix issue #4312 --- client/cache/ssdb/ssdb.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/cache/ssdb/ssdb.go b/client/cache/ssdb/ssdb.go index 1acee861..def9273d 100644 --- a/client/cache/ssdb/ssdb.go +++ b/client/cache/ssdb/ssdb.go @@ -28,14 +28,14 @@ func NewSsdbCache() cache.Cache { func (rc *Cache) Get(ctx context.Context, key string) (interface{}, error) { if rc.conn == nil { if err := rc.connectInit(); err != nil { - return nil, nil + return nil, err } } value, err := rc.conn.Get(key) if err == nil { return value, nil } - return nil, nil + return nil, err } // GetMulti gets one or keys values from ssdb. From 6225f0c1e91ae81c5fe1615354655f1fead77e0c Mon Sep 17 00:00:00 2001 From: AllenX2018 Date: Tue, 17 Nov 2020 20:53:33 +0800 Subject: [PATCH 20/29] fix issue 4311 --- client/cache/cache_test.go | 28 +++++++++++++++++++++++++ client/cache/file.go | 24 +++++++++++++-------- client/cache/memcache/memcache.go | 25 ++++++++++++++++------ client/cache/memcache/memcache_test.go | 15 ++++++++++++- client/cache/memory.go | 24 ++++++++++++++------- client/cache/redis/redis_test.go | 8 +++++++ client/cache/ssdb/ssdb.go | 29 +++++++++++++++++++------- client/cache/ssdb/ssdb_test.go | 14 +++++++++++++ 8 files changed, 136 insertions(+), 31 deletions(-) diff --git a/client/cache/cache_test.go b/client/cache/cache_test.go index 6066b72d..bd9b0801 100644 --- a/client/cache/cache_test.go +++ b/client/cache/cache_test.go @@ -120,6 +120,20 @@ func TestCache(t *testing.T) { if vv[1].(string) != "author1" { t.Error("GetMulti ERROR") } + + vv, err = bm.GetMulti(context.Background(), []string{"astaxie0", "astaxie1"}) + if len(vv) != 2 { + t.Error("GetMulti ERROR") + } + if vv[0] != nil { + t.Error("GetMulti ERROR") + } + if vv[1].(string) != "author1" { + t.Error("GetMulti ERROR") + } + if err != nil && err.Error() != "key [astaxie0] error: the key isn't exist" { + t.Error("GetMulti ERROR") + } } func TestFileCache(t *testing.T) { @@ -189,5 +203,19 @@ func TestFileCache(t *testing.T) { t.Error("GetMulti ERROR") } + vv, err = bm.GetMulti(context.Background(), []string{"astaxie0", "astaxie1"}) + if len(vv) != 2 { + t.Error("GetMulti ERROR") + } + if vv[0] != nil { + t.Error("GetMulti ERROR") + } + if vv[1].(string) != "author1" { + t.Error("GetMulti ERROR") + } + if err == nil { + t.Error("GetMulti ERROR") + } + os.RemoveAll("cache") } diff --git a/client/cache/file.go b/client/cache/file.go index dc818258..84ac03c8 100644 --- a/client/cache/file.go +++ b/client/cache/file.go @@ -28,6 +28,7 @@ import ( "path/filepath" "reflect" "strconv" + "strings" "time" "github.com/pkg/errors" @@ -144,17 +145,22 @@ func (fc *FileCache) Get(ctx context.Context, key string) (interface{}, error) { // GetMulti gets values from file cache. // if nonexistent or expired return an empty string. func (fc *FileCache) GetMulti(ctx context.Context, keys []string) ([]interface{}, error) { - var rc []interface{} - for _, key := range keys { - val, err := fc.Get(context.Background(), key) - if err != nil { - rc = append(rc, err) - } else { - rc = append(rc, val) - } + rc := make([]interface{}, len(keys)) + keysErr := make([]string, 0) + for i, ki := range keys { + val, err := fc.Get(context.Background(), ki) + if err != nil { + keysErr = append(keysErr, fmt.Sprintf("key [%s] error: %s", ki, err.Error())) + continue + } + rc[i] = val } - return rc, nil + + if len(keysErr) == 0 { + return rc, nil + } + return rc, errors.New(strings.Join(keysErr, "; ")) } // Put value into file cache. diff --git a/client/cache/memcache/memcache.go b/client/cache/memcache/memcache.go index f3774571..67aedc73 100644 --- a/client/cache/memcache/memcache.go +++ b/client/cache/memcache/memcache.go @@ -33,6 +33,7 @@ import ( "context" "encoding/json" "errors" + "fmt" "strings" "time" @@ -68,19 +69,31 @@ func (rc *Cache) Get(ctx context.Context, key string) (interface{}, error) { // GetMulti gets a value from a key in memcache. func (rc *Cache) GetMulti(ctx context.Context, keys []string) ([]interface{}, error) { - var rv []interface{} + rv := make([]interface{}, len(keys)) if rc.conn == nil { if err := rc.connectInit(); err != nil { return rv, err } } + mv, err := rc.conn.GetMulti(keys) - if err == nil { - for _, v := range mv { - rv = append(rv, v.Value) - } + if err != nil { + return rv, err } - return rv, err + + keysErr := make([]string, 0) + for i, ki := range keys { + if _, ok := mv[ki]; !ok { + keysErr = append(keysErr, fmt.Sprintf("key [%s] error: %s", ki, "the key isn't exist")) + continue + } + rv[i] = mv[ki].Value + } + + if len(keysErr) == 0 { + return rv, nil + } + return rv, fmt.Errorf(strings.Join(keysErr, "; ")) } // Put puts a value into memcache. diff --git a/client/cache/memcache/memcache_test.go b/client/cache/memcache/memcache_test.go index bc8936a7..ca86276e 100644 --- a/client/cache/memcache/memcache_test.go +++ b/client/cache/memcache/memcache_test.go @@ -28,7 +28,6 @@ import ( ) func TestMemcacheCache(t *testing.T) { - addr := os.Getenv("MEMCACHE_ADDR") if addr == "" { addr = "127.0.0.1:11211" @@ -114,6 +113,20 @@ func TestMemcacheCache(t *testing.T) { t.Error("GetMulti ERROR") } + vv, err = bm.GetMulti(context.Background(), []string{"astaxie0", "astaxie1"}) + if len(vv) != 2 { + t.Error("GetMulti ERROR") + } + if vv[0] != nil { + t.Error("GetMulti ERROR") + } + if string(vv[1].([]byte)) != "author1" { + t.Error("GetMulti ERROR") + } + if err != nil && err.Error() == "key [astaxie0] error: key isn't exist" { + t.Error("GetMulti ERROR") + } + // test clear all if err = bm.ClearAll(context.Background()); err != nil { t.Error("clear all err") diff --git a/client/cache/memory.go b/client/cache/memory.go index 6f87ec08..28c7d980 100644 --- a/client/cache/memory.go +++ b/client/cache/memory.go @@ -18,6 +18,8 @@ import ( "context" "encoding/json" "errors" + "fmt" + "strings" "sync" "time" ) @@ -68,22 +70,28 @@ func (bc *MemoryCache) Get(ctx context.Context, key string) (interface{}, error) } return itm.val, nil } - return nil, nil + return nil, errors.New("the key isn't exist") } // GetMulti gets caches from memory. // If non-existent or expired, return nil. func (bc *MemoryCache) GetMulti(ctx context.Context, keys []string) ([]interface{}, error) { - var rc []interface{} - for _, name := range keys { - val, err := bc.Get(context.Background(), name) + rc := make([]interface{}, len(keys)) + keysErr := make([]string, 0) + + for i, ki := range keys { + val, err := bc.Get(context.Background(), ki) if err != nil { - rc = append(rc, err) - } else { - rc = append(rc, val) + keysErr = append(keysErr, fmt.Sprintf("key [%s] error: %s", ki, err.Error())) + continue } + rc[i] = val } - return rc, nil + + if len(keysErr) == 0 { + return rc, nil + } + return rc, errors.New(strings.Join(keysErr, "; ")) } // Put puts cache into memory. diff --git a/client/cache/redis/redis_test.go b/client/cache/redis/redis_test.go index f82b2c40..75ba50c5 100644 --- a/client/cache/redis/redis_test.go +++ b/client/cache/redis/redis_test.go @@ -113,6 +113,14 @@ func TestRedisCache(t *testing.T) { t.Error("GetMulti ERROR") } + vv, err = bm.GetMulti(context.Background(), []string{"astaxie0", "astaxie1"}) + if vv[0] != nil { + t.Error("GetMulti ERROR") + } + if v, _ := redis.String(vv[1], nil); v != "author1" { + t.Error("GetMulti ERROR") + } + // test clear all if err = bm.ClearAll(context.Background()); err != nil { t.Error("clear all err") diff --git a/client/cache/ssdb/ssdb.go b/client/cache/ssdb/ssdb.go index def9273d..8d9d2b35 100644 --- a/client/cache/ssdb/ssdb.go +++ b/client/cache/ssdb/ssdb.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "errors" + "fmt" "strconv" "strings" "time" @@ -41,23 +42,37 @@ func (rc *Cache) Get(ctx context.Context, key string) (interface{}, error) { // GetMulti gets one or keys values from ssdb. func (rc *Cache) GetMulti(ctx context.Context, keys []string) ([]interface{}, error) { size := len(keys) - var values []interface{} + values := make([]interface{}, size) if rc.conn == nil { if err := rc.connectInit(); err != nil { return values, err } } + res, err := rc.conn.Do("multi_get", keys) + if err != nil { + return values, err + } + resSize := len(res) - if err == nil { - for i := 1; i < resSize; i += 2 { - values = append(values, res[i+1]) + keyIdx := make(map[string]int) + for i := 1; i < resSize; i += 2 { + keyIdx[res[i]] = i + } + + keysErr := make([]string, 0) + for i, ki := range keys { + if _, ok := keyIdx[ki]; !ok { + keysErr = append(keysErr, fmt.Sprintf("key [%s] error: %s", ki, "the key isn't exist")) + continue } - return values, nil + values[i] = res[keyIdx[ki]+1] } - for i := 0; i < size; i++ { - values = append(values, err) + + if len(keysErr) != 0 { + return values, fmt.Errorf(strings.Join(keysErr, "; ")) } + return values, nil } diff --git a/client/cache/ssdb/ssdb_test.go b/client/cache/ssdb/ssdb_test.go index cebaa975..b23871ca 100644 --- a/client/cache/ssdb/ssdb_test.go +++ b/client/cache/ssdb/ssdb_test.go @@ -106,6 +106,20 @@ func TestSsdbcacheCache(t *testing.T) { t.Error("getmulti error") } + vv, err = ssdb.GetMulti(context.Background(), []string{"ssdb", "ssdb11"}) + if len(vv) != 2 { + t.Error("getmulti error") + } + if vv[0].(string) != "ssdb" { + t.Error("getmulti error") + } + if vv[1] != nil { + t.Error("getmulti error") + } + if err != nil && err.Error() != "key [ssdb11] error: the key isn't exist" { + t.Error("getmulti error") + } + // test clear all done if err = ssdb.ClearAll(context.Background()); err != nil { t.Error("clear all err") From c6282e7b279942909a87a88951f1a69db94e0b15 Mon Sep 17 00:00:00 2001 From: AllenX2018 Date: Wed, 18 Nov 2020 09:56:56 +0800 Subject: [PATCH 21/29] remove ineffectual assignment to err --- client/cache/redis/redis_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/cache/redis/redis_test.go b/client/cache/redis/redis_test.go index 75ba50c5..c8cf0024 100644 --- a/client/cache/redis/redis_test.go +++ b/client/cache/redis/redis_test.go @@ -113,7 +113,7 @@ func TestRedisCache(t *testing.T) { t.Error("GetMulti ERROR") } - vv, err = bm.GetMulti(context.Background(), []string{"astaxie0", "astaxie1"}) + vv, _ = bm.GetMulti(context.Background(), []string{"astaxie0", "astaxie1"}) if vv[0] != nil { t.Error("GetMulti ERROR") } From 0958174bc8ea8c51ac73244bdfdaaa8618336cd1 Mon Sep 17 00:00:00 2001 From: Ming Deng Date: Thu, 12 Nov 2020 21:36:11 +0800 Subject: [PATCH 22/29] update doc --- README.md | 19 +++++++++++++++++-- core/config/global.go | 1 - 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 934fc429..0c9bfc15 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,22 @@ beego is used for rapid development of RESTful APIs, web apps and backend services in Go. It is inspired by Tornado, Sinatra and Flask. beego has some Go-specific features such as interfaces and struct embedding. -###### More info at [beego.me](http://beego.me). +###### More info at [beego.me](http://beego.me). + +> If you could not open this website, go to [beedoc](https://github.com/beego/beedoc) + +## beego 1.x and 2.x + +We recently release beego 2.0.0-beta, and its structure change a lot, so you may get some error + +1. If you are working on beego v1.x please try `go get github.com/astaxie/beego@v1.12.3` +2. If you want to try beego 2.0.0, run `go get github.com/astaxie/beego@develop` + +We are still working on fix bug and documentation of v2.x. And v2.x's doc will be released with v2.0.0. + +## Next version + +v1.12.4 will be released on Jan 2021 And v2.0.0 will be released next month. ## Quick Start @@ -25,7 +40,7 @@ It is inspired by Tornado, Sinatra and Flask. beego has some Go-specific feature #### Download and install - go get github.com/astaxie/beego + go get -u github.com/astaxie/beego #### Create file `hello.go` ```go diff --git a/core/config/global.go b/core/config/global.go index 5491fe2c..a7fb795f 100644 --- a/core/config/global.go +++ b/core/config/global.go @@ -18,7 +18,6 @@ package config // for most users, they only need to use those methods var globalInstance Configer - // InitGlobalInstance will ini the global instance // If you want to use specific implementation, don't forget to import it. // e.g. _ import "github.com/astaxie/beego/core/config/etcd" From 00ed1c3733871c6d46343365d49ad0c1ec3f7a39 Mon Sep 17 00:00:00 2001 From: Ming Deng Date: Wed, 25 Nov 2020 20:13:23 +0800 Subject: [PATCH 23/29] change the globalInstance to read conf/app.conf --- core/config/ini.go | 2 +- server/web/router.go | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/core/config/ini.go b/core/config/ini.go index 4d17fb7a..70d00980 100644 --- a/core/config/ini.go +++ b/core/config/ini.go @@ -519,7 +519,7 @@ func (c *IniConfigContainer) Unmarshaler(prefix string, obj interface{}, opt ... func init() { Register("ini", &IniConfig{}) - err := InitGlobalInstance("ini", "config/app.conf") + err := InitGlobalInstance("ini", "conf/app.conf") if err != nil { logs.Warn("init global config instance failed. If you donot use this, just ignore it. ", err) } diff --git a/server/web/router.go b/server/web/router.go index 7bb89d82..d729013b 100644 --- a/server/web/router.go +++ b/server/web/router.go @@ -273,7 +273,6 @@ 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) } } From 4afa9d2d259320fc4b6f5c4deeb81730383079c1 Mon Sep 17 00:00:00 2001 From: Ming Deng Date: Thu, 26 Nov 2020 23:49:37 +0800 Subject: [PATCH 24/29] Update readme --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0c9bfc15..446ad15b 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,9 @@ v1.12.4 will be released on Jan 2021 And v2.0.0 will be released next month. #### Download and install - go get -u github.com/astaxie/beego + go get -u github.com/astaxie/beego@develop + +Now we are working on beego v2.0.0, so using `@develop`. #### Create file `hello.go` ```go From 8d7f48ea75f97886e6dd9ef62f455d8b9b48c661 Mon Sep 17 00:00:00 2001 From: Ming Deng Date: Sun, 29 Nov 2020 21:16:53 +0800 Subject: [PATCH 25/29] expose more error code in web module --- adapter/controller.go | 3 +- adapter/session/session.go | 2 +- client/orm/utils.go | 4 +- client/orm/utils_test.go | 2 +- server/web/context/output.go | 8 ++-- server/web/controller.go | 71 ++++++++++++++++++++++------------- server/web/session/session.go | 26 ++++++++++--- 7 files changed, 74 insertions(+), 42 deletions(-) diff --git a/adapter/controller.go b/adapter/controller.go index 14dc9b97..a56d1743 100644 --- a/adapter/controller.go +++ b/adapter/controller.go @@ -212,7 +212,8 @@ func (c *Controller) ServeFormatted(encoding ...bool) { // Input returns the input data map from POST or PUT request body and query string. func (c *Controller) Input() url.Values { - return (*web.Controller)(c).Input() + val, _ := (*web.Controller)(c).Input() + return val } // ParseForm maps input data map to obj struct. diff --git a/adapter/session/session.go b/adapter/session/session.go index d8b151b7..72eeb080 100644 --- a/adapter/session/session.go +++ b/adapter/session/session.go @@ -141,7 +141,7 @@ func (manager *Manager) GC() { // SessionRegenerateID Regenerate a session id for this SessionStore who's id is saving in http request. func (manager *Manager) SessionRegenerateID(w http.ResponseWriter, r *http.Request) Store { - s := (*session.Manager)(manager).SessionRegenerateID(w, r) + s, _ := (*session.Manager)(manager).SessionRegenerateID(w, r) return &NewToOldStoreAdapter{ delegate: s, } diff --git a/client/orm/utils.go b/client/orm/utils.go index 3ff76772..d6c0a8e8 100644 --- a/client/orm/utils.go +++ b/client/orm/utils.go @@ -49,12 +49,12 @@ func (f *StrTo) Set(v string) { // Clear string func (f *StrTo) Clear() { - *f = StrTo(0x1E) + *f = StrTo(rune(0x1E)) } // Exist check string exist func (f StrTo) Exist() bool { - return string(f) != string(0x1E) + return string(f) != string(rune(0x1E)) } // Bool string to bool diff --git a/client/orm/utils_test.go b/client/orm/utils_test.go index 7d94cada..fa75258a 100644 --- a/client/orm/utils_test.go +++ b/client/orm/utils_test.go @@ -67,4 +67,4 @@ func TestSnakeStringWithAcronym(t *testing.T) { t.Error("Unit Test Fail:", v, res, answer[v]) } } -} +} \ No newline at end of file diff --git a/server/web/context/output.go b/server/web/context/output.go index a6e83681..28ff2819 100644 --- a/server/web/context/output.go +++ b/server/web/context/output.go @@ -261,15 +261,15 @@ func (output *BeegoOutput) XML(data interface{}, hasIndent bool) error { } // ServeFormatted serves YAML, XML or JSON, depending on the value of the Accept header -func (output *BeegoOutput) ServeFormatted(data interface{}, hasIndent bool, hasEncode ...bool) { +func (output *BeegoOutput) ServeFormatted(data interface{}, hasIndent bool, hasEncode ...bool) error { accept := output.Context.Input.Header("Accept") switch accept { case ApplicationYAML: - output.YAML(data) + return output.YAML(data) case ApplicationXML, TextXML: - output.XML(data, hasIndent) + return output.XML(data, hasIndent) default: - output.JSON(data, hasIndent, len(hasEncode) > 0 && hasEncode[0]) + return output.JSON(data, hasIndent, len(hasEncode) > 0 && hasEncode[0]) } } diff --git a/server/web/controller.go b/server/web/controller.go index 3a1b9837..f363c655 100644 --- a/server/web/controller.go +++ b/server/web/controller.go @@ -16,6 +16,7 @@ package web import ( "bytes" + context2 "context" "errors" "fmt" "html/template" @@ -250,13 +251,16 @@ func (c *Controller) Render() error { // RenderString returns the rendered template string. Do not send out response. func (c *Controller) RenderString() (string, error) { b, e := c.RenderBytes() + if e != nil { + return "", e + } return string(b), e } // RenderBytes returns the bytes of rendered template string. Do not send out response. func (c *Controller) RenderBytes() ([]byte, error) { buf, err := c.renderTemplate() - //if the controller has set layout, then first get the tplName's content set the content to the layout + // if the controller has set layout, then first get the tplName's content set the content to the layout if err == nil && c.Layout != "" { c.Data["LayoutContent"] = template.HTML(buf.String()) @@ -276,7 +280,7 @@ func (c *Controller) RenderBytes() ([]byte, error) { } buf.Reset() - ExecuteViewPathTemplate(&buf, c.Layout, c.viewPath(), c.Data) + err = ExecuteViewPathTemplate(&buf, c.Layout, c.viewPath(), c.Data) } return buf.Bytes(), err } @@ -373,50 +377,57 @@ func (c *Controller) URLFor(endpoint string, values ...interface{}) string { } // ServeJSON sends a json response with encoding charset. -func (c *Controller) ServeJSON(encoding ...bool) { +func (c *Controller) ServeJSON(encoding ...bool) error { var ( hasIndent = BConfig.RunMode != PROD hasEncoding = len(encoding) > 0 && encoding[0] ) - c.Ctx.Output.JSON(c.Data["json"], hasIndent, hasEncoding) + return c.Ctx.Output.JSON(c.Data["json"], hasIndent, hasEncoding) } // ServeJSONP sends a jsonp response. -func (c *Controller) ServeJSONP() { +func (c *Controller) ServeJSONP() error { hasIndent := BConfig.RunMode != PROD - c.Ctx.Output.JSONP(c.Data["jsonp"], hasIndent) + return c.Ctx.Output.JSONP(c.Data["jsonp"], hasIndent) } // ServeXML sends xml response. -func (c *Controller) ServeXML() { +func (c *Controller) ServeXML() error { hasIndent := BConfig.RunMode != PROD - c.Ctx.Output.XML(c.Data["xml"], hasIndent) + return c.Ctx.Output.XML(c.Data["xml"], hasIndent) } // ServeYAML sends yaml response. -func (c *Controller) ServeYAML() { - c.Ctx.Output.YAML(c.Data["yaml"]) +func (c *Controller) ServeYAML() error { + return c.Ctx.Output.YAML(c.Data["yaml"]) } // ServeFormatted serve YAML, XML OR JSON, depending on the value of the Accept header -func (c *Controller) ServeFormatted(encoding ...bool) { +func (c *Controller) ServeFormatted(encoding ...bool) error { hasIndent := BConfig.RunMode != PROD hasEncoding := len(encoding) > 0 && encoding[0] - c.Ctx.Output.ServeFormatted(c.Data, hasIndent, hasEncoding) + return c.Ctx.Output.ServeFormatted(c.Data, hasIndent, hasEncoding) } // Input returns the input data map from POST or PUT request body and query string. -func (c *Controller) Input() url.Values { +func (c *Controller) Input() (url.Values, error) { if c.Ctx.Request.Form == nil { - c.Ctx.Request.ParseForm() + err := c.Ctx.Request.ParseForm() + if err != nil { + return nil, err + } } - return c.Ctx.Request.Form + return c.Ctx.Request.Form, nil } // ParseForm maps input data map to obj struct. func (c *Controller) ParseForm(obj interface{}) error { - return ParseForm(c.Input(), obj) + form, err := c.Input() + if err != nil { + return err + } + return ParseForm(form, obj) } // GetString returns the input value by key string or the default value while it's present and input is blank @@ -438,7 +449,7 @@ func (c *Controller) GetStrings(key string, def ...[]string) []string { defv = def[0] } - if f := c.Input(); f == nil { + if f, err := c.Input(); f == nil || err != nil { return defv } else if vs := f[key]; len(vs) > 0 { return vs @@ -618,11 +629,11 @@ func (c *Controller) StartSession() session.Store { } // SetSession puts value into session. -func (c *Controller) SetSession(name interface{}, value interface{}) { +func (c *Controller) SetSession(name interface{}, value interface{}) error { if c.CruSession == nil { c.StartSession() } - c.CruSession.Set(nil, name, value) + return c.CruSession.Set(context2.Background(), name, value) } // GetSession gets value from session. @@ -630,32 +641,38 @@ func (c *Controller) GetSession(name interface{}) interface{} { if c.CruSession == nil { c.StartSession() } - return c.CruSession.Get(nil, name) + return c.CruSession.Get(context2.Background(), name) } // DelSession removes value from session. -func (c *Controller) DelSession(name interface{}) { +func (c *Controller) DelSession(name interface{}) error { if c.CruSession == nil { c.StartSession() } - c.CruSession.Delete(nil, name) + return c.CruSession.Delete(context2.Background(), name) } // SessionRegenerateID regenerates session id for this session. // the session data have no changes. -func (c *Controller) SessionRegenerateID() { +func (c *Controller) SessionRegenerateID() error { if c.CruSession != nil { - c.CruSession.SessionRelease(nil, c.Ctx.ResponseWriter) + c.CruSession.SessionRelease(context2.Background(), c.Ctx.ResponseWriter) } - c.CruSession = GlobalSessions.SessionRegenerateID(c.Ctx.ResponseWriter, c.Ctx.Request) + var err error + c.CruSession, err = GlobalSessions.SessionRegenerateID(c.Ctx.ResponseWriter, c.Ctx.Request) c.Ctx.Input.CruSession = c.CruSession + return err } // DestroySession cleans session data and session cookie. -func (c *Controller) DestroySession() { - c.Ctx.Input.CruSession.Flush(nil) +func (c *Controller) DestroySession() error { + err := c.Ctx.Input.CruSession.Flush(nil) + if err != nil { + return err + } c.Ctx.Input.CruSession = nil GlobalSessions.SessionDestroy(c.Ctx.ResponseWriter, c.Ctx.Request) + return nil } // IsAjax returns this request is ajax or not. diff --git a/server/web/session/session.go b/server/web/session/session.go index bb7e5bd6..60fc0e00 100644 --- a/server/web/session/session.go +++ b/server/web/session/session.go @@ -298,15 +298,21 @@ func (manager *Manager) GC() { } // SessionRegenerateID Regenerate a session id for this SessionStore who's id is saving in http request. -func (manager *Manager) SessionRegenerateID(w http.ResponseWriter, r *http.Request) (session Store) { +func (manager *Manager) SessionRegenerateID(w http.ResponseWriter, r *http.Request) (Store, error) { sid, err := manager.sessionID() if err != nil { - return + return nil, err } + + var session Store + cookie, err := r.Cookie(manager.config.CookieName) if err != nil || cookie.Value == "" { //delete old cookie - session, _ = manager.provider.SessionRead(nil, sid) + session, err = manager.provider.SessionRead(nil, sid) + if err != nil { + return nil, err + } cookie = &http.Cookie{Name: manager.config.CookieName, Value: url.QueryEscape(sid), Path: "/", @@ -315,8 +321,16 @@ func (manager *Manager) SessionRegenerateID(w http.ResponseWriter, r *http.Reque Domain: manager.config.Domain, } } else { - oldsid, _ := url.QueryUnescape(cookie.Value) - session, _ = manager.provider.SessionRegenerate(nil, oldsid, sid) + oldsid, err := url.QueryUnescape(cookie.Value) + if err != nil { + return nil, err + } + + session, err = manager.provider.SessionRegenerate(nil, oldsid, sid) + if err != nil { + return nil, err + } + cookie.Value = url.QueryEscape(sid) cookie.HttpOnly = true cookie.Path = "/" @@ -335,7 +349,7 @@ func (manager *Manager) SessionRegenerateID(w http.ResponseWriter, r *http.Reque w.Header().Set(manager.config.SessionNameInHTTPHeader, sid) } - return + return session, nil } // GetActiveSession Get all active sessions count number. From 59ca0d063f370ee1a1ec1a8134a4e1f96810cab5 Mon Sep 17 00:00:00 2001 From: Anker Jam Date: Sun, 29 Nov 2020 23:39:58 +0800 Subject: [PATCH 26/29] fix dot parsing result in route & delete useless testing file --- adapter/tree_test.go | 249 ---------------------------------------- server/web/tree_test.go | 144 ++++++++++++++--------- 2 files changed, 88 insertions(+), 305 deletions(-) delete mode 100644 adapter/tree_test.go diff --git a/adapter/tree_test.go b/adapter/tree_test.go deleted file mode 100644 index 2315d829..00000000 --- a/adapter/tree_test.go +++ /dev/null @@ -1,249 +0,0 @@ -// Copyright 2014 beego Author. All Rights Reserved. -// -// 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 adapter - -import ( - "testing" - - "github.com/astaxie/beego/adapter/context" - beecontext "github.com/astaxie/beego/server/web/context" -) - -type testinfo struct { - url string - requesturl string - params map[string]string -} - -var routers []testinfo - -func init() { - routers = make([]testinfo, 0) - routers = append(routers, testinfo{"/topic/?:auth:int", "/topic", nil}) - routers = append(routers, testinfo{"/topic/?:auth:int", "/topic/123", map[string]string{":auth": "123"}}) - routers = append(routers, testinfo{"/topic/:id/?:auth", "/topic/1", map[string]string{":id": "1"}}) - routers = append(routers, testinfo{"/topic/:id/?:auth", "/topic/1/2", map[string]string{":id": "1", ":auth": "2"}}) - routers = append(routers, testinfo{"/topic/:id/?:auth:int", "/topic/1", map[string]string{":id": "1"}}) - routers = append(routers, testinfo{"/topic/:id/?:auth:int", "/topic/1/123", map[string]string{":id": "1", ":auth": "123"}}) - routers = append(routers, testinfo{"/:id", "/123", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/hello/?:id", "/hello", map[string]string{":id": ""}}) - routers = append(routers, testinfo{"/", "/", nil}) - routers = append(routers, testinfo{"/customer/login", "/customer/login", nil}) - routers = append(routers, testinfo{"/customer/login", "/customer/login.json", map[string]string{":ext": "json"}}) - routers = append(routers, testinfo{"/*", "/http://customer/123/", map[string]string{":splat": "http://customer/123/"}}) - routers = append(routers, testinfo{"/*", "/customer/2009/12/11", map[string]string{":splat": "customer/2009/12/11"}}) - routers = append(routers, testinfo{"/aa/*/bb", "/aa/2009/bb", map[string]string{":splat": "2009"}}) - routers = append(routers, testinfo{"/cc/*/dd", "/cc/2009/11/dd", map[string]string{":splat": "2009/11"}}) - routers = append(routers, testinfo{"/cc/:id/*", "/cc/2009/11/dd", map[string]string{":id": "2009", ":splat": "11/dd"}}) - routers = append(routers, testinfo{"/ee/:year/*/ff", "/ee/2009/11/ff", map[string]string{":year": "2009", ":splat": "11"}}) - routers = append(routers, testinfo{"/thumbnail/:size/uploads/*", - "/thumbnail/100x100/uploads/items/2014/04/20/dPRCdChkUd651t1Hvs18.jpg", - map[string]string{":size": "100x100", ":splat": "items/2014/04/20/dPRCdChkUd651t1Hvs18.jpg"}}) - routers = append(routers, testinfo{"/*.*", "/nice/api.json", map[string]string{":path": "nice/api", ":ext": "json"}}) - routers = append(routers, testinfo{"/:name/*.*", "/nice/api.json", map[string]string{":name": "nice", ":path": "api", ":ext": "json"}}) - routers = append(routers, testinfo{"/:name/test/*.*", "/nice/test/api.json", map[string]string{":name": "nice", ":path": "api", ":ext": "json"}}) - routers = append(routers, testinfo{"/dl/:width:int/:height:int/*.*", - "/dl/48/48/05ac66d9bda00a3acf948c43e306fc9a.jpg", - map[string]string{":width": "48", ":height": "48", ":ext": "jpg", ":path": "05ac66d9bda00a3acf948c43e306fc9a"}}) - routers = append(routers, testinfo{"/v1/shop/:id:int", "/v1/shop/123", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/v1/shop/:id\\((a|b|c)\\)", "/v1/shop/123(a)", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/v1/shop/:id\\((a|b|c)\\)", "/v1/shop/123(b)", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/v1/shop/:id\\((a|b|c)\\)", "/v1/shop/123(c)", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/:year:int/:month:int/:id/:endid", "/1111/111/aaa/aaa", map[string]string{":year": "1111", ":month": "111", ":id": "aaa", ":endid": "aaa"}}) - routers = append(routers, testinfo{"/v1/shop/:id/:name", "/v1/shop/123/nike", map[string]string{":id": "123", ":name": "nike"}}) - routers = append(routers, testinfo{"/v1/shop/:id/account", "/v1/shop/123/account", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/v1/shop/:name:string", "/v1/shop/nike", map[string]string{":name": "nike"}}) - routers = append(routers, testinfo{"/v1/shop/:id([0-9]+)", "/v1/shop//123", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/v1/shop/:id([0-9]+)_:name", "/v1/shop/123_nike", map[string]string{":id": "123", ":name": "nike"}}) - routers = append(routers, testinfo{"/v1/shop/:id(.+)_cms.html", "/v1/shop/123_cms.html", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/v1/shop/cms_:id(.+)_:page(.+).html", "/v1/shop/cms_123_1.html", map[string]string{":id": "123", ":page": "1"}}) - routers = append(routers, testinfo{"/v1/:v/cms/aaa_:id(.+)_:page(.+).html", "/v1/2/cms/aaa_123_1.html", map[string]string{":v": "2", ":id": "123", ":page": "1"}}) - routers = append(routers, testinfo{"/v1/:v/cms_:id(.+)_:page(.+).html", "/v1/2/cms_123_1.html", map[string]string{":v": "2", ":id": "123", ":page": "1"}}) - routers = append(routers, testinfo{"/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, testinfo{"/api/projects/:pid/members/?:mid", "/api/projects/1/members", map[string]string{":pid": "1"}}) - routers = append(routers, testinfo{"/api/projects/:pid/members/?:mid", "/api/projects/1/members/2", map[string]string{":pid": "1", ":mid": "2"}}) -} - -func TestTreeRouters(t *testing.T) { - for _, r := range routers { - tr := NewTree() - tr.AddRouter(r.url, "astaxie") - ctx := context.NewContext() - obj := tr.Match(r.requesturl, ctx) - if obj == nil || obj.(string) != "astaxie" { - t.Fatal(r.url+" can't get obj, Expect ", r.requesturl) - } - if r.params != nil { - for k, v := range r.params { - if vv := ctx.Input.Param(k); vv != v { - t.Fatal("The Rule: " + r.url + "\nThe RequestURL:" + r.requesturl + "\nThe Key is " + k + ", The Value should be: " + v + ", but get: " + vv) - } else if vv == "" && v != "" { - t.Fatal(r.url + " " + r.requesturl + " get param empty:" + k) - } - } - } - } -} - -func TestStaticPath(t *testing.T) { - tr := NewTree() - tr.AddRouter("/topic/:id", "wildcard") - tr.AddRouter("/topic", "static") - ctx := context.NewContext() - obj := tr.Match("/topic", ctx) - if obj == nil || obj.(string) != "static" { - t.Fatal("/topic is a static route") - } - obj = tr.Match("/topic/1", ctx) - if obj == nil || obj.(string) != "wildcard" { - t.Fatal("/topic/1 is a wildcard route") - } -} - -func TestAddTree(t *testing.T) { - tr := NewTree() - tr.AddRouter("/shop/:id/account", "astaxie") - tr.AddRouter("/shop/:sd/ttt_:id(.+)_:page(.+).html", "astaxie") - t1 := NewTree() - t1.AddTree("/v1/zl", tr) - ctx := context.NewContext() - obj := t1.Match("/v1/zl/shop/123/account", ctx) - if obj == nil || obj.(string) != "astaxie" { - t.Fatal("/v1/zl/shop/:id/account can't get obj ") - } - if ctx.Input.ParamsLen() == 0 { - t.Fatal("get param error") - } - if ctx.Input.Param(":id") != "123" { - t.Fatal("get :id param error") - } - ctx.Input.Reset((*beecontext.Context)(ctx)) - obj = t1.Match("/v1/zl/shop/123/ttt_1_12.html", ctx) - if obj == nil || obj.(string) != "astaxie" { - t.Fatal("/v1/zl//shop/:sd/ttt_:id(.+)_:page(.+).html can't get obj ") - } - if ctx.Input.ParamsLen() == 0 { - t.Fatal("get param error") - } - if ctx.Input.Param(":sd") != "123" || ctx.Input.Param(":id") != "1" || ctx.Input.Param(":page") != "12" { - t.Fatal("get :sd :id :page param error") - } - - t2 := NewTree() - t2.AddTree("/v1/:shopid", tr) - ctx.Input.Reset((*beecontext.Context)(ctx)) - obj = t2.Match("/v1/zl/shop/123/account", ctx) - if obj == nil || obj.(string) != "astaxie" { - t.Fatal("/v1/:shopid/shop/:id/account can't get obj ") - } - if ctx.Input.ParamsLen() == 0 { - t.Fatal("get param error") - } - if ctx.Input.Param(":id") != "123" || ctx.Input.Param(":shopid") != "zl" { - t.Fatal("get :id :shopid param error") - } - ctx.Input.Reset((*beecontext.Context)(ctx)) - obj = t2.Match("/v1/zl/shop/123/ttt_1_12.html", ctx) - if obj == nil || obj.(string) != "astaxie" { - t.Fatal("/v1/:shopid/shop/:sd/ttt_:id(.+)_:page(.+).html can't get obj ") - } - if ctx.Input.ParamsLen() == 0 { - t.Fatal("get :shopid param error") - } - if ctx.Input.Param(":sd") != "123" || ctx.Input.Param(":id") != "1" || ctx.Input.Param(":page") != "12" || ctx.Input.Param(":shopid") != "zl" { - t.Fatal("get :sd :id :page :shopid param error") - } -} - -func TestAddTree2(t *testing.T) { - tr := NewTree() - tr.AddRouter("/shop/:id/account", "astaxie") - tr.AddRouter("/shop/:sd/ttt_:id(.+)_:page(.+).html", "astaxie") - t3 := NewTree() - t3.AddTree("/:version(v1|v2)/:prefix", tr) - ctx := context.NewContext() - obj := t3.Match("/v1/zl/shop/123/account", ctx) - if obj == nil || obj.(string) != "astaxie" { - t.Fatal("/:version(v1|v2)/:prefix/shop/:id/account can't get obj ") - } - if ctx.Input.ParamsLen() == 0 { - t.Fatal("get param error") - } - if ctx.Input.Param(":id") != "123" || ctx.Input.Param(":prefix") != "zl" || ctx.Input.Param(":version") != "v1" { - t.Fatal("get :id :prefix :version param error") - } -} - -func TestAddTree3(t *testing.T) { - tr := NewTree() - tr.AddRouter("/create", "astaxie") - tr.AddRouter("/shop/:sd/account", "astaxie") - t3 := NewTree() - t3.AddTree("/table/:num", tr) - ctx := context.NewContext() - obj := t3.Match("/table/123/shop/123/account", ctx) - if obj == nil || obj.(string) != "astaxie" { - t.Fatal("/table/:num/shop/:sd/account can't get obj ") - } - if ctx.Input.ParamsLen() == 0 { - t.Fatal("get param error") - } - if ctx.Input.Param(":num") != "123" || ctx.Input.Param(":sd") != "123" { - t.Fatal("get :num :sd param error") - } - ctx.Input.Reset((*beecontext.Context)(ctx)) - obj = t3.Match("/table/123/create", ctx) - if obj == nil || obj.(string) != "astaxie" { - t.Fatal("/table/:num/create can't get obj ") - } -} - -func TestAddTree4(t *testing.T) { - tr := NewTree() - tr.AddRouter("/create", "astaxie") - tr.AddRouter("/shop/:sd/:account", "astaxie") - t4 := NewTree() - t4.AddTree("/:info:int/:num/:id", tr) - ctx := context.NewContext() - obj := t4.Match("/12/123/456/shop/123/account", ctx) - if obj == nil || obj.(string) != "astaxie" { - t.Fatal("/:info:int/:num/:id/shop/:sd/:account can't get obj ") - } - if ctx.Input.ParamsLen() == 0 { - t.Fatal("get param error") - } - if ctx.Input.Param(":info") != "12" || ctx.Input.Param(":num") != "123" || - ctx.Input.Param(":id") != "456" || ctx.Input.Param(":sd") != "123" || - ctx.Input.Param(":account") != "account" { - t.Fatal("get :info :num :id :sd :account param error") - } - ctx.Input.Reset((*beecontext.Context)(ctx)) - obj = t4.Match("/12/123/456/create", ctx) - if obj == nil || obj.(string) != "astaxie" { - t.Fatal("/:info:int/:num/:id/create can't get obj ") - } -} - -// Test for issue #1595 -func TestAddTree5(t *testing.T) { - tr := NewTree() - tr.AddRouter("/v1/shop/:id", "shopdetail") - tr.AddRouter("/v1/shop/", "shophome") - ctx := context.NewContext() - obj := tr.Match("/v1/shop/", ctx) - if obj == nil || obj.(string) != "shophome" { - t.Fatal("url /v1/shop/ need match router /v1/shop/ ") - } -} diff --git a/server/web/tree_test.go b/server/web/tree_test.go index e72bc1f9..b6b3d52a 100644 --- a/server/web/tree_test.go +++ b/server/web/tree_test.go @@ -21,76 +21,109 @@ import ( "github.com/astaxie/beego/server/web/context" ) -type testinfo struct { - url string - requesturl string - params map[string]string +type testInfo struct { + pattern string + requestUrl string + params map[string]string + shouldMatchOrNot bool } -var routers []testinfo +var routers []testInfo + +func matchTestInfo(pattern, url string, params map[string]string) testInfo { + return testInfo{ + pattern: pattern, + requestUrl: url, + params: params, + shouldMatchOrNot: true, + } +} + +func notMatchTestInfo(pattern, url string) testInfo { + return testInfo{ + pattern: pattern, + requestUrl: url, + params: nil, + shouldMatchOrNot: false, + } +} func init() { - routers = make([]testinfo, 0) - routers = append(routers, testinfo{"/topic/?:auth:int", "/topic", nil}) - routers = append(routers, testinfo{"/topic/?:auth:int", "/topic/123", map[string]string{":auth": "123"}}) - routers = append(routers, testinfo{"/topic/:id/?:auth", "/topic/1", map[string]string{":id": "1"}}) - routers = append(routers, testinfo{"/topic/:id/?:auth", "/topic/1/2", map[string]string{":id": "1", ":auth": "2"}}) - routers = append(routers, testinfo{"/topic/:id/?:auth:int", "/topic/1", map[string]string{":id": "1"}}) - routers = append(routers, testinfo{"/topic/:id/?:auth:int", "/topic/1/123", map[string]string{":id": "1", ":auth": "123"}}) - routers = append(routers, testinfo{"/:id", "/123", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/hello/?:id", "/hello", map[string]string{":id": ""}}) - routers = append(routers, testinfo{"/", "/", nil}) - routers = append(routers, testinfo{"/customer/login", "/customer/login", nil}) - routers = append(routers, testinfo{"/customer/login", "/customer/login.json", map[string]string{":ext": "json"}}) - routers = append(routers, testinfo{"/*", "/http://customer/123/", map[string]string{":splat": "http://customer/123/"}}) - routers = append(routers, testinfo{"/*", "/customer/2009/12/11", map[string]string{":splat": "customer/2009/12/11"}}) - routers = append(routers, testinfo{"/aa/*/bb", "/aa/2009/bb", map[string]string{":splat": "2009"}}) - routers = append(routers, testinfo{"/cc/*/dd", "/cc/2009/11/dd", map[string]string{":splat": "2009/11"}}) - routers = append(routers, testinfo{"/cc/:id/*", "/cc/2009/11/dd", map[string]string{":id": "2009", ":splat": "11/dd"}}) - routers = append(routers, testinfo{"/ee/:year/*/ff", "/ee/2009/11/ff", map[string]string{":year": "2009", ":splat": "11"}}) - routers = append(routers, testinfo{"/thumbnail/:size/uploads/*", - "/thumbnail/100x100/uploads/items/2014/04/20/dPRCdChkUd651t1Hvs18.jpg", - map[string]string{":size": "100x100", ":splat": "items/2014/04/20/dPRCdChkUd651t1Hvs18.jpg"}}) - routers = append(routers, testinfo{"/*.*", "/nice/api.json", map[string]string{":path": "nice/api", ":ext": "json"}}) - routers = append(routers, testinfo{"/:name/*.*", "/nice/api.json", map[string]string{":name": "nice", ":path": "api", ":ext": "json"}}) - routers = append(routers, testinfo{"/:name/test/*.*", "/nice/test/api.json", map[string]string{":name": "nice", ":path": "api", ":ext": "json"}}) - routers = append(routers, testinfo{"/dl/:width:int/:height:int/*.*", - "/dl/48/48/05ac66d9bda00a3acf948c43e306fc9a.jpg", - map[string]string{":width": "48", ":height": "48", ":ext": "jpg", ":path": "05ac66d9bda00a3acf948c43e306fc9a"}}) - routers = append(routers, testinfo{"/v1/shop/:id:int", "/v1/shop/123", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/v1/shop/:id\\((a|b|c)\\)", "/v1/shop/123(a)", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/v1/shop/:id\\((a|b|c)\\)", "/v1/shop/123(b)", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/v1/shop/:id\\((a|b|c)\\)", "/v1/shop/123(c)", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/:year:int/:month:int/:id/:endid", "/1111/111/aaa/aaa", map[string]string{":year": "1111", ":month": "111", ":id": "aaa", ":endid": "aaa"}}) - routers = append(routers, testinfo{"/v1/shop/:id/:name", "/v1/shop/123/nike", map[string]string{":id": "123", ":name": "nike"}}) - routers = append(routers, testinfo{"/v1/shop/:id/account", "/v1/shop/123/account", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/v1/shop/:name:string", "/v1/shop/nike", map[string]string{":name": "nike"}}) - routers = append(routers, testinfo{"/v1/shop/:id([0-9]+)", "/v1/shop//123", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/v1/shop/:id([0-9]+)_:name", "/v1/shop/123_nike", map[string]string{":id": "123", ":name": "nike"}}) - routers = append(routers, testinfo{"/v1/shop/:id(.+)_cms.html", "/v1/shop/123_cms.html", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/v1/shop/cms_:id(.+)_:page(.+).html", "/v1/shop/cms_123_1.html", map[string]string{":id": "123", ":page": "1"}}) - routers = append(routers, testinfo{"/v1/:v/cms/aaa_:id(.+)_:page(.+).html", "/v1/2/cms/aaa_123_1.html", map[string]string{":v": "2", ":id": "123", ":page": "1"}}) - routers = append(routers, testinfo{"/v1/:v/cms_:id(.+)_:page(.+).html", "/v1/2/cms_123_1.html", map[string]string{":v": "2", ":id": "123", ":page": "1"}}) - routers = append(routers, testinfo{"/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, testinfo{"/api/projects/:pid/members/?:mid", "/api/projects/1/members", map[string]string{":pid": "1"}}) - routers = append(routers, testinfo{"/api/projects/:pid/members/?:mid", "/api/projects/1/members/2", map[string]string{":pid": "1", ":mid": "2"}}) + routers = make([]testInfo, 0) + //match example + routers = append(routers, matchTestInfo("/topic/?:auth:int", "/topic", nil)) + routers = append(routers, matchTestInfo("/topic/?:auth:int", "/topic/123", map[string]string{":auth": "123"})) + routers = append(routers, matchTestInfo("/topic/:id/?:auth", "/topic/1", map[string]string{":id": "1"})) + routers = append(routers, matchTestInfo("/topic/:id/?:auth", "/topic/1/2", map[string]string{":id": "1", ":auth": "2"})) + routers = append(routers, matchTestInfo("/topic/:id/?:auth:int", "/topic/1", map[string]string{":id": "1"})) + routers = append(routers, matchTestInfo("/topic/:id/?:auth:int", "/topic/1/123", map[string]string{":id": "1", ":auth": "123"})) + routers = append(routers, matchTestInfo("/:id", "/123", map[string]string{":id": "123"})) + routers = append(routers, matchTestInfo("/hello/?:id", "/hello", map[string]string{":id": ""})) + routers = append(routers, matchTestInfo("/", "/", nil)) + routers = append(routers, matchTestInfo("/customer/login", "/customer/login", nil)) + routers = append(routers, matchTestInfo("/customer/login", "/customer/login.json", map[string]string{":ext": "json"})) + routers = append(routers, matchTestInfo("/*", "/http://customer/123/", map[string]string{":splat": "http://customer/123/"})) + routers = append(routers, matchTestInfo("/*", "/customer/2009/12/11", map[string]string{":splat": "customer/2009/12/11"})) + routers = append(routers, matchTestInfo("/aa/*/bb", "/aa/2009/bb", map[string]string{":splat": "2009"})) + routers = append(routers, matchTestInfo("/cc/*/dd", "/cc/2009/11/dd", map[string]string{":splat": "2009/11"})) + routers = append(routers, matchTestInfo("/cc/:id/*", "/cc/2009/11/dd", map[string]string{":id": "2009", ":splat": "11/dd"})) + routers = append(routers, matchTestInfo("/ee/:year/*/ff", "/ee/2009/11/ff", map[string]string{":year": "2009", ":splat": "11"})) + routers = append(routers, matchTestInfo("/thumbnail/:size/uploads/*", "/thumbnail/100x100/uploads/items/2014/04/20/dPRCdChkUd651t1Hvs18.jpg", map[string]string{":size": "100x100", ":splat": "items/2014/04/20/dPRCdChkUd651t1Hvs18.jpg"})) + routers = append(routers, matchTestInfo("/*.*", "/nice/api.json", map[string]string{":path": "nice/api", ":ext": "json"})) + routers = append(routers, matchTestInfo("/:name/*.*", "/nice/api.json", map[string]string{":name": "nice", ":path": "api", ":ext": "json"})) + routers = append(routers, matchTestInfo("/:name/test/*.*", "/nice/test/api.json", map[string]string{":name": "nice", ":path": "api", ":ext": "json"})) + routers = append(routers, matchTestInfo("/dl/:width:int/:height:int/*.*", "/dl/48/48/05ac66d9bda00a3acf948c43e306fc9a.jpg", map[string]string{":width": "48", ":height": "48", ":ext": "jpg", ":path": "05ac66d9bda00a3acf948c43e306fc9a"})) + routers = append(routers, matchTestInfo("/v1/shop/:id:int", "/v1/shop/123", map[string]string{":id": "123"})) + routers = append(routers, matchTestInfo("/v1/shop/:id\\((a|b|c)\\)", "/v1/shop/123(a)", map[string]string{":id": "123"})) + routers = append(routers, matchTestInfo("/v1/shop/:id\\((a|b|c)\\)", "/v1/shop/123(b)", map[string]string{":id": "123"})) + routers = append(routers, matchTestInfo("/v1/shop/:id\\((a|b|c)\\)", "/v1/shop/123(c)", map[string]string{":id": "123"})) + routers = append(routers, matchTestInfo("/:year:int/:month:int/:id/:endid", "/1111/111/aaa/aaa", map[string]string{":year": "1111", ":month": "111", ":id": "aaa", ":endid": "aaa"})) + routers = append(routers, matchTestInfo("/v1/shop/:id/:name", "/v1/shop/123/nike", map[string]string{":id": "123", ":name": "nike"})) + routers = append(routers, matchTestInfo("/v1/shop/:id/account", "/v1/shop/123/account", map[string]string{":id": "123"})) + routers = append(routers, matchTestInfo("/v1/shop/:name:string", "/v1/shop/nike", map[string]string{":name": "nike"})) + routers = append(routers, matchTestInfo("/v1/shop/:id([0-9]+)", "/v1/shop//123", map[string]string{":id": "123"})) + routers = append(routers, matchTestInfo("/v1/shop/:id([0-9]+)_:name", "/v1/shop/123_nike", map[string]string{":id": "123", ":name": "nike"})) + routers = append(routers, matchTestInfo("/v1/shop/:id(.+)_cms.html", "/v1/shop/123_cms.html", map[string]string{":id": "123"})) + routers = append(routers, matchTestInfo("/v1/shop/cms_:id(.+)_:page(.+).html", "/v1/shop/cms_123_1.html", map[string]string{":id": "123", ":page": "1"})) + routers = append(routers, matchTestInfo("/v1/:v/cms/aaa_:id(.+)_:page(.+).html", "/v1/2/cms/aaa_123_1.html", map[string]string{":v": "2", ":id": "123", ":page": "1"})) + routers = append(routers, matchTestInfo("/v1/:v/cms_:id(.+)_:page(.+).html", "/v1/2/cms_123_1.html", map[string]string{":v": "2", ":id": "123", ":page": "1"})) + 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"})) + + //not match example + + // https://github.com/astaxie/beego/issues/3865 + routers = append(routers, notMatchTestInfo("/read_:id:int.htm", "/read_222htm")) + routers = append(routers, notMatchTestInfo("/read_:id:int.htm", "/read_222_htm")) + routers = append(routers, notMatchTestInfo("/read_:id:int.htm", " /read_262shtm")) + } func TestTreeRouters(t *testing.T) { for _, r := range routers { + shouldMatch := r.shouldMatchOrNot + tr := NewTree() - tr.AddRouter(r.url, "astaxie") + tr.AddRouter(r.pattern, "astaxie") ctx := context.NewContext() - obj := tr.Match(r.requesturl, ctx) + obj := tr.Match(r.requestUrl, ctx) + if !shouldMatch { + if obj != nil { + t.Fatal("pattern:", r.pattern, ", should not match", r.requestUrl) + } else { + return + } + } if obj == nil || obj.(string) != "astaxie" { - t.Fatal(r.url+" can't get obj, Expect ", r.requesturl) + t.Fatal("pattern:", r.pattern+", can't match obj, Expect ", r.requestUrl) } if r.params != nil { for k, v := range r.params { if vv := ctx.Input.Param(k); vv != v { - t.Fatal("The Rule: " + r.url + "\nThe RequestURL:" + r.requesturl + "\nThe Key is " + k + ", The Value should be: " + v + ", but get: " + vv) + t.Fatal("The Rule: " + r.pattern + "\nThe RequestURL:" + r.requestUrl + "\nThe Key is " + k + ", The Value should be: " + v + ", but get: " + vv) } else if vv == "" && v != "" { - t.Fatal(r.url + " " + r.requesturl + " get param empty:" + k) + t.Fatal(r.pattern + " " + r.requestUrl + " get param empty:" + k) } } } @@ -247,7 +280,6 @@ func TestAddTree5(t *testing.T) { t.Fatal("url /v1/shop/ need match router /v1/shop/ ") } } - func TestSplitPath(t *testing.T) { a := splitPath("") if len(a) != 0 { @@ -303,4 +335,4 @@ func TestSplitSegment(t *testing.T) { t.Fatalf("%s should return %t,%s,%q, got %t,%s,%q", pattern, v.isReg, v.params, v.regStr, b, w, r) } } -} +} \ No newline at end of file From 99a47e76449d81ca580e3eb76b25d0b910b4b75c Mon Sep 17 00:00:00 2001 From: jianzhiyao Date: Mon, 30 Nov 2020 19:27:59 +0800 Subject: [PATCH 27/29] fix reg_express --- server/web/tree.go | 3 +++ server/web/tree_test.go | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/server/web/tree.go b/server/web/tree.go index fc5a11a2..b389e148 100644 --- a/server/web/tree.go +++ b/server/web/tree.go @@ -570,6 +570,9 @@ func splitSegment(key string) (bool, []string, string) { param = make([]rune, 0) } else if v == '?' { params = append(params, ":") + } else if v == '.' { + out = append(out, '\\') + out = append(out, v) } else { out = append(out, v) } diff --git a/server/web/tree_test.go b/server/web/tree_test.go index b6b3d52a..92a6b7f2 100644 --- a/server/web/tree_test.go +++ b/server/web/tree_test.go @@ -323,8 +323,8 @@ func TestSplitSegment(t *testing.T) { ":name:string": {true, []string{":name"}, `([\w]+)`}, ":id([0-9]+)": {true, []string{":id"}, `([0-9]+)`}, ":id([0-9]+)_:name": {true, []string{":id", ":name"}, `([0-9]+)_(.+)`}, - ":id(.+)_cms.html": {true, []string{":id"}, `(.+)_cms.html`}, - "cms_:id(.+)_:page(.+).html": {true, []string{":id", ":page"}, `cms_(.+)_(.+).html`}, + ":id(.+)_cms.html": {true, []string{":id"}, `(.+)_cms\.html`}, + "cms_:id(.+)_:page(.+).html": {true, []string{":id", ":page"}, `cms_(.+)_(.+)\.html`}, `:app(a|b|c)`: {true, []string{":app"}, `(a|b|c)`}, `:app\((a|b|c)\)`: {true, []string{":app"}, `(.+)\((a|b|c)\)`}, } From c034d3767a313120fb0be9381ffd3ba884824727 Mon Sep 17 00:00:00 2001 From: jianzhiyao Date: Mon, 30 Nov 2020 20:22:52 +0800 Subject: [PATCH 28/29] rollback --- server/web/tree.go | 3 --- server/web/tree_test.go | 11 ++++++----- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/server/web/tree.go b/server/web/tree.go index b389e148..fc5a11a2 100644 --- a/server/web/tree.go +++ b/server/web/tree.go @@ -570,9 +570,6 @@ func splitSegment(key string) (bool, []string, string) { param = make([]rune, 0) } else if v == '?' { params = append(params, ":") - } else if v == '.' { - out = append(out, '\\') - out = append(out, v) } else { out = append(out, v) } diff --git a/server/web/tree_test.go b/server/web/tree_test.go index 92a6b7f2..2c41a227 100644 --- a/server/web/tree_test.go +++ b/server/web/tree_test.go @@ -94,9 +94,9 @@ func init() { //not match example // https://github.com/astaxie/beego/issues/3865 - routers = append(routers, notMatchTestInfo("/read_:id:int.htm", "/read_222htm")) - routers = append(routers, notMatchTestInfo("/read_:id:int.htm", "/read_222_htm")) - routers = append(routers, notMatchTestInfo("/read_:id:int.htm", " /read_262shtm")) + routers = append(routers, notMatchTestInfo("/read_:id:int\\.htm", "/read_222htm")) + routers = append(routers, notMatchTestInfo("/read_:id:int\\.htm", "/read_222_htm")) + routers = append(routers, notMatchTestInfo("/read_:id:int\\.htm", " /read_262shtm")) } @@ -323,8 +323,9 @@ func TestSplitSegment(t *testing.T) { ":name:string": {true, []string{":name"}, `([\w]+)`}, ":id([0-9]+)": {true, []string{":id"}, `([0-9]+)`}, ":id([0-9]+)_:name": {true, []string{":id", ":name"}, `([0-9]+)_(.+)`}, - ":id(.+)_cms.html": {true, []string{":id"}, `(.+)_cms\.html`}, - "cms_:id(.+)_:page(.+).html": {true, []string{":id", ":page"}, `cms_(.+)_(.+)\.html`}, + ":id(.+)_cms.html": {true, []string{":id"}, `(.+)_cms.html`}, + ":id(.+)_cms\\.html": {true, []string{":id"}, `(.+)_cms\.html`}, + "cms_:id(.+)_:page(.+).html": {true, []string{":id", ":page"}, `cms_(.+)_(.+).html`}, `:app(a|b|c)`: {true, []string{":app"}, `(a|b|c)`}, `:app\((a|b|c)\)`: {true, []string{":app"}, `(.+)\((a|b|c)\)`}, } From db785479abbcbe9c0927fff3ceb7928a42e3639e Mon Sep 17 00:00:00 2001 From: AllenX2018 Date: Tue, 1 Dec 2020 17:18:30 +0800 Subject: [PATCH 29/29] fix issue #4331 1. Modify Incr&Decr for file cache 2. Add different type of integer testcases for Incr&Decr --- client/cache/cache_test.go | 70 +++++++++++++++++++++-------------- client/cache/file.go | 75 +++++++++++++++++++++++++++++--------- 2 files changed, 100 insertions(+), 45 deletions(-) diff --git a/client/cache/cache_test.go b/client/cache/cache_test.go index bd9b0801..85f83fc4 100644 --- a/client/cache/cache_test.go +++ b/client/cache/cache_test.go @@ -72,21 +72,9 @@ func TestCache(t *testing.T) { t.Error("set Error", err) } - if err = bm.Incr(context.Background(), "astaxie"); err != nil { - t.Error("Incr Error", err) - } + // test different integer type for incr & decr + testMultiIncrDecr(t, bm, timeoutDuration) - if v, _ := bm.Get(context.Background(), "astaxie"); v.(int) != 2 { - t.Error("get err") - } - - if err = bm.Decr(context.Background(), "astaxie"); err != nil { - t.Error("Decr Error", err) - } - - if v, _ := bm.Get(context.Background(), "astaxie"); v.(int) != 1 { - t.Error("get err") - } bm.Delete(context.Background(), "astaxie") if res, _ := bm.IsExist(context.Background(), "astaxie"); res { t.Error("delete err") @@ -153,21 +141,9 @@ func TestFileCache(t *testing.T) { t.Error("get err") } - if err = bm.Incr(context.Background(), "astaxie"); err != nil { - t.Error("Incr Error", err) - } + // test different integer type for incr & decr + testMultiIncrDecr(t, bm, timeoutDuration) - if v, _ := bm.Get(context.Background(), "astaxie"); v.(int) != 2 { - t.Error("get err") - } - - if err = bm.Decr(context.Background(), "astaxie"); err != nil { - t.Error("Decr Error", err) - } - - if v, _ := bm.Get(context.Background(), "astaxie"); v.(int) != 1 { - t.Error("get err") - } bm.Delete(context.Background(), "astaxie") if res, _ := bm.IsExist(context.Background(), "astaxie"); res { t.Error("delete err") @@ -219,3 +195,41 @@ func TestFileCache(t *testing.T) { os.RemoveAll("cache") } + +func testMultiIncrDecr(t *testing.T, c Cache, timeout time.Duration) { + testIncrDecr(t, c, 1, 2, timeout) + testIncrDecr(t, c, int32(1), int32(2), timeout) + testIncrDecr(t, c, int64(1), int64(2), timeout) + testIncrDecr(t, c, uint(1), uint(2), timeout) + testIncrDecr(t, c, uint32(1), uint32(2), timeout) + testIncrDecr(t, c, uint64(1), uint64(2), timeout) +} + +func testIncrDecr(t *testing.T, c Cache, beforeIncr interface{}, afterIncr interface{}, timeout time.Duration) { + var err error + ctx := context.Background() + key := "incDecKey" + if err = c.Put(ctx, key, beforeIncr, timeout); err != nil { + t.Error("Get Error", err) + } + + if err = c.Incr(ctx, key); err != nil { + t.Error("Incr Error", err) + } + + if v, _ := c.Get(ctx, key); v != afterIncr { + t.Error("Get Error") + } + + if err = c.Decr(ctx, key); err != nil { + t.Error("Decr Error", err) + } + + if v, _ := c.Get(ctx, key); v != beforeIncr { + t.Error("Get Error") + } + + if err := c.Delete(ctx, key); err != nil { + t.Error("Delete Error") + } +} diff --git a/client/cache/file.go b/client/cache/file.go index 84ac03c8..043c4650 100644 --- a/client/cache/file.go +++ b/client/cache/file.go @@ -26,7 +26,6 @@ import ( "io/ioutil" "os" "path/filepath" - "reflect" "strconv" "strings" "time" @@ -195,28 +194,70 @@ func (fc *FileCache) Delete(ctx context.Context, key string) error { // Incr increases cached int value. // fc value is saved forever unless deleted. func (fc *FileCache) Incr(ctx context.Context, key string) error { - data, _ := fc.Get(context.Background(), key) - var incr int - if reflect.TypeOf(data).Name() != "int" { - incr = 0 - } else { - incr = data.(int) + 1 + data, err := fc.Get(context.Background(), key) + if err != nil { + return err } - fc.Put(context.Background(), key, incr, time.Duration(fc.EmbedExpiry)) - return nil + + var res interface{} + switch val := data.(type) { + case int: + res = val + 1 + case int32: + res = val + 1 + case int64: + res = val + 1 + case uint: + res = val + 1 + case uint32: + res = val + 1 + case uint64: + res = val + 1 + default: + return errors.Errorf("data is not (u)int (u)int32 (u)int64") + } + + return fc.Put(context.Background(), key, res, time.Duration(fc.EmbedExpiry)) } // Decr decreases cached int value. func (fc *FileCache) Decr(ctx context.Context, key string) error { - data, _ := fc.Get(context.Background(), key) - var decr int - if reflect.TypeOf(data).Name() != "int" || data.(int)-1 <= 0 { - decr = 0 - } else { - decr = data.(int) - 1 + data, err := fc.Get(context.Background(), key) + if err != nil { + return err } - fc.Put(context.Background(), key, decr, time.Duration(fc.EmbedExpiry)) - return nil + + var res interface{} + switch val := data.(type) { + case int: + res = val - 1 + case int32: + res = val - 1 + case int64: + res = val - 1 + case uint: + if val > 0 { + res = val - 1 + } else { + return errors.New("data val is less than 0") + } + case uint32: + if val > 0 { + res = val - 1 + } else { + return errors.New("data val is less than 0") + } + case uint64: + if val > 0 { + res = val - 1 + } else { + return errors.New("data val is less than 0") + } + default: + return errors.Errorf("data is not (u)int (u)int32 (u)int64") + } + + return fc.Put(context.Background(), key, res, time.Duration(fc.EmbedExpiry)) } // IsExist checks if value exists.