Merge remote-tracking branch 'origin/develop' into develop
This commit is contained in:
commit
99b7c0bae4
17
.github/dependabot.yml
vendored
Normal file
17
.github/dependabot.yml
vendored
Normal 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"
|
||||
2
.github/workflows/stale.yml
vendored
2
.github/workflows/stale.yml
vendored
@ -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
124
.github/workflows/test.yml
vendored
Normal 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)
|
||||
75
.travis.yml
75
.travis.yml
@ -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"
|
||||
25
CHANGELOG.md
25
CHANGELOG.md
@ -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)
|
||||
|
||||
14
README.md
14
README.md
@ -1,14 +1,12 @@
|
||||
# Beego [](https://travis-ci.org/beego/beego) [](http://godoc.org/github.com/beego/beego) [](http://golangfoundation.org) [](https://goreportcard.com/report/github.com/beego/beego)
|
||||
# Beego [](https://github.com/beego/beego/actions/workflows/test.yml) [](https://goreportcard.com/report/github.com/beego/beego) [](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.
|
||||
|
||||

|
||||
|
||||
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)).
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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.
|
||||
|
||||
28
adapter/cache/conv_test.go
vendored
28
adapter/cache/conv_test.go
vendored
@ -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")
|
||||
}
|
||||
|
||||
6
adapter/cache/redis/redis.go
vendored
6
adapter/cache/redis/redis.go
vendored
@ -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 {
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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"?>
|
||||
|
||||
@ -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")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -25,7 +25,6 @@ import (
|
||||
|
||||
// Demo is used to test, it's empty
|
||||
func Demo(i int) {
|
||||
|
||||
}
|
||||
|
||||
func TestConvertParams(t *testing.T) {
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
}
|
||||
@ -72,5 +72,4 @@ func TestRedisSentinel(t *testing.T) {
|
||||
assert.Nil(t, password)
|
||||
|
||||
sess.SessionRelease(w)
|
||||
|
||||
}
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -79,7 +79,6 @@ func TestHtmlunquote(t *testing.T) {
|
||||
h := `<' ”“&">`
|
||||
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)
|
||||
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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]
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -19,6 +19,7 @@ import (
|
||||
)
|
||||
|
||||
type reducetype func(interface{}) interface{}
|
||||
|
||||
type filtertype func(interface{}) bool
|
||||
|
||||
// InSlice checks given string in string slice or not.
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
}
|
||||
|
||||
9
client/cache/calc_utils.go
vendored
9
client/cache/calc_utils.go
vendored
@ -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
|
||||
|
||||
28
client/cache/conv_test.go
vendored
28
client/cache/conv_test.go
vendored
@ -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))
|
||||
|
||||
6
client/cache/error_code.go
vendored
6
client/cache/error_code.go
vendored
@ -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")
|
||||
)
|
||||
|
||||
1
client/cache/file.go
vendored
1
client/cache/file.go
vendored
@ -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 {
|
||||
|
||||
6
client/cache/memory.go
vendored
6
client/cache/memory.go
vendored
@ -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 {
|
||||
|
||||
6
client/cache/redis/redis.go
vendored
6
client/cache/redis/redis.go
vendored
@ -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 {
|
||||
|
||||
1
client/cache/redis/redis_test.go
vendored
1
client/cache/redis/redis_test.go
vendored
@ -28,7 +28,6 @@ import (
|
||||
)
|
||||
|
||||
func TestRedisCache(t *testing.T) {
|
||||
|
||||
redisAddr := os.Getenv("REDIS_ADDR")
|
||||
if redisAddr == "" {
|
||||
redisAddr = "127.0.0.1:6379"
|
||||
|
||||
1
client/cache/ssdb/ssdb.go
vendored
1
client/cache/ssdb/ssdb.go
vendored
@ -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.
|
||||
|
||||
1
client/cache/ssdb/ssdb_test.go
vendored
1
client/cache/ssdb/ssdb_test.go
vendored
@ -15,7 +15,6 @@ import (
|
||||
)
|
||||
|
||||
func TestSsdbcacheCache(t *testing.T) {
|
||||
|
||||
ssdbAddr := os.Getenv("SSDB_ADDR")
|
||||
if ssdbAddr == "" {
|
||||
ssdbAddr = "127.0.0.1:8888"
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
155
client/httplib/client_option.go
Normal file
155
client/httplib/client_option.go
Normal 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)
|
||||
}
|
||||
}
|
||||
261
client/httplib/client_option_test.go
Normal file
261
client/httplib/client_option_test.go
Normal 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)
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
`)
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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",
|
||||
|
||||
174
client/httplib/httpclient.go
Normal file
174
client/httplib/httpclient.go
Normal 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)
|
||||
}
|
||||
220
client/httplib/httpclient_test.go
Normal file
220
client/httplib/httpclient_test.go
Normal 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)
|
||||
}
|
||||
@ -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()
|
||||
|
||||
@ -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) {
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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")
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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(), ``)
|
||||
}
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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),
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -58,5 +58,4 @@ func TestFilterChainBuilder_FilterChain1(t *testing.T) {
|
||||
|
||||
inv.Method = "Update"
|
||||
builder.report(ctx, inv, time.Second)
|
||||
|
||||
}
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -27,7 +27,6 @@ import (
|
||||
)
|
||||
|
||||
func TestFilterOrmDecorator_Read(t *testing.T) {
|
||||
|
||||
register()
|
||||
|
||||
o := &filterMockOrm{}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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...)
|
||||
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -387,7 +387,6 @@ checkType:
|
||||
fi.timePrecision = &v
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if attrs["auto_now"] {
|
||||
|
||||
@ -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"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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"))
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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, "=")
|
||||
|
||||
@ -246,7 +246,7 @@ type ormer interface {
|
||||
DriverGetter
|
||||
}
|
||||
|
||||
//QueryExecutor wrapping for ormer
|
||||
// QueryExecutor wrapping for ormer
|
||||
type QueryExecutor interface {
|
||||
ormer
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
142
core/bean/mock.go
Normal 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
74
core/bean/mock_test.go
Normal 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")
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -66,7 +66,6 @@ func newBaseConfier(str1 string) *BaseConfiger {
|
||||
} else {
|
||||
return "", errors.New("mock error")
|
||||
}
|
||||
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -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{}
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -32,7 +32,6 @@ func TestEtcdConfigerProvider_Parse(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestEtcdConfiger(t *testing.T) {
|
||||
|
||||
provider := &EtcdConfigerProvider{}
|
||||
cfger, _ := provider.Parse(readEtcdConfig())
|
||||
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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
Loading…
x
Reference in New Issue
Block a user