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 }