gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/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 "gitee.com/ks-custle/core-gm/grpc/balancer" 30 "gitee.com/ks-custle/core-gm/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 }