github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/service_config_test.go (about)

     1  /*
     2   *
     3   * Copyright 2017 gRPC authors.
     4   *
     5   * Licensed under the Apache License, Version 2.0 (the "License");
     6   * you may not use this file except in compliance with the License.
     7   * You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   *
    17   */
    18  
    19  package grpc
    20  
    21  import (
    22  	"encoding/json"
    23  	"fmt"
    24  	"math"
    25  	"reflect"
    26  	"testing"
    27  	"time"
    28  
    29  	"github.com/hxx258456/ccgo/grpc/balancer"
    30  	"github.com/hxx258456/ccgo/grpc/serviceconfig"
    31  )
    32  
    33  type parseTestCase struct {
    34  	scjs    string
    35  	wantSC  *ServiceConfig
    36  	wantErr bool
    37  }
    38  
    39  func runParseTests(t *testing.T, testCases []parseTestCase) {
    40  	t.Helper()
    41  	for _, c := range testCases {
    42  		scpr := parseServiceConfig(c.scjs)
    43  		var sc *ServiceConfig
    44  		sc, _ = scpr.Config.(*ServiceConfig)
    45  		if !c.wantErr {
    46  			c.wantSC.rawJSONString = c.scjs
    47  		}
    48  		if c.wantErr != (scpr.Err != nil) || !reflect.DeepEqual(sc, c.wantSC) {
    49  			t.Fatalf("parseServiceConfig(%s) = %+v, %v, want %+v, %v", c.scjs, sc, scpr.Err, c.wantSC, c.wantErr)
    50  		}
    51  	}
    52  }
    53  
    54  type pbbData struct {
    55  	serviceconfig.LoadBalancingConfig
    56  	Foo string
    57  	Bar int
    58  }
    59  
    60  type parseBalancerBuilder struct{}
    61  
    62  func (parseBalancerBuilder) Name() string {
    63  	return "pbb"
    64  }
    65  
    66  func (parseBalancerBuilder) ParseConfig(c json.RawMessage) (serviceconfig.LoadBalancingConfig, error) {
    67  	d := pbbData{}
    68  	if err := json.Unmarshal(c, &d); err != nil {
    69  		return nil, err
    70  	}
    71  	return d, nil
    72  }
    73  
    74  func (parseBalancerBuilder) Build(cc balancer.ClientConn, opts balancer.BuildOptions) balancer.Balancer {
    75  	panic("unimplemented")
    76  }
    77  
    78  func init() {
    79  	balancer.Register(parseBalancerBuilder{})
    80  }
    81  
    82  func (s) TestParseLBConfig(t *testing.T) {
    83  	testcases := []parseTestCase{
    84  		{
    85  			`{
    86      "loadBalancingConfig": [{"pbb": { "foo": "hi" } }]
    87  }`,
    88  			&ServiceConfig{
    89  				Methods:  make(map[string]MethodConfig),
    90  				lbConfig: &lbConfig{name: "pbb", cfg: pbbData{Foo: "hi"}},
    91  			},
    92  			false,
    93  		},
    94  	}
    95  	runParseTests(t, testcases)
    96  }
    97  
    98  func (s) TestParseNoLBConfigSupported(t *testing.T) {
    99  	// We have a loadBalancingConfig field but will not encounter a supported
   100  	// policy.  The config will be considered invalid in this case.
   101  	testcases := []parseTestCase{
   102  		{
   103  			scjs: `{
   104      "loadBalancingConfig": [{"not_a_balancer1": {} }, {"not_a_balancer2": {}}]
   105  }`,
   106  			wantErr: true,
   107  		}, {
   108  			scjs:    `{"loadBalancingConfig": []}`,
   109  			wantErr: true,
   110  		},
   111  	}
   112  	runParseTests(t, testcases)
   113  }
   114  
   115  func (s) TestParseLoadBalancer(t *testing.T) {
   116  	testcases := []parseTestCase{
   117  		{
   118  			`{
   119      "loadBalancingPolicy": "round_robin",
   120      "methodConfig": [
   121          {
   122              "name": [
   123                  {
   124                      "service": "foo",
   125                      "method": "Bar"
   126                  }
   127              ],
   128              "waitForReady": true
   129          }
   130      ]
   131  }`,
   132  			&ServiceConfig{
   133  				LB: newString("round_robin"),
   134  				Methods: map[string]MethodConfig{
   135  					"/foo/Bar": {
   136  						WaitForReady: newBool(true),
   137  					},
   138  				},
   139  			},
   140  			false,
   141  		},
   142  		{
   143  			`{
   144      "loadBalancingPolicy": 1,
   145      "methodConfig": [
   146          {
   147              "name": [
   148                  {
   149                      "service": "foo",
   150                      "method": "Bar"
   151                  }
   152              ],
   153              "waitForReady": false
   154          }
   155      ]
   156  }`,
   157  			nil,
   158  			true,
   159  		},
   160  	}
   161  	runParseTests(t, testcases)
   162  }
   163  
   164  func (s) TestParseWaitForReady(t *testing.T) {
   165  	testcases := []parseTestCase{
   166  		{
   167  			`{
   168      "methodConfig": [
   169          {
   170              "name": [
   171                  {
   172                      "service": "foo",
   173                      "method": "Bar"
   174                  }
   175              ],
   176              "waitForReady": true
   177          }
   178      ]
   179  }`,
   180  			&ServiceConfig{
   181  				Methods: map[string]MethodConfig{
   182  					"/foo/Bar": {
   183  						WaitForReady: newBool(true),
   184  					},
   185  				},
   186  			},
   187  			false,
   188  		},
   189  		{
   190  			`{
   191      "methodConfig": [
   192          {
   193              "name": [
   194                  {
   195                      "service": "foo",
   196                      "method": "Bar"
   197                  }
   198              ],
   199              "waitForReady": false
   200          }
   201      ]
   202  }`,
   203  			&ServiceConfig{
   204  				Methods: map[string]MethodConfig{
   205  					"/foo/Bar": {
   206  						WaitForReady: newBool(false),
   207  					},
   208  				},
   209  			},
   210  			false,
   211  		},
   212  		{
   213  			`{
   214      "methodConfig": [
   215          {
   216              "name": [
   217                  {
   218                      "service": "foo",
   219                      "method": "Bar"
   220                  }
   221              ],
   222              "waitForReady": fall
   223          },
   224          {
   225              "name": [
   226                  {
   227                      "service": "foo",
   228                      "method": "Bar"
   229                  }
   230              ],
   231              "waitForReady": true
   232          }
   233      ]
   234  }`,
   235  			nil,
   236  			true,
   237  		},
   238  	}
   239  
   240  	runParseTests(t, testcases)
   241  }
   242  
   243  func (s) TestParseTimeOut(t *testing.T) {
   244  	testcases := []parseTestCase{
   245  		{
   246  			`{
   247      "methodConfig": [
   248          {
   249              "name": [
   250                  {
   251                      "service": "foo",
   252                      "method": "Bar"
   253                  }
   254              ],
   255              "timeout": "1s"
   256          }
   257      ]
   258  }`,
   259  			&ServiceConfig{
   260  				Methods: map[string]MethodConfig{
   261  					"/foo/Bar": {
   262  						Timeout: newDuration(time.Second),
   263  					},
   264  				},
   265  			},
   266  			false,
   267  		},
   268  		{
   269  			`{
   270      "methodConfig": [
   271          {
   272              "name": [
   273                  {
   274                      "service": "foo",
   275                      "method": "Bar"
   276                  }
   277              ],
   278              "timeout": "3c"
   279          }
   280      ]
   281  }`,
   282  			nil,
   283  			true,
   284  		},
   285  		{
   286  			`{
   287      "methodConfig": [
   288          {
   289              "name": [
   290                  {
   291                      "service": "foo",
   292                      "method": "Bar"
   293                  }
   294              ],
   295              "timeout": "3c"
   296          },
   297          {
   298              "name": [
   299                  {
   300                      "service": "foo",
   301                      "method": "Bar"
   302                  }
   303              ],
   304              "timeout": "1s"
   305          }
   306      ]
   307  }`,
   308  			nil,
   309  			true,
   310  		},
   311  	}
   312  
   313  	runParseTests(t, testcases)
   314  }
   315  
   316  func (s) TestParseMsgSize(t *testing.T) {
   317  	testcases := []parseTestCase{
   318  		{
   319  			`{
   320      "methodConfig": [
   321          {
   322              "name": [
   323                  {
   324                      "service": "foo",
   325                      "method": "Bar"
   326                  }
   327              ],
   328              "maxRequestMessageBytes": 1024,
   329              "maxResponseMessageBytes": 2048
   330          }
   331      ]
   332  }`,
   333  			&ServiceConfig{
   334  				Methods: map[string]MethodConfig{
   335  					"/foo/Bar": {
   336  						MaxReqSize:  newInt(1024),
   337  						MaxRespSize: newInt(2048),
   338  					},
   339  				},
   340  			},
   341  			false,
   342  		},
   343  		{
   344  			`{
   345      "methodConfig": [
   346          {
   347              "name": [
   348                  {
   349                      "service": "foo",
   350                      "method": "Bar"
   351                  }
   352              ],
   353              "maxRequestMessageBytes": "1024",
   354              "maxResponseMessageBytes": "2048"
   355          },
   356          {
   357              "name": [
   358                  {
   359                      "service": "foo",
   360                      "method": "Bar"
   361                  }
   362              ],
   363              "maxRequestMessageBytes": 1024,
   364              "maxResponseMessageBytes": 2048
   365          }
   366      ]
   367  }`,
   368  			nil,
   369  			true,
   370  		},
   371  	}
   372  
   373  	runParseTests(t, testcases)
   374  }
   375  func (s) TestParseDefaultMethodConfig(t *testing.T) {
   376  	dc := &ServiceConfig{
   377  		Methods: map[string]MethodConfig{
   378  			"": {WaitForReady: newBool(true)},
   379  		},
   380  	}
   381  
   382  	runParseTests(t, []parseTestCase{
   383  		{
   384  			`{
   385    "methodConfig": [{
   386      "name": [{}],
   387      "waitForReady": true
   388    }]
   389  }`,
   390  			dc,
   391  			false,
   392  		},
   393  		{
   394  			`{
   395    "methodConfig": [{
   396      "name": [{"service": null}],
   397      "waitForReady": true
   398    }]
   399  }`,
   400  			dc,
   401  			false,
   402  		},
   403  		{
   404  			`{
   405    "methodConfig": [{
   406      "name": [{"service": ""}],
   407      "waitForReady": true
   408    }]
   409  }`,
   410  			dc,
   411  			false,
   412  		},
   413  		{
   414  			`{
   415    "methodConfig": [{
   416      "name": [{"method": "Bar"}],
   417      "waitForReady": true
   418    }]
   419  }`,
   420  			nil,
   421  			true,
   422  		},
   423  		{
   424  			`{
   425    "methodConfig": [{
   426      "name": [{"service": "", "method": "Bar"}],
   427      "waitForReady": true
   428    }]
   429  }`,
   430  			nil,
   431  			true,
   432  		},
   433  	})
   434  }
   435  
   436  func (s) TestParseMethodConfigDuplicatedName(t *testing.T) {
   437  	runParseTests(t, []parseTestCase{
   438  		{
   439  			`{
   440    "methodConfig": [{
   441      "name": [
   442        {"service": "foo"},
   443        {"service": "foo"}
   444      ],
   445      "waitForReady": true
   446    }]
   447  }`, nil, true,
   448  		},
   449  	})
   450  }
   451  
   452  func (s) TestParseDuration(t *testing.T) {
   453  	testCases := []struct {
   454  		s    *string
   455  		want *time.Duration
   456  		err  bool
   457  	}{
   458  		{s: nil, want: nil},
   459  		{s: newString("1s"), want: newDuration(time.Second)},
   460  		{s: newString("-1s"), want: newDuration(-time.Second)},
   461  		{s: newString("1.1s"), want: newDuration(1100 * time.Millisecond)},
   462  		{s: newString("1.s"), want: newDuration(time.Second)},
   463  		{s: newString("1.0s"), want: newDuration(time.Second)},
   464  		{s: newString(".002s"), want: newDuration(2 * time.Millisecond)},
   465  		{s: newString(".002000s"), want: newDuration(2 * time.Millisecond)},
   466  		{s: newString("0.003s"), want: newDuration(3 * time.Millisecond)},
   467  		{s: newString("0.000004s"), want: newDuration(4 * time.Microsecond)},
   468  		{s: newString("5000.000000009s"), want: newDuration(5000*time.Second + 9*time.Nanosecond)},
   469  		{s: newString("4999.999999999s"), want: newDuration(5000*time.Second - time.Nanosecond)},
   470  		{s: newString("1"), err: true},
   471  		{s: newString("s"), err: true},
   472  		{s: newString(".s"), err: true},
   473  		{s: newString("1 s"), err: true},
   474  		{s: newString(" 1s"), err: true},
   475  		{s: newString("1ms"), err: true},
   476  		{s: newString("1.1.1s"), err: true},
   477  		{s: newString("Xs"), err: true},
   478  		{s: newString("as"), err: true},
   479  		{s: newString(".0000000001s"), err: true},
   480  		{s: newString(fmt.Sprint(math.MaxInt32) + "s"), want: newDuration(math.MaxInt32 * time.Second)},
   481  		{s: newString(fmt.Sprint(int64(math.MaxInt32)+1) + "s"), err: true},
   482  	}
   483  	for _, tc := range testCases {
   484  		got, err := parseDuration(tc.s)
   485  		if tc.err != (err != nil) ||
   486  			(got == nil) != (tc.want == nil) ||
   487  			(got != nil && *got != *tc.want) {
   488  			wantErr := "<nil>"
   489  			if tc.err {
   490  				wantErr = "<non-nil error>"
   491  			}
   492  			s := "<nil>"
   493  			if tc.s != nil {
   494  				s = `&"` + *tc.s + `"`
   495  			}
   496  			t.Errorf("parseDuration(%v) = %v, %v; want %v, %v", s, got, err, tc.want, wantErr)
   497  		}
   498  	}
   499  }
   500  
   501  func newBool(b bool) *bool {
   502  	return &b
   503  }
   504  
   505  func newDuration(b time.Duration) *time.Duration {
   506  	return &b
   507  }
   508  
   509  func newString(b string) *string {
   510  	return &b
   511  }