Merge remote-tracking branch 'origin/develop' into develop

This commit is contained in:
letu 2021-06-16 23:21:45 +08:00
commit 99b7c0bae4
183 changed files with 1823 additions and 855 deletions

17
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,17 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "daily"
open-pull-requests-limit: 10
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"

View File

@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v1
- uses: actions/stale@v3.0.19
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: 'This issue is inactive for a long time.'

124
.github/workflows/test.yml vendored Normal file
View File

@ -0,0 +1,124 @@
name: Test
on:
push:
branches:
- master
- develop
paths:
- "**/*.go"
- "go.mod"
- "go.sum"
- ".github/workflows/test.yml"
pull_request:
types: [opened, synchronize, reopened]
branches:
- master
- develop
paths:
- "**/*.go"
- "go.mod"
- "go.sum"
- ".github/workflows/test.yml"
jobs:
test:
strategy:
fail-fast: false
matrix:
go-version: [1.14, 1.15, 1.16]
runs-on: ubuntu-latest
services:
redis:
image: redis:latest
ports:
- 6379:6379
memcached:
image: memcached:latest
ports:
- 11211:11211
ssdb:
image: wendal/ssdb:latest
ports:
- 8888:8888
postgres:
image: postgres:latest
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: orm_test
ports:
- 5432/tcp
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
steps:
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go-version }}
- name: Checkout codebase
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Run etcd
env:
ETCD_VERSION: v3.4.16
run: |
rm -rf /tmp/etcd-data.tmp
mkdir -p /tmp/etcd-data.tmp
docker rmi gcr.io/etcd-development/etcd:${ETCD_VERSION} || true && \
docker run -d \
-p 2379:2379 \
-p 2380:2380 \
--mount type=bind,source=/tmp/etcd-data.tmp,destination=/etcd-data \
--name etcd-gcr-${ETCD_VERSION} \
gcr.io/etcd-development/etcd:${ETCD_VERSION} \
/usr/local/bin/etcd \
--name s1 \
--data-dir /etcd-data \
--listen-client-urls http://0.0.0.0:2379 \
--advertise-client-urls http://0.0.0.0:2379 \
--listen-peer-urls http://0.0.0.0:2380 \
--initial-advertise-peer-urls http://0.0.0.0:2380 \
--initial-cluster s1=http://0.0.0.0:2380 \
--initial-cluster-token tkn \
--initial-cluster-state new
docker exec etcd-gcr-${ETCD_VERSION} /bin/sh -c "ETCDCTL_API=3 /usr/local/bin/etcdctl put current.float 1.23"
docker exec etcd-gcr-${ETCD_VERSION} /bin/sh -c "ETCDCTL_API=3 /usr/local/bin/etcdctl put current.bool true"
docker exec etcd-gcr-${ETCD_VERSION} /bin/sh -c "ETCDCTL_API=3 /usr/local/bin/etcdctl put current.int 11"
docker exec etcd-gcr-${ETCD_VERSION} /bin/sh -c "ETCDCTL_API=3 /usr/local/bin/etcdctl put current.string hello"
docker exec etcd-gcr-${ETCD_VERSION} /bin/sh -c "ETCDCTL_API=3 /usr/local/bin/etcdctl put current.serialize.name test"
docker exec etcd-gcr-${ETCD_VERSION} /bin/sh -c "ETCDCTL_API=3 /usr/local/bin/etcdctl put sub.sub.key1 sub.sub.key"
- name: Run ORM tests on sqlite3
env:
GOPATH: /home/runner/go
ORM_DRIVER: sqlite3
ORM_SOURCE: /tmp/sqlite3/orm_test.db
run: |
mkdir -p /tmp/sqlite3 && touch /tmp/sqlite3/orm_test.db
go test -coverprofile=coverage_sqlite3.txt -covermode=atomic $(go list ./... | grep client/orm)
- name: Run ORM tests on postgres
env:
GOPATH: /home/runner/go
ORM_DRIVER: postgres
ORM_SOURCE: host=localhost port=${{ job.services.postgres.ports[5432] }} user=postgres password=postgres dbname=orm_test sslmode=disable
run: |
go test -coverprofile=coverage_postgres.txt -covermode=atomic $(go list ./... | grep client/orm)
- name: Run tests on mysql
env:
GOPATH: /home/runner/go
ORM_DRIVER: mysql
ORM_SOURCE: root:root@/orm_test?charset=utf8
run: |
sudo systemctl start mysql
mysql -u root -proot -e 'create database orm_test;'
go test -coverprofile=coverage.txt -covermode=atomic ./...
- name: Upload codecov
env:
CODECOV_TOKEN: 4f4bc484-32a8-43b7-9f48-20966bd48ceb
run: bash <(curl -s https://codecov.io/bash)

View File

@ -1,75 +0,0 @@
language: go
go:
- "1.14.x"
services:
- redis-server
- mysql
- postgresql
- memcached
- docker
env:
global:
- GO_REPO_FULLNAME="github.com/beego/beego/v2"
matrix:
- ORM_DRIVER=sqlite3 ORM_SOURCE=$TRAVIS_BUILD_DIR/orm_test.db
- ORM_DRIVER=postgres ORM_SOURCE="user=postgres dbname=orm_test sslmode=disable"
- ORM_DRIVER=mysql export ORM_SOURCE="root:@/orm_test?charset=utf8"
before_install:
- export CODECOV_TOKEN="4f4bc484-32a8-43b7-9f48-20966bd48ceb"
# link the local repo with ${GOPATH}/src/<namespace>/<repo>
- GO_REPO_NAMESPACE=${GO_REPO_FULLNAME%/*}
# relies on GOPATH to contain only one directory...
- mkdir -p ${GOPATH}/src/${GO_REPO_NAMESPACE}
- ln -sv ${TRAVIS_BUILD_DIR} ${GOPATH}/src/${GO_REPO_FULLNAME}
- cd ${GOPATH}/src/${GO_REPO_FULLNAME}
# get and build ssdb
- git clone git://github.com/ideawu/ssdb.git
- cd ssdb
- make
- cd ..
# - prepare etcd
# - prepare for etcd unit tests
- rm -rf /tmp/etcd-data.tmp
- mkdir -p /tmp/etcd-data.tmp
- docker rmi gcr.io/etcd-development/etcd:v3.3.25 || true &&
docker run -d
-p 2379:2379
-p 2380:2380
--mount type=bind,source=/tmp/etcd-data.tmp,destination=/etcd-data
--name etcd-gcr-v3.3.25
gcr.io/etcd-development/etcd:v3.3.25
/usr/local/bin/etcd
--name s1
--data-dir /etcd-data
--listen-client-urls http://0.0.0.0:2379
--advertise-client-urls http://0.0.0.0:2379
--listen-peer-urls http://0.0.0.0:2380
--initial-advertise-peer-urls http://0.0.0.0:2380
--initial-cluster s1=http://0.0.0.0:2380
--initial-cluster-token tkn
--initial-cluster-state new
- docker exec etcd-gcr-v3.3.25 /bin/sh -c "ETCDCTL_API=3 /usr/local/bin/etcdctl put current.float 1.23"
- docker exec etcd-gcr-v3.3.25 /bin/sh -c "ETCDCTL_API=3 /usr/local/bin/etcdctl put current.bool true"
- docker exec etcd-gcr-v3.3.25 /bin/sh -c "ETCDCTL_API=3 /usr/local/bin/etcdctl put current.int 11"
- docker exec etcd-gcr-v3.3.25 /bin/sh -c "ETCDCTL_API=3 /usr/local/bin/etcdctl put current.string hello"
- docker exec etcd-gcr-v3.3.25 /bin/sh -c "ETCDCTL_API=3 /usr/local/bin/etcdctl put current.serialize.name test"
- docker exec etcd-gcr-v3.3.25 /bin/sh -c "ETCDCTL_API=3 /usr/local/bin/etcdctl put sub.sub.key1 sub.sub.key"
before_script:
- psql --version
# - prepare for orm unit tests
- sh -c "if [ '$ORM_DRIVER' = 'postgres' ]; then psql -c 'create database orm_test;' -U postgres; fi"
- sh -c "if [ '$ORM_DRIVER' = 'mysql' ]; then mysql -u root -e 'create database orm_test;'; fi"
- sh -c "if [ '$ORM_DRIVER' = 'sqlite' ]; then touch $TRAVIS_BUILD_DIR/orm_test.db; fi"
- sh -c "go list ./... | grep -v vendor | xargs go vet -v"
- mkdir -p res/var
- ./ssdb/ssdb-server ./ssdb/ssdb.conf -d
after_script:
- killall -w ssdb-server
- rm -rf ./res/var/*
after_success:
- bash <(curl -s https://codecov.io/bash)
script:
- GO111MODULE=on go test -coverprofile=coverage.txt -covermode=atomic ./...
addons:
postgresql: "9.6"

View File

@ -1,7 +1,13 @@
# developing
- Add template functions eq,lt to support uint and int compare. [4607](https://github.com/beego/beego/pull/4607)
- Migrate tests to GitHub Actions. [4663](https://github.com/beego/beego/issues/4663)
- Add http client and option func. [4455](https://github.com/beego/beego/issues/4455)
- Add: Convenient way to generate mock object [4620](https://github.com/beego/beego/issues/4620)
- Infra: use dependabot to update dependencies. [4623](https://github.com/beego/beego/pull/4623)
- Lint: use golangci-lint. [4619](https://github.com/beego/beego/pull/4619)
- Chore: format code. [4615](https://github.com/beego/beego/pull/4615)
- Test on Go v1.15.x & v1.16.x. [4614](https://github.com/beego/beego/pull/4614)
- Env: non-empty GOBIN & GOPATH. [4613](https://github.com/beego/beego/pull/4613)
- Chore: update dependencies. [4611](https://github.com/beego/beego/pull/4611)
- Update orm_test.go/TestInsertOrUpdate with table-driven. [4609](https://github.com/beego/beego/pull/4609)
@ -45,10 +51,29 @@
- Optimize AddAutoPrefix: only register one router in case-insensitive mode. [4582](https://github.com/beego/beego/pull/4582)
- Init exceptMethod by using reflection. [4583](https://github.com/beego/beego/pull/4583)
- Deprecated BeeMap and replace all usage with `sync.map` [4616](https://github.com/beego/beego/pull/4616)
- TaskManager support graceful shutdown [4635](https://github.com/beego/beego/pull/4635)
## Fix Sonar
- [4624](https://github.com/beego/beego/pull/4624)
- [4608](https://github.com/beego/beego/pull/4608)
- [4473](https://github.com/beego/beego/pull/4473)
- [4474](https://github.com/beego/beego/pull/4474)
- [4479](https://github.com/beego/beego/pull/4479)
- [4639](https://github.com/beego/beego/pull/4639)
## Fix lint and format code
- [4644](https://github.com/beego/beego/pull/4644)
- [4645](https://github.com/beego/beego/pull/4645)
- [4646](https://github.com/beego/beego/pull/4646)
- [4647](https://github.com/beego/beego/pull/4647)
- [4648](https://github.com/beego/beego/pull/4648)
- [4649](https://github.com/beego/beego/pull/4649)
- [4651](https://github.com/beego/beego/pull/4651)
- [4652](https://github.com/beego/beego/pull/4652)
- [4653](https://github.com/beego/beego/pull/4653)
- [4654](https://github.com/beego/beego/pull/4654)
- [4655](https://github.com/beego/beego/pull/4655)
- [4656](https://github.com/beego/beego/pull/4656)
- [4660](https://github.com/beego/beego/pull/4660)

View File

@ -1,14 +1,12 @@
# Beego [![Build Status](https://travis-ci.org/beego/beego.svg?branch=master)](https://travis-ci.org/beego/beego) [![GoDoc](http://godoc.org/github.com/beego/beego?status.svg)](http://godoc.org/github.com/beego/beego) [![Foundation](https://img.shields.io/badge/Golang-Foundation-green.svg)](http://golangfoundation.org) [![Go Report Card](https://goreportcard.com/badge/github.com/beego/beego)](https://goreportcard.com/report/github.com/beego/beego)
# Beego [![Test](https://github.com/beego/beego/actions/workflows/test.yml/badge.svg?branch=develop)](https://github.com/beego/beego/actions/workflows/test.yml) [![Go Report Card](https://goreportcard.com/badge/github.com/beego/beego)](https://goreportcard.com/report/github.com/beego/beego) [![Go Reference](https://pkg.go.dev/badge/github.com/beego/beego/v2.svg)](https://pkg.go.dev/github.com/beego/beego/v2)
Beego is used for rapid development of enterprise application in Go, including RESTful APIs, web apps and backend
services.
Beego is used for rapid development of enterprise application in Go, including RESTful APIs, web apps and backend services.
It is inspired by Tornado, Sinatra and Flask. beego has some Go-specific features such as interfaces and struct
embedding.
It is inspired by Tornado, Sinatra and Flask. beego has some Go-specific features such as interfaces and struct embedding.
![architecture](https://cdn.nlark.com/yuque/0/2020/png/755700/1607857489109-1e267fce-d65f-4c5e-b915-5c475df33c58.png)
Beego is compos of four parts:
Beego is composed of four parts:
1. Base modules: including log module, config module, governor module;
2. Task: is used for running timed tasks or periodic tasks;
@ -90,11 +88,11 @@ Congratulations! You've just built your first **beego** app.
## Community
* [http://beego.me/community](http://beego.me/community)
* Welcome to join us in Slack: [https://beego.slack.com invite](https://join.slack.com/t/beego/shared_invite/zt-fqlfjaxs-_CRmiITCSbEqQG9NeBqXKA),
* Welcome to join us in Slack: [https://beego.slack.com invite](https://join.slack.com/t/beego/shared_invite/zt-fqlfjaxs-_CRmiITCSbEqQG9NeBqXKA),
* QQ Group Group ID:523992905
* [Contribution Guide](https://github.com/beego/beedoc/blob/master/en-US/intro/contributing.md).
## License
beego source code is licensed under the Apache Licence, Version 2.0
(http://www.apache.org/licenses/LICENSE-2.0.html).
([https://www.apache.org/licenses/LICENSE-2.0.html](https://www.apache.org/licenses/LICENSE-2.0.html)).

View File

@ -22,10 +22,8 @@ import (
"github.com/beego/beego/v2/server/web/context"
)
var (
// BeeApp is an application instance
BeeApp *App
)
// BeeApp is an application instance
var BeeApp *App
func init() {
// create beego application

View File

@ -36,10 +36,6 @@ type M web.M
// Hook function to run
type hookfunc func() error
var (
hooks = make([]hookfunc, 0) // hook function slice to store the hookfunc
)
// AddAPPStartHook is used to register the hookfunc
// The hookfuncs will run in beego.Run()
// such as initiating session , starting middleware , building template, starting admin control and so on.

View File

@ -19,15 +19,15 @@ import (
)
func TestGetString(t *testing.T) {
var t1 = "test1"
t1 := "test1"
if "test1" != GetString(t1) {
t.Error("get string from string error")
}
var t2 = []byte("test2")
t2 := []byte("test2")
if "test2" != GetString(t2) {
t.Error("get string from byte array error")
}
var t3 = 1
t3 := 1
if "1" != GetString(t3) {
t.Error("get string from int error")
}
@ -35,7 +35,7 @@ func TestGetString(t *testing.T) {
if "1" != GetString(t4) {
t.Error("get string from int64 error")
}
var t5 = 1.1
t5 := 1.1
if "1.1" != GetString(t5) {
t.Error("get string from float64 error")
}
@ -46,7 +46,7 @@ func TestGetString(t *testing.T) {
}
func TestGetInt(t *testing.T) {
var t1 = 1
t1 := 1
if 1 != GetInt(t1) {
t.Error("get int from int error")
}
@ -58,7 +58,7 @@ func TestGetInt(t *testing.T) {
if 64 != GetInt(t3) {
t.Error("get int from int64 error")
}
var t4 = "128"
t4 := "128"
if 128 != GetInt(t4) {
t.Error("get int from num string error")
}
@ -69,7 +69,7 @@ func TestGetInt(t *testing.T) {
func TestGetInt64(t *testing.T) {
var i int64 = 1
var t1 = 1
t1 := 1
if i != GetInt64(t1) {
t.Error("get int64 from int error")
}
@ -81,7 +81,7 @@ func TestGetInt64(t *testing.T) {
if i != GetInt64(t3) {
t.Error("get int64 from int64 error")
}
var t4 = "1"
t4 := "1"
if i != GetInt64(t4) {
t.Error("get int64 from num string error")
}
@ -91,22 +91,22 @@ func TestGetInt64(t *testing.T) {
}
func TestGetFloat64(t *testing.T) {
var f = 1.11
f := 1.11
var t1 float32 = 1.11
if f != GetFloat64(t1) {
t.Error("get float64 from float32 error")
}
var t2 = 1.11
t2 := 1.11
if f != GetFloat64(t2) {
t.Error("get float64 from float64 error")
}
var t3 = "1.11"
t3 := "1.11"
if f != GetFloat64(t3) {
t.Error("get float64 from string error")
}
var f2 float64 = 1
var t4 = 1
t4 := 1
if f2 != GetFloat64(t4) {
t.Error("get float64 from int error")
}
@ -117,11 +117,11 @@ func TestGetFloat64(t *testing.T) {
}
func TestGetBool(t *testing.T) {
var t1 = true
t1 := true
if !GetBool(t1) {
t.Error("get bool from bool error")
}
var t2 = "true"
t2 := "true"
if !GetBool(t2) {
t.Error("get bool from string error")
}

View File

@ -34,10 +34,8 @@ import (
redis2 "github.com/beego/beego/v2/client/cache/redis"
)
var (
// DefaultKey the collection name of redis for cache adapter.
DefaultKey = "beecacheRedis"
)
// DefaultKey the collection name of redis for cache adapter.
var DefaultKey = "beecacheRedis"
// NewRedisCache create new redis cache with default collection name.
func NewRedisCache() cache.Cache {

View File

@ -20,7 +20,6 @@ import (
)
func TestExpandValueEnv(t *testing.T) {
testCases := []struct {
item string
want string
@ -51,5 +50,4 @@ func TestExpandValueEnv(t *testing.T) {
t.Errorf("expand value error, item %q want %q, got %q", c.item, c.want, got)
}
}
}

View File

@ -23,7 +23,6 @@ import (
)
func TestIni(t *testing.T) {
var (
inicontext = `
;comment one
@ -129,11 +128,9 @@ password = ${GOPATH}
if iniconf.String("name") != "astaxie" {
t.Fatal("get name error")
}
}
func TestIniSave(t *testing.T) {
const (
inicontext = `
app = app

View File

@ -23,7 +23,6 @@ import (
)
func TestJsonStartsWithArray(t *testing.T) {
const jsoncontextwitharray = `[
{
"url": "user",
@ -71,7 +70,6 @@ func TestJsonStartsWithArray(t *testing.T) {
}
func TestJson(t *testing.T) {
var (
jsoncontext = `{
"appname": "beeapi",

View File

@ -23,7 +23,6 @@ import (
)
func TestXML(t *testing.T) {
var (
// xml parse should incluce in <config></config> tags
xmlcontext = `<?xml version="1.0" encoding="UTF-8"?>

View File

@ -23,7 +23,6 @@ import (
)
func TestYaml(t *testing.T) {
var (
yamlcontext = `
"appname": beeapi
@ -112,5 +111,4 @@ func TestYaml(t *testing.T) {
if yamlconf.String("name") != "astaxie" {
t.Fatal("get name error")
}
}

View File

@ -25,7 +25,6 @@ import (
// Demo is used to test, it's empty
func Demo(i int) {
}
func TestConvertParams(t *testing.T) {

View File

@ -48,9 +48,11 @@ type ControllerCommentsSlice web.ControllerCommentsSlice
func (p ControllerCommentsSlice) Len() int {
return (web.ControllerCommentsSlice)(p).Len()
}
func (p ControllerCommentsSlice) Less(i, j int) bool {
return (web.ControllerCommentsSlice)(p).Less(i, j)
}
func (p ControllerCommentsSlice) Swap(i, j int) {
(web.ControllerCommentsSlice)(p).Swap(i, j)
}

View File

@ -26,11 +26,13 @@ import (
"time"
)
const getUrl = "http://httpbin.org/get"
const ipUrl = "http://httpbin.org/ip"
const (
getURL = "http://httpbin.org/get"
ipURL = "http://httpbin.org/ip"
)
func TestResponse(t *testing.T) {
req := Get(getUrl)
req := Get(getURL)
resp, err := req.Response()
if err != nil {
t.Fatal(err)
@ -63,12 +65,10 @@ func TestDoRequest(t *testing.T) {
if elapsedTime < delayedTime {
t.Errorf("Not enough retries. Took %dms. Delay was meant to take %dms", elapsedTime, delayedTime)
}
}
func TestGet(t *testing.T) {
req := Get(getUrl)
req := Get(getURL)
b, err := req.Bytes()
if err != nil {
t.Fatal(err)
@ -210,7 +210,7 @@ func TestWithSetting(t *testing.T) {
setting.ReadWriteTimeout = 5 * time.Second
SetDefaultSetting(setting)
str, err := Get(getUrl).String()
str, err := Get(getURL).String()
if err != nil {
t.Fatal(err)
}
@ -223,8 +223,7 @@ func TestWithSetting(t *testing.T) {
}
func TestToJson(t *testing.T) {
req := Get(ipUrl)
req := Get(ipURL)
resp, err := req.Response()
if err != nil {
t.Fatal(err)
@ -250,12 +249,11 @@ func TestToJson(t *testing.T) {
t.Fatal("response is not valid ip")
}
}
}
func TestToFile(t *testing.T) {
f := "beego_testfile"
req := Get(ipUrl)
req := Get(ipURL)
err := req.ToFile(f)
if err != nil {
t.Fatal(err)
@ -269,7 +267,7 @@ func TestToFile(t *testing.T) {
func TestToFileDir(t *testing.T) {
f := "./files/beego_testfile"
req := Get(ipUrl)
req := Get(ipURL)
err := req.ToFile(f)
if err != nil {
t.Fatal(err)

View File

@ -18,7 +18,5 @@ import (
"github.com/beego/beego/v2/client/orm"
)
var (
// ErrMissPK missing pk error
ErrMissPK = orm.ErrMissPK
)
// ErrMissPK missing pk error
var ErrMissPK = orm.ErrMissPK

View File

@ -1,36 +0,0 @@
// 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 orm
import (
"github.com/beego/beego/v2/client/orm"
)
type baseQuerySetter struct {
}
const shouldNotInvoke = "you should not invoke this method."
func (b *baseQuerySetter) ForceIndex(indexes ...string) orm.QuerySeter {
panic(shouldNotInvoke)
}
func (b *baseQuerySetter) UseIndex(indexes ...string) orm.QuerySeter {
panic(shouldNotInvoke)
}
func (b *baseQuerySetter) IgnoreIndex(indexes ...string) orm.QuerySeter {
panic(shouldNotInvoke)
}

View File

@ -72,5 +72,4 @@ func TestRedisSentinel(t *testing.T) {
assert.Nil(t, password)
sess.SessionRelease(w)
}

View File

@ -22,14 +22,14 @@ import (
"time"
)
const sid = "Session_id"
const sidNew = "Session_id_new"
const sessionPath = "./_session_runtime"
var (
mutex sync.Mutex
const (
sid = "Session_id"
sidNew = "Session_id_new"
sessionPath = "./_session_runtime"
)
var mutex sync.Mutex
func TestFileProviderSessionExist(t *testing.T) {
mutex.Lock()
defer mutex.Unlock()

View File

@ -118,7 +118,6 @@ func AssetsJs(text string) template.HTML {
// AssetsCSS returns stylesheet link tag with src string.
func AssetsCSS(text string) template.HTML {
text = "<link href=\"" + text + "\" rel=\"stylesheet\" />"
return template.HTML(text)

View File

@ -79,7 +79,6 @@ func TestHtmlunquote(t *testing.T) {
h := `&lt;&#39;&nbsp;&rdquo;&ldquo;&amp;&#34;&gt;`
s := `<' ”“&">`
assert.Equal(t, s, Htmlunquote(h))
}
func TestParseForm(t *testing.T) {
@ -234,5 +233,4 @@ func TestMapGet(t *testing.T) {
res, err = MapGet(m5, 5, 4, 3, 2, 1)
assert.Nil(t, err)
assert.Nil(t, res)
}

View File

@ -14,12 +14,7 @@
package testing
import (
"github.com/beego/beego/v2/client/httplib/testing"
)
var port = ""
var baseURL = "http://localhost:"
import "github.com/beego/beego/v2/client/httplib/testing"
// TestHTTPRequest beego test request client
type TestHTTPRequest testing.TestHTTPRequest

View File

@ -16,19 +16,10 @@ package toolbox
import (
"io"
"os"
"time"
"github.com/beego/beego/v2/core/admin"
)
var startTime = time.Now()
var pid int
func init() {
pid = os.Getpid()
}
// ProcessInput parse input command string
func ProcessInput(input string, w io.Writer) {
admin.ProcessInput(input, w)

View File

@ -80,7 +80,6 @@ type Task struct {
// NewTask add new task with name, time and func
func NewTask(tname string, spec string, f TaskFunc) *Task {
task := task.NewTask(tname, spec, func(ctx context.Context) error {
return f()
})
@ -98,7 +97,6 @@ func (t *Task) GetSpec() string {
// GetStatus get current task status
func (t *Task) GetStatus() string {
t.initDelegate()
return t.delegate.GetStatus(context.Background())
@ -222,7 +220,6 @@ type MapSorter task.MapSorter
// NewMapSorter create new tasker map
func NewMapSorter(m map[string]Tasker) *MapSorter {
newTaskerMap := make(map[string]task.Tasker, len(m))
for key, value := range m {
@ -249,6 +246,7 @@ func (ms *MapSorter) Less(i, j int) bool {
}
return ms.Vals[i].GetNext(context.Background()).Before(ms.Vals[j].GetNext(context.Background()))
}
func (ms *MapSorter) Swap(i, j int) {
ms.Vals[i], ms.Vals[j] = ms.Vals[j], ms.Vals[i]
ms.Keys[i], ms.Keys[j] = ms.Keys[j], ms.Keys[i]

View File

@ -69,9 +69,7 @@ import (
beecontext "github.com/beego/beego/v2/server/web/context"
)
var (
defaultChars = []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
)
var defaultChars = []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
const (
// default captcha attributes

View File

@ -28,8 +28,8 @@ func TestPrint(t *testing.T) {
}
func TestPrintPoint(t *testing.T) {
var v1 = new(mytype)
var v2 = new(mytype)
v1 := new(mytype)
v2 := new(mytype)
v1.prev = nil
v1.next = v2

View File

@ -19,6 +19,7 @@ import (
)
type reducetype func(interface{}) interface{}
type filtertype func(interface{}) bool
// InSlice checks given string in string slice or not.

View File

@ -27,9 +27,7 @@ const (
LabelTag = validation.LabelTag
)
var (
ErrInt64On32 = validation.ErrInt64On32
)
var ErrInt64On32 = validation.ErrInt64On32
// CustomFunc is for custom validate function
type CustomFunc func(v *Validation, obj interface{}, key string)

View File

@ -50,7 +50,6 @@ func TestMin(t *testing.T) {
assert.False(t, valid.Min(-1, 0, "min0").Ok)
assert.True(t, valid.Min(1, 0, "min0").Ok)
}
func TestMax(t *testing.T) {
@ -502,5 +501,4 @@ func TestCanSkipAlso(t *testing.T) {
assert.Nil(t, err)
assert.True(t, b)
}

View File

@ -12,6 +12,11 @@ var (
ErrNotIntegerType = berror.Error(NotIntegerType, "item val is not (u)int (u)int32 (u)int64")
)
const (
MinUint32 uint32 = 0
MinUint64 uint64 = 0
)
func incr(originVal interface{}) (interface{}, error) {
switch val := originVal.(type) {
case int:
@ -75,12 +80,12 @@ func decr(originVal interface{}) (interface{}, error) {
}
return val - 1, nil
case uint32:
if val == 0 {
if val == MinUint32 {
return nil, ErrDecrementOverflow
}
return val - 1, nil
case uint64:
if val == 0 {
if val == MinUint64 {
return nil, ErrDecrementOverflow
}
return val - 1, nil

View File

@ -21,29 +21,29 @@ import (
)
func TestGetString(t *testing.T) {
var t1 = "test1"
t1 := "test1"
assert.Equal(t, "test1", GetString(t1))
var t2 = []byte("test2")
t2 := []byte("test2")
assert.Equal(t, "test2", GetString(t2))
var t3 = 1
t3 := 1
assert.Equal(t, "1", GetString(t3))
var t4 int64 = 1
assert.Equal(t, "1", GetString(t4))
var t5 = 1.1
t5 := 1.1
assert.Equal(t, "1.1", GetString(t5))
assert.Equal(t, "", GetString(nil))
}
func TestGetInt(t *testing.T) {
var t1 = 1
t1 := 1
assert.Equal(t, 1, GetInt(t1))
var t2 int32 = 32
assert.Equal(t, 32, GetInt(t2))
var t3 int64 = 64
assert.Equal(t, 64, GetInt(t3))
var t4 = "128"
t4 := "128"
assert.Equal(t, 128, GetInt(t4))
assert.Equal(t, 0, GetInt(nil))
@ -51,38 +51,38 @@ func TestGetInt(t *testing.T) {
func TestGetInt64(t *testing.T) {
var i int64 = 1
var t1 = 1
t1 := 1
assert.Equal(t, i, GetInt64(t1))
var t2 int32 = 1
assert.Equal(t, i, GetInt64(t2))
var t3 int64 = 1
assert.Equal(t, i, GetInt64(t3))
var t4 = "1"
t4 := "1"
assert.Equal(t, i, GetInt64(t4))
assert.Equal(t, int64(0), GetInt64(nil))
}
func TestGetFloat64(t *testing.T) {
var f = 1.11
f := 1.11
var t1 float32 = 1.11
assert.Equal(t, f, GetFloat64(t1))
var t2 = 1.11
t2 := 1.11
assert.Equal(t, f, GetFloat64(t2))
var t3 = "1.11"
t3 := "1.11"
assert.Equal(t, f, GetFloat64(t3))
var f2 float64 = 1
var t4 = 1
t4 := 1
assert.Equal(t, f2, GetFloat64(t4))
assert.Equal(t, float64(0), GetFloat64(nil))
}
func TestGetBool(t *testing.T) {
var t1 = true
t1 := true
assert.True(t, GetBool(t1))
var t2 = "true"
t2 := "true"
assert.True(t, GetBool(t2))
assert.False(t, GetBool(nil))

View File

@ -170,5 +170,7 @@ The reponse from SSDB server is invalid.
Usually it indicates something wrong on server side.
`)
var ErrKeyExpired = berror.Error(KeyExpired, "the key is expired")
var ErrKeyNotExist = berror.Error(KeyNotExist, "the key isn't exist")
var (
ErrKeyExpired = berror.Error(KeyExpired, "the key is expired")
ErrKeyNotExist = berror.Error(KeyNotExist, "the key isn't exist")
)

View File

@ -67,7 +67,6 @@ func NewFileCache() Cache {
// StartAndGC starts gc for file cache.
// config must be in the format {CachePath:"/cache","FileSuffix":".bin","DirectoryLevel":"2","EmbedExpiry":"0"}
func (fc *FileCache) StartAndGC(config string) error {
cfg := make(map[string]string)
err := json.Unmarshal([]byte(config), &cfg)
if err != nil {

View File

@ -25,10 +25,8 @@ import (
"github.com/beego/beego/v2/core/berror"
)
var (
// Timer for how often to recycle the expired cache items in memory (in seconds)
DefaultEvery = 60 // 1 minute
)
// DefaultEvery sets a timer for how often to recycle the expired cache items in memory (in seconds)
var DefaultEvery = 60 // 1 minute
// MemoryItem stores memory cache item.
type MemoryItem struct {

View File

@ -43,10 +43,8 @@ import (
"github.com/beego/beego/v2/core/berror"
)
var (
// The collection name of redis for the cache adapter.
DefaultKey = "beecacheRedis"
)
// DefaultKey defines the collection name of redis for the cache adapter.
var DefaultKey = "beecacheRedis"
// Cache is Redis cache adapter.
type Cache struct {

View File

@ -28,7 +28,6 @@ import (
)
func TestRedisCache(t *testing.T) {
redisAddr := os.Getenv("REDIS_ADDR")
if redisAddr == "" {
redisAddr = "127.0.0.1:6379"

View File

@ -124,7 +124,6 @@ func (rc *Cache) IsExist(ctx context.Context, key string) (bool, error) {
return true, nil
}
return false, nil
}
// ClearAll clears all cached items in ssdb.

View File

@ -15,7 +15,6 @@ import (
)
func TestSsdbcacheCache(t *testing.T) {
ssdbAddr := os.Getenv("SSDB_ADDR")
if ssdbAddr == "" {
ssdbAddr = "127.0.0.1:8888"

View File

@ -9,7 +9,7 @@ httplib is an libs help you to curl remote url.
you can use Get to crawl data.
import "github.com/beego/beego/v2/client/httplib"
str, err := httplib.Get("http://beego.me/").String()
if err != nil {
// error
@ -39,7 +39,7 @@ Example:
// GET
httplib.Get("http://beego.me/").SetTimeout(100 * time.Second, 30 * time.Second)
// POST
httplib.Post("http://beego.me/").SetTimeout(100 * time.Second, 30 * time.Second)

View File

@ -0,0 +1,155 @@
// Copyright 2020 beego
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package httplib
import (
"crypto/tls"
"net/http"
"net/url"
"time"
)
type (
ClientOption func(client *Client)
BeegoHTTPRequestOption func(request *BeegoHTTPRequest)
)
// WithEnableCookie will enable cookie in all subsequent request
func WithEnableCookie(enable bool) ClientOption {
return func(client *Client) {
client.Setting.EnableCookie = enable
}
}
// WithEnableCookie will adds UA in all subsequent request
func WithUserAgent(userAgent string) ClientOption {
return func(client *Client) {
client.Setting.UserAgent = userAgent
}
}
// WithTLSClientConfig will adds tls config in all subsequent request
func WithTLSClientConfig(config *tls.Config) ClientOption {
return func(client *Client) {
client.Setting.TLSClientConfig = config
}
}
// WithTransport will set transport field in all subsequent request
func WithTransport(transport http.RoundTripper) ClientOption {
return func(client *Client) {
client.Setting.Transport = transport
}
}
// WithProxy will set http proxy field in all subsequent request
func WithProxy(proxy func(*http.Request) (*url.URL, error)) ClientOption {
return func(client *Client) {
client.Setting.Proxy = proxy
}
}
// WithCheckRedirect will specifies the policy for handling redirects in all subsequent request
func WithCheckRedirect(redirect func(req *http.Request, via []*http.Request) error) ClientOption {
return func(client *Client) {
client.Setting.CheckRedirect = redirect
}
}
// WithHTTPSetting can replace beegoHTTPSeting
func WithHTTPSetting(setting BeegoHTTPSettings) ClientOption {
return func(client *Client) {
client.Setting = setting
}
}
// WithEnableGzip will enable gzip in all subsequent request
func WithEnableGzip(enable bool) ClientOption {
return func(client *Client) {
client.Setting.Gzip = enable
}
}
// BeegoHttpRequestOption
// WithTimeout sets connect time out and read-write time out for BeegoRequest.
func WithTimeout(connectTimeout, readWriteTimeout time.Duration) BeegoHTTPRequestOption {
return func(request *BeegoHTTPRequest) {
request.SetTimeout(connectTimeout, readWriteTimeout)
}
}
// WithHeader adds header item string in request.
func WithHeader(key, value string) BeegoHTTPRequestOption {
return func(request *BeegoHTTPRequest) {
request.Header(key, value)
}
}
// WithCookie adds a cookie to the request.
func WithCookie(cookie *http.Cookie) BeegoHTTPRequestOption {
return func(request *BeegoHTTPRequest) {
request.Header("Cookie", cookie.String())
}
}
// Withtokenfactory adds a custom function to set Authorization
func WithTokenFactory(tokenFactory func() string) BeegoHTTPRequestOption {
return func(request *BeegoHTTPRequest) {
t := tokenFactory()
request.Header("Authorization", t)
}
}
// WithBasicAuth adds a custom function to set basic auth
func WithBasicAuth(basicAuth func() (string, string)) BeegoHTTPRequestOption {
return func(request *BeegoHTTPRequest) {
username, password := basicAuth()
request.SetBasicAuth(username, password)
}
}
// WithFilters will use the filter as the invocation filters
func WithFilters(fcs ...FilterChain) BeegoHTTPRequestOption {
return func(request *BeegoHTTPRequest) {
request.SetFilters(fcs...)
}
}
// WithContentType adds ContentType in header
func WithContentType(contentType string) BeegoHTTPRequestOption {
return func(request *BeegoHTTPRequest) {
request.Header(contentTypeKey, contentType)
}
}
// WithParam adds query param in to request.
func WithParam(key, value string) BeegoHTTPRequestOption {
return func(request *BeegoHTTPRequest) {
request.Param(key, value)
}
}
// WithRetry set retry times and delay for the request
// default is 0 (never retry)
// -1 retry indefinitely (forever)
// Other numbers specify the exact retry amount
func WithRetry(times int, delay time.Duration) BeegoHTTPRequestOption {
return func(request *BeegoHTTPRequest) {
request.Retries(times)
request.RetryDelay(delay)
}
}

View File

@ -0,0 +1,261 @@
// Copyright 2020 beego
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package httplib
import (
"errors"
"net"
"net/http"
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
type respCarrier struct {
bytes []byte
}
func (r *respCarrier) SetBytes(bytes []byte) {
r.bytes = bytes
}
func (r *respCarrier) String() string {
return string(r.bytes)
}
func TestOption_WithEnableCookie(t *testing.T) {
client, err := NewClient("test", "http://httpbin.org/",
WithEnableCookie(true))
if err != nil {
t.Fatal(err)
}
v := "smallfish"
resp := &respCarrier{}
err = client.Get(resp, "/cookies/set?k1="+v)
if err != nil {
t.Fatal(err)
}
t.Log(resp.String())
err = client.Get(resp, "/cookies")
if err != nil {
t.Fatal(err)
}
t.Log(resp.String())
n := strings.Index(resp.String(), v)
if n == -1 {
t.Fatal(v + " not found in cookie")
}
}
func TestOption_WithUserAgent(t *testing.T) {
v := "beego"
client, err := NewClient("test", "http://httpbin.org/",
WithUserAgent(v))
if err != nil {
t.Fatal(err)
}
resp := &respCarrier{}
err = client.Get(resp, "/headers")
if err != nil {
t.Fatal(err)
}
t.Log(resp.String())
n := strings.Index(resp.String(), v)
if n == -1 {
t.Fatal(v + " not found in user-agent")
}
}
func TestOption_WithCheckRedirect(t *testing.T) {
client, err := NewClient("test", "https://goolnk.com/33BD2j",
WithCheckRedirect(func(redirectReq *http.Request, redirectVia []*http.Request) error {
return errors.New("Redirect triggered")
}))
if err != nil {
t.Fatal(err)
}
err = client.Get(nil, "")
assert.NotNil(t, err)
}
func TestOption_WithHTTPSetting(t *testing.T) {
v := "beego"
var setting BeegoHTTPSettings
setting.EnableCookie = true
setting.UserAgent = v
setting.Transport = &http.Transport{
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
DualStack: true,
}).DialContext,
MaxIdleConns: 50,
IdleConnTimeout: 90 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
}
setting.ReadWriteTimeout = 5 * time.Second
client, err := NewClient("test", "http://httpbin.org/",
WithHTTPSetting(setting))
if err != nil {
t.Fatal(err)
}
resp := &respCarrier{}
err = client.Get(resp, "/get")
if err != nil {
t.Fatal(err)
}
t.Log(resp.String())
n := strings.Index(resp.String(), v)
if n == -1 {
t.Fatal(v + " not found in user-agent")
}
}
func TestOption_WithHeader(t *testing.T) {
client, err := NewClient("test", "http://httpbin.org/")
if err != nil {
t.Fatal(err)
}
client.CommonOpts = append(client.CommonOpts, WithHeader("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36"))
resp := &respCarrier{}
err = client.Get(resp, "/headers")
if err != nil {
t.Fatal(err)
}
t.Log(resp.String())
n := strings.Index(resp.String(), "Mozilla/5.0")
if n == -1 {
t.Fatal("Mozilla/5.0 not found in user-agent")
}
}
func TestOption_WithTokenFactory(t *testing.T) {
client, err := NewClient("test", "http://httpbin.org/")
if err != nil {
t.Fatal(err)
}
client.CommonOpts = append(client.CommonOpts,
WithTokenFactory(func() string {
return "testauth"
}))
resp := &respCarrier{}
err = client.Get(resp, "/headers")
if err != nil {
t.Fatal(err)
}
t.Log(resp.String())
n := strings.Index(resp.String(), "testauth")
if n == -1 {
t.Fatal("Auth is not set in request")
}
}
func TestOption_WithBasicAuth(t *testing.T) {
client, err := NewClient("test", "http://httpbin.org/")
if err != nil {
t.Fatal(err)
}
resp := &respCarrier{}
err = client.Get(resp, "/basic-auth/user/passwd",
WithBasicAuth(func() (string, string) {
return "user", "passwd"
}))
if err != nil {
t.Fatal(err)
}
t.Log(resp.String())
n := strings.Index(resp.String(), "authenticated")
if n == -1 {
t.Fatal("authenticated not found in response")
}
}
func TestOption_WithContentType(t *testing.T) {
client, err := NewClient("test", "http://httpbin.org/")
if err != nil {
t.Fatal(err)
}
v := "application/json"
resp := &respCarrier{}
err = client.Get(resp, "/headers", WithContentType(v))
if err != nil {
t.Fatal(err)
}
t.Log(resp.String())
n := strings.Index(resp.String(), v)
if n == -1 {
t.Fatal(v + " not found in header")
}
}
func TestOption_WithParam(t *testing.T) {
client, err := NewClient("test", "http://httpbin.org/")
if err != nil {
t.Fatal(err)
}
v := "smallfish"
resp := &respCarrier{}
err = client.Get(resp, "/get", WithParam("username", v))
if err != nil {
t.Fatal(err)
}
t.Log(resp.String())
n := strings.Index(resp.String(), v)
if n == -1 {
t.Fatal(v + " not found in header")
}
}
func TestOption_WithRetry(t *testing.T) {
client, err := NewClient("test", "https://goolnk.com/33BD2j",
WithCheckRedirect(func(redirectReq *http.Request, redirectVia []*http.Request) error {
return errors.New("Redirect triggered")
}))
if err != nil {
t.Fatal(err)
}
retryAmount := 1
retryDelay := 800 * time.Millisecond
startTime := time.Now().UnixNano() / int64(time.Millisecond)
_ = client.Get(nil, "", WithRetry(retryAmount, retryDelay))
endTime := time.Now().UnixNano() / int64(time.Millisecond)
elapsedTime := endTime - startTime
delayedTime := int64(retryAmount) * retryDelay.Milliseconds()
if elapsedTime < delayedTime {
t.Errorf("Not enough retries. Took %dms. Delay was meant to take %dms", elapsedTime, delayedTime)
}
}

View File

@ -124,3 +124,11 @@ Make sure that:
1. You pass valid structure pointer to the function;
2. The body is valid YAML document
`)
var UnmarshalResponseToObjectFailed = berror.DefineCode(5001011, moduleName,
"UnmarshalResponseToObjectFailed", `
Beego trying to unmarshal response's body to structure but failed.
There are several cases that cause this error:
1. You pass valid structure pointer to the function;
2. The body is valid json, Yaml or XML document
`)

View File

@ -35,9 +35,7 @@ type FilterChainBuilder struct {
}
func (builder *FilterChainBuilder) FilterChain(next httplib.Filter) httplib.Filter {
return func(ctx context.Context, req *httplib.BeegoHTTPRequest) (*http.Response, error) {
method := req.GetRequest().Method
operationName := method + "#" + req.GetRequest().URL.String()

View File

@ -32,11 +32,12 @@ type FilterChainBuilder struct {
RunMode string
}
var summaryVec prometheus.ObserverVec
var initSummaryVec sync.Once
var (
summaryVec prometheus.ObserverVec
initSummaryVec sync.Once
)
func (builder *FilterChainBuilder) FilterChain(next httplib.Filter) httplib.Filter {
initSummaryVec.Do(func() {
summaryVec = prometheus.NewSummaryVec(prometheus.SummaryOpts{
Name: "beego",

View File

@ -0,0 +1,174 @@
// Copyright 2020 beego
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package httplib
import (
"bytes"
"io"
"io/ioutil"
"net/http"
)
// Client provides an HTTP client supporting chain call
type Client struct {
Name string
Endpoint string
CommonOpts []BeegoHTTPRequestOption
Setting BeegoHTTPSettings
}
// HTTPResponseCarrier If value implement HTTPResponseCarrier. http.Response will pass to SetHTTPResponse
type HTTPResponseCarrier interface {
SetHTTPResponse(resp *http.Response)
}
// HTTPBodyCarrier If value implement HTTPBodyCarrier. http.Response.Body will pass to SetReader
type HTTPBodyCarrier interface {
SetReader(r io.ReadCloser)
}
// HTTPBytesCarrier If value implement HTTPBytesCarrier.
// All the byte in http.Response.Body will pass to SetBytes
type HTTPBytesCarrier interface {
SetBytes(bytes []byte)
}
// HTTPStatusCarrier If value implement HTTPStatusCarrier. http.Response.StatusCode will pass to SetStatusCode
type HTTPStatusCarrier interface {
SetStatusCode(status int)
}
// HttpHeaderCarrier If value implement HttpHeaderCarrier. http.Response.Header will pass to SetHeader
type HTTPHeadersCarrier interface {
SetHeader(header map[string][]string)
}
// NewClient return a new http client
func NewClient(name string, endpoint string, opts ...ClientOption) (*Client, error) {
res := &Client{
Name: name,
Endpoint: endpoint,
}
setting := GetDefaultSetting()
res.Setting = setting
for _, o := range opts {
o(res)
}
return res, nil
}
func (c *Client) customReq(req *BeegoHTTPRequest, opts []BeegoHTTPRequestOption) {
req.Setting(c.Setting)
opts = append(c.CommonOpts, opts...)
for _, o := range opts {
o(req)
}
}
// handleResponse try to parse body to meaningful value
func (c *Client) handleResponse(value interface{}, req *BeegoHTTPRequest) error {
// make sure req.resp is not nil
_, err := req.Bytes()
if err != nil {
return err
}
err = c.handleCarrier(value, req)
if err != nil {
return err
}
return req.ToValue(value)
}
// handleCarrier set http data to value
func (c *Client) handleCarrier(value interface{}, req *BeegoHTTPRequest) error {
if value == nil {
return nil
}
if carrier, ok := value.(HTTPResponseCarrier); ok {
b, err := req.Bytes()
if err != nil {
return err
}
req.resp.Body = ioutil.NopCloser(bytes.NewReader(b))
carrier.SetHTTPResponse(req.resp)
}
if carrier, ok := value.(HTTPBodyCarrier); ok {
b, err := req.Bytes()
if err != nil {
return err
}
reader := ioutil.NopCloser(bytes.NewReader(b))
carrier.SetReader(reader)
}
if carrier, ok := value.(HTTPBytesCarrier); ok {
b, err := req.Bytes()
if err != nil {
return err
}
carrier.SetBytes(b)
}
if carrier, ok := value.(HTTPStatusCarrier); ok {
carrier.SetStatusCode(req.resp.StatusCode)
}
if carrier, ok := value.(HTTPHeadersCarrier); ok {
carrier.SetHeader(req.resp.Header)
}
return nil
}
// Get Send a GET request and try to give its result value
func (c *Client) Get(value interface{}, path string, opts ...BeegoHTTPRequestOption) error {
req := Get(c.Endpoint + path)
c.customReq(req, opts)
return c.handleResponse(value, req)
}
// Post Send a POST request and try to give its result value
func (c *Client) Post(value interface{}, path string, body interface{}, opts ...BeegoHTTPRequestOption) error {
req := Post(c.Endpoint + path)
c.customReq(req, opts)
if body != nil {
req = req.Body(body)
}
return c.handleResponse(value, req)
}
// Put Send a Put request and try to give its result value
func (c *Client) Put(value interface{}, path string, body interface{}, opts ...BeegoHTTPRequestOption) error {
req := Put(c.Endpoint + path)
c.customReq(req, opts)
if body != nil {
req = req.Body(body)
}
return c.handleResponse(value, req)
}
// Delete Send a Delete request and try to give its result value
func (c *Client) Delete(value interface{}, path string, opts ...BeegoHTTPRequestOption) error {
req := Delete(c.Endpoint + path)
c.customReq(req, opts)
return c.handleResponse(value, req)
}
// Head Send a Head request and try to give its result value
func (c *Client) Head(value interface{}, path string, opts ...BeegoHTTPRequestOption) error {
req := Head(c.Endpoint + path)
c.customReq(req, opts)
return c.handleResponse(value, req)
}

View File

@ -0,0 +1,220 @@
// Copyright 2020 beego
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package httplib
import (
"encoding/xml"
"io"
"io/ioutil"
"net/http"
"testing"
"github.com/stretchr/testify/assert"
)
func TestNewClient(t *testing.T) {
client, err := NewClient("test1", "http://beego.me", WithEnableCookie(true))
assert.NoError(t, err)
assert.NotNil(t, client)
assert.Equal(t, true, client.Setting.EnableCookie)
}
type slideShowResponse struct {
Resp *http.Response
bytes []byte
StatusCode int
Body io.ReadCloser
Header map[string][]string
Slideshow slideshow `json:"slideshow" yaml:"slideshow"`
}
func (r *slideShowResponse) SetHTTPResponse(resp *http.Response) {
r.Resp = resp
}
func (r *slideShowResponse) SetBytes(bytes []byte) {
r.bytes = bytes
}
func (r *slideShowResponse) SetReader(reader io.ReadCloser) {
r.Body = reader
}
func (r *slideShowResponse) SetStatusCode(status int) {
r.StatusCode = status
}
func (r *slideShowResponse) SetHeader(header map[string][]string) {
r.Header = header
}
func (r *slideShowResponse) String() string {
return string(r.bytes)
}
type slideshow struct {
XMLName xml.Name `xml:"slideshow"`
Title string `json:"title" yaml:"title" xml:"title,attr"`
Author string `json:"author" yaml:"author" xml:"author,attr"`
Date string `json:"date" yaml:"date" xml:"date,attr"`
Slides []slide `json:"slides" yaml:"slides" xml:"slide"`
}
type slide struct {
XMLName xml.Name `xml:"slide"`
Title string `json:"title" yaml:"title" xml:"title"`
}
func TestClient_handleCarrier(t *testing.T) {
v := "beego"
client, err := NewClient("test", "http://httpbin.org/",
WithUserAgent(v))
if err != nil {
t.Fatal(err)
}
s := &slideShowResponse{}
err = client.Get(s, "/json")
if err != nil {
t.Fatal(err)
}
defer s.Body.Close()
assert.NotNil(t, s.Resp)
assert.NotNil(t, s.Body)
assert.Equal(t, "429", s.Header["Content-Length"][0])
assert.Equal(t, 200, s.StatusCode)
b, err := ioutil.ReadAll(s.Body)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, 429, len(b))
assert.Equal(t, s.String(), string(b))
}
func TestClient_Get(t *testing.T) {
client, err := NewClient("test", "http://httpbin.org/")
if err != nil {
t.Fatal(err)
}
// json
var s *slideShowResponse
err = client.Get(&s, "/json")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, "Sample Slide Show", s.Slideshow.Title)
assert.Equal(t, 2, len(s.Slideshow.Slides))
assert.Equal(t, "Overview", s.Slideshow.Slides[1].Title)
// xml
var ssp *slideshow
err = client.Get(&ssp, "/base64/PD94bWwgPz48c2xpZGVzaG93CnRpdGxlPSJTYW1wbGUgU2xpZGUgU2hvdyIKZGF0ZT0iRGF0ZSBvZiBwdWJsaWNhdGlvbiIKYXV0aG9yPSJZb3VycyBUcnVseSI+PHNsaWRlIHR5cGU9ImFsbCI+PHRpdGxlPldha2UgdXAgdG8gV29uZGVyV2lkZ2V0cyE8L3RpdGxlPjwvc2xpZGU+PHNsaWRlIHR5cGU9ImFsbCI+PHRpdGxlPk92ZXJ2aWV3PC90aXRsZT48aXRlbT5XaHkgPGVtPldvbmRlcldpZGdldHM8L2VtPiBhcmUgZ3JlYXQ8L2l0ZW0+PGl0ZW0vPjxpdGVtPldobyA8ZW0+YnV5czwvZW0+IFdvbmRlcldpZGdldHM8L2l0ZW0+PC9zbGlkZT48L3NsaWRlc2hvdz4=")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, "Sample Slide Show", ssp.Title)
assert.Equal(t, 2, len(ssp.Slides))
assert.Equal(t, "Overview", ssp.Slides[1].Title)
// yaml
s = nil
err = client.Get(&s, "/base64/c2xpZGVzaG93OgogIGF1dGhvcjogWW91cnMgVHJ1bHkKICBkYXRlOiBkYXRlIG9mIHB1YmxpY2F0aW9uCiAgc2xpZGVzOgogIC0gdGl0bGU6IFdha2UgdXAgdG8gV29uZGVyV2lkZ2V0cyEKICAgIHR5cGU6IGFsbAogIC0gaXRlbXM6CiAgICAtIFdoeSA8ZW0+V29uZGVyV2lkZ2V0czwvZW0+IGFyZSBncmVhdAogICAgLSBXaG8gPGVtPmJ1eXM8L2VtPiBXb25kZXJXaWRnZXRzCiAgICB0aXRsZTogT3ZlcnZpZXcKICAgIHR5cGU6IGFsbAogIHRpdGxlOiBTYW1wbGUgU2xpZGUgU2hvdw==")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, "Sample Slide Show", s.Slideshow.Title)
assert.Equal(t, 2, len(s.Slideshow.Slides))
assert.Equal(t, "Overview", s.Slideshow.Slides[1].Title)
}
func TestClient_Post(t *testing.T) {
client, err := NewClient("test", "http://httpbin.org")
if err != nil {
t.Fatal(err)
}
resp := &slideShowResponse{}
err = client.Get(resp, "/json")
if err != nil {
t.Fatal(err)
}
jsonStr := resp.String()
err = client.Post(resp, "/post", jsonStr)
if err != nil {
t.Fatal(err)
}
assert.NotNil(t, resp)
assert.Equal(t, http.MethodPost, resp.Resp.Request.Method)
}
func TestClient_Put(t *testing.T) {
client, err := NewClient("test", "http://httpbin.org")
if err != nil {
t.Fatal(err)
}
resp := &slideShowResponse{}
err = client.Get(resp, "/json")
if err != nil {
t.Fatal(err)
}
jsonStr := resp.String()
err = client.Put(resp, "/put", jsonStr)
if err != nil {
t.Fatal(err)
}
assert.NotNil(t, resp)
assert.Equal(t, http.MethodPut, resp.Resp.Request.Method)
}
func TestClient_Delete(t *testing.T) {
client, err := NewClient("test", "http://httpbin.org")
if err != nil {
t.Fatal(err)
}
resp := &slideShowResponse{}
err = client.Delete(resp, "/delete")
if err != nil {
t.Fatal(err)
}
defer resp.Resp.Body.Close()
assert.NotNil(t, resp)
assert.Equal(t, http.MethodDelete, resp.Resp.Request.Method)
}
func TestClient_Head(t *testing.T) {
client, err := NewClient("test", "http://beego.me")
if err != nil {
t.Fatal(err)
}
resp := &slideShowResponse{}
err = client.Head(resp, "")
if err != nil {
t.Fatal(err)
}
defer resp.Resp.Body.Close()
assert.NotNil(t, resp)
assert.Equal(t, http.MethodHead, resp.Resp.Request.Method)
}

View File

@ -124,7 +124,6 @@ type BeegoHTTPRequest struct {
setting BeegoHTTPSettings
resp *http.Response
body []byte
dump []byte
}
// GetRequest returns the request object
@ -199,7 +198,7 @@ func (b *BeegoHTTPRequest) SetHost(host string) *BeegoHTTPRequest {
// SetProtocolVersion sets the protocol version for incoming requests.
// Client requests always use HTTP/1.1
func (b *BeegoHTTPRequest) SetProtocolVersion(vers string) *BeegoHTTPRequest {
if len(vers) == 0 {
if vers == "" {
vers = "HTTP/1.1"
}
@ -401,7 +400,6 @@ func (b *BeegoHTTPRequest) handleFileToBody(bodyWriter *multipart.Writer, formna
"could not create form file, formname: %s, filename: %s", formname, filename))
}
fh, err := os.Open(filename)
if err != nil {
logs.Error(errFmt, berror.Wrapf(err, ReadFileFailed, "could not open this file %s", filename))
}
@ -511,18 +509,16 @@ func (b *BeegoHTTPRequest) buildTrans() http.RoundTripper {
DialContext: TimeoutDialerCtx(b.setting.ConnectTimeout, b.setting.ReadWriteTimeout),
MaxIdleConnsPerHost: 100,
}
} else {
} else if t, ok := trans.(*http.Transport); ok {
// if b.transport is *http.Transport then set the settings.
if t, ok := trans.(*http.Transport); ok {
if t.TLSClientConfig == nil {
t.TLSClientConfig = b.setting.TLSClientConfig
}
if t.Proxy == nil {
t.Proxy = b.setting.Proxy
}
if t.DialContext == nil {
t.DialContext = TimeoutDialerCtx(b.setting.ConnectTimeout, b.setting.ReadWriteTimeout)
}
if t.TLSClientConfig == nil {
t.TLSClientConfig = b.setting.TLSClientConfig
}
if t.Proxy == nil {
t.Proxy = b.setting.Proxy
}
if t.DialContext == nil {
t.DialContext = TimeoutDialerCtx(b.setting.ConnectTimeout, b.setting.ReadWriteTimeout)
}
}
return trans
@ -656,6 +652,40 @@ func (b *BeegoHTTPRequest) ToYAML(v interface{}) error {
UnmarshalYAMLResponseToObjectFailed, "unmarshal yaml body to object failed.")
}
// ToValue attempts to resolve the response body to value using an existing method.
// Calls Response inner.
// If response header contain Content-Type, func will call ToJSON\ToXML\ToYAML.
// Else it will try to parse body as json\yaml\xml, If all attempts fail, an error will be returned
func (b *BeegoHTTPRequest) ToValue(value interface{}) error {
if value == nil {
return nil
}
contentType := strings.Split(b.resp.Header.Get(contentTypeKey), ";")[0]
// try to parse it as content type
switch contentType {
case "application/json":
return b.ToJSON(value)
case "text/xml", "application/xml":
return b.ToXML(value)
case "text/yaml", "application/x-yaml", "application/x+yaml":
return b.ToYAML(value)
}
// try to parse it anyway
if err := b.ToJSON(value); err == nil {
return nil
}
if err := b.ToYAML(value); err == nil {
return nil
}
if err := b.ToXML(value); err == nil {
return nil
}
return berror.Error(UnmarshalResponseToObjectFailed, "unmarshal body to object failed.")
}
// Response executes request client gets response manually.
func (b *BeegoHTTPRequest) Response() (*http.Response, error) {
return b.getResponse()

View File

@ -63,7 +63,6 @@ func TestDoRequest(t *testing.T) {
if elapsedTime < delayedTime {
t.Errorf("Not enough retries. Took %dms. Delay was meant to take %dms", elapsedTime, delayedTime)
}
}
func TestGet(t *testing.T) {
@ -248,7 +247,6 @@ func TestToJson(t *testing.T) {
t.Fatal("response is not valid ip")
}
}
}
func TestToFile(t *testing.T) {
@ -433,3 +431,7 @@ func TestBeegoHTTPRequestXMLBody(t *testing.T) {
assert.Nil(t, err)
assert.NotNil(t, req.req.GetBody)
}
// TODO
func TestBeegoHTTPRequest_ResponseForValue(t *testing.T) {
}

View File

@ -57,7 +57,7 @@ func NewSimpleCondition(path string, opts ...simpleConditionOption) *SimpleCondi
}
func (sc *SimpleCondition) Match(ctx context.Context, req *httplib.BeegoHTTPRequest) bool {
res := true
var res bool
if len(sc.path) > 0 {
res = sc.matchPath(ctx, req)
} else if len(sc.pathReg) > 0 {

View File

@ -23,10 +23,6 @@ import (
"github.com/beego/beego/v2/client/httplib"
)
func init() {
}
func TestSimpleCondition_MatchPath(t *testing.T) {
sc := NewSimpleCondition("/abc/s")
res := sc.Match(context.Background(), httplib.Get("http://localhost:8080/abc/s"))
@ -72,7 +68,6 @@ func TestSimpleCondition_MatchHeader(t *testing.T) {
}
func TestSimpleCondition_MatchBodyField(t *testing.T) {
sc := NewSimpleCondition("/abc/s")
req := httplib.Post("http://localhost:8080/abc/s")

View File

@ -26,7 +26,6 @@ import (
)
func TestStartMock(t *testing.T) {
// httplib.defaultSetting.FilterChains = []httplib.FilterChain{mockFilter.FilterChain}
stub := StartMock()
@ -41,7 +40,6 @@ func TestStartMock(t *testing.T) {
assert.Equal(t, expectedErr, err)
assert.Equal(t, expectedResp, resp)
}
// TestStartMock_Isolation Test StartMock that

View File

@ -55,6 +55,11 @@ func SetDefaultSetting(setting BeegoHTTPSettings) {
defaultSetting = setting
}
// GetDefaultSetting return current default setting
func GetDefaultSetting() BeegoHTTPSettings {
return defaultSetting
}
var defaultSetting = BeegoHTTPSettings{
UserAgent: "beegoServer",
ConnectTimeout: 60 * time.Second,
@ -63,8 +68,10 @@ var defaultSetting = BeegoHTTPSettings{
FilterChains: make([]FilterChain, 0, 4),
}
var defaultCookieJar http.CookieJar
var settingMutex sync.Mutex
var (
defaultCookieJar http.CookieJar
settingMutex sync.Mutex
)
// AddDefaultFilter add a new filter into defaultSetting
// Be careful about using this method if you invoke SetDefaultSetting somewhere

View File

@ -18,8 +18,10 @@ import (
"github.com/beego/beego/v2/client/httplib"
)
var port = ""
var baseURL = "http://localhost:"
var (
port = ""
baseURL = "http://localhost:"
)
// TestHTTPRequest beego test request client
type TestHTTPRequest struct {

View File

@ -5,9 +5,7 @@ import (
)
func TestClause(t *testing.T) {
var (
column = `a`
)
column := `a`
o := Clause(
Column(column),
@ -108,7 +106,6 @@ func TestParseOrder(t *testing.T) {
if orders[2].GetColumn() != `user.status` {
t.Error()
}
}
func TestOrder_GetColumn(t *testing.T) {
@ -120,25 +117,21 @@ func TestOrder_GetColumn(t *testing.T) {
}
}
func TestOrder_GetSort(t *testing.T) {
o := Clause(
SortDescending(),
)
if o.GetSort() != Descending {
t.Error()
}
}
func TestSortString(t *testing.T) {
template := "got: %s, want: %s"
func TestOrder_IsRaw(t *testing.T) {
o1 := Clause()
if o1.IsRaw() {
t.Error()
o1 := Clause(sort(Sort(1)))
if o1.SortString() != "ASC" {
t.Errorf(template, o1.SortString(), "ASC")
}
o2 := Clause(
Raw(),
)
if !o2.IsRaw() {
t.Error()
o2 := Clause(sort(Sort(2)))
if o2.SortString() != "DESC" {
t.Errorf(template, o2.SortString(), "DESC")
}
o3 := Clause(sort(Sort(3)))
if o3.SortString() != `` {
t.Errorf(template, o3.SortString(), ``)
}
}

View File

@ -27,9 +27,7 @@ type commander interface {
Run() error
}
var (
commands = make(map[string]commander)
)
var commands = make(map[string]commander)
// print help.
func printHelp(errs ...string) {

View File

@ -126,9 +126,7 @@ func getColumnAddQuery(al *alias, fi *fieldInfo) string {
// Get string value for the attribute "DEFAULT" for the CREATE, ALTER commands
func getColumnDefault(fi *fieldInfo) string {
var (
v, t, d string
)
var v, t, d string
// Skip default attribute if field is in relations
if fi.rel || fi.reverse {

View File

@ -32,41 +32,37 @@ const (
formatDateTime = "2006-01-02 15:04:05"
)
var (
// ErrMissPK missing pk error
ErrMissPK = errors.New("missed pk value")
)
// ErrMissPK missing pk error
var ErrMissPK = errors.New("missed pk value")
var (
operators = map[string]bool{
"exact": true,
"iexact": true,
"strictexact": true,
"contains": true,
"icontains": true,
// "regex": true,
// "iregex": true,
"gt": true,
"gte": true,
"lt": true,
"lte": true,
"eq": true,
"nq": true,
"ne": true,
"startswith": true,
"endswith": true,
"istartswith": true,
"iendswith": true,
"in": true,
"between": true,
// "year": true,
// "month": true,
// "day": true,
// "week_day": true,
"isnull": true,
// "search": true,
}
)
var operators = map[string]bool{
"exact": true,
"iexact": true,
"strictexact": true,
"contains": true,
"icontains": true,
// "regex": true,
// "iregex": true,
"gt": true,
"gte": true,
"lt": true,
"lte": true,
"eq": true,
"nq": true,
"ne": true,
"startswith": true,
"endswith": true,
"istartswith": true,
"iendswith": true,
"in": true,
"between": true,
// "year": true,
// "month": true,
// "day": true,
// "week_day": true,
"isnull": true,
// "search": true,
}
// an instance of dbBaser interface/
type dbBase struct {
@ -537,7 +533,6 @@ func (d *dbBase) InsertOrUpdate(ctx context.Context, q dbQuerier, mi *modelInfo,
names := make([]string, 0, len(mi.fields.dbcols)-1)
Q := d.ins.TableQuote()
values, _, err := d.collectValues(mi, ind, mi.fields.dbcols, true, true, &names, a.TZ)
if err != nil {
return 0, err
}
@ -934,7 +929,6 @@ func (d *dbBase) DeleteBatch(ctx context.Context, q dbQuerier, qs *querySet, mi
// read related records.
func (d *dbBase) ReadBatch(ctx context.Context, q dbQuerier, qs *querySet, mi *modelInfo, cond *Condition, container interface{}, tz *time.Location, cols []string) (int64, error) {
val := reflect.ValueOf(container)
ind := reflect.Indirect(val)
@ -1435,12 +1429,10 @@ end:
}
return value, nil
}
// set one value to struct column field.
func (d *dbBase) setFieldValue(fi *fieldInfo, value interface{}, field reflect.Value) (interface{}, error) {
fieldType := fi.fieldType
isNative := !fi.isFielder
@ -1632,7 +1624,6 @@ setValue:
// query sql, read values , save to *[]ParamList.
func (d *dbBase) ReadValues(ctx context.Context, q dbQuerier, qs *querySet, mi *modelInfo, cond *Condition, exprs []string, container interface{}, tz *time.Location) (int64, error) {
var (
maps []Params
lists []ParamsList

View File

@ -112,8 +112,10 @@ type DB struct {
stmtDecoratorsLimit int
}
var _ dbQuerier = new(DB)
var _ txer = new(DB)
var (
_ dbQuerier = new(DB)
_ txer = new(DB)
)
func (d *DB) Begin() (*sql.Tx, error) {
return d.DB.Begin()
@ -221,8 +223,10 @@ type TxDB struct {
tx *sql.Tx
}
var _ dbQuerier = new(TxDB)
var _ txEnder = new(TxDB)
var (
_ dbQuerier = new(TxDB)
_ txEnder = new(TxDB)
)
func (t *TxDB) Commit() error {
return t.tx.Commit()
@ -240,8 +244,10 @@ func (t *TxDB) RollbackUnlessCommit() error {
return nil
}
var _ dbQuerier = new(TxDB)
var _ txEnder = new(TxDB)
var (
_ dbQuerier = new(TxDB)
_ txEnder = new(TxDB)
)
func (t *TxDB) Prepare(query string) (*sql.Stmt, error) {
return t.PrepareContext(context.Background(), query)
@ -365,7 +371,6 @@ func addAliasWthDB(aliasName, driverName string, db *sql.DB, params ...DBOption)
}
func newAliasWithDb(aliasName, driverName string, db *sql.DB, params ...DBOption) (*alias, error) {
al := &alias{}
al.DB = &DB{
RWMutex: new(sync.RWMutex),

View File

@ -124,7 +124,6 @@ func (d *dbBaseMysql) InsertOrUpdate(ctx context.Context, q dbQuerier, mi *model
names := make([]string, 0, len(mi.fields.dbcols)-1)
Q := d.ins.TableQuote()
values, _, err := d.collectValues(mi, ind, mi.fields.dbcols, true, true, &names, a.TZ)
if err != nil {
return 0, err
}

View File

@ -106,7 +106,6 @@ func (t *dbTables) loopDepth(depth int, prefix string, fi *fieldInfo, related []
// parse related fields.
func (t *dbTables) parseRelated(rels []string, depth int) {
relsNum := len(rels)
related := make([]string, relsNum)
copy(related, rels)

View File

@ -55,7 +55,6 @@ func getExistPk(mi *modelInfo, ind reflect.Value) (column string, value interfac
// get fields description as flatted string.
func getFlatParams(fi *fieldInfo, args []interface{}, tz *time.Location) (params []interface{}) {
outFor:
for _, arg := range args {
val := reflect.ValueOf(arg)

View File

@ -27,8 +27,7 @@ import (
var _ Ormer = new(DoNothingOrm)
type DoNothingOrm struct {
}
type DoNothingOrm struct{}
func (d *DoNothingOrm) Read(md interface{}, cols ...string) error {
return nil

View File

@ -57,7 +57,6 @@ func TestDefaultValueFilterChainBuilder_FilterChain(t *testing.T) {
_, _ = o.InsertMulti(3, []*DefaultValueTestEntity{entity})
assert.Equal(t, 12, entity.Age)
assert.Equal(t, 13, entity.AgeInOldStyle)
}
type defaultValueTestOrm struct {

View File

@ -39,11 +39,12 @@ type FilterChainBuilder struct {
RunMode string
}
var summaryVec prometheus.ObserverVec
var initSummaryVec sync.Once
var (
summaryVec prometheus.ObserverVec
initSummaryVec sync.Once
)
func (builder *FilterChainBuilder) FilterChain(next orm.Filter) orm.Filter {
initSummaryVec.Do(func() {
summaryVec = prometheus.NewSummaryVec(prometheus.SummaryOpts{
Name: "beego",

View File

@ -58,5 +58,4 @@ func TestFilterChainBuilder_FilterChain1(t *testing.T) {
inv.Method = "Update"
builder.report(ctx, inv, time.Second)
}

View File

@ -28,8 +28,10 @@ const (
TxNameKey = "TxName"
)
var _ Ormer = new(filterOrmDecorator)
var _ TxOrmer = new(filterOrmDecorator)
var (
_ Ormer = new(filterOrmDecorator)
_ TxOrmer = new(filterOrmDecorator)
)
type filterOrmDecorator struct {
ormer
@ -120,7 +122,6 @@ func (f *filterOrmDecorator) ReadOrCreate(md interface{}, col1 string, cols ...s
}
func (f *filterOrmDecorator) ReadOrCreateWithCtx(ctx context.Context, md interface{}, col1 string, cols ...string) (bool, int64, error) {
mi, _ := modelCache.getByMd(md)
inv := &Invocation{
Method: "ReadOrCreateWithCtx",
@ -143,7 +144,6 @@ func (f *filterOrmDecorator) LoadRelated(md interface{}, name string, args ...ut
}
func (f *filterOrmDecorator) LoadRelatedWithCtx(ctx context.Context, md interface{}, name string, args ...utils.KV) (int64, error) {
mi, _ := modelCache.getByMd(md)
inv := &Invocation{
Method: "LoadRelatedWithCtx",
@ -162,7 +162,6 @@ func (f *filterOrmDecorator) LoadRelatedWithCtx(ctx context.Context, md interfac
}
func (f *filterOrmDecorator) QueryM2M(md interface{}, name string) QueryM2Mer {
mi, _ := modelCache.getByMd(md)
inv := &Invocation{
Method: "QueryM2M",

View File

@ -27,7 +27,6 @@ import (
)
func TestFilterOrmDecorator_Read(t *testing.T) {
register()
o := &filterMockOrm{}

View File

@ -116,7 +116,6 @@ func (m *Migration) UniCol(uni, name string) *Column {
// ForeignCol creates a new foreign column and returns the instance of column
func (m *Migration) ForeignCol(colname, foreigncol, foreigntable string) (foreign *Foreign) {
foreign = &Foreign{ForeignColumn: foreigncol, ForeignTable: foreigntable}
foreign.Name = colname
m.AddForeign(foreign)
@ -153,7 +152,6 @@ func (c *Column) SetAuto(inc bool) *Column {
func (c *Column) SetNullable(null bool) *Column {
if null {
c.Null = ""
} else {
c.Null = "NOT NULL"
}
@ -184,7 +182,6 @@ func (c *Column) SetDataType(dataType string) *Column {
func (c *RenameColumn) SetOldNullable(null bool) *RenameColumn {
if null {
c.OldNull = ""
} else {
c.OldNull = "NOT NULL"
}
@ -219,7 +216,6 @@ func (c *Column) SetPrimary(m *Migration) *Column {
// AddColumnsToUnique adds the columns to Unique Struct
func (unique *Unique) AddColumnsToUnique(columns ...*Column) *Unique {
unique.Columns = append(unique.Columns, columns...)
return unique
@ -227,7 +223,6 @@ func (unique *Unique) AddColumnsToUnique(columns ...*Column) *Unique {
// AddColumns adds columns to m struct
func (m *Migration) AddColumns(columns ...*Column) *Migration {
m.Columns = append(m.Columns, columns...)
return m

View File

@ -72,9 +72,7 @@ type Migration struct {
RemoveForeigns []*Foreign
}
var (
migrationMap map[string]Migrationer
)
var migrationMap map[string]Migrationer
func init() {
migrationMap = make(map[string]Migrationer)
@ -82,7 +80,6 @@ func init() {
// Up implement in the Inheritance struct for upgrade
func (m *Migration) Up() {
switch m.ModifyType {
case "reverse":
m.ModifyType = "alter"
@ -94,7 +91,6 @@ func (m *Migration) Up() {
// Down implement in the Inheritance struct for down
func (m *Migration) Down() {
switch m.ModifyType {
case "alter":
m.ModifyType = "reverse"
@ -311,6 +307,7 @@ func isRollBack(name string) bool {
}
return false
}
func getAllMigrations() (map[string]string, error) {
o := orm.NewOrm()
var maps []orm.Params

View File

@ -55,7 +55,6 @@ func (o *OrmStub) Clear() {
func (o *OrmStub) FilterChain(next orm.Filter) orm.Filter {
return func(ctx context.Context, inv *orm.Invocation) []interface{} {
ms := mockFromCtx(ctx)
ms = append(ms, o.ms...)

View File

@ -247,7 +247,7 @@ func TestTransactionRollbackUnlessCommit(t *testing.T) {
mock := errors.New(mockErrorMsg)
s.Mock(MockRollbackUnlessCommit(mock))
//u := &User{}
// u := &User{}
o := orm.NewOrm()
txOrm, _ := o.Begin()
err := txOrm.RollbackUnlessCommit()

View File

@ -22,8 +22,7 @@ import (
// DoNothingQueryM2Mer do nothing
// use it to build mock orm.QueryM2Mer
type DoNothingQueryM2Mer struct {
}
type DoNothingQueryM2Mer struct{}
func (d *DoNothingQueryM2Mer) AddWithCtx(ctx context.Context, i ...interface{}) (int64, error) {
return 0, nil

View File

@ -23,8 +23,7 @@ import (
// DoNothingQuerySetter do nothing
// usually you use this to build your mock QuerySetter
type DoNothingQuerySetter struct {
}
type DoNothingQuerySetter struct{}
func (d *DoNothingQuerySetter) OrderClauses(orders ...*order_clause.Order) orm.QuerySeter {
return d

View File

@ -20,8 +20,7 @@ import (
"github.com/beego/beego/v2/client/orm"
)
type DoNothingRawSetter struct {
}
type DoNothingRawSetter struct{}
func (d *DoNothingRawSetter) Exec() (sql.Result, error) {
return nil, nil

View File

@ -32,9 +32,7 @@ const (
defaultStructTagDelim = ";"
)
var (
modelCache = NewModelCacheHandler()
)
var modelCache = NewModelCacheHandler()
// model info collection
type _modelCache struct {
@ -332,7 +330,6 @@ end:
// register register models to model cache
func (mc *_modelCache) register(prefixOrSuffixStr string, prefixOrSuffix bool, models ...interface{}) (err error) {
for _, model := range models {
val := reflect.ValueOf(model)
typ := reflect.Indirect(val).Type()

View File

@ -387,7 +387,6 @@ checkType:
fi.timePrecision = &v
}
}
}
if attrs["auto_now"] {

View File

@ -193,22 +193,24 @@ type DataNull struct {
DateTimePtr *time.Time `orm:"null"`
}
type String string
type Boolean bool
type Byte byte
type Rune rune
type Int int
type Int8 int8
type Int16 int16
type Int32 int32
type Int64 int64
type Uint uint
type Uint8 uint8
type Uint16 uint16
type Uint32 uint32
type Uint64 uint64
type Float32 float64
type Float64 float64
type (
String string
Boolean bool
Byte byte
Rune rune
Int int
Int8 int8
Int16 int16
Int32 int32
Int64 int64
Uint uint
Uint8 uint8
Uint16 uint16
Uint32 uint32
Uint64 uint64
Float32 float64
Float64 float64
)
type DataCustom struct {
ID int `orm:"column(id)"`
@ -486,8 +488,7 @@ var (
dDbBaser dbBaser
)
var (
helpinfo = `need driver and source!
var helpinfo = `need driver and source!
Default DB Drivers.
@ -530,7 +531,6 @@ var (
go test -v github.com/beego/beego/v2/pgk/orm
`
)
func init() {
// Debug, _ = StrTo(DBARGS.Debug).Bool()
@ -542,7 +542,6 @@ func init() {
}
err := RegisterDataBase("default", DBARGS.Driver, DBARGS.Source, MaxIdleConnections(20))
if err != nil {
panic(fmt.Sprintf("can not register database: %v", err))
}
@ -551,5 +550,4 @@ func init() {
if alias.Driver == DRMySQL {
alias.Engine = "INNODB"
}
}

View File

@ -101,9 +101,11 @@ type ormBase struct {
db dbQuerier
}
var _ DQL = new(ormBase)
var _ DML = new(ormBase)
var _ DriverGetter = new(ormBase)
var (
_ DQL = new(ormBase)
_ DML = new(ormBase)
_ DriverGetter = new(ormBase)
)
// get model info and model reflect value
func (o *ormBase) getMiInd(md interface{}, needPtr bool) (mi *modelInfo, ind reflect.Value) {
@ -133,6 +135,7 @@ func (o *ormBase) getFieldInfo(mi *modelInfo, name string) *fieldInfo {
func (o *ormBase) Read(md interface{}, cols ...string) error {
return o.ReadWithCtx(context.Background(), md, cols...)
}
func (o *ormBase) ReadWithCtx(ctx context.Context, md interface{}, cols ...string) error {
mi, ind := o.getMiInd(md, true)
return o.alias.DbBaser.Read(ctx, o.db, mi, ind, o.alias.TZ, cols, false)
@ -142,6 +145,7 @@ func (o *ormBase) ReadWithCtx(ctx context.Context, md interface{}, cols ...strin
func (o *ormBase) ReadForUpdate(md interface{}, cols ...string) error {
return o.ReadForUpdateWithCtx(context.Background(), md, cols...)
}
func (o *ormBase) ReadForUpdateWithCtx(ctx context.Context, md interface{}, cols ...string) error {
mi, ind := o.getMiInd(md, true)
return o.alias.DbBaser.Read(ctx, o.db, mi, ind, o.alias.TZ, cols, true)
@ -151,6 +155,7 @@ func (o *ormBase) ReadForUpdateWithCtx(ctx context.Context, md interface{}, cols
func (o *ormBase) ReadOrCreate(md interface{}, col1 string, cols ...string) (bool, int64, error) {
return o.ReadOrCreateWithCtx(context.Background(), md, col1, cols...)
}
func (o *ormBase) ReadOrCreateWithCtx(ctx context.Context, md interface{}, col1 string, cols ...string) (bool, int64, error) {
cols = append([]string{col1}, cols...)
mi, ind := o.getMiInd(md, true)
@ -177,6 +182,7 @@ func (o *ormBase) ReadOrCreateWithCtx(ctx context.Context, md interface{}, col1
func (o *ormBase) Insert(md interface{}) (int64, error) {
return o.InsertWithCtx(context.Background(), md)
}
func (o *ormBase) InsertWithCtx(ctx context.Context, md interface{}) (int64, error) {
mi, ind := o.getMiInd(md, true)
id, err := o.alias.DbBaser.Insert(ctx, o.db, mi, ind, o.alias.TZ)
@ -204,6 +210,7 @@ func (o *ormBase) setPk(mi *modelInfo, ind reflect.Value, id int64) {
func (o *ormBase) InsertMulti(bulk int, mds interface{}) (int64, error) {
return o.InsertMultiWithCtx(context.Background(), bulk, mds)
}
func (o *ormBase) InsertMultiWithCtx(ctx context.Context, bulk int, mds interface{}) (int64, error) {
var cnt int64
@ -242,6 +249,7 @@ func (o *ormBase) InsertMultiWithCtx(ctx context.Context, bulk int, mds interfac
func (o *ormBase) InsertOrUpdate(md interface{}, colConflictAndArgs ...string) (int64, error) {
return o.InsertOrUpdateWithCtx(context.Background(), md, colConflictAndArgs...)
}
func (o *ormBase) InsertOrUpdateWithCtx(ctx context.Context, md interface{}, colConflitAndArgs ...string) (int64, error) {
mi, ind := o.getMiInd(md, true)
id, err := o.alias.DbBaser.InsertOrUpdate(ctx, o.db, mi, ind, o.alias, colConflitAndArgs...)
@ -259,6 +267,7 @@ func (o *ormBase) InsertOrUpdateWithCtx(ctx context.Context, md interface{}, col
func (o *ormBase) Update(md interface{}, cols ...string) (int64, error) {
return o.UpdateWithCtx(context.Background(), md, cols...)
}
func (o *ormBase) UpdateWithCtx(ctx context.Context, md interface{}, cols ...string) (int64, error) {
mi, ind := o.getMiInd(md, true)
return o.alias.DbBaser.Update(ctx, o.db, mi, ind, o.alias.TZ, cols)
@ -269,6 +278,7 @@ func (o *ormBase) UpdateWithCtx(ctx context.Context, md interface{}, cols ...str
func (o *ormBase) Delete(md interface{}, cols ...string) (int64, error) {
return o.DeleteWithCtx(context.Background(), md, cols...)
}
func (o *ormBase) DeleteWithCtx(ctx context.Context, md interface{}, cols ...string) (int64, error) {
mi, ind := o.getMiInd(md, true)
num, err := o.alias.DbBaser.Delete(ctx, o.db, mi, ind, o.alias.TZ, cols)
@ -313,6 +323,7 @@ func (o *ormBase) QueryM2MWithCtx(_ context.Context, md interface{}, name string
func (o *ormBase) LoadRelated(md interface{}, name string, args ...utils.KV) (int64, error) {
return o.LoadRelatedWithCtx(context.Background(), md, name, args...)
}
func (o *ormBase) LoadRelatedWithCtx(ctx context.Context, md interface{}, name string, args ...utils.KV) (int64, error) {
_, fi, ind, qs := o.queryRelated(md, name)
@ -482,6 +493,7 @@ func (o *ormBase) QueryTableWithCtx(_ context.Context, ptrStructOrTableName inte
func (o *ormBase) Raw(query string, args ...interface{}) RawSeter {
return o.RawWithCtx(context.Background(), query, args...)
}
func (o *ormBase) RawWithCtx(ctx context.Context, query string, args ...interface{}) RawSeter {
return newRawSet(o, query, args)
}
@ -571,7 +583,7 @@ func doTxTemplate(o TxBeginner, ctx context.Context, opts *sql.TxOptions,
}
}
}()
var taskTxOrm = _txOrm
taskTxOrm := _txOrm
err = task(ctx, taskTxOrm)
panicked = false
return err

View File

@ -78,7 +78,6 @@ func (c Condition) AndNot(expr string, args ...interface{}) *Condition {
// AndCond combine a condition to current condition
func (c *Condition) AndCond(cond *Condition) *Condition {
if c == cond {
panic(fmt.Errorf("<Condition.AndCond> cannot use self as sub cond"))
}

View File

@ -40,7 +40,7 @@ func NewLog(out io.Writer) *Log {
}
func debugLogQueies(alias *alias, operaton, query string, t time.Time, err error, args ...interface{}) {
var logMap = make(map[string]interface{})
logMap := make(map[string]interface{})
sub := time.Since(t) / 1e5
elsp := float64(int(sub)) / 10.0
logMap["cost_time"] = elsp
@ -94,6 +94,7 @@ func (d *stmtQueryLog) ExecContext(ctx context.Context, args ...interface{}) (sq
debugLogQueies(d.alias, "st.Exec", d.query, a, err, args...)
return res, err
}
func (d *stmtQueryLog) Query(args ...interface{}) (*sql.Rows, error) {
return d.QueryContext(context.Background(), args...)
}
@ -133,9 +134,11 @@ type dbQueryLog struct {
txe txEnder
}
var _ dbQuerier = new(dbQueryLog)
var _ txer = new(dbQueryLog)
var _ txEnder = new(dbQueryLog)
var (
_ dbQuerier = new(dbQueryLog)
_ txer = new(dbQueryLog)
_ txEnder = new(dbQueryLog)
)
func (d *dbQueryLog) Prepare(query string) (*sql.Stmt, error) {
return d.PrepareContext(context.Background(), query)

View File

@ -253,7 +253,6 @@ func (o *rawSet) loopSetRefs(refs []interface{}, sInds []reflect.Value, nIndsPtr
}
cur++
}
} else {
value := reflect.ValueOf(refs[cur]).Elem().Interface()
if isPtr && value == nil {
@ -437,7 +436,6 @@ func (o *rawSet) QueryRow(containers ...interface{}) error {
sInd.Set(nInd)
}
}
} else {
return ErrNoRows
}
@ -606,7 +604,6 @@ func (o *rawSet) QueryRows(containers ...interface{}) (int64, error) {
}
if cnt > 0 {
if structMode {
sInds[0].Set(sInd)
} else {

View File

@ -842,7 +842,6 @@ The program—and web server—godoc processes Go source files to extract docume
throwFailNow(t, AssertIs(nums, num))
}
}
}
func TestCustomField(t *testing.T) {
@ -1235,7 +1234,6 @@ func TestOne(t *testing.T) {
err = qs.Filter("user_name", "nothing").One(&user)
throwFail(t, AssertIs(err, ErrNoRows))
}
func TestValues(t *testing.T) {
@ -1285,8 +1283,8 @@ func TestValuesList(t *testing.T) {
throwFail(t, err)
throwFail(t, AssertIs(num, 3))
if num == 3 {
throwFail(t, AssertIs(list[0][1], "slene")) //username
throwFail(t, AssertIs(list[2][10], nil)) //profile
throwFail(t, AssertIs(list[0][1], "slene")) // username
throwFail(t, AssertIs(list[2][10], nil)) // profile
}
num, err = qs.OrderBy("Id").ValuesList(&list, "UserName", "Profile__Age")
@ -1845,17 +1843,12 @@ func TestRawQueryRow(t *testing.T) {
case "id":
throwFail(t, AssertIs(id, 1))
break
case "time":
case "time", "datetime":
v = v.(time.Time).In(DefaultTimeLoc)
value := dataValues[col].(time.Time).In(DefaultTimeLoc)
assert.True(t, v.(time.Time).Sub(value) <= time.Second)
break
case "date":
case "datetime":
v = v.(time.Time).In(DefaultTimeLoc)
value := dataValues[col].(time.Time).In(DefaultTimeLoc)
assert.True(t, v.(time.Time).Sub(value) <= time.Second)
break
default:
throwFail(t, AssertIs(v, dataValues[col]))
}
@ -2224,7 +2217,7 @@ func TestTransaction(t *testing.T) {
to, err := o.Begin()
throwFail(t, err)
var names = []string{"1", "2", "3"}
names := []string{"1", "2", "3"}
var tag Tag
tag.Name = names[0]
@ -2267,7 +2260,6 @@ func TestTransaction(t *testing.T) {
num, err = o.QueryTable("tag").Filter("name", "commit").Delete()
assert.Nil(t, err)
assert.Equal(t, int64(1), num)
}
func TestTxOrmRollbackUnlessCommit(t *testing.T) {
@ -2768,7 +2760,9 @@ func TestStrPkInsert(t *testing.T) {
if err != nil {
fmt.Println(err)
if err.Error() == "postgres version must 9.5 or higher" || err.Error() == "`sqlite3` nonsupport InsertOrUpdate in beego" {
return
} else if err == ErrLastInsertIdUnavailable {
return
} else {
throwFailNow(t, err)
}

View File

@ -21,7 +21,6 @@ func processingStr(str []string) string {
// Select will join the fields
func (qb *PostgresQueryBuilder) Select(fields ...string) QueryBuilder {
var str string
n := len(fields)
@ -80,7 +79,6 @@ func (qb *PostgresQueryBuilder) RightJoin(table string) QueryBuilder {
// On join with on cond
func (qb *PostgresQueryBuilder) On(cond string) QueryBuilder {
var str string
cond = strings.Replace(cond, " ", "", -1)
slice := strings.Split(cond, "=")

View File

@ -246,7 +246,7 @@ type ormer interface {
DriverGetter
}
//QueryExecutor wrapping for ormer
// QueryExecutor wrapping for ormer
type QueryExecutor interface {
ormer
}

View File

@ -29,8 +29,10 @@ import (
"github.com/beego/beego/v2/core/utils"
)
var startTime = time.Now()
var pid int
var (
startTime = time.Now()
pid int
)
func init() {
pid = os.Getpid()
@ -105,7 +107,6 @@ func PrintGCSummary(w io.Writer) {
}
func printGC(memStats *runtime.MemStats, gcstats *debug.GCStats, w io.Writer) {
if gcstats.NumGC > 0 {
lastPause := gcstats.Pause[0]
elapsed := time.Since(startTime)

View File

@ -16,5 +16,4 @@ package bean
// ApplicationContext define for future
// when we decide to support DI, IoC, this will be core API
type ApplicationContext interface {
}
type ApplicationContext interface{}

142
core/bean/mock.go Normal file
View File

@ -0,0 +1,142 @@
package bean
import (
"fmt"
"reflect"
"strconv"
"strings"
)
// the mock object must be pointer of struct
// the element in mock object can be slices, structures, basic data types, pointers and interface
func Mock(v interface{}) (err error) {
pv := reflect.ValueOf(v)
// the input must be pointer of struct
if pv.Kind() != reflect.Ptr || pv.IsNil() {
err = fmt.Errorf("not a pointer of struct")
return
}
err = mock(pv)
return
}
func mock(pv reflect.Value) (err error) {
pt := pv.Type()
for i := 0; i < pt.Elem().NumField(); i++ {
ptt := pt.Elem().Field(i)
pvv := pv.Elem().FieldByName(ptt.Name)
if !pvv.CanSet() {
continue
}
kt := ptt.Type.Kind()
tagValue := ptt.Tag.Get("mock")
switch kt {
case reflect.Map:
continue
case reflect.Interface:
if pvv.IsNil() { // when interface is nil,can not sure the type
continue
}
pvv.Set(reflect.New(pvv.Elem().Type().Elem()))
err = mock(pvv.Elem())
case reflect.Ptr:
err = mockPtr(pvv, ptt.Type.Elem())
case reflect.Struct:
err = mock(pvv.Addr())
case reflect.Array, reflect.Slice:
err = mockSlice(tagValue, pvv)
case reflect.String:
pvv.SetString(tagValue)
case reflect.Bool:
err = mockBool(tagValue, pvv)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
value, e := strconv.ParseInt(tagValue, 10, 64)
if e != nil || pvv.OverflowInt(value) {
err = fmt.Errorf("the value:%s is invalid", tagValue)
}
pvv.SetInt(value)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
value, e := strconv.ParseUint(tagValue, 10, 64)
if e != nil || pvv.OverflowUint(value) {
err = fmt.Errorf("the value:%s is invalid", tagValue)
}
pvv.SetUint(value)
case reflect.Float32, reflect.Float64:
value, e := strconv.ParseFloat(tagValue, pvv.Type().Bits())
if e != nil || pvv.OverflowFloat(value) {
err = fmt.Errorf("the value:%s is invalid", tagValue)
}
pvv.SetFloat(value)
default:
}
if err != nil {
return
}
}
return
}
// mock slice value
func mockSlice(tagValue string, pvv reflect.Value) (err error) {
if tagValue == "" {
return
}
sliceMetas := strings.Split(tagValue, ":")
if len(sliceMetas) != 2 || sliceMetas[0] != "length" {
err = fmt.Errorf("the value:%s is invalid", tagValue)
return
}
length, e := strconv.Atoi(sliceMetas[1])
if e != nil {
return e
}
sliceType := reflect.SliceOf(pvv.Type().Elem()) // get slice type
itemType := sliceType.Elem() // get the type of item in slice
value := reflect.MakeSlice(sliceType, 0, length)
newSliceValue := make([]reflect.Value, 0, length)
for k := 0; k < length; k++ {
itemValue := reflect.New(itemType).Elem()
// if item in slice is struct or pointer,must set zero value
switch itemType.Kind() {
case reflect.Struct:
err = mock(itemValue.Addr())
case reflect.Ptr:
if itemValue.IsNil() {
itemValue.Set(reflect.New(itemType.Elem()))
if e := mock(itemValue); e != nil {
return e
}
}
}
newSliceValue = append(newSliceValue, itemValue)
if err != nil {
return
}
}
value = reflect.Append(value, newSliceValue...)
pvv.Set(value)
return
}
// mock bool value
func mockBool(tagValue string, pvv reflect.Value) (err error) {
switch tagValue {
case "true":
pvv.SetBool(true)
case "false":
pvv.SetBool(false)
default:
err = fmt.Errorf("the value:%s is invalid", tagValue)
}
return
}
// mock pointer
func mockPtr(pvv reflect.Value, ptt reflect.Type) (err error) {
if pvv.IsNil() {
pvv.Set(reflect.New(ptt)) // must set nil value to zero value
}
err = mock(pvv)
return
}

74
core/bean/mock_test.go Normal file
View File

@ -0,0 +1,74 @@
package bean
import (
"fmt"
"testing"
)
func TestMock(t *testing.T) {
type MockSubSubObject struct {
A int `mock:"20"`
}
type MockSubObjectAnoy struct {
Anoy int `mock:"20"`
}
type MockSubObject struct {
A bool `mock:"true"`
B MockSubSubObject
}
type MockObject struct {
A string `mock:"aaaaa"`
B int8 `mock:"10"`
C []*MockSubObject `mock:"length:2"`
D bool `mock:"true"`
E *MockSubObject
F []int `mock:"length:3"`
G InterfaceA
H InterfaceA
MockSubObjectAnoy
}
m := &MockObject{G: &ImplA{}}
err := Mock(m)
if err != nil {
t.Fatalf("mock failed: %v", err)
}
if m.A != "aaaaa" || m.B != 10 || m.C[1].B.A != 20 ||
!m.E.A || m.E.B.A != 20 || !m.D || len(m.F) != 3 {
t.Fail()
}
_, ok := m.G.(*ImplA)
if !ok {
t.Fail()
}
_, ok = m.G.(*ImplB)
if ok {
t.Fail()
}
_, ok = m.H.(*ImplA)
if ok {
t.Fail()
}
if m.Anoy != 20 {
t.Fail()
}
}
type InterfaceA interface {
Item()
}
type ImplA struct {
A string `mock:"aaa"`
}
func (i *ImplA) Item() {
fmt.Println("implA")
}
type ImplB struct {
B string `mock:"bbb"`
}
func (i *ImplB) Item() {
fmt.Println("implB")
}

View File

@ -46,6 +46,7 @@ func init() {
func goCodeBlock(code string) string {
return codeBlock("go", code)
}
func codeBlock(lan string, code string) string {
return fmt.Sprintf("```%s\n%s\n```", lan, code)
}

View File

@ -66,7 +66,6 @@ func newBaseConfier(str1 string) *BaseConfiger {
} else {
return "", errors.New("mock error")
}
},
}
}

View File

@ -165,6 +165,7 @@ func (c *BaseConfiger) DefaultBool(key string, defaultVal bool) bool {
}
return defaultVal
}
func (c *BaseConfiger) DefaultFloat(key string, defaultVal float64) float64 {
if res, err := c.Float(key); err == nil {
return res
@ -370,5 +371,4 @@ func ToString(x interface{}) string {
type DecodeOption func(options decodeOptions)
type decodeOptions struct {
}
type decodeOptions struct{}

View File

@ -20,7 +20,6 @@ import (
)
func TestExpandValueEnv(t *testing.T) {
testCases := []struct {
item string
want string
@ -51,5 +50,4 @@ func TestExpandValueEnv(t *testing.T) {
t.Errorf("expand value error, item %q want %q, got %q", c.item, c.want, got)
}
}
}

View File

@ -119,7 +119,6 @@ func (e *EtcdConfiger) Sub(key string) (config.Configer, error) {
// TODO remove this before release v2.0.0
func (e *EtcdConfiger) OnChange(key string, fn func(value string)) {
buildOptsFunc := func() []clientv3.OpOption {
return []clientv3.OpOption{}
}
@ -144,11 +143,9 @@ func (e *EtcdConfiger) OnChange(key string, fn func(value string)) {
rch = e.client.Watch(context.Background(), e.prefix+key, buildOptsFunc()...)
}
}()
}
type EtcdConfigerProvider struct {
}
type EtcdConfigerProvider struct{}
// Parse = ParseData([]byte(key))
// key must be json

View File

@ -32,7 +32,6 @@ func TestEtcdConfigerProvider_Parse(t *testing.T) {
}
func TestEtcdConfiger(t *testing.T) {
provider := &EtcdConfigerProvider{}
cfger, _ := provider.Parse(readEtcdConfig())

View File

@ -42,15 +42,19 @@ func String(key string) (string, error) {
func Strings(key string) ([]string, error) {
return globalInstance.Strings(key)
}
func Int(key string) (int, error) {
return globalInstance.Int(key)
}
func Int64(key string) (int64, error) {
return globalInstance.Int64(key)
}
func Bool(key string) (bool, error) {
return globalInstance.Bool(key)
}
func Float(key string) (float64, error) {
return globalInstance.Float(key)
}
@ -64,15 +68,19 @@ func DefaultString(key string, defaultVal string) string {
func DefaultStrings(key string, defaultVal []string) []string {
return globalInstance.DefaultStrings(key, defaultVal)
}
func DefaultInt(key string, defaultVal int) int {
return globalInstance.DefaultInt(key, defaultVal)
}
func DefaultInt64(key string, defaultVal int64) int64 {
return globalInstance.DefaultInt64(key, defaultVal)
}
func DefaultBool(key string, defaultVal bool) bool {
return globalInstance.DefaultBool(key, defaultVal)
}
func DefaultFloat(key string, defaultVal float64) float64 {
return globalInstance.DefaultFloat(key, defaultVal)
}
@ -89,6 +97,7 @@ func GetSection(section string) (map[string]string, error) {
func Unmarshaler(prefix string, obj interface{}, opt ...DecodeOption) error {
return globalInstance.Unmarshaler(prefix, obj, opt...)
}
func Sub(key string) (Configer, error) {
return globalInstance.Sub(key)
}

View File

@ -46,8 +46,7 @@ var (
)
// IniConfig implements Config to parse ini file.
type IniConfig struct {
}
type IniConfig struct{}
// Parse creates a new Config and parses the file configuration from the named file.
func (ini *IniConfig) Parse(name string) (Configer, error) {

View File

@ -23,7 +23,6 @@ import (
)
func TestIni(t *testing.T) {
var (
inicontext = `
;comment one
@ -129,11 +128,9 @@ password = ${GOPATH}
if res != "astaxie" {
t.Fatal("get name error")
}
}
func TestIniSave(t *testing.T) {
const (
inicontext = `
app = app

Some files were not shown because too many files have changed in this diff Show More