github.com/unionj-cloud/go-doudou@v1.3.8-0.20221011095552-0088008e5b31/framework/registry/node_test.go (about)

     1  package registry
     2  
     3  import (
     4  	"github.com/apolloconfig/agollo/v4"
     5  	"github.com/apolloconfig/agollo/v4/agcache/memory"
     6  	apolloConfig "github.com/apolloconfig/agollo/v4/env/config"
     7  	"github.com/apolloconfig/agollo/v4/storage"
     8  	"github.com/golang/mock/gomock"
     9  	"github.com/pkg/errors"
    10  	. "github.com/smartystreets/goconvey/convey"
    11  	"github.com/stretchr/testify/require"
    12  	"github.com/unionj-cloud/go-doudou/framework/buildinfo"
    13  	"github.com/unionj-cloud/go-doudou/framework/configmgr"
    14  	"github.com/unionj-cloud/go-doudou/framework/configmgr/mock"
    15  	"github.com/unionj-cloud/go-doudou/framework/internal/config"
    16  	"github.com/unionj-cloud/go-doudou/framework/memberlist"
    17  	memmock "github.com/unionj-cloud/go-doudou/framework/memberlist/mock"
    18  	"github.com/unionj-cloud/go-doudou/framework/registry/nacos"
    19  	nmock "github.com/unionj-cloud/go-doudou/framework/registry/nacos/mock"
    20  	"github.com/unionj-cloud/go-doudou/toolkit/maputils"
    21  	"github.com/wubin1989/nacos-sdk-go/clients/cache"
    22  	"github.com/wubin1989/nacos-sdk-go/clients/config_client"
    23  	"github.com/wubin1989/nacos-sdk-go/clients/naming_client"
    24  	"github.com/wubin1989/nacos-sdk-go/vo"
    25  	"os"
    26  	"reflect"
    27  	"testing"
    28  	"time"
    29  )
    30  
    31  func setup() {
    32  	_ = config.GddMemSeed.Write("")
    33  	_ = config.GddServiceName.Write("seed")
    34  	_ = config.GddMemName.Write("seed")
    35  	_ = config.GddMemPort.Write("56199")
    36  	_ = config.GddMemWeight.Write("8")
    37  	_ = config.GddMemDeadTimeout.Write("8s")
    38  	_ = config.GddMemSyncInterval.Write("8s")
    39  	_ = config.GddMemReclaimTimeout.Write("8s")
    40  	_ = config.GddMemProbeInterval.Write("8s")
    41  	_ = config.GddMemProbeTimeout.Write("8s")
    42  	_ = config.GddMemSuspicionMult.Write("8")
    43  	_ = config.GddMemGossipNodes.Write("8")
    44  	_ = config.GddMemGossipInterval.Write("8s")
    45  	_ = config.GddMemWeightInterval.Write("8s")
    46  	_ = config.GddMemTCPTimeout.Write("8s")
    47  	_ = config.GddMemHost.Write("seed.seed-svc-headless.default.svc.cluster.local")
    48  	_ = config.GddMemIndirectChecks.Write("8")
    49  	_ = config.GddLogLevel.Write("debug")
    50  	_ = config.GddPort.Write("8088")
    51  	_ = config.GddRouteRootPath.Write("/v1")
    52  	_ = config.GddApolloAddr.Write("http://apollo-config-dev-svc:8080")
    53  	_ = config.GddNacosServerAddr.Write("http://localhost:8848")
    54  }
    55  
    56  func Test_seeds(t *testing.T) {
    57  	type args struct {
    58  		seedstr string
    59  	}
    60  	tests := []struct {
    61  		name string
    62  		args args
    63  		want []string
    64  	}{
    65  		{
    66  			name: "",
    67  			args: args{
    68  				seedstr: "seed-01,seed-02,seed-03",
    69  			},
    70  			want: []string{"seed-01:7946", "seed-02:7946", "seed-03:7946"},
    71  		},
    72  		{
    73  			name: "",
    74  			args: args{
    75  				seedstr: "",
    76  			},
    77  			want: nil,
    78  		},
    79  		{
    80  			name: "",
    81  			args: args{
    82  				seedstr: "seed-01:56199,seed-02,seed-03:03,seed-04:abc",
    83  			},
    84  			want: []string{"seed-01:56199", "seed-02:7946", "seed-03:3", "seed-04:7946"},
    85  		},
    86  	}
    87  	for _, tt := range tests {
    88  		t.Run(tt.name, func(t *testing.T) {
    89  			if got := seeds(tt.args.seedstr); !reflect.DeepEqual(got, tt.want) {
    90  				t.Errorf("seeds() = %v, want %v", got, tt.want)
    91  			}
    92  		})
    93  	}
    94  }
    95  
    96  func Test_join_fail(t *testing.T) {
    97  	setup()
    98  	err := NewNode()
    99  	if err != nil {
   100  		panic(err)
   101  	}
   102  	defer Shutdown()
   103  	_ = config.GddMemSeed.Write("not exist seed")
   104  	_ = config.GddServiceName.Write("testsvc")
   105  	require.Error(t, join())
   106  }
   107  
   108  func TestAllNodes(t *testing.T) {
   109  	setup()
   110  	err := NewNode()
   111  	if err != nil {
   112  		panic(err)
   113  	}
   114  	defer Shutdown()
   115  	Convey("There should be only one node", t, func() {
   116  		nodes, _ := AllNodes()
   117  		So(len(nodes), ShouldEqual, 1)
   118  	})
   119  }
   120  
   121  func TestAllNodesError(t *testing.T) {
   122  	Convey("There should be only one node", t, func() {
   123  		_, err := AllNodes()
   124  		So(err.Error(), ShouldEqual, "mlist is nil")
   125  	})
   126  }
   127  
   128  func TestInfo(t *testing.T) {
   129  	setup()
   130  	err := NewNode()
   131  	if err != nil {
   132  		panic(err)
   133  	}
   134  	defer Shutdown()
   135  	Convey("Should not zero value", t, func() {
   136  		info := Info(LocalNode())
   137  		So(info, ShouldNotBeZeroValue)
   138  	})
   139  }
   140  
   141  func TestMetaWeight(t *testing.T) {
   142  	setup()
   143  	err := NewNode()
   144  	if err != nil {
   145  		panic(err)
   146  	}
   147  	defer Shutdown()
   148  	Convey("Should not zero value", t, func() {
   149  		weight, _ := MetaWeight(LocalNode())
   150  		So(weight, ShouldNotBeZeroValue)
   151  	})
   152  }
   153  
   154  func TestSvcName(t *testing.T) {
   155  	setup()
   156  	err := NewNode()
   157  	if err != nil {
   158  		panic(err)
   159  	}
   160  	defer Shutdown()
   161  	Convey("Should be equal to seed", t, func() {
   162  		So(SvcName(LocalNode()), ShouldEqual, "seed")
   163  	})
   164  }
   165  
   166  func TestRegisterServiceProvider(t *testing.T) {
   167  	setup()
   168  	err := NewNode()
   169  	if err != nil {
   170  		panic(err)
   171  	}
   172  	defer Shutdown()
   173  	Convey("", t, func() {
   174  		provider := newMockServiceProvider("TEST")
   175  		RegisterServiceProvider(provider)
   176  		So(len(events.ServiceProviders), ShouldEqual, 1)
   177  		So(len(provider.servers), ShouldEqual, 1)
   178  	})
   179  }
   180  
   181  func Test_memConfigListener_OnChange(t *testing.T) {
   182  	Convey("Test OnChange callback", t, func() {
   183  		c := &memConfigListener{
   184  			memConf: &memberlist.Config{},
   185  		}
   186  		c.OnChange(&storage.ChangeEvent{
   187  			Changes: map[string]*storage.ConfigChange{
   188  				"gdd.mem.dead.timeout": {
   189  					OldValue:   "60s",
   190  					NewValue:   "30s",
   191  					ChangeType: storage.MODIFIED,
   192  				},
   193  			},
   194  		})
   195  		Convey("Should equal to 8s", func() {
   196  			So(os.Getenv("GDD_MEM_DEAD_TIMEOUT"), ShouldEqual, "8s")
   197  		})
   198  
   199  		c.OnChange(&storage.ChangeEvent{
   200  			Changes: map[string]*storage.ConfigChange{
   201  				"gdd.mem.dead.timeout": {
   202  					OldValue:   "8s",
   203  					NewValue:   "30s",
   204  					ChangeType: storage.MODIFIED,
   205  				},
   206  			},
   207  		})
   208  		Convey("Should equal to 30s", func() {
   209  			So(os.Getenv("GDD_MEM_DEAD_TIMEOUT"), ShouldEqual, "30s")
   210  			So(c.memConf.GossipToTheDeadTime, ShouldEqual, 30*time.Second)
   211  		})
   212  
   213  		c.OnChange(&storage.ChangeEvent{
   214  			Changes: map[string]*storage.ConfigChange{
   215  				"gdd.mem.dead.timeout": {
   216  					OldValue:   "30s",
   217  					NewValue:   "",
   218  					ChangeType: storage.DELETED,
   219  				},
   220  			},
   221  		})
   222  		Convey("Should equal to 60s", func() {
   223  			So(os.Getenv("GDD_MEM_DEAD_TIMEOUT"), ShouldEqual, "")
   224  			So(c.memConf.GossipToTheDeadTime, ShouldEqual, 60*time.Second)
   225  		})
   226  
   227  	})
   228  }
   229  
   230  func TestNewNode_NacosConfigType(t *testing.T) {
   231  	Convey("Should not have error", t, func() {
   232  		setup()
   233  		_ = config.GddConfigRemoteType.Write("nacos")
   234  		ctrl := gomock.NewController(t)
   235  		defer ctrl.Finish()
   236  		dataId := ".env"
   237  		configClient := mock.NewMockIConfigClient(ctrl)
   238  		configClient.
   239  			EXPECT().
   240  			GetConfig(vo.ConfigParam{
   241  				DataId: dataId,
   242  				Group:  config.DefaultGddNacosConfigGroup,
   243  			}).
   244  			AnyTimes().
   245  			Return("GDD_READ_TIMEOUT=60s\nGDD_WRITE_TIMEOUT=60s\nGDD_IDLE_TIMEOUT=120s", nil)
   246  
   247  		configClient.
   248  			EXPECT().
   249  			ListenConfig(gomock.Any()).
   250  			AnyTimes().
   251  			Return(nil)
   252  
   253  		configmgr.NewConfigClient = func(param vo.NacosClientParam) (iClient config_client.IConfigClient, err error) {
   254  			return configClient, nil
   255  		}
   256  
   257  		if configmgr.NacosClient != nil {
   258  			configmgr.NacosClient = configmgr.NewNacosConfigMgr([]string{dataId},
   259  				config.DefaultGddNacosConfigGroup, configmgr.DotenvConfigFormat, config.DefaultGddNacosNamespaceId, configClient, cache.NewConcurrentMap())
   260  		}
   261  
   262  		err := configmgr.LoadFromNacos(config.GetNacosClientParam(), dataId, string(config.DefaultGddNacosConfigFormat), config.DefaultGddNacosConfigGroup)
   263  		So(err, ShouldBeNil)
   264  		So(NewNode(), ShouldBeNil)
   265  		defer Shutdown()
   266  	})
   267  }
   268  
   269  func TestNewNode_ApolloConfigType(t *testing.T) {
   270  	Convey("Should not have error", t, func() {
   271  		setup()
   272  		_ = config.GddConfigRemoteType.Write("apollo")
   273  		ctrl := gomock.NewController(t)
   274  		defer ctrl.Finish()
   275  		configClient := mock.NewMockClient(ctrl)
   276  		factory := &memory.DefaultCacheFactory{}
   277  		cache := factory.Create()
   278  		cache.Set("gdd.retry.count", "3", 0)
   279  		cache.Set("gdd.weight", "5", 0)
   280  		configClient.
   281  			EXPECT().
   282  			GetConfigCache(config.DefaultGddApolloNamespace).
   283  			AnyTimes().
   284  			Return(cache)
   285  
   286  		configClient.
   287  			EXPECT().
   288  			AddChangeListener(gomock.Any()).
   289  			AnyTimes().
   290  			Return()
   291  
   292  		configmgr.StartWithConfig = func(loadAppConfig func() (*apolloConfig.AppConfig, error)) (agollo.Client, error) {
   293  			_, _ = loadAppConfig()
   294  			return configClient, nil
   295  		}
   296  
   297  		if configmgr.ApolloClient != nil {
   298  			configmgr.ApolloClient = configClient
   299  		}
   300  
   301  		apolloCluster := config.DefaultGddApolloCluster
   302  		apolloAddr := config.GddApolloAddr.Load()
   303  		apolloNamespace := config.DefaultGddApolloNamespace
   304  		apolloBackupPath := config.DefaultGddApolloBackupPath
   305  		c := &apolloConfig.AppConfig{
   306  			AppID:            config.GddServiceName.Load(),
   307  			Cluster:          apolloCluster,
   308  			IP:               apolloAddr,
   309  			NamespaceName:    apolloNamespace,
   310  			IsBackupConfig:   false,
   311  			BackupConfigPath: apolloBackupPath,
   312  			MustStart:        false,
   313  		}
   314  		So(func() {
   315  			configmgr.LoadFromApollo(c)
   316  		}, ShouldNotPanic)
   317  
   318  		So(NewNode(), ShouldBeNil)
   319  		defer Shutdown()
   320  	})
   321  }
   322  
   323  func TestNewNode_InvalidConfigType(t *testing.T) {
   324  	Convey("Should panic", t, func() {
   325  		setup()
   326  		_ = config.GddConfigRemoteType.Write("invalid")
   327  		defer Shutdown()
   328  		So(func() {
   329  			NewNode()
   330  		}, ShouldPanic)
   331  	})
   332  }
   333  
   334  func TestNewNode_Nacos(t *testing.T) {
   335  	Convey("Should return nil", t, func() {
   336  		setup()
   337  		_ = config.GddServiceDiscoveryMode.Write("nacos")
   338  		ctrl := gomock.NewController(t)
   339  		defer ctrl.Finish()
   340  		defer Shutdown()
   341  
   342  		namingClient := nmock.NewMockINamingClient(ctrl)
   343  		namingClient.
   344  			EXPECT().
   345  			RegisterInstance(gomock.Any()).
   346  			AnyTimes().
   347  			Return(true, nil)
   348  
   349  		namingClient.
   350  			EXPECT().
   351  			DeregisterInstance(gomock.Any()).
   352  			AnyTimes().
   353  			Return(true, nil)
   354  
   355  		nacos.NewNamingClient = func(param vo.NacosClientParam) (iClient naming_client.INamingClient, err error) {
   356  			return namingClient, nil
   357  		}
   358  
   359  		if nacos.NamingClient == nil {
   360  			nacos.NamingClient = namingClient
   361  		}
   362  
   363  		So(NewNode(), ShouldBeNil)
   364  	})
   365  }
   366  
   367  func TestNewNode_InvalidServiceDiscoveryMode(t *testing.T) {
   368  	Convey("Should return nil", t, func() {
   369  		setup()
   370  		_ = config.GddServiceDiscoveryMode.Write("invalid")
   371  		So(NewNode(), ShouldBeNil)
   372  	})
   373  }
   374  
   375  func TestCallbackOnChange(t *testing.T) {
   376  	Convey("Should equal to 30s", t, func() {
   377  		listener := &memConfigListener{
   378  			memConf: &memberlist.Config{},
   379  		}
   380  		CallbackOnChange(listener)(&configmgr.NacosChangeEvent{
   381  			Namespace: config.DefaultGddNacosNamespaceId,
   382  			Group:     config.DefaultGddNacosConfigGroup,
   383  			DataId:    ".env",
   384  			Changes: map[string]maputils.Change{
   385  				"gdd.mem.dead.timeout": {
   386  					OldValue:   "8s",
   387  					NewValue:   "30s",
   388  					ChangeType: maputils.MODIFIED,
   389  				},
   390  			},
   391  		})
   392  		CallbackOnChange(listener)(&configmgr.NacosChangeEvent{
   393  			Namespace: config.DefaultGddNacosNamespaceId,
   394  			Group:     config.DefaultGddNacosConfigGroup,
   395  			DataId:    ".env",
   396  			Changes: map[string]maputils.Change{
   397  				"gdd.mem.dead.timeout": {
   398  					OldValue:   "8s",
   399  					NewValue:   "30s",
   400  					ChangeType: maputils.MODIFIED,
   401  				},
   402  			},
   403  		})
   404  		So(os.Getenv("GDD_MEM_DEAD_TIMEOUT"), ShouldEqual, "30s")
   405  		So(listener.memConf.GossipToTheDeadTime, ShouldEqual, 30*time.Second)
   406  	})
   407  }
   408  
   409  func Test_join_fail1(t *testing.T) {
   410  	mlist = nil
   411  	require.Error(t, join())
   412  }
   413  
   414  func Test_join(t *testing.T) {
   415  	Convey("Join should be successful", t, func() {
   416  		ctrl := gomock.NewController(t)
   417  		defer ctrl.Finish()
   418  		mem := memmock.NewMockIMemberlist(ctrl)
   419  		mlist = mem
   420  		seedAddr := "seed:7946"
   421  		config.GddMemSeed.Write(seedAddr)
   422  		mem.
   423  			EXPECT().
   424  			Join([]string{seedAddr}).
   425  			AnyTimes().
   426  			Return(0, nil)
   427  
   428  		mem.
   429  			EXPECT().
   430  			LocalNode().
   431  			AnyTimes().
   432  			Return(&memberlist.Node{
   433  				Name: "",
   434  				Addr: "test",
   435  				Port: 7946,
   436  			})
   437  
   438  		So(join(), ShouldBeNil)
   439  	})
   440  }
   441  
   442  func Test_newMeta(t *testing.T) {
   443  	Convey("Should panic", t, func() {
   444  		So(func() {
   445  			newMeta(&memberlist.Node{
   446  				Meta: []byte("fake meta"),
   447  			})
   448  		}, ShouldPanic)
   449  	})
   450  }
   451  
   452  func Test_newConf_GddMemCIDRsAllowed(t *testing.T) {
   453  	config.GddMemCIDRsAllowed.Write("172.28.0.0/16")
   454  	newConf()
   455  }
   456  
   457  func Test_newConf_GddMemCIDRsAllowed_error(t *testing.T) {
   458  	config.GddMemCIDRsAllowed.Write("invalid")
   459  	newConf()
   460  }
   461  
   462  func Test_newConf(t *testing.T) {
   463  	defer os.Clearenv()
   464  	config.GddLogLevel.Write("ERROR")
   465  	newConf()
   466  
   467  	config.GddLogLevel.Write("WARNING")
   468  	newConf()
   469  
   470  	config.GddMemLogDisable.Write("true")
   471  	newConf()
   472  
   473  	config.GddWeight.Write("5")
   474  	newConf()
   475  
   476  	config.GddWeight.Write("0")
   477  	newConf()
   478  
   479  	config.GddWeight.Write("0")
   480  	config.GddMemWeightInterval.Write("200")
   481  	newConf()
   482  
   483  	config.GddMemTCPTimeout.Write("10")
   484  	newConf()
   485  
   486  	config.GddMemHost.Write(".seed-headless")
   487  	newConf()
   488  }
   489  
   490  func Test_newNode(t *testing.T) {
   491  	Convey("Test newNode", t, func() {
   492  		Convey("Should return error as service name not set", func() {
   493  			So(newNode().Error(), ShouldEqual, "NewNode() error: No env variable GDD_SERVICE_NAME found")
   494  		})
   495  
   496  		Convey("Should return error as join failed", func() {
   497  			setup()
   498  			buildinfo.BuildTime = "Mon Jan 2 15:04:05 MST 2006"
   499  			config.GddWeight.Write("8")
   500  			config.GddMemSeed.Write("invalid seed")
   501  
   502  			Convey("Should return error as join failed", func() {
   503  				So(newNode(map[string]interface{}{
   504  					"foo": "bar",
   505  				}), ShouldNotBeNil)
   506  			})
   507  
   508  			Convey("Should return error as memberlist create failed", func() {
   509  				defer func() {
   510  					createMemberlist = memberlist.Create
   511  				}()
   512  				createMemberlist = func(conf *memberlist.Config) (*memberlist.Memberlist, error) {
   513  					return nil, errors.New("mock test error")
   514  				}
   515  				So(newNode(), ShouldNotBeNil)
   516  			})
   517  		})
   518  
   519  		Convey("Should return nil", func() {
   520  			setup()
   521  			So(newNode(), ShouldBeNil)
   522  			So(numNodes(), ShouldEqual, 1)
   523  			So(retransmitMultGetter(), ShouldEqual, 4)
   524  		})
   525  	})
   526  }
   527  
   528  func Test_numNodes(t *testing.T) {
   529  	Convey("Should return 0", t, func() {
   530  		mlist = nil
   531  		So(numNodes(), ShouldEqual, 0)
   532  	})
   533  }
   534  
   535  func TestShutdown(t *testing.T) {
   536  	config.GddServiceDiscoveryMode.Write("invalid")
   537  	Shutdown()
   538  }
   539  
   540  func TestLeave(t *testing.T) {
   541  	Convey("Should leave", t, func() {
   542  		ctrl := gomock.NewController(t)
   543  		defer ctrl.Finish()
   544  		mem := memmock.NewMockIMemberlist(ctrl)
   545  		mlist = mem
   546  		mem.
   547  			EXPECT().
   548  			Leave(10 * time.Second).
   549  			AnyTimes().
   550  			Return(nil)
   551  
   552  		Leave(10 * time.Second)
   553  	})
   554  }