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. 5
      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. 63
      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: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v3.3.0 uses: actions/setup-go@v3.3.1
with: with:
go-version: ${{ matrix.go }} go-version: ${{ matrix.go }}

@ -7,6 +7,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"sort"
"sync" "sync"
"google.golang.org/grpc" "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)) reply.Methods = append(reply.Methods, fmt.Sprintf("/%s/%s", name, method))
} }
} }
sort.Strings(reply.Services)
sort.Strings(reply.Methods)
return reply, nil return reply, nil
} }

@ -8,7 +8,7 @@ import (
) )
var ( 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"} 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" { if version != "latest" {
api = fmt.Sprintf("https://api.github.com/repos/%s/%s/releases/tags/%s", g.Owner, g.Repo, version) 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 { if code != http.StatusOK {
printGithubErrorInfo(resp) printGithubErrorInfo(resp)
} }
@ -63,7 +63,7 @@ func (g *GithubAPI) GetCommitsInfo() []CommitInfo {
var list []CommitInfo var list []CommitInfo
for { 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) 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 { if code != http.StatusOK {
printGithubErrorInfo(resp) printGithubErrorInfo(resp)
} }

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

@ -1,4 +1,4 @@
package main package main
// release is the current protoc-gen-go-errors version. // 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 ( import (
"fmt" "fmt"
"net/http"
"os" "os"
"regexp" "regexp"
"strings" "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)) sd.Methods = append(sd.Methods, buildHTTPRule(g, method, rule))
} else if !omitempty { } else if !omitempty {
path := fmt.Sprintf("/%s/%s", service.Desc.FullName(), method.Desc.Name()) 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 { if len(sd.Methods) != 0 {
@ -119,19 +120,19 @@ func buildHTTPRule(g *protogen.GeneratedFile, m *protogen.Method, rule *annotati
switch pattern := rule.Pattern.(type) { switch pattern := rule.Pattern.(type) {
case *annotations.HttpRule_Get: case *annotations.HttpRule_Get:
path = pattern.Get path = pattern.Get
method = "GET" method = http.MethodGet
case *annotations.HttpRule_Put: case *annotations.HttpRule_Put:
path = pattern.Put path = pattern.Put
method = "PUT" method = http.MethodPut
case *annotations.HttpRule_Post: case *annotations.HttpRule_Post:
path = pattern.Post path = pattern.Post
method = "POST" method = http.MethodPost
case *annotations.HttpRule_Delete: case *annotations.HttpRule_Delete:
path = pattern.Delete path = pattern.Delete
method = "DELETE" method = http.MethodDelete
case *annotations.HttpRule_Patch: case *annotations.HttpRule_Patch:
path = pattern.Patch path = pattern.Patch
method = "PATCH" method = http.MethodPatch
case *annotations.HttpRule_Custom: case *annotations.HttpRule_Custom:
path = pattern.Custom.Path path = pattern.Custom.Path
method = pattern.Custom.Kind method = pattern.Custom.Kind
@ -139,7 +140,7 @@ func buildHTTPRule(g *protogen.GeneratedFile, m *protogen.Method, rule *annotati
body = rule.Body body = rule.Body
responseBody = rule.ResponseBody responseBody = rule.ResponseBody
md := buildMethodDesc(g, m, method, path) md := buildMethodDesc(g, m, method, path)
if method == "GET" || method == "DELETE" { if method == http.MethodGet || method == http.MethodDelete {
if body != "" { if body != "" {
_, _ = fmt.Fprintf(os.Stderr, "\u001B[31mWARN\u001B[m: %s %s body should not be declared.\n", method, path) _, _ = 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, "/") { if strings.HasSuffix(path, "/") {
fmt.Fprintf(os.Stderr, "\u001B[31mWARN\u001B[m: Path %s should not end with \"/\" \n", 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) matches := pattern.FindAllStringSubmatch(path, -1)
res = make(map[string]*string, len(matches)) res = make(map[string]*string, len(matches))
for _, m := range matches { for _, m := range matches {

@ -1,4 +1,4 @@
package main package main
// release is the current protoc-gen-go-http version. // 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 ( import (
"strings" "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"
"github.com/apolloconfig/agollo/v4/constant" "github.com/apolloconfig/agollo/v4/constant"
apolloConfig "github.com/apolloconfig/agollo/v4/env/config" apolloConfig "github.com/apolloconfig/agollo/v4/env/config"
"github.com/apolloconfig/agollo/v4/extension" "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/encoding"
"github.com/go-kratos/kratos/v2/log"
) )
type apollo struct { type apollo struct {

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

@ -2,11 +2,12 @@
```go ```go
import ( import (
"github.com/go-kratos/kratos/contrib/config/consul/v2"
"github.com/hashicorp/consul/api" "github.com/hashicorp/consul/api"
"github.com/go-kratos/kratos/contrib/config/consul/v2"
) )
func main() {
func main() {
consulClient, err := api.NewClient(&api.Config{ consulClient, err := api.NewClient(&api.Config{
Address: "127.0.0.1:8500", Address: "127.0.0.1:8500",
}) })

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

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

@ -2,9 +2,10 @@
```go ```go
import ( import (
kconfig "github.com/go-kratos/kratos/v2/config"
"github.com/nacos-group/nacos-sdk-go/clients" "github.com/nacos-group/nacos-sdk-go/clients"
"github.com/nacos-group/nacos-sdk-go/common/constant" "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 ( require (
github.com/go-kratos/kratos/v2 v2.4.0 github.com/go-kratos/kratos/v2 v2.4.0
github.com/nacos-group/nacos-sdk-go v1.0.9 github.com/nacos-group/nacos-sdk-go v1.0.9
)
require (
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
) )

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

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

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

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

@ -2,6 +2,7 @@ package aliyun
import ( import (
"math" "math"
"reflect"
"testing" "testing"
"github.com/go-kratos/kratos/v2/log" "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) { func TestToString(t *testing.T) {
tests := []struct { tests := []struct {
name string
in interface{} in interface{}
out string out string
}{ }{
{math.MaxFloat64, "17976931348623157000000000000000000000000000000000000" + {"float64", 6.66, "6.66"},
"000000000000000000000000000000000000000000000000000000000000000000000000000" + {"max float64", math.MaxFloat64, "179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}, //nolint:lll
"000000000000000000000000000000000000000000000000000000000000000000000000000" + {"float32", float32(6.66), "6.66"},
"000000000000000000000000000000000000000000000000000000000000000000000000000" + {"max float32", math.MaxFloat32, "340282346638528860000000000000000000000"},
"0000000000000000000000000000000"}, {"int", int(math.MaxInt64), "9223372036854775807"},
{math.MaxFloat32, "340282346638528860000000000000000000000"}, {"uint", uint(math.MaxUint64), "18446744073709551615"},
{1<<((32<<(^uint(0)>>63))-1) - 1, "9223372036854775807"}, {"int8", math.MaxInt8, "127"},
{uint(1<<(32<<(^uint(0)>>63)) - 1), "-1"}, {"uint8", math.MaxUint8, "255"},
{math.MaxInt8, "127"}, {"int16", math.MaxInt16, "32767"},
{math.MaxUint8, "255"}, {"uint16", math.MaxUint16, "65535"},
{math.MaxInt16, "32767"}, {"int32", math.MaxInt32, "2147483647"},
{math.MaxUint16, "65535"}, {"uint32", math.MaxUint32, "4294967295"},
{math.MaxInt32, "2147483647"}, {"int64", math.MaxInt64, "9223372036854775807"},
{math.MaxUint32, "4294967295"}, {"uint64", uint64(math.MaxUint64), "18446744073709551615"},
{math.MaxInt64, "9223372036854775807"}, {"string", "abc", "abc"},
{uint64(math.MaxUint64), "18446744073709551615"}, {"bool", false, "false"},
{"abc", "abc"}, {"[]byte", []byte("abc"), "abc"},
{false, "false"}, {"struct", struct{ Name string }{}, `{"Name":""}`},
{[]byte("abc"), "abc"},
} }
for _, test := range tests { for _, test := range tests {
if toString(test.in) != test.out { t.Run(test.name, func(t *testing.T) {
t.Fatalf("want: %s, got: %s", test.out, toString(test.in)) 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 ( require (
github.com/aliyun/aliyun-log-go-sdk v0.1.37 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 google.golang.org/protobuf v1.28.1
) )

@ -11,19 +11,24 @@ import (
) )
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
if ln, err := net.Listen("tcp", ":24224"); err == nil { listener := func(ln net.Listener) {
defer ln.Close()
go func() {
for {
conn, err := ln.Accept() conn, err := ln.Accept()
if err != nil { if err != nil {
return return
} }
defer conn.Close() defer conn.Close()
if _, err = io.ReadAll(conn); err != nil { _, err = io.ReadAll(conn)
continue 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 ( require (
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
github.com/fluent/fluent-logger-golang v1.9.0 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/kr/pretty v0.3.0 // indirect
github.com/tinylib/msgp v1.1.6 // 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 go 1.16
require ( 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 github.com/sirupsen/logrus v1.8.1
) )

@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/log/tencent/v2
go 1.16 go 1.16
require ( 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 github.com/tencentcloud/tencentcloud-cls-sdk-go v1.0.2
google.golang.org/protobuf v1.28.0 google.golang.org/protobuf v1.28.0
) )

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

@ -1,6 +1,8 @@
package tencent package tencent
import ( import (
"math"
"reflect"
"testing" "testing"
"github.com/go-kratos/kratos/v2/log" "github.com/go-kratos/kratos/v2/log"
@ -101,3 +103,45 @@ func TestLog(t *testing.T) {
t.Errorf("Log() returns error:%v", err) 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 go 1.16
require ( 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 go.uber.org/zap v1.23.0
) )

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

@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/metrics/prometheus/v2
go 1.16 go 1.16
require ( 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/client_golang v1.12.2
github.com/prometheus/common v0.37.0 github.com/prometheus/common v0.37.0
) )

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

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

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

@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/registry/consul/v2
go 1.16 go 1.16
require ( 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 github.com/hashicorp/consul/api v1.14.0
) )

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

@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/registry/discovery/v2
go 1.16 go 1.16
require ( 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/go-resty/resty/v2 v2.7.0
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
) )

@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/registry/etcd/v2
go 1.16 go 1.16
require ( 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 go.etcd.io/etcd/client/v3 v3.5.4
google.golang.org/grpc v1.46.2 google.golang.org/grpc v1.46.2
) )

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

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

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

@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/registry/kubernetes/v2
go 1.16 go 1.16
require ( 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 github.com/json-iterator/go v1.1.12
k8s.io/api v0.24.3 k8s.io/api v0.24.3
k8s.io/apimachinery 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 go 1.16
require ( 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 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 go 1.16
require ( 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 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 go 1.16
require ( 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 github.com/go-zookeeper/zk v1.0.3
golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 golang.org/x/sync v0.0.0-20220513210516-0976fa681c29
) )

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

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

@ -2,6 +2,12 @@ package log
import "testing" 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) { func TestLevel_String(t *testing.T) {
tests := []struct { tests := []struct {
name string name string

@ -254,7 +254,7 @@ func TestServer(t *testing.T) {
} }
if test.exceptErr == nil { if test.exceptErr == nil {
if testToken == 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) _, ok := testToken.(jwt.MapClaims)
if !ok { 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" return "my value"
} }
func Test_extractArgs(t *testing.T) { func TestExtractArgs(t *testing.T) {
if extractArgs(&dummyStringer{field: ""}) != "my value" { if extractArgs(&dummyStringer{field: ""}) != "my value" {
t.Errorf(`The stringified dummyStringer structure must be equal to "my value", %v given`, extractArgs(&dummyStringer{field: ""})) 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"})) 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(handler middleware.Handler) middleware.Handler {
return func(ctx context.Context, req interface{}) (reply interface{}, err error) { 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() md := options.md.Clone()
header := tr.RequestHeader() header := tr.RequestHeader()
for _, k := range header.Keys() { for _, k := range header.Keys() {
@ -60,7 +64,6 @@ func Server(opts ...Option) middleware.Middleware {
} }
} }
ctx = metadata.NewServerContext(ctx, md) ctx = metadata.NewServerContext(ctx, md)
}
return handler(ctx, req) return handler(ctx, req)
} }
} }
@ -76,7 +79,11 @@ func Client(opts ...Option) middleware.Middleware {
} }
return func(handler middleware.Handler) middleware.Handler { return func(handler middleware.Handler) middleware.Handler {
return func(ctx context.Context, req interface{}) (reply interface{}, err error) { 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() header := tr.RequestHeader()
// x-md-local- // x-md-local-
for k, v := range options.md { for k, v := range options.md {
@ -95,7 +102,6 @@ func Client(opts ...Option) middleware.Middleware {
} }
} }
} }
}
return handler(ctx, req) return handler(ctx, req)
} }
} }

@ -4,6 +4,7 @@ import (
"context" "context"
"errors" "errors"
"net/http" "net/http"
"reflect"
"testing" "testing"
"github.com/go-kratos/kratos/v2/metadata" "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) RequestHeader() transport.Header { return tr.header }
func (tr *testTransport) ReplyHeader() 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" globalKey = "x-md-global-key"
globalValue = "global-value" globalValue = "global-value"
localKey = "x-md-local-key" localKey = "x-md-local-key"
localValue = "local-value" localValue = "local-value"
customKey = "x-md-local-custom"
customValue = "custom-value"
constKey = "x-md-local-const" constKey = "x-md-local-const"
constValue = "x-md-local-const" constValue = "x-md-local-const"
) )
func TestSever(t *testing.T) {
hs := func(ctx context.Context, in interface{}) (interface{}, error) { hs := func(ctx context.Context, in interface{}) (interface{}, error) {
md, ok := metadata.FromServerContext(ctx) md, ok := metadata.FromServerContext(ctx)
if !ok { if !ok {
@ -75,16 +79,6 @@ func TestSever(t *testing.T) {
} }
func TestClient(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) { hs := func(ctx context.Context, in interface{}) (interface{}, error) {
tr, ok := transport.FromClientContext(ctx) tr, ok := transport.FromClientContext(ctx)
if !ok { if !ok {
@ -127,13 +121,52 @@ func TestClient(t *testing.T) {
} }
} }
func Test_WithPropagatedPrefix(t *testing.T) { func TestWithConstants(t *testing.T) {
o := &options{ 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"}, 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.") 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" "container/list"
"context" "context"
"math" "math"
"net"
"sync" "sync"
"sync/atomic" "sync/atomic"
"time" "time"
@ -158,8 +159,9 @@ func (n *Node) Pick() selector.DoneFunc {
if n.errHandler != nil && n.errHandler(di.Err) { if n.errHandler != nil && n.errHandler(di.Err) {
success = 0 success = 0
} }
var netErr net.Error
if errors.Is(context.DeadlineExceeded, di.Err) || errors.Is(context.Canceled, di.Err) || 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 success = 0
} }
} }

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

@ -1,13 +1,13 @@
package grpc package grpc
import ( 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"
"google.golang.org/grpc/balancer/base" "google.golang.org/grpc/balancer/base"
"google.golang.org/grpc/metadata" "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 ( const (
@ -15,8 +15,8 @@ const (
) )
var ( var (
_ base.PickerBuilder = &balancerBuilder{} _ base.PickerBuilder = (*balancerBuilder)(nil)
_ balancer.Picker = &balancerPicker{} _ balancer.Picker = (*balancerPicker)(nil)
) )
func init() { func init() {

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

@ -9,6 +9,7 @@ import (
"fmt" "fmt"
"io" "io"
"log" "log"
"net/http"
nethttp "net/http" nethttp "net/http"
"reflect" "reflect"
"strconv" "strconv"
@ -348,18 +349,18 @@ func TestNewClient(t *testing.T) {
t.Error(err) 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 { if err == nil {
t.Error("err should not be equal to 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 { if err == nil {
t.Error("err should be equal to callOption err") t.Error("err should be equal to callOption err")
} }
client.opts.encoder = func(ctx context.Context, contentType string, in interface{}) (body []byte, err error) { client.opts.encoder = func(ctx context.Context, contentType string, in interface{}) (body []byte, err error) {
return nil, errors.New("mock test encoder 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 { if err == nil {
t.Error("err should be equal to encoder error") t.Error("err should be equal to encoder error")
} }

@ -30,7 +30,7 @@ func TestContextHeader(t *testing.T) {
func TestContextForm(t *testing.T) { func TestContextForm(t *testing.T) {
w := wrapper{ w := wrapper{
router: testRouter, 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, res: nil,
w: responseWriter{}, w: responseWriter{},
} }
@ -54,7 +54,7 @@ func TestContextForm(t *testing.T) {
func TestContextQuery(t *testing.T) { func TestContextQuery(t *testing.T) {
w := wrapper{ w := wrapper{
router: testRouter, 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, res: nil,
w: responseWriter{}, w: responseWriter{},
} }
@ -65,7 +65,7 @@ func TestContextQuery(t *testing.T) {
} }
func TestContextRequest(t *testing.T) { func TestContextRequest(t *testing.T) {
req := &http.Request{Method: "POST"} req := &http.Request{Method: http.MethodPost}
w := wrapper{ w := wrapper{
router: testRouter, router: testRouter,
req: req, req: req,
@ -82,7 +82,7 @@ func TestContextResponse(t *testing.T) {
res := httptest.NewRecorder() res := httptest.NewRecorder()
w := wrapper{ w := wrapper{
router: &Router{srv: &Server{enc: DefaultResponseEncoder}}, router: &Router{srv: &Server{enc: DefaultResponseEncoder}},
req: &http.Request{Method: "POST"}, req: &http.Request{Method: http.MethodPost},
res: res, res: res,
w: responseWriter{200, res}, w: responseWriter{200, res},
} }
@ -173,7 +173,7 @@ func TestContextResponseReturn(t *testing.T) {
func TestContextCtx(t *testing.T) { func TestContextCtx(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second) ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel() defer cancel()
req := &http.Request{Method: "POST"} req := &http.Request{Method: http.MethodPost}
req = req.WithContext(ctx) req = req.WithContext(ctx)
w := wrapper{ w := wrapper{
router: testRouter, router: testRouter,

@ -1,6 +1,7 @@
package http package http
import ( import (
"net/http"
"net/http/httptest" "net/http/httptest"
"testing" "testing"
) )
@ -10,7 +11,7 @@ func TestRedirect(t *testing.T) {
redirectURL = "/redirect" redirectURL = "/redirect"
redirectCode = 302 redirectCode = 302
) )
r := httptest.NewRequest("POST", "/test", nil) r := httptest.NewRequest(http.MethodPost, "/test", nil)
w := httptest.NewRecorder() w := httptest.NewRecorder()
_ = DefaultResponseEncoder(w, r, NewRedirect(redirectURL, redirectCode)) _ = 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) t.Fatalf("got %s want bar", u.Name)
} }
// PUT // 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) req.Header.Set("Content-Type", appJSONStr)
resp, err = http.DefaultClient.Do(req) resp, err = http.DefaultClient.Do(req)
if err != nil { if err != nil {
@ -157,7 +157,7 @@ func testRoute(t *testing.T, srv *Server) {
t.Fatalf("got %s want bar", u.Name) t.Fatalf("got %s want bar", u.Name)
} }
// OPTIONS // OPTIONS
req, _ = http.NewRequest("OPTIONS", base+"/users", nil) req, _ = http.NewRequest(http.MethodOptions, base+"/users", nil)
resp, err = http.DefaultClient.Do(req) resp, err = http.DefaultClient.Do(req)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -166,7 +166,7 @@ func testRoute(t *testing.T, srv *Server) {
if resp.StatusCode != 200 { if resp.StatusCode != 200 {
t.Fatalf("code: %d", resp.StatusCode) 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") 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. // Server is an HTTP server wrapper.
type Server struct { type Server struct {
*http.Server *http.Server
@ -162,11 +169,12 @@ func NewServer(opts ...ServerOption) *Server {
enc: DefaultResponseEncoder, enc: DefaultResponseEncoder,
ene: DefaultErrorEncoder, ene: DefaultErrorEncoder,
strictSlash: true, strictSlash: true,
router: mux.NewRouter(),
} }
for _, o := range opts { for _, o := range opts {
o(srv) o(srv)
} }
srv.router = mux.NewRouter().StrictSlash(srv.strictSlash) srv.router.StrictSlash(srv.strictSlash)
srv.router.NotFoundHandler = http.DefaultServeMux srv.router.NotFoundHandler = http.DefaultServeMux
srv.router.MethodNotAllowedHandler = http.DefaultServeMux srv.router.MethodNotAllowedHandler = http.DefaultServeMux
srv.router.Use(srv.filter()) srv.router.Use(srv.filter())

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

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

Loading…
Cancel
Save