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  }