Repository: go-kratos/kratos
Pull request #1993 (2022-05-18 05:57:29)

feat: Added ability to configure protojson
use kratos with watch apollo config.
add a new config item in apollo server,after publish ,kartos config watch works,but UnmarshalOptions.DiscardUnknown default is false,so scan will failed.

codecov-commenter: # [Codecov](https://codecov.io/gh/go-kratos/kratos/pull/1993?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-kratos) Report
> Merging [#1993](https://codecov.io/gh/go-kratos/kratos/pull/1993?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-kratos) (ae6df9c) into [main](https://codecov.io/gh/go-kratos/kratos/commit/c8c870b77f70d545367fb77ec638dac8dc6543fa?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-kratos) (c8c870b) will **decrease** coverage by `0.05%`.
> The diff coverage is `66.66%`.

```diff
@@            Coverage Diff             @@
##             main    #1993      +/-   ##
==========================================
- Coverage   80.74%   80.68%   -0.06%     
==========================================
  Files          82       82              
  Lines        3640     3640              
==========================================
- Hits         2939     2937       -2     
- Misses        493      495       +2     
  Partials      208      208              
```


| [Impacted Files](https://codecov.io/gh/go-kratos/kratos/pull/1993?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-kratos) | Coverage Δ | |
|---|---|---|
| [config/value.go](https://codecov.io/gh/go-kratos/kratos/pull/1993/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-kratos#diff-Y29uZmlnL3ZhbHVlLmdv) | `68.23% <66.66%> (ø)` | |
| [internal/context/context.go](https://codecov.io/gh/go-kratos/kratos/pull/1993/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-kratos#diff-aW50ZXJuYWwvY29udGV4dC9jb250ZXh0Lmdv) | `97.01% <0.00%> (-2.99%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/go-kratos/kratos/pull/1993?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-kratos).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-kratos)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/go-kratos/kratos/pull/1993?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-kratos). Last update [c8c870b...ae6df9c](https://codecov.io/gh/go-kratos/kratos/pull/1993?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-kratos). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-kratos).


Patch:
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index f2bb809a..4e4e2061 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -3,22 +3,8 @@
 
 1. If this is your first time contributing to Kratos, please read our contribution guide: https://go-kratos.dev/en/docs/community/contribution/
 2. Ensure you have added or ran the appropriate tests and lint for your PR, please use `make lint` and `make test` before filing your PR, use `make clean` to tidy your go mod.
-3. If the PR is unfinished, you may need mark it as a WIP(Work In Progress) PR or draft PR
-4. Please use a conventional commits format title: `<type>[optional scope]: <description>`
-    
-    Some suggestion on <type>:
-
-    fix: A bug fix
-    feat: A new feature
-    test: Adding missing tests or correcting existing tests
-    refactor: A code change that neither fixes a bug nor adds a feature
-    break: Changes has break change
-
-    docs: Documentation only changes
-    deps: Changes external dependencies
-    style: Changes that do not affect the meaning of the code (white-space, formatting, etc)
-    chore Daily work, examples, etc.
-    ci: Changes to our CI configuration files and scripts
+3. If the PR is unfinished, you may need to mark it as a WIP(Work In Progress) PR or draft PR
+4. Please use a semantic commits format title, such as `<type>[optional scope]: <description>`, see: https://go-kratos.dev/docs/community/contribution#type
 -->
 
 #### Description (what this PR does / why we need it):
@@ -30,14 +16,14 @@
 #### Which issue(s) this PR fixes (resolves / be part of):
 <!--
 * Automatically closes linked issue when PR is merged.
-* If you PR is not fully resolved issue, please use `part of #<issue number>` instead.
+* If your PR is not fully resolved the issue, please use `part of #<issue number>` instead.
 
 Usage: `fixes/resolves #<issue number>`, or `fixes/resolves (paste link of issue)`.
 -->
-fixes #
 
-#### Other special notes for reviewer:
+
+#### Other special notes for the reviewers:
 <!--
-* Somethings that need extra attention for reviewer
+* Somethings that need extra attention for the reviewers
 * Some additional notes, TODO list, etc.
--->
+-->
\ No newline at end of file
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 4d5c5f2f..c1cf783e 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -13,7 +13,7 @@ jobs:
   build:
     strategy:
       matrix:
-        go: [ 1.16, 1.17, 1.18 ]
+        go: [1.16, 1.17, 1.18]
     name: build & test
     runs-on: ubuntu-latest
     services:
@@ -36,7 +36,7 @@ jobs:
           - "8848:8848"
           - "9848:9848"
       polaris:
-        image: huyuanxin/polaris-server-with-config:latest
+        image: houseme/polaris-server-with-config:latest
         ports:
           - 8090:8090
           - 8091:8091
diff --git a/.golangci.yml b/.golangci.yml
index 0cd7ecb0..441db5ee 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -65,4 +65,4 @@ linters-settings:
     ignore-tests: true
   gocyclo:
     # recommend 10-20
-    min-complexity: 30
+    min-complexity: 50
diff --git a/cmd/protoc-gen-go-http/http.go b/cmd/protoc-gen-go-http/http.go
index eb3fa89e..fca4a63c 100644
--- a/cmd/protoc-gen-go-http/http.go
+++ b/cmd/protoc-gen-go-http/http.go
@@ -192,13 +192,14 @@ func buildMethodDesc(g *protogen.GeneratedFile, m *protogen.Method, method, path
 		}
 	}
 	return &methodDesc{
-		Name:    m.GoName,
-		Num:     methodSets[m.GoName],
-		Request: g.QualifiedGoIdent(m.Input.GoIdent),
-		Reply:   g.QualifiedGoIdent(m.Output.GoIdent),
-		Path:    path,
-		Method:  method,
-		HasVars: len(vars) > 0,
+		Name:         m.GoName,
+		OriginalName: string(m.Desc.Name()),
+		Num:          methodSets[m.GoName],
+		Request:      g.QualifiedGoIdent(m.Input.GoIdent),
+		Reply:        g.QualifiedGoIdent(m.Output.GoIdent),
+		Path:         path,
+		Method:       method,
+		HasVars:      len(vars) > 0,
 	}
 }
 
diff --git a/cmd/protoc-gen-go-http/template.go b/cmd/protoc-gen-go-http/template.go
index 50671e57..d2ffcd41 100644
--- a/cmd/protoc-gen-go-http/template.go
+++ b/cmd/protoc-gen-go-http/template.go
@@ -46,7 +46,7 @@ func _{{$svrType}}_{{.Name}}{{.Num}}_HTTP_Handler(srv {{$svrType}}HTTPServer) fu
 			return err
 		}
 		{{- end}}
-		http.SetOperation(ctx,"/{{$svrName}}/{{.Name}}")
+		http.SetOperation(ctx,"/{{$svrName}}/{{.OriginalName}}")
 		h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) {
 			return srv.{{.Name}}(ctx, req.(*{{.Request}}))
 		})
@@ -79,7 +79,7 @@ func (c *{{$svrType}}HTTPClientImpl) {{.Name}}(ctx context.Context, in *{{.Reque
 	var out {{.Reply}}
 	pattern := "{{.Path}}"
 	path := binding.EncodeURL(pattern, in, {{not .HasBody}})
-	opts = append(opts, http.Operation("/{{$svrName}}/{{.Name}}"))
+	opts = append(opts, http.Operation("/{{$svrName}}/{{.OriginalName}}"))
 	opts = append(opts, http.PathTemplate(pattern))
 	{{if .HasBody -}}
 	err := c.cc.Invoke(ctx, "{{.Method}}", path, in{{.Body}}, &out{{.ResponseBody}}, opts...)
@@ -104,10 +104,11 @@ type serviceDesc struct {
 
 type methodDesc struct {
 	// method
-	Name    string
-	Num     int
-	Request string
-	Reply   string
+	Name         string
+	OriginalName string // The parsed original name
+	Num          int
+	Request      string
+	Reply        string
 	// http_rule
 	Path         string
 	Method       string
diff --git a/config/value.go b/config/value.go
index d31bd86a..04c1c0eb 100644
--- a/config/value.go
+++ b/config/value.go
@@ -1,15 +1,16 @@
 package config
 
 import (
-	"encoding/json"
+	stdjson "encoding/json"
 	"fmt"
 	"reflect"
 	"strconv"
 	"sync/atomic"
 	"time"
 
-	"google.golang.org/protobuf/encoding/protojson"
 	"google.golang.org/protobuf/proto"
+
+	"github.com/go-kratos/kratos/v2/encoding/json"
 )
 
 var (
@@ -128,14 +129,14 @@ func (v *atomicValue) Duration() (time.Duration, error) {
 }
 
 func (v *atomicValue) Scan(obj interface{}) error {
-	data, err := json.Marshal(v.Load())
+	data, err := stdjson.Marshal(v.Load())
 	if err != nil {
 		return err
 	}
 	if pb, ok := obj.(proto.Message); ok {
-		return protojson.Unmarshal(data, pb)
+		return json.UnmarshalOptions.Unmarshal(data, pb)
 	}
-	return json.Unmarshal(data, obj)
+	return stdjson.Unmarshal(data, obj)
 }
 
 type errValue struct {
diff --git a/encoding/form/proto_decode.go b/encoding/form/proto_decode.go
index 8b4b3159..9e31e3ba 100644
--- a/encoding/form/proto_decode.go
+++ b/encoding/form/proto_decode.go
@@ -283,7 +283,9 @@ func parseMessage(md protoreflect.MessageDescriptor, value string) (protoreflect
 	case "google.protobuf.BytesValue":
 		v, err := base64.StdEncoding.DecodeString(value)
 		if err != nil {
-			return protoreflect.Value{}, err
+			if v, err = base64.URLEncoding.DecodeString(value); err != nil {
+				return protoreflect.Value{}, err
+			}
 		}
 		msg = wrapperspb.Bytes(v)
 	case "google.protobuf.FieldMask":
diff --git a/transport/http/resolver.go b/transport/http/resolver.go
index 6a264cb3..6bb1c3ff 100644
--- a/transport/http/resolver.go
+++ b/transport/http/resolver.go
@@ -79,17 +79,17 @@ func newResolver(ctx context.Context, discovery registry.Discovery, target *Targ
 		select {
 		case err := <-done:
 			if err != nil {
-				err := watcher.Stop()
-				if err != nil {
-					r.logger.Errorf("failed to http client watch stop: %v", target)
+				stopErr := watcher.Stop()
+				if stopErr != nil {
+					r.logger.Errorf("failed to http client watch stop: %v, error: %+v", target, stopErr)
 				}
 				return nil, err
 			}
 		case <-ctx.Done():
 			r.logger.Errorf("http client watch service %v reaching context deadline!", target)
-			err := watcher.Stop()
-			if err != nil {
-				r.logger.Errorf("failed to http client watch stop: %v", target)
+			stopErr := watcher.Stop()
+			if stopErr != nil {
+				r.logger.Errorf("failed to http client watch stop: %v, error: %+v", target, stopErr)
 			}
 			return nil, ctx.Err()
 		}


Test patch:
diff --git a/contrib/registry/consul/registry_test.go b/contrib/registry/consul/registry_test.go
index 82b7b041..e6b85e7d 100644
--- a/contrib/registry/consul/registry_test.go
+++ b/contrib/registry/consul/registry_test.go
@@ -57,10 +57,6 @@ func TestRegister(t *testing.T) {
 	}
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
 	defer cancel()
-	err = r.Deregister(ctx, svc)
-	if err != nil {
-		t.Errorf("Deregister failed: %v", err)
-	}
 	err = r.Register(ctx, svc)
 	if err != nil {
 		t.Errorf("Register failed: %v", err)
@@ -86,6 +82,10 @@ func TestRegister(t *testing.T) {
 	if !reflect.DeepEqual(version, services[0].Version) {
 		t.Errorf("no expect float_key value: %v, but got: %v", services[0].Version, version)
 	}
+	err = r.Deregister(ctx, svc)
+	if err != nil {
+		t.Errorf("Deregister failed: %v", err)
+	}
 }
 
 func getIntranetIP() string {
diff --git a/contrib/registry/polaris/registry_test.go b/contrib/registry/polaris/registry_test.go
index c6cc49f2..d0564051 100644
--- a/contrib/registry/polaris/registry_test.go
+++ b/contrib/registry/polaris/registry_test.go
@@ -5,10 +5,9 @@ import (
 	"testing"
 	"time"
 
-	"github.com/go-kratos/kratos/v2/log"
-
 	"github.com/polarismesh/polaris-go/pkg/config"
 
+	"github.com/go-kratos/kratos/v2/log"
 	"github.com/go-kratos/kratos/v2/registry"
 )
 
diff --git a/encoding/form/form_test.go b/encoding/form/form_test.go
index f437ddf1..384869c5 100644
--- a/encoding/form/form_test.go
+++ b/encoding/form/form_test.go
@@ -1,6 +1,7 @@
 package form
 
 import (
+	"encoding/base64"
 	"reflect"
 	"testing"
 
@@ -178,3 +179,16 @@ func TestDecodeStructPb(t *testing.T) {
 		t.Errorf("except %v, got %v", "go-kratos", req.Data.GetFields()["name2"].GetStringValue())
 	}
 }
+
+func TestDecodeBytesValuePb(t *testing.T) {
+	url := "https://example.com/xx/?a=1&b=2&c=3"
+	val := base64.URLEncoding.EncodeToString([]byte(url))
+	content := "bytes=" + val
+	in2 := &complex.Complex{}
+	if err := encoding.GetCodec(contentType).Unmarshal([]byte(content), in2); err != nil {
+		t.Errorf("expect %v, got %v", nil, err)
+	}
+	if !reflect.DeepEqual(url, string(in2.Bytes.Value)) {
+		t.Errorf("except %v, got %v", val, string(in2.Bytes.Value))
+	}
+}
diff --git a/hack/.test_ignored_files b/hack/.test_ignored_files
index 52d736ef..c33d3f4f 100644
--- a/hack/.test_ignored_files
+++ b/hack/.test_ignored_files
@@ -5,6 +5,4 @@
 ./contrib/config/kubernetes
 ./contrib/registry/kubernetes
 ./contrib/registry/zookeeper
-./contrib/registry/etcd
-./contrib/registry/consul
 ./contrib/registry/eureka
diff --git a/transport/http/resolver_test.go b/transport/http/resolver_test.go
index 5a214ad9..419bae44 100644
--- a/transport/http/resolver_test.go
+++ b/transport/http/resolver_test.go
@@ -77,10 +77,10 @@ type mockWatch struct {
 }
 
 func (m *mockWatch) Next() ([]*registry.ServiceInstance, error) {
-	m.count++
 	if m.count == 1 {
 		return nil, errors.New("mock test error")
 	}
+	m.count++
 	instance := &registry.ServiceInstance{
 		ID:        "1",
 		Name:      "kratos",