pull/2481/head
FengbinShi 2 years ago
commit 42a18320b1
  1. 2
      .github/workflows/go.yml
  2. 3
      api/metadata/server.go
  3. 2
      cmd/kratos/internal/base/vcs_url.go
  4. 4
      cmd/kratos/internal/change/get.go
  5. 2
      cmd/kratos/version.go
  6. 2
      cmd/protoc-gen-go-errors/version.go
  7. 17
      cmd/protoc-gen-go-http/http.go
  8. 2
      cmd/protoc-gen-go-http/version.go
  9. 1
      contrib/config/apollo/README.md
  10. 5
      contrib/config/apollo/apollo.go
  11. 5
      contrib/config/apollo/watcher.go
  12. 9
      contrib/config/consul/README.md
  13. 15
      contrib/config/etcd/README.md
  14. 4
      contrib/config/kubernetes/config_test.go
  15. 3
      contrib/config/nacos/README.md
  16. 3
      contrib/config/nacos/go.mod
  17. 3
      contrib/config/polaris/README.md
  18. 4
      contrib/config/polaris/config.go
  19. 10
      contrib/config/polaris/watcher.go
  20. 2
      contrib/encoding/msgpack/go.mod
  21. 36
      contrib/log/aliyun/aliyun.go
  22. 53
      contrib/log/aliyun/aliyun_test.go
  23. 2
      contrib/log/aliyun/go.mod
  24. 17
      contrib/log/fluent/fluent_test.go
  25. 2
      contrib/log/fluent/go.mod
  26. 2
      contrib/log/logrus/go.mod
  27. 2
      contrib/log/tencent/go.mod
  28. 36
      contrib/log/tencent/tencent.go
  29. 44
      contrib/log/tencent/tencent_test.go
  30. 2
      contrib/log/zap/go.mod
  31. 2
      contrib/metrics/datadog/go.mod
  32. 2
      contrib/metrics/prometheus/go.mod
  33. 2
      contrib/opensergo/go.mod
  34. 11
      contrib/opensergo/opensergo.go
  35. 11
      contrib/opensergo/opensergo_test.go
  36. 2
      contrib/registry/consul/go.mod
  37. 8
      contrib/registry/consul/registry.go
  38. 2
      contrib/registry/discovery/go.mod
  39. 2
      contrib/registry/etcd/go.mod
  40. 4
      contrib/registry/etcd/registry.go
  41. 55
      contrib/registry/eureka/client.go
  42. 4
      contrib/registry/eureka/register.go
  43. 2
      contrib/registry/kubernetes/go.mod
  44. 2
      contrib/registry/nacos/go.mod
  45. 2
      contrib/registry/polaris/go.mod
  46. 2
      contrib/registry/zookeeper/go.mod
  47. 4
      contrib/registry/zookeeper/register.go
  48. 4
      log/level.go
  49. 6
      log/level_test.go
  50. 25
      middleware/auth/jwt/jwt_test.go
  51. 29
      middleware/logging/logging_test.go
  52. 14
      middleware/metadata/metadata.go
  53. 67
      middleware/metadata/metadata_test.go
  54. 4
      selector/node/ewma/node.go
  55. 9
      selector/node/ewma/node_test.go
  56. 12
      transport/grpc/balancer.go
  57. 6
      transport/http/binding/bind_test.go
  58. 7
      transport/http/client_test.go
  59. 10
      transport/http/context_test.go
  60. 3
      transport/http/redirect_test.go
  61. 6
      transport/http/router_test.go
  62. 10
      transport/http/server.go
  63. 34
      transport/http/server_test.go
  64. 2
      version.go

@ -44,7 +44,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v3.3.0
uses: actions/setup-go@v3.3.1
with:
go-version: ${{ matrix.go }}

@ -7,6 +7,7 @@ import (
"errors"
"fmt"
"io"
"sort"
"sync"
"google.golang.org/grpc"
@ -115,6 +116,8 @@ func (s *Server) ListServices(ctx context.Context, in *ListServicesRequest) (*Li
reply.Methods = append(reply.Methods, fmt.Sprintf("/%s/%s", name, method))
}
}
sort.Strings(reply.Services)
sort.Strings(reply.Methods)
return reply, nil
}

@ -8,7 +8,7 @@ import (
)
var (
scpSyntaxRe = regexp.MustCompile(`^([a-zA-Z0-9_]+)@([a-zA-Z0-9._-]+):(.*)$`)
scpSyntaxRe = regexp.MustCompile(`^(\w+)@([\w.-]+):(.*)$`)
scheme = []string{"git", "https", "http", "git+ssh", "ssh", "file", "ftp", "ftps"}
)

@ -43,7 +43,7 @@ func (g *GithubAPI) GetReleaseInfo(version string) ReleaseInfo {
if version != "latest" {
api = fmt.Sprintf("https://api.github.com/repos/%s/%s/releases/tags/%s", g.Owner, g.Repo, version)
}
resp, code := requestGithubAPI(api, "GET", nil, g.Token)
resp, code := requestGithubAPI(api, http.MethodGet, nil, g.Token)
if code != http.StatusOK {
printGithubErrorInfo(resp)
}
@ -63,7 +63,7 @@ func (g *GithubAPI) GetCommitsInfo() []CommitInfo {
var list []CommitInfo
for {
url := fmt.Sprintf("https://api.github.com/repos/%s/%s/commits?pre_page=%d&page=%d&since=%s", g.Owner, g.Repo, prePage, page, info.PublishedAt)
resp, code := requestGithubAPI(url, "GET", nil, g.Token)
resp, code := requestGithubAPI(url, http.MethodGet, nil, g.Token)
if code != http.StatusOK {
printGithubErrorInfo(resp)
}

@ -1,4 +1,4 @@
package main
// release is the current kratos tool version.
const release = "v2.5.1"
const release = "v2.5.2"

@ -1,4 +1,4 @@
package main
// release is the current protoc-gen-go-errors version.
const release = "v2.5.1"
const release = "v2.5.2"

@ -2,6 +2,7 @@ package main
import (
"fmt"
"net/http"
"os"
"regexp"
"strings"
@ -85,7 +86,7 @@ func genService(gen *protogen.Plugin, file *protogen.File, g *protogen.Generated
sd.Methods = append(sd.Methods, buildHTTPRule(g, method, rule))
} else if !omitempty {
path := fmt.Sprintf("/%s/%s", service.Desc.FullName(), method.Desc.Name())
sd.Methods = append(sd.Methods, buildMethodDesc(g, method, "POST", path))
sd.Methods = append(sd.Methods, buildMethodDesc(g, method, http.MethodPost, path))
}
}
if len(sd.Methods) != 0 {
@ -119,19 +120,19 @@ func buildHTTPRule(g *protogen.GeneratedFile, m *protogen.Method, rule *annotati
switch pattern := rule.Pattern.(type) {
case *annotations.HttpRule_Get:
path = pattern.Get
method = "GET"
method = http.MethodGet
case *annotations.HttpRule_Put:
path = pattern.Put
method = "PUT"
method = http.MethodPut
case *annotations.HttpRule_Post:
path = pattern.Post
method = "POST"
method = http.MethodPost
case *annotations.HttpRule_Delete:
path = pattern.Delete
method = "DELETE"
method = http.MethodDelete
case *annotations.HttpRule_Patch:
path = pattern.Patch
method = "PATCH"
method = http.MethodPatch
case *annotations.HttpRule_Custom:
path = pattern.Custom.Path
method = pattern.Custom.Kind
@ -139,7 +140,7 @@ func buildHTTPRule(g *protogen.GeneratedFile, m *protogen.Method, rule *annotati
body = rule.Body
responseBody = rule.ResponseBody
md := buildMethodDesc(g, m, method, path)
if method == "GET" || method == "DELETE" {
if method == http.MethodGet || method == http.MethodDelete {
if body != "" {
_, _ = fmt.Fprintf(os.Stderr, "\u001B[31mWARN\u001B[m: %s %s body should not be declared.\n", method, path)
}
@ -213,7 +214,7 @@ func buildPathVars(path string) (res map[string]*string) {
if strings.HasSuffix(path, "/") {
fmt.Fprintf(os.Stderr, "\u001B[31mWARN\u001B[m: Path %s should not end with \"/\" \n", path)
}
pattern := regexp.MustCompile(`(?i){([a-z\.0-9_\s]*)=?([^{}]*)}`)
pattern := regexp.MustCompile(`(?i){([a-z.0-9_\s]*)=?([^{}]*)}`)
matches := pattern.FindAllStringSubmatch(path, -1)
res = make(map[string]*string, len(matches))
for _, m := range matches {

@ -1,4 +1,4 @@
package main
// release is the current protoc-gen-go-http version.
const release = "v2.5.1"
const release = "v2.5.2"

@ -97,5 +97,4 @@ config := map[string]interface{}{
}
}
}
_ = config
```

@ -3,15 +3,14 @@ package apollo
import (
"strings"
"github.com/go-kratos/kratos/v2/config"
"github.com/go-kratos/kratos/v2/log"
"github.com/apolloconfig/agollo/v4"
"github.com/apolloconfig/agollo/v4/constant"
apolloConfig "github.com/apolloconfig/agollo/v4/env/config"
"github.com/apolloconfig/agollo/v4/extension"
"github.com/go-kratos/kratos/v2/config"
"github.com/go-kratos/kratos/v2/encoding"
"github.com/go-kratos/kratos/v2/log"
)
type apollo struct {

@ -4,12 +4,11 @@ import (
"context"
"strings"
"github.com/go-kratos/kratos/v2/encoding"
"github.com/apolloconfig/agollo/v4/storage"
"github.com/go-kratos/kratos/v2/config"
"github.com/go-kratos/kratos/v2/encoding"
"github.com/go-kratos/kratos/v2/log"
"github.com/apolloconfig/agollo/v4/storage"
)
type watcher struct {

@ -2,11 +2,12 @@
```go
import (
"github.com/go-kratos/kratos/contrib/config/consul/v2"
"github.com/hashicorp/consul/api"
"github.com/go-kratos/kratos/contrib/config/consul/v2"
)
func main() {
func main() {
consulClient, err := api.NewClient(&api.Config{
Address: "127.0.0.1:8500",
})
@ -14,8 +15,8 @@ func main() {
panic(err)
}
cs, err := consul.New(consulClient, consul.WithPath("app/cart/configs/"))
//consul中需要标注文件后缀,kratos读取配置需要适配文件后缀
//The file suffix needs to be marked, and kratos needs to adapt the file suffix to read the configuration.
// consul中需要标注文件后缀,kratos读取配置需要适配文件后缀
// The file suffix needs to be marked, and kratos needs to adapt the file suffix to read the configuration.
if err != nil {
panic(err)
}

@ -4,10 +4,11 @@
import (
"log"
cfg "github.com/go-kratos/kratos/contrib/config/etcd/v2"
"github.com/go-kratos/kratos/v2/config"
clientv3 "go.etcd.io/etcd/client/v3"
"google.golang.org/grpc"
cfg "github.com/go-kratos/kratos/contrib/config/etcd/v2"
"github.com/go-kratos/kratos/v2/config"
)
// create an etcd client
@ -30,12 +31,16 @@ if err != nil {
c := config.New(config.WithSource(source))
defer c.Close()
// load sources before get
if err := c.Load(); err != nil {
log.Fatalln(err)
}
// acquire config value
foo, err := c.Value("/app-config").String()
if err != nil {
log.Println(err)
log.Fatalln(err)
}
println(foo)
log.Println(foo)
```

@ -8,14 +8,14 @@ import (
"strings"
"testing"
"github.com/go-kratos/kratos/v2/config"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir"
"github.com/go-kratos/kratos/v2/config"
)
const (

@ -2,9 +2,10 @@
```go
import (
kconfig "github.com/go-kratos/kratos/v2/config"
"github.com/nacos-group/nacos-sdk-go/clients"
"github.com/nacos-group/nacos-sdk-go/common/constant"
kconfig "github.com/go-kratos/kratos/v2/config"
)

@ -5,6 +5,9 @@ go 1.16
require (
github.com/go-kratos/kratos/v2 v2.4.0
github.com/nacos-group/nacos-sdk-go v1.0.9
)
require (
gopkg.in/yaml.v3 v3.0.1 // indirect
)

@ -5,18 +5,17 @@ import (
"log"
"github.com/polarismesh/polaris-go"
"github.com/go-kratos/kratos/contrib/config/polaris/v2"
)
func main() {
configApi, err := polaris.NewConfigAPI()
if err != nil {
log.Fatalln(err)
}
source, err := New(&configApi, WithNamespace("default"), WithFileGroup("default"), WithFileName("default.yaml"))
if err != nil {
log.Fatalln(err)
}

@ -6,9 +6,9 @@ import (
"path/filepath"
"strings"
"github.com/go-kratos/kratos/v2/config"
"github.com/polarismesh/polaris-go"
"github.com/go-kratos/kratos/v2/config"
)
// Option is polaris config option.

@ -5,11 +5,11 @@ import (
"path/filepath"
"strings"
"github.com/go-kratos/kratos/v2/config"
"github.com/go-kratos/kratos/v2/log"
"github.com/polarismesh/polaris-go"
"github.com/polarismesh/polaris-go/pkg/model"
"github.com/go-kratos/kratos/v2/config"
"github.com/go-kratos/kratos/v2/log"
)
type Watcher struct {
@ -28,7 +28,7 @@ func getFullPath(namespace string, fileGroup string, fileName string) string {
return fmt.Sprintf("%s/%s/%s", namespace, fileGroup, fileName)
}
func recieve(event model.ConfigFileChangeEvent) {
func receive(event model.ConfigFileChangeEvent) {
meta := event.ConfigFileMetadata
ec := eventChanMap[getFullPath(meta.GetNamespace(), meta.GetFileGroup(), meta.GetFileName())]
defer func() {
@ -42,7 +42,7 @@ func recieve(event model.ConfigFileChangeEvent) {
}
func newWatcher(configFile polaris.ConfigFile) *Watcher {
configFile.AddChangeListener(recieve)
configFile.AddChangeListener(receive)
fullPath := getFullPath(configFile.GetNamespace(), configFile.GetFileGroup(), configFile.GetFileName())
if _, ok := eventChanMap[fullPath]; !ok {

@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/encoding/msgpack/v2
go 1.16
require (
github.com/go-kratos/kratos/v2 v2.5.1
github.com/go-kratos/kratos/v2 v2.5.2
github.com/vmihailenco/msgpack/v5 v5.3.5
)

@ -16,6 +16,7 @@ import (
// Logger see more detail https://github.com/aliyun/aliyun-log-go-sdk
type Logger interface {
log.Logger
GetProducer() *producer.Producer
Close() error
}
@ -81,22 +82,16 @@ func (a *aliyunLog) Close() error {
}
func (a *aliyunLog) Log(level log.Level, keyvals ...interface{}) error {
buf := level.String()
levelTitle := "level"
contents := make([]*sls.LogContent, 0)
contents := make([]*sls.LogContent, 0, len(keyvals)/2+1)
contents = append(contents, &sls.LogContent{
Key: &levelTitle,
Value: &buf,
Key: newString(level.Key()),
Value: newString(level.String()),
})
for i := 0; i < len(keyvals); i += 2 {
key := toString(keyvals[i])
value := toString(keyvals[i+1])
contents = append(contents, &sls.LogContent{
Key: &key,
Value: &value,
Key: newString(toString(keyvals[i])),
Value: newString(toString(keyvals[i+1])),
})
}
@ -104,9 +99,7 @@ func (a *aliyunLog) Log(level log.Level, keyvals ...interface{}) error {
Time: proto.Uint32(uint32(time.Now().Unix())),
Contents: contents,
}
err := a.producer.SendLog(a.opts.project, a.opts.logstore, "", "", logInst)
return err
return a.producer.SendLog(a.opts.project, a.opts.logstore, "", "", logInst)
}
// NewAliyunLog new a aliyun logger with options.
@ -128,6 +121,11 @@ func NewAliyunLog(options ...Option) Logger {
}
}
// newString string convert to *string
func newString(s string) *string {
return &s
}
// toString convert any type to string
func toString(v interface{}) string {
var key string
@ -138,23 +136,23 @@ func toString(v interface{}) string {
case float64:
key = strconv.FormatFloat(v, 'f', -1, 64)
case float32:
key = strconv.FormatFloat(float64(v), 'f', -1, 64)
key = strconv.FormatFloat(float64(v), 'f', -1, 32)
case int:
key = strconv.Itoa(v)
case uint:
key = strconv.Itoa(int(v))
key = strconv.FormatUint(uint64(v), 10)
case int8:
key = strconv.Itoa(int(v))
case uint8:
key = strconv.Itoa(int(v))
key = strconv.FormatUint(uint64(v), 10)
case int16:
key = strconv.Itoa(int(v))
case uint16:
key = strconv.Itoa(int(v))
key = strconv.FormatUint(uint64(v), 10)
case int32:
key = strconv.Itoa(int(v))
case uint32:
key = strconv.Itoa(int(v))
key = strconv.FormatUint(uint64(v), 10)
case int64:
key = strconv.FormatInt(v, 10)
case uint64:

@ -2,6 +2,7 @@ package aliyun
import (
"math"
"reflect"
"testing"
"github.com/go-kratos/kratos/v2/log"
@ -99,34 +100,44 @@ func TestLog(t *testing.T) {
}
}
func TestNewString(t *testing.T) {
ptr := newString("")
if kind := reflect.TypeOf(ptr).Kind(); kind != reflect.Ptr {
t.Errorf("want type: %v, got type: %v", reflect.Ptr, kind)
}
}
func TestToString(t *testing.T) {
tests := []struct {
name string
in interface{}
out string
}{
{math.MaxFloat64, "17976931348623157000000000000000000000000000000000000" +
"000000000000000000000000000000000000000000000000000000000000000000000000000" +
"000000000000000000000000000000000000000000000000000000000000000000000000000" +
"000000000000000000000000000000000000000000000000000000000000000000000000000" +
"0000000000000000000000000000000"},
{math.MaxFloat32, "340282346638528860000000000000000000000"},
{1<<((32<<(^uint(0)>>63))-1) - 1, "9223372036854775807"},
{uint(1<<(32<<(^uint(0)>>63)) - 1), "-1"},
{math.MaxInt8, "127"},
{math.MaxUint8, "255"},
{math.MaxInt16, "32767"},
{math.MaxUint16, "65535"},
{math.MaxInt32, "2147483647"},
{math.MaxUint32, "4294967295"},
{math.MaxInt64, "9223372036854775807"},
{uint64(math.MaxUint64), "18446744073709551615"},
{"abc", "abc"},
{false, "false"},
{[]byte("abc"), "abc"},
{"float64", 6.66, "6.66"},
{"max float64", math.MaxFloat64, "179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}, //nolint:lll
{"float32", float32(6.66), "6.66"},
{"max float32", math.MaxFloat32, "340282346638528860000000000000000000000"},
{"int", int(math.MaxInt64), "9223372036854775807"},
{"uint", uint(math.MaxUint64), "18446744073709551615"},
{"int8", math.MaxInt8, "127"},
{"uint8", math.MaxUint8, "255"},
{"int16", math.MaxInt16, "32767"},
{"uint16", math.MaxUint16, "65535"},
{"int32", math.MaxInt32, "2147483647"},
{"uint32", math.MaxUint32, "4294967295"},
{"int64", math.MaxInt64, "9223372036854775807"},
{"uint64", uint64(math.MaxUint64), "18446744073709551615"},
{"string", "abc", "abc"},
{"bool", false, "false"},
{"[]byte", []byte("abc"), "abc"},
{"struct", struct{ Name string }{}, `{"Name":""}`},
}
for _, test := range tests {
if toString(test.in) != test.out {
t.Fatalf("want: %s, got: %s", test.out, toString(test.in))
t.Run(test.name, func(t *testing.T) {
out := toString(test.in)
if test.out != out {
t.Fatalf("want: %s, got: %s", test.out, out)
}
})
}
}

@ -4,7 +4,7 @@ go 1.16
require (
github.com/aliyun/aliyun-log-go-sdk v0.1.37
github.com/go-kratos/kratos/v2 v2.5.1
github.com/go-kratos/kratos/v2 v2.5.2
google.golang.org/protobuf v1.28.1
)

@ -11,19 +11,24 @@ import (
)
func TestMain(m *testing.M) {
if ln, err := net.Listen("tcp", ":24224"); err == nil {
defer ln.Close()
go func() {
for {
listener := func(ln net.Listener) {
conn, err := ln.Accept()
if err != nil {
return
}
defer conn.Close()
if _, err = io.ReadAll(conn); err != nil {
continue
_, err = io.ReadAll(conn)
if err != nil {
return
}
}
if ln, err := net.Listen("tcp", ":24224"); err == nil {
defer ln.Close()
go func() {
for {
listener(ln)
}
}()
}

@ -5,7 +5,7 @@ go 1.16
require (
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
github.com/fluent/fluent-logger-golang v1.9.0
github.com/go-kratos/kratos/v2 v2.5.1
github.com/go-kratos/kratos/v2 v2.5.2
github.com/kr/pretty v0.3.0 // indirect
github.com/tinylib/msgp v1.1.6 // indirect
)

@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/log/logrus/v2
go 1.16
require (
github.com/go-kratos/kratos/v2 v2.5.1
github.com/go-kratos/kratos/v2 v2.5.2
github.com/sirupsen/logrus v1.8.1
)

@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/log/tencent/v2
go 1.16
require (
github.com/go-kratos/kratos/v2 v2.5.1
github.com/go-kratos/kratos/v2 v2.5.2
github.com/tencentcloud/tencentcloud-cls-sdk-go v1.0.2
google.golang.org/protobuf v1.28.0
)

@ -14,8 +14,8 @@ import (
type Logger interface {
log.Logger
GetProducer() *cls.AsyncProducerClient
GetProducer() *cls.AsyncProducerClient
Close() error
}
@ -66,25 +66,20 @@ func WithAccessSecret(as string) Option {
type Option func(cls *options)
func (log *tencentLog) Close() error {
err := log.producer.Close(5000)
return err
return log.producer.Close(5000)
}
func (log *tencentLog) Log(level log.Level, keyvals ...interface{}) error {
buf := level.String()
levelTitle := "level"
contents := make([]*cls.Log_Content, 0)
contents := make([]*cls.Log_Content, 0, len(keyvals)/2+1)
contents = append(contents, &cls.Log_Content{
Key: &levelTitle,
Value: &buf,
Key: newString(level.Key()),
Value: newString(level.String()),
})
for i := 0; i < len(keyvals); i += 2 {
key := toString(keyvals[i])
value := toString(keyvals[i+1])
contents = append(contents, &cls.Log_Content{
Key: &key,
Value: &value,
Key: newString(toString(keyvals[i])),
Value: newString(toString(keyvals[i+1])),
})
}
@ -92,8 +87,7 @@ func (log *tencentLog) Log(level log.Level, keyvals ...interface{}) error {
Time: proto.Int64(time.Now().Unix()),
Contents: contents,
}
err := log.producer.SendLog(log.opts.topicID, logInst, nil)
return err
return log.producer.SendLog(log.opts.topicID, logInst, nil)
}
func NewLogger(options ...Option) (Logger, error) {
@ -115,6 +109,10 @@ func NewLogger(options ...Option) (Logger, error) {
}, nil
}
func newString(s string) *string {
return &s
}
// toString convert any type to string
func toString(v interface{}) string {
var key string
@ -125,23 +123,23 @@ func toString(v interface{}) string {
case float64:
key = strconv.FormatFloat(v, 'f', -1, 64)
case float32:
key = strconv.FormatFloat(float64(v), 'f', -1, 64)
key = strconv.FormatFloat(float64(v), 'f', -1, 32)
case int:
key = strconv.Itoa(v)
case uint:
key = strconv.Itoa(int(v))
key = strconv.FormatUint(uint64(v), 10)
case int8:
key = strconv.Itoa(int(v))
case uint8:
key = strconv.Itoa(int(v))
key = strconv.FormatUint(uint64(v), 10)
case int16:
key = strconv.Itoa(int(v))
case uint16:
key = strconv.Itoa(int(v))
key = strconv.FormatUint(uint64(v), 10)
case int32:
key = strconv.Itoa(int(v))
case uint32:
key = strconv.Itoa(int(v))
key = strconv.FormatUint(uint64(v), 10)
case int64:
key = strconv.FormatInt(v, 10)
case uint64:

@ -1,6 +1,8 @@
package tencent
import (
"math"
"reflect"
"testing"
"github.com/go-kratos/kratos/v2/log"
@ -101,3 +103,45 @@ func TestLog(t *testing.T) {
t.Errorf("Log() returns error:%v", err)
}
}
func TestNewString(t *testing.T) {
ptr := newString("")
if kind := reflect.TypeOf(ptr).Kind(); kind != reflect.Ptr {
t.Errorf("want type: %v, got type: %v", reflect.Ptr, kind)
}
}
func TestToString(t *testing.T) {
tests := []struct {
name string
in interface{}
out string
}{
{"float64", 6.66, "6.66"},
{"max float64", math.MaxFloat64, "179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}, //nolint:lll
{"float32", float32(6.66), "6.66"},
{"max float32", math.MaxFloat32, "340282346638528860000000000000000000000"},
{"int", int(math.MaxInt64), "9223372036854775807"},
{"uint", uint(math.MaxUint64), "18446744073709551615"},
{"int8", math.MaxInt8, "127"},
{"uint8", math.MaxUint8, "255"},
{"int16", math.MaxInt16, "32767"},
{"uint16", math.MaxUint16, "65535"},
{"int32", math.MaxInt32, "2147483647"},
{"uint32", math.MaxUint32, "4294967295"},
{"int64", math.MaxInt64, "9223372036854775807"},
{"uint64", uint64(math.MaxUint64), "18446744073709551615"},
{"string", "abc", "abc"},
{"bool", false, "false"},
{"[]byte", []byte("abc"), "abc"},
{"struct", struct{ Name string }{}, `{"Name":""}`},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
out := toString(test.in)
if test.out != out {
t.Fatalf("want: %s, got: %s", test.out, out)
}
})
}
}

@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/log/zap/v2
go 1.16
require (
github.com/go-kratos/kratos/v2 v2.5.1
github.com/go-kratos/kratos/v2 v2.5.2
go.uber.org/zap v1.23.0
)

@ -5,7 +5,7 @@ go 1.16
require (
github.com/DataDog/datadog-go v4.8.3+incompatible
github.com/Microsoft/go-winio v0.5.2 // indirect
github.com/go-kratos/kratos/v2 v2.5.1
github.com/go-kratos/kratos/v2 v2.5.2
)
replace github.com/go-kratos/kratos/v2 => ../../../

@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/metrics/prometheus/v2
go 1.16
require (
github.com/go-kratos/kratos/v2 v2.5.1
github.com/go-kratos/kratos/v2 v2.5.2
github.com/prometheus/client_golang v1.12.2
github.com/prometheus/common v0.37.0
)

@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/opensergo/v2
go 1.17
require (
github.com/go-kratos/kratos/v2 v2.5.1
github.com/go-kratos/kratos/v2 v2.5.2
github.com/opensergo/opensergo-go v0.0.0-20220331070310-e5b01fee4d1c
golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2
google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd

@ -3,6 +3,7 @@ package opensergo
import (
"encoding/json"
"net"
"net/http"
"net/url"
"os"
"strconv"
@ -186,15 +187,15 @@ func listDescriptors() (services []*v1.ServiceDescriptor, types []*v1.TypeDescri
func HTTPPatternInfo(pattern interface{}) (method string, path string) {
switch p := pattern.(type) {
case *annotations.HttpRule_Get:
return "GET", p.Get
return http.MethodGet, p.Get
case *annotations.HttpRule_Post:
return "POST", p.Post
return http.MethodPost, p.Post
case *annotations.HttpRule_Delete:
return "DELETE", p.Delete
return http.MethodDelete, p.Delete
case *annotations.HttpRule_Patch:
return "PATCH", p.Patch
return http.MethodPatch, p.Patch
case *annotations.HttpRule_Put:
return "PUT", p.Put
return http.MethodPut, p.Put
case *annotations.HttpRule_Custom:
return p.Custom.Kind, p.Custom.Path
default:

@ -2,6 +2,7 @@ package opensergo
import (
"net"
"net/http"
"os"
"path/filepath"
"reflect"
@ -195,7 +196,7 @@ func TestHTTPPatternInfo(t *testing.T) {
args: args{
pattern: &annotations.HttpRule_Get{Get: "/foo"},
},
wantMethod: "GET",
wantMethod: http.MethodGet,
wantPath: "/foo",
},
{
@ -203,7 +204,7 @@ func TestHTTPPatternInfo(t *testing.T) {
args: args{
pattern: &annotations.HttpRule_Post{Post: "/foo"},
},
wantMethod: "POST",
wantMethod: http.MethodPost,
wantPath: "/foo",
},
{
@ -211,7 +212,7 @@ func TestHTTPPatternInfo(t *testing.T) {
args: args{
pattern: &annotations.HttpRule_Put{Put: "/foo"},
},
wantMethod: "PUT",
wantMethod: http.MethodPut,
wantPath: "/foo",
},
{
@ -219,7 +220,7 @@ func TestHTTPPatternInfo(t *testing.T) {
args: args{
pattern: &annotations.HttpRule_Delete{Delete: "/foo"},
},
wantMethod: "DELETE",
wantMethod: http.MethodDelete,
wantPath: "/foo",
},
{
@ -227,7 +228,7 @@ func TestHTTPPatternInfo(t *testing.T) {
args: args{
pattern: &annotations.HttpRule_Patch{Patch: "/foo"},
},
wantMethod: "PATCH",
wantMethod: http.MethodPatch,
wantPath: "/foo",
},
{

@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/registry/consul/v2
go 1.16
require (
github.com/go-kratos/kratos/v2 v2.5.1
github.com/go-kratos/kratos/v2 v2.5.2
github.com/hashicorp/consul/api v1.14.0
)

@ -7,14 +7,14 @@ import (
"sync/atomic"
"time"
"github.com/go-kratos/kratos/v2/registry"
"github.com/hashicorp/consul/api"
"github.com/go-kratos/kratos/v2/registry"
)
var (
_ registry.Registrar = &Registry{}
_ registry.Discovery = &Registry{}
_ registry.Registrar = (*Registry)(nil)
_ registry.Discovery = (*Registry)(nil)
)
// Option is consul registry option.

@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/registry/discovery/v2
go 1.16
require (
github.com/go-kratos/kratos/v2 v2.5.1
github.com/go-kratos/kratos/v2 v2.5.2
github.com/go-resty/resty/v2 v2.7.0
github.com/pkg/errors v0.9.1
)

@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/registry/etcd/v2
go 1.16
require (
github.com/go-kratos/kratos/v2 v2.5.1
github.com/go-kratos/kratos/v2 v2.5.2
go.etcd.io/etcd/client/v3 v3.5.4
google.golang.org/grpc v1.46.2
)

@ -12,8 +12,8 @@ import (
)
var (
_ registry.Registrar = &Registry{}
_ registry.Discovery = &Registry{}
_ registry.Registrar = (*Registry)(nil)
_ registry.Discovery = (*Registry)(nil)
)
// Option is etcd registry option.

@ -16,7 +16,7 @@ import (
const (
statusUp = "UP"
statusDown = "DOWN"
statusOutOfServeice = "OUT_OF_SERVICE"
statusOutOfService = "OUT_OF_SERVICE"
heartbeatRetry = 3
maxIdleConns = 100
heartbeatTime = 10
@ -153,7 +153,7 @@ func NewClient(urls []string, opts ...ClientOption) *Client {
func (e *Client) FetchApps(ctx context.Context) []Application {
var m ApplicationsRootResponse
if err := e.do(ctx, "GET", []string{"apps"}, nil, &m); err != nil {
if err := e.do(ctx, http.MethodGet, []string{"apps"}, nil, &m); err != nil {
return nil
}
@ -161,7 +161,7 @@ func (e *Client) FetchApps(ctx context.Context) []Application {
}
func (e *Client) FetchAppInstances(ctx context.Context, appID string) (m Application, err error) {
err = e.do(ctx, "GET", []string{"apps", appID}, nil, &m)
err = e.do(ctx, http.MethodGet, []string{"apps", appID}, nil, &m)
return
}
@ -174,21 +174,21 @@ func (e *Client) FetchAppUpInstances(ctx context.Context, appID string) []Instan
}
func (e *Client) FetchAppInstance(ctx context.Context, appID string, instanceID string) (m Instance, err error) {
err = e.do(ctx, "GET", []string{"apps", appID, instanceID}, nil, &m)
err = e.do(ctx, http.MethodGet, []string{"apps", appID, instanceID}, nil, &m)
return
}
func (e *Client) FetchInstance(ctx context.Context, instanceID string) (m Instance, err error) {
err = e.do(ctx, "GET", []string{"instances", instanceID}, nil, &m)
err = e.do(ctx, http.MethodGet, []string{"instances", instanceID}, nil, &m)
return
}
func (e *Client) Out(ctx context.Context, appID, instanceID string) error {
return e.do(ctx, "PUT", []string{"apps", appID, instanceID, fmt.Sprintf("status?value=%s", statusOutOfServeice)}, nil, nil)
return e.do(ctx, http.MethodPut, []string{"apps", appID, instanceID, fmt.Sprintf("status?value=%s", statusOutOfService)}, nil, nil)
}
func (e *Client) Down(ctx context.Context, appID, instanceID string) error {
return e.do(ctx, "PUT", []string{"apps", appID, instanceID, fmt.Sprintf("status?value=%s", statusDown)}, nil, nil)
return e.do(ctx, http.MethodPut, []string{"apps", appID, instanceID, fmt.Sprintf("status?value=%s", statusDown)}, nil, nil)
}
func (e *Client) FetchAllUpInstances(ctx context.Context) []Instance {
@ -200,7 +200,7 @@ func (e *Client) Register(ctx context.Context, ep Endpoint) error {
}
func (e *Client) Deregister(ctx context.Context, appID, instanceID string) error {
if err := e.do(ctx, "DELETE", []string{"apps", appID, instanceID}, nil, nil); err != nil {
if err := e.do(ctx, http.MethodDelete, []string{"apps", appID, instanceID}, nil, nil); err != nil {
return err
}
go e.cancelHeartbeat(appID)
@ -239,7 +239,7 @@ func (e *Client) registerEndpoint(ctx context.Context, ep Endpoint) error {
if err != nil {
return err
}
return e.do(ctx, "POST", []string{"apps", ep.AppID}, bytes.NewReader(body), nil)
return e.do(ctx, http.MethodPost, []string{"apps", ep.AppID}, bytes.NewReader(body), nil)
}
func (e *Client) Heartbeat(ep Endpoint) {
@ -257,7 +257,7 @@ func (e *Client) Heartbeat(ep Endpoint) {
case <-e.keepalive[ep.AppID]:
return
case <-ticker.C:
if err := e.do(e.ctx, "PUT", []string{"apps", ep.AppID, ep.InstanceID}, nil, nil); err != nil {
if err := e.do(e.ctx, http.MethodPut, []string{"apps", ep.AppID, ep.InstanceID}, nil, nil); err != nil {
if retryCount++; retryCount > heartbeatRetry {
_ = e.registerEndpoint(e.ctx, ep)
retryCount = 0
@ -268,8 +268,8 @@ func (e *Client) Heartbeat(ep Endpoint) {
}
func (e *Client) cancelHeartbeat(appID string) {
defer e.lock.Unlock()
e.lock.Lock()
defer e.lock.Unlock()
if ch, ok := e.keepalive[appID]; ok {
ch <- struct{}{}
}
@ -307,39 +307,50 @@ func (e *Client) buildAPI(currentTimes int, params ...string) string {
return strings.Join(params, "/")
}
func (e *Client) do(ctx context.Context, method string, params []string, input io.Reader, output interface{}) error {
for i := 0; i < e.maxRetry; i++ {
request, err := http.NewRequest(method, e.buildAPI(i, params...), input)
func (e *Client) request(ctx context.Context, method string, params []string, input io.Reader, output interface{}, i int) (bool, error) {
request, err := http.NewRequestWithContext(ctx, method, e.buildAPI(i, params...), input)
if err != nil {
return err
return false, err
}
request = request.WithContext(ctx)
request.Header.Add("User-Agent", "go-eureka-client")
request.Header.Add("Accept", "application/json;charset=UTF-8")
request.Header.Add("Content-Type", "application/json;charset=UTF-8")
resp, err := e.client.Do(request)
if err != nil {
continue
return true, err
}
defer func() {
_, _ = io.Copy(io.Discard, resp.Body)
resp.Body.Close()
_ = resp.Body.Close()
}()
if output != nil && resp.StatusCode/100 == 2 {
data, err := io.ReadAll(resp.Body)
if err != nil {
return err
return false, err
}
if err = json.Unmarshal(data, output); err != nil {
return err
err = json.Unmarshal(data, output)
if err != nil {
return false, err
}
}
if resp.StatusCode >= http.StatusBadRequest {
return fmt.Errorf("response Error %d", resp.StatusCode)
return false, fmt.Errorf("response Error %d", resp.StatusCode)
}
return false, nil
}
func (e *Client) do(ctx context.Context, method string, params []string, input io.Reader, output interface{}) error {
for i := 0; i < e.maxRetry; i++ {
retry, err := e.request(ctx, method, params, input, output, i)
if retry {
continue
}
if err != nil {
return err
}
return nil
}
return fmt.Errorf("retry after %d times", e.maxRetry)

@ -11,8 +11,8 @@ import (
)
var (
_ registry.Registrar = &Registry{}
_ registry.Discovery = &Registry{}
_ registry.Registrar = (*Registry)(nil)
_ registry.Discovery = (*Registry)(nil)
)
type Option func(o *Registry)

@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/registry/kubernetes/v2
go 1.16
require (
github.com/go-kratos/kratos/v2 v2.5.1
github.com/go-kratos/kratos/v2 v2.5.2
github.com/json-iterator/go v1.1.12
k8s.io/api v0.24.3
k8s.io/apimachinery v0.24.3

@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/registry/nacos/v2
go 1.16
require (
github.com/go-kratos/kratos/v2 v2.5.1
github.com/go-kratos/kratos/v2 v2.5.2
github.com/nacos-group/nacos-sdk-go v1.0.9
)

@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/registry/polaris/v2
go 1.16
require (
github.com/go-kratos/kratos/v2 v2.5.1
github.com/go-kratos/kratos/v2 v2.5.2
github.com/polarismesh/polaris-go v1.1.0
)

@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/registry/zookeeper/v2
go 1.16
require (
github.com/go-kratos/kratos/v2 v2.5.1
github.com/go-kratos/kratos/v2 v2.5.2
github.com/go-zookeeper/zk v1.0.3
golang.org/x/sync v0.0.0-20220513210516-0976fa681c29
)

@ -12,8 +12,8 @@ import (
)
var (
_ registry.Registrar = &Registry{}
_ registry.Discovery = &Registry{}
_ registry.Registrar = (*Registry)(nil)
_ registry.Discovery = (*Registry)(nil)
)
// Option is etcd registry option.

@ -21,6 +21,10 @@ const (
LevelFatal
)
func (l Level) Key() string {
return LevelKey
}
func (l Level) String() string {
switch l {
case LevelDebug:

@ -2,6 +2,12 @@ package log
import "testing"
func TestLevel_Key(t *testing.T) {
if LevelInfo.Key() != LevelKey {
t.Errorf("want: %s, got: %s", LevelKey, LevelInfo.Key())
}
}
func TestLevel_String(t *testing.T) {
tests := []struct {
name string

@ -254,7 +254,7 @@ func TestServer(t *testing.T) {
}
if test.exceptErr == nil {
if testToken == nil {
t.Errorf("except testToken not nil, but got nil")
t.Fatal("except testToken not nil, but got nil")
}
_, ok := testToken.(jwt.MapClaims)
if !ok {
@ -493,3 +493,26 @@ func TestClientMissKey(t *testing.T) {
}
})
}
func TestNewContextAndFromContext(t *testing.T) {
tests := []struct {
name string
claims jwt.MapClaims
}{
{"val not nil", jwt.MapClaims{"name": "kratos"}},
{"val nil", nil},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
ctx := NewContext(context.Background(), test.claims)
claims, ok := FromContext(ctx)
if !ok {
t.Fatal("ctx not found authKey{}")
}
if !reflect.DeepEqual(test.claims, claims) {
t.Errorf(`want: %s, got: %v`, test.claims, claims)
}
})
}
}

@ -111,7 +111,7 @@ func (d *dummyStringer) String() string {
return "my value"
}
func Test_extractArgs(t *testing.T) {
func TestExtractArgs(t *testing.T) {
if extractArgs(&dummyStringer{field: ""}) != "my value" {
t.Errorf(`The stringified dummyStringer structure must be equal to "my value", %v given`, extractArgs(&dummyStringer{field: ""}))
}
@ -120,3 +120,30 @@ func Test_extractArgs(t *testing.T) {
t.Errorf(`The stringified dummy structure must be equal to "&{field:value}", %v given`, extractArgs(&dummy{field: "value"}))
}
}
func TestExtractError(t *testing.T) {
tests := []struct {
name string
err error
wantLevel log.Level
wantErrStr string
}{
{
"no error", nil, log.LevelInfo, "",
},
{
"error", errors.New("test error"), log.LevelError, "test error",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
level, errStr := extractError(test.err)
if level != test.wantLevel {
t.Errorf("want: %d, got: %d", test.wantLevel, level)
}
if errStr != test.wantErrStr {
t.Errorf("want: %s, got: %s", test.wantErrStr, errStr)
}
})
}
}

@ -51,7 +51,11 @@ func Server(opts ...Option) middleware.Middleware {
}
return func(handler middleware.Handler) middleware.Handler {
return func(ctx context.Context, req interface{}) (reply interface{}, err error) {
if tr, ok := transport.FromServerContext(ctx); ok {
tr, ok := transport.FromServerContext(ctx)
if !ok {
return handler(ctx, req)
}
md := options.md.Clone()
header := tr.RequestHeader()
for _, k := range header.Keys() {
@ -60,7 +64,6 @@ func Server(opts ...Option) middleware.Middleware {
}
}
ctx = metadata.NewServerContext(ctx, md)
}
return handler(ctx, req)
}
}
@ -76,7 +79,11 @@ func Client(opts ...Option) middleware.Middleware {
}
return func(handler middleware.Handler) middleware.Handler {
return func(ctx context.Context, req interface{}) (reply interface{}, err error) {
if tr, ok := transport.FromClientContext(ctx); ok {
tr, ok := transport.FromClientContext(ctx)
if !ok {
return handler(ctx, req)
}
header := tr.RequestHeader()
// x-md-local-
for k, v := range options.md {
@ -95,7 +102,6 @@ func Client(opts ...Option) middleware.Middleware {
}
}
}
}
return handler(ctx, req)
}
}

@ -4,6 +4,7 @@ import (
"context"
"errors"
"net/http"
"reflect"
"testing"
"github.com/go-kratos/kratos/v2/metadata"
@ -33,15 +34,18 @@ func (tr *testTransport) Operation() string { return "" }
func (tr *testTransport) RequestHeader() transport.Header { return tr.header }
func (tr *testTransport) ReplyHeader() transport.Header { return tr.header }
func TestSever(t *testing.T) {
var (
var (
globalKey = "x-md-global-key"
globalValue = "global-value"
localKey = "x-md-local-key"
localValue = "local-value"
customKey = "x-md-local-custom"
customValue = "custom-value"
constKey = "x-md-local-const"
constValue = "x-md-local-const"
)
)
func TestSever(t *testing.T) {
hs := func(ctx context.Context, in interface{}) (interface{}, error) {
md, ok := metadata.FromServerContext(ctx)
if !ok {
@ -75,16 +79,6 @@ func TestSever(t *testing.T) {
}
func TestClient(t *testing.T) {
var (
globalKey = "x-md-global-key"
globalValue = "global-value"
localKey = "x-md-local-key"
localValue = "local-value"
customKey = "x-md-local-custom"
customValue = "custom-value"
constKey = "x-md-local-const"
constValue = "x-md-local-const"
)
hs := func(ctx context.Context, in interface{}) (interface{}, error) {
tr, ok := transport.FromClientContext(ctx)
if !ok {
@ -127,13 +121,52 @@ func TestClient(t *testing.T) {
}
}
func Test_WithPropagatedPrefix(t *testing.T) {
o := &options{
func TestWithConstants(t *testing.T) {
md := metadata.Metadata{
constKey: constValue,
}
options := &options{
md: metadata.Metadata{
"override": "override",
},
}
WithConstants(md)(options)
if !reflect.DeepEqual(md, options.md) {
t.Errorf("want: %v, got: %v", md, options.md)
}
}
func TestOptions_WithPropagatedPrefix(t *testing.T) {
options := &options{
prefix: []string{"override"},
}
WithPropagatedPrefix("something", "another")(o)
prefixes := []string{"something", "another"}
if len(o.prefix) != 2 {
WithPropagatedPrefix(prefixes...)(options)
if !reflect.DeepEqual(prefixes, options.prefix) {
t.Error("The prefix must be overridden.")
}
}
func TestOptions_hasPrefix(t *testing.T) {
tests := []struct {
name string
options *options
key string
exists bool
}{
{"exists key upper", &options{prefix: []string{"prefix"}}, "PREFIX_true", true},
{"exists key lower", &options{prefix: []string{"prefix"}}, "prefix_true", true},
{"not exists key upper", &options{prefix: []string{"prefix"}}, "false_PREFIX", false},
{"not exists key lower", &options{prefix: []string{"prefix"}}, "false_prefix", false},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
exists := test.options.hasPrefix(test.key)
if test.exists != exists {
t.Errorf("key: '%sr', not exists prefixs: %v", test.key, test.options.prefix)
}
})
}
}

@ -4,6 +4,7 @@ import (
"container/list"
"context"
"math"
"net"
"sync"
"sync/atomic"
"time"
@ -158,8 +159,9 @@ func (n *Node) Pick() selector.DoneFunc {
if n.errHandler != nil && n.errHandler(di.Err) {
success = 0
}
var netErr net.Error
if errors.Is(context.DeadlineExceeded, di.Err) || errors.Is(context.Canceled, di.Err) ||
errors.IsServiceUnavailable(di.Err) || errors.IsGatewayTimeout(di.Err) {
errors.IsServiceUnavailable(di.Err) || errors.IsGatewayTimeout(di.Err) || errors.As(di.Err, &netErr) {
success = 0
}
}

@ -2,6 +2,7 @@ package ewma
import (
"context"
"net"
"reflect"
"testing"
"time"
@ -100,11 +101,15 @@ func TestDirectErrorHandler(t *testing.T) {
Endpoints: []string{"http://127.0.0.1:9090"},
Metadata: map[string]string{"weight": "10"},
}))
errs := []error{
context.DeadlineExceeded,
context.Canceled,
net.ErrClosed,
}
for i := 0; i < 5; i++ {
var err error
if i != 0 {
err = context.DeadlineExceeded
err = errs[i%len(errs)]
}
done := wn.Pick()
if done == nil {

@ -1,13 +1,13 @@
package grpc
import (
"github.com/go-kratos/kratos/v2/registry"
"github.com/go-kratos/kratos/v2/selector"
"github.com/go-kratos/kratos/v2/transport"
"google.golang.org/grpc/balancer"
"google.golang.org/grpc/balancer/base"
"google.golang.org/grpc/metadata"
"github.com/go-kratos/kratos/v2/registry"
"github.com/go-kratos/kratos/v2/selector"
"github.com/go-kratos/kratos/v2/transport"
)
const (
@ -15,8 +15,8 @@ const (
)
var (
_ base.PickerBuilder = &balancerBuilder{}
_ balancer.Picker = &balancerPicker{}
_ base.PickerBuilder = (*balancerBuilder)(nil)
_ balancer.Picker = (*balancerPicker)(nil)
)
func init() {

@ -96,7 +96,7 @@ func TestBindForm(t *testing.T) {
{
name: "error not nil",
args: args{
req: &http.Request{Method: "POST"},
req: &http.Request{Method: http.MethodPost},
target: &p1,
},
wantErr: true,
@ -106,7 +106,7 @@ func TestBindForm(t *testing.T) {
name: "error is nil",
args: args{
req: &http.Request{
Method: "POST",
Method: http.MethodPost,
Header: http.Header{"Content-Type": {"application/x-www-form-urlencoded; param=value"}},
Body: io.NopCloser(strings.NewReader("name=kratos&url=https://go-kratos.dev/")),
},
@ -119,7 +119,7 @@ func TestBindForm(t *testing.T) {
name: "error BadRequest",
args: args{
req: &http.Request{
Method: "POST",
Method: http.MethodPost,
Header: http.Header{"Content-Type": {"application/x-www-form-urlencoded; param=value"}},
Body: io.NopCloser(strings.NewReader("age=a")),
},

@ -9,6 +9,7 @@ import (
"fmt"
"io"
"log"
"net/http"
nethttp "net/http"
"reflect"
"strconv"
@ -348,18 +349,18 @@ func TestNewClient(t *testing.T) {
t.Error(err)
}
err = client.Invoke(context.Background(), "POST", "/go", map[string]string{"name": "kratos"}, nil, EmptyCallOption{}, &mockCallOption{})
err = client.Invoke(context.Background(), http.MethodPost, "/go", map[string]string{"name": "kratos"}, nil, EmptyCallOption{}, &mockCallOption{})
if err == nil {
t.Error("err should not be equal to nil")
}
err = client.Invoke(context.Background(), "POST", "/go", map[string]string{"name": "kratos"}, nil, EmptyCallOption{}, &mockCallOption{needErr: true})
err = client.Invoke(context.Background(), http.MethodPost, "/go", map[string]string{"name": "kratos"}, nil, EmptyCallOption{}, &mockCallOption{needErr: true})
if err == nil {
t.Error("err should be equal to callOption err")
}
client.opts.encoder = func(ctx context.Context, contentType string, in interface{}) (body []byte, err error) {
return nil, errors.New("mock test encoder error")
}
err = client.Invoke(context.Background(), "POST", "/go", map[string]string{"name": "kratos"}, nil, EmptyCallOption{})
err = client.Invoke(context.Background(), http.MethodPost, "/go", map[string]string{"name": "kratos"}, nil, EmptyCallOption{})
if err == nil {
t.Error("err should be equal to encoder error")
}

@ -30,7 +30,7 @@ func TestContextHeader(t *testing.T) {
func TestContextForm(t *testing.T) {
w := wrapper{
router: testRouter,
req: &http.Request{Header: map[string][]string{"name": {"kratos"}}, Method: "POST"},
req: &http.Request{Header: map[string][]string{"name": {"kratos"}}, Method: http.MethodPost},
res: nil,
w: responseWriter{},
}
@ -54,7 +54,7 @@ func TestContextForm(t *testing.T) {
func TestContextQuery(t *testing.T) {
w := wrapper{
router: testRouter,
req: &http.Request{URL: &url.URL{Scheme: "https", Host: "github.com", Path: "go-kratos/kratos", RawQuery: "page=1"}, Method: "POST"},
req: &http.Request{URL: &url.URL{Scheme: "https", Host: "github.com", Path: "go-kratos/kratos", RawQuery: "page=1"}, Method: http.MethodPost},
res: nil,
w: responseWriter{},
}
@ -65,7 +65,7 @@ func TestContextQuery(t *testing.T) {
}
func TestContextRequest(t *testing.T) {
req := &http.Request{Method: "POST"}
req := &http.Request{Method: http.MethodPost}
w := wrapper{
router: testRouter,
req: req,
@ -82,7 +82,7 @@ func TestContextResponse(t *testing.T) {
res := httptest.NewRecorder()
w := wrapper{
router: &Router{srv: &Server{enc: DefaultResponseEncoder}},
req: &http.Request{Method: "POST"},
req: &http.Request{Method: http.MethodPost},
res: res,
w: responseWriter{200, res},
}
@ -173,7 +173,7 @@ func TestContextResponseReturn(t *testing.T) {
func TestContextCtx(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
req := &http.Request{Method: "POST"}
req := &http.Request{Method: http.MethodPost}
req = req.WithContext(ctx)
w := wrapper{
router: testRouter,

@ -1,6 +1,7 @@
package http
import (
"net/http"
"net/http/httptest"
"testing"
)
@ -10,7 +11,7 @@ func TestRedirect(t *testing.T) {
redirectURL = "/redirect"
redirectCode = 302
)
r := httptest.NewRequest("POST", "/test", nil)
r := httptest.NewRequest(http.MethodPost, "/test", nil)
w := httptest.NewRecorder()
_ = DefaultResponseEncoder(w, r, NewRedirect(redirectURL, redirectCode))

@ -136,7 +136,7 @@ func testRoute(t *testing.T, srv *Server) {
t.Fatalf("got %s want bar", u.Name)
}
// PUT
req, _ := http.NewRequest("PUT", base+"/users", strings.NewReader(`{"name":"bar"}`))
req, _ := http.NewRequest(http.MethodPut, base+"/users", strings.NewReader(`{"name":"bar"}`))
req.Header.Set("Content-Type", appJSONStr)
resp, err = http.DefaultClient.Do(req)
if err != nil {
@ -157,7 +157,7 @@ func testRoute(t *testing.T, srv *Server) {
t.Fatalf("got %s want bar", u.Name)
}
// OPTIONS
req, _ = http.NewRequest("OPTIONS", base+"/users", nil)
req, _ = http.NewRequest(http.MethodOptions, base+"/users", nil)
resp, err = http.DefaultClient.Do(req)
if err != nil {
t.Fatal(err)
@ -166,7 +166,7 @@ func testRoute(t *testing.T, srv *Server) {
if resp.StatusCode != 200 {
t.Fatalf("code: %d", resp.StatusCode)
}
if resp.Header.Get("Access-Control-Allow-Methods") != "OPTIONS" {
if resp.Header.Get("Access-Control-Allow-Methods") != http.MethodOptions {
t.Fatal("cors failed")
}
}

@ -128,6 +128,13 @@ func Listener(lis net.Listener) ServerOption {
}
}
// PathPrefix with mux's PathPrefix, router will replaced by a subrouter that start with prefix.
func PathPrefix(prefix string) ServerOption {
return func(s *Server) {
s.router = s.router.PathPrefix(prefix).Subrouter()
}
}
// Server is an HTTP server wrapper.
type Server struct {
*http.Server
@ -162,11 +169,12 @@ func NewServer(opts ...ServerOption) *Server {
enc: DefaultResponseEncoder,
ene: DefaultErrorEncoder,
strictSlash: true,
router: mux.NewRouter(),
}
for _, o := range opts {
o(srv)
}
srv.router = mux.NewRouter().StrictSlash(srv.strictSlash)
srv.router.StrictSlash(srv.strictSlash)
srv.router.NotFoundHandler = http.DefaultServeMux
srv.router.MethodNotAllowedHandler = http.DefaultServeMux
srv.router.Use(srv.filter())

@ -117,8 +117,8 @@ func testAccept(t *testing.T, srv *Server) {
path string
contentType string
}{
{"GET", "/errors/cause", "application/json"},
{"GET", "/errors/cause", "application/proto"},
{http.MethodGet, "/errors/cause", "application/json"},
{http.MethodGet, "/errors/cause", "application/proto"},
}
e, err := srv.Endpoint()
if err != nil {
@ -154,7 +154,7 @@ func testHeader(t *testing.T, srv *Server) {
t.Errorf("expected nil got %v", err)
}
reqURL := fmt.Sprintf(e.String() + "/index")
req, err := http.NewRequest("GET", reqURL, nil)
req, err := http.NewRequest(http.MethodGet, reqURL, nil)
if err != nil {
t.Errorf("expected nil got %v", err)
}
@ -172,21 +172,21 @@ func testClient(t *testing.T, srv *Server) {
path string
code int
}{
{"GET", "/index", http.StatusOK},
{"PUT", "/index", http.StatusOK},
{"POST", "/index", http.StatusOK},
{"PATCH", "/index", http.StatusOK},
{"DELETE", "/index", http.StatusOK},
{http.MethodGet, "/index", http.StatusOK},
{http.MethodPut, "/index", http.StatusOK},
{http.MethodPost, "/index", http.StatusOK},
{http.MethodPatch, "/index", http.StatusOK},
{http.MethodDelete, "/index", http.StatusOK},
{"GET", "/index/1", http.StatusOK},
{"PUT", "/index/1", http.StatusOK},
{"POST", "/index/1", http.StatusOK},
{"PATCH", "/index/1", http.StatusOK},
{"DELETE", "/index/1", http.StatusOK},
{http.MethodGet, "/index/1", http.StatusOK},
{http.MethodPut, "/index/1", http.StatusOK},
{http.MethodPost, "/index/1", http.StatusOK},
{http.MethodPatch, "/index/1", http.StatusOK},
{http.MethodDelete, "/index/1", http.StatusOK},
{"GET", "/index/notfound", http.StatusNotFound},
{"GET", "/errors/cause", http.StatusBadRequest},
{"GET", "/test/prefix/123111", http.StatusOK},
{http.MethodGet, "/index/notfound", http.StatusNotFound},
{http.MethodGet, "/errors/cause", http.StatusBadRequest},
{http.MethodGet, "/test/prefix/123111", http.StatusOK},
}
e, err := srv.Endpoint()
if err != nil {
@ -273,7 +273,7 @@ func BenchmarkServer(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
var res testData
err := client.Invoke(context.Background(), "POST", "/index", nil, &res)
err := client.Invoke(context.Background(), http.MethodPost, "/index", nil, &res)
if err != nil {
b.Errorf("expected nil got %v", err)
}

@ -1,4 +1,4 @@
package kratos
// Release is the current kratos version.
const Release = "v2.5.1"
const Release = "v2.5.2"

Loading…
Cancel
Save