trpc.group/trpc-go/trpc-go@v1.0.3/plugin/setup_test.go (about) 1 // 2 // 3 // Tencent is pleased to support the open source community by making tRPC available. 4 // 5 // Copyright (C) 2023 THL A29 Limited, a Tencent company. 6 // All rights reserved. 7 // 8 // If you have downloaded a copy of the tRPC source code from Tencent, 9 // please note that tRPC source code is licensed under the Apache 2.0 License, 10 // A copy of the Apache 2.0 License is included in this file. 11 // 12 // 13 14 package plugin_test 15 16 import ( 17 "errors" 18 "testing" 19 "time" 20 21 "github.com/stretchr/testify/assert" 22 "github.com/stretchr/testify/require" 23 yaml "gopkg.in/yaml.v3" 24 25 "trpc.group/trpc-go/trpc-go/plugin" 26 ) 27 28 type config struct { 29 Plugins plugin.Config 30 } 31 32 const ( 33 pluginType = "mock_type" 34 pluginName = "mock_name" 35 pluginFailName = "mock_fail_name" 36 pluginTimeoutName = "mock_timeout_name" 37 pluginDependName = "mock_depend_name" 38 ) 39 40 func TestConfig_Setup(t *testing.T) { 41 const configInfoNotRegister = ` 42 plugins: 43 mock_type: 44 mock_not_register: 45 address: localhost:8000 46 ` 47 cfg := config{} 48 err := yaml.Unmarshal([]byte(configInfoNotRegister), &cfg) 49 assert.Nil(t, err) 50 51 _, err = cfg.Plugins.SetupClosables() 52 assert.NotNil(t, err) 53 54 const configInfo = ` 55 plugins: 56 mock_type: 57 mock_name: 58 address: localhost:8000 59 ` 60 plugin.Register(pluginName, &mockPlugin{}) 61 cfg = config{} 62 err = yaml.Unmarshal([]byte(configInfo), &cfg) 63 assert.Nil(t, err) 64 65 clo, err := cfg.Plugins.SetupClosables() 66 assert.Nil(t, err) 67 require.Nil(t, clo()) 68 } 69 70 type mockTimeoutPlugin struct{} 71 72 func (p *mockTimeoutPlugin) Type() string { 73 return pluginType 74 } 75 76 func (p *mockTimeoutPlugin) Setup(name string, decoder plugin.Decoder) error { 77 time.Sleep(time.Second * 5) 78 return nil 79 } 80 func TestConfig_TimeoutSetup(t *testing.T) { 81 const configInfo = ` 82 plugins: 83 mock_type: 84 mock_name: 85 address: localhost:8000 86 mock_timeout_name: 87 address: localhost:8000 88 ` 89 plugin.Register(pluginName, &mockPlugin{}) 90 plugin.Register(pluginTimeoutName, &mockTimeoutPlugin{}) 91 cfg := config{} 92 err := yaml.Unmarshal([]byte(configInfo), &cfg) 93 assert.Nil(t, err) 94 95 _, err = cfg.Plugins.SetupClosables() 96 assert.NotNil(t, err) 97 } 98 99 type mockDependPlugin struct{} 100 101 func (p *mockDependPlugin) Type() string { 102 return pluginType 103 } 104 105 func (p *mockDependPlugin) Setup(name string, decoder plugin.Decoder) error { 106 return nil 107 } 108 func (p *mockDependPlugin) DependsOn() []string { 109 return []string{"mock_type-mock_name"} 110 } 111 func TestConfig_DependSetup(t *testing.T) { 112 const configInfo = ` 113 plugins: 114 mock_type: 115 mock_name: 116 address: localhost:8000 117 mock_depend_name: 118 address: localhost:8000 119 ` 120 plugin.Register(pluginName, &mockPlugin{}) 121 plugin.Register(pluginDependName, &mockDependPlugin{}) 122 cfg := config{} 123 err := yaml.Unmarshal([]byte(configInfo), &cfg) 124 assert.Nil(t, err) 125 126 clo, err := cfg.Plugins.SetupClosables() 127 assert.Nil(t, err) 128 require.Nil(t, clo()) 129 } 130 func TestConfig_ExceedSetup(t *testing.T) { 131 const configInfo = ` 132 plugins: 133 mock_type: 134 mock_name: 135 address: localhost:8000 136 mock_depend_name: 137 address: localhost:8000 138 ` 139 plugin.Register(pluginName, &mockPlugin{}) 140 plugin.Register(pluginDependName, &mockDependPlugin{}) 141 tmp := plugin.MaxPluginSize 142 plugin.MaxPluginSize = 1 143 defer func() { 144 plugin.MaxPluginSize = tmp 145 }() 146 cfg := config{} 147 err := yaml.Unmarshal([]byte(configInfo), &cfg) 148 assert.Nil(t, err) 149 150 _, err = cfg.Plugins.SetupClosables() 151 assert.NotNil(t, err) 152 } 153 154 type mockDependNonePlugin struct{} 155 156 func (p *mockDependNonePlugin) Type() string { 157 return pluginType 158 } 159 160 func (p *mockDependNonePlugin) Setup(name string, decoder plugin.Decoder) error { 161 return nil 162 } 163 func (p *mockDependNonePlugin) DependsOn() []string { 164 return []string{"mock_type-mock_none_name"} 165 } 166 func TestConfig_DependNoneSetup(t *testing.T) { 167 const configInfo = ` 168 plugins: 169 mock_type: 170 mock_name: 171 address: localhost:8000 172 mock_depend_name: 173 address: localhost:8000 174 ` 175 plugin.Register(pluginName, &mockPlugin{}) 176 plugin.Register(pluginDependName, &mockDependNonePlugin{}) 177 cfg := config{} 178 err := yaml.Unmarshal([]byte(configInfo), &cfg) 179 assert.Nil(t, err) 180 181 _, err = cfg.Plugins.SetupClosables() 182 assert.NotNil(t, err) 183 } 184 185 type mockDependSelfPlugin struct{} 186 187 func (p *mockDependSelfPlugin) Type() string { 188 return pluginType 189 } 190 191 func (p *mockDependSelfPlugin) Setup(name string, decoder plugin.Decoder) error { 192 return nil 193 } 194 func (p *mockDependSelfPlugin) DependsOn() []string { 195 return []string{"mock_type-mock_depend_name"} 196 } 197 func TestConfig_DependSelfSetup(t *testing.T) { 198 const configInfo = ` 199 plugins: 200 mock_type: 201 mock_name: 202 address: localhost:8000 203 mock_depend_name: 204 address: localhost:8000 205 ` 206 plugin.Register(pluginName, &mockPlugin{}) 207 plugin.Register(pluginDependName, &mockDependSelfPlugin{}) 208 cfg := config{} 209 err := yaml.Unmarshal([]byte(configInfo), &cfg) 210 assert.Nil(t, err) 211 212 _, err = cfg.Plugins.SetupClosables() 213 assert.NotNil(t, err) 214 } 215 216 type mockDependCycle1Plugin struct{} 217 218 func (p *mockDependCycle1Plugin) Type() string { 219 return pluginType 220 } 221 222 func (p *mockDependCycle1Plugin) Setup(name string, decoder plugin.Decoder) error { 223 return nil 224 } 225 func (p *mockDependCycle1Plugin) DependsOn() []string { 226 return []string{"mock_type-mock_cycle2_name"} 227 } 228 229 type mockDependCycle2Plugin struct{} 230 231 func (p *mockDependCycle2Plugin) Type() string { 232 return pluginType 233 } 234 235 func (p *mockDependCycle2Plugin) Setup(name string, decoder plugin.Decoder) error { 236 return nil 237 } 238 func (p *mockDependCycle2Plugin) DependsOn() []string { 239 return []string{"mock_type-mock_cycle1_name"} 240 } 241 func TestConfig_DependCycleSetup(t *testing.T) { 242 const configInfo = ` 243 plugins: 244 mock_type: 245 mock_cycle1_name: 246 address: localhost:8000 247 mock_cycle2_name: 248 address: localhost:8000 249 ` 250 plugin.Register("mock_cycle1_name", &mockDependCycle1Plugin{}) 251 plugin.Register("mock_cycle2_name", &mockDependCycle2Plugin{}) 252 cfg := config{} 253 err := yaml.Unmarshal([]byte(configInfo), &cfg) 254 assert.Nil(t, err) 255 256 _, err = cfg.Plugins.SetupClosables() 257 assert.NotNil(t, err) 258 } 259 260 type mockFailPlugin struct{} 261 262 func (p *mockFailPlugin) Type() string { 263 return pluginType 264 } 265 266 func (p *mockFailPlugin) Setup(name string, decoder plugin.Decoder) error { 267 return errors.New("mock fail") 268 } 269 func TestConfig_SetupFail(t *testing.T) { 270 const configInfo = ` 271 plugins: 272 mock_type: 273 mock_fail_name: 274 address: localhost:8000 275 ` 276 plugin.Register(pluginFailName, &mockFailPlugin{}) 277 cfg := config{} 278 err := yaml.Unmarshal([]byte(configInfo), &cfg) 279 assert.Nil(t, err) 280 281 _, err = cfg.Plugins.SetupClosables() 282 assert.NotNil(t, err) 283 } 284 285 func TestYamlNodeDecoder_Decode(t *testing.T) { 286 var nodeCfg = struct { 287 Address string 288 }{} 289 const configInfo = ` 290 plugins: 291 mock_type: 292 mock_fail_name: 293 address: localhost:8000 294 ` 295 cfg := config{} 296 err := yaml.Unmarshal([]byte(configInfo), &cfg) 297 assert.Nil(t, err) 298 299 node := cfg.Plugins["mock_type"]["mock_fail_name"] 300 d := &plugin.YamlNodeDecoder{Node: &node} 301 err = d.Decode(&nodeCfg) 302 assert.Nil(t, err) 303 assert.Equal(t, "localhost:8000", nodeCfg.Address) 304 305 // Node 为空判断失败 306 d.Node = nil 307 err = d.Decode(&nodeCfg) 308 assert.NotNil(t, err) 309 } 310 311 type mockFlexDependerPlugin1 struct { 312 testOrderCh chan int 313 } 314 315 func (p *mockFlexDependerPlugin1) Type() string { 316 return pluginType 317 } 318 319 func (p *mockFlexDependerPlugin1) Setup(name string, decoder plugin.Decoder) error { 320 p.testOrderCh <- 1 321 return nil 322 } 323 324 func (p *mockFlexDependerPlugin1) FlexDependsOn() []string { 325 return []string{"mock_type-mock_flex_depender_name3", "anything", "mock_type-mock_flex_depender_name2"} 326 } 327 328 type mockFlexDependerPlugin2 struct { 329 testOrderCh chan int 330 } 331 332 func (p *mockFlexDependerPlugin2) Type() string { 333 return pluginType 334 } 335 336 func (p *mockFlexDependerPlugin2) Setup(name string, decoder plugin.Decoder) error { 337 p.testOrderCh <- 2 338 return nil 339 } 340 341 func (p *mockFlexDependerPlugin2) FlexDependsOn() []string { 342 return []string{"anything", "mock_type-mock_flex_depender_name3"} 343 } 344 345 type mockFlexDependerPlugin3 struct { 346 testOrderCh chan int 347 } 348 349 func (p *mockFlexDependerPlugin3) Type() string { 350 return pluginType 351 } 352 353 func (p *mockFlexDependerPlugin3) Setup(name string, decoder plugin.Decoder) error { 354 p.testOrderCh <- 3 355 return nil 356 } 357 func TestFlexDepender(t *testing.T) { 358 const configInfo = ` 359 plugins: 360 mock_type: 361 mock_flex_depender_name1: 362 address: localhost:8000 363 mock_flex_depender_name2: 364 address: localhost:8000 365 mock_flex_depender_name3: 366 address: localhost:8000 367 ` 368 testOrderCh := make(chan int, 3) 369 plugin.Register("mock_flex_depender_name1", &mockFlexDependerPlugin1{ 370 testOrderCh: testOrderCh, 371 }) 372 plugin.Register("mock_flex_depender_name2", &mockFlexDependerPlugin2{ 373 testOrderCh: testOrderCh, 374 }) 375 plugin.Register("mock_flex_depender_name3", &mockFlexDependerPlugin3{ 376 testOrderCh: testOrderCh, 377 }) 378 cfg := config{} 379 err := yaml.Unmarshal([]byte(configInfo), &cfg) 380 assert.Nil(t, err) 381 382 clo, err := cfg.Plugins.SetupClosables() 383 assert.Nil(t, err) 384 require.Nil(t, clo()) 385 v, ok := <-testOrderCh 386 assert.True(t, ok) 387 assert.Equal(t, 3, v) 388 v, ok = <-testOrderCh 389 assert.True(t, ok) 390 assert.Equal(t, 2, v) 391 v, ok = <-testOrderCh 392 assert.True(t, ok) 393 assert.Equal(t, 1, v) 394 } 395 396 type mockBothDepender struct { 397 testOrderCh chan int 398 } 399 400 func (p *mockBothDepender) Type() string { 401 return pluginType 402 } 403 404 func (p *mockBothDepender) Setup(name string, decoder plugin.Decoder) error { 405 p.testOrderCh <- 4 406 return nil 407 } 408 func (p *mockBothDepender) DependsOn() []string { 409 return []string{"mock_type-mock_flex_depender_name2"} 410 } 411 412 func (p *mockBothDepender) FlexDependsOn() []string { 413 return []string{"mock_type-mock_flex_depender_name3"} 414 } 415 func TestBothDepender(t *testing.T) { 416 const configInfo = ` 417 plugins: 418 mock_type: 419 mock_both_depender: 420 address: localhost:8000 421 mock_flex_depender_name2: 422 address: localhost:8000 423 mock_flex_depender_name3: 424 address: localhost:8000 425 ` 426 testOrderCh := make(chan int, 3) 427 plugin.Register("mock_flex_depender_name3", &mockFlexDependerPlugin3{ 428 testOrderCh: testOrderCh, 429 }) 430 plugin.Register("mock_flex_depender_name2", &mockFlexDependerPlugin2{ 431 testOrderCh: testOrderCh, 432 }) 433 plugin.Register("mock_both_depender", &mockBothDepender{ 434 testOrderCh: testOrderCh, 435 }) 436 cfg := config{} 437 err := yaml.Unmarshal([]byte(configInfo), &cfg) 438 assert.Nil(t, err) 439 440 clo, err := cfg.Plugins.SetupClosables() 441 assert.Nil(t, err) 442 require.Nil(t, clo()) 443 v, ok := <-testOrderCh 444 assert.True(t, ok) 445 assert.Equal(t, v, 3) 446 v, ok = <-testOrderCh 447 assert.True(t, ok) 448 assert.Equal(t, v, 2) 449 v, ok = <-testOrderCh 450 assert.True(t, ok) 451 assert.Equal(t, 4, v) 452 } 453 454 type mockFinishSuccPlugin struct{} 455 456 func (p *mockFinishSuccPlugin) Type() string { 457 return pluginType 458 } 459 460 func (p *mockFinishSuccPlugin) Setup(name string, decoder plugin.Decoder) error { 461 return nil 462 } 463 func (p *mockFinishSuccPlugin) OnFinish(name string) error { 464 return nil 465 } 466 func TestConfig_OnFinishSucc(t *testing.T) { 467 const configInfo = ` 468 plugins: 469 mock_type: 470 mock_name: 471 address: localhost:8000 472 mock_finish_succ: 473 address: localhost:8000 474 ` 475 plugin.Register(pluginName, &mockPlugin{}) 476 plugin.Register("mock_finish_succ", &mockFinishSuccPlugin{}) 477 cfg := config{} 478 err := yaml.Unmarshal([]byte(configInfo), &cfg) 479 assert.Nil(t, err) 480 481 clo, err := cfg.Plugins.SetupClosables() 482 assert.Nil(t, err) 483 require.Nil(t, clo()) 484 } 485 486 type mockFinishFailPlugin struct{} 487 488 func (p *mockFinishFailPlugin) Type() string { 489 return pluginType 490 } 491 492 func (p *mockFinishFailPlugin) Setup(name string, decoder plugin.Decoder) error { 493 return nil 494 } 495 func (p *mockFinishFailPlugin) OnFinish(name string) error { 496 return errors.New("on finish fail") 497 } 498 func TestConfig_OnFinishFail(t *testing.T) { 499 const configInfo = ` 500 plugins: 501 mock_type: 502 mock_name: 503 address: localhost:8000 504 mock_finish_fail: 505 address: localhost:8000 506 ` 507 plugin.Register(pluginName, &mockPlugin{}) 508 plugin.Register("mock_finish_fail", &mockFinishFailPlugin{}) 509 cfg := config{} 510 err := yaml.Unmarshal([]byte(configInfo), &cfg) 511 assert.Nil(t, err) 512 513 _, err = cfg.Plugins.SetupClosables() 514 assert.NotNil(t, err) 515 } 516 517 type mockClosablePlugin struct { 518 onClose func() error 519 } 520 521 func (*mockClosablePlugin) Type() string { 522 return pluginType 523 } 524 525 func (*mockClosablePlugin) Setup(string, plugin.Decoder) error { 526 return nil 527 } 528 529 func (p *mockClosablePlugin) Close() error { 530 return p.onClose() 531 } 532 533 func TestPluginClose(t *testing.T) { 534 t.Run("close success", func(t *testing.T) { 535 var closed bool 536 plugin.Register("close success", &mockClosablePlugin{onClose: func() error { 537 closed = true 538 return nil 539 }}) 540 close, err := plugin.Config{pluginType: {"close success": yaml.Node{}}}.SetupClosables() 541 require.Nil(t, err) 542 require.Nil(t, close()) 543 require.True(t, closed) 544 }) 545 t.Run("close error", func(t *testing.T) { 546 plugin.Register("close error", &mockClosablePlugin{onClose: func() error { 547 return errors.New("close error") 548 }}) 549 close, err := plugin.Config{pluginType: {"close error": yaml.Node{}}}.SetupClosables() 550 require.Nil(t, err) 551 require.Error(t, close()) 552 }) 553 }