Compare commits

..

107 Commits

Author SHA1 Message Date
Kevin Wan
8c9b619199 chore: update go-zero for goctl (#3165) 2023-04-24 13:02:26 +08:00
Kevin Wan
49f73265b9 chore: refactor (#3164) 2023-04-24 12:34:52 +08:00
Kevin Wan
7568674b2b chore: use %q instead of %s for unmarshaling (#3163) 2023-04-24 12:11:12 +08:00
Kevin Wan
3da740b7fc chore: remove unnecessary code (#3161) 2023-04-23 22:58:22 +08:00
chen quan
ce4eb6ed61 fix: fixed #2945 (#2953)
Co-authored-by: Kevin Wan <wanjunfeng@gmail.com>
2023-04-23 14:22:03 +00:00
MarkJoyMa
9970ff55cd feat: refactor gateway code (#3160) 2023-04-23 22:05:10 +08:00
MarkJoyMa
d10740f871 feat: inheritance rewrite error prompt is more friendly (#3156) 2023-04-23 12:56:54 +00:00
Kevin Wan
027193dc99 chore: refactor gateway (#3157) 2023-04-22 23:25:51 +08:00
Kevin Wan
de1e0f2410 Update readme-cn.md 2023-04-22 22:36:55 +08:00
Kevin Wan
062073ce58 chore: update codecov to ignore mock files (#3155) 2023-04-22 14:07:15 +08:00
MarkJoyMa
e20b02f311 gateway: open timeout function cabinet (#3047)
Co-authored-by: Kevin Wan <wanjunfeng@gmail.com>
2023-04-22 05:23:47 +00:00
Kevin Wan
02357d2616 chore: make error message more readable (#3154) 2023-04-22 13:03:59 +08:00
guangwu
489d69f779 Add debug message on unmarshal errors (#3153) 2023-04-21 13:12:02 +00:00
Kevin Wan
117611a170 fix: default value for keepalive set to 0 (#3152) 2023-04-21 03:15:05 +00:00
Kevin Wan
0a46ad7ac1 chore: fix go 1.18 dep problem (#3149) 2023-04-21 01:01:17 +08:00
Liam Hao
bf905eaff3 fix default grpc-gateway connect timeout (#3142) 2023-04-20 15:13:13 +00:00
dependabot[bot]
88cb35e3d5 chore(deps): bump github.com/alicebob/miniredis/v2 from 2.30.1 to 2.30.2 (#3144)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-20 22:59:57 +08:00
fondoger
078825b4eb [dart-gen] Support Null-safe and omitempty json tag (#3134) 2023-04-17 05:06:52 +00:00
Kevin Wan
bbfce6abe9 chore: refactor max/min in fx (#3135) 2023-04-16 23:40:30 +08:00
suplalalala
0d11ce03a8 feature: two evaluate operate func addtion in package stream (#3129)
Co-authored-by: Riven <Riven.chen@hairobotics.com>
2023-04-16 15:14:25 +00:00
dependabot[bot]
757ed19dc5 chore(deps): bump k8s.io/apimachinery from 0.26.3 to 0.27.1 (#3131)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-15 22:29:46 +08:00
dependabot[bot]
c5fd074aac chore(deps): bump github.com/prometheus/client_golang from 1.14.0 to 1.15.0 (#3122)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-15 22:01:02 +08:00
LiKe
8fa0bd1f1c fix(goctl): test field (#3114) 2023-04-15 21:46:37 +08:00
dependabot[bot]
ede19a89ec chore(deps): bump go.etcd.io/etcd/client/v3 from 3.5.7 to 3.5.8 (#3123)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-15 21:24:11 +08:00
anqiansong
73664b92f0 fix(goctl): missing rpc --style flag (#3112) 2023-04-10 09:48:48 +00:00
Kevin Wan
8d9c2fa22a chore: update go-zero version in goctl (#3109) 2023-04-08 23:24:29 +08:00
cong
22fad4bb9c feat(trace): add trace test helpers (#3108) 2023-04-08 14:52:25 +00:00
lchjczw
189e9bd9da Fix the problem of package name for generated kt code. (#3082)
Co-authored-by: 李春华 <lichunhua@threesoft.cn>
2023-04-08 14:46:34 +00:00
Kevin Wan
98c9b5928a refactor: simplify zrpc stat config (#3107) 2023-04-08 14:45:05 +00:00
Kevin Wan
e13fd62d38 chore: coding style (#3106)
Co-authored-by: cong <zhangcong1992@gmail.com>
2023-04-08 21:37:53 +08:00
李登富
ffacae89eb fix:multipule flag client go package name (#3104)
Co-authored-by: lidengfu <lidengfu@excean.com>
2023-04-08 21:36:45 +08:00
cong
49135fe25e refactor(zrpc): prefer static config for zrpc server statinterceptor (#3105) 2023-04-08 13:03:32 +00:00
MarkJoyMa
2e6402f4b5 fix: fillDefault, handling of nested structs (#3072) 2023-04-08 11:43:13 +00:00
Kevin Wan
07f03ebd0c fix: should not conflict on lower members (#3095) 2023-04-08 14:47:57 +08:00
dependabot[bot]
92f2676afc chore(deps): bump golang.org/x/text from 0.8.0 to 0.9.0 in /tools/goctl (#3101) 2023-04-08 13:28:01 +08:00
dependabot[bot]
1807305e6d chore(deps): bump golang.org/x/net from 0.8.0 to 0.9.0 (#3100) 2023-04-08 13:27:14 +08:00
dependabot[bot]
38a97d4531 chore(deps): bump github.com/spf13/cobra from 1.6.1 to 1.7.0 in /tools/goctl (#3098)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-07 20:41:03 +08:00
dependabot[bot]
b9f98ecc4a chore(deps): bump go.mongodb.org/mongo-driver from 1.11.3 to 1.11.4 (#3097)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-07 20:22:51 +08:00
dependabot[bot]
1dc222f4b2 chore(deps): bump golang.org/x/sys from 0.6.0 to 0.7.0 (#3096)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-05 22:33:40 +08:00
cong
a79b8de24d feat(bloom): bloom support Ctx API (#3089) 2023-04-03 14:37:04 +00:00
cong
5da8a93c75 feat(redis): add ScriptRun API and migrate EvalCtx to ScriptRun for limit, lock and bloom (#3087) 2023-04-02 11:28:25 +08:00
cong
b49fc81618 refactor(redistest): simplify redistest.CreateRedis API (#3086) 2023-04-01 05:02:21 +00:00
cong
6a692453dc chore(ci): fail lint ci when gofmt or tidy check failed (#3085) 2023-04-01 03:41:17 +00:00
Kevin Wan
8d0cceb80c chore: add more tests (#3084) 2023-03-31 22:33:43 +08:00
heyehang
e06abf4f6f fixbug:superfluous response.WriteHeader (#3083) 2023-03-31 13:05:29 +00:00
Kevin Wan
ee555a85da chore: coding style (#3080) 2023-03-31 02:13:48 +00:00
anqiansong
1904af2323 feat(goctl): Support gateway sample generation (#3049) 2023-03-29 09:06:23 +00:00
cong
95b85336d6 refactor(redis): add NonBlock config, disable redis ping by default (#3073) 2023-03-29 02:28:12 +00:00
guoguangwu
ca4ce7bce8 fix : misspelled word (#3075) 2023-03-29 02:25:26 +00:00
Kevin Wan
9065eb90d9 chore: coding style (#3074) 2023-03-28 16:34:22 +00:00
anqiansong
50bc361430 feat(goctl): Add api parser (#2585) 2023-03-28 15:45:26 +00:00
Kevin Wan
455a6c8f97 Update readme-cn.md, add company users. 2023-03-27 12:22:32 +08:00
Kevin Wan
04434646eb chore: refactor zrpc setup (#3064) 2023-03-25 20:40:21 +08:00
dependabot[bot]
992a56e90b chore(deps): bump google.golang.org/grpc from 1.53.0 to 1.54.0 in /tools/goctl (#3061)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-24 16:14:44 +08:00
dependabot[bot]
ed4d5e5813 chore(deps): bump google.golang.org/grpc from 1.53.0 to 1.54.0 (#3060)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-24 11:44:26 +08:00
dependabot[bot]
fe85e7cb42 chore(deps): bump k8s.io/client-go from 0.26.2 to 0.26.3 (#3052)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-24 10:16:45 +08:00
Kevin Wan
9c6b516bb8 fix: #3058 (#3059) 2023-03-23 23:45:57 +08:00
dependabot[bot]
2e9063a9a1 chore(deps): bump go.mongodb.org/mongo-driver from 1.11.2 to 1.11.3 (#3054)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-23 22:46:50 +08:00
dependabot[bot]
c3648be533 chore(deps): bump go.uber.org/automaxprocs from 1.5.1 to 1.5.2 (#3051)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-23 22:23:47 +08:00
Kevin Wan
0ab06f62ca chore: add more tests (#3045) 2023-03-19 23:56:36 +08:00
Kevin Wan
6170d7b790 feat: rest validation on http requests (#3041) 2023-03-19 12:04:18 +00:00
cong
18d163c4f7 fix(executors): periodicalexecutor should handle crash correctly (#3043) 2023-03-18 15:04:15 +00:00
Snake
a561048d59 Fix bug: replace int and float with num type in dart (#3042)
Co-authored-by: zhoumingji <zhoumingji@cmsr.chinamobile.com>
2023-03-18 14:49:22 +00:00
dependabot[bot]
7a647ca40c chore(deps): bump google.golang.org/protobuf from 1.29.1 to 1.30.0 in /tools/goctl (#3037)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-17 20:40:36 +08:00
dependabot[bot]
3f6f14f976 chore(deps): bump google.golang.org/protobuf from 1.29.1 to 1.30.0 (#3036)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-17 20:25:43 +08:00
dependabot[bot]
a78d57bebd chore(deps): bump google.golang.org/protobuf from 1.28.2-0.20220831092852-f930b1dc76e8 to 1.29.1 in /tools/goctl (#3029)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-16 00:20:18 +08:00
dependabot[bot]
74452eb7b5 chore(deps): bump golang.org/x/text from 0.7.0 to 0.8.0 in /tools/goctl (#3028)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-15 23:56:58 +08:00
dependabot[bot]
a9e364a01a chore(deps): bump golang.org/x/net from 0.7.0 to 0.8.0 (#3027)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-15 23:32:23 +08:00
chen quan
29c2e20b41 chore(action): upgrade go 1.18 version in release (#3032) 2023-03-15 12:53:04 +00:00
dependabot[bot]
42c146bcbd chore(deps): bump google.golang.org/protobuf from 1.29.0 to 1.29.1 (#3026)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-15 11:30:19 +08:00
dependabot[bot]
b61e364458 chore(deps): bump github.com/zeromicro/go-zero from 1.4.4 to 1.5.0 in /tools/goctl (#3023) 2023-03-14 08:48:42 +08:00
dependabot[bot]
18a4dcb79f chore(deps): bump github.com/fatih/color from 1.14.1 to 1.15.0 (#3022) 2023-03-14 08:47:44 +08:00
Kevin Wan
60a13f1e53 chore: add more tests (#3018) 2023-03-12 20:42:50 +08:00
sniperwzq
3e093bf34e defines the method to customize http server (#2171) 2023-03-11 23:15:00 +08:00
Kevin Wan
211b9498ef chore: add more tests (#3016) 2023-03-11 22:22:39 +08:00
Kevin Wan
cca45be3c5 chore: refactor orm code (#3015) 2023-03-11 18:03:20 +08:00
YK.xiong
e735915d89 fix QueryRowsPartial getTaggedFieldValueMap func (#2884)
Co-authored-by: yongkun.xiong <weilone@vip.qq.com>
2023-03-11 07:28:09 +00:00
Kevin Wan
f77e2c9cfa chore: add more tests (#3014) 2023-03-11 14:57:56 +08:00
Shyunn
544aa7c432 Added zrpc server custom serverID for custom registration Key when the service is registered on ETCD. (#3008) 2023-03-11 14:34:28 +08:00
Kevin Wan
4cef2b412c fix: avoid unmarshal panic with incorrect map keys #3002 (#3013) 2023-03-11 07:53:57 +08:00
Kevin Wan
123c61ad12 chore: update readme (#3011) 2023-03-10 22:18:48 +08:00
Kevin Wan
fbf129d535 chore: add more tests (#3010) 2023-03-10 21:56:19 +08:00
Kevin Wan
c8a17a97be chore: add more tests (#3009) 2023-03-10 20:48:10 +08:00
Kevin Wan
3a493cd6a6 chore: add more tests (#3006) 2023-03-10 17:36:39 +08:00
Kevin Wan
7a0c04bc21 feat: unique redis addrs and trim spaces (#3004) 2023-03-10 16:09:07 +08:00
iyyzh
3c9fe0b381 init postgresql err (#3003) 2023-03-10 05:58:07 +00:00
文豆芽
f8b2dc8c9f reids cluster bug (#2986)
Co-authored-by: shaocongcong <shao.congcong@yalla.live>
2023-03-09 21:37:34 +08:00
taobig
37cb00d789 Export cache.Option param to NewXXXModel() (#2995) 2023-03-09 13:34:58 +00:00
dependabot[bot]
e3e7bc736b chore(deps): bump google.golang.org/protobuf from 1.28.2-0.20230222093303-bc1253ad3743 to 1.29.0 (#2993)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-09 19:56:14 +08:00
dependabot[bot]
fafbee24b8 chore(deps): bump github.com/golang/protobuf from 1.5.2 to 1.5.3 (#2992)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-09 16:24:37 +08:00
dependabot[bot]
8ec29d29ce chore(deps): bump golang.org/x/sys from 0.5.0 to 0.6.0 (#2983)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-09 15:23:02 +08:00
fabio
cb7f3e8a17 feat(redis):add LpopCount,RpopCount (#2990) 2023-03-09 05:45:45 +00:00
dependabot[bot]
03391b48ca chore(deps): bump github.com/alicebob/miniredis/v2 from 2.30.0 to 2.30.1 (#2991)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-09 13:34:48 +08:00
dependabot[bot]
d0dedb0624 chore(deps): bump github.com/jhump/protoreflect from 1.15.0 to 1.15.1 (#2982)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-08 23:55:43 +08:00
Snake
e136deb3a7 Update goclt dart gen: Add scheme config and content-type header (#2987)
Co-authored-by: zhoumingji <zhoumingji@cmsr.chinamobile.com>
2023-03-08 15:40:55 +00:00
anqiansong
a2592a17e9 format code 2023-03-08 15:32:08 +00:00
anqiansong
05abf4a2ff fix typo 2023-03-08 15:32:08 +00:00
anqiansong
d40000d4b9 fix typo 2023-03-08 15:32:08 +00:00
anqiansong
4620924105 Fix typo 2023-03-08 15:32:08 +00:00
Kevin Wan
a05fe7bf0a chore: remove optional in redis config (#2979) 2023-03-07 14:58:04 +08:00
kevin
dd347e96b0 chore: add comments 2023-03-07 01:27:41 +00:00
kevin
a972f400c6 fix: test failure 2023-03-07 01:27:41 +00:00
kevin.wan
fb7664a764 fix: config map with json tag 2023-03-07 01:27:41 +00:00
Kevin Wan
7d5d7d9085 chore: clear errors on conf conflict keys (#2972)
Co-authored-by: kevin.wan <kevin.wan@yijinin.com>
2023-03-06 12:45:17 +08:00
Kevin Wan
9911c11e9c Update FUNDING.yml 2023-03-05 22:47:17 +08:00
Kevin Wan
0d5a68869d fix: gateway conf doesn't work (#2968) 2023-03-05 22:19:58 +08:00
Kevin Wan
d9d79e930d Merge pull request from GHSA-fgxv-gw55-r5fq
* fix: Authorization Bypass Through User-Controlled Key

* chore: add not safe domain test
2023-03-04 23:34:11 +08:00
226 changed files with 16429 additions and 2378 deletions

View File

@@ -3,4 +3,6 @@ comment:
behavior: once behavior: once
require_changes: true require_changes: true
ignore: ignore:
- "tools" - "tools"
- "**/mock"
- "**/*_mock.go"

2
.github/FUNDING.yml vendored
View File

@@ -10,4 +10,4 @@ liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username otechie: # Replace with a single Otechie username
custom: # https://gitee.com/kevwan/static/raw/master/images/sponsor.jpg custom: # https://gitee.com/kevwan/static/raw/master/images/sponsor.jpg
ethereum: 0x5052b7f6B937B02563996D23feb69b38D06Ca150 | kevwan ethereum: # 0x5052b7f6B937B02563996D23feb69b38D06Ca150 | kevwan

View File

@@ -17,7 +17,7 @@ jobs:
- name: Set up Go 1.x - name: Set up Go 1.x
uses: actions/setup-go@v3 uses: actions/setup-go@v3
with: with:
go-version: ^1.18 go-version: 1.18
check-latest: true check-latest: true
cache: true cache: true
id: go id: go
@@ -29,8 +29,12 @@ jobs:
- name: Lint - name: Lint
run: | run: |
go vet -stdmethods=false $(go list ./...) go vet -stdmethods=false $(go list ./...)
go install mvdan.cc/gofumpt@latest
test -z "$(gofumpt -l -extra .)" || echo "Please run 'gofumpt -l -w -extra .'" go mod tidy
if ! test -z "$(git status --porcelain)"; then
echo "Please run 'go mod tidy'"
exit 1
fi
- name: Test - name: Test
run: go test -race -coverprofile=coverage.txt -covermode=atomic ./... run: go test -race -coverprofile=coverage.txt -covermode=atomic ./...

View File

@@ -22,7 +22,7 @@ jobs:
github_token: ${{ secrets.GITHUB_TOKEN }} github_token: ${{ secrets.GITHUB_TOKEN }}
goos: ${{ matrix.goos }} goos: ${{ matrix.goos }}
goarch: ${{ matrix.goarch }} goarch: ${{ matrix.goarch }}
goversion: "https://dl.google.com/go/go1.17.5.linux-amd64.tar.gz" goversion: "https://dl.google.com/go/go1.18.10.linux-amd64.tar.gz"
project_path: "tools/goctl" project_path: "tools/goctl"
binary_name: "goctl" binary_name: "goctl"
extra_files: tools/goctl/readme.md tools/goctl/readme-cn.md extra_files: tools/goctl/readme.md tools/goctl/readme-cn.md

View File

@@ -1,6 +1,7 @@
package bloom package bloom
import ( import (
"context"
"errors" "errors"
"strconv" "strconv"
@@ -8,28 +9,29 @@ import (
"github.com/zeromicro/go-zero/core/stores/redis" "github.com/zeromicro/go-zero/core/stores/redis"
) )
const ( // for detailed error rate table, see http://pages.cs.wisc.edu/~cao/papers/summary-cache/node8.html
// for detailed error rate table, see http://pages.cs.wisc.edu/~cao/papers/summary-cache/node8.html // maps as k in the error rate table
// maps as k in the error rate table const maps = 14
maps = 14
setScript = ` var (
// ErrTooLargeOffset indicates the offset is too large in bitset.
ErrTooLargeOffset = errors.New("too large offset")
setScript = redis.NewScript(`
for _, offset in ipairs(ARGV) do for _, offset in ipairs(ARGV) do
redis.call("setbit", KEYS[1], offset, 1) redis.call("setbit", KEYS[1], offset, 1)
end end
` `)
testScript = ` testScript = redis.NewScript(`
for _, offset in ipairs(ARGV) do for _, offset in ipairs(ARGV) do
if tonumber(redis.call("getbit", KEYS[1], offset)) == 0 then if tonumber(redis.call("getbit", KEYS[1], offset)) == 0 then
return false return false
end end
end end
return true return true
` `)
) )
// ErrTooLargeOffset indicates the offset is too large in bitset.
var ErrTooLargeOffset = errors.New("too large offset")
type ( type (
// A Filter is a bloom filter. // A Filter is a bloom filter.
Filter struct { Filter struct {
@@ -38,8 +40,8 @@ type (
} }
bitSetProvider interface { bitSetProvider interface {
check([]uint) (bool, error) check(ctx context.Context, offsets []uint) (bool, error)
set([]uint) error set(ctx context.Context, offsets []uint) error
} }
) )
@@ -58,14 +60,24 @@ func New(store *redis.Redis, key string, bits uint) *Filter {
// Add adds data into f. // Add adds data into f.
func (f *Filter) Add(data []byte) error { func (f *Filter) Add(data []byte) error {
return f.AddCtx(context.Background(), data)
}
// AddCtx adds data into f with context.
func (f *Filter) AddCtx(ctx context.Context, data []byte) error {
locations := f.getLocations(data) locations := f.getLocations(data)
return f.bitSet.set(locations) return f.bitSet.set(ctx, locations)
} }
// Exists checks if data is in f. // Exists checks if data is in f.
func (f *Filter) Exists(data []byte) (bool, error) { func (f *Filter) Exists(data []byte) (bool, error) {
return f.ExistsCtx(context.Background(), data)
}
// ExistsCtx checks if data is in f with context.
func (f *Filter) ExistsCtx(ctx context.Context, data []byte) (bool, error) {
locations := f.getLocations(data) locations := f.getLocations(data)
isSet, err := f.bitSet.check(locations) isSet, err := f.bitSet.check(ctx, locations)
if err != nil { if err != nil {
return false, err return false, err
} }
@@ -111,13 +123,13 @@ func (r *redisBitSet) buildOffsetArgs(offsets []uint) ([]string, error) {
return args, nil return args, nil
} }
func (r *redisBitSet) check(offsets []uint) (bool, error) { func (r *redisBitSet) check(ctx context.Context, offsets []uint) (bool, error) {
args, err := r.buildOffsetArgs(offsets) args, err := r.buildOffsetArgs(offsets)
if err != nil { if err != nil {
return false, err return false, err
} }
resp, err := r.store.Eval(testScript, []string{r.key}, args) resp, err := r.store.ScriptRunCtx(ctx, testScript, []string{r.key}, args)
if err == redis.Nil { if err == redis.Nil {
return false, nil return false, nil
} else if err != nil { } else if err != nil {
@@ -132,22 +144,24 @@ func (r *redisBitSet) check(offsets []uint) (bool, error) {
return exists == 1, nil return exists == 1, nil
} }
// del only use for testing.
func (r *redisBitSet) del() error { func (r *redisBitSet) del() error {
_, err := r.store.Del(r.key) _, err := r.store.Del(r.key)
return err return err
} }
// expire only use for testing.
func (r *redisBitSet) expire(seconds int) error { func (r *redisBitSet) expire(seconds int) error {
return r.store.Expire(r.key, seconds) return r.store.Expire(r.key, seconds)
} }
func (r *redisBitSet) set(offsets []uint) error { func (r *redisBitSet) set(ctx context.Context, offsets []uint) error {
args, err := r.buildOffsetArgs(offsets) args, err := r.buildOffsetArgs(offsets)
if err != nil { if err != nil {
return err return err
} }
_, err = r.store.Eval(setScript, []string{r.key}, args) _, err = r.store.ScriptRunCtx(ctx, setScript, []string{r.key}, args)
if err == redis.Nil { if err == redis.Nil {
return nil return nil
} }

View File

@@ -1,30 +1,31 @@
package bloom package bloom
import ( import (
"context"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/stores/redis/redistest" "github.com/zeromicro/go-zero/core/stores/redis/redistest"
) )
func TestRedisBitSet_New_Set_Test(t *testing.T) { func TestRedisBitSet_New_Set_Test(t *testing.T) {
store, clean, err := redistest.CreateRedis() store := redistest.CreateRedis(t)
assert.Nil(t, err) ctx := context.Background()
defer clean()
bitSet := newRedisBitSet(store, "test_key", 1024) bitSet := newRedisBitSet(store, "test_key", 1024)
isSetBefore, err := bitSet.check([]uint{0}) isSetBefore, err := bitSet.check(ctx, []uint{0})
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if isSetBefore { if isSetBefore {
t.Fatal("Bit should not be set") t.Fatal("Bit should not be set")
} }
err = bitSet.set([]uint{512}) err = bitSet.set(ctx, []uint{512})
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
isSetAfter, err := bitSet.check([]uint{512}) isSetAfter, err := bitSet.check(ctx, []uint{512})
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -42,9 +43,7 @@ func TestRedisBitSet_New_Set_Test(t *testing.T) {
} }
func TestRedisBitSet_Add(t *testing.T) { func TestRedisBitSet_Add(t *testing.T) {
store, clean, err := redistest.CreateRedis() store := redistest.CreateRedis(t)
assert.Nil(t, err)
defer clean()
filter := New(store, "test_key", 64) filter := New(store, "test_key", 64)
assert.Nil(t, filter.Add([]byte("hello"))) assert.Nil(t, filter.Add([]byte("hello")))
@@ -53,3 +52,51 @@ func TestRedisBitSet_Add(t *testing.T) {
assert.Nil(t, err) assert.Nil(t, err)
assert.True(t, ok) assert.True(t, ok)
} }
func TestFilter_Exists(t *testing.T) {
store, clean := redistest.CreateRedisWithClean(t)
rbs := New(store, "test", 64)
_, err := rbs.Exists([]byte{0, 1, 2})
assert.NoError(t, err)
clean()
rbs = New(store, "test", 64)
_, err = rbs.Exists([]byte{0, 1, 2})
assert.Error(t, err)
}
func TestRedisBitSet_check(t *testing.T) {
store, clean := redistest.CreateRedisWithClean(t)
ctx := context.Background()
rbs := newRedisBitSet(store, "test", 0)
assert.Error(t, rbs.set(ctx, []uint{0, 1, 2}))
_, err := rbs.check(ctx, []uint{0, 1, 2})
assert.Error(t, err)
rbs = newRedisBitSet(store, "test", 64)
_, err = rbs.check(ctx, []uint{0, 1, 2})
assert.NoError(t, err)
clean()
rbs = newRedisBitSet(store, "test", 64)
_, err = rbs.check(ctx, []uint{0, 1, 2})
assert.Error(t, err)
}
func TestRedisBitSet_set(t *testing.T) {
logx.Disable()
store, clean := redistest.CreateRedisWithClean(t)
ctx := context.Background()
rbs := newRedisBitSet(store, "test", 0)
assert.Error(t, rbs.set(ctx, []uint{0, 1, 2}))
rbs = newRedisBitSet(store, "test", 64)
assert.NoError(t, rbs.set(ctx, []uint{0, 1, 2}))
clean()
rbs = newRedisBitSet(store, "test", 64)
assert.Error(t, rbs.set(ctx, []uint{0, 1, 2}))
}

View File

@@ -2,6 +2,8 @@ package codec
import ( import (
"bytes" "bytes"
"compress/gzip"
"errors"
"fmt" "fmt"
"testing" "testing"
@@ -21,3 +23,45 @@ func TestGzip(t *testing.T) {
assert.True(t, len(bs) < buf.Len()) assert.True(t, len(bs) < buf.Len())
assert.Equal(t, buf.Bytes(), actual) assert.Equal(t, buf.Bytes(), actual)
} }
func TestGunzip(t *testing.T) {
tests := []struct {
name string
input []byte
expected []byte
expectedErr error
}{
{
name: "valid input",
input: func() []byte {
var buf bytes.Buffer
gz := gzip.NewWriter(&buf)
gz.Write([]byte("hello"))
gz.Close()
return buf.Bytes()
}(),
expected: []byte("hello"),
expectedErr: nil,
},
{
name: "invalid input",
input: []byte("invalid input"),
expected: nil,
expectedErr: gzip.ErrHeader,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
result, err := Gunzip(test.input)
if !bytes.Equal(result, test.expected) {
t.Errorf("unexpected result: %v", result)
}
if !errors.Is(err, test.expectedErr) {
t.Errorf("unexpected error: %v", err)
}
})
}
}

View File

@@ -2,6 +2,7 @@ package codec
import ( import (
"encoding/base64" "encoding/base64"
"os"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@@ -41,6 +42,7 @@ func TestCryption(t *testing.T) {
file, err := fs.TempFilenameWithText(priKey) file, err := fs.TempFilenameWithText(priKey)
assert.Nil(t, err) assert.Nil(t, err)
defer os.Remove(file)
dec, err := NewRsaDecrypter(file) dec, err := NewRsaDecrypter(file)
assert.Nil(t, err) assert.Nil(t, err)
actual, err := dec.Decrypt(ret) actual, err := dec.Decrypt(ret)

View File

@@ -13,7 +13,10 @@ import (
"github.com/zeromicro/go-zero/internal/encoding" "github.com/zeromicro/go-zero/internal/encoding"
) )
const jsonTagKey = "json" const (
jsonTagKey = "json"
jsonTagSep = ','
)
var ( var (
fillDefaultUnmarshaler = mapping.NewUnmarshaler(jsonTagKey, mapping.WithDefault()) fillDefaultUnmarshaler = mapping.NewUnmarshaler(jsonTagKey, mapping.WithDefault())
@@ -70,13 +73,13 @@ func LoadConfig(file string, v any, opts ...Option) error {
// LoadFromJsonBytes loads config into v from content json bytes. // LoadFromJsonBytes loads config into v from content json bytes.
func LoadFromJsonBytes(content []byte, v any) error { func LoadFromJsonBytes(content []byte, v any) error {
info, err := buildFieldsInfo(reflect.TypeOf(v)) info, err := buildFieldsInfo(reflect.TypeOf(v), "")
if err != nil { if err != nil {
return err return err
} }
var m map[string]any var m map[string]any
if err := jsonx.Unmarshal(content, &m); err != nil { if err = jsonx.Unmarshal(content, &m); err != nil {
return err return err
} }
@@ -124,13 +127,13 @@ func MustLoad(path string, v any, opts ...Option) {
} }
} }
func addOrMergeFields(info *fieldInfo, key string, child *fieldInfo) error { func addOrMergeFields(info *fieldInfo, key string, child *fieldInfo, fullName string) error {
if prev, ok := info.children[key]; ok { if prev, ok := info.children[key]; ok {
if child.mapField != nil { if child.mapField != nil {
return newDupKeyError(key) return newConflictKeyError(fullName)
} }
if err := mergeFields(prev, key, child.children); err != nil { if err := mergeFields(prev, key, child.children, fullName); err != nil {
return err return err
} }
} else { } else {
@@ -140,27 +143,27 @@ func addOrMergeFields(info *fieldInfo, key string, child *fieldInfo) error {
return nil return nil
} }
func buildAnonymousFieldInfo(info *fieldInfo, lowerCaseName string, ft reflect.Type) error { func buildAnonymousFieldInfo(info *fieldInfo, lowerCaseName string, ft reflect.Type, fullName string) error {
switch ft.Kind() { switch ft.Kind() {
case reflect.Struct: case reflect.Struct:
fields, err := buildFieldsInfo(ft) fields, err := buildFieldsInfo(ft, fullName)
if err != nil { if err != nil {
return err return err
} }
for k, v := range fields.children { for k, v := range fields.children {
if err = addOrMergeFields(info, k, v); err != nil { if err = addOrMergeFields(info, k, v, fullName); err != nil {
return err return err
} }
} }
case reflect.Map: case reflect.Map:
elemField, err := buildFieldsInfo(mapping.Deref(ft.Elem())) elemField, err := buildFieldsInfo(mapping.Deref(ft.Elem()), fullName)
if err != nil { if err != nil {
return err return err
} }
if _, ok := info.children[lowerCaseName]; ok { if _, ok := info.children[lowerCaseName]; ok {
return newDupKeyError(lowerCaseName) return newConflictKeyError(fullName)
} }
info.children[lowerCaseName] = &fieldInfo{ info.children[lowerCaseName] = &fieldInfo{
@@ -169,7 +172,7 @@ func buildAnonymousFieldInfo(info *fieldInfo, lowerCaseName string, ft reflect.T
} }
default: default:
if _, ok := info.children[lowerCaseName]; ok { if _, ok := info.children[lowerCaseName]; ok {
return newDupKeyError(lowerCaseName) return newConflictKeyError(fullName)
} }
info.children[lowerCaseName] = &fieldInfo{ info.children[lowerCaseName] = &fieldInfo{
@@ -180,14 +183,14 @@ func buildAnonymousFieldInfo(info *fieldInfo, lowerCaseName string, ft reflect.T
return nil return nil
} }
func buildFieldsInfo(tp reflect.Type) (*fieldInfo, error) { func buildFieldsInfo(tp reflect.Type, fullName string) (*fieldInfo, error) {
tp = mapping.Deref(tp) tp = mapping.Deref(tp)
switch tp.Kind() { switch tp.Kind() {
case reflect.Struct: case reflect.Struct:
return buildStructFieldsInfo(tp) return buildStructFieldsInfo(tp, fullName)
case reflect.Array, reflect.Slice: case reflect.Array, reflect.Slice:
return buildFieldsInfo(mapping.Deref(tp.Elem())) return buildFieldsInfo(mapping.Deref(tp.Elem()), fullName)
case reflect.Chan, reflect.Func: case reflect.Chan, reflect.Func:
return nil, fmt.Errorf("unsupported type: %s", tp.Kind()) return nil, fmt.Errorf("unsupported type: %s", tp.Kind())
default: default:
@@ -197,23 +200,23 @@ func buildFieldsInfo(tp reflect.Type) (*fieldInfo, error) {
} }
} }
func buildNamedFieldInfo(info *fieldInfo, lowerCaseName string, ft reflect.Type) error { func buildNamedFieldInfo(info *fieldInfo, lowerCaseName string, ft reflect.Type, fullName string) error {
var finfo *fieldInfo var finfo *fieldInfo
var err error var err error
switch ft.Kind() { switch ft.Kind() {
case reflect.Struct: case reflect.Struct:
finfo, err = buildFieldsInfo(ft) finfo, err = buildFieldsInfo(ft, fullName)
if err != nil { if err != nil {
return err return err
} }
case reflect.Array, reflect.Slice: case reflect.Array, reflect.Slice:
finfo, err = buildFieldsInfo(ft.Elem()) finfo, err = buildFieldsInfo(ft.Elem(), fullName)
if err != nil { if err != nil {
return err return err
} }
case reflect.Map: case reflect.Map:
elemInfo, err := buildFieldsInfo(mapping.Deref(ft.Elem())) elemInfo, err := buildFieldsInfo(mapping.Deref(ft.Elem()), fullName)
if err != nil { if err != nil {
return err return err
} }
@@ -223,31 +226,37 @@ func buildNamedFieldInfo(info *fieldInfo, lowerCaseName string, ft reflect.Type)
mapField: elemInfo, mapField: elemInfo,
} }
default: default:
finfo, err = buildFieldsInfo(ft) finfo, err = buildFieldsInfo(ft, fullName)
if err != nil { if err != nil {
return err return err
} }
} }
return addOrMergeFields(info, lowerCaseName, finfo) return addOrMergeFields(info, lowerCaseName, finfo, fullName)
} }
func buildStructFieldsInfo(tp reflect.Type) (*fieldInfo, error) { func buildStructFieldsInfo(tp reflect.Type, fullName string) (*fieldInfo, error) {
info := &fieldInfo{ info := &fieldInfo{
children: make(map[string]*fieldInfo), children: make(map[string]*fieldInfo),
} }
for i := 0; i < tp.NumField(); i++ { for i := 0; i < tp.NumField(); i++ {
field := tp.Field(i) field := tp.Field(i)
name := field.Name if !field.IsExported() {
continue
}
name := getTagName(field)
lowerCaseName := toLowerCase(name) lowerCaseName := toLowerCase(name)
ft := mapping.Deref(field.Type) ft := mapping.Deref(field.Type)
// flatten anonymous fields // flatten anonymous fields
if field.Anonymous { if field.Anonymous {
if err := buildAnonymousFieldInfo(info, lowerCaseName, ft); err != nil { if err := buildAnonymousFieldInfo(info, lowerCaseName, ft,
getFullName(fullName, lowerCaseName)); err != nil {
return nil, err return nil, err
} }
} else if err := buildNamedFieldInfo(info, lowerCaseName, ft); err != nil { } else if err := buildNamedFieldInfo(info, lowerCaseName, ft,
getFullName(fullName, lowerCaseName)); err != nil {
return nil, err return nil, err
} }
} }
@@ -255,15 +264,32 @@ func buildStructFieldsInfo(tp reflect.Type) (*fieldInfo, error) {
return info, nil return info, nil
} }
func mergeFields(prev *fieldInfo, key string, children map[string]*fieldInfo) error { // getTagName get the tag name of the given field, if no tag name, use file.Name.
// field.Name is returned on tags like `json:""` and `json:",optional"`.
func getTagName(field reflect.StructField) string {
if tag, ok := field.Tag.Lookup(jsonTagKey); ok {
if pos := strings.IndexByte(tag, jsonTagSep); pos >= 0 {
tag = tag[:pos]
}
tag = strings.TrimSpace(tag)
if len(tag) > 0 {
return tag
}
}
return field.Name
}
func mergeFields(prev *fieldInfo, key string, children map[string]*fieldInfo, fullName string) error {
if len(prev.children) == 0 || len(children) == 0 { if len(prev.children) == 0 || len(children) == 0 {
return newDupKeyError(key) return newConflictKeyError(fullName)
} }
// merge fields // merge fields
for k, v := range children { for k, v := range children {
if _, ok := prev.children[k]; ok { if _, ok := prev.children[k]; ok {
return newDupKeyError(k) return newConflictKeyError(fullName)
} }
prev.children[k] = v prev.children[k] = v
@@ -314,14 +340,22 @@ func toLowerCaseKeyMap(m map[string]any, info *fieldInfo) map[string]any {
return res return res
} }
type dupKeyError struct { type conflictKeyError struct {
key string key string
} }
func newDupKeyError(key string) dupKeyError { func newConflictKeyError(key string) conflictKeyError {
return dupKeyError{key: key} return conflictKeyError{key: key}
} }
func (e dupKeyError) Error() string { func (e conflictKeyError) Error() string {
return fmt.Sprintf("duplicated key %s", e.key) return fmt.Sprintf("conflict key %s, pay attention to anonymous fields", e.key)
}
func getFullName(parent, child string) string {
if len(parent) == 0 {
return child
}
return strings.Join([]string{parent, child}, ".")
} }

View File

@@ -2,6 +2,7 @@ package conf
import ( import (
"os" "os"
"reflect"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@@ -9,7 +10,7 @@ import (
"github.com/zeromicro/go-zero/core/hash" "github.com/zeromicro/go-zero/core/hash"
) )
var dupErr dupKeyError var dupErr conflictKeyError
func TestLoadConfig_notExists(t *testing.T) { func TestLoadConfig_notExists(t *testing.T) {
assert.NotNil(t, Load("not_a_file", nil)) assert.NotNil(t, Load("not_a_file", nil))
@@ -123,6 +124,24 @@ d = "abcd"
} }
} }
func TestConfigWithLower(t *testing.T) {
text := `a = "foo"
b = 1
`
tmpfile, err := createTempFile(".toml", text)
assert.Nil(t, err)
defer os.Remove(tmpfile)
var val struct {
A string `json:"a"`
b int
}
if assert.NoError(t, Load(tmpfile, &val)) {
assert.Equal(t, "foo", val.A)
assert.Equal(t, 0, val.b)
}
}
func TestConfigJsonCanonical(t *testing.T) { func TestConfigJsonCanonical(t *testing.T) {
text := []byte(`{"a": "foo", "B": "bar"}`) text := []byte(`{"a": "foo", "B": "bar"}`)
@@ -672,7 +691,7 @@ func Test_FieldOverwrite(t *testing.T) {
input := []byte(`{"Name": "hello"}`) input := []byte(`{"Name": "hello"}`)
err := LoadFromJsonBytes(input, val) err := LoadFromJsonBytes(input, val)
assert.ErrorAs(t, err, &dupErr) assert.ErrorAs(t, err, &dupErr)
assert.Equal(t, newDupKeyError("name").Error(), err.Error()) assert.Equal(t, newConflictKeyError("name").Error(), err.Error())
} }
validate(&St1{}) validate(&St1{})
@@ -715,7 +734,7 @@ func Test_FieldOverwrite(t *testing.T) {
input := []byte(`{"Name": "hello"}`) input := []byte(`{"Name": "hello"}`)
err := LoadFromJsonBytes(input, val) err := LoadFromJsonBytes(input, val)
assert.ErrorAs(t, err, &dupErr) assert.ErrorAs(t, err, &dupErr)
assert.Equal(t, newDupKeyError("name").Error(), err.Error()) assert.Error(t, err)
} }
validate(&St0{}) validate(&St0{})
@@ -1022,22 +1041,22 @@ func TestLoadNamedFieldOverwritten(t *testing.T) {
}) })
} }
func createTempFile(ext, text string) (string, error) { func TestLoadLowerMemberShouldNotConflict(t *testing.T) {
tmpfile, err := os.CreateTemp(os.TempDir(), hash.Md5Hex([]byte(text))+"*"+ext) type (
if err != nil { Redis struct {
return "", err db uint
} }
if err := os.WriteFile(tmpfile.Name(), []byte(text), os.ModeTemporary); err != nil { Config struct {
return "", err db uint
} Redis
}
)
filename := tmpfile.Name() var c Config
if err = tmpfile.Close(); err != nil { assert.NoError(t, LoadFromJsonBytes([]byte(`{}`), &c))
return "", err assert.Zero(t, c.db)
} assert.Zero(t, c.Redis.db)
return filename, nil
} }
func TestFillDefaultUnmarshal(t *testing.T) { func TestFillDefaultUnmarshal(t *testing.T) {
@@ -1079,7 +1098,7 @@ func TestFillDefaultUnmarshal(t *testing.T) {
assert.Equal(t, st.C, "c") assert.Equal(t, st.C, "c")
}) })
t.Run("has vaue", func(t *testing.T) { t.Run("has value", func(t *testing.T) {
type St struct { type St struct {
A string `json:",default=a"` A string `json:",default=a"`
B string B string
@@ -1091,3 +1110,201 @@ func TestFillDefaultUnmarshal(t *testing.T) {
assert.Error(t, err) assert.Error(t, err)
}) })
} }
func TestConfigWithJsonTag(t *testing.T) {
t.Run("map with value", func(t *testing.T) {
var input = []byte(`[Value]
[Value.first]
Email = "foo"
[Value.second]
Email = "bar"`)
type Value struct {
Email string
}
type Config struct {
ValueMap map[string]Value `json:"Value"`
}
var c Config
if assert.NoError(t, LoadFromTomlBytes(input, &c)) {
assert.Len(t, c.ValueMap, 2)
}
})
t.Run("map with ptr value", func(t *testing.T) {
var input = []byte(`[Value]
[Value.first]
Email = "foo"
[Value.second]
Email = "bar"`)
type Value struct {
Email string
}
type Config struct {
ValueMap map[string]*Value `json:"Value"`
}
var c Config
if assert.NoError(t, LoadFromTomlBytes(input, &c)) {
assert.Len(t, c.ValueMap, 2)
}
})
t.Run("map with optional", func(t *testing.T) {
var input = []byte(`[Value]
[Value.first]
Email = "foo"
[Value.second]
Email = "bar"`)
type Value struct {
Email string
}
type Config struct {
Value map[string]Value `json:",optional"`
}
var c Config
if assert.NoError(t, LoadFromTomlBytes(input, &c)) {
assert.Len(t, c.Value, 2)
}
})
t.Run("map with empty tag", func(t *testing.T) {
var input = []byte(`[Value]
[Value.first]
Email = "foo"
[Value.second]
Email = "bar"`)
type Value struct {
Email string
}
type Config struct {
Value map[string]Value `json:" "`
}
var c Config
if assert.NoError(t, LoadFromTomlBytes(input, &c)) {
assert.Len(t, c.Value, 2)
}
})
}
func Test_getFullName(t *testing.T) {
assert.Equal(t, "a.b", getFullName("a", "b"))
assert.Equal(t, "a", getFullName("", "a"))
}
func Test_buildFieldsInfo(t *testing.T) {
type ParentSt struct {
Name string
M map[string]int
}
tests := []struct {
name string
t reflect.Type
ok bool
containsKey string
}{
{
name: "normal",
t: reflect.TypeOf(struct{ A string }{}),
ok: true,
},
{
name: "struct anonymous",
t: reflect.TypeOf(struct {
ParentSt
Name string
}{}),
ok: false,
containsKey: newConflictKeyError("name").Error(),
},
{
name: "struct ptr anonymous",
t: reflect.TypeOf(struct {
*ParentSt
Name string
}{}),
ok: false,
containsKey: newConflictKeyError("name").Error(),
},
{
name: "more struct anonymous",
t: reflect.TypeOf(struct {
Value struct {
ParentSt
Name string
}
}{}),
ok: false,
containsKey: newConflictKeyError("value.name").Error(),
},
{
name: "map anonymous",
t: reflect.TypeOf(struct {
ParentSt
M string
}{}),
ok: false,
containsKey: newConflictKeyError("m").Error(),
},
{
name: "map more anonymous",
t: reflect.TypeOf(struct {
Value struct {
ParentSt
M string
}
}{}),
ok: false,
containsKey: newConflictKeyError("value.m").Error(),
},
{
name: "struct slice anonymous",
t: reflect.TypeOf([]struct {
ParentSt
Name string
}{}),
ok: false,
containsKey: newConflictKeyError("name").Error(),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_, err := buildFieldsInfo(tt.t, "")
if tt.ok {
assert.NoError(t, err)
} else {
assert.Error(t, err)
assert.Equal(t, err.Error(), tt.containsKey)
}
})
}
}
func createTempFile(ext, text string) (string, error) {
tmpFile, err := os.CreateTemp(os.TempDir(), hash.Md5Hex([]byte(text))+"*"+ext)
if err != nil {
return "", err
}
if err := os.WriteFile(tmpFile.Name(), []byte(text), os.ModeTemporary); err != nil {
return "", err
}
filename := tmpFile.Name()
if err = tmpFile.Close(); err != nil {
return "", err
}
return filename, nil
}

View File

@@ -13,6 +13,7 @@ var (
type EtcdConf struct { type EtcdConf struct {
Hosts []string Hosts []string
Key string Key string
ID int64 `json:",optional"`
User string `json:",optional"` User string `json:",optional"`
Pass string `json:",optional"` Pass string `json:",optional"`
CertFile string `json:",optional"` CertFile string `json:",optional"`
@@ -26,6 +27,11 @@ func (c EtcdConf) HasAccount() bool {
return len(c.User) > 0 && len(c.Pass) > 0 return len(c.User) > 0 && len(c.Pass) > 0
} }
// HasID returns if ID provided.
func (c EtcdConf) HasID() bool {
return c.ID > 0
}
// HasTLS returns if TLS CertFile/CertKeyFile/CACertFile are provided. // HasTLS returns if TLS CertFile/CertKeyFile/CACertFile are provided.
func (c EtcdConf) HasTLS() bool { func (c EtcdConf) HasTLS() bool {
return len(c.CertFile) > 0 && len(c.CertKeyFile) > 0 && len(c.CACertFile) > 0 return len(c.CertFile) > 0 && len(c.CertKeyFile) > 0 && len(c.CACertFile) > 0

View File

@@ -80,3 +80,90 @@ func TestEtcdConf_HasAccount(t *testing.T) {
assert.Equal(t, test.hasAccount, test.EtcdConf.HasAccount()) assert.Equal(t, test.hasAccount, test.EtcdConf.HasAccount())
} }
} }
func TestEtcdConf_HasID(t *testing.T) {
tests := []struct {
EtcdConf
hasServerID bool
}{
{
EtcdConf: EtcdConf{
Hosts: []string{"any"},
ID: -1,
},
hasServerID: false,
},
{
EtcdConf: EtcdConf{
Hosts: []string{"any"},
ID: 0,
},
hasServerID: false,
},
{
EtcdConf: EtcdConf{
Hosts: []string{"any"},
ID: 10000,
},
hasServerID: true,
},
}
for _, test := range tests {
assert.Equal(t, test.hasServerID, test.EtcdConf.HasID())
}
}
func TestEtcdConf_HasTLS(t *testing.T) {
tests := []struct {
name string
conf EtcdConf
want bool
}{
{
name: "empty config",
conf: EtcdConf{},
want: false,
},
{
name: "missing CertFile",
conf: EtcdConf{
CertKeyFile: "key",
CACertFile: "ca",
},
want: false,
},
{
name: "missing CertKeyFile",
conf: EtcdConf{
CertFile: "cert",
CACertFile: "ca",
},
want: false,
},
{
name: "missing CACertFile",
conf: EtcdConf{
CertFile: "cert",
CertKeyFile: "key",
},
want: false,
},
{
name: "valid config",
conf: EtcdConf{
CertFile: "cert",
CertKeyFile: "key",
CACertFile: "ca",
},
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := tt.conf.HasTLS()
assert.Equal(t, tt.want, got)
})
}
}

View File

@@ -1,12 +1,85 @@
package internal package internal
import ( import (
"os"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/stringx" "github.com/zeromicro/go-zero/core/stringx"
) )
const (
certContent = `-----BEGIN CERTIFICATE-----
MIIDazCCAlOgAwIBAgIUEg9GVO2oaPn+YSmiqmFIuAo10WIwDQYJKoZIhvcNAQEM
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAgFw0yMzAzMTExMzIxMjNaGA8yMTIz
MDIxNTEzMjEyM1owRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx
ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBALplXlWsIf0O/IgnIplmiZHKGnxyfyufyE2FBRNk
OofRqbKuPH8GNqbkvZm7N29fwTDAQ+mViAggCkDht4hOzoWJMA7KYJt8JnTSWL48
M1lcrpc9DL2gszC/JF/FGvyANbBtLklkZPFBGdHUX14pjrT937wqPtm+SqUHSvRT
B7bmwmm2drRcmhpVm98LSlV7uQ2EgnJgsLjBPITKUejLmVLHfgX0RwQ2xIpX9pS4
FCe1BTacwl2gGp7Mje7y4Mfv3o0ArJW6Tuwbjx59ZXwb1KIP71b7bT04AVS8ZeYO
UMLKKuB5UR9x9Rn6cLXOTWBpcMVyzDgrAFLZjnE9LPUolZMCAwEAAaNRME8wHwYD
VR0jBBgwFoAUeW8w8pmhncbRgTsl48k4/7wnfx8wCQYDVR0TBAIwADALBgNVHQ8E
BAMCBPAwFAYDVR0RBA0wC4IJbG9jYWxob3N0MA0GCSqGSIb3DQEBDAUAA4IBAQAI
y9xaoS88CLPBsX6mxfcTAFVfGNTRW9VN9Ng1cCnUR+YGoXGM/l+qP4f7p8ocdGwK
iYZErVTzXYIn+D27//wpY3klJk3gAnEUBT3QRkStBw7XnpbeZ2oPBK+cmDnCnZPS
BIF1wxPX7vIgaxs5Zsdqwk3qvZ4Djr2wP7LabNWTLSBKgQoUY45Liw6pffLwcGF9
UKlu54bvGze2SufISCR3ib+I+FLvqpvJhXToZWYb/pfI/HccuCL1oot1x8vx6DQy
U+TYxlZsKS5mdNxAX3dqEkEMsgEi+g/tzDPXJImfeCGGBhIOXLm8SRypiuGdEbc9
xkWYxRPegajuEZGvCqVs
-----END CERTIFICATE-----`
keyContent = `-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAumVeVawh/Q78iCcimWaJkcoafHJ/K5/ITYUFE2Q6h9Gpsq48
fwY2puS9mbs3b1/BMMBD6ZWICCAKQOG3iE7OhYkwDspgm3wmdNJYvjwzWVyulz0M
vaCzML8kX8Ua/IA1sG0uSWRk8UEZ0dRfXimOtP3fvCo+2b5KpQdK9FMHtubCabZ2
tFyaGlWb3wtKVXu5DYSCcmCwuME8hMpR6MuZUsd+BfRHBDbEilf2lLgUJ7UFNpzC
XaAansyN7vLgx+/ejQCslbpO7BuPHn1lfBvUog/vVvttPTgBVLxl5g5Qwsoq4HlR
H3H1Gfpwtc5NYGlwxXLMOCsAUtmOcT0s9SiVkwIDAQABAoIBAD5meTJNMgO55Kjg
ESExxpRcCIno+tHr5+6rvYtEXqPheOIsmmwb9Gfi4+Z3WpOaht5/Pz0Ppj6yGzyl
U//6AgGKb+BDuBvVcDpjwPnOxZIBCSHwejdxeQu0scSuA97MPS0XIAvJ5FEv7ijk
5Bht6SyGYURpECltHygoTNuGgGqmO+McCJRLE9L09lTBI6UQ/JQwWJqSr7wx6iPU
M1Ze/srIV+7cyEPu6i0DGjS1gSQKkX68Lqn1w6oE290O+OZvleO0gZ02fLDWCZke
aeD9+EU/Pw+rqm3H6o0szOFIpzhRp41FUdW9sybB3Yp3u7c/574E+04Z/e30LMKs
TCtE1QECgYEA3K7KIpw0NH2HXL5C3RHcLmr204xeBfS70riBQQuVUgYdmxak2ima
80RInskY8hRhSGTg0l+VYIH8cmjcUyqMSOELS5XfRH99r4QPiK8AguXg80T4VumY
W3Pf+zEC2ssgP/gYthV0g0Xj5m2QxktOF9tRw5nkg739ZR4dI9lm/iECgYEA2Dnf
uwEDGqHiQRF6/fh5BG/nGVMvrefkqx6WvTJQ3k/M/9WhxB+lr/8yH46TuS8N2b29
FoTf3Mr9T7pr/PWkOPzoY3P56nYbKU8xSwCim9xMzhBMzj8/N9ukJvXy27/VOz56
eQaKqnvdXNGtPJrIMDGHps2KKWlKLyAlapzjVTMCgYAA/W++tACv85g13EykfT4F
n0k4LbsGP9DP4zABQLIMyiY72eAncmRVjwrcW36XJ2xATOONTgx3gF3HjZzfaqNy
eD/6uNNllUTVEryXGmHgNHPL45VRnn6memCY2eFvZdXhM5W4y2PYaunY0MkDercA
+GTngbs6tBF88KOk04bYwQKBgFl68cRgsdkmnwwQYNaTKfmVGYzYaQXNzkqmWPko
xmCJo6tHzC7ubdG8iRCYHzfmahPuuj6EdGPZuSRyYFgJi5Ftz/nAN+84OxtIQ3zn
YWOgskQgaLh9YfsKsQ7Sf1NDOsnOnD5TX7UXl07fEpLe9vNCvAFiU8e5Y9LGudU5
4bYTAoGBAMdX3a3bXp4cZvXNBJ/QLVyxC6fP1Q4haCR1Od3m+T00Jth2IX2dk/fl
p6xiJT1av5JtYabv1dFKaXOS5s1kLGGuCCSKpkvFZm826aQ2AFm0XGqEQDLeei5b
A52Kpy/YJ+RkG4BTFtAooFq6DmA0cnoP6oPvG2h6XtDJwDTPInJb
-----END RSA PRIVATE KEY-----`
caContent = `-----BEGIN CERTIFICATE-----
MIIDbTCCAlWgAwIBAgIUBJvFoCowKich7MMfseJ+DYzzirowDQYJKoZIhvcNAQEM
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAgFw0yMzAzMTExMzIxMDNaGA8yMTIz
MDIxNTEzMjEwM1owRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx
ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBAO4to2YMYj0bxgr2FCiweSTSFuPx33zSw2x/s9Wf
OR41bm2DFsyYT5f3sOIKlXZEdLmOKty2e3ho3yC0EyNpVHdykkkHT3aDI17quZax
kYi/URqqtl1Z08A22txolc04hAZisg2BypGi3vql81UW1t3zyloGnJoIAeXR9uca
ljP6Bk3bwsxoVBLi1JtHrO0hHLQaeHmKhAyrys06X0LRdn7Px48yRZlt6FaLSa8X
YiRM0G44bVy/h6BkoQjMYGwVmCVk6zjJ9U7ZPFqdnDMNxAfR+hjDnYodqdLDMTTR
1NPVrnEnNwFx0AMLvgt/ba/45vZCEAmSZnFXFAJJcM7ai9ECAwEAAaNTMFEwHQYD
VR0OBBYEFHlvMPKZoZ3G0YE7JePJOP+8J38fMB8GA1UdIwQYMBaAFHlvMPKZoZ3G
0YE7JePJOP+8J38fMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggEB
AMX8dNulADOo9uQgBMyFb9TVra7iY0zZjzv4GY5XY7scd52n6CnfAPvYBBDnTr/O
BgNp5jaujb4+9u/2qhV3f9n+/3WOb2CmPehBgVSzlXqHeQ9lshmgwZPeem2T+8Tm
Nnc/xQnsUfCFszUDxpkr55+aLVM22j02RWqcZ4q7TAaVYL+kdFVMc8FoqG/0ro6A
BjE/Qn0Nn7ciX1VUjDt8l+k7ummPJTmzdi6i6E4AwO9dzrGNgGJ4aWL8cC6xYcIX
goVIRTFeONXSDno/oPjWHpIPt7L15heMpKBHNuzPkKx2YVqPHE5QZxWfS+Lzgx+Q
E2oTTM0rYKOZ8p6000mhvKI=
-----END CERTIFICATE-----`
)
func TestAccount(t *testing.T) { func TestAccount(t *testing.T) {
endpoints := []string{ endpoints := []string{
"192.168.0.2:2379", "192.168.0.2:2379",
@@ -32,3 +105,34 @@ func TestAccount(t *testing.T) {
assert.Equal(t, username, account.User) assert.Equal(t, username, account.User)
assert.Equal(t, anotherPassword, account.Pass) assert.Equal(t, anotherPassword, account.Pass)
} }
func TestTLSMethods(t *testing.T) {
certFile := createTempFile(t, []byte(certContent))
defer os.Remove(certFile)
keyFile := createTempFile(t, []byte(keyContent))
defer os.Remove(keyFile)
caFile := createTempFile(t, []byte(caContent))
defer os.Remove(caFile)
assert.NoError(t, AddTLS([]string{"foo"}, certFile, keyFile, caFile, false))
cfg, ok := GetTLS([]string{"foo"})
assert.True(t, ok)
assert.NotNil(t, cfg)
assert.Error(t, AddTLS([]string{"bar"}, "bad-file", keyFile, caFile, false))
assert.Error(t, AddTLS([]string{"bar"}, certFile, keyFile, "bad-file", false))
}
func createTempFile(t *testing.T, body []byte) string {
tmpFile, err := os.CreateTemp(os.TempDir(), "go-unit-*.tmp")
if err != nil {
t.Fatal(err)
}
tmpFile.Close()
if err = os.WriteFile(tmpFile.Name(), body, os.ModePerm); err != nil {
t.Fatal(err)
}
return tmpFile.Name()
}

View File

@@ -2,8 +2,10 @@ package internal
import ( import (
"context" "context"
"os"
"sync" "sync"
"testing" "testing"
"time"
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@@ -14,6 +16,7 @@ import (
"go.etcd.io/etcd/api/v3/etcdserverpb" "go.etcd.io/etcd/api/v3/etcdserverpb"
"go.etcd.io/etcd/api/v3/mvccpb" "go.etcd.io/etcd/api/v3/mvccpb"
clientv3 "go.etcd.io/etcd/client/v3" clientv3 "go.etcd.io/etcd/client/v3"
"go.etcd.io/etcd/client/v3/mock/mockserver"
) )
var mockLock sync.Mutex var mockLock sync.Mutex
@@ -242,3 +245,58 @@ func TestValueOnlyContext(t *testing.T) {
ctx.Done() ctx.Done()
assert.Nil(t, ctx.Err()) assert.Nil(t, ctx.Err())
} }
func TestDialClient(t *testing.T) {
svr, err := mockserver.StartMockServers(1)
assert.NoError(t, err)
svr.StartAt(0)
certFile := createTempFile(t, []byte(certContent))
defer os.Remove(certFile)
keyFile := createTempFile(t, []byte(keyContent))
defer os.Remove(keyFile)
caFile := createTempFile(t, []byte(caContent))
defer os.Remove(caFile)
endpoints := []string{svr.Servers[0].Address}
AddAccount(endpoints, "foo", "bar")
assert.NoError(t, AddTLS(endpoints, certFile, keyFile, caFile, false))
old := DialTimeout
DialTimeout = time.Millisecond
defer func() {
DialTimeout = old
}()
_, err = DialClient(endpoints)
assert.Error(t, err)
}
func TestRegistry_Monitor(t *testing.T) {
svr, err := mockserver.StartMockServers(1)
assert.NoError(t, err)
svr.StartAt(0)
endpoints := []string{svr.Servers[0].Address}
GetRegistry().lock.Lock()
GetRegistry().clusters = map[string]*cluster{
getClusterKey(endpoints): {
listeners: map[string][]UpdateListener{},
values: map[string]map[string]string{
"foo": {
"bar": "baz",
},
},
},
}
GetRegistry().lock.Unlock()
assert.Error(t, GetRegistry().Monitor(endpoints, "foo", new(mockListener)))
}
type mockListener struct {
}
func (m *mockListener) OnAdd(_ KV) {
}
func (m *mockListener) OnDelete(_ KV) {
}

View File

@@ -1,7 +1,10 @@
package discov package discov
import ( import (
"context"
"errors" "errors"
"net"
"os"
"sync" "sync"
"testing" "testing"
"time" "time"
@@ -13,6 +16,83 @@ import (
"github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/stringx" "github.com/zeromicro/go-zero/core/stringx"
clientv3 "go.etcd.io/etcd/client/v3" clientv3 "go.etcd.io/etcd/client/v3"
"golang.org/x/net/http2"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/resolver"
"google.golang.org/grpc/resolver/manual"
)
const (
certContent = `-----BEGIN CERTIFICATE-----
MIIDazCCAlOgAwIBAgIUEg9GVO2oaPn+YSmiqmFIuAo10WIwDQYJKoZIhvcNAQEM
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAgFw0yMzAzMTExMzIxMjNaGA8yMTIz
MDIxNTEzMjEyM1owRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx
ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBALplXlWsIf0O/IgnIplmiZHKGnxyfyufyE2FBRNk
OofRqbKuPH8GNqbkvZm7N29fwTDAQ+mViAggCkDht4hOzoWJMA7KYJt8JnTSWL48
M1lcrpc9DL2gszC/JF/FGvyANbBtLklkZPFBGdHUX14pjrT937wqPtm+SqUHSvRT
B7bmwmm2drRcmhpVm98LSlV7uQ2EgnJgsLjBPITKUejLmVLHfgX0RwQ2xIpX9pS4
FCe1BTacwl2gGp7Mje7y4Mfv3o0ArJW6Tuwbjx59ZXwb1KIP71b7bT04AVS8ZeYO
UMLKKuB5UR9x9Rn6cLXOTWBpcMVyzDgrAFLZjnE9LPUolZMCAwEAAaNRME8wHwYD
VR0jBBgwFoAUeW8w8pmhncbRgTsl48k4/7wnfx8wCQYDVR0TBAIwADALBgNVHQ8E
BAMCBPAwFAYDVR0RBA0wC4IJbG9jYWxob3N0MA0GCSqGSIb3DQEBDAUAA4IBAQAI
y9xaoS88CLPBsX6mxfcTAFVfGNTRW9VN9Ng1cCnUR+YGoXGM/l+qP4f7p8ocdGwK
iYZErVTzXYIn+D27//wpY3klJk3gAnEUBT3QRkStBw7XnpbeZ2oPBK+cmDnCnZPS
BIF1wxPX7vIgaxs5Zsdqwk3qvZ4Djr2wP7LabNWTLSBKgQoUY45Liw6pffLwcGF9
UKlu54bvGze2SufISCR3ib+I+FLvqpvJhXToZWYb/pfI/HccuCL1oot1x8vx6DQy
U+TYxlZsKS5mdNxAX3dqEkEMsgEi+g/tzDPXJImfeCGGBhIOXLm8SRypiuGdEbc9
xkWYxRPegajuEZGvCqVs
-----END CERTIFICATE-----`
keyContent = `-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAumVeVawh/Q78iCcimWaJkcoafHJ/K5/ITYUFE2Q6h9Gpsq48
fwY2puS9mbs3b1/BMMBD6ZWICCAKQOG3iE7OhYkwDspgm3wmdNJYvjwzWVyulz0M
vaCzML8kX8Ua/IA1sG0uSWRk8UEZ0dRfXimOtP3fvCo+2b5KpQdK9FMHtubCabZ2
tFyaGlWb3wtKVXu5DYSCcmCwuME8hMpR6MuZUsd+BfRHBDbEilf2lLgUJ7UFNpzC
XaAansyN7vLgx+/ejQCslbpO7BuPHn1lfBvUog/vVvttPTgBVLxl5g5Qwsoq4HlR
H3H1Gfpwtc5NYGlwxXLMOCsAUtmOcT0s9SiVkwIDAQABAoIBAD5meTJNMgO55Kjg
ESExxpRcCIno+tHr5+6rvYtEXqPheOIsmmwb9Gfi4+Z3WpOaht5/Pz0Ppj6yGzyl
U//6AgGKb+BDuBvVcDpjwPnOxZIBCSHwejdxeQu0scSuA97MPS0XIAvJ5FEv7ijk
5Bht6SyGYURpECltHygoTNuGgGqmO+McCJRLE9L09lTBI6UQ/JQwWJqSr7wx6iPU
M1Ze/srIV+7cyEPu6i0DGjS1gSQKkX68Lqn1w6oE290O+OZvleO0gZ02fLDWCZke
aeD9+EU/Pw+rqm3H6o0szOFIpzhRp41FUdW9sybB3Yp3u7c/574E+04Z/e30LMKs
TCtE1QECgYEA3K7KIpw0NH2HXL5C3RHcLmr204xeBfS70riBQQuVUgYdmxak2ima
80RInskY8hRhSGTg0l+VYIH8cmjcUyqMSOELS5XfRH99r4QPiK8AguXg80T4VumY
W3Pf+zEC2ssgP/gYthV0g0Xj5m2QxktOF9tRw5nkg739ZR4dI9lm/iECgYEA2Dnf
uwEDGqHiQRF6/fh5BG/nGVMvrefkqx6WvTJQ3k/M/9WhxB+lr/8yH46TuS8N2b29
FoTf3Mr9T7pr/PWkOPzoY3P56nYbKU8xSwCim9xMzhBMzj8/N9ukJvXy27/VOz56
eQaKqnvdXNGtPJrIMDGHps2KKWlKLyAlapzjVTMCgYAA/W++tACv85g13EykfT4F
n0k4LbsGP9DP4zABQLIMyiY72eAncmRVjwrcW36XJ2xATOONTgx3gF3HjZzfaqNy
eD/6uNNllUTVEryXGmHgNHPL45VRnn6memCY2eFvZdXhM5W4y2PYaunY0MkDercA
+GTngbs6tBF88KOk04bYwQKBgFl68cRgsdkmnwwQYNaTKfmVGYzYaQXNzkqmWPko
xmCJo6tHzC7ubdG8iRCYHzfmahPuuj6EdGPZuSRyYFgJi5Ftz/nAN+84OxtIQ3zn
YWOgskQgaLh9YfsKsQ7Sf1NDOsnOnD5TX7UXl07fEpLe9vNCvAFiU8e5Y9LGudU5
4bYTAoGBAMdX3a3bXp4cZvXNBJ/QLVyxC6fP1Q4haCR1Od3m+T00Jth2IX2dk/fl
p6xiJT1av5JtYabv1dFKaXOS5s1kLGGuCCSKpkvFZm826aQ2AFm0XGqEQDLeei5b
A52Kpy/YJ+RkG4BTFtAooFq6DmA0cnoP6oPvG2h6XtDJwDTPInJb
-----END RSA PRIVATE KEY-----`
caContent = `-----BEGIN CERTIFICATE-----
MIIDbTCCAlWgAwIBAgIUBJvFoCowKich7MMfseJ+DYzzirowDQYJKoZIhvcNAQEM
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAgFw0yMzAzMTExMzIxMDNaGA8yMTIz
MDIxNTEzMjEwM1owRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx
ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBAO4to2YMYj0bxgr2FCiweSTSFuPx33zSw2x/s9Wf
OR41bm2DFsyYT5f3sOIKlXZEdLmOKty2e3ho3yC0EyNpVHdykkkHT3aDI17quZax
kYi/URqqtl1Z08A22txolc04hAZisg2BypGi3vql81UW1t3zyloGnJoIAeXR9uca
ljP6Bk3bwsxoVBLi1JtHrO0hHLQaeHmKhAyrys06X0LRdn7Px48yRZlt6FaLSa8X
YiRM0G44bVy/h6BkoQjMYGwVmCVk6zjJ9U7ZPFqdnDMNxAfR+hjDnYodqdLDMTTR
1NPVrnEnNwFx0AMLvgt/ba/45vZCEAmSZnFXFAJJcM7ai9ECAwEAAaNTMFEwHQYD
VR0OBBYEFHlvMPKZoZ3G0YE7JePJOP+8J38fMB8GA1UdIwQYMBaAFHlvMPKZoZ3G
0YE7JePJOP+8J38fMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggEB
AMX8dNulADOo9uQgBMyFb9TVra7iY0zZjzv4GY5XY7scd52n6CnfAPvYBBDnTr/O
BgNp5jaujb4+9u/2qhV3f9n+/3WOb2CmPehBgVSzlXqHeQ9lshmgwZPeem2T+8Tm
Nnc/xQnsUfCFszUDxpkr55+aLVM22j02RWqcZ4q7TAaVYL+kdFVMc8FoqG/0ro6A
BjE/Qn0Nn7ciX1VUjDt8l+k7ummPJTmzdi6i6E4AwO9dzrGNgGJ4aWL8cC6xYcIX
goVIRTFeONXSDno/oPjWHpIPt7L15heMpKBHNuzPkKx2YVqPHE5QZxWfS+Lzgx+Q
E2oTTM0rYKOZ8p6000mhvKI=
-----END CERTIFICATE-----`
) )
func init() { func init() {
@@ -37,7 +117,7 @@ func TestPublisher_register(t *testing.T) {
assert.Nil(t, err) assert.Nil(t, err)
} }
func TestPublisher_registerWithId(t *testing.T) { func TestPublisher_registerWithOptions(t *testing.T) {
ctrl := gomock.NewController(t) ctrl := gomock.NewController(t)
defer ctrl.Finish() defer ctrl.Finish()
const id = 2 const id = 2
@@ -49,7 +129,15 @@ func TestPublisher_registerWithId(t *testing.T) {
ID: 1, ID: 1,
}, nil) }, nil)
cli.EXPECT().Put(gomock.Any(), makeEtcdKey("thekey", id), "thevalue", gomock.Any()) cli.EXPECT().Put(gomock.Any(), makeEtcdKey("thekey", id), "thevalue", gomock.Any())
pub := NewPublisher(nil, "thekey", "thevalue", WithId(id))
certFile := createTempFile(t, []byte(certContent))
defer os.Remove(certFile)
keyFile := createTempFile(t, []byte(keyContent))
defer os.Remove(keyFile)
caFile := createTempFile(t, []byte(caContent))
defer os.Remove(caFile)
pub := NewPublisher(nil, "thekey", "thevalue", WithId(id),
WithPubEtcdTLS(certFile, keyFile, caFile, true))
_, err := pub.register(cli) _, err := pub.register(cli)
assert.Nil(t, err) assert.Nil(t, err)
} }
@@ -169,3 +257,92 @@ func TestPublisher_Resume(t *testing.T) {
}() }()
<-publisher.resumeChan <-publisher.resumeChan
} }
func TestPublisher_keepAliveAsync(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
const id clientv3.LeaseID = 1
conn := createMockConn(t)
defer conn.Close()
cli := internal.NewMockEtcdClient(ctrl)
cli.EXPECT().ActiveConnection().Return(conn).AnyTimes()
cli.EXPECT().Close()
defer cli.Close()
cli.ActiveConnection()
restore := setMockClient(cli)
defer restore()
cli.EXPECT().Ctx().AnyTimes()
cli.EXPECT().KeepAlive(gomock.Any(), id)
cli.EXPECT().Grant(gomock.Any(), timeToLive).Return(&clientv3.LeaseGrantResponse{
ID: 1,
}, nil)
cli.EXPECT().Put(gomock.Any(), makeEtcdKey("thekey", int64(id)), "thevalue", gomock.Any())
var wg sync.WaitGroup
wg.Add(1)
cli.EXPECT().Revoke(gomock.Any(), id).Do(func(_, _ any) {
wg.Done()
})
pub := NewPublisher([]string{"the-endpoint"}, "thekey", "thevalue")
pub.lease = id
assert.Nil(t, pub.KeepAlive())
pub.Stop()
wg.Wait()
}
func createMockConn(t *testing.T) *grpc.ClientConn {
lis, err := net.Listen("tcp", "localhost:0")
if err != nil {
t.Fatalf("Error while listening. Err: %v", err)
}
defer lis.Close()
lisAddr := resolver.Address{Addr: lis.Addr().String()}
lisDone := make(chan struct{})
dialDone := make(chan struct{})
// 1st listener accepts the connection and then does nothing
go func() {
defer close(lisDone)
conn, err := lis.Accept()
if err != nil {
t.Errorf("Error while accepting. Err: %v", err)
return
}
framer := http2.NewFramer(conn, conn)
if err := framer.WriteSettings(http2.Setting{}); err != nil {
t.Errorf("Error while writing settings. Err: %v", err)
return
}
<-dialDone // Close conn only after dial returns.
}()
r := manual.NewBuilderWithScheme("whatever")
r.InitialState(resolver.State{Addresses: []resolver.Address{lisAddr}})
client, err := grpc.DialContext(context.Background(), r.Scheme()+":///test.server",
grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithResolvers(r))
close(dialDone)
if err != nil {
t.Fatalf("Dial failed. Err: %v", err)
}
timeout := time.After(1 * time.Second)
select {
case <-timeout:
t.Fatal("timed out waiting for server to finish")
case <-lisDone:
}
return client
}
func createTempFile(t *testing.T, body []byte) string {
tmpFile, err := os.CreateTemp(os.TempDir(), "go-unit-*.tmp")
if err != nil {
t.Fatal(err)
}
tmpFile.Close()
if err = os.WriteFile(tmpFile.Name(), body, os.ModePerm); err != nil {
t.Fatal(err)
}
return tmpFile.Name()
}

View File

@@ -81,7 +81,7 @@ func (pe *PeriodicalExecutor) Flush() bool {
}()) }())
} }
// Sync lets caller to run fn thread-safe with pe, especially for the underlying container. // Sync lets caller run fn thread-safe with pe, especially for the underlying container.
func (pe *PeriodicalExecutor) Sync(fn func()) { func (pe *PeriodicalExecutor) Sync(fn func()) {
pe.lock.Lock() pe.lock.Lock()
defer pe.lock.Unlock() defer pe.lock.Unlock()
@@ -116,7 +116,7 @@ func (pe *PeriodicalExecutor) addAndCheck(task any) (any, bool) {
} }
func (pe *PeriodicalExecutor) backgroundFlush() { func (pe *PeriodicalExecutor) backgroundFlush() {
threading.GoSafe(func() { go func() {
// flush before quit goroutine to avoid missing tasks // flush before quit goroutine to avoid missing tasks
defer pe.Flush() defer pe.Flush()
@@ -144,7 +144,7 @@ func (pe *PeriodicalExecutor) backgroundFlush() {
} }
} }
} }
}) }()
} }
func (pe *PeriodicalExecutor) doneExecution() { func (pe *PeriodicalExecutor) doneExecution() {
@@ -162,7 +162,9 @@ func (pe *PeriodicalExecutor) executeTasks(tasks any) bool {
ok := pe.hasTasks(tasks) ok := pe.hasTasks(tasks)
if ok { if ok {
pe.container.Execute(tasks) threading.RunSafe(func() {
pe.container.Execute(tasks)
})
} }
return ok return ok

View File

@@ -108,6 +108,64 @@ func TestPeriodicalExecutor_Bulk(t *testing.T) {
lock.Unlock() lock.Unlock()
} }
func TestPeriodicalExecutor_Panic(t *testing.T) {
// avoid data race
var lock sync.Mutex
ticker := timex.NewFakeTicker()
var (
executedTasks []int
expected []int
)
executor := NewPeriodicalExecutor(time.Millisecond, newContainer(time.Millisecond, func(tasks any) {
tt := tasks.([]int)
lock.Lock()
executedTasks = append(executedTasks, tt...)
lock.Unlock()
if tt[0] == 0 {
panic("test")
}
}))
executor.newTicker = func(duration time.Duration) timex.Ticker {
return ticker
}
for i := 0; i < 30; i++ {
executor.Add(i)
expected = append(expected, i)
}
ticker.Tick()
ticker.Tick()
time.Sleep(time.Millisecond)
lock.Lock()
assert.Equal(t, expected, executedTasks)
lock.Unlock()
}
func TestPeriodicalExecutor_FlushPanic(t *testing.T) {
var (
executedTasks []int
expected []int
lock sync.Mutex
)
executor := NewPeriodicalExecutor(time.Millisecond, newContainer(time.Millisecond, func(tasks any) {
tt := tasks.([]int)
lock.Lock()
executedTasks = append(executedTasks, tt...)
lock.Unlock()
if tt[0] == 0 {
panic("flush panic")
}
}))
for i := 0; i < 8; i++ {
executor.Add(i)
expected = append(expected, i)
}
executor.Flush()
lock.Lock()
assert.Equal(t, expected, executedTasks)
lock.Unlock()
}
func TestPeriodicalExecutor_Wait(t *testing.T) { func TestPeriodicalExecutor_Wait(t *testing.T) {
var lock sync.Mutex var lock sync.Mutex
executer := NewBulkExecutor(func(tasks []any) { executer := NewBulkExecutor(func(tasks []any) {
@@ -151,13 +209,7 @@ func TestPeriodicalExecutor_Deadlock(t *testing.T) {
} }
func TestPeriodicalExecutor_hasTasks(t *testing.T) { func TestPeriodicalExecutor_hasTasks(t *testing.T) {
ticker := timex.NewFakeTicker()
defer ticker.Stop()
exec := NewPeriodicalExecutor(time.Millisecond, newContainer(time.Millisecond, nil)) exec := NewPeriodicalExecutor(time.Millisecond, newContainer(time.Millisecond, nil))
exec.newTicker = func(d time.Duration) timex.Ticker {
return ticker
}
assert.False(t, exec.hasTasks(nil)) assert.False(t, exec.hasTasks(nil))
assert.True(t, exec.hasTasks(1)) assert.True(t, exec.hasTasks(1))
} }

View File

@@ -1,5 +1,4 @@
//go:build windows //go:build windows
// +build windows
package fs package fs

View File

@@ -1,5 +1,4 @@
//go:build linux || darwin //go:build linux || darwin
// +build linux darwin
package fs package fs

View File

@@ -292,6 +292,18 @@ func (s Stream) Map(fn MapFunc, opts ...Option) Stream {
}, opts...) }, opts...)
} }
// Max returns the maximum item from the underlying source.
func (s Stream) Max(less LessFunc) any {
var max any
for item := range s.source {
if max == nil || less(max, item) {
max = item
}
}
return max
}
// Merge merges all the items into a slice and generates a new stream. // Merge merges all the items into a slice and generates a new stream.
func (s Stream) Merge() Stream { func (s Stream) Merge() Stream {
var items []any var items []any
@@ -306,6 +318,18 @@ func (s Stream) Merge() Stream {
return Range(source) return Range(source)
} }
// Min returns the minimum item from the underlying source.
func (s Stream) Min(less LessFunc) any {
var min any
for item := range s.source {
if min == nil || less(item, min) {
min = item
}
}
return min
}
// NoneMatch returns whether all elements of this stream don't match the provided predicate. // NoneMatch returns whether all elements of this stream don't match the provided predicate.
// May not evaluate the predicate on all elements if not necessary for determining the result. // May not evaluate the predicate on all elements if not necessary for determining the result.
// If the stream is empty then true is returned and the predicate is not evaluated. // If the stream is empty then true is returned and the predicate is not evaluated.

View File

@@ -503,6 +503,83 @@ func TestStream_Concat(t *testing.T) {
}) })
} }
func TestStream_Max(t *testing.T) {
runCheckedTest(t, func(t *testing.T) {
tests := []struct {
name string
elements []any
max any
}{
{
name: "no elements with nil",
},
{
name: "no elements",
elements: []any{},
max: nil,
},
{
name: "1 element",
elements: []any{1},
max: 1,
},
{
name: "multiple elements",
elements: []any{1, 2, 9, 5, 8},
max: 9,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
val := Just(test.elements...).Max(func(a, b any) bool {
return a.(int) < b.(int)
})
assetEqual(t, test.max, val)
})
}
})
}
func TestStream_Min(t *testing.T) {
runCheckedTest(t, func(t *testing.T) {
tests := []struct {
name string
elements []any
min any
}{
{
name: "no elements with nil",
min: nil,
},
{
name: "no elements",
elements: []any{},
min: nil,
},
{
name: "1 element",
elements: []any{1},
min: 1,
},
{
name: "multiple elements",
elements: []any{-1, 1, 2, 9, 5, 8},
min: -1,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
val := Just(test.elements...).Min(func(a, b any) bool {
return a.(int) < b.(int)
})
assetEqual(t, test.min, val)
})
}
})
}
func BenchmarkParallelMapReduce(b *testing.B) { func BenchmarkParallelMapReduce(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()

View File

@@ -9,21 +9,6 @@ import (
"github.com/zeromicro/go-zero/core/stores/redis" "github.com/zeromicro/go-zero/core/stores/redis"
) )
// to be compatible with aliyun redis, we cannot use `local key = KEYS[1]` to reuse the key
const periodScript = `local limit = tonumber(ARGV[1])
local window = tonumber(ARGV[2])
local current = redis.call("INCRBY", KEYS[1], 1)
if current == 1 then
redis.call("expire", KEYS[1], window)
end
if current < limit then
return 1
elseif current == limit then
return 2
else
return 0
end`
const ( const (
// Unknown means not initialized state. // Unknown means not initialized state.
Unknown = iota Unknown = iota
@@ -39,8 +24,25 @@ const (
internalHitQuota = 2 internalHitQuota = 2
) )
// ErrUnknownCode is an error that represents unknown status code. var (
var ErrUnknownCode = errors.New("unknown status code") // ErrUnknownCode is an error that represents unknown status code.
ErrUnknownCode = errors.New("unknown status code")
// to be compatible with aliyun redis, we cannot use `local key = KEYS[1]` to reuse the key
periodScript = redis.NewScript(`local limit = tonumber(ARGV[1])
local window = tonumber(ARGV[2])
local current = redis.call("INCRBY", KEYS[1], 1)
if current == 1 then
redis.call("expire", KEYS[1], window)
end
if current < limit then
return 1
elseif current == limit then
return 2
else
return 0
end`)
)
type ( type (
// PeriodOption defines the method to customize a PeriodLimit. // PeriodOption defines the method to customize a PeriodLimit.
@@ -80,7 +82,7 @@ func (h *PeriodLimit) Take(key string) (int, error) {
// TakeCtx requests a permit with context, it returns the permit state. // TakeCtx requests a permit with context, it returns the permit state.
func (h *PeriodLimit) TakeCtx(ctx context.Context, key string) (int, error) { func (h *PeriodLimit) TakeCtx(ctx context.Context, key string) (int, error) {
resp, err := h.limitStore.EvalCtx(ctx, periodScript, []string{h.keyPrefix + key}, []string{ resp, err := h.limitStore.ScriptRunCtx(ctx, periodScript, []string{h.keyPrefix + key}, []string{
strconv.Itoa(h.quota), strconv.Itoa(h.quota),
strconv.Itoa(h.calcExpireSeconds()), strconv.Itoa(h.calcExpireSeconds()),
}) })

View File

@@ -33,9 +33,7 @@ func TestPeriodLimit_RedisUnavailable(t *testing.T) {
} }
func testPeriodLimit(t *testing.T, opts ...PeriodOption) { func testPeriodLimit(t *testing.T, opts ...PeriodOption) {
store, clean, err := redistest.CreateRedis() store := redistest.CreateRedis(t)
assert.Nil(t, err)
defer clean()
const ( const (
seconds = 1 seconds = 1

View File

@@ -15,10 +15,15 @@ import (
) )
const ( const (
// to be compatible with aliyun redis, we cannot use `local key = KEYS[1]` to reuse the key tokenFormat = "{%s}.tokens"
// KEYS[1] as tokens_key timestampFormat = "{%s}.ts"
// KEYS[2] as timestamp_key pingInterval = time.Millisecond * 100
script = `local rate = tonumber(ARGV[1]) )
// to be compatible with aliyun redis, we cannot use `local key = KEYS[1]` to reuse the key
// KEYS[1] as tokens_key
// KEYS[2] as timestamp_key
var script = redis.NewScript(`local rate = tonumber(ARGV[1])
local capacity = tonumber(ARGV[2]) local capacity = tonumber(ARGV[2])
local now = tonumber(ARGV[3]) local now = tonumber(ARGV[3])
local requested = tonumber(ARGV[4]) local requested = tonumber(ARGV[4])
@@ -45,11 +50,7 @@ end
redis.call("setex", KEYS[1], ttl, new_tokens) redis.call("setex", KEYS[1], ttl, new_tokens)
redis.call("setex", KEYS[2], ttl, now) redis.call("setex", KEYS[2], ttl, now)
return allowed` return allowed`)
tokenFormat = "{%s}.tokens"
timestampFormat = "{%s}.ts"
pingInterval = time.Millisecond * 100
)
// A TokenLimiter controls how frequently events are allowed to happen with in one second. // A TokenLimiter controls how frequently events are allowed to happen with in one second.
type TokenLimiter struct { type TokenLimiter struct {
@@ -110,7 +111,7 @@ func (lim *TokenLimiter) reserveN(ctx context.Context, now time.Time, n int) boo
return lim.rescueLimiter.AllowN(now, n) return lim.rescueLimiter.AllowN(now, n)
} }
resp, err := lim.store.EvalCtx(ctx, resp, err := lim.store.ScriptRunCtx(ctx,
script, script,
[]string{ []string{
lim.tokenKey, lim.tokenKey,

View File

@@ -70,9 +70,7 @@ func TestTokenLimit_Rescue(t *testing.T) {
} }
func TestTokenLimit_Take(t *testing.T) { func TestTokenLimit_Take(t *testing.T) {
store, clean, err := redistest.CreateRedis() store := redistest.CreateRedis(t)
assert.Nil(t, err)
defer clean()
const ( const (
total = 100 total = 100
@@ -92,9 +90,7 @@ func TestTokenLimit_Take(t *testing.T) {
} }
func TestTokenLimit_TakeBurst(t *testing.T) { func TestTokenLimit_TakeBurst(t *testing.T) {
store, clean, err := redistest.CreateRedis() store := redistest.CreateRedis(t)
assert.Nil(t, err)
defer clean()
const ( const (
total = 100 total = 100

View File

@@ -23,7 +23,7 @@ type LogConf struct {
MaxContentLength uint32 `json:",optional"` MaxContentLength uint32 `json:",optional"`
// Compress represents whether to compress the log file, default is `false`. // Compress represents whether to compress the log file, default is `false`.
Compress bool `json:",optional"` Compress bool `json:",optional"`
// Stdout represents whether to log statistics, default is `true`. // Stat represents whether to log statistics, default is `true`.
Stat bool `json:",default=true"` Stat bool `json:",default=true"`
// KeepDays represents how many days the log files will be kept. Default to keep all files. // KeepDays represents how many days the log files will be kept. Default to keep all files.
// Only take effect when Mode is `file` or `volume`, both work when Rotation is `daily` or `size`. // Only take effect when Mode is `file` or `volume`, both work when Rotation is `daily` or `size`.
@@ -38,7 +38,7 @@ type LogConf struct {
// MaxSize represents how much space the writing log file takes up. 0 means no limit. The unit is `MB`. // MaxSize represents how much space the writing log file takes up. 0 means no limit. The unit is `MB`.
// Only take effect when RotationRuleType is `size` // Only take effect when RotationRuleType is `size`
MaxSize int `json:",default=0"` MaxSize int `json:",default=0"`
// RotationRuleType represents the type of log rotation rule. Default is `daily`. // Rotation represents the type of log rotation rule. Default is `daily`.
// daily: daily rotation. // daily: daily rotation.
// size: size limited rotation. // size: size limited rotation.
Rotation string `json:",default=daily,options=[daily,size]"` Rotation string `json:",default=daily,options=[daily,size]"`

View File

@@ -197,7 +197,12 @@ func Must(err error) {
msg := err.Error() msg := err.Error()
log.Print(msg) log.Print(msg)
getWriter().Severe(msg) getWriter().Severe(msg)
os.Exit(1)
if ExitOnFatal.True() {
os.Exit(1)
} else {
panic(msg)
}
} }
// MustSetup sets up logging with given config c. It exits on error. // MustSetup sets up logging with given config c. It exits on error.

View File

@@ -24,6 +24,10 @@ var (
_ Writer = (*mockWriter)(nil) _ Writer = (*mockWriter)(nil)
) )
func init() {
ExitOnFatal.Set(false)
}
type mockWriter struct { type mockWriter struct {
lock sync.Mutex lock sync.Mutex
builder strings.Builder builder strings.Builder
@@ -208,6 +212,12 @@ func TestFileLineConsoleMode(t *testing.T) {
assert.True(t, w.Contains(fmt.Sprintf("%s:%d", file, line+1))) assert.True(t, w.Contains(fmt.Sprintf("%s:%d", file, line+1)))
} }
func TestMust(t *testing.T) {
assert.Panics(t, func() {
Must(errors.New("foo"))
})
}
func TestStructedLogAlert(t *testing.T) { func TestStructedLogAlert(t *testing.T) {
w := new(mockWriter) w := new(mockWriter)
old := writer.Swap(w) old := writer.Swap(w)
@@ -574,26 +584,38 @@ func TestSetup(t *testing.T) {
atomic.StoreUint32(&encoding, jsonEncodingType) atomic.StoreUint32(&encoding, jsonEncodingType)
}() }()
setupOnce = sync.Once{}
MustSetup(LogConf{
ServiceName: "any",
Mode: "console",
Encoding: "json",
TimeFormat: timeFormat,
})
setupOnce = sync.Once{}
MustSetup(LogConf{ MustSetup(LogConf{
ServiceName: "any", ServiceName: "any",
Mode: "console", Mode: "console",
TimeFormat: timeFormat, TimeFormat: timeFormat,
}) })
setupOnce = sync.Once{}
MustSetup(LogConf{ MustSetup(LogConf{
ServiceName: "any", ServiceName: "any",
Mode: "file", Mode: "file",
Path: os.TempDir(), Path: os.TempDir(),
}) })
setupOnce = sync.Once{}
MustSetup(LogConf{ MustSetup(LogConf{
ServiceName: "any", ServiceName: "any",
Mode: "volume", Mode: "volume",
Path: os.TempDir(), Path: os.TempDir(),
}) })
setupOnce = sync.Once{}
MustSetup(LogConf{ MustSetup(LogConf{
ServiceName: "any", ServiceName: "any",
Mode: "console", Mode: "console",
TimeFormat: timeFormat, TimeFormat: timeFormat,
}) })
setupOnce = sync.Once{}
MustSetup(LogConf{ MustSetup(LogConf{
ServiceName: "any", ServiceName: "any",
Mode: "console", Mode: "console",

View File

@@ -237,7 +237,7 @@ func NewLogger(filename string, rule RotateRule, compress bool) (*RotateLogger,
rule: rule, rule: rule,
compress: compress, compress: compress,
} }
if err := l.init(); err != nil { if err := l.initialize(); err != nil {
return nil, err return nil, err
} }
@@ -281,7 +281,7 @@ func (l *RotateLogger) getBackupFilename() string {
return l.backup return l.backup
} }
func (l *RotateLogger) init() error { func (l *RotateLogger) initialize() error {
l.backup = l.rule.BackupFileName() l.backup = l.rule.BackupFileName()
if fileInfo, err := os.Stat(l.filename); err != nil { if fileInfo, err := os.Stat(l.filename); err != nil {

View File

@@ -1,6 +1,10 @@
package logx package logx
import "errors" import (
"errors"
"github.com/zeromicro/go-zero/core/syncx"
)
const ( const (
// DebugLevel logs everything // DebugLevel logs everything
@@ -61,6 +65,8 @@ var (
ErrLogPathNotSet = errors.New("log path must be set") ErrLogPathNotSet = errors.New("log path must be set")
// ErrLogServiceNameNotSet is an error that indicates that the service name is not set. // ErrLogServiceNameNotSet is an error that indicates that the service name is not set.
ErrLogServiceNameNotSet = errors.New("log service name must be set") ErrLogServiceNameNotSet = errors.New("log service name must be set")
// ExitOnFatal defines whether to exit on fatal errors, defined here to make it easier to test.
ExitOnFatal = syncx.ForAtomicBool(true)
truncatedField = Field(truncatedKey, true) truncatedField = Field(truncatedKey, true)
) )

View File

@@ -289,6 +289,10 @@ func (u *Unmarshaler) generateMap(keyType, elemType reflect.Type, mapValue any)
return reflect.ValueOf(mapValue), nil return reflect.ValueOf(mapValue), nil
} }
if keyType != valueType.Key() {
return emptyValue, errTypeMismatch
}
refValue := reflect.ValueOf(mapValue) refValue := reflect.ValueOf(mapValue)
targetValue := reflect.MakeMapWithSize(mapType, refValue.Len()) targetValue := reflect.MakeMapWithSize(mapType, refValue.Len())
dereffedElemType := Deref(elemType) dereffedElemType := Deref(elemType)
@@ -486,7 +490,7 @@ func (u *Unmarshaler) processAnonymousStructFieldOptional(fieldType reflect.Type
} }
if filled && required != requiredFilled { if filled && required != requiredFilled {
return fmt.Errorf("%s is not fully set", key) return fmt.Errorf("%q is not fully set", key)
} }
return nil return nil
@@ -691,6 +695,10 @@ func (u *Unmarshaler) processFieldWithEnvValue(fieldType reflect.Type, value ref
func (u *Unmarshaler) processNamedField(field reflect.StructField, value reflect.Value, func (u *Unmarshaler) processNamedField(field reflect.StructField, value reflect.Value,
m valuerWithParent, fullName string) error { m valuerWithParent, fullName string) error {
if !field.IsExported() {
return nil
}
key, opts, err := u.parseOptionsWithContext(field, m, fullName) key, opts, err := u.parseOptionsWithContext(field, m, fullName)
if err != nil { if err != nil {
return err return err
@@ -715,7 +723,7 @@ func (u *Unmarshaler) processNamedField(field reflect.StructField, value reflect
// When fillDefault is used, m is a null value, hasValue must be false, all priority judgments fillDefault. // When fillDefault is used, m is a null value, hasValue must be false, all priority judgments fillDefault.
if u.opts.fillDefault { if u.opts.fillDefault {
if !value.IsZero() { if !value.IsZero() {
return fmt.Errorf("set the default value, %s must be zero", fullName) return fmt.Errorf("set the default value, %q must be zero", fullName)
} }
return u.processNamedFieldWithoutValue(field.Type, value, opts, fullName) return u.processNamedFieldWithoutValue(field.Type, value, opts, fullName)
} else if !hasValue { } else if !hasValue {
@@ -736,11 +744,11 @@ func (u *Unmarshaler) processNamedFieldWithValue(fieldType reflect.Type, value r
return nil return nil
} }
return fmt.Errorf("field %s mustn't be nil", key) return fmt.Errorf("field %q mustn't be nil", key)
} }
if !value.CanSet() { if !value.CanSet() {
return fmt.Errorf("field %s is not settable", key) return fmt.Errorf("field %q is not settable", key)
} }
maybeNewValue(fieldType, value) maybeNewValue(fieldType, value)
@@ -784,7 +792,7 @@ func (u *Unmarshaler) processNamedFieldWithValueFromString(fieldType reflect.Typ
} }
if !stringx.Contains(options, checkValue) { if !stringx.Contains(options, checkValue) {
return fmt.Errorf(`value "%s" for field "%s" is not defined in options "%v"`, return fmt.Errorf(`value "%s" for field %q is not defined in options "%v"`,
mapValue, key, options) mapValue, key, options)
} }
} }
@@ -810,6 +818,11 @@ func (u *Unmarshaler) processNamedFieldWithoutValue(fieldType reflect.Type, valu
} }
if u.opts.fillDefault { if u.opts.fillDefault {
if fieldType.Kind() != reflect.Ptr && fieldKind == reflect.Struct {
return u.processFieldNotFromString(fieldType, value, valueWithParent{
value: emptyMap,
}, opts, fullName)
}
return nil return nil
} }
@@ -865,12 +878,14 @@ func (u *Unmarshaler) unmarshalWithFullName(m valuerWithParent, v any, fullName
numFields := baseType.NumField() numFields := baseType.NumField()
for i := 0; i < numFields; i++ { for i := 0; i < numFields; i++ {
field := baseType.Field(i) typeField := baseType.Field(i)
if !field.IsExported() { valueField := valElem.Field(i)
continue if err := u.processField(typeField, valueField, m, fullName); err != nil {
} if len(fullName) > 0 {
err = fmt.Errorf("%w, fullName: %s, field: %s, type: %s",
err, fullName, typeField.Name, valueField.Type().Name())
}
if err := u.processField(field, valElem.Field(i), m, fullName); err != nil {
return err return err
} }
} }
@@ -1024,11 +1039,11 @@ func join(elem ...string) string {
} }
func newInitError(name string) error { func newInitError(name string) error {
return fmt.Errorf("field %s is not set", name) return fmt.Errorf("field %q is not set", name)
} }
func newTypeMismatchError(name string) error { func newTypeMismatchError(name string) error {
return fmt.Errorf("type mismatch for field %s", name) return fmt.Errorf("type mismatch for field %q", name)
} }
func readKeys(key string) []string { func readKeys(key string) []string {

View File

@@ -53,6 +53,52 @@ func TestUnmarshalWithoutTagName(t *testing.T) {
} }
} }
func TestUnmarshalWithLowerField(t *testing.T) {
type (
Lower struct {
value int `key:"lower"`
}
inner struct {
Lower
Optional bool `key:",optional"`
}
)
m := map[string]any{
"Optional": true,
"lower": 1,
}
var in inner
if assert.NoError(t, UnmarshalKey(m, &in)) {
assert.True(t, in.Optional)
assert.Equal(t, 0, in.value)
}
}
func TestUnmarshalWithLowerAnonymousStruct(t *testing.T) {
type (
lower struct {
Value int `key:"lower"`
}
inner struct {
lower
Optional bool `key:",optional"`
}
)
m := map[string]any{
"Optional": true,
"lower": 1,
}
var in inner
if assert.NoError(t, UnmarshalKey(m, &in)) {
assert.True(t, in.Optional)
assert.Equal(t, 1, in.Value)
}
}
func TestUnmarshalWithoutTagNameWithCanonicalKey(t *testing.T) { func TestUnmarshalWithoutTagNameWithCanonicalKey(t *testing.T) {
type inner struct { type inner struct {
Name string `key:"name"` Name string `key:"name"`
@@ -4285,6 +4331,97 @@ func TestUnmarshalOnlyPublicVariables(t *testing.T) {
} }
} }
func TestFillDefaultUnmarshal(t *testing.T) {
fillDefaultUnmarshal := NewUnmarshaler(jsonTagKey, WithDefault())
t.Run("nil", func(t *testing.T) {
type St struct{}
err := fillDefaultUnmarshal.Unmarshal(map[string]any{}, St{})
assert.Error(t, err)
})
t.Run("not nil", func(t *testing.T) {
type St struct{}
err := fillDefaultUnmarshal.Unmarshal(map[string]any{}, &St{})
assert.NoError(t, err)
})
t.Run("default", func(t *testing.T) {
type St struct {
A string `json:",default=a"`
B string
}
var st St
err := fillDefaultUnmarshal.Unmarshal(map[string]any{}, &st)
assert.NoError(t, err)
assert.Equal(t, "a", st.A)
})
t.Run("env", func(t *testing.T) {
type St struct {
A string `json:",default=a"`
B string
C string `json:",env=TEST_C"`
}
t.Setenv("TEST_C", "c")
var st St
err := fillDefaultUnmarshal.Unmarshal(map[string]any{}, &st)
assert.NoError(t, err)
assert.Equal(t, "a", st.A)
assert.Equal(t, "c", st.C)
})
t.Run("has value", func(t *testing.T) {
type St struct {
A string `json:",default=a"`
B string
}
var st = St{
A: "b",
}
err := fillDefaultUnmarshal.Unmarshal(map[string]any{}, &st)
assert.Error(t, err)
})
t.Run("handling struct", func(t *testing.T) {
type St struct {
A string `json:",default=a"`
B string
}
type St2 struct {
St
St1 St
St3 *St
C string `json:",default=c"`
D string
Child *St2
}
var st2 St2
err := fillDefaultUnmarshal.Unmarshal(map[string]any{}, &st2)
assert.NoError(t, err)
assert.Equal(t, "a", st2.St.A)
assert.Equal(t, "a", st2.St1.A)
assert.Nil(t, st2.St3)
assert.Equal(t, "c", st2.C)
assert.Nil(t, st2.Child)
})
}
func Test_UnmarshalMap(t *testing.T) {
type Customer struct {
Names map[int]string `key:"names"`
}
input := map[string]any{
"names": map[string]any{
"19": "Tom",
},
}
var customer Customer
assert.ErrorIs(t, UnmarshalKey(input, &customer), errTypeMismatch)
}
func BenchmarkDefaultValue(b *testing.B) { func BenchmarkDefaultValue(b *testing.B) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
var a struct { var a struct {
@@ -4384,56 +4521,3 @@ func BenchmarkUnmarshal(b *testing.B) {
UnmarshalKey(data, &an) UnmarshalKey(data, &an)
} }
} }
func TestFillDefaultUnmarshal(t *testing.T) {
fillDefaultUnmarshal := NewUnmarshaler(jsonTagKey, WithDefault())
t.Run("nil", func(t *testing.T) {
type St struct{}
err := fillDefaultUnmarshal.Unmarshal(map[string]any{}, St{})
assert.Error(t, err)
})
t.Run("not nil", func(t *testing.T) {
type St struct{}
err := fillDefaultUnmarshal.Unmarshal(map[string]any{}, &St{})
assert.NoError(t, err)
})
t.Run("default", func(t *testing.T) {
type St struct {
A string `json:",default=a"`
B string
}
var st St
err := fillDefaultUnmarshal.Unmarshal(map[string]any{}, &st)
assert.NoError(t, err)
assert.Equal(t, st.A, "a")
})
t.Run("env", func(t *testing.T) {
type St struct {
A string `json:",default=a"`
B string
C string `json:",env=TEST_C"`
}
t.Setenv("TEST_C", "c")
var st St
err := fillDefaultUnmarshal.Unmarshal(map[string]any{}, &st)
assert.NoError(t, err)
assert.Equal(t, st.A, "a")
assert.Equal(t, st.C, "c")
})
t.Run("has value", func(t *testing.T) {
type St struct {
A string `json:",default=a"`
B string
}
var st = St{
A: "b",
}
err := fillDefaultUnmarshal.Unmarshal(map[string]any{}, &st)
assert.Error(t, err)
})
}

View File

@@ -255,7 +255,7 @@ func parseGroupedSegments(val string) []string {
// don't modify returned fieldOptions, it's cached and shared among different calls. // don't modify returned fieldOptions, it's cached and shared among different calls.
func parseKeyAndOptions(tagName string, field reflect.StructField) (string, *fieldOptions, error) { func parseKeyAndOptions(tagName string, field reflect.StructField) (string, *fieldOptions, error) {
value := field.Tag.Get(tagName) value := strings.TrimSpace(field.Tag.Get(tagName))
if len(value) == 0 { if len(value) == 0 {
return field.Name, nil, nil return field.Name, nil, nil
} }
@@ -370,7 +370,7 @@ func parseOption(fieldOpts *fieldOptions, fieldName, option string) error {
fieldOpts.Optional = true fieldOpts.Optional = true
fieldOpts.OptionalDep = segs[1] fieldOpts.OptionalDep = segs[1]
default: default:
return fmt.Errorf("field %s has wrong optional", fieldName) return fmt.Errorf("field %q has wrong optional", fieldName)
} }
case option == optionalOption: case option == optionalOption:
fieldOpts.Optional = true fieldOpts.Optional = true
@@ -429,7 +429,7 @@ func parseOptions(val string) []string {
func parseProperty(field, tag, val string) (string, error) { func parseProperty(field, tag, val string) (string, error) {
segs := strings.Split(val, equalToken) segs := strings.Split(val, equalToken)
if len(segs) != 2 { if len(segs) != 2 {
return "", fmt.Errorf("field %s has wrong %s", field, tag) return "", fmt.Errorf("field %q has wrong tag value %q", field, tag)
} }
return strings.TrimSpace(segs[1]), nil return strings.TrimSpace(segs[1]), nil
@@ -628,7 +628,7 @@ func validateValueInOptions(val any, options []string) error {
switch v := val.(type) { switch v := val.(type) {
case string: case string:
if !stringx.Contains(options, v) { if !stringx.Contains(options, v) {
return fmt.Errorf(`error: value "%s" is not defined in options "%v"`, v, options) return fmt.Errorf(`error: value %q is not defined in options "%v"`, v, options)
} }
default: default:
if !stringx.Contains(options, Repr(v)) { if !stringx.Contains(options, Repr(v)) {

View File

@@ -144,6 +144,10 @@ func TestParseSegments(t *testing.T) {
input: "", input: "",
expect: []string{}, expect: []string{},
}, },
{
input: " ",
expect: []string{},
},
{ {
input: ",", input: ",",
expect: []string{""}, expect: []string{""},

View File

@@ -34,7 +34,7 @@ type (
recursiveValuer node recursiveValuer node
) )
// Value gets the value assciated with the given key from mv. // Value gets the value associated with the given key from mv.
func (mv mapValuer) Value(key string) (any, bool) { func (mv mapValuer) Value(key string) (any, bool) {
v, ok := mv[key] v, ok := mv[key]
return v, ok return v, ok

View File

@@ -1,5 +1,4 @@
//go:build fuzz //go:build fuzz
// +build fuzz
package mr package mr

View File

@@ -1,5 +1,4 @@
//go:build windows //go:build windows
// +build windows
package proc package proc

View File

@@ -1,5 +1,4 @@
//go:build linux || darwin //go:build linux || darwin
// +build linux darwin
package proc package proc

View File

@@ -1,5 +1,4 @@
//go:build windows //go:build windows
// +build windows
package proc package proc

View File

@@ -1,5 +1,4 @@
//go:build linux || darwin //go:build linux || darwin
// +build linux darwin
package proc package proc

View File

@@ -1,5 +1,4 @@
//go:build windows //go:build windows
// +build windows
package proc package proc

View File

@@ -1,5 +1,4 @@
//go:build linux || darwin //go:build linux || darwin
// +build linux darwin
package proc package proc

View File

@@ -1,5 +1,4 @@
//go:build linux || darwin //go:build linux || darwin
// +build linux darwin
package proc package proc

View File

@@ -1,5 +1,4 @@
//go:build windows //go:build windows
// +build windows
package proc package proc

View File

@@ -1,5 +1,4 @@
//go:build linux || darwin //go:build linux || darwin
// +build linux darwin
package proc package proc

View File

@@ -1,5 +1,4 @@
//go:build debug //go:build debug
// +build debug
package search package search

View File

@@ -1,5 +1,4 @@
//go:build !linux //go:build !linux
// +build !linux
package stat package stat

View File

@@ -1,5 +1,4 @@
//go:build linux //go:build linux
// +build linux
package stat package stat

View File

@@ -1,5 +1,4 @@
//go:build linux //go:build linux
// +build linux
package stat package stat

View File

@@ -278,10 +278,8 @@ func runningInUserNS() bool {
var a, b, c int64 var a, b, c int64
fmt.Sscanf(line, "%d %d %d", &a, &b, &c) fmt.Sscanf(line, "%d %d %d", &a, &b, &c)
/* // We assume we are in the initial user namespace if we have a full
* We assume we are in the initial user namespace if we have a full // range - 4294967295 uids starting at uid 0.
* range - 4294967295 uids starting at uid 0.
*/
if a == 0 && b == 0 && c == 4294967295 { if a == 0 && b == 0 && c == 4294967295 {
return return
} }

View File

@@ -1,5 +1,4 @@
//go:build !linux //go:build !linux
// +build !linux
package internal package internal

View File

@@ -6,11 +6,9 @@ import (
"time" "time"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/logx"
) )
func TestMetrics(t *testing.T) { func TestMetrics(t *testing.T) {
logx.Disable()
DisableLog() DisableLog()
defer logEnabled.Set(true) defer logEnabled.Set(true)

64
core/stat/usage_test.go Normal file
View File

@@ -0,0 +1,64 @@
package stat
import (
"bytes"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/logx"
)
func TestBToMb(t *testing.T) {
tests := []struct {
name string
bytes uint64
expected float32
}{
{
name: "Test 1: Convert 0 bytes to MB",
bytes: 0,
expected: 0,
},
{
name: "Test 2: Convert 1048576 bytes to MB",
bytes: 1048576,
expected: 1,
},
{
name: "Test 3: Convert 2097152 bytes to MB",
bytes: 2097152,
expected: 2,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
result := bToMb(test.bytes)
assert.Equal(t, test.expected, result)
})
}
}
func TestPrintUsage(t *testing.T) {
var buf bytes.Buffer
writer := logx.NewWriter(&buf)
old := logx.Reset()
logx.SetWriter(writer)
defer logx.SetWriter(old)
printUsage()
output := buf.String()
assert.Contains(t, output, "CPU:")
assert.Contains(t, output, "MEMORY:")
assert.Contains(t, output, "Alloc=")
assert.Contains(t, output, "TotalAlloc=")
assert.Contains(t, output, "Sys=")
assert.Contains(t, output, "NumGC=")
lines := strings.Split(output, "\n")
assert.Len(t, lines, 2)
fields := strings.Split(lines[0], ", ")
assert.Len(t, fields, 5)
}

View File

@@ -112,12 +112,8 @@ func (mc *mockedNode) TakeWithExpireCtx(ctx context.Context, val any, key string
func TestCache_SetDel(t *testing.T) { func TestCache_SetDel(t *testing.T) {
t.Run("test set del", func(t *testing.T) { t.Run("test set del", func(t *testing.T) {
const total = 1000 const total = 1000
r1, clean1, err := redistest.CreateRedis() r1 := redistest.CreateRedis(t)
assert.Nil(t, err) r2 := redistest.CreateRedis(t)
defer clean1()
r2, clean2, err := redistest.CreateRedis()
assert.Nil(t, err)
defer clean2()
conf := ClusterConf{ conf := ClusterConf{
{ {
RedisConf: redis.RedisConf{ RedisConf: redis.RedisConf{
@@ -193,9 +189,7 @@ func TestCache_SetDel(t *testing.T) {
func TestCache_OneNode(t *testing.T) { func TestCache_OneNode(t *testing.T) {
const total = 1000 const total = 1000
r, clean, err := redistest.CreateRedis() r := redistest.CreateRedis(t)
assert.Nil(t, err)
defer clean()
conf := ClusterConf{ conf := ClusterConf{
{ {
RedisConf: redis.RedisConf{ RedisConf: redis.RedisConf{

View File

@@ -34,10 +34,8 @@ func init() {
func TestCacheNode_DelCache(t *testing.T) { func TestCacheNode_DelCache(t *testing.T) {
t.Run("del cache", func(t *testing.T) { t.Run("del cache", func(t *testing.T) {
store, clean, err := redistest.CreateRedis() store := redistest.CreateRedis(t)
assert.Nil(t, err)
store.Type = redis.ClusterType store.Type = redis.ClusterType
defer clean()
cn := cacheNode{ cn := cacheNode{
rds: store, rds: store,
@@ -84,9 +82,7 @@ func TestCacheNode_DelCache(t *testing.T) {
} }
func TestCacheNode_DelCacheWithErrors(t *testing.T) { func TestCacheNode_DelCacheWithErrors(t *testing.T) {
store, clean, err := redistest.CreateRedis() store := redistest.CreateRedis(t)
assert.Nil(t, err)
defer clean()
store.Type = redis.ClusterType store.Type = redis.ClusterType
cn := cacheNode{ cn := cacheNode{
@@ -122,9 +118,7 @@ func TestCacheNode_InvalidCache(t *testing.T) {
} }
func TestCacheNode_SetWithExpire(t *testing.T) { func TestCacheNode_SetWithExpire(t *testing.T) {
store, clean, err := redistest.CreateRedis() store := redistest.CreateRedis(t)
assert.Nil(t, err)
defer clean()
cn := cacheNode{ cn := cacheNode{
rds: store, rds: store,
@@ -139,14 +133,12 @@ func TestCacheNode_SetWithExpire(t *testing.T) {
} }
func TestCacheNode_Take(t *testing.T) { func TestCacheNode_Take(t *testing.T) {
store, clean, err := redistest.CreateRedis() store := redistest.CreateRedis(t)
assert.Nil(t, err)
defer clean()
cn := NewNode(store, syncx.NewSingleFlight(), NewStat("any"), errTestNotFound, cn := NewNode(store, syncx.NewSingleFlight(), NewStat("any"), errTestNotFound,
WithExpiry(time.Second), WithNotFoundExpiry(time.Second)) WithExpiry(time.Second), WithNotFoundExpiry(time.Second))
var str string var str string
err = cn.Take(&str, "any", func(v any) error { err := cn.Take(&str, "any", func(v any) error {
*v.(*string) = "value" *v.(*string) = "value"
return nil return nil
}) })
@@ -174,9 +166,7 @@ func TestCacheNode_TakeBadRedis(t *testing.T) {
} }
func TestCacheNode_TakeNotFound(t *testing.T) { func TestCacheNode_TakeNotFound(t *testing.T) {
store, clean, err := redistest.CreateRedis() store := redistest.CreateRedis(t)
assert.Nil(t, err)
defer clean()
cn := cacheNode{ cn := cacheNode{
rds: store, rds: store,
@@ -188,7 +178,7 @@ func TestCacheNode_TakeNotFound(t *testing.T) {
errNotFound: errTestNotFound, errNotFound: errTestNotFound,
} }
var str string var str string
err = cn.Take(&str, "any", func(v any) error { err := cn.Take(&str, "any", func(v any) error {
return errTestNotFound return errTestNotFound
}) })
assert.True(t, cn.IsNotFound(err)) assert.True(t, cn.IsNotFound(err))
@@ -213,9 +203,7 @@ func TestCacheNode_TakeNotFound(t *testing.T) {
} }
func TestCacheNode_TakeNotFoundButChangedByOthers(t *testing.T) { func TestCacheNode_TakeNotFoundButChangedByOthers(t *testing.T) {
store, clean, err := redistest.CreateRedis() store := redistest.CreateRedis(t)
assert.NoError(t, err)
defer clean()
cn := cacheNode{ cn := cacheNode{
rds: store, rds: store,
@@ -228,7 +216,7 @@ func TestCacheNode_TakeNotFoundButChangedByOthers(t *testing.T) {
} }
var str string var str string
err = cn.Take(&str, "any", func(v any) error { err := cn.Take(&str, "any", func(v any) error {
store.Set("any", "foo") store.Set("any", "foo")
return errTestNotFound return errTestNotFound
}) })
@@ -242,9 +230,7 @@ func TestCacheNode_TakeNotFoundButChangedByOthers(t *testing.T) {
} }
func TestCacheNode_TakeWithExpire(t *testing.T) { func TestCacheNode_TakeWithExpire(t *testing.T) {
store, clean, err := redistest.CreateRedis() store := redistest.CreateRedis(t)
assert.Nil(t, err)
defer clean()
cn := cacheNode{ cn := cacheNode{
rds: store, rds: store,
@@ -256,7 +242,7 @@ func TestCacheNode_TakeWithExpire(t *testing.T) {
errNotFound: errors.New("any"), errNotFound: errors.New("any"),
} }
var str string var str string
err = cn.TakeWithExpire(&str, "any", func(v any, expire time.Duration) error { err := cn.TakeWithExpire(&str, "any", func(v any, expire time.Duration) error {
*v.(*string) = "value" *v.(*string) = "value"
return nil return nil
}) })
@@ -269,9 +255,7 @@ func TestCacheNode_TakeWithExpire(t *testing.T) {
} }
func TestCacheNode_String(t *testing.T) { func TestCacheNode_String(t *testing.T) {
store, clean, err := redistest.CreateRedis() store := redistest.CreateRedis(t)
assert.Nil(t, err)
defer clean()
cn := cacheNode{ cn := cacheNode{
rds: store, rds: store,
@@ -286,9 +270,7 @@ func TestCacheNode_String(t *testing.T) {
} }
func TestCacheValueWithBigInt(t *testing.T) { func TestCacheValueWithBigInt(t *testing.T) {
store, clean, err := redistest.CreateRedis() store := redistest.CreateRedis(t)
assert.Nil(t, err)
defer clean()
cn := cacheNode{ cn := cacheNode{
rds: store, rds: store,

View File

@@ -2,7 +2,8 @@ package postgres
import ( import (
// imports the driver, don't remove this comment, golint requires. // imports the driver, don't remove this comment, golint requires.
_ "github.com/jackc/pgx/v5" _ "github.com/jackc/pgx/v5/stdlib"
"github.com/zeromicro/go-zero/core/stores/sqlx" "github.com/zeromicro/go-zero/core/stores/sqlx"
) )

View File

@@ -1,6 +1,9 @@
package redis package redis
import "errors" import (
"errors"
"time"
)
var ( var (
// ErrEmptyHost is an error that indicates no redis host is set. // ErrEmptyHost is an error that indicates no redis host is set.
@@ -9,23 +12,24 @@ var (
ErrEmptyType = errors.New("empty redis type") ErrEmptyType = errors.New("empty redis type")
// ErrEmptyKey is an error that indicates no redis key is set. // ErrEmptyKey is an error that indicates no redis key is set.
ErrEmptyKey = errors.New("empty redis key") ErrEmptyKey = errors.New("empty redis key")
// ErrPing is an error that indicates ping failed.
ErrPing = errors.New("ping redis failed")
) )
type ( type (
// A RedisConf is a redis config. // A RedisConf is a redis config.
RedisConf struct { RedisConf struct {
Host string Host string
Type string `json:",default=node,options=node|cluster"` Type string `json:",default=node,options=node|cluster"`
Pass string `json:",optional"` Pass string `json:",optional"`
Tls bool `json:",optional"` Tls bool `json:",optional"`
NonBlock bool `json:",default=true"`
// PingTimeout is the timeout for ping redis.
PingTimeout time.Duration `json:",default=1s"`
} }
// A RedisKeyConf is a redis config with key. // A RedisKeyConf is a redis config with key.
RedisKeyConf struct { RedisKeyConf struct {
RedisConf RedisConf
Key string `json:",optional"` Key string
} }
) )

View File

@@ -10,6 +10,7 @@ import (
red "github.com/go-redis/redis/v8" red "github.com/go-redis/redis/v8"
"github.com/zeromicro/go-zero/core/breaker" "github.com/zeromicro/go-zero/core/breaker"
"github.com/zeromicro/go-zero/core/errorx"
"github.com/zeromicro/go-zero/core/mapping" "github.com/zeromicro/go-zero/core/mapping"
"github.com/zeromicro/go-zero/core/syncx" "github.com/zeromicro/go-zero/core/syncx"
) )
@@ -25,6 +26,7 @@ const (
blockingQueryTimeout = 5 * time.Second blockingQueryTimeout = 5 * time.Second
readWriteTimeout = 2 * time.Second readWriteTimeout = 2 * time.Second
defaultSlowThreshold = time.Millisecond * 100 defaultSlowThreshold = time.Millisecond * 100
defaultPingTimeout = time.Second
) )
var ( var (
@@ -51,11 +53,12 @@ type (
// Redis defines a redis node/cluster. It is thread-safe. // Redis defines a redis node/cluster. It is thread-safe.
Redis struct { Redis struct {
Addr string Addr string
Type string Type string
Pass string Pass string
tls bool tls bool
brk breaker.Breaker brk breaker.Breaker
hooks []red.Hook
} }
// RedisNode interface represents a redis node. // RedisNode interface represents a redis node.
@@ -84,6 +87,8 @@ type (
FloatCmd = red.FloatCmd FloatCmd = red.FloatCmd
// StringCmd is an alias of redis.StringCmd. // StringCmd is an alias of redis.StringCmd.
StringCmd = red.StringCmd StringCmd = red.StringCmd
// Script is an alias of redis.Script.
Script = red.Script
) )
// New returns a Redis with given options. // New returns a Redis with given options.
@@ -119,8 +124,10 @@ func NewRedis(conf RedisConf, opts ...Option) (*Redis, error) {
} }
rds := newRedis(conf.Host, opts...) rds := newRedis(conf.Host, opts...)
if !rds.Ping() { if !conf.NonBlock {
return nil, ErrPing if err := rds.checkConnection(conf.PingTimeout); err != nil {
return nil, errorx.Wrap(err, fmt.Sprintf("redis connect error, addr: %s", conf.Host))
}
} }
return rds, nil return rds, nil
@@ -140,6 +147,11 @@ func newRedis(addr string, opts ...Option) *Redis {
return r return r
} }
// NewScript returns a new Script instance.
func NewScript(script string) *Script {
return red.NewScript(script)
}
// BitCount is redis bitcount command implementation. // BitCount is redis bitcount command implementation.
func (s *Redis) BitCount(key string, start, end int64) (int64, error) { func (s *Redis) BitCount(key string, start, end int64) (int64, error) {
return s.BitCountCtx(context.Background(), key, start, end) return s.BitCountCtx(context.Background(), key, start, end)
@@ -832,12 +844,12 @@ func (s *Redis) HincrbyCtx(ctx context.Context, key, field string, increment int
return return
} }
// HincrbyFloat is the implementation of redis hincrby command. // HincrbyFloat is the implementation of redis hincrbyfloat command.
func (s *Redis) HincrbyFloat(key, field string, increment float64) (float64, error) { func (s *Redis) HincrbyFloat(key, field string, increment float64) (float64, error) {
return s.HincrbyFloatCtx(context.Background(), key, field, increment) return s.HincrbyFloatCtx(context.Background(), key, field, increment)
} }
// HincrbyFloatCtx is the implementation of redis hincrby command. // HincrbyFloatCtx is the implementation of redis hincrbyfloat command.
func (s *Redis) HincrbyFloatCtx(ctx context.Context, key, field string, increment float64) (val float64, err error) { func (s *Redis) HincrbyFloatCtx(ctx context.Context, key, field string, increment float64) (val float64, err error) {
err = s.brk.DoWithAcceptable(func() error { err = s.brk.DoWithAcceptable(func() error {
conn, err := getRedis(s) conn, err := getRedis(s)
@@ -1065,12 +1077,12 @@ func (s *Redis) IncrbyCtx(ctx context.Context, key string, increment int64) (val
return return
} }
// IncrbyFloat is the implementation of redis incrby command. // IncrbyFloat is the implementation of redis hincrbyfloat command.
func (s *Redis) IncrbyFloat(key string, increment float64) (float64, error) { func (s *Redis) IncrbyFloat(key string, increment float64) (float64, error) {
return s.IncrbyFloatCtx(context.Background(), key, increment) return s.IncrbyFloatCtx(context.Background(), key, increment)
} }
// IncrbyFloatCtx is the implementation of redis incrby command. // IncrbyFloatCtx is the implementation of redis hincrbyfloat command.
func (s *Redis) IncrbyFloatCtx(ctx context.Context, key string, increment float64) (val float64, err error) { func (s *Redis) IncrbyFloatCtx(ctx context.Context, key string, increment float64) (val float64, err error) {
err = s.brk.DoWithAcceptable(func() error { err = s.brk.DoWithAcceptable(func() error {
conn, err := getRedis(s) conn, err := getRedis(s)
@@ -1170,6 +1182,26 @@ func (s *Redis) LpopCtx(ctx context.Context, key string) (val string, err error)
return return
} }
// LpopCount is the implementation of redis lpopCount command.
func (s *Redis) LpopCount(key string, count int) ([]string, error) {
return s.LpopCountCtx(context.Background(), key, count)
}
// LpopCountCtx is the implementation of redis lpopCount command.
func (s *Redis) LpopCountCtx(ctx context.Context, key string, count int) (val []string, err error) {
err = s.brk.DoWithAcceptable(func() error {
conn, err := getRedis(s)
if err != nil {
return err
}
val, err = conn.LPopCount(ctx, key, count).Result()
return err
}, acceptable)
return
}
// Lpush is the implementation of redis lpush command. // Lpush is the implementation of redis lpush command.
func (s *Redis) Lpush(key string, values ...any) (int, error) { func (s *Redis) Lpush(key string, values ...any) (int, error) {
return s.LpushCtx(context.Background(), key, values...) return s.LpushCtx(context.Background(), key, values...)
@@ -1432,6 +1464,26 @@ func (s *Redis) RpopCtx(ctx context.Context, key string) (val string, err error)
return return
} }
// RpopCount is the implementation of redis rpopCount command.
func (s *Redis) RpopCount(key string, count int) ([]string, error) {
return s.RpopCountCtx(context.Background(), key, count)
}
// RpopCountCtx is the implementation of redis rpopCount command.
func (s *Redis) RpopCountCtx(ctx context.Context, key string, count int) (val []string, err error) {
err = s.brk.DoWithAcceptable(func() error {
conn, err := getRedis(s)
if err != nil {
return err
}
val, err = conn.RPopCount(ctx, key, count).Result()
return err
}, acceptable)
return
}
// Rpush is the implementation of redis rpush command. // Rpush is the implementation of redis rpush command.
func (s *Redis) Rpush(key string, values ...any) (int, error) { func (s *Redis) Rpush(key string, values ...any) (int, error) {
return s.RpushCtx(context.Background(), key, values...) return s.RpushCtx(context.Background(), key, values...)
@@ -1585,6 +1637,25 @@ func (s *Redis) ScriptLoadCtx(ctx context.Context, script string) (string, error
return conn.ScriptLoad(ctx, script).Result() return conn.ScriptLoad(ctx, script).Result()
} }
// ScriptRun is the implementation of *redis.Script run command.
func (s *Redis) ScriptRun(script *Script, keys []string, args ...any) (any, error) {
return s.ScriptRunCtx(context.Background(), script, keys, args...)
}
// ScriptRunCtx is the implementation of *redis.Script run command.
func (s *Redis) ScriptRunCtx(ctx context.Context, script *Script, keys []string, args ...any) (val any, err error) {
err = s.brk.DoWithAcceptable(func() error {
conn, err := getRedis(s)
if err != nil {
return err
}
val, err = script.Run(ctx, conn, keys, args...).Result()
return err
}, acceptable)
return
}
// Set is the implementation of redis set command. // Set is the implementation of redis set command.
func (s *Redis) Set(key, value string) error { func (s *Redis) Set(key, value string) error {
return s.SetCtx(context.Background(), key, value) return s.SetCtx(context.Background(), key, value)
@@ -2729,6 +2800,23 @@ func (s *Redis) ZunionstoreCtx(ctx context.Context, dest string, store *ZStore)
return return
} }
func (s *Redis) checkConnection(pingTimeout time.Duration) error {
conn, err := getRedis(s)
if err != nil {
return err
}
timeout := defaultPingTimeout
if pingTimeout > 0 {
timeout = pingTimeout
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
return conn.Ping(ctx).Err()
}
// Cluster customizes the given Redis as a cluster. // Cluster customizes the given Redis as a cluster.
func Cluster() Option { func Cluster() Option {
return func(r *Redis) { return func(r *Redis) {
@@ -2755,6 +2843,14 @@ func WithTLS() Option {
} }
} }
// withHook customizes the given Redis with given hook, only for private use now,
// maybe expose later.
func withHook(hook red.Hook) Option {
return func(r *Redis) {
r.hooks = append(r.hooks, hook)
}
}
func acceptable(err error) bool { func acceptable(err error) bool {
return err == nil || err == red.Nil || err == context.Canceled return err == nil || err == red.Nil || err == context.Canceled
} }

View File

@@ -16,6 +16,25 @@ import (
"github.com/zeromicro/go-zero/core/stringx" "github.com/zeromicro/go-zero/core/stringx"
) )
type myHook struct {
red.Hook
includePing bool
}
var _ red.Hook = myHook{}
func (m myHook) BeforeProcess(ctx context.Context, cmd red.Cmder) (context.Context, error) {
return ctx, nil
}
func (m myHook) AfterProcess(ctx context.Context, cmd red.Cmder) error {
// skip ping cmd
if cmd.Name() == "ping" && !m.includePing {
return nil
}
return errors.New("hook error")
}
func TestNewRedis(t *testing.T) { func TestNewRedis(t *testing.T) {
r1, err := miniredis.Run() r1, err := miniredis.Run()
assert.NoError(t, err) assert.NoError(t, err)
@@ -126,6 +145,31 @@ func TestNewRedis(t *testing.T) {
} }
} }
func TestRedis_NonBlock(t *testing.T) {
logx.Disable()
t.Run("nonBlock true", func(t *testing.T) {
s := miniredis.RunT(t)
// use hook to simulate redis ping error
_, err := NewRedis(RedisConf{
Host: s.Addr(),
NonBlock: true,
Type: NodeType,
}, withHook(myHook{includePing: true}))
assert.NoError(t, err)
})
t.Run("nonBlock false", func(t *testing.T) {
s := miniredis.RunT(t)
_, err := NewRedis(RedisConf{
Host: s.Addr(),
NonBlock: false,
Type: NodeType,
}, withHook(myHook{includePing: true}))
assert.ErrorContains(t, err, "redis connect error")
})
}
func TestRedis_Decr(t *testing.T) { func TestRedis_Decr(t *testing.T) {
runOnRedis(t, func(client *Redis) { runOnRedis(t, func(client *Redis) {
_, err := New(client.Addr, badType()).Decr("a") _, err := New(client.Addr, badType()).Decr("a")
@@ -196,6 +240,24 @@ func TestRedis_Eval(t *testing.T) {
}) })
} }
func TestRedis_ScriptRun(t *testing.T) {
runOnRedis(t, func(client *Redis) {
sc := NewScript(`redis.call("EXISTS", KEYS[1])`)
sc2 := NewScript(`return redis.call("EXISTS", KEYS[1])`)
_, err := New(client.Addr, badType()).ScriptRun(sc, []string{"notexist"})
assert.NotNil(t, err)
_, err = client.ScriptRun(sc, []string{"notexist"})
assert.Equal(t, Nil, err)
err = client.Set("key1", "value1")
assert.Nil(t, err)
_, err = client.ScriptRun(sc, []string{"key1"})
assert.Equal(t, Nil, err)
val, err := client.ScriptRun(sc2, []string{"key1"})
assert.Nil(t, err)
assert.Equal(t, int64(1), val)
})
}
func TestRedis_GeoHash(t *testing.T) { func TestRedis_GeoHash(t *testing.T) {
runOnRedis(t, func(client *Redis) { runOnRedis(t, func(client *Redis) {
_, err := client.GeoHash("parent", "child1", "child2") _, err := client.GeoHash("parent", "child1", "child2")
@@ -507,6 +569,14 @@ func TestRedis_List(t *testing.T) {
vals, err = client.Lrange("key", 0, 10) vals, err = client.Lrange("key", 0, 10)
assert.Nil(t, err) assert.Nil(t, err)
assert.EqualValues(t, []string{"value2", "value3"}, vals) assert.EqualValues(t, []string{"value2", "value3"}, vals)
vals, err = client.LpopCount("key", 2)
assert.Nil(t, err)
assert.EqualValues(t, []string{"value2", "value3"}, vals)
_, err = client.Lpush("key", "value1", "value2")
assert.Nil(t, err)
vals, err = client.RpopCount("key", 4)
assert.Nil(t, err)
assert.EqualValues(t, []string{"value1", "value2"}, vals)
}) })
}) })
@@ -523,6 +593,34 @@ func TestRedis_List(t *testing.T) {
_, err = client.Rpush("key", "value3", "value4") _, err = client.Rpush("key", "value3", "value4")
assert.Error(t, err) assert.Error(t, err)
_, err = client.LpopCount("key", 2)
assert.Error(t, err)
_, err = client.RpopCount("key", 2)
assert.Error(t, err)
})
})
t.Run("list redis type error", func(t *testing.T) {
runOnRedisWithError(t, func(client *Redis) {
client.Type = "nil"
_, err := client.Llen("key")
assert.Error(t, err)
_, err = client.Lpush("key", "value1", "value2")
assert.Error(t, err)
_, err = client.Lrem("key", 2, "value1")
assert.Error(t, err)
_, err = client.Rpush("key", "value3", "value4")
assert.Error(t, err)
_, err = client.LpopCount("key", 2)
assert.Error(t, err)
_, err = client.RpopCount("key", 2)
assert.Error(t, err)
}) })
}) })
} }

View File

@@ -31,7 +31,7 @@ func CreateBlockingNode(r *Redis) (ClosableNode, error) {
return &clientBridge{client}, nil return &clientBridge{client}, nil
case ClusterType: case ClusterType:
client := red.NewClusterClient(&red.ClusterOptions{ client := red.NewClusterClient(&red.ClusterOptions{
Addrs: []string{r.Addr}, Addrs: splitClusterAddrs(r.Addr),
Password: r.Pass, Password: r.Pass,
MaxRetries: maxRetries, MaxRetries: maxRetries,
PoolSize: 1, PoolSize: 1,

View File

@@ -33,6 +33,9 @@ func getClient(r *Redis) (*red.Client, error) {
TLSConfig: tlsConfig, TLSConfig: tlsConfig,
}) })
store.AddHook(durationHook) store.AddHook(durationHook)
for _, hook := range r.hooks {
store.AddHook(hook)
}
return store, nil return store, nil
}) })

View File

@@ -3,11 +3,14 @@ package redis
import ( import (
"crypto/tls" "crypto/tls"
"io" "io"
"strings"
red "github.com/go-redis/redis/v8" red "github.com/go-redis/redis/v8"
"github.com/zeromicro/go-zero/core/syncx" "github.com/zeromicro/go-zero/core/syncx"
) )
const addrSep = ","
var clusterManager = syncx.NewResourceManager() var clusterManager = syncx.NewResourceManager()
func getCluster(r *Redis) (*red.ClusterClient, error) { func getCluster(r *Redis) (*red.ClusterClient, error) {
@@ -19,13 +22,16 @@ func getCluster(r *Redis) (*red.ClusterClient, error) {
} }
} }
store := red.NewClusterClient(&red.ClusterOptions{ store := red.NewClusterClient(&red.ClusterOptions{
Addrs: []string{r.Addr}, Addrs: splitClusterAddrs(r.Addr),
Password: r.Pass, Password: r.Pass,
MaxRetries: maxRetries, MaxRetries: maxRetries,
MinIdleConns: idleConns, MinIdleConns: idleConns,
TLSConfig: tlsConfig, TLSConfig: tlsConfig,
}) })
store.AddHook(durationHook) store.AddHook(durationHook)
for _, hook := range r.hooks {
store.AddHook(hook)
}
return store, nil return store, nil
}) })
@@ -35,3 +41,18 @@ func getCluster(r *Redis) (*red.ClusterClient, error) {
return val.(*red.ClusterClient), nil return val.(*red.ClusterClient), nil
} }
func splitClusterAddrs(addr string) []string {
addrs := strings.Split(addr, addrSep)
unique := make(map[string]struct{})
for _, each := range addrs {
unique[strings.TrimSpace(each)] = struct{}{}
}
addrs = addrs[:0]
for k := range unique {
addrs = append(addrs, k)
}
return addrs
}

View File

@@ -0,0 +1,43 @@
package redis
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestSplitClusterAddrs(t *testing.T) {
testCases := []struct {
name string
input string
expected []string
}{
{
name: "empty input",
input: "",
expected: []string{""},
},
{
name: "single address",
input: "127.0.0.1:8000",
expected: []string{"127.0.0.1:8000"},
},
{
name: "multiple addresses with duplicates",
input: "127.0.0.1:8000,127.0.0.1:8001, 127.0.0.1:8000",
expected: []string{"127.0.0.1:8000", "127.0.0.1:8001"},
},
{
name: "multiple addresses without duplicates",
input: "127.0.0.1:8000, 127.0.0.1:8001, 127.0.0.1:8002",
expected: []string{"127.0.0.1:8000", "127.0.0.1:8001", "127.0.0.1:8002"},
},
}
for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
assert.ElementsMatch(t, tc.expected, splitClusterAddrs(tc.input))
})
}
}

View File

@@ -17,17 +17,20 @@ const (
randomLen = 16 randomLen = 16
tolerance = 500 // milliseconds tolerance = 500 // milliseconds
millisPerSecond = 1000 millisPerSecond = 1000
lockCommand = `if redis.call("GET", KEYS[1]) == ARGV[1] then )
var (
lockScript = NewScript(`if redis.call("GET", KEYS[1]) == ARGV[1] then
redis.call("SET", KEYS[1], ARGV[1], "PX", ARGV[2]) redis.call("SET", KEYS[1], ARGV[1], "PX", ARGV[2])
return "OK" return "OK"
else else
return redis.call("SET", KEYS[1], ARGV[1], "NX", "PX", ARGV[2]) return redis.call("SET", KEYS[1], ARGV[1], "NX", "PX", ARGV[2])
end` end`)
delCommand = `if redis.call("GET", KEYS[1]) == ARGV[1] then delScript = NewScript(`if redis.call("GET", KEYS[1]) == ARGV[1] then
return redis.call("DEL", KEYS[1]) return redis.call("DEL", KEYS[1])
else else
return 0 return 0
end` end`)
) )
// A RedisLock is a redis lock. // A RedisLock is a redis lock.
@@ -59,7 +62,7 @@ func (rl *RedisLock) Acquire() (bool, error) {
// AcquireCtx acquires the lock with the given ctx. // AcquireCtx acquires the lock with the given ctx.
func (rl *RedisLock) AcquireCtx(ctx context.Context) (bool, error) { func (rl *RedisLock) AcquireCtx(ctx context.Context) (bool, error) {
seconds := atomic.LoadUint32(&rl.seconds) seconds := atomic.LoadUint32(&rl.seconds)
resp, err := rl.store.EvalCtx(ctx, lockCommand, []string{rl.key}, []string{ resp, err := rl.store.ScriptRunCtx(ctx, lockScript, []string{rl.key}, []string{
rl.id, strconv.Itoa(int(seconds)*millisPerSecond + tolerance), rl.id, strconv.Itoa(int(seconds)*millisPerSecond + tolerance),
}) })
if err == red.Nil { if err == red.Nil {
@@ -87,7 +90,7 @@ func (rl *RedisLock) Release() (bool, error) {
// ReleaseCtx releases the lock with the given ctx. // ReleaseCtx releases the lock with the given ctx.
func (rl *RedisLock) ReleaseCtx(ctx context.Context) (bool, error) { func (rl *RedisLock) ReleaseCtx(ctx context.Context) (bool, error) {
resp, err := rl.store.EvalCtx(ctx, delCommand, []string{rl.key}, []string{rl.id}) resp, err := rl.store.ScriptRunCtx(ctx, delScript, []string{rl.key}, []string{rl.id})
if err != nil { if err != nil {
return false, err return false, err
} }

View File

@@ -1,31 +1,20 @@
package redistest package redistest
import ( import (
"time" "testing"
"github.com/alicebob/miniredis/v2" "github.com/alicebob/miniredis/v2"
"github.com/zeromicro/go-zero/core/lang"
"github.com/zeromicro/go-zero/core/stores/redis" "github.com/zeromicro/go-zero/core/stores/redis"
) )
// CreateRedis returns an in process redis.Redis. // CreateRedis returns an in process redis.Redis.
func CreateRedis() (r *redis.Redis, clean func(), err error) { func CreateRedis(t *testing.T) *redis.Redis {
mr, err := miniredis.Run() r, _ := CreateRedisWithClean(t)
if err != nil { return r
return nil, nil, err }
}
// CreateRedisWithClean returns an in process redis.Redis and a clean function.
return redis.New(mr.Addr()), func() { func CreateRedisWithClean(t *testing.T) (r *redis.Redis, clean func()) {
ch := make(chan lang.PlaceholderType) mr := miniredis.RunT(t)
return redis.New(mr.Addr()), mr.Close
go func() {
mr.Close()
close(ch)
}()
select {
case <-ch:
case <-time.After(time.Second):
}
}, nil
} }

View File

@@ -33,13 +33,11 @@ func init() {
func TestCachedConn_GetCache(t *testing.T) { func TestCachedConn_GetCache(t *testing.T) {
resetStats() resetStats()
r, clean, err := redistest.CreateRedis() r := redistest.CreateRedis(t)
assert.Nil(t, err)
defer clean()
c := NewNodeConn(dummySqlConn{}, r, cache.WithExpiry(time.Second*10)) c := NewNodeConn(dummySqlConn{}, r, cache.WithExpiry(time.Second*10))
var value string var value string
err = c.GetCache("any", &value) err := c.GetCache("any", &value)
assert.Equal(t, ErrNotFound, err) assert.Equal(t, ErrNotFound, err)
r.Set("any", `"value"`) r.Set("any", `"value"`)
err = c.GetCache("any", &value) err = c.GetCache("any", &value)
@@ -49,15 +47,13 @@ func TestCachedConn_GetCache(t *testing.T) {
func TestStat(t *testing.T) { func TestStat(t *testing.T) {
resetStats() resetStats()
r, clean, err := redistest.CreateRedis() r := redistest.CreateRedis(t)
assert.Nil(t, err)
defer clean()
c := NewNodeConn(dummySqlConn{}, r, cache.WithExpiry(time.Second*10)) c := NewNodeConn(dummySqlConn{}, r, cache.WithExpiry(time.Second*10))
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
var str string var str string
err = c.QueryRow(&str, "name", func(conn sqlx.SqlConn, v any) error { err := c.QueryRow(&str, "name", func(conn sqlx.SqlConn, v any) error {
*v.(*string) = "zero" *v.(*string) = "zero"
return nil return nil
}) })
@@ -72,9 +68,7 @@ func TestStat(t *testing.T) {
func TestCachedConn_QueryRowIndex_NoCache(t *testing.T) { func TestCachedConn_QueryRowIndex_NoCache(t *testing.T) {
resetStats() resetStats()
r, clean, err := redistest.CreateRedis() r := redistest.CreateRedis(t)
assert.Nil(t, err)
defer clean()
c := NewConn(dummySqlConn{}, cache.CacheConf{ c := NewConn(dummySqlConn{}, cache.CacheConf{
{ {
@@ -87,7 +81,7 @@ func TestCachedConn_QueryRowIndex_NoCache(t *testing.T) {
}, cache.WithExpiry(time.Second*10)) }, cache.WithExpiry(time.Second*10))
var str string var str string
err = c.QueryRowIndex(&str, "index", func(s any) string { err := c.QueryRowIndex(&str, "index", func(s any) string {
return fmt.Sprintf("%s/1234", s) return fmt.Sprintf("%s/1234", s)
}, func(conn sqlx.SqlConn, v any) (any, error) { }, func(conn sqlx.SqlConn, v any) (any, error) {
*v.(*string) = "zero" *v.(*string) = "zero"
@@ -121,16 +115,14 @@ func TestCachedConn_QueryRowIndex_NoCache(t *testing.T) {
func TestCachedConn_QueryRowIndex_HasCache(t *testing.T) { func TestCachedConn_QueryRowIndex_HasCache(t *testing.T) {
resetStats() resetStats()
r, clean, err := redistest.CreateRedis() r := redistest.CreateRedis(t)
assert.Nil(t, err)
defer clean()
c := NewNodeConn(dummySqlConn{}, r, cache.WithExpiry(time.Second*10), c := NewNodeConn(dummySqlConn{}, r, cache.WithExpiry(time.Second*10),
cache.WithNotFoundExpiry(time.Second)) cache.WithNotFoundExpiry(time.Second))
var str string var str string
r.Set("index", `"primary"`) r.Set("index", `"primary"`)
err = c.QueryRowIndex(&str, "index", func(s any) string { err := c.QueryRowIndex(&str, "index", func(s any) string {
return fmt.Sprintf("%s/1234", s) return fmt.Sprintf("%s/1234", s)
}, func(conn sqlx.SqlConn, v any) (any, error) { }, func(conn sqlx.SqlConn, v any) (any, error) {
assert.Fail(t, "should not go here") assert.Fail(t, "should not go here")
@@ -211,16 +203,14 @@ func TestCachedConn_QueryRowIndex_HasCache_IntPrimary(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
resetStats() resetStats()
r, clean, err := redistest.CreateRedis() r := redistest.CreateRedis(t)
assert.Nil(t, err)
defer clean()
c := NewNodeConn(dummySqlConn{}, r, cache.WithExpiry(time.Second*10), c := NewNodeConn(dummySqlConn{}, r, cache.WithExpiry(time.Second*10),
cache.WithNotFoundExpiry(time.Second)) cache.WithNotFoundExpiry(time.Second))
var str string var str string
r.Set("index", test.primaryCache) r.Set("index", test.primaryCache)
err = c.QueryRowIndex(&str, "index", func(s any) string { err := c.QueryRowIndex(&str, "index", func(s any) string {
return fmt.Sprintf("%v/1234", s) return fmt.Sprintf("%v/1234", s)
}, func(conn sqlx.SqlConn, v any) (any, error) { }, func(conn sqlx.SqlConn, v any) (any, error) {
assert.Fail(t, "should not go here") assert.Fail(t, "should not go here")
@@ -251,16 +241,14 @@ func TestCachedConn_QueryRowIndex_HasWrongCache(t *testing.T) {
for k, v := range caches { for k, v := range caches {
t.Run(k+"/"+v, func(t *testing.T) { t.Run(k+"/"+v, func(t *testing.T) {
resetStats() resetStats()
r, clean, err := redistest.CreateRedis() r := redistest.CreateRedis(t)
assert.Nil(t, err)
defer clean()
c := NewNodeConn(dummySqlConn{}, r, cache.WithExpiry(time.Second*10), c := NewNodeConn(dummySqlConn{}, r, cache.WithExpiry(time.Second*10),
cache.WithNotFoundExpiry(time.Second)) cache.WithNotFoundExpiry(time.Second))
var str string var str string
r.Set(k, v) r.Set(k, v)
err = c.QueryRowIndex(&str, "index", func(s any) string { err := c.QueryRowIndex(&str, "index", func(s any) string {
return fmt.Sprintf("%s/1234", s) return fmt.Sprintf("%s/1234", s)
}, func(conn sqlx.SqlConn, v any) (any, error) { }, func(conn sqlx.SqlConn, v any) (any, error) {
*v.(*string) = "xin" *v.(*string) = "xin"
@@ -306,15 +294,13 @@ func TestStatCacheFails(t *testing.T) {
func TestStatDbFails(t *testing.T) { func TestStatDbFails(t *testing.T) {
resetStats() resetStats()
r, clean, err := redistest.CreateRedis() r := redistest.CreateRedis(t)
assert.Nil(t, err)
defer clean()
c := NewNodeConn(dummySqlConn{}, r, cache.WithExpiry(time.Second*10)) c := NewNodeConn(dummySqlConn{}, r, cache.WithExpiry(time.Second*10))
for i := 0; i < 20; i++ { for i := 0; i < 20; i++ {
var str string var str string
err = c.QueryRow(&str, "name", func(conn sqlx.SqlConn, v any) error { err := c.QueryRow(&str, "name", func(conn sqlx.SqlConn, v any) error {
return errors.New("db failed") return errors.New("db failed")
}) })
assert.NotNil(t, err) assert.NotNil(t, err)
@@ -327,9 +313,7 @@ func TestStatDbFails(t *testing.T) {
func TestStatFromMemory(t *testing.T) { func TestStatFromMemory(t *testing.T) {
resetStats() resetStats()
r, clean, err := redistest.CreateRedis() r := redistest.CreateRedis(t)
assert.Nil(t, err)
defer clean()
c := NewNodeConn(dummySqlConn{}, r, cache.WithExpiry(time.Second*10)) c := NewNodeConn(dummySqlConn{}, r, cache.WithExpiry(time.Second*10))
@@ -385,9 +369,7 @@ func TestStatFromMemory(t *testing.T) {
} }
func TestCachedConnQueryRow(t *testing.T) { func TestCachedConnQueryRow(t *testing.T) {
r, clean, err := redistest.CreateRedis() r := redistest.CreateRedis(t)
assert.Nil(t, err)
defer clean()
const ( const (
key = "user" key = "user"
@@ -397,7 +379,7 @@ func TestCachedConnQueryRow(t *testing.T) {
var user string var user string
var ran bool var ran bool
c := NewNodeConn(&conn, r, cache.WithExpiry(time.Second*30)) c := NewNodeConn(&conn, r, cache.WithExpiry(time.Second*30))
err = c.QueryRow(&user, key, func(conn sqlx.SqlConn, v any) error { err := c.QueryRow(&user, key, func(conn sqlx.SqlConn, v any) error {
ran = true ran = true
user = value user = value
return nil return nil
@@ -413,9 +395,7 @@ func TestCachedConnQueryRow(t *testing.T) {
} }
func TestCachedConnQueryRowFromCache(t *testing.T) { func TestCachedConnQueryRowFromCache(t *testing.T) {
r, clean, err := redistest.CreateRedis() r := redistest.CreateRedis(t)
assert.Nil(t, err)
defer clean()
const ( const (
key = "user" key = "user"
@@ -426,7 +406,7 @@ func TestCachedConnQueryRowFromCache(t *testing.T) {
var ran bool var ran bool
c := NewNodeConn(&conn, r, cache.WithExpiry(time.Second*30)) c := NewNodeConn(&conn, r, cache.WithExpiry(time.Second*30))
assert.Nil(t, c.SetCache(key, value)) assert.Nil(t, c.SetCache(key, value))
err = c.QueryRow(&user, key, func(conn sqlx.SqlConn, v any) error { err := c.QueryRow(&user, key, func(conn sqlx.SqlConn, v any) error {
ran = true ran = true
user = value user = value
return nil return nil
@@ -442,9 +422,7 @@ func TestCachedConnQueryRowFromCache(t *testing.T) {
} }
func TestQueryRowNotFound(t *testing.T) { func TestQueryRowNotFound(t *testing.T) {
r, clean, err := redistest.CreateRedis() r := redistest.CreateRedis(t)
assert.Nil(t, err)
defer clean()
const key = "user" const key = "user"
var conn trackedConn var conn trackedConn
@@ -452,7 +430,7 @@ func TestQueryRowNotFound(t *testing.T) {
var ran int var ran int
c := NewNodeConn(&conn, r, cache.WithExpiry(time.Second*30)) c := NewNodeConn(&conn, r, cache.WithExpiry(time.Second*30))
for i := 0; i < 20; i++ { for i := 0; i < 20; i++ {
err = c.QueryRow(&user, key, func(conn sqlx.SqlConn, v any) error { err := c.QueryRow(&user, key, func(conn sqlx.SqlConn, v any) error {
ran++ ran++
return sql.ErrNoRows return sql.ErrNoRows
}) })
@@ -462,13 +440,11 @@ func TestQueryRowNotFound(t *testing.T) {
} }
func TestCachedConnExec(t *testing.T) { func TestCachedConnExec(t *testing.T) {
r, clean, err := redistest.CreateRedis() r := redistest.CreateRedis(t)
assert.Nil(t, err)
defer clean()
var conn trackedConn var conn trackedConn
c := NewNodeConn(&conn, r, cache.WithExpiry(time.Second*10)) c := NewNodeConn(&conn, r, cache.WithExpiry(time.Second*10))
_, err = c.ExecNoCache("delete from user_table where id='kevin'") _, err := c.ExecNoCache("delete from user_table where id='kevin'")
assert.Nil(t, err) assert.Nil(t, err)
assert.True(t, conn.execValue) assert.True(t, conn.execValue)
} }
@@ -514,26 +490,22 @@ func TestCachedConnExecDropCacheFailed(t *testing.T) {
} }
func TestCachedConnQueryRows(t *testing.T) { func TestCachedConnQueryRows(t *testing.T) {
r, clean, err := redistest.CreateRedis() r := redistest.CreateRedis(t)
assert.Nil(t, err)
defer clean()
var conn trackedConn var conn trackedConn
c := NewNodeConn(&conn, r, cache.WithExpiry(time.Second*10)) c := NewNodeConn(&conn, r, cache.WithExpiry(time.Second*10))
var users []string var users []string
err = c.QueryRowsNoCache(&users, "select user from user_table where id='kevin'") err := c.QueryRowsNoCache(&users, "select user from user_table where id='kevin'")
assert.Nil(t, err) assert.Nil(t, err)
assert.True(t, conn.queryRowsValue) assert.True(t, conn.queryRowsValue)
} }
func TestCachedConnTransact(t *testing.T) { func TestCachedConnTransact(t *testing.T) {
r, clean, err := redistest.CreateRedis() r := redistest.CreateRedis(t)
assert.Nil(t, err)
defer clean()
var conn trackedConn var conn trackedConn
c := NewNodeConn(&conn, r, cache.WithExpiry(time.Second*10)) c := NewNodeConn(&conn, r, cache.WithExpiry(time.Second*10))
err = c.Transact(func(session sqlx.Session) error { err := c.Transact(func(session sqlx.Session) error {
return nil return nil
}) })
assert.Nil(t, err) assert.Nil(t, err)
@@ -541,9 +513,7 @@ func TestCachedConnTransact(t *testing.T) {
} }
func TestQueryRowNoCache(t *testing.T) { func TestQueryRowNoCache(t *testing.T) {
r, clean, err := redistest.CreateRedis() r := redistest.CreateRedis(t)
assert.Nil(t, err)
defer clean()
const ( const (
key = "user" key = "user"
@@ -557,20 +527,18 @@ func TestQueryRowNoCache(t *testing.T) {
return nil return nil
}} }}
c := NewNodeConn(&conn, r, cache.WithExpiry(time.Second*30)) c := NewNodeConn(&conn, r, cache.WithExpiry(time.Second*30))
err = c.QueryRowNoCache(&user, key) err := c.QueryRowNoCache(&user, key)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, value, user) assert.Equal(t, value, user)
assert.True(t, ran) assert.True(t, ran)
} }
func TestNewConnWithCache(t *testing.T) { func TestNewConnWithCache(t *testing.T) {
r, clean, err := redistest.CreateRedis() r := redistest.CreateRedis(t)
assert.Nil(t, err)
defer clean()
var conn trackedConn var conn trackedConn
c := NewConnWithCache(&conn, cache.NewNode(r, singleFlights, stats, sql.ErrNoRows)) c := NewConnWithCache(&conn, cache.NewNode(r, singleFlights, stats, sql.ErrNoRows))
_, err = c.ExecNoCache("delete from user_table where id='kevin'") _, err := c.ExecNoCache("delete from user_table where id='kevin'")
assert.Nil(t, err) assert.Nil(t, err)
assert.True(t, conn.execValue) assert.True(t, conn.execValue)
} }

View File

@@ -34,9 +34,23 @@ func getTaggedFieldValueMap(v reflect.Value) (map[string]any, error) {
result := make(map[string]any, size) result := make(map[string]any, size)
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
key := parseTagName(rt.Field(i)) field := rt.Field(i)
if field.Anonymous && mapping.Deref(field.Type).Kind() == reflect.Struct {
inner, err := getTaggedFieldValueMap(reflect.Indirect(v).Field(i))
if err != nil {
return nil, err
}
for key, val := range inner {
result[key] = val
}
continue
}
key := parseTagName(field)
if len(key) == 0 { if len(key) == 0 {
return nil, nil continue
} }
valueField := reflect.Indirect(v).Field(i) valueField := reflect.Indirect(v).Field(i)
@@ -114,7 +128,7 @@ func parseTagName(field reflect.StructField) string {
} }
options := strings.Split(key, ",") options := strings.Split(key, ",")
return options[0] return strings.TrimSpace(options[0])
} }
func unmarshalRow(v any, scanner rowsScanner, strict bool) error { func unmarshalRow(v any, scanner rowsScanner, strict bool) error {

View File

@@ -1041,6 +1041,127 @@ func TestUnmarshalRowError(t *testing.T) {
} }
} }
func TestAnonymousStructPr(t *testing.T) {
type Score struct {
Discipline string `db:"discipline"`
Score uint `db:"score"`
}
type ClassType struct {
Grade sql.NullString `db:"grade"`
ClassName *string `db:"class_name"`
}
type Class struct {
*ClassType
Score
}
expect := []*struct {
Name string
Age int64
Grade sql.NullString
Discipline string
Score uint
ClassName string
}{
{
Name: "first",
Age: 2,
Grade: sql.NullString{
String: "",
Valid: false,
},
ClassName: "experimental class",
Discipline: "math",
Score: 100,
},
{
Name: "second",
Age: 3,
Grade: sql.NullString{
String: "grade one",
Valid: true,
},
ClassName: "class three grade two",
Discipline: "chinese",
Score: 99,
},
}
var value []*struct {
Age int64 `db:"age"`
Class
Name string `db:"name"`
}
runOrmTest(t, func(db *sql.DB, mock sqlmock.Sqlmock) {
rs := sqlmock.NewRows([]string{
"name",
"age",
"grade",
"discipline",
"class_name",
"score",
}).
AddRow("first", 2, nil, "math", "experimental class", 100).
AddRow("second", 3, "grade one", "chinese", "class three grade two", 99)
mock.ExpectQuery("select (.+) from users where user=?").
WithArgs("anyone").WillReturnRows(rs)
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
return unmarshalRows(&value, rows, true)
}, "select name, age,grade,discipline,class_name,score from users where user=?",
"anyone"))
for i, each := range expect {
assert.Equal(t, each.Name, value[i].Name)
assert.Equal(t, each.Age, value[i].Age)
assert.Equal(t, each.ClassName, *value[i].Class.ClassName)
assert.Equal(t, each.Discipline, value[i].Score.Discipline)
assert.Equal(t, each.Score, value[i].Score.Score)
assert.Equal(t, each.Grade, value[i].Class.Grade)
}
})
}
func TestAnonymousStructPrError(t *testing.T) {
type Score struct {
Discipline string `db:"discipline"`
score uint `db:"score"`
}
type ClassType struct {
Grade sql.NullString `db:"grade"`
ClassName *string `db:"class_name"`
}
type Class struct {
*ClassType
Score
}
var value []*struct {
Age int64 `db:"age"`
Class
Name string `db:"name"`
}
runOrmTest(t, func(db *sql.DB, mock sqlmock.Sqlmock) {
rs := sqlmock.NewRows([]string{
"name",
"age",
"grade",
"discipline",
"class_name",
"score",
}).
AddRow("first", 2, nil, "math", "experimental class", 100).
AddRow("second", 3, "grade one", "chinese", "class three grade two", 99)
mock.ExpectQuery("select (.+) from users where user=?").
WithArgs("anyone").WillReturnRows(rs)
assert.Error(t, query(context.Background(), db, func(rows *sql.Rows) error {
return unmarshalRows(&value, rows, true)
}, "select name, age,grade,discipline,class_name,score from users where user=?",
"anyone"))
if len(value) > 0 {
assert.Equal(t, value[0].score, 0)
}
})
}
func runOrmTest(t *testing.T, fn func(db *sql.DB, mock sqlmock.Sqlmock)) { func runOrmTest(t *testing.T, fn func(db *sql.DB, mock sqlmock.Sqlmock)) {
logx.Disable() logx.Disable()

View File

@@ -8,6 +8,7 @@ import (
"github.com/DATA-DOG/go-sqlmock" "github.com/DATA-DOG/go-sqlmock"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/trace/tracetest"
) )
const mockedDatasource = "sqlmock" const mockedDatasource = "sqlmock"
@@ -17,6 +18,7 @@ func init() {
} }
func TestSqlConn(t *testing.T) { func TestSqlConn(t *testing.T) {
me := tracetest.NewInMemoryExporter(t)
mock, err := buildConn() mock, err := buildConn()
assert.Nil(t, err) assert.Nil(t, err)
mock.ExpectExec("any") mock.ExpectExec("any")
@@ -49,6 +51,7 @@ func TestSqlConn(t *testing.T) {
assert.NotNil(t, badConn.Transact(func(session Session) error { assert.NotNil(t, badConn.Transact(func(session Session) error {
return nil return nil
})) }))
assert.Equal(t, 14, len(me.GetSpans()))
} }
func buildConn() (mock sqlmock.Sqlmock, err error) { func buildConn() (mock sqlmock.Sqlmock, err error) {

View File

@@ -159,7 +159,7 @@ func transactOnConn(ctx context.Context, conn *sql.DB, b beginnable,
if e := tx.Rollback(); e != nil { if e := tx.Rollback(); e != nil {
err = fmt.Errorf("recover from %#v, rollback failed: %w", p, e) err = fmt.Errorf("recover from %#v, rollback failed: %w", p, e)
} else { } else {
err = fmt.Errorf("recoveer from %#v", p) err = fmt.Errorf("recover from %#v", p)
} }
} else if err != nil { } else if err != nil {
if e := tx.Rollback(); e != nil { if e := tx.Rollback(); e != nil {

View File

@@ -1,6 +1,3 @@
//go:build go1.18
// +build go1.18
package stringx package stringx
import ( import (

View File

@@ -0,0 +1,20 @@
package tracetest
import (
"testing"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/sdk/trace"
"go.opentelemetry.io/otel/sdk/trace/tracetest"
)
// NewInMemoryExporter returns a new InMemoryExporter
// and sets it as the global for tests.
func NewInMemoryExporter(t *testing.T) *tracetest.InMemoryExporter {
me := tracetest.NewInMemoryExporter()
t.Cleanup(func() {
me.Reset()
})
otel.SetTracerProvider(trace.NewTracerProvider(trace.WithSyncer(me)))
return me
}

View File

@@ -15,8 +15,10 @@ func TestCompareVersions(t *testing.T) {
out bool out bool
}{ }{
{"1", "1.0.1", ">", false}, {"1", "1.0.1", ">", false},
{"1.0.1", "1.0", "<", false},
{"1", "0.9.9", ">", true}, {"1", "0.9.9", ">", true},
{"1", "1.0-1", "<", true}, {"1", "1.0-1", "<", true},
{"1", "1.0-1", "!", false},
{"1.0.1", "1-0.1", "<", false}, {"1.0.1", "1-0.1", "<", false},
{"1.0.1", "1.0.1", "==", true}, {"1.0.1", "1.0.1", "==", true},
{"1.0.1", "1.0.2", "==", false}, {"1.0.1", "1.0.2", "==", false},
@@ -37,3 +39,21 @@ func TestCompareVersions(t *testing.T) {
}) })
} }
} }
func TestStrsToInts(t *testing.T) {
testCases := []struct {
input []string
expected []int64
}{
{[]string{}, nil},
{[]string{"1", "2", "3"}, []int64{1, 2, 3}},
}
for _, tc := range testCases {
tc := tc
t.Run("", func(t *testing.T) {
actual := strsToInts(tc.input)
assert.Equal(t, tc.expected, actual)
})
}
}

View File

@@ -0,0 +1,7 @@
package validation
// Validator represents a validator.
type Validator interface {
// Validate validates the value.
Validate() error
}

View File

@@ -1,8 +1,6 @@
package gateway package gateway
import ( import (
"time"
"github.com/zeromicro/go-zero/rest" "github.com/zeromicro/go-zero/rest"
"github.com/zeromicro/go-zero/zrpc" "github.com/zeromicro/go-zero/zrpc"
) )
@@ -12,7 +10,6 @@ type (
GatewayConf struct { GatewayConf struct {
rest.RestConf rest.RestConf
Upstreams []Upstream Upstreams []Upstream
Timeout time.Duration `json:",default=5s"`
} }
// RouteMapping is a mapping between a gateway route and an upstream rpc method. // RouteMapping is a mapping between a gateway route and an upstream rpc method.

View File

@@ -37,52 +37,51 @@ func GetMethods(source grpcurl.DescriptorSource) ([]Method, error) {
for _, method := range svcMethods { for _, method := range svcMethods {
rpcPath := fmt.Sprintf("%s/%s", svc, method.GetName()) rpcPath := fmt.Sprintf("%s/%s", svc, method.GetName())
ext := proto.GetExtension(method.GetMethodOptions(), annotations.E_Http) ext := proto.GetExtension(method.GetMethodOptions(), annotations.E_Http)
if ext == nil { switch rule := ext.(type) {
methods = append(methods, Method{ case *annotations.HttpRule:
RpcPath: rpcPath, if rule == nil {
}) methods = append(methods, Method{
continue RpcPath: rpcPath,
} })
continue
}
httpExt, ok := ext.(*annotations.HttpRule) switch httpRule := rule.GetPattern().(type) {
if !ok { case *annotations.HttpRule_Get:
methods = append(methods, Method{ methods = append(methods, Method{
RpcPath: rpcPath, HttpMethod: http.MethodGet,
}) HttpPath: adjustHttpPath(httpRule.Get),
continue RpcPath: rpcPath,
} })
case *annotations.HttpRule_Post:
switch rule := httpExt.GetPattern().(type) { methods = append(methods, Method{
case *annotations.HttpRule_Get: HttpMethod: http.MethodPost,
methods = append(methods, Method{ HttpPath: adjustHttpPath(httpRule.Post),
HttpMethod: http.MethodGet, RpcPath: rpcPath,
HttpPath: adjustHttpPath(rule.Get), })
RpcPath: rpcPath, case *annotations.HttpRule_Put:
}) methods = append(methods, Method{
case *annotations.HttpRule_Post: HttpMethod: http.MethodPut,
methods = append(methods, Method{ HttpPath: adjustHttpPath(httpRule.Put),
HttpMethod: http.MethodPost, RpcPath: rpcPath,
HttpPath: adjustHttpPath(rule.Post), })
RpcPath: rpcPath, case *annotations.HttpRule_Delete:
}) methods = append(methods, Method{
case *annotations.HttpRule_Put: HttpMethod: http.MethodDelete,
methods = append(methods, Method{ HttpPath: adjustHttpPath(httpRule.Delete),
HttpMethod: http.MethodPut, RpcPath: rpcPath,
HttpPath: adjustHttpPath(rule.Put), })
RpcPath: rpcPath, case *annotations.HttpRule_Patch:
}) methods = append(methods, Method{
case *annotations.HttpRule_Delete: HttpMethod: http.MethodPatch,
methods = append(methods, Method{ HttpPath: adjustHttpPath(httpRule.Patch),
HttpMethod: http.MethodDelete, RpcPath: rpcPath,
HttpPath: adjustHttpPath(rule.Delete), })
RpcPath: rpcPath, default:
}) methods = append(methods, Method{
case *annotations.HttpRule_Patch: RpcPath: rpcPath,
methods = append(methods, Method{ })
HttpMethod: http.MethodPatch, }
HttpPath: adjustHttpPath(rule.Patch),
RpcPath: rpcPath,
})
default: default:
methods = append(methods, Method{ methods = append(methods, Method{
RpcPath: rpcPath, RpcPath: rpcPath,

View File

@@ -2,11 +2,13 @@ package internal
import ( import (
"encoding/base64" "encoding/base64"
"errors"
"net/http" "net/http"
"os" "os"
"testing" "testing"
"github.com/fullstorydev/grpcurl" "github.com/fullstorydev/grpcurl"
"github.com/jhump/protoreflect/desc"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/hash" "github.com/zeromicro/go-zero/core/hash"
) )
@@ -75,3 +77,50 @@ func TestGetMethodsWithAnnotations(t *testing.T) {
}, },
}, methods) }, methods)
} }
func TestGetMethodsBadCases(t *testing.T) {
t.Run("no services", func(t *testing.T) {
source := &mockDescriptorSource{
servicesErr: errors.New("no services"),
}
_, err := GetMethods(source)
assert.NotNil(t, err)
})
t.Run("no symbol in services", func(t *testing.T) {
source := &mockDescriptorSource{
services: []string{"hello.Hello"},
symbolErr: errors.New("no symbol"),
}
_, err := GetMethods(source)
assert.NotNil(t, err)
})
t.Run("no symbol in services", func(t *testing.T) {
source := &mockDescriptorSource{
services: []string{"hello.Hello"},
symbolErr: errors.New("no symbol"),
}
_, err := GetMethods(source)
assert.NotNil(t, err)
})
}
type mockDescriptorSource struct {
symbolDesc desc.Descriptor
symbolErr error
services []string
servicesErr error
}
func (m *mockDescriptorSource) AllExtensionsForType(_ string) ([]*desc.FieldDescriptor, error) {
return nil, nil
}
func (m *mockDescriptorSource) FindSymbol(_ string) (desc.Descriptor, error) {
return m.symbolDesc, m.symbolErr
}
func (m *mockDescriptorSource) ListServices() ([]string, error) {
return m.services, m.servicesErr
}

View File

@@ -5,7 +5,6 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"strings" "strings"
"time"
"github.com/fullstorydev/grpcurl" "github.com/fullstorydev/grpcurl"
"github.com/golang/protobuf/jsonpb" "github.com/golang/protobuf/jsonpb"
@@ -17,7 +16,6 @@ import (
"github.com/zeromicro/go-zero/rest/httpx" "github.com/zeromicro/go-zero/rest/httpx"
"github.com/zeromicro/go-zero/zrpc" "github.com/zeromicro/go-zero/zrpc"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/reflection/grpc_reflection_v1alpha"
) )
type ( type (
@@ -25,8 +23,8 @@ type (
Server struct { Server struct {
*rest.Server *rest.Server
upstreams []Upstream upstreams []Upstream
timeout time.Duration
processHeader func(http.Header) []string processHeader func(http.Header) []string
dialer func(conf zrpc.RpcClientConf) zrpc.Client
} }
// Option defines the method to customize Server. // Option defines the method to customize Server.
@@ -36,9 +34,8 @@ type (
// MustNewServer creates a new gateway server. // MustNewServer creates a new gateway server.
func MustNewServer(c GatewayConf, opts ...Option) *Server { func MustNewServer(c GatewayConf, opts ...Option) *Server {
svr := &Server{ svr := &Server{
Server: rest.MustNewServer(c.RestConf),
upstreams: c.Upstreams, upstreams: c.Upstreams,
timeout: c.Timeout, Server: rest.MustNewServer(c.RestConf),
} }
for _, opt := range opts { for _, opt := range opts {
opt(svr) opt(svr)
@@ -68,7 +65,13 @@ func (s *Server) build() error {
source <- up source <- up
} }
}, func(up Upstream, writer mr.Writer[rest.Route], cancel func(error)) { }, func(up Upstream, writer mr.Writer[rest.Route], cancel func(error)) {
cli := zrpc.MustNewClient(up.Grpc) var cli zrpc.Client
if s.dialer != nil {
cli = s.dialer(up.Grpc)
} else {
cli = zrpc.MustNewClient(up.Grpc)
}
source, err := s.createDescriptorSource(cli, up) source, err := s.createDescriptorSource(cli, up)
if err != nil { if err != nil {
cancel(fmt.Errorf("%s: %w", up.Name, err)) cancel(fmt.Errorf("%s: %w", up.Name, err))
@@ -124,13 +127,9 @@ func (s *Server) buildHandler(source grpcurl.DescriptorSource, resolver jsonpb.A
return return
} }
timeout := internal.GetTimeout(r.Header, s.timeout)
ctx, can := context.WithTimeout(r.Context(), timeout)
defer can()
w.Header().Set(httpx.ContentType, httpx.JsonContentType) w.Header().Set(httpx.ContentType, httpx.JsonContentType)
handler := internal.NewEventHandler(w, resolver) handler := internal.NewEventHandler(w, resolver)
if err := grpcurl.InvokeRPC(ctx, source, cli.Conn(), rpcPath, s.prepareMetadata(r.Header), if err := grpcurl.InvokeRPC(r.Context(), source, cli.Conn(), rpcPath, s.prepareMetadata(r.Header),
handler, parser.Next); err != nil { handler, parser.Next); err != nil {
httpx.ErrorCtx(r.Context(), w, err) httpx.ErrorCtx(r.Context(), w, err)
} }
@@ -152,8 +151,7 @@ func (s *Server) createDescriptorSource(cli zrpc.Client, up Upstream) (grpcurl.D
return nil, err return nil, err
} }
} else { } else {
refCli := grpc_reflection_v1alpha.NewServerReflectionClient(cli.Conn()) client := grpcreflect.NewClientAuto(context.Background(), cli.Conn())
client := grpcreflect.NewClient(context.Background(), refCli)
source = grpcurl.DescriptorSourceFromServer(context.Background(), client) source = grpcurl.DescriptorSourceFromServer(context.Background(), client)
} }
@@ -161,13 +159,13 @@ func (s *Server) createDescriptorSource(cli zrpc.Client, up Upstream) (grpcurl.D
} }
func (s *Server) ensureUpstreamNames() error { func (s *Server) ensureUpstreamNames() error {
for _, up := range s.upstreams { for i := 0; i < len(s.upstreams); i++ {
target, err := up.Grpc.BuildTarget() target, err := s.upstreams[i].Grpc.BuildTarget()
if err != nil { if err != nil {
return err return err
} }
up.Name = target s.upstreams[i].Name = target
} }
return nil return nil
@@ -189,3 +187,10 @@ func WithHeaderProcessor(processHeader func(http.Header) []string) func(*Server)
s.processHeader = processHeader s.processHeader = processHeader
} }
} }
// withDialer sets a dialer to create a gRPC client.
func withDialer(dialer func(conf zrpc.RpcClientConf) zrpc.Client) func(*Server) {
return func(s *Server) {
s.dialer = dialer
}
}

105
gateway/server_test.go Normal file
View File

@@ -0,0 +1,105 @@
package gateway
import (
"context"
"log"
"net"
"net/http"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/conf"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/internal/mock"
"github.com/zeromicro/go-zero/rest/httpc"
"github.com/zeromicro/go-zero/zrpc"
"google.golang.org/grpc"
"google.golang.org/grpc/reflection"
"google.golang.org/grpc/test/bufconn"
)
func init() {
logx.Disable()
}
func dialer() func(context.Context, string) (net.Conn, error) {
listener := bufconn.Listen(1024 * 1024)
server := grpc.NewServer()
mock.RegisterDepositServiceServer(server, &mock.DepositServer{})
reflection.Register(server)
go func() {
if err := server.Serve(listener); err != nil {
log.Fatal(err)
}
}()
return func(context.Context, string) (net.Conn, error) {
return listener.Dial()
}
}
func TestMustNewServer(t *testing.T) {
var c GatewayConf
assert.NoError(t, conf.FillDefault(&c))
// avoid popup alert on macos for asking permissions
c.DevServer.Host = "localhost"
c.Host = "localhost"
c.Port = 18881
s := MustNewServer(c, withDialer(func(conf zrpc.RpcClientConf) zrpc.Client {
return zrpc.MustNewClient(conf, zrpc.WithDialOption(grpc.WithContextDialer(dialer())))
}))
s.upstreams = []Upstream{
{
Mappings: []RouteMapping{
{
Method: "get",
Path: "/deposit/:amount",
RpcPath: "mock.DepositService/Deposit",
},
},
Grpc: zrpc.RpcClientConf{
Endpoints: []string{"foo"},
Timeout: 1000,
Middlewares: zrpc.ClientMiddlewaresConf{
Trace: true,
Duration: true,
Prometheus: true,
Breaker: true,
Timeout: true,
},
},
},
}
assert.NoError(t, s.build())
go s.Server.Start()
time.Sleep(time.Millisecond * 200)
resp, err := httpc.Do(context.Background(), http.MethodGet, "http://localhost:18881/deposit/100", nil)
assert.NoError(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode)
resp, err = httpc.Do(context.Background(), http.MethodGet, "http://localhost:18881/deposit_fail/100", nil)
assert.NoError(t, err)
assert.Equal(t, http.StatusNotFound, resp.StatusCode)
}
func TestServer_ensureUpstreamNames(t *testing.T) {
var s = Server{
upstreams: []Upstream{
{
Grpc: zrpc.RpcClientConf{
Target: "target",
},
},
},
}
assert.NoError(t, s.ensureUpstreamNames())
assert.Equal(t, "target", s.upstreams[0].Name)
}

66
go.mod
View File

@@ -4,26 +4,26 @@ go 1.18
require ( require (
github.com/DATA-DOG/go-sqlmock v1.5.0 github.com/DATA-DOG/go-sqlmock v1.5.0
github.com/alicebob/miniredis/v2 v2.30.0 github.com/alicebob/miniredis/v2 v2.30.2
github.com/fatih/color v1.14.1 github.com/fatih/color v1.15.0
github.com/felixge/fgprof v0.9.3 github.com/felixge/fgprof v0.9.3
github.com/fullstorydev/grpcurl v1.8.7 github.com/fullstorydev/grpcurl v1.8.7
github.com/go-redis/redis/v8 v8.11.5 github.com/go-redis/redis/v8 v8.11.5
github.com/go-sql-driver/mysql v1.7.0 github.com/go-sql-driver/mysql v1.7.0
github.com/golang-jwt/jwt/v4 v4.5.0 github.com/golang-jwt/jwt/v4 v4.5.0
github.com/golang/mock v1.6.0 github.com/golang/mock v1.6.0
github.com/golang/protobuf v1.5.2 github.com/golang/protobuf v1.5.3
github.com/google/uuid v1.3.0 github.com/google/uuid v1.3.0
github.com/jackc/pgx/v5 v5.3.1 github.com/jackc/pgx/v5 v5.3.1
github.com/jhump/protoreflect v1.15.0 github.com/jhump/protoreflect v1.15.1
github.com/olekukonko/tablewriter v0.0.5 github.com/olekukonko/tablewriter v0.0.5
github.com/pelletier/go-toml/v2 v2.0.7 github.com/pelletier/go-toml/v2 v2.0.7
github.com/prometheus/client_golang v1.14.0 github.com/prometheus/client_golang v1.15.0
github.com/spaolacci/murmur3 v1.1.0 github.com/spaolacci/murmur3 v1.1.0
github.com/stretchr/testify v1.8.2 github.com/stretchr/testify v1.8.2
go.etcd.io/etcd/api/v3 v3.5.7 go.etcd.io/etcd/api/v3 v3.5.8
go.etcd.io/etcd/client/v3 v3.5.7 go.etcd.io/etcd/client/v3 v3.5.8
go.mongodb.org/mongo-driver v1.11.2 go.mongodb.org/mongo-driver v1.11.4
go.opentelemetry.io/otel v1.14.0 go.opentelemetry.io/otel v1.14.0
go.opentelemetry.io/otel/exporters/jaeger v1.14.0 go.opentelemetry.io/otel/exporters/jaeger v1.14.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.14.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.14.0
@@ -31,26 +31,27 @@ require (
go.opentelemetry.io/otel/exporters/zipkin v1.14.0 go.opentelemetry.io/otel/exporters/zipkin v1.14.0
go.opentelemetry.io/otel/sdk v1.14.0 go.opentelemetry.io/otel/sdk v1.14.0
go.opentelemetry.io/otel/trace v1.14.0 go.opentelemetry.io/otel/trace v1.14.0
go.uber.org/automaxprocs v1.5.1 go.uber.org/automaxprocs v1.5.2
go.uber.org/goleak v1.2.1 go.uber.org/goleak v1.2.1
golang.org/x/sys v0.5.0 golang.org/x/net v0.9.0
golang.org/x/sys v0.7.0
golang.org/x/time v0.3.0 golang.org/x/time v0.3.0
google.golang.org/genproto v0.0.0-20230123190316-2c411cf9d197 google.golang.org/genproto v0.0.0-20230123190316-2c411cf9d197
google.golang.org/grpc v1.53.0 google.golang.org/grpc v1.54.0
google.golang.org/protobuf v1.28.2-0.20220831092852-f930b1dc76e8 google.golang.org/protobuf v1.30.0
gopkg.in/cheggaaa/pb.v1 v1.0.28 gopkg.in/cheggaaa/pb.v1 v1.0.28
gopkg.in/h2non/gock.v1 v1.1.2 gopkg.in/h2non/gock.v1 v1.1.2
gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v2 v2.4.0
k8s.io/api v0.26.2 k8s.io/api v0.26.3
k8s.io/apimachinery v0.26.2 k8s.io/apimachinery v0.27.0-alpha.3
k8s.io/client-go v0.26.2 k8s.io/client-go v0.26.3
k8s.io/utils v0.0.0-20230115233650-391b47cb4029 k8s.io/utils v0.0.0-20230209194617-a36077c30491
) )
require ( require (
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/bufbuild/protocompile v0.2.1-0.20230123224550-da57cd758c2f // indirect github.com/bufbuild/protocompile v0.4.0 // indirect
github.com/cenkalti/backoff/v4 v4.2.0 // indirect github.com/cenkalti/backoff/v4 v4.2.0 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/coreos/go-semver v0.3.1 // indirect github.com/coreos/go-semver v0.3.1 // indirect
@@ -60,9 +61,9 @@ require (
github.com/emicklei/go-restful/v3 v3.9.0 // indirect github.com/emicklei/go-restful/v3 v3.9.0 // indirect
github.com/go-logr/logr v1.2.3 // indirect github.com/go-logr/logr v1.2.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect
github.com/go-openapi/jsonreference v0.20.0 // indirect github.com/go-openapi/jsonreference v0.20.1 // indirect
github.com/go-openapi/swag v0.19.14 // indirect github.com/go-openapi/swag v0.22.3 // indirect
github.com/gogo/protobuf v1.3.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/snappy v0.0.4 // indirect github.com/golang/snappy v0.0.4 // indirect
github.com/google/gnostic v0.5.7-v3refs // indirect github.com/google/gnostic v0.5.7-v3refs // indirect
@@ -76,11 +77,11 @@ require (
github.com/josharian/intern v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.15.15 // indirect github.com/klauspost/compress v1.15.15 // indirect
github.com/mailru/easyjson v0.7.6 // indirect github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect github.com/mattn/go-isatty v0.0.17 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
@@ -89,15 +90,15 @@ require (
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/common v0.42.0 // indirect
github.com/prometheus/procfs v0.8.0 // indirect github.com/prometheus/procfs v0.9.0 // indirect
github.com/rivo/uniseg v0.2.0 // indirect github.com/rivo/uniseg v0.2.0 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.1.1 // indirect github.com/xdg-go/scram v1.1.1 // indirect
github.com/xdg-go/stringprep v1.0.3 // indirect github.com/xdg-go/stringprep v1.0.3 // indirect
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64 // indirect github.com/yuin/gopher-lua v1.1.0 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.5.7 // indirect go.etcd.io/etcd/client/pkg/v3 v3.5.8 // indirect
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0 // indirect go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0 // indirect
go.opentelemetry.io/proto/otlp v0.19.0 // indirect go.opentelemetry.io/proto/otlp v0.19.0 // indirect
@@ -105,17 +106,16 @@ require (
go.uber.org/multierr v1.9.0 // indirect go.uber.org/multierr v1.9.0 // indirect
go.uber.org/zap v1.24.0 // indirect go.uber.org/zap v1.24.0 // indirect
golang.org/x/crypto v0.6.0 // indirect golang.org/x/crypto v0.6.0 // indirect
golang.org/x/net v0.7.0 // indirect golang.org/x/oauth2 v0.5.0 // indirect
golang.org/x/oauth2 v0.4.0 // indirect
golang.org/x/sync v0.1.0 // indirect golang.org/x/sync v0.1.0 // indirect
golang.org/x/term v0.5.0 // indirect golang.org/x/term v0.7.0 // indirect
golang.org/x/text v0.7.0 // indirect golang.org/x/text v0.9.0 // indirect
google.golang.org/appengine v1.6.7 // indirect google.golang.org/appengine v1.6.7 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/klog/v2 v2.80.1 // indirect k8s.io/klog/v2 v2.90.1 // indirect
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect k8s.io/kube-openapi v0.0.0-20230307230338-69ee2d25a840 // indirect
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect sigs.k8s.io/yaml v1.3.0 // indirect
) )

227
go.sum
View File

@@ -36,29 +36,21 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk= github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk=
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
github.com/alicebob/miniredis/v2 v2.30.0 h1:uA3uhDbCxfO9+DI/DuGeAMr9qI+noVWwGPNTFuKID5M= github.com/alicebob/miniredis/v2 v2.30.2 h1:lc1UAUT9ZA7h4srlfBmBt2aorm5Yftk9nBjxz7EyY9I=
github.com/alicebob/miniredis/v2 v2.30.0/go.mod h1:84TWKZlxYkfgMucPBf5SOQBYJceZeQRFIaQgNMiCX6Q= github.com/alicebob/miniredis/v2 v2.30.2/go.mod h1:b25qWj4fCEsBeAAR2mlb0ufImGC6uH3VlUfb/HS5zKg=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bufbuild/protocompile v0.2.1-0.20230123224550-da57cd758c2f h1:IXSA5gow10s7zIOJfPOpXDtNBWCTA0715BDAhoJBXEs= github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA=
github.com/bufbuild/protocompile v0.2.1-0.20230123224550-da57cd758c2f/go.mod h1:tleDrpPTlLUVmgnEoN6qBliKWqJaZFJXqZdFjTd+ocU= github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8=
github.com/cenkalti/backoff/v4 v4.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+MN3u4= github.com/cenkalti/backoff/v4 v4.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+MN3u4=
github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
@@ -95,8 +87,8 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.m
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w= github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g= github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g=
github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw= github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
@@ -106,35 +98,23 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8=
github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA= github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng=
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
@@ -169,8 +149,9 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
@@ -186,7 +167,6 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
@@ -232,39 +212,29 @@ github.com/jhump/gopoet v0.1.0/go.mod h1:me9yfT6IJSlOL3FCfrg+L6yzUEZ+5jW6WHt4Sk+
github.com/jhump/goprotoc v0.5.0/go.mod h1:VrbvcYrQOrTi3i0Vf+m+oqQWk9l72mjkJCYo7UvLHRQ= github.com/jhump/goprotoc v0.5.0/go.mod h1:VrbvcYrQOrTi3i0Vf+m+oqQWk9l72mjkJCYo7UvLHRQ=
github.com/jhump/protoreflect v1.11.0/go.mod h1:U7aMIjN0NWq9swDP7xDdoMfRHb35uiuTd3Z9nFXJf5E= github.com/jhump/protoreflect v1.11.0/go.mod h1:U7aMIjN0NWq9swDP7xDdoMfRHb35uiuTd3Z9nFXJf5E=
github.com/jhump/protoreflect v1.12.0/go.mod h1:JytZfP5d0r8pVNLZvai7U/MCuTWITgrI4tTg7puQFKI= github.com/jhump/protoreflect v1.12.0/go.mod h1:JytZfP5d0r8pVNLZvai7U/MCuTWITgrI4tTg7puQFKI=
github.com/jhump/protoreflect v1.15.0 h1:U5T5/2LF0AZQFP9T4W5GfBjBaTruomrKobiR4E+oA/Q= github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c=
github.com/jhump/protoreflect v1.15.0/go.mod h1:qww51KYjD2hoCl/ohxw5cK2LSssFczrbO1t8Ld2TENs= github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw= github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw=
github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4= github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
@@ -273,87 +243,57 @@ github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4= github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4=
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo/v2 v2.4.0 h1:+Ig9nvqgS5OBSACXNk15PLdp0U9XPYROt9CFzVdFGIs= github.com/onsi/ginkgo/v2 v2.7.0 h1:/XxtEV3I3Eif/HobnVx9YmJgk8ENdRsuUmM+fLCFNow=
github.com/onsi/gomega v1.23.0 h1:/oxKu9c2HVap+F3PfKort2Hw5DEU+HGlW8n+tguWsys= github.com/onsi/gomega v1.26.0 h1:03cDLK28U6hWvCAns6NeydX3zIm4SF3ci69ulidS32Q=
github.com/openzipkin/zipkin-go v0.4.1 h1:kNd/ST2yLLWhaWrkgchya40TJabe8Hioj9udfPcEO5A= github.com/openzipkin/zipkin-go v0.4.1 h1:kNd/ST2yLLWhaWrkgchya40TJabe8Hioj9udfPcEO5A=
github.com/openzipkin/zipkin-go v0.4.1/go.mod h1:qY0VqDSN1pOBN94dBc6w2GJlWLiovAyg7Qt6/I9HecM= github.com/openzipkin/zipkin-go v0.4.1/go.mod h1:qY0VqDSN1pOBN94dBc6w2GJlWLiovAyg7Qt6/I9HecM=
github.com/pelletier/go-toml/v2 v2.0.7 h1:muncTPStnKRos5dpVKULv2FVd4bMOhNePj9CjgDb8Us= github.com/pelletier/go-toml/v2 v2.0.7 h1:muncTPStnKRos5dpVKULv2FVd4bMOhNePj9CjgDb8Us=
github.com/pelletier/go-toml/v2 v2.0.7/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= github.com/pelletier/go-toml/v2 v2.0.7/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.15.0 h1:5fCgGYogn0hFdhyhLbw7hEsWxufKtY9klyvdNfFlFhM=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.15.0/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw=
github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI=
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE=
github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
@@ -379,16 +319,16 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64 h1:5mLPGnFdSsevFRFc9q3yYbBkB6tsm4aCwwQV/j1JQAQ= github.com/yuin/gopher-lua v1.1.0 h1:BojcDhfyDWgU2f2TOzYK/g5p2gxMrku8oupLDqlnSqE=
github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= github.com/yuin/gopher-lua v1.1.0/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
go.etcd.io/etcd/api/v3 v3.5.7 h1:sbcmosSVesNrWOJ58ZQFitHMdncusIifYcrBfwrlJSY= go.etcd.io/etcd/api/v3 v3.5.8 h1:Zf44zJszoU7zRV0X/nStPenegNXoFDWcB/MwrJbA+L4=
go.etcd.io/etcd/api/v3 v3.5.7/go.mod h1:9qew1gCdDDLu+VwmeG+iFpL+QlpHTo7iubavdVDgCAA= go.etcd.io/etcd/api/v3 v3.5.8/go.mod h1:uyAal843mC8uUVSLWz6eHa/d971iDGnCRpmKd2Z+X8k=
go.etcd.io/etcd/client/pkg/v3 v3.5.7 h1:y3kf5Gbp4e4q7egZdn5T7W9TSHUvkClN6u+Rq9mEOmg= go.etcd.io/etcd/client/pkg/v3 v3.5.8 h1:tPp9YRn/UBFAHdhOQUII9eUs7aOK35eulpMhX4YBd+M=
go.etcd.io/etcd/client/pkg/v3 v3.5.7/go.mod h1:o0Abi1MK86iad3YrWhgUsbGx1pmTS+hrORWc2CamuhY= go.etcd.io/etcd/client/pkg/v3 v3.5.8/go.mod h1:y+CzeSmkMpWN2Jyu1npecjB9BBnABxGM4pN8cGuJeL4=
go.etcd.io/etcd/client/v3 v3.5.7 h1:u/OhpiuCgYY8awOHlhIhmGIGpxfBU/GZBUP3m/3/Iz4= go.etcd.io/etcd/client/v3 v3.5.8 h1:B6ngTKZSWWowHEoaucOKHQR/AtZKaoHLiUpWxOLG4l4=
go.etcd.io/etcd/client/v3 v3.5.7/go.mod h1:sOWmj9DZUMyAngS7QQwCyAXXAL6WhgTOPLNS/NabQgw= go.etcd.io/etcd/client/v3 v3.5.8/go.mod h1:idZYIPVkttBJBiRigkB5EM0MmEyx8jcl18zCV3F5noc=
go.mongodb.org/mongo-driver v1.11.2 h1:+1v2rDQUWNcGW7/7E0Jvdz51V38XXxJfhzbV17aNHCw= go.mongodb.org/mongo-driver v1.11.4 h1:4ayjakA013OdpGyL2K3ZqylTac/rMjrJOMZ1EHizXas=
go.mongodb.org/mongo-driver v1.11.2/go.mod h1:s7p5vEtfbeR1gYi6pnj3c3/urpbLv2T5Sfd6Rp2HBB8= go.mongodb.org/mongo-driver v1.11.4/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
@@ -417,15 +357,14 @@ go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJP
go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/automaxprocs v1.5.1 h1:e1YG66Lrk73dn4qhg8WFSvhF0JuFQF0ERIp4rpuV8Qk= go.uber.org/automaxprocs v1.5.2 h1:2LxUOGiR3O6tw8ui5sZa2LAaHnsviZdVOUZw4fvbnME=
go.uber.org/automaxprocs v1.5.1/go.mod h1:BF4eumQw0P9GtnuxxovUd06vwm1o18oMzFtK66vU6XU= go.uber.org/automaxprocs v1.5.2/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0=
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@@ -467,7 +406,6 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
@@ -475,7 +413,6 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -495,22 +432,17 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.5.0 h1:HuArIo48skDwlrvM3sEdHXElYslAMsf3KwRkkW4MC4s=
golang.org/x/oauth2 v0.4.0 h1:NF0gk8LVPg1Ml7SSbGyySuoxdsXitj7TvgvuRxIMc/M= golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I=
golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -520,18 +452,14 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -540,7 +468,6 @@ golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -553,28 +480,21 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ=
golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -583,8 +503,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -713,8 +633,8 @@ google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQ
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag=
google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -729,14 +649,13 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.28.2-0.20220831092852-f930b1dc76e8 h1:KR8+MyP7/qOlV+8Af01LtjL04bu7on42eVsxT4EyBQk= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.28.2-0.20220831092852-f930b1dc76e8/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/cheggaaa/pb.v1 v1.0.28 h1:n1tBJnnK2r7g9OW2btFH91V92STTUevLXYFb8gy9EMk= gopkg.in/cheggaaa/pb.v1 v1.0.28 h1:n1tBJnnK2r7g9OW2btFH91V92STTUevLXYFb8gy9EMk=
gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
@@ -745,13 +664,9 @@ gopkg.in/h2non/gock.v1 v1.1.2/go.mod h1:n7UGz/ckNChHiK05rDoiC4MYSunEC/lyaUm2WWaD
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
@@ -765,23 +680,23 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
k8s.io/api v0.26.2 h1:dM3cinp3PGB6asOySalOZxEG4CZ0IAdJsrYZXE/ovGQ= k8s.io/api v0.26.3 h1:emf74GIQMTik01Aum9dPP0gAypL8JTLl/lHa4V9RFSU=
k8s.io/api v0.26.2/go.mod h1:1kjMQsFE+QHPfskEcVNgL3+Hp88B80uj0QtSOlj8itU= k8s.io/api v0.26.3/go.mod h1:PXsqwPMXBSBcL1lJ9CYDKy7kIReUydukS5JiRlxC3qE=
k8s.io/apimachinery v0.26.2 h1:da1u3D5wfR5u2RpLhE/ZtZS2P7QvDgLZTi9wrNZl/tQ= k8s.io/apimachinery v0.27.0-alpha.3 h1:uujqsdFrbqF+cEbqFHrkLKp+s3XxRgphTpc6Yg84qLo=
k8s.io/apimachinery v0.26.2/go.mod h1:ats7nN1LExKHvJ9TmwootT00Yz05MuYqPXEXaVeOy5I= k8s.io/apimachinery v0.27.0-alpha.3/go.mod h1:TO4higCGNMwebVSdb1XPJdXMU4kk+nmMY/cTMVCGa6M=
k8s.io/client-go v0.26.2 h1:s1WkVujHX3kTp4Zn4yGNFK+dlDXy1bAAkIl+cFAiuYI= k8s.io/client-go v0.26.3 h1:k1UY+KXfkxV2ScEL3gilKcF7761xkYsSD6BC9szIu8s=
k8s.io/client-go v0.26.2/go.mod h1:u5EjOuSyBa09yqqyY7m3abZeovO/7D/WehVVlZ2qcqU= k8s.io/client-go v0.26.3/go.mod h1:ZPNu9lm8/dbRIPAgteN30RSXea6vrCpFvq+MateTUuQ=
k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4= k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw=
k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 h1:+70TFaan3hfJzs+7VK2o+OGxg8HsuBr/5f6tVAjDu6E= k8s.io/kube-openapi v0.0.0-20230307230338-69ee2d25a840 h1:1Q4XWtrQQh04ZweCpL7aMNYafFMoPEiST4dl5b4PmYw=
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4= k8s.io/kube-openapi v0.0.0-20230307230338-69ee2d25a840/go.mod h1:y5VtZWM9sHHc2ZodIH/6SHzXj+TPU5USoA8lcIeKEKY=
k8s.io/utils v0.0.0-20230115233650-391b47cb4029 h1:L8zDtT4jrxj+TaQYD0k8KNlr556WaVQylDXswKmX+dE= k8s.io/utils v0.0.0-20230209194617-a36077c30491 h1:r0BAOLElQnnFhE/ApUsg3iHdVYYPBjNSSOMowRZxxsY=
k8s.io/utils v0.0.0-20230115233650-391b47cb4029/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= k8s.io/utils v0.0.0-20230209194617-a36077c30491/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE=
sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E=
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=

View File

@@ -23,7 +23,7 @@
> >
> `GOPROXY=https://goproxy.cn/,direct go install github.com/zeromicro/go-zero/tools/goctl@latest` > `GOPROXY=https://goproxy.cn/,direct go install github.com/zeromicro/go-zero/tools/goctl@latest`
> >
> `goctl migrate —verbose —version v1.4.3` > `goctl migrate —verbose —version v1.5.0`
## 0. go-zero 介绍 ## 0. go-zero 介绍
@@ -119,28 +119,25 @@ GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/zeromicro
`goctl` 读作 `go control`,不要读成 `go C-T-L``goctl` 的意思是不要被代码控制,而是要去控制它。其中的 `go` 不是指 `golang`。在设计 `goctl` 之初,我就希望通过 `工具` 来解放我们的双手👈 `goctl` 读作 `go control`,不要读成 `go C-T-L``goctl` 的意思是不要被代码控制,而是要去控制它。其中的 `go` 不是指 `golang`。在设计 `goctl` 之初,我就希望通过 `工具` 来解放我们的双手👈
```shell ```shell
# Go 1.15 及之前版本 # Go
GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/zeromicro/go-zero/tools/goctl@latest
# Go 1.16 及以后版本
GOPROXY=https://goproxy.cn/,direct go install github.com/zeromicro/go-zero/tools/goctl@latest GOPROXY=https://goproxy.cn/,direct go install github.com/zeromicro/go-zero/tools/goctl@latest
# For Mac # For Mac
brew install goctl brew install goctl
# docker for amd64 architecture # docker for amd64 architecture
docker pull kevinwan/goctl docker pull kevinwan/goctl
# run goctl like # run goctl like
docker run --rm -it -v `pwd`:/app kevinwan/goctl goctl --help docker run --rm -it -v `pwd`:/app kevinwan/goctl goctl --help
# docker for arm64 (M1) architecture # docker for arm64 (M1) architecture
docker pull kevinwan/goctl:latest-arm64 docker pull kevinwan/goctl:latest-arm64
# run goctl like # run goctl like
docker run --rm -it -v `pwd`:/app kevinwan/goctl:latest-arm64 goctl --help docker run --rm -it -v `pwd`:/app kevinwan/goctl:latest-arm64 goctl --help
``` ```
确保 goctl 可执行 确保 goctl 可执行
2. 快速生成 api 服务 2. 快速生成 api 服务
```shell ```shell
@@ -301,6 +298,8 @@ go-zero 已被许多公司用于生产部署,接入场景如在线教育、电
>86. 中国移动上海产业研究院 >86. 中国移动上海产业研究院
>87. 天枢数链(浙江)科技有限公司 >87. 天枢数链(浙江)科技有限公司
>88. 北京娱人共享智能科技有限公司 >88. 北京娱人共享智能科技有限公司
>89. 北京数智方科技有限公司
>90. 元匠科技
如果贵公司也已使用 go-zero欢迎在 [登记地址](https://github.com/zeromicro/go-zero/issues/602) 登记,仅仅为了推广,不做其它用途。 如果贵公司也已使用 go-zero欢迎在 [登记地址](https://github.com/zeromicro/go-zero/issues/602) 登记,仅仅为了推广,不做其它用途。

View File

@@ -111,7 +111,7 @@ go install github.com/zeromicro/go-zero/tools/goctl@latest
``` ```
```shell ```shell
goctl migrate —verbose —version v1.4.3 goctl migrate —verbose —version v1.5.0
``` ```
## Quick Start ## Quick Start
@@ -127,28 +127,25 @@ goctl migrate —verbose —version v1.4.3
`goctl`can be read as `go control`. `goctl` means not to be controlled by code, instead, we control it. The inside `go` is not `golang`. At the very beginning, I was expecting it to help us improve productivity, and make our lives easier. `goctl`can be read as `go control`. `goctl` means not to be controlled by code, instead, we control it. The inside `go` is not `golang`. At the very beginning, I was expecting it to help us improve productivity, and make our lives easier.
```shell ```shell
# for Go 1.15 and earlier # for Go
GO111MODULE=on go get -u github.com/zeromicro/go-zero/tools/goctl@latest
# for Go 1.16 and later
go install github.com/zeromicro/go-zero/tools/goctl@latest go install github.com/zeromicro/go-zero/tools/goctl@latest
# For Mac # For Mac
brew install goctl brew install goctl
# docker for amd64 architecture # docker for amd64 architecture
docker pull kevinwan/goctl docker pull kevinwan/goctl
# run goctl like # run goctl like
docker run --rm -it -v `pwd`:/app kevinwan/goctl goctl --help docker run --rm -it -v `pwd`:/app kevinwan/goctl goctl --help
# docker for arm64 (M1) architecture # docker for arm64 (M1) architecture
docker pull kevinwan/goctl:latest-arm64 docker pull kevinwan/goctl:latest-arm64
# run goctl like # run goctl like
docker run --rm -it -v `pwd`:/app kevinwan/goctl:latest-arm64 goctl --help docker run --rm -it -v `pwd`:/app kevinwan/goctl:latest-arm64 goctl --help
``` ```
make sure goctl is executable. make sure goctl is executable.
3. create the API file, like greet.api, you can install the plugin of goctl in vs code, api syntax is supported. 3. create the API file, like greet.api, you can install the plugin of goctl in vs code, api syntax is supported.
```go ```go

View File

@@ -292,30 +292,39 @@ func (ng *engine) signatureVerifier(signature signatureSetting) (func(chain.Chai
} }
return func(chn chain.Chain) chain.Chain { return func(chn chain.Chain) chain.Chain {
if ng.unsignedCallback != nil { if ng.unsignedCallback == nil {
return chn.Append(handler.ContentSecurityHandler( return chn.Append(handler.LimitContentSecurityHandler(ng.conf.MaxBytes,
decrypters, signature.Expiry, signature.Strict, ng.unsignedCallback)) decrypters, signature.Expiry, signature.Strict))
} }
return chn.Append(handler.ContentSecurityHandler(decrypters, signature.Expiry, signature.Strict)) return chn.Append(handler.LimitContentSecurityHandler(ng.conf.MaxBytes,
decrypters, signature.Expiry, signature.Strict, ng.unsignedCallback))
}, nil }, nil
} }
func (ng *engine) start(router httpx.Router) error { func (ng *engine) start(router httpx.Router, opts ...StartOption) error {
if err := ng.bindRoutes(router); err != nil { if err := ng.bindRoutes(router); err != nil {
return err return err
} }
// make sure user defined options overwrite default options
opts = append([]StartOption{ng.withTimeout()}, opts...)
if len(ng.conf.CertFile) == 0 && len(ng.conf.KeyFile) == 0 { if len(ng.conf.CertFile) == 0 && len(ng.conf.KeyFile) == 0 {
return internal.StartHttp(ng.conf.Host, ng.conf.Port, router, ng.withTimeout()) return internal.StartHttp(ng.conf.Host, ng.conf.Port, router, opts...)
} }
return internal.StartHttps(ng.conf.Host, ng.conf.Port, ng.conf.CertFile, // make sure user defined options overwrite default options
ng.conf.KeyFile, router, func(svr *http.Server) { opts = append([]StartOption{
func(svr *http.Server) {
if ng.tlsConfig != nil { if ng.tlsConfig != nil {
svr.TLSConfig = ng.tlsConfig svr.TLSConfig = ng.tlsConfig
} }
}, ng.withTimeout()) },
}, opts...)
return internal.StartHttps(ng.conf.Host, ng.conf.Port, ng.conf.CertFile,
ng.conf.KeyFile, router, opts...)
} }
func (ng *engine) use(middleware Middleware) { func (ng *engine) use(middleware Middleware) {

View File

@@ -3,32 +3,60 @@ package rest
import ( import (
"context" "context"
"errors" "errors"
"fmt"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"os"
"sync/atomic" "sync/atomic"
"testing" "testing"
"time" "time"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/conf" "github.com/zeromicro/go-zero/core/conf"
"github.com/zeromicro/go-zero/core/fs"
"github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/logx"
) )
const (
priKey = `-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQC4TJk3onpqb2RYE3wwt23J9SHLFstHGSkUYFLe+nl1dEKHbD+/
Zt95L757J3xGTrwoTc7KCTxbrgn+stn0w52BNjj/kIE2ko4lbh/v8Fl14AyVR9ms
fKtKOnhe5FCT72mdtApr+qvzcC3q9hfXwkyQU32pv7q5UimZ205iKSBmgQIDAQAB
AoGAM5mWqGIAXj5z3MkP01/4CDxuyrrGDVD5FHBno3CDgyQa4Gmpa4B0/ywj671B
aTnwKmSmiiCN2qleuQYASixes2zY5fgTzt+7KNkl9JHsy7i606eH2eCKzsUa/s6u
WD8V3w/hGCQ9zYI18ihwyXlGHIgcRz/eeRh+nWcWVJzGOPUCQQD5nr6It/1yHb1p
C6l4fC4xXF19l4KxJjGu1xv/sOpSx0pOqBDEX3Mh//FU954392rUWDXV1/I65BPt
TLphdsu3AkEAvQJ2Qay/lffFj9FaUrvXuftJZ/Ypn0FpaSiUh3Ak3obBT6UvSZS0
bcYdCJCNHDtBOsWHnIN1x+BcWAPrdU7PhwJBAIQ0dUlH2S3VXnoCOTGc44I1Hzbj
Rc65IdsuBqA3fQN2lX5vOOIog3vgaFrOArg1jBkG1wx5IMvb/EnUN2pjVqUCQCza
KLXtCInOAlPemlCHwumfeAvznmzsWNdbieOZ+SXVVIpR6KbNYwOpv7oIk3Pfm9sW
hNffWlPUKhW42Gc+DIECQQDmk20YgBXwXWRM5DRPbhisIV088N5Z58K9DtFWkZsd
OBDT3dFcgZONtlmR1MqZO0pTh30lA4qovYj3Bx7A8i36
-----END RSA PRIVATE KEY-----`
)
func TestNewEngine(t *testing.T) { func TestNewEngine(t *testing.T) {
priKeyfile, err := fs.TempFilenameWithText(priKey)
assert.Nil(t, err)
defer os.Remove(priKeyfile)
yamls := []string{ yamls := []string{
`Name: foo `Name: foo
Port: 54321 Host: localhost
Port: 0
Middlewares: Middlewares:
Log: false Log: false
`, `,
`Name: foo `Name: foo
Port: 54321 Host: localhost
Port: 0
CpuThreshold: 500 CpuThreshold: 500
Middlewares: Middlewares:
Log: false Log: false
`, `,
`Name: foo `Name: foo
Port: 54321 Host: localhost
Port: 0
CpuThreshold: 500 CpuThreshold: 500
Verbose: true Verbose: true
`, `,
@@ -147,25 +175,55 @@ Verbose: true
Handler: func(w http.ResponseWriter, r *http.Request) {}, Handler: func(w http.ResponseWriter, r *http.Request) {},
}}, }},
}, },
{
priority: true,
jwt: jwtSetting{
enabled: true,
},
signature: signatureSetting{
enabled: true,
SignatureConf: SignatureConf{
Strict: true,
PrivateKeys: []PrivateKeyConf{
{
Fingerprint: "a",
KeyFile: priKeyfile,
},
},
},
},
routes: []Route{{
Method: http.MethodGet,
Path: "/",
Handler: func(w http.ResponseWriter, r *http.Request) {},
}},
},
} }
for _, yaml := range yamls { for _, yaml := range yamls {
yaml := yaml
for _, route := range routes { for _, route := range routes {
var cnf RestConf route := route
assert.Nil(t, conf.LoadFromYamlBytes([]byte(yaml), &cnf)) t.Run(fmt.Sprintf("%s-%v", yaml, route.routes), func(t *testing.T) {
ng := newEngine(cnf) var cnf RestConf
ng.addRoutes(route) assert.Nil(t, conf.LoadFromYamlBytes([]byte(yaml), &cnf))
ng.use(func(next http.HandlerFunc) http.HandlerFunc { ng := newEngine(cnf)
return func(w http.ResponseWriter, r *http.Request) { ng.addRoutes(route)
next.ServeHTTP(w, r) ng.use(func(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
next.ServeHTTP(w, r)
}
})
assert.NotNil(t, ng.start(mockedRouter{}, func(svr *http.Server) {
}))
timeout := time.Second * 3
if route.timeout > timeout {
timeout = route.timeout
} }
assert.Equal(t, timeout, ng.timeout)
}) })
assert.NotNil(t, ng.start(mockedRouter{}))
timeout := time.Second * 3
if route.timeout > timeout {
timeout = route.timeout
}
assert.Equal(t, timeout, ng.timeout)
} }
} }
} }
@@ -340,7 +398,8 @@ func TestEngine_withTimeout(t *testing.T) {
} }
} }
type mockedRouter struct{} type mockedRouter struct {
}
func (m mockedRouter) ServeHTTP(_ http.ResponseWriter, _ *http.Request) { func (m mockedRouter) ServeHTTP(_ http.ResponseWriter, _ *http.Request) {
} }

View File

@@ -18,6 +18,12 @@ type UnsignedCallback func(w http.ResponseWriter, r *http.Request, next http.Han
// ContentSecurityHandler returns a middleware to verify content security. // ContentSecurityHandler returns a middleware to verify content security.
func ContentSecurityHandler(decrypters map[string]codec.RsaDecrypter, tolerance time.Duration, func ContentSecurityHandler(decrypters map[string]codec.RsaDecrypter, tolerance time.Duration,
strict bool, callbacks ...UnsignedCallback) func(http.Handler) http.Handler { strict bool, callbacks ...UnsignedCallback) func(http.Handler) http.Handler {
return LimitContentSecurityHandler(maxBytes, decrypters, tolerance, strict, callbacks...)
}
// LimitContentSecurityHandler returns a middleware to verify content security.
func LimitContentSecurityHandler(limitBytes int64, decrypters map[string]codec.RsaDecrypter,
tolerance time.Duration, strict bool, callbacks ...UnsignedCallback) func(http.Handler) http.Handler {
if len(callbacks) == 0 { if len(callbacks) == 0 {
callbacks = append(callbacks, handleVerificationFailure) callbacks = append(callbacks, handleVerificationFailure)
} }
@@ -36,7 +42,7 @@ func ContentSecurityHandler(decrypters map[string]codec.RsaDecrypter, tolerance
r.Header.Get(contentSecurity)) r.Header.Get(contentSecurity))
executeCallbacks(w, r, next, strict, code, callbacks) executeCallbacks(w, r, next, strict, code, callbacks)
} else if r.ContentLength > 0 && header.Encrypted() { } else if r.ContentLength > 0 && header.Encrypted() {
CryptionHandler(header.Key)(next).ServeHTTP(w, r) LimitCryptionHandler(limitBytes, header.Key)(next).ServeHTTP(w, r)
} else { } else {
next.ServeHTTP(w, r) next.ServeHTTP(w, r)
} }

View File

@@ -379,8 +379,7 @@ func createTempFile(body []byte) (string, error) {
} }
tmpFile.Close() tmpFile.Close()
err = os.WriteFile(tmpFile.Name(), body, os.ModePerm) if err = os.WriteFile(tmpFile.Name(), body, os.ModePerm); err != nil {
if err != nil {
return "", err return "", err
} }

View File

@@ -19,6 +19,11 @@ var errContentLengthExceeded = errors.New("content length exceeded")
// CryptionHandler returns a middleware to handle cryption. // CryptionHandler returns a middleware to handle cryption.
func CryptionHandler(key []byte) func(http.Handler) http.Handler { func CryptionHandler(key []byte) func(http.Handler) http.Handler {
return LimitCryptionHandler(maxBytes, key)
}
// LimitCryptionHandler returns a middleware to handle cryption.
func LimitCryptionHandler(limitBytes int64, key []byte) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler { return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
cw := newCryptionResponseWriter(w) cw := newCryptionResponseWriter(w)
@@ -29,7 +34,7 @@ func CryptionHandler(key []byte) func(http.Handler) http.Handler {
return return
} }
if err := decryptBody(key, r); err != nil { if err := decryptBody(limitBytes, key, r); err != nil {
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
return return
} }
@@ -39,8 +44,8 @@ func CryptionHandler(key []byte) func(http.Handler) http.Handler {
} }
} }
func decryptBody(key []byte, r *http.Request) error { func decryptBody(limitBytes int64, key []byte, r *http.Request) error {
if r.ContentLength > maxBytes { if limitBytes > 0 && r.ContentLength > limitBytes {
return errContentLengthExceeded return errContentLengthExceeded
} }

View File

@@ -183,7 +183,10 @@ func (tw *timeoutWriter) writeHeaderLocked(code int) {
func (tw *timeoutWriter) WriteHeader(code int) { func (tw *timeoutWriter) WriteHeader(code int) {
tw.mu.Lock() tw.mu.Lock()
defer tw.mu.Unlock() defer tw.mu.Unlock()
tw.writeHeaderLocked(code)
if !tw.wroteHeader {
tw.writeHeaderLocked(code)
}
} }
func checkWriteHeaderCode(code int) { func checkWriteHeaderCode(code int) {

View File

@@ -10,9 +10,12 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
ztrace "github.com/zeromicro/go-zero/core/trace" ztrace "github.com/zeromicro/go-zero/core/trace"
"github.com/zeromicro/go-zero/core/trace/tracetest"
"github.com/zeromicro/go-zero/rest/chain" "github.com/zeromicro/go-zero/rest/chain"
"go.opentelemetry.io/otel" "go.opentelemetry.io/otel"
tcodes "go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/propagation"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
"go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace"
) )
@@ -54,6 +57,31 @@ func TestOtelHandler(t *testing.T) {
} }
} }
func TestTraceHandler(t *testing.T) {
me := tracetest.NewInMemoryExporter(t)
h := chain.New(TraceHandler("foo", "/")).Then(
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
ts := httptest.NewServer(h)
defer ts.Close()
client := ts.Client()
err := func(ctx context.Context) error {
req, _ := http.NewRequest("GET", ts.URL, nil)
res, err := client.Do(req)
assert.Nil(t, err)
return res.Body.Close()
}(context.Background())
assert.NoError(t, err)
assert.Equal(t, 1, len(me.GetSpans()))
span := me.GetSpans()[0].Snapshot()
assert.Equal(t, sdktrace.Status{
Code: tcodes.Unset,
}, span.Status())
assert.Equal(t, 0, len(span.Events()))
assert.Equal(t, 9, len(span.Attributes()))
}
func TestDontTracingSpan(t *testing.T) { func TestDontTracingSpan(t *testing.T) {
ztrace.StartAgent(ztrace.Config{ ztrace.StartAgent(ztrace.Config{
Name: "go-zero-test", Name: "go-zero-test",

View File

@@ -10,9 +10,12 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
ztrace "github.com/zeromicro/go-zero/core/trace" ztrace "github.com/zeromicro/go-zero/core/trace"
"github.com/zeromicro/go-zero/core/trace/tracetest"
"github.com/zeromicro/go-zero/rest/httpx" "github.com/zeromicro/go-zero/rest/httpx"
"github.com/zeromicro/go-zero/rest/internal/header" "github.com/zeromicro/go-zero/rest/internal/header"
"github.com/zeromicro/go-zero/rest/router" "github.com/zeromicro/go-zero/rest/router"
tcodes "go.opentelemetry.io/otel/codes"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
"go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace"
) )
@@ -59,6 +62,7 @@ func TestDoRequest_Moved(t *testing.T) {
} }
func TestDo(t *testing.T) { func TestDo(t *testing.T) {
me := tracetest.NewInMemoryExporter(t)
type Data struct { type Data struct {
Key string `path:"key"` Key string `path:"key"`
Value int `form:"value"` Value int `form:"value"`
@@ -86,6 +90,13 @@ func TestDo(t *testing.T) {
resp, err := Do(context.Background(), http.MethodPost, svr.URL+"/nodes/:key", data) resp, err := Do(context.Background(), http.MethodPost, svr.URL+"/nodes/:key", data)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, http.StatusOK, resp.StatusCode)
assert.Equal(t, 1, len(me.GetSpans()))
span := me.GetSpans()[0].Snapshot()
assert.Equal(t, sdktrace.Status{
Code: tcodes.Unset,
}, span.Status())
assert.Equal(t, 0, len(span.Events()))
assert.Equal(t, 7, len(span.Attributes()))
} }
func TestDo_Ptr(t *testing.T) { func TestDo_Ptr(t *testing.T) {

View File

@@ -7,6 +7,7 @@ import (
"sync/atomic" "sync/atomic"
"github.com/zeromicro/go-zero/core/mapping" "github.com/zeromicro/go-zero/core/mapping"
"github.com/zeromicro/go-zero/core/validation"
"github.com/zeromicro/go-zero/rest/internal/encoding" "github.com/zeromicro/go-zero/rest/internal/encoding"
"github.com/zeromicro/go-zero/rest/internal/header" "github.com/zeromicro/go-zero/rest/internal/header"
"github.com/zeromicro/go-zero/rest/pathvar" "github.com/zeromicro/go-zero/rest/pathvar"
@@ -51,7 +52,9 @@ func Parse(r *http.Request, v any) error {
return err return err
} }
if val := validator.Load(); val != nil { if valid, ok := v.(validation.Validator); ok {
return valid.Validate()
} else if val := validator.Load(); val != nil {
return val.(Validator).Validate(r, v) return val.(Validator).Validate(r, v)
} }

View File

@@ -354,6 +354,14 @@ func TestParseWithValidatorWithError(t *testing.T) {
assert.Error(t, Parse(r, &v)) assert.Error(t, Parse(r, &v))
} }
func TestParseWithValidatorRequest(t *testing.T) {
SetValidator(mockValidator{})
var v mockRequest
r, err := http.NewRequest(http.MethodGet, "/a?&age=18", http.NoBody)
assert.Nil(t, err)
assert.Error(t, Parse(r, &v))
}
func BenchmarkParseRaw(b *testing.B) { func BenchmarkParseRaw(b *testing.B) {
r, err := http.NewRequest(http.MethodGet, "http://hello.com/a?name=hello&age=18&percent=3.4", http.NoBody) r, err := http.NewRequest(http.MethodGet, "http://hello.com/a?name=hello&age=18&percent=3.4", http.NoBody)
if err != nil { if err != nil {
@@ -410,3 +418,15 @@ func (m mockValidator) Validate(r *http.Request, data any) error {
return nil return nil
} }
type mockRequest struct {
Name string `json:"name,optional"`
}
func (m mockRequest) Validate() error {
if m.Name != "hello" {
return errors.New("name is not hello")
}
return nil
}

View File

@@ -77,12 +77,19 @@ func checkAndSetHeaders(w http.ResponseWriter, r *http.Request, origins []string
} }
func isOriginAllowed(allows []string, origin string) bool { func isOriginAllowed(allows []string, origin string) bool {
for _, o := range allows { origin = strings.ToLower(origin)
if o == allOrigins {
for _, allow := range allows {
if allow == allOrigins {
return true return true
} }
if strings.HasSuffix(origin, o) { allow = strings.ToLower(allow)
if origin == allow {
return true
}
if strings.HasSuffix(origin, "."+allow) {
return true return true
} }
} }

View File

@@ -53,6 +53,11 @@ func TestCorsHandlerWithOrigins(t *testing.T) {
origins: []string{"http://local", "http://remote"}, origins: []string{"http://local", "http://remote"},
reqOrigin: "http://another", reqOrigin: "http://another",
}, },
{
name: "not safe origin",
origins: []string{"safe.com"},
reqOrigin: "not-safe.com",
},
} }
methods := []string{ methods := []string{

View File

@@ -778,7 +778,7 @@ func TestParseWithMissingForm(t *testing.T) {
err = httpx.Parse(r, &v) err = httpx.Parse(r, &v)
assert.NotNil(t, err) assert.NotNil(t, err)
assert.Equal(t, "field zipcode is not set", err.Error()) assert.Equal(t, `field "zipcode" is not set`, err.Error())
})) }))
assert.Nil(t, err) assert.Nil(t, err)

View File

@@ -2,7 +2,6 @@ package rest
import ( import (
"crypto/tls" "crypto/tls"
"log"
"net/http" "net/http"
"path" "path"
"time" "time"
@@ -11,6 +10,7 @@ import (
"github.com/zeromicro/go-zero/rest/chain" "github.com/zeromicro/go-zero/rest/chain"
"github.com/zeromicro/go-zero/rest/handler" "github.com/zeromicro/go-zero/rest/handler"
"github.com/zeromicro/go-zero/rest/httpx" "github.com/zeromicro/go-zero/rest/httpx"
"github.com/zeromicro/go-zero/rest/internal"
"github.com/zeromicro/go-zero/rest/internal/cors" "github.com/zeromicro/go-zero/rest/internal/cors"
"github.com/zeromicro/go-zero/rest/router" "github.com/zeromicro/go-zero/rest/router"
) )
@@ -19,6 +19,9 @@ type (
// RunOption defines the method to customize a Server. // RunOption defines the method to customize a Server.
RunOption func(*Server) RunOption func(*Server)
// StartOption defines the method to customize http server.
StartOption = internal.StartOption
// A Server is a http server. // A Server is a http server.
Server struct { Server struct {
ngin *engine ngin *engine
@@ -32,7 +35,7 @@ type (
func MustNewServer(c RestConf, opts ...RunOption) *Server { func MustNewServer(c RestConf, opts ...RunOption) *Server {
server, err := NewServer(c, opts...) server, err := NewServer(c, opts...)
if err != nil { if err != nil {
log.Fatal(err) logx.Must(err)
} }
return server return server
@@ -116,6 +119,13 @@ func (s *Server) Start() {
handleError(s.ngin.start(s.router)) handleError(s.ngin.start(s.router))
} }
// StartWithOpts starts the Server.
// Graceful shutdown is enabled by default.
// Use proc.SetTimeToForceQuit to customize the graceful shutdown period.
func (s *Server) StartWithOpts(opts ...StartOption) {
handleError(s.ngin.start(s.router, opts...))
}
// Stop stops the Server. // Stop stops the Server.
func (s *Server) Stop() { func (s *Server) Stop() {
logx.Close() logx.Close()

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