Skip to content

Commit

Permalink
Add default method config support
Browse files Browse the repository at this point in the history
  • Loading branch information
amenzhinsky committed Jun 12, 2020
1 parent 6f5ecbe commit 5c57934
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 10 deletions.
12 changes: 7 additions & 5 deletions clientconn.go
Expand Up @@ -871,12 +871,14 @@ func (cc *ClientConn) GetMethodConfig(method string) MethodConfig {
if cc.sc == nil {
return MethodConfig{}
}
m, ok := cc.sc.Methods[method]
if !ok {
i := strings.LastIndex(method, "/")
m = cc.sc.Methods[method[:i+1]]
if m, ok := cc.sc.Methods[method]; ok {
return m
}
return m
i := strings.LastIndex(method, "/")
if m, ok := cc.sc.Methods[method[:i+1]]; ok {
return m
}
return cc.sc.Methods[""]
}

func (cc *ClientConn) healthCheckConfig() *healthCheckConfig {
Expand Down
23 changes: 23 additions & 0 deletions clientconn_test.go
Expand Up @@ -782,6 +782,29 @@ func (s) TestDisableServiceConfigOption(t *testing.T) {
}
}

func (s) TestMethodConfigDefaultService(t *testing.T) {
addr := "nonexist:///non.existent"
cc, err := Dial(addr, WithInsecure(), WithDefaultServiceConfig(`{
"methodConfig": [{
"name": [
{
"service": ""
}
],
"waitForReady": true
}]
}`))
if err != nil {
t.Fatalf("Dial(%s, _) = _, %v, want _, <nil>", addr, err)
}
defer cc.Close()

m := cc.GetMethodConfig("/foo/Bar")
if m.WaitForReady == nil {
t.Fatalf("want: method (%q) config to fallback to the default service", "/foo/Bar")
}
}

func (s) TestGetClientConnTarget(t *testing.T) {
addr := "nonexist:///non.existent"
cc, err := Dial(addr, WithInsecure())
Expand Down
33 changes: 28 additions & 5 deletions service_config.go
Expand Up @@ -20,6 +20,7 @@ package grpc

import (
"encoding/json"
"errors"
"fmt"
"reflect"
"strconv"
Expand Down Expand Up @@ -229,15 +230,22 @@ type jsonName struct {
Method *string
}

func (j jsonName) generatePath() (string, bool) {
func (j jsonName) generatePath() (string, bool, error) {
if j.Service == nil {
return "", false
return "", false, nil
}
if *j.Service == "" {
// when 'service' is empty 'method' must be empty as well
if j.Method != nil && *j.Method != "" {
return "", false, errors.New("cannot combine empty 'service' and non-empty 'method'")
}
return "", true, nil
}
res := "/" + *j.Service + "/"
if j.Method != nil {
res += *j.Method
}
return res, true
return res, true, nil
}

// TODO(lyuxuan): delete this struct after cleaning up old service config implementation.
Expand Down Expand Up @@ -289,6 +297,8 @@ func parseServiceConfig(js string) *serviceconfig.ParseResult {
if rsc.MethodConfig == nil {
return &serviceconfig.ParseResult{Config: &sc}
}

paths := map[string]struct{}{}
for _, m := range *rsc.MethodConfig {
if m.Name == nil {
continue
Expand Down Expand Up @@ -321,8 +331,21 @@ func parseServiceConfig(js string) *serviceconfig.ParseResult {
mc.MaxRespSize = newInt(int(*m.MaxResponseMessageBytes))
}
}
for _, n := range *m.Name {
if path, valid := n.generatePath(); valid {
for i, n := range *m.Name {
path, valid, err := n.generatePath()
if err != nil {
grpclog.Warningf("grpc: parseServiceConfig error unmarshaling %s due to methodConfig[%d]: %v", js, i, err)
return &serviceconfig.ParseResult{Err: err}
}

if _, ok := paths[path]; ok {
err = errors.New("duplicated name")
grpclog.Warningf("grpc: parseServiceConfig error unmarshaling %s due to methodConfig[%d]: %v", js, i, err)
return &serviceconfig.ParseResult{Err: err}
}
paths[path] = struct{}{}

if valid {
sc.Methods[path] = mc
}
}
Expand Down
32 changes: 32 additions & 0 deletions service_config_test.go
Expand Up @@ -373,6 +373,38 @@ func (s) TestParseMsgSize(t *testing.T) {
runParseTests(t, testcases)
}

func (s) TestParseMethodConfigEmptyServiceAndNonEmptyMethod(t *testing.T) {
runParseTests(t, []parseTestCase{{
`{
"methodConfig": [{
"name": [
{
"service": "",
"method": "Bar"
}
],
"waitForReady": true
}]
}`, nil, true,
}})
}

func (s) TestParseMethodConfigDuplicatedName(t *testing.T) {
runParseTests(t, []parseTestCase{
{
`{
"methodConfig": [{
"name": [
{"service": "foo"},
{"service": "foo"}
],
"waitForReady": true
}]
}`, nil, true,
},
})
}

func (s) TestParseDuration(t *testing.T) {
testCases := []struct {
s *string
Expand Down

0 comments on commit 5c57934

Please sign in to comment.