github.com/dubbogo/gost@v1.14.0/database/kv/etcd/v3/client_test.go (about)

     1  /*
     2   * Licensed to the Apache Software Foundation (ASF) under one or more
     3   * contributor license agreements.  See the NOTICE file distributed with
     4   * this work for additional information regarding copyright ownership.
     5   * The ASF licenses this file to You under the Apache License, Version 2.0
     6   * (the "License"); you may not use this file except in compliance with
     7   * the License.  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  package gxetcd
    19  
    20  import (
    21  	"net/url"
    22  	"os"
    23  	"path"
    24  	"reflect"
    25  	"strings"
    26  	"testing"
    27  	"time"
    28  )
    29  
    30  import (
    31  	perrors "github.com/pkg/errors"
    32  
    33  	"github.com/stretchr/testify/assert"
    34  	"github.com/stretchr/testify/suite"
    35  
    36  	"go.etcd.io/etcd/api/v3/mvccpb"
    37  
    38  	"go.etcd.io/etcd/server/v3/embed"
    39  
    40  	"google.golang.org/grpc/connectivity"
    41  )
    42  
    43  const defaultEtcdV3WorkDir = "/tmp/default-dubbo-go-remote.etcd"
    44  
    45  // tests dataset
    46  var tests = []struct {
    47  	input struct {
    48  		k string
    49  		v string
    50  	}
    51  }{
    52  	{input: struct {
    53  		k string
    54  		v string
    55  	}{k: "name/name", v: "scott.wang"}},
    56  	{input: struct {
    57  		k string
    58  		v string
    59  	}{k: "name/namePrefix", v: "prefix.scott.wang"}},
    60  	{input: struct {
    61  		k string
    62  		v string
    63  	}{k: "name/namePrefix1", v: "prefix1.scott.wang"}},
    64  	{input: struct {
    65  		k string
    66  		v string
    67  	}{k: "age", v: "27"}},
    68  }
    69  
    70  // test dataset prefix
    71  const prefixKey = "name/"
    72  const keyPrefix = "name/name"
    73  
    74  type ClientTestSuite struct {
    75  	suite.Suite
    76  
    77  	etcdConfig struct {
    78  		name      string
    79  		endpoints []string
    80  		timeout   time.Duration
    81  		heartbeat int
    82  	}
    83  
    84  	etcd *embed.Etcd
    85  
    86  	client *Client
    87  }
    88  
    89  // start etcd server
    90  func (suite *ClientTestSuite) SetupSuite() {
    91  	t := suite.T()
    92  
    93  	DefaultListenPeerURLs := "http://localhost:2382"
    94  	DefaultListenClientURLs := "http://localhost:2381"
    95  	lpurl, _ := url.Parse(DefaultListenPeerURLs)
    96  	lcurl, _ := url.Parse(DefaultListenClientURLs)
    97  	cfg := embed.NewConfig()
    98  	cfg.LPUrls = []url.URL{*lpurl}
    99  	cfg.LCUrls = []url.URL{*lcurl}
   100  	cfg.Dir = defaultEtcdV3WorkDir
   101  	e, err := embed.StartEtcd(cfg)
   102  	if err != nil {
   103  		t.Fatal(err)
   104  	}
   105  	select {
   106  	case <-e.Server.ReadyNotify():
   107  		t.Log("Server is ready!")
   108  	case <-time.After(60 * time.Second):
   109  		e.Server.Stop() // trigger a shutdown
   110  		t.Logf("Server took too long to start!")
   111  	}
   112  
   113  	suite.etcd = e
   114  	return
   115  }
   116  
   117  // stop etcd server
   118  func (suite *ClientTestSuite) TearDownSuite() {
   119  	suite.etcd.Close()
   120  	if err := os.RemoveAll(defaultEtcdV3WorkDir); err != nil {
   121  		suite.FailNow(err.Error())
   122  	}
   123  }
   124  
   125  func (suite *ClientTestSuite) setUpClient() *Client {
   126  	c, err := NewConfigClientWithErr(WithName(suite.etcdConfig.name),
   127  		WithEndpoints(suite.etcdConfig.endpoints...),
   128  		WithTimeout(suite.etcdConfig.timeout),
   129  		WithHeartbeat(suite.etcdConfig.heartbeat))
   130  	if err != nil {
   131  		suite.T().Fatal(err)
   132  	}
   133  	return c
   134  }
   135  
   136  // set up a client for suite
   137  func (suite *ClientTestSuite) SetupTest() {
   138  	c := suite.setUpClient()
   139  	c.CleanKV()
   140  	suite.client = c
   141  	return
   142  }
   143  
   144  func (suite *ClientTestSuite) TestClientClose() {
   145  	c := suite.client
   146  	t := suite.T()
   147  
   148  	defer c.Close()
   149  	if c.rawClient.ActiveConnection().GetState() != connectivity.Ready {
   150  		t.Fatal(suite.client.rawClient.ActiveConnection().GetState())
   151  	}
   152  }
   153  
   154  func (suite *ClientTestSuite) TestClientValid() {
   155  	c := suite.client
   156  	t := suite.T()
   157  
   158  	if !c.Valid() {
   159  		t.Fatal("client is not valid")
   160  	}
   161  	c.Close()
   162  	if suite.client.Valid() != false {
   163  		t.Fatal("client is valid")
   164  	}
   165  }
   166  
   167  func (suite *ClientTestSuite) TestClientDone() {
   168  	c := suite.client
   169  
   170  	go func() {
   171  		time.Sleep(2 * time.Second)
   172  		c.Close()
   173  	}()
   174  
   175  	c.Wait.Wait()
   176  
   177  	if c.Valid() {
   178  		suite.T().Fatal("client should be invalid then")
   179  	}
   180  }
   181  
   182  func (suite *ClientTestSuite) TestClientCreateKV() {
   183  	tests := tests
   184  
   185  	c := suite.client
   186  	t := suite.T()
   187  
   188  	defer suite.client.Close()
   189  
   190  	for _, tc := range tests {
   191  
   192  		k := tc.input.k
   193  		v := tc.input.v
   194  		expect := tc.input.v
   195  
   196  		if err := c.Create(k, v); err != nil {
   197  			t.Fatal(err)
   198  		}
   199  
   200  		value, err := c.Get(k)
   201  		if err != nil {
   202  			t.Fatal(err)
   203  		}
   204  
   205  		if value != expect {
   206  			t.Fatalf("expect %v but get %v", expect, value)
   207  		}
   208  
   209  	}
   210  }
   211  
   212  func (suite *ClientTestSuite) TestBatchClientCreateKV() {
   213  	tests := tests
   214  
   215  	c := suite.client
   216  	t := suite.T()
   217  
   218  	defer suite.client.Close()
   219  
   220  	for _, tc := range tests {
   221  
   222  		k := tc.input.k
   223  		v := tc.input.v
   224  		expect := tc.input.v
   225  		kList := make([]string, 0, 1)
   226  		vList := make([]string, 0, 1)
   227  		kList = append(kList, k)
   228  		vList = append(vList, v)
   229  
   230  		if err := c.BatchCreate(kList, vList); err != nil {
   231  			t.Fatal(err)
   232  		}
   233  
   234  		value, err := c.Get(k)
   235  		if err != nil {
   236  			t.Fatal(err)
   237  		}
   238  
   239  		if value != expect {
   240  			t.Fatalf("expect %v but get %v", expect, value)
   241  		}
   242  	}
   243  }
   244  
   245  func (suite *ClientTestSuite) TestBatchClientGetValAndRevKV() {
   246  	tests := tests
   247  
   248  	c := suite.client
   249  	t := suite.T()
   250  
   251  	defer suite.client.Close()
   252  
   253  	for _, tc := range tests {
   254  
   255  		k := tc.input.k
   256  		v := tc.input.v
   257  		expect := tc.input.v
   258  		kList := make([]string, 0, 1)
   259  		vList := make([]string, 0, 1)
   260  		kList = append(kList, k)
   261  		vList = append(vList, v)
   262  
   263  		if err := c.BatchCreate(kList, vList); err != nil {
   264  			t.Fatal(err)
   265  		}
   266  
   267  		value, revision, err := c.getValAndRev(k)
   268  		if err != nil {
   269  			t.Fatal(err)
   270  		}
   271  
   272  		err = c.UpdateWithRev(k, k, revision)
   273  		if err != nil {
   274  			t.Fatal(err)
   275  		}
   276  
   277  		err = c.Update(k, k)
   278  		if err != nil {
   279  			t.Fatal(err)
   280  		}
   281  
   282  		if value != expect {
   283  			t.Fatalf("expect %v but get %v", expect, value)
   284  		}
   285  	}
   286  }
   287  
   288  func (suite *ClientTestSuite) TestClientDeleteKV() {
   289  	tests := tests
   290  	c := suite.client
   291  	t := suite.T()
   292  
   293  	defer c.Close()
   294  
   295  	for _, tc := range tests {
   296  
   297  		k := tc.input.k
   298  		v := tc.input.v
   299  		expect := ErrKVPairNotFound
   300  
   301  		if err := c.Put(k, v); err != nil {
   302  			t.Fatal(err)
   303  		}
   304  
   305  		if err := c.Delete(k); err != nil {
   306  			t.Fatal(err)
   307  		}
   308  
   309  		_, err := c.Get(k)
   310  		if perrors.Cause(err) == expect {
   311  			continue
   312  		}
   313  
   314  		if err != nil {
   315  			t.Fatal(err)
   316  		}
   317  	}
   318  }
   319  
   320  func (suite *ClientTestSuite) TestClientGetChildrenKVList() {
   321  	tests := tests
   322  
   323  	c := suite.client
   324  	t := suite.T()
   325  
   326  	var expectKList []string
   327  	var expectVList []string
   328  
   329  	for _, tc := range tests {
   330  
   331  		k := tc.input.k
   332  		v := tc.input.v
   333  
   334  		if strings.Contains(k, prefixKey) {
   335  			expectKList = append(expectKList, k)
   336  			expectVList = append(expectVList, v)
   337  		}
   338  
   339  		if err := c.Create(k, v); err != nil {
   340  			t.Fatal(err)
   341  		}
   342  	}
   343  
   344  	kList, vList, err := c.GetChildrenKVList(prefixKey)
   345  	if err != nil {
   346  		t.Fatal(err)
   347  	}
   348  
   349  	if reflect.DeepEqual(expectKList, kList) && reflect.DeepEqual(expectVList, vList) {
   350  		return
   351  	}
   352  
   353  	t.Fatalf("expect keylist %v but got %v expect valueList %v but got %v ", expectKList, kList, expectVList, vList)
   354  }
   355  
   356  func (suite *ClientTestSuite) TestClientWatch() {
   357  	tests := tests
   358  
   359  	c := suite.client
   360  	t := suite.T()
   361  
   362  	go func() {
   363  		time.Sleep(time.Second)
   364  		for _, tc := range tests {
   365  
   366  			k := tc.input.k
   367  			v := tc.input.v
   368  
   369  			if err := c.Create(k, v); err != nil {
   370  				assert.Error(t, err)
   371  			}
   372  
   373  			if err := c.delete(k); err != nil {
   374  				assert.Error(t, err)
   375  			}
   376  		}
   377  
   378  		c.Close()
   379  	}()
   380  
   381  	wc, err := c.WatchWithOption(keyPrefix)
   382  	if err != nil {
   383  		assert.Error(t, err)
   384  	}
   385  
   386  	events := make([]mvccpb.Event, 0)
   387  	var eCreate, eDelete mvccpb.Event
   388  
   389  	for e := range wc {
   390  		for _, event := range e.Events {
   391  			events = append(events, (mvccpb.Event)(*event))
   392  			if event.Type == mvccpb.PUT {
   393  				eCreate = (mvccpb.Event)(*event)
   394  			}
   395  			if event.Type == mvccpb.DELETE {
   396  				eDelete = (mvccpb.Event)(*event)
   397  			}
   398  			t.Logf("type IsCreate %v k %s v %s", event.IsCreate(), event.Kv.Key, event.Kv.Value)
   399  		}
   400  	}
   401  
   402  	assert.Equal(t, 2, len(events))
   403  	assert.Contains(t, events, eCreate)
   404  	assert.Contains(t, events, eDelete)
   405  }
   406  
   407  func (suite *ClientTestSuite) TestClientRegisterTemp() {
   408  	c := suite.client
   409  	observeC := suite.setUpClient()
   410  	t := suite.T()
   411  
   412  	go func() {
   413  		time.Sleep(2 * time.Second)
   414  		err := c.RegisterTemp("scott/wang", "test")
   415  		if err != nil {
   416  			assert.Error(t, err)
   417  		}
   418  		c.Close()
   419  	}()
   420  
   421  	completePath := path.Join("scott", "wang")
   422  	wc, err := observeC.watchWithOption(completePath)
   423  	if err != nil {
   424  		assert.Error(t, err)
   425  	}
   426  
   427  	events := make([]mvccpb.Event, 0)
   428  	var eCreate, eDelete mvccpb.Event
   429  
   430  	for e := range wc {
   431  		for _, event := range e.Events {
   432  			events = append(events, (mvccpb.Event)(*event))
   433  			if event.Type == mvccpb.DELETE {
   434  				eDelete = (mvccpb.Event)(*event)
   435  				t.Logf("complete key (%s) is delete", completePath)
   436  				observeC.Close()
   437  				break
   438  			}
   439  			eCreate = (mvccpb.Event)(*event)
   440  			t.Logf("type IsCreate %v k %s v %s", event.IsCreate(), event.Kv.Key, event.Kv.Value)
   441  		}
   442  	}
   443  
   444  	assert.Equal(t, 2, len(events))
   445  	assert.Contains(t, events, eCreate)
   446  	assert.Contains(t, events, eDelete)
   447  }
   448  
   449  func TestClientSuite(t *testing.T) {
   450  	suite.Run(t, &ClientTestSuite{
   451  		etcdConfig: struct {
   452  			name      string
   453  			endpoints []string
   454  			timeout   time.Duration
   455  			heartbeat int
   456  		}{
   457  			name:      "test",
   458  			endpoints: []string{"localhost:2381"},
   459  			timeout:   time.Second,
   460  			heartbeat: 1,
   461  		},
   462  	})
   463  }