Compare commits

...

29 Commits

Author SHA1 Message Date
Kevin Wan
6f2730d5ae chore: update goctl version (#4754) 2025-04-06 19:09:02 +08:00
dependabot[bot]
0eff777b62 chore(deps): bump github.com/jackc/pgx/v5 from 5.7.2 to 5.7.4 (#4737)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-26 22:41:55 +08:00
dependabot[bot]
cafbf535f7 chore(deps): bump github.com/golang-jwt/jwt/v4 from 4.5.1 to 4.5.2 (#4734) 2025-03-26 16:28:36 +08:00
Kevin Wan
6edfce63e3 feat: add rest.WithSSE to build SSE route easier (#4729) 2025-03-22 13:38:13 +08:00
dependabot[bot]
cdb0098b18 chore(deps): bump github.com/redis/go-redis/v9 from 9.7.1 to 9.7.3 (#4722) 2025-03-21 09:51:31 +08:00
Kevin Wan
620c7f9693 chore: add more tests (#4718) 2025-03-19 23:54:04 +08:00
Meng Ye
dba444a382 feat: support redis getdel command (#4709) 2025-03-19 23:40:14 +08:00
dependabot[bot]
b24fb3ebf7 chore(deps): bump github.com/fullstorydev/grpcurl from 1.9.2 to 1.9.3 (#4701) 2025-03-12 12:05:28 +08:00
POABOB
967f0926eb fix: fix the bug of the numeric/decimal data type in pg (#4686) 2025-03-07 11:12:02 +00:00
dependabot[bot]
e68c683df9 chore(deps): bump github.com/prometheus/client_golang from 1.21.0 to 1.21.1 (#4683)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-05 11:14:23 +08:00
Kevin Wan
247985a065 chore: refactoring & add more tests (#4677) 2025-03-02 20:11:10 +08:00
anlynn
80573af0d8 feat: Add support for serialization of anonymous fields in HTTP client(httpc) (#4676)
Co-authored-by: 李安琳 <anlynn@gmail.com>
2025-03-02 19:10:50 +08:00
Kevin Wan
c0394b631a chore: fix display problems in version-check workflow (#4675) 2025-03-01 22:18:49 +08:00
Kevin Wan
68d1aba377 chore: upgrade go-zero version in goctl (#4674) 2025-03-01 21:23:23 +08:00
Kevin Wan
3315e60272 chore: performance tunning for stable runner (#4670) 2025-02-26 19:19:24 +08:00
dependabot[bot]
327ef73700 chore(deps): bump go.mongodb.org/mongo-driver from 1.17.2 to 1.17.3 (#4669) 2025-02-26 10:03:43 +08:00
dependabot[bot]
eb11521655 chore(deps): bump github.com/redis/go-redis/v9 from 9.7.0 to 9.7.1 (#4665) 2025-02-22 08:19:28 +08:00
Kevin Wan
4c37545e55 Update readme-cn.md (#4664) 2025-02-20 21:13:33 +08:00
dependabot[bot]
2f47c1fba4 chore(deps): bump github.com/prometheus/client_golang from 1.20.5 to 1.21.0 (#4663) 2025-02-20 11:14:13 +08:00
dependabot[bot]
16d54d0ace chore(deps): bump github.com/go-sql-driver/mysql from 1.8.1 to 1.9.0 in /tools/goctl (#4662)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-19 11:38:41 +08:00
dependabot[bot]
9925bcbf99 chore(deps): bump github.com/go-sql-driver/mysql from 1.8.1 to 1.9.0 (#4661)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-19 11:13:41 +08:00
dependabot[bot]
38a5ecb796 chore(deps): bump github.com/spf13/cobra from 1.8.1 to 1.9.1 in /tools/goctl (#4660)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-18 10:47:42 +08:00
Kevin Wan
af78fc7c5f chore: add more tests (#4656) 2025-02-14 23:43:34 +08:00
Kevin Wan
790302b486 fix: should not ignore slowThreshold (#4655) 2025-02-14 23:14:57 +08:00
Nanosk07
6a0672b801 fix: SlowThreshold configuration not taking effect (#4654) 2025-02-14 14:56:25 +00:00
Kevin Wan
560c61612c chore: refactor (#4652) 2025-02-14 09:41:54 +08:00
Kevin Wan
6a988dc4a9 fix: make test purpose method private (#4649) 2025-02-14 00:31:53 +08:00
Kevin Wan
15842c3c7a Create version-check.yml (#4646) 2025-02-13 19:39:22 +08:00
Rui Chen
f2914a74df fix: update version to match with the release (#4645) 2025-02-13 01:11:09 +00:00
28 changed files with 473 additions and 160 deletions

42
.github/workflows/version-check.yml vendored Normal file
View File

@@ -0,0 +1,42 @@
name: Release Version Check
on:
push:
tags:
- 'tools/goctl/v*'
workflow_dispatch:
jobs:
version-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.21'
- name: Extract tag version
id: get_version
run: |
# Extract version from tools/goctl/v* format
VERSION="${GITHUB_REF#refs/tags/tools/goctl/v}"
echo "VERSION=$VERSION" >> $GITHUB_ENV
echo "Extracted version: $VERSION"
- name: Check version in goctl source code
run: |
# Change to goctl directory
cd tools/goctl
# Check version in BuildVersion constant
VERSION_IN_CODE=$(grep -r "const BuildVersion =" . | grep -o '".*"' | tr -d '"')
echo "Version in code: $VERSION_IN_CODE"
echo "Expected version: $VERSION"
if [ "$VERSION_IN_CODE" != "$VERSION" ]; then
echo "Version mismatch: Version in code ($VERSION_IN_CODE) doesn't match tag version ($VERSION)"
exit 1
fi
echo "✅ Version check passed!"

View File

@@ -13,6 +13,15 @@ const (
// Marshal marshals the given val and returns the map that contains the fields.
// optional=another is not implemented, and it's hard to implement and not commonly used.
// support anonymous field, e.g.:
//
// type Foo struct {
// Token string `header:"token"`
// }
// type FooB struct {
// Foo
// Bar string `json:"bar"`
// }
func Marshal(val any) (map[string]map[string]any, error) {
ret := make(map[string]map[string]any)
tp := reflect.TypeOf(val)
@@ -44,6 +53,16 @@ func getTag(field reflect.StructField) (string, bool) {
return strings.TrimSpace(tag), false
}
func insertValue(collector map[string]map[string]any, tag string, key string, val any) {
if m, ok := collector[tag]; ok {
m[key] = val
} else {
collector[tag] = map[string]any{
key: val,
}
}
}
func processMember(field reflect.StructField, value reflect.Value,
collector map[string]map[string]any) error {
var key string
@@ -69,15 +88,20 @@ func processMember(field reflect.StructField, value reflect.Value,
val = fmt.Sprint(val)
}
m, ok := collector[tag]
if ok {
m[key] = val
} else {
m = map[string]any{
key: val,
if field.Anonymous {
anonCollector, err := Marshal(val)
if err != nil {
return err
}
for anonTag, anonMap := range anonCollector {
for anonKey, anonVal := range anonMap {
insertValue(collector, anonTag, anonKey, anonVal)
}
}
} else {
insertValue(collector, tag, key, val)
}
collector[tag] = m
return nil
}

View File

@@ -27,6 +27,124 @@ func TestMarshal(t *testing.T) {
assert.True(t, m[emptyTag]["Anonymous"].(bool))
}
func TestMarshal_Anonymous(t *testing.T) {
t.Run("anonymous", func(t *testing.T) {
type BaseHeader struct {
Token string `header:"token"`
}
v := struct {
Name string `json:"name"`
Address string `json:"address,options=[beijing,shanghai]"`
Age int `json:"age"`
BaseHeader
}{
Name: "kevin",
Address: "shanghai",
Age: 20,
BaseHeader: BaseHeader{
Token: "token_xxx",
},
}
m, err := Marshal(v)
assert.Nil(t, err)
assert.Equal(t, "kevin", m["json"]["name"])
assert.Equal(t, "shanghai", m["json"]["address"])
assert.Equal(t, 20, m["json"]["age"].(int))
assert.Equal(t, "token_xxx", m["header"]["token"])
v1 := struct {
Name string `json:"name"`
Address string `json:"address,options=[beijing,shanghai]"`
Age int `json:"age"`
BaseHeader
}{
Name: "kevin",
Address: "shanghai",
Age: 20,
}
m1, err1 := Marshal(v1)
assert.Nil(t, err1)
assert.Equal(t, "kevin", m1["json"]["name"])
assert.Equal(t, "shanghai", m1["json"]["address"])
assert.Equal(t, 20, m1["json"]["age"].(int))
type AnotherHeader struct {
Version string `header:"version"`
}
v2 := struct {
Name string `json:"name"`
Address string `json:"address,options=[beijing,shanghai]"`
Age int `json:"age"`
BaseHeader
AnotherHeader
}{
Name: "kevin",
Address: "shanghai",
Age: 20,
BaseHeader: BaseHeader{
Token: "token_xxx",
},
AnotherHeader: AnotherHeader{
Version: "v1.0",
},
}
m2, err2 := Marshal(v2)
assert.Nil(t, err2)
assert.Equal(t, "kevin", m2["json"]["name"])
assert.Equal(t, "shanghai", m2["json"]["address"])
assert.Equal(t, 20, m2["json"]["age"].(int))
assert.Equal(t, "token_xxx", m2["header"]["token"])
assert.Equal(t, "v1.0", m2["header"]["version"])
type PointerHeader struct {
Ref *string `header:"ref"`
}
ref := "reference"
v3 := struct {
Name string `json:"name"`
Address string `json:"address,options=[beijing,shanghai]"`
Age int `json:"age"`
PointerHeader
}{
Name: "kevin",
Address: "shanghai",
Age: 20,
PointerHeader: PointerHeader{
Ref: &ref,
},
}
m3, err3 := Marshal(v3)
assert.Nil(t, err3)
assert.Equal(t, "kevin", m3["json"]["name"])
assert.Equal(t, "shanghai", m3["json"]["address"])
assert.Equal(t, 20, m3["json"]["age"].(int))
assert.Equal(t, "reference", *m3["header"]["ref"].(*string))
})
t.Run("bad anonymous", func(t *testing.T) {
type BaseHeader struct {
Token string `json:"token,options=[a,b]"`
}
v := struct {
Name string `json:"name"`
Address string `json:"address,options=[beijing,shanghai]"`
Age int `json:"age"`
BaseHeader
}{
Name: "kevin",
Address: "shanghai",
Age: 20,
BaseHeader: BaseHeader{
Token: "c",
},
}
_, err := Marshal(v)
assert.NotNil(t, err)
})
}
func TestMarshal_Ptr(t *testing.T) {
v := &struct {
Name string `path:"name"`

View File

@@ -609,6 +609,28 @@ func (s *Redis) GetBitCtx(ctx context.Context, key string, offset int64) (int, e
return int(v), nil
}
// GetDel is the implementation of redis getdel command.
// Available since: redis version 6.2.0
func (s *Redis) GetDel(key string) (string, error) {
return s.GetDelCtx(context.Background(), key)
}
// GetDelCtx is the implementation of redis getdel command.
// Available since: redis version 6.2.0
func (s *Redis) GetDelCtx(ctx context.Context, key string) (string, error) {
conn, err := getRedis(s)
if err != nil {
return "", err
}
val, err := conn.GetDel(ctx, key).Result()
if errors.Is(err, red.Nil) {
return "", nil
}
return val, err
}
// GetSet is the implementation of redis getset command.
func (s *Redis) GetSet(key, value string) (string, error) {
return s.GetSetCtx(context.Background(), key, value)

View File

@@ -1071,6 +1071,34 @@ func TestRedis_Set(t *testing.T) {
})
}
func TestRedis_GetDel(t *testing.T) {
t.Run("get_del", func(t *testing.T) {
runOnRedis(t, func(client *Redis) {
val, err := newRedis(client.Addr).GetDel("hello")
assert.Equal(t, "", val)
assert.Nil(t, err)
err = client.Set("hello", "world")
assert.Nil(t, err)
val, err = client.Get("hello")
assert.Nil(t, err)
assert.Equal(t, "world", val)
val, err = client.GetDel("hello")
assert.Nil(t, err)
assert.Equal(t, "world", val)
val, err = client.Get("hello")
assert.Nil(t, err)
assert.Equal(t, "", val)
})
})
t.Run("get_del_with_error", func(t *testing.T) {
runOnRedisWithError(t, func(client *Redis) {
_, err := newRedis(client.Addr, badType()).GetDel("hello")
assert.Error(t, err)
})
})
}
func TestRedis_GetSet(t *testing.T) {
t.Run("set_get", func(t *testing.T) {
runOnRedis(t, func(client *Redis) {

View File

@@ -5,6 +5,7 @@ import (
"runtime"
"sync"
"sync/atomic"
"time"
)
const factor = 10
@@ -100,6 +101,6 @@ func (r *StableRunner[I, O]) Wait() {
close(r.done)
r.runner.Wait()
for atomic.LoadUint64(&r.consumedIndex) < atomic.LoadUint64(&r.writtenIndex) {
runtime.Gosched()
time.Sleep(time.Millisecond)
}
}

20
go.mod
View File

@@ -6,23 +6,23 @@ require (
github.com/DATA-DOG/go-sqlmock v1.5.2
github.com/alicebob/miniredis/v2 v2.34.0
github.com/fatih/color v1.18.0
github.com/fullstorydev/grpcurl v1.9.2
github.com/go-sql-driver/mysql v1.8.1
github.com/golang-jwt/jwt/v4 v4.5.1
github.com/fullstorydev/grpcurl v1.9.3
github.com/go-sql-driver/mysql v1.9.0
github.com/golang-jwt/jwt/v4 v4.5.2
github.com/golang/mock v1.6.0
github.com/golang/protobuf v1.5.4
github.com/google/uuid v1.6.0
github.com/jackc/pgx/v5 v5.7.2
github.com/jackc/pgx/v5 v5.7.4
github.com/jhump/protoreflect v1.17.0
github.com/olekukonko/tablewriter v0.0.5
github.com/pelletier/go-toml/v2 v2.2.2
github.com/prometheus/client_golang v1.20.5
github.com/redis/go-redis/v9 v9.7.0
github.com/prometheus/client_golang v1.21.1
github.com/redis/go-redis/v9 v9.7.3
github.com/spaolacci/murmur3 v1.1.0
github.com/stretchr/testify v1.10.0
go.etcd.io/etcd/api/v3 v3.5.15
go.etcd.io/etcd/client/v3 v3.5.15
go.mongodb.org/mongo-driver v1.17.2
go.mongodb.org/mongo-driver v1.17.3
go.opentelemetry.io/otel v1.24.0
go.opentelemetry.io/otel/exporters/jaeger v1.17.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0
@@ -80,7 +80,7 @@ require (
github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.17.9 // indirect
github.com/klauspost/compress v1.17.11 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
@@ -93,7 +93,7 @@ require (
github.com/openzipkin/zipkin-go v0.4.3 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.55.0 // indirect
github.com/prometheus/common v0.62.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/stretchr/objx v0.5.2 // indirect
@@ -110,7 +110,7 @@ require (
go.uber.org/multierr v1.9.0 // indirect
go.uber.org/zap v1.24.0 // indirect
golang.org/x/crypto v0.33.0 // indirect
golang.org/x/oauth2 v0.21.0 // indirect
golang.org/x/oauth2 v0.24.0 // indirect
golang.org/x/sync v0.11.0 // indirect
golang.org/x/term v0.29.0 // indirect
golang.org/x/text v0.22.0 // indirect

40
go.sum
View File

@@ -40,8 +40,8 @@ github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU
github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/fullstorydev/grpcurl v1.9.2 h1:ObqVQTZW7aFnhuqQoppUrvep2duMBanB0UYK2Mm8euo=
github.com/fullstorydev/grpcurl v1.9.2/go.mod h1:jLfcF55HAz6TYIJY9xFFWgsl0D7o2HlxA5Z4lUG0Tdo=
github.com/fullstorydev/grpcurl v1.9.3 h1:PC1Xi3w+JAvEE2Tg2Gf2RfVgPbf9+tbuQr1ZkyVU3jk=
github.com/fullstorydev/grpcurl v1.9.3/go.mod h1:/b4Wxe8bG6ndAjlfSUjwseQReUDUvBJiFEB7UllOlUE=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
@@ -55,15 +55,15 @@ github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU=
github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/go-sql-driver/mysql v1.9.0 h1:Y0zIbQXhQKmQgTp44Y1dp3wTXcn804QoTptLZT1vtvo=
github.com/go-sql-driver/mysql v1.9.0/go.mod h1:pDetrLJeA3oMujJuvXc8RJoasr589B6A9fwzD3QMrqw=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo=
github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI=
github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
@@ -90,8 +90,8 @@ github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsI
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.7.2 h1:mLoDLV6sonKlvjIEsV56SkWNCnuNv531l94GaIzO+XI=
github.com/jackc/pgx/v5 v5.7.2/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ=
github.com/jackc/pgx/v5 v5.7.4 h1:9wKznZrhWa2QiHL+NjTSPP6yjl3451BX3imWDnokYlg=
github.com/jackc/pgx/v5 v5.7.4/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jhump/protoreflect v1.17.0 h1:qOEr613fac2lOuTgWN4tPAtLL7fUSbuJL5X5XumQh94=
@@ -103,8 +103,8 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm
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/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
@@ -151,16 +151,16 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
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/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk=
github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E=
github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw=
github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM=
github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
@@ -203,8 +203,8 @@ go.etcd.io/etcd/client/pkg/v3 v3.5.15 h1:fo0HpWz/KlHGMCC+YejpiCmyWDEuIpnTDzpJLB5
go.etcd.io/etcd/client/pkg/v3 v3.5.15/go.mod h1:mXDI4NAOwEiszrHCb0aqfAYNCrZP4e9hRca3d1YK8EU=
go.etcd.io/etcd/client/v3 v3.5.15 h1:23M0eY4Fd/inNv1ZfU3AxrbbOdW79r9V9Rl62Nm6ip4=
go.etcd.io/etcd/client/v3 v3.5.15/go.mod h1:CLSJxrYjvLtHsrPKsy7LmZEE+DK2ktfd2bN4RhBMwlU=
go.mongodb.org/mongo-driver v1.17.2 h1:gvZyk8352qSfzyZ2UMWcpDpMSGEr1eqE4T793SqyhzM=
go.mongodb.org/mongo-driver v1.17.2/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
go.mongodb.org/mongo-driver v1.17.3 h1:TQyXhnsWfWtgAhMtOgtYHMTkZIfBTpMTsMnd9ZBeHxQ=
go.mongodb.org/mongo-driver v1.17.3/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
go.opentelemetry.io/otel/exporters/jaeger v1.17.0 h1:D7UpUy2Xc2wsi1Ras6V40q806WM07rqoCWzXu7Sqy+4=
@@ -256,8 +256,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE=
golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=

View File

@@ -301,6 +301,7 @@ go-zero 已被许多公司用于生产部署,接入场景如在线教育、电
>102. 深圳市兴海物联科技有限公司
>103. 爱芯元智半导体股份有限公司
>104. 杭州升恒科技有限公司
>105. 昆仑万维科技股份有限公司
如果贵公司也已使用 go-zero欢迎在 [登记地址](https://github.com/zeromicro/go-zero/issues/602) 登记,仅仅为了推广,不做其它用途。

View File

@@ -15,6 +15,7 @@ import (
"github.com/zeromicro/go-zero/rest/handler"
"github.com/zeromicro/go-zero/rest/httpx"
"github.com/zeromicro/go-zero/rest/internal"
"github.com/zeromicro/go-zero/rest/internal/header"
"github.com/zeromicro/go-zero/rest/internal/response"
)
@@ -54,6 +55,9 @@ func newEngine(c RestConf) *engine {
}
func (ng *engine) addRoutes(r featuredRoutes) {
if r.sse {
r.routes = buildSSERoutes(r.routes)
}
ng.routes = append(ng.routes, r)
// need to guarantee the timeout is the max of all routes
@@ -63,6 +67,20 @@ func (ng *engine) addRoutes(r featuredRoutes) {
}
}
func buildSSERoutes(routes []Route) []Route {
for i, route := range routes {
h := route.Handler
routes[i].Handler = func(w http.ResponseWriter, r *http.Request) {
w.Header().Set(header.ContentType, header.ContentTypeEventStream)
w.Header().Set(header.CacheControl, header.CacheControlNoCache)
w.Header().Set(header.Connection, header.ConnectionKeepAlive)
h(w, r)
}
}
return routes
}
func (ng *engine) appendAuthHandler(fr featuredRoutes, chn chain.Chain,
verifier func(chain.Chain) chain.Chain) chain.Chain {
if fr.jwt.enabled {

View File

@@ -105,7 +105,7 @@ func buildRequest(ctx context.Context, method, url string, data any) (*http.Requ
req.URL.RawQuery = buildFormQuery(u, val[formKey])
fillHeader(req, val[headerKey])
if hasJsonBody {
req.Header.Set(header.ContentType, header.JsonContentType)
req.Header.Set(header.ContentType, header.ContentTypeJson)
}
return req, nil

View File

@@ -45,7 +45,7 @@ func TestDoRequest_NotFound(t *testing.T) {
defer svr.Close()
req, err := http.NewRequest(http.MethodPost, svr.URL, nil)
assert.Nil(t, err)
req.Header.Set(header.ContentType, header.JsonContentType)
req.Header.Set(header.ContentType, header.ContentTypeJson)
resp, err := DoRequest(req)
assert.Nil(t, err)
assert.Equal(t, http.StatusNotFound, resp.StatusCode)

View File

@@ -18,7 +18,7 @@ func TestParse(t *testing.T) {
}
svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("foo", "bar")
w.Header().Set(header.ContentType, header.JsonContentType)
w.Header().Set(header.ContentType, header.ContentTypeJson)
w.Write([]byte(`{"name":"kevin","value":100}`))
}))
defer svr.Close()
@@ -38,7 +38,7 @@ func TestParseHeaderError(t *testing.T) {
}
svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("foo", "bar")
w.Header().Set(header.ContentType, header.JsonContentType)
w.Header().Set(header.ContentType, header.ContentTypeJson)
}))
defer svr.Close()
req, err := http.NewRequest(http.MethodGet, svr.URL, nil)
@@ -54,7 +54,7 @@ func TestParseNoBody(t *testing.T) {
}
svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("foo", "bar")
w.Header().Set(header.ContentType, header.JsonContentType)
w.Header().Set(header.ContentType, header.ContentTypeJson)
}))
defer svr.Close()
req, err := http.NewRequest(http.MethodGet, svr.URL, nil)
@@ -72,7 +72,7 @@ func TestParseWithZeroValue(t *testing.T) {
}
svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("foo", "0")
w.Header().Set(header.ContentType, header.JsonContentType)
w.Header().Set(header.ContentType, header.ContentTypeJson)
w.Write([]byte(`{"bar":0}`))
}))
defer svr.Close()
@@ -90,7 +90,7 @@ func TestParseWithNegativeContentLength(t *testing.T) {
Bar int `json:"bar"`
}
svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set(header.ContentType, header.JsonContentType)
w.Header().Set(header.ContentType, header.ContentTypeJson)
w.Write([]byte(`{"bar":0}`))
}))
defer svr.Close()
@@ -124,7 +124,7 @@ func TestParseWithNegativeContentLength(t *testing.T) {
func TestParseWithNegativeContentLengthNoBody(t *testing.T) {
var val struct{}
svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set(header.ContentType, header.JsonContentType)
w.Header().Set(header.ContentType, header.ContentTypeJson)
}))
defer svr.Close()
req, err := http.NewRequest(http.MethodGet, svr.URL, nil)
@@ -156,7 +156,7 @@ func TestParseWithNegativeContentLengthNoBody(t *testing.T) {
func TestParseJsonBody_BodyError(t *testing.T) {
var val struct{}
svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set(header.ContentType, header.JsonContentType)
w.Header().Set(header.ContentType, header.ContentTypeJson)
}))
defer svr.Close()
req, err := http.NewRequest(http.MethodGet, svr.URL, nil)

View File

@@ -44,7 +44,7 @@ func TestNamedService_DoRequestPost(t *testing.T) {
service := NewService("foo")
req, err := http.NewRequest(http.MethodPost, svr.URL, nil)
assert.Nil(t, err)
req.Header.Set(header.ContentType, header.JsonContentType)
req.Header.Set(header.ContentType, header.ContentTypeJson)
resp, err := service.DoRequest(req)
assert.Nil(t, err)
assert.Equal(t, http.StatusNotFound, resp.StatusCode)

View File

@@ -476,7 +476,7 @@ func TestParseJsonBody(t *testing.T) {
body := `{"name":"kevin", "age": 18}`
r := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(body))
r.Header.Set(ContentType, header.JsonContentType)
r.Header.Set(ContentType, header.ContentTypeJson)
if assert.NoError(t, Parse(r, &v)) {
assert.Equal(t, "kevin", v.Name)
@@ -492,7 +492,7 @@ func TestParseJsonBody(t *testing.T) {
body := `{"name":"kevin", "ag": 18}`
r := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(body))
r.Header.Set(ContentType, header.JsonContentType)
r.Header.Set(ContentType, header.ContentTypeJson)
assert.Error(t, Parse(r, &v))
})
@@ -517,7 +517,7 @@ func TestParseJsonBody(t *testing.T) {
body := `[{"name":"kevin", "age": 18}]`
r := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(body))
r.Header.Set(ContentType, header.JsonContentType)
r.Header.Set(ContentType, header.ContentTypeJson)
assert.NoError(t, Parse(r, &v))
assert.Equal(t, 1, len(v))
@@ -537,7 +537,7 @@ func TestParseJsonBody(t *testing.T) {
body := `[{"name":"apple", "age": 18}]`
r := httptest.NewRequest(http.MethodPost, "/a?product=tree", strings.NewReader(body))
r.Header.Set(ContentType, header.JsonContentType)
r.Header.Set(ContentType, header.ContentTypeJson)
assert.NoError(t, Parse(r, &v))
assert.Equal(t, 1, len(v))
@@ -555,7 +555,7 @@ func TestParseJsonBody(t *testing.T) {
body, _ := json.Marshal(v1)
t.Logf("body:%s", string(body))
r := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(string(body)))
r.Header.Set(ContentType, header.JsonContentType)
r.Header.Set(ContentType, header.ContentTypeJson)
var v2 v
err := ParseJsonBody(r, &v2)
if assert.NoError(t, err) {
@@ -609,7 +609,7 @@ func TestParseHeaders(t *testing.T) {
request.Header.Add("addrs", "addr2")
request.Header.Add("X-Forwarded-For", "10.0.10.11")
request.Header.Add("x-real-ip", "10.0.11.10")
request.Header.Add("Accept", header.JsonContentType)
request.Header.Add("Accept", header.ContentTypeJson)
err = ParseHeaders(request, &v)
if err != nil {
t.Fatal(err)
@@ -619,7 +619,7 @@ func TestParseHeaders(t *testing.T) {
assert.Equal(t, []string{"addr1", "addr2"}, v.Addrs)
assert.Equal(t, "10.0.10.11", v.XForwardedFor)
assert.Equal(t, "10.0.11.10", v.XRealIP)
assert.Equal(t, header.JsonContentType, v.Accept)
assert.Equal(t, header.ContentTypeJson, v.Accept)
}
func TestParseHeaders_Error(t *testing.T) {
@@ -711,7 +711,7 @@ func TestParseWithFloatPtr(t *testing.T) {
}
body := `{"weightFloat32": 3.2}`
r := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(body))
r.Header.Set(ContentType, header.JsonContentType)
r.Header.Set(ContentType, header.ContentTypeJson)
if assert.NoError(t, Parse(r, &v)) {
assert.Equal(t, float32(3.2), *v.WeightFloat32)

View File

@@ -179,7 +179,7 @@ func doWriteJson(w http.ResponseWriter, code int, v any) error {
return fmt.Errorf("marshal json failed, error: %w", err)
}
w.Header().Set(ContentType, header.JsonContentType)
w.Header().Set(ContentType, header.ContentTypeJson)
w.WriteHeader(code)
if n, err := w.Write(bs); err != nil {

View File

@@ -10,7 +10,7 @@ const (
// ContentType means Content-Type.
ContentType = header.ContentType
// JsonContentType means application/json.
JsonContentType = header.JsonContentType
JsonContentType = header.ContentTypeJson
// KeyField means key.
KeyField = "key"
// SecretField means secret.

View File

@@ -3,8 +3,18 @@ package header
const (
// ApplicationJson stands for application/json.
ApplicationJson = "application/json"
// CacheControl is the header key for Cache-Control.
CacheControl = "Cache-Control"
// CacheControlNoCache is the value for Cache-Control: no-cache.
CacheControlNoCache = "no-cache"
// Connection is the header key for Connection.
Connection = "Connection"
// ConnectionKeepAlive is the value for Connection: keep-alive.
ConnectionKeepAlive = "keep-alive"
// ContentType is the header key for Content-Type.
ContentType = "Content-Type"
// JsonContentType is the content type for JSON.
JsonContentType = "application/json; charset=utf-8"
// ContentTypeJson is the content type for JSON.
ContentTypeJson = "application/json; charset=utf-8"
// ContentTypeEventStream is the content type for event stream.
ContentTypeEventStream = "text/event-stream"
)

View File

@@ -628,7 +628,7 @@ func TestParseWrappedRequest(t *testing.T) {
func TestParseWrappedGetRequestWithJsonHeader(t *testing.T) {
r, err := http.NewRequest(http.MethodGet, "http://hello.com/kevin/2017", bytes.NewReader(nil))
assert.Nil(t, err)
r.Header.Set(httpx.ContentType, header.JsonContentType)
r.Header.Set(httpx.ContentType, header.ContentTypeJson)
type (
Request struct {
@@ -661,7 +661,7 @@ func TestParseWrappedGetRequestWithJsonHeader(t *testing.T) {
func TestParseWrappedHeadRequestWithJsonHeader(t *testing.T) {
r, err := http.NewRequest(http.MethodHead, "http://hello.com/kevin/2017", bytes.NewReader(nil))
assert.Nil(t, err)
r.Header.Set(httpx.ContentType, header.JsonContentType)
r.Header.Set(httpx.ContentType, header.ContentTypeJson)
type (
Request struct {
@@ -758,7 +758,7 @@ func TestParseWithAllUtf8(t *testing.T) {
r, err := http.NewRequest(http.MethodPost, "http://hello.com/kevin/2017?nickname=whatever&zipcode=200000",
bytes.NewBufferString(`{"location": "shanghai", "time": 20170912}`))
assert.Nil(t, err)
r.Header.Set(httpx.ContentType, header.JsonContentType)
r.Header.Set(httpx.ContentType, header.ContentTypeJson)
router := NewRouter()
err = router.Handle(http.MethodPost, "/:name/:year", http.HandlerFunc(
@@ -948,7 +948,7 @@ func TestParseWithMissingAllPaths(t *testing.T) {
func TestParseGetWithContentLengthHeader(t *testing.T) {
r, err := http.NewRequest(http.MethodGet, "http://hello.com/kevin/2017?nickname=whatever&zipcode=200000", nil)
assert.Nil(t, err)
r.Header.Set(httpx.ContentType, header.JsonContentType)
r.Header.Set(httpx.ContentType, header.ContentTypeJson)
r.Header.Set(contentLength, "1024")
router := NewRouter()
@@ -976,7 +976,7 @@ func TestParseJsonPostWithTypeMismatch(t *testing.T) {
r, err := http.NewRequest(http.MethodPost, "http://hello.com/kevin/2017?nickname=whatever&zipcode=200000",
bytes.NewBufferString(`{"time": "20170912"}`))
assert.Nil(t, err)
r.Header.Set(httpx.ContentType, header.JsonContentType)
r.Header.Set(httpx.ContentType, header.ContentTypeJson)
router := NewRouter()
err = router.Handle(http.MethodPost, "/:name/:year", http.HandlerFunc(
@@ -1002,7 +1002,7 @@ func TestParseJsonPostWithInt2String(t *testing.T) {
r, err := http.NewRequest(http.MethodPost, "http://hello.com/kevin/2017",
bytes.NewBufferString(`{"time": 20170912}`))
assert.Nil(t, err)
r.Header.Set(httpx.ContentType, header.JsonContentType)
r.Header.Set(httpx.ContentType, header.ContentTypeJson)
router := NewRouter()
err = router.Handle(http.MethodPost, "/:name/:year", http.HandlerFunc(

View File

@@ -63,6 +63,11 @@ func NewServer(c RestConf, opts ...RunOption) (*Server, error) {
return server, nil
}
// AddRoute adds given route into the Server.
func (s *Server) AddRoute(r Route, opts ...RouteOption) {
s.AddRoutes([]Route{r}, opts...)
}
// AddRoutes add given routes into the Server.
func (s *Server) AddRoutes(rs []Route, opts ...RouteOption) {
r := featuredRoutes{
@@ -74,11 +79,6 @@ func (s *Server) AddRoutes(rs []Route, opts ...RouteOption) {
s.ngin.addRoutes(r)
}
// AddRoute adds given route into the Server.
func (s *Server) AddRoute(r Route, opts ...RouteOption) {
s.AddRoutes([]Route{r}, opts...)
}
// PrintRoutes prints the added routes to stdout.
func (s *Server) PrintRoutes() {
s.ngin.print()
@@ -95,25 +95,6 @@ func (s *Server) Routes() []Route {
return routes
}
// ServeHTTP is for test purpose, allow developer to do a unit test with
// all defined router without starting an HTTP Server.
//
// For example:
//
// server := MustNewServer(...)
// server.addRoute(...) // router a
// server.addRoute(...) // router b
// server.addRoute(...) // router c
//
// r, _ := http.NewRequest(...)
// w := httptest.NewRecorder(...)
// server.ServeHTTP(w, r)
// // verify the response
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
s.ngin.bindRoutes(s.router)
s.router.ServeHTTP(w, r)
}
// Start starts the Server.
// Graceful shutdown is enabled by default.
// Use proc.SetTimeToForceQuit to customize the graceful shutdown period.
@@ -298,6 +279,14 @@ func WithSignature(signature SignatureConf) RouteOption {
}
}
// WithSSE returns a RouteOption to enable server-sent events.
func WithSSE() RouteOption {
return func(r *featuredRoutes) {
r.sse = true
r.timeout = 0
}
}
// WithTimeout returns a RouteOption to set timeout with given value.
func WithTimeout(timeout time.Duration) RouteOption {
return func(r *featuredRoutes) {

View File

@@ -20,6 +20,7 @@ import (
"github.com/zeromicro/go-zero/rest/chain"
"github.com/zeromicro/go-zero/rest/httpx"
"github.com/zeromicro/go-zero/rest/internal/cors"
"github.com/zeromicro/go-zero/rest/internal/header"
"github.com/zeromicro/go-zero/rest/router"
)
@@ -231,7 +232,7 @@ func TestWithFileServerMiddleware(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, tt.requestPath, nil)
rr := httptest.NewRecorder()
server.ServeHTTP(rr, req)
serve(server, rr, req)
assert.Equal(t, tt.expectedStatus, rr.Code)
if len(tt.expectedContent) > 0 {
@@ -458,7 +459,7 @@ Port: 54321
// we would need to verify the behavior here. Since we don't have
// direct access to headers, we'll mock newCorsRouter to capture it.
w := httptest.NewRecorder()
svr.ServeHTTP(w, httptest.NewRequest(http.MethodOptions, "/", nil))
serve(svr, w, httptest.NewRequest(http.MethodOptions, "/", nil))
vals := w.Header().Values("Access-Control-Allow-Headers")
respHeaders := make(map[string]struct{})
@@ -748,12 +749,46 @@ Port: 54321
t.Run(test.name, func(t *testing.T) {
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", test.path, nil)
svr.ServeHTTP(w, req)
serve(svr, w, req)
assert.Equal(t, test.code, w.Code)
})
}
}
func TestServerEventStream(t *testing.T) {
server := MustNewServer(RestConf{})
server.AddRoutes([]Route{
{
Method: http.MethodGet,
Path: "/foo",
Handler: func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("foo"))
},
},
{
Method: http.MethodGet,
Path: "/bar",
Handler: func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("bar"))
},
},
}, WithSSE())
check := func(val string) {
req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("/%s", val), http.NoBody)
assert.Nil(t, err)
rr := httptest.NewRecorder()
serve(server, rr, req)
assert.Equal(t, http.StatusOK, rr.Code)
assert.Equal(t, header.ContentTypeEventStream, rr.Header().Get(header.ContentType))
assert.Equal(t, header.CacheControlNoCache, rr.Header().Get(header.CacheControl))
assert.Equal(t, header.ConnectionKeepAlive, rr.Header().Get(header.Connection))
assert.Equal(t, val, rr.Body.String())
}
check("foo")
check("bar")
}
//go:embed testdata
var content embed.FS
@@ -765,6 +800,25 @@ func TestServerEmbedFileSystem(t *testing.T) {
req, err := http.NewRequest(http.MethodGet, "/assets/sample.txt", http.NoBody)
assert.Nil(t, err)
rr := httptest.NewRecorder()
server.ServeHTTP(rr, req)
serve(server, rr, req)
assert.Equal(t, sampleContent, rr.Body.String())
}
// serve is for test purpose, allow developer to do a unit test with
// all defined routes without starting an HTTP Server.
//
// For example:
//
// server := MustNewServer(...)
// server.addRoute(...) // router a
// server.addRoute(...) // router b
// server.addRoute(...) // router c
//
// r, _ := http.NewRequest(...)
// w := httptest.NewRecorder(...)
// serve(server, w, r)
// // verify the response
func serve(s *Server, w http.ResponseWriter, r *http.Request) {
s.ngin.bindRoutes(s.router)
s.router.ServeHTTP(w, r)
}

View File

@@ -35,6 +35,7 @@ type (
priority bool
jwt jwtSetting
signature signatureSetting
sse bool
routes []Route
maxBytes int64
}

View File

@@ -6,16 +6,16 @@ require (
github.com/DATA-DOG/go-sqlmock v1.5.2
github.com/emicklei/proto v1.14.0
github.com/fatih/structtag v1.2.0
github.com/go-sql-driver/mysql v1.8.1
github.com/go-sql-driver/mysql v1.9.0
github.com/gookit/color v1.5.4
github.com/iancoleman/strcase v0.3.0
github.com/spf13/cobra v1.8.1
github.com/spf13/cobra v1.9.1
github.com/spf13/pflag v1.0.6
github.com/stretchr/testify v1.10.0
github.com/withfig/autocomplete-tools/integrations/cobra v1.2.1
github.com/zeromicro/antlr v0.0.1
github.com/zeromicro/ddl-parser v1.0.5
github.com/zeromicro/go-zero v1.8.0
github.com/zeromicro/go-zero v1.8.2
golang.org/x/text v0.22.0
google.golang.org/grpc v1.65.0
google.golang.org/protobuf v1.36.5
@@ -52,11 +52,11 @@ require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/pgx/v5 v5.7.2 // indirect
github.com/jackc/pgx/v5 v5.7.4 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.17.9 // indirect
github.com/klauspost/compress v1.17.11 // indirect
github.com/logrusorgru/aurora v2.0.3+incompatible // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
@@ -67,11 +67,11 @@ require (
github.com/openzipkin/zipkin-go v0.4.3 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.20.5 // indirect
github.com/prometheus/client_golang v1.21.1 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.55.0 // indirect
github.com/prometheus/common v0.62.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/redis/go-redis/v9 v9.7.0 // indirect
github.com/redis/go-redis/v9 v9.7.3 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
github.com/yuin/gopher-lua v1.1.1 // indirect
@@ -93,13 +93,13 @@ require (
go.uber.org/automaxprocs v1.6.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
go.uber.org/zap v1.24.0 // indirect
golang.org/x/crypto v0.32.0 // indirect
golang.org/x/net v0.34.0 // indirect
golang.org/x/oauth2 v0.21.0 // indirect
golang.org/x/crypto v0.33.0 // indirect
golang.org/x/net v0.35.0 // indirect
golang.org/x/oauth2 v0.24.0 // indirect
golang.org/x/sync v0.11.0 // indirect
golang.org/x/sys v0.29.0 // indirect
golang.org/x/term v0.28.0 // indirect
golang.org/x/time v0.9.0 // indirect
golang.org/x/sys v0.30.0 // indirect
golang.org/x/term v0.29.0 // indirect
golang.org/x/time v0.10.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240711142825-46eb208f015d // indirect
gopkg.in/inf.v0 v0.9.1 // indirect

View File

@@ -24,7 +24,7 @@ github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -52,8 +52,8 @@ github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU=
github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/go-sql-driver/mysql v1.9.0 h1:Y0zIbQXhQKmQgTp44Y1dp3wTXcn804QoTptLZT1vtvo=
github.com/go-sql-driver/mysql v1.9.0/go.mod h1:pDetrLJeA3oMujJuvXc8RJoasr589B6A9fwzD3QMrqw=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
@@ -89,8 +89,8 @@ github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsI
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.7.2 h1:mLoDLV6sonKlvjIEsV56SkWNCnuNv531l94GaIzO+XI=
github.com/jackc/pgx/v5 v5.7.2/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ=
github.com/jackc/pgx/v5 v5.7.4 h1:9wKznZrhWa2QiHL+NjTSPP6yjl3451BX3imWDnokYlg=
github.com/jackc/pgx/v5 v5.7.4/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
@@ -100,8 +100,8 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm
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/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
@@ -141,24 +141,23 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
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/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk=
github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E=
github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw=
github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM=
github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -188,8 +187,8 @@ github.com/zeromicro/antlr v0.0.1 h1:CQpIn/dc0pUjgGQ81y98s/NGOm2Hfru2NNio2I9mQgk
github.com/zeromicro/antlr v0.0.1/go.mod h1:nfpjEwFR6Q4xGDJMcZnCL9tEfQRgszMwu3rDz2Z+p5M=
github.com/zeromicro/ddl-parser v1.0.5 h1:LaVqHdzMTjasua1yYpIYaksxKqRzFrEukj2Wi2EbWaQ=
github.com/zeromicro/ddl-parser v1.0.5/go.mod h1:ISU/8NuPyEpl9pa17Py9TBPetMjtsiHrb9f5XGiYbo8=
github.com/zeromicro/go-zero v1.8.0 h1:4g/8VW+fOyM51HZYPeI3mXIZdEX+Fl6SsdYX2H5PYw4=
github.com/zeromicro/go-zero v1.8.0/go.mod h1:xDBF+/iDzj30zPvu6HNUIbpz1J6+/g3Sx9D/DytJfss=
github.com/zeromicro/go-zero v1.8.2 h1:AbJckBoojbr1lqCN1dkvURTIHOau7yvKReEd7ZmjuCk=
github.com/zeromicro/go-zero v1.8.2/go.mod h1:G5dF+jzCEuq0t1j8qdrtVAy30QMgctGcKSfqFIGsvSg=
go.etcd.io/etcd/api/v3 v3.5.15 h1:3KpLJir1ZEBrYuV2v+Twaa/e2MdDCEZ/70H+lzEiwsk=
go.etcd.io/etcd/api/v3 v3.5.15/go.mod h1:N9EhGzXq58WuMllgH9ZvnEr7SI9pS0k0+DHZezGp7jM=
go.etcd.io/etcd/client/pkg/v3 v3.5.15 h1:fo0HpWz/KlHGMCC+YejpiCmyWDEuIpnTDzpJLB5fWlA=
@@ -231,8 +230,8 @@ go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@@ -241,10 +240,10 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
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.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE=
golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -259,17 +258,17 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4=
golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=

View File

@@ -6,7 +6,7 @@ import (
)
// BuildVersion is the version of goctl.
const BuildVersion = "1.7.6"
const BuildVersion = "1.8.2"
var tag = map[string]int{"pre-alpha": 0, "alpha": 1, "pre-bata": 2, "beta": 3, "released": 4, "": 5}

View File

@@ -9,7 +9,8 @@ import (
var p2m = map[string]string{
"int8": "bigint",
"numeric": "bigint",
"numeric": "double",
"decimal": "double",
"float8": "double",
"float4": "float",
"int2": "smallint",

View File

@@ -84,7 +84,7 @@ func logDuration(ctx context.Context, method string, req any, duration time.Dura
content, err := json.Marshal(req)
if err != nil {
logx.WithContext(ctx).Errorf("%s - %s", addr, err.Error())
} else if duration > slowThreshold.Load() {
} else if isSlow(duration, durationThreshold) {
logger.Slowf("[RPC] slowcall - %s - %s - %s", addr, method, string(content))
} else {
logger.Infof("%s - %s - %s", addr, method, string(content))

View File

@@ -43,10 +43,11 @@ func TestLogDuration(t *testing.T) {
assert.True(t, len(addrs) > 0)
tests := []struct {
name string
ctx context.Context
req any
duration time.Duration
name string
ctx context.Context
req any
duration time.Duration
durationThreshold time.Duration
}{
{
name: "normal",
@@ -59,10 +60,11 @@ func TestLogDuration(t *testing.T) {
req: make(chan lang.PlaceholderType), // not marshalable
},
{
name: "timeout",
ctx: context.Background(),
req: "foo",
duration: time.Second,
name: "timeout",
ctx: context.Background(),
req: "foo",
duration: time.Second,
durationThreshold: time.Millisecond * 500,
},
{
name: "timeout",
@@ -86,7 +88,7 @@ func TestLogDuration(t *testing.T) {
assert.NotPanics(t, func() {
logDuration(test.ctx, "foo", test.req, test.duration,
collection.NewSet(), 0)
collection.NewSet(), test.durationThreshold)
})
})
}
@@ -98,10 +100,11 @@ func TestLogDurationWithoutContent(t *testing.T) {
assert.True(t, len(addrs) > 0)
tests := []struct {
name string
ctx context.Context
req any
duration time.Duration
name string
ctx context.Context
req any
duration time.Duration
durationThreshold time.Duration
}{
{
name: "normal",
@@ -114,10 +117,11 @@ func TestLogDurationWithoutContent(t *testing.T) {
req: make(chan lang.PlaceholderType), // not marshalable
},
{
name: "timeout",
ctx: context.Background(),
req: "foo",
duration: time.Second,
name: "timeout",
ctx: context.Background(),
req: "foo",
duration: time.Second,
durationThreshold: time.Millisecond * 500,
},
{
name: "timeout",
@@ -146,7 +150,7 @@ func TestLogDurationWithoutContent(t *testing.T) {
assert.NotPanics(t, func() {
logDuration(test.ctx, "foo", test.req, test.duration,
collection.NewSet(), 0)
collection.NewSet(), test.durationThreshold)
})
})
}
@@ -257,7 +261,8 @@ func Test_isSlow(t *testing.T) {
t.Cleanup(func() {
slowThreshold = syncx.ForAtomicDuration(defaultSlowThreshold)
})
assert.Equalf(t, tt.want, isSlow(tt.args.duration, tt.args.staticSlowThreshold), "isSlow(%v, %v)", tt.args.duration, tt.args.staticSlowThreshold)
assert.Equalf(t, tt.want, isSlow(tt.args.duration, tt.args.staticSlowThreshold),
"isSlow(%v, %v)", tt.args.duration, tt.args.staticSlowThreshold)
})
}
}