github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/libnetwork/networkdb/networkdb_test.go (about)

     1  package networkdb
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"log"
     7  	"net"
     8  	"os"
     9  	"strconv"
    10  	"strings"
    11  	"sync/atomic"
    12  	"testing"
    13  	"time"
    14  
    15  	"github.com/docker/docker/pkg/stringid"
    16  	"github.com/docker/go-events"
    17  	"github.com/hashicorp/memberlist"
    18  	"github.com/sirupsen/logrus"
    19  	"gotest.tools/v3/assert"
    20  	is "gotest.tools/v3/assert/cmp"
    21  	"gotest.tools/v3/poll"
    22  
    23  	// this takes care of the incontainer flag
    24  	_ "github.com/docker/libnetwork/testutils"
    25  )
    26  
    27  var dbPort int32 = 10000
    28  
    29  func TestMain(m *testing.M) {
    30  	ioutil.WriteFile("/proc/sys/net/ipv6/conf/lo/disable_ipv6", []byte{'0', '\n'}, 0644)
    31  	logrus.SetLevel(logrus.ErrorLevel)
    32  	os.Exit(m.Run())
    33  }
    34  
    35  func launchNode(t *testing.T, conf Config) *NetworkDB {
    36  	db, err := New(&conf)
    37  	assert.NilError(t, err)
    38  	return db
    39  }
    40  
    41  func createNetworkDBInstances(t *testing.T, num int, namePrefix string, conf *Config) []*NetworkDB {
    42  	var dbs []*NetworkDB
    43  	for i := 0; i < num; i++ {
    44  		localConfig := *conf
    45  		localConfig.Hostname = fmt.Sprintf("%s%d", namePrefix, i+1)
    46  		localConfig.NodeID = stringid.TruncateID(stringid.GenerateRandomID())
    47  		localConfig.BindPort = int(atomic.AddInt32(&dbPort, 1))
    48  		db := launchNode(t, localConfig)
    49  		if i != 0 {
    50  			assert.Check(t, db.Join([]string{fmt.Sprintf("localhost:%d", db.config.BindPort-1)}))
    51  		}
    52  
    53  		dbs = append(dbs, db)
    54  	}
    55  
    56  	// Wait till the cluster creation is successful
    57  	check := func(t poll.LogT) poll.Result {
    58  		// Check that the cluster is properly created
    59  		for i := 0; i < num; i++ {
    60  			if num != len(dbs[i].ClusterPeers()) {
    61  				return poll.Continue("%s:Waiting for cluser peers to be established", dbs[i].config.Hostname)
    62  			}
    63  		}
    64  		return poll.Success()
    65  	}
    66  	poll.WaitOn(t, check, poll.WithDelay(2*time.Second), poll.WithTimeout(20*time.Second))
    67  
    68  	return dbs
    69  }
    70  
    71  func closeNetworkDBInstances(dbs []*NetworkDB) {
    72  	log.Print("Closing DB instances...")
    73  	for _, db := range dbs {
    74  		db.Close()
    75  	}
    76  }
    77  
    78  func (db *NetworkDB) verifyNodeExistence(t *testing.T, node string, present bool) {
    79  	for i := 0; i < 80; i++ {
    80  		db.RLock()
    81  		_, ok := db.nodes[node]
    82  		db.RUnlock()
    83  		if present && ok {
    84  			return
    85  		}
    86  
    87  		if !present && !ok {
    88  			return
    89  		}
    90  
    91  		time.Sleep(50 * time.Millisecond)
    92  	}
    93  
    94  	t.Errorf("%v(%v): Node existence verification for node %s failed", db.config.Hostname, db.config.NodeID, node)
    95  }
    96  
    97  func (db *NetworkDB) verifyNetworkExistence(t *testing.T, node string, id string, present bool) {
    98  	for i := 0; i < 80; i++ {
    99  		db.RLock()
   100  		nn, nnok := db.networks[node]
   101  		db.RUnlock()
   102  		if nnok {
   103  			n, ok := nn[id]
   104  			if present && ok {
   105  				return
   106  			}
   107  
   108  			if !present &&
   109  				((ok && n.leaving) ||
   110  					!ok) {
   111  				return
   112  			}
   113  		}
   114  
   115  		time.Sleep(50 * time.Millisecond)
   116  	}
   117  
   118  	t.Error("Network existence verification failed")
   119  }
   120  
   121  func (db *NetworkDB) verifyEntryExistence(t *testing.T, tname, nid, key, value string, present bool) {
   122  	n := 80
   123  	for i := 0; i < n; i++ {
   124  		entry, err := db.getEntry(tname, nid, key)
   125  		if present && err == nil && string(entry.value) == value {
   126  			return
   127  		}
   128  
   129  		if !present &&
   130  			((err == nil && entry.deleting) ||
   131  				(err != nil)) {
   132  			return
   133  		}
   134  
   135  		if i == n-1 && !present && err != nil {
   136  			return
   137  		}
   138  
   139  		time.Sleep(50 * time.Millisecond)
   140  	}
   141  
   142  	t.Errorf("Entry existence verification test failed for %v(%v)", db.config.Hostname, db.config.NodeID)
   143  }
   144  
   145  func testWatch(t *testing.T, ch chan events.Event, ev interface{}, tname, nid, key, value string) {
   146  	select {
   147  	case rcvdEv := <-ch:
   148  		assert.Check(t, is.Equal(fmt.Sprintf("%T", rcvdEv), fmt.Sprintf("%T", ev)))
   149  		switch rcvdEv.(type) {
   150  		case CreateEvent:
   151  			assert.Check(t, is.Equal(tname, rcvdEv.(CreateEvent).Table))
   152  			assert.Check(t, is.Equal(nid, rcvdEv.(CreateEvent).NetworkID))
   153  			assert.Check(t, is.Equal(key, rcvdEv.(CreateEvent).Key))
   154  			assert.Check(t, is.Equal(value, string(rcvdEv.(CreateEvent).Value)))
   155  		case UpdateEvent:
   156  			assert.Check(t, is.Equal(tname, rcvdEv.(UpdateEvent).Table))
   157  			assert.Check(t, is.Equal(nid, rcvdEv.(UpdateEvent).NetworkID))
   158  			assert.Check(t, is.Equal(key, rcvdEv.(UpdateEvent).Key))
   159  			assert.Check(t, is.Equal(value, string(rcvdEv.(UpdateEvent).Value)))
   160  		case DeleteEvent:
   161  			assert.Check(t, is.Equal(tname, rcvdEv.(DeleteEvent).Table))
   162  			assert.Check(t, is.Equal(nid, rcvdEv.(DeleteEvent).NetworkID))
   163  			assert.Check(t, is.Equal(key, rcvdEv.(DeleteEvent).Key))
   164  		}
   165  	case <-time.After(time.Second):
   166  		t.Fail()
   167  		return
   168  	}
   169  }
   170  
   171  func TestNetworkDBSimple(t *testing.T) {
   172  	dbs := createNetworkDBInstances(t, 2, "node", DefaultConfig())
   173  	closeNetworkDBInstances(dbs)
   174  }
   175  
   176  func TestNetworkDBJoinLeaveNetwork(t *testing.T) {
   177  	dbs := createNetworkDBInstances(t, 2, "node", DefaultConfig())
   178  
   179  	err := dbs[0].JoinNetwork("network1")
   180  	assert.NilError(t, err)
   181  
   182  	dbs[1].verifyNetworkExistence(t, dbs[0].config.NodeID, "network1", true)
   183  
   184  	err = dbs[0].LeaveNetwork("network1")
   185  	assert.NilError(t, err)
   186  
   187  	dbs[1].verifyNetworkExistence(t, dbs[0].config.NodeID, "network1", false)
   188  	closeNetworkDBInstances(dbs)
   189  }
   190  
   191  func TestNetworkDBJoinLeaveNetworks(t *testing.T) {
   192  	dbs := createNetworkDBInstances(t, 2, "node", DefaultConfig())
   193  
   194  	n := 10
   195  	for i := 1; i <= n; i++ {
   196  		err := dbs[0].JoinNetwork(fmt.Sprintf("network0%d", i))
   197  		assert.NilError(t, err)
   198  	}
   199  
   200  	for i := 1; i <= n; i++ {
   201  		err := dbs[1].JoinNetwork(fmt.Sprintf("network1%d", i))
   202  		assert.NilError(t, err)
   203  	}
   204  
   205  	for i := 1; i <= n; i++ {
   206  		dbs[1].verifyNetworkExistence(t, dbs[0].config.NodeID, fmt.Sprintf("network0%d", i), true)
   207  	}
   208  
   209  	for i := 1; i <= n; i++ {
   210  		dbs[0].verifyNetworkExistence(t, dbs[1].config.NodeID, fmt.Sprintf("network1%d", i), true)
   211  	}
   212  
   213  	for i := 1; i <= n; i++ {
   214  		err := dbs[0].LeaveNetwork(fmt.Sprintf("network0%d", i))
   215  		assert.NilError(t, err)
   216  	}
   217  
   218  	for i := 1; i <= n; i++ {
   219  		err := dbs[1].LeaveNetwork(fmt.Sprintf("network1%d", i))
   220  		assert.NilError(t, err)
   221  	}
   222  
   223  	for i := 1; i <= n; i++ {
   224  		dbs[1].verifyNetworkExistence(t, dbs[0].config.NodeID, fmt.Sprintf("network0%d", i), false)
   225  	}
   226  
   227  	for i := 1; i <= n; i++ {
   228  		dbs[0].verifyNetworkExistence(t, dbs[1].config.NodeID, fmt.Sprintf("network1%d", i), false)
   229  	}
   230  
   231  	closeNetworkDBInstances(dbs)
   232  }
   233  
   234  func TestNetworkDBCRUDTableEntry(t *testing.T) {
   235  	dbs := createNetworkDBInstances(t, 3, "node", DefaultConfig())
   236  
   237  	err := dbs[0].JoinNetwork("network1")
   238  	assert.NilError(t, err)
   239  
   240  	dbs[1].verifyNetworkExistence(t, dbs[0].config.NodeID, "network1", true)
   241  
   242  	err = dbs[1].JoinNetwork("network1")
   243  	assert.NilError(t, err)
   244  
   245  	err = dbs[0].CreateEntry("test_table", "network1", "test_key", []byte("test_value"))
   246  	assert.NilError(t, err)
   247  
   248  	dbs[1].verifyEntryExistence(t, "test_table", "network1", "test_key", "test_value", true)
   249  	dbs[2].verifyEntryExistence(t, "test_table", "network1", "test_key", "test_value", false)
   250  
   251  	err = dbs[0].UpdateEntry("test_table", "network1", "test_key", []byte("test_updated_value"))
   252  	assert.NilError(t, err)
   253  
   254  	dbs[1].verifyEntryExistence(t, "test_table", "network1", "test_key", "test_updated_value", true)
   255  
   256  	err = dbs[0].DeleteEntry("test_table", "network1", "test_key")
   257  	assert.NilError(t, err)
   258  
   259  	dbs[1].verifyEntryExistence(t, "test_table", "network1", "test_key", "", false)
   260  
   261  	closeNetworkDBInstances(dbs)
   262  }
   263  
   264  func TestNetworkDBCRUDTableEntries(t *testing.T) {
   265  	dbs := createNetworkDBInstances(t, 2, "node", DefaultConfig())
   266  
   267  	err := dbs[0].JoinNetwork("network1")
   268  	assert.NilError(t, err)
   269  
   270  	dbs[1].verifyNetworkExistence(t, dbs[0].config.NodeID, "network1", true)
   271  
   272  	err = dbs[1].JoinNetwork("network1")
   273  	assert.NilError(t, err)
   274  
   275  	n := 10
   276  	for i := 1; i <= n; i++ {
   277  		err = dbs[0].CreateEntry("test_table", "network1",
   278  			fmt.Sprintf("test_key0%d", i),
   279  			[]byte(fmt.Sprintf("test_value0%d", i)))
   280  		assert.NilError(t, err)
   281  	}
   282  
   283  	for i := 1; i <= n; i++ {
   284  		err = dbs[1].CreateEntry("test_table", "network1",
   285  			fmt.Sprintf("test_key1%d", i),
   286  			[]byte(fmt.Sprintf("test_value1%d", i)))
   287  		assert.NilError(t, err)
   288  	}
   289  
   290  	for i := 1; i <= n; i++ {
   291  		dbs[0].verifyEntryExistence(t, "test_table", "network1",
   292  			fmt.Sprintf("test_key1%d", i),
   293  			fmt.Sprintf("test_value1%d", i), true)
   294  		assert.NilError(t, err)
   295  	}
   296  
   297  	for i := 1; i <= n; i++ {
   298  		dbs[1].verifyEntryExistence(t, "test_table", "network1",
   299  			fmt.Sprintf("test_key0%d", i),
   300  			fmt.Sprintf("test_value0%d", i), true)
   301  		assert.NilError(t, err)
   302  	}
   303  
   304  	// Verify deletes
   305  	for i := 1; i <= n; i++ {
   306  		err = dbs[0].DeleteEntry("test_table", "network1",
   307  			fmt.Sprintf("test_key0%d", i))
   308  		assert.NilError(t, err)
   309  	}
   310  
   311  	for i := 1; i <= n; i++ {
   312  		err = dbs[1].DeleteEntry("test_table", "network1",
   313  			fmt.Sprintf("test_key1%d", i))
   314  		assert.NilError(t, err)
   315  	}
   316  
   317  	for i := 1; i <= n; i++ {
   318  		dbs[0].verifyEntryExistence(t, "test_table", "network1",
   319  			fmt.Sprintf("test_key1%d", i), "", false)
   320  		assert.NilError(t, err)
   321  	}
   322  
   323  	for i := 1; i <= n; i++ {
   324  		dbs[1].verifyEntryExistence(t, "test_table", "network1",
   325  			fmt.Sprintf("test_key0%d", i), "", false)
   326  		assert.NilError(t, err)
   327  	}
   328  
   329  	closeNetworkDBInstances(dbs)
   330  }
   331  
   332  func TestNetworkDBNodeLeave(t *testing.T) {
   333  	dbs := createNetworkDBInstances(t, 2, "node", DefaultConfig())
   334  
   335  	err := dbs[0].JoinNetwork("network1")
   336  	assert.NilError(t, err)
   337  
   338  	err = dbs[1].JoinNetwork("network1")
   339  	assert.NilError(t, err)
   340  
   341  	err = dbs[0].CreateEntry("test_table", "network1", "test_key", []byte("test_value"))
   342  	assert.NilError(t, err)
   343  
   344  	dbs[1].verifyEntryExistence(t, "test_table", "network1", "test_key", "test_value", true)
   345  
   346  	dbs[0].Close()
   347  	dbs[1].verifyEntryExistence(t, "test_table", "network1", "test_key", "test_value", false)
   348  	dbs[1].Close()
   349  }
   350  
   351  func TestNetworkDBWatch(t *testing.T) {
   352  	dbs := createNetworkDBInstances(t, 2, "node", DefaultConfig())
   353  	err := dbs[0].JoinNetwork("network1")
   354  	assert.NilError(t, err)
   355  
   356  	err = dbs[1].JoinNetwork("network1")
   357  	assert.NilError(t, err)
   358  
   359  	ch, cancel := dbs[1].Watch("", "", "")
   360  
   361  	err = dbs[0].CreateEntry("test_table", "network1", "test_key", []byte("test_value"))
   362  	assert.NilError(t, err)
   363  
   364  	testWatch(t, ch.C, CreateEvent{}, "test_table", "network1", "test_key", "test_value")
   365  
   366  	err = dbs[0].UpdateEntry("test_table", "network1", "test_key", []byte("test_updated_value"))
   367  	assert.NilError(t, err)
   368  
   369  	testWatch(t, ch.C, UpdateEvent{}, "test_table", "network1", "test_key", "test_updated_value")
   370  
   371  	err = dbs[0].DeleteEntry("test_table", "network1", "test_key")
   372  	assert.NilError(t, err)
   373  
   374  	testWatch(t, ch.C, DeleteEvent{}, "test_table", "network1", "test_key", "")
   375  
   376  	cancel()
   377  	closeNetworkDBInstances(dbs)
   378  }
   379  
   380  func TestNetworkDBBulkSync(t *testing.T) {
   381  	dbs := createNetworkDBInstances(t, 2, "node", DefaultConfig())
   382  
   383  	err := dbs[0].JoinNetwork("network1")
   384  	assert.NilError(t, err)
   385  
   386  	dbs[1].verifyNetworkExistence(t, dbs[0].config.NodeID, "network1", true)
   387  
   388  	n := 1000
   389  	for i := 1; i <= n; i++ {
   390  		err = dbs[0].CreateEntry("test_table", "network1",
   391  			fmt.Sprintf("test_key0%d", i),
   392  			[]byte(fmt.Sprintf("test_value0%d", i)))
   393  		assert.NilError(t, err)
   394  	}
   395  
   396  	err = dbs[1].JoinNetwork("network1")
   397  	assert.NilError(t, err)
   398  
   399  	dbs[0].verifyNetworkExistence(t, dbs[1].config.NodeID, "network1", true)
   400  
   401  	for i := 1; i <= n; i++ {
   402  		dbs[1].verifyEntryExistence(t, "test_table", "network1",
   403  			fmt.Sprintf("test_key0%d", i),
   404  			fmt.Sprintf("test_value0%d", i), true)
   405  		assert.NilError(t, err)
   406  	}
   407  
   408  	closeNetworkDBInstances(dbs)
   409  }
   410  
   411  func TestNetworkDBCRUDMediumCluster(t *testing.T) {
   412  	n := 5
   413  
   414  	dbs := createNetworkDBInstances(t, n, "node", DefaultConfig())
   415  
   416  	for i := 0; i < n; i++ {
   417  		for j := 0; j < n; j++ {
   418  			if i == j {
   419  				continue
   420  			}
   421  
   422  			dbs[i].verifyNodeExistence(t, dbs[j].config.NodeID, true)
   423  		}
   424  	}
   425  
   426  	for i := 0; i < n; i++ {
   427  		err := dbs[i].JoinNetwork("network1")
   428  		assert.NilError(t, err)
   429  	}
   430  
   431  	for i := 0; i < n; i++ {
   432  		for j := 0; j < n; j++ {
   433  			dbs[i].verifyNetworkExistence(t, dbs[j].config.NodeID, "network1", true)
   434  		}
   435  	}
   436  
   437  	err := dbs[0].CreateEntry("test_table", "network1", "test_key", []byte("test_value"))
   438  	assert.NilError(t, err)
   439  
   440  	for i := 1; i < n; i++ {
   441  		dbs[i].verifyEntryExistence(t, "test_table", "network1", "test_key", "test_value", true)
   442  	}
   443  
   444  	err = dbs[0].UpdateEntry("test_table", "network1", "test_key", []byte("test_updated_value"))
   445  	assert.NilError(t, err)
   446  
   447  	for i := 1; i < n; i++ {
   448  		dbs[i].verifyEntryExistence(t, "test_table", "network1", "test_key", "test_updated_value", true)
   449  	}
   450  
   451  	err = dbs[0].DeleteEntry("test_table", "network1", "test_key")
   452  	assert.NilError(t, err)
   453  
   454  	for i := 1; i < n; i++ {
   455  		dbs[i].verifyEntryExistence(t, "test_table", "network1", "test_key", "", false)
   456  	}
   457  
   458  	for i := 1; i < n; i++ {
   459  		_, err = dbs[i].GetEntry("test_table", "network1", "test_key")
   460  		assert.Check(t, is.ErrorContains(err, ""))
   461  		assert.Check(t, strings.Contains(err.Error(), "deleted and pending garbage collection"))
   462  	}
   463  
   464  	closeNetworkDBInstances(dbs)
   465  }
   466  
   467  func TestNetworkDBNodeJoinLeaveIteration(t *testing.T) {
   468  	maxRetry := 5
   469  	dbs := createNetworkDBInstances(t, 2, "node", DefaultConfig())
   470  
   471  	// Single node Join/Leave
   472  	err := dbs[0].JoinNetwork("network1")
   473  	assert.NilError(t, err)
   474  
   475  	if len(dbs[0].networkNodes["network1"]) != 1 {
   476  		t.Fatalf("The networkNodes list has to have be 1 instead of %d", len(dbs[0].networkNodes["network1"]))
   477  	}
   478  
   479  	err = dbs[0].LeaveNetwork("network1")
   480  	assert.NilError(t, err)
   481  
   482  	if len(dbs[0].networkNodes["network1"]) != 0 {
   483  		t.Fatalf("The networkNodes list has to have be 0 instead of %d", len(dbs[0].networkNodes["network1"]))
   484  	}
   485  
   486  	// Multiple nodes Join/Leave
   487  	err = dbs[0].JoinNetwork("network1")
   488  	assert.NilError(t, err)
   489  
   490  	err = dbs[1].JoinNetwork("network1")
   491  	assert.NilError(t, err)
   492  
   493  	// Wait for the propagation on db[0]
   494  	for i := 0; i < maxRetry; i++ {
   495  		if len(dbs[0].networkNodes["network1"]) == 2 {
   496  			break
   497  		}
   498  		time.Sleep(1 * time.Second)
   499  	}
   500  	if len(dbs[0].networkNodes["network1"]) != 2 {
   501  		t.Fatalf("The networkNodes list has to have be 2 instead of %d - %v", len(dbs[0].networkNodes["network1"]), dbs[0].networkNodes["network1"])
   502  	}
   503  	if n, ok := dbs[0].networks[dbs[0].config.NodeID]["network1"]; !ok || n.leaving {
   504  		t.Fatalf("The network should not be marked as leaving:%t", n.leaving)
   505  	}
   506  
   507  	// Wait for the propagation on db[1]
   508  	for i := 0; i < maxRetry; i++ {
   509  		if len(dbs[1].networkNodes["network1"]) == 2 {
   510  			break
   511  		}
   512  		time.Sleep(1 * time.Second)
   513  	}
   514  	if len(dbs[1].networkNodes["network1"]) != 2 {
   515  		t.Fatalf("The networkNodes list has to have be 2 instead of %d - %v", len(dbs[1].networkNodes["network1"]), dbs[1].networkNodes["network1"])
   516  	}
   517  	if n, ok := dbs[1].networks[dbs[1].config.NodeID]["network1"]; !ok || n.leaving {
   518  		t.Fatalf("The network should not be marked as leaving:%t", n.leaving)
   519  	}
   520  
   521  	// Try a quick leave/join
   522  	err = dbs[0].LeaveNetwork("network1")
   523  	assert.NilError(t, err)
   524  	err = dbs[0].JoinNetwork("network1")
   525  	assert.NilError(t, err)
   526  
   527  	for i := 0; i < maxRetry; i++ {
   528  		if len(dbs[0].networkNodes["network1"]) == 2 {
   529  			break
   530  		}
   531  		time.Sleep(1 * time.Second)
   532  	}
   533  	if len(dbs[0].networkNodes["network1"]) != 2 {
   534  		t.Fatalf("The networkNodes list has to have be 2 instead of %d - %v", len(dbs[0].networkNodes["network1"]), dbs[0].networkNodes["network1"])
   535  	}
   536  
   537  	for i := 0; i < maxRetry; i++ {
   538  		if len(dbs[1].networkNodes["network1"]) == 2 {
   539  			break
   540  		}
   541  		time.Sleep(1 * time.Second)
   542  	}
   543  	if len(dbs[1].networkNodes["network1"]) != 2 {
   544  		t.Fatalf("The networkNodes list has to have be 2 instead of %d - %v", len(dbs[1].networkNodes["network1"]), dbs[1].networkNodes["network1"])
   545  	}
   546  
   547  	closeNetworkDBInstances(dbs)
   548  }
   549  
   550  func TestNetworkDBGarbageCollection(t *testing.T) {
   551  	keysWriteDelete := 5
   552  	config := DefaultConfig()
   553  	config.reapEntryInterval = 30 * time.Second
   554  	config.StatsPrintPeriod = 15 * time.Second
   555  
   556  	dbs := createNetworkDBInstances(t, 3, "node", config)
   557  
   558  	// 2 Nodes join network
   559  	err := dbs[0].JoinNetwork("network1")
   560  	assert.NilError(t, err)
   561  
   562  	err = dbs[1].JoinNetwork("network1")
   563  	assert.NilError(t, err)
   564  
   565  	for i := 0; i < keysWriteDelete; i++ {
   566  		err = dbs[i%2].CreateEntry("testTable", "network1", "key-"+strconv.Itoa(i), []byte("value"))
   567  		assert.NilError(t, err)
   568  	}
   569  	time.Sleep(time.Second)
   570  	for i := 0; i < keysWriteDelete; i++ {
   571  		err = dbs[i%2].DeleteEntry("testTable", "network1", "key-"+strconv.Itoa(i))
   572  		assert.NilError(t, err)
   573  	}
   574  	for i := 0; i < 2; i++ {
   575  		assert.Check(t, is.Equal(keysWriteDelete, dbs[i].networks[dbs[i].config.NodeID]["network1"].entriesNumber), "entries number should match")
   576  	}
   577  
   578  	// from this point the timer for the garbage collection started, wait 5 seconds and then join a new node
   579  	time.Sleep(5 * time.Second)
   580  
   581  	err = dbs[2].JoinNetwork("network1")
   582  	assert.NilError(t, err)
   583  	for i := 0; i < 3; i++ {
   584  		assert.Check(t, is.Equal(keysWriteDelete, dbs[i].networks[dbs[i].config.NodeID]["network1"].entriesNumber), "entries number should match")
   585  	}
   586  	// at this point the entries should had been all deleted
   587  	time.Sleep(30 * time.Second)
   588  	for i := 0; i < 3; i++ {
   589  		assert.Check(t, is.Equal(0, dbs[i].networks[dbs[i].config.NodeID]["network1"].entriesNumber), "entries should had been garbage collected")
   590  	}
   591  
   592  	// make sure that entries are not coming back
   593  	time.Sleep(15 * time.Second)
   594  	for i := 0; i < 3; i++ {
   595  		assert.Check(t, is.Equal(0, dbs[i].networks[dbs[i].config.NodeID]["network1"].entriesNumber), "entries should had been garbage collected")
   596  	}
   597  
   598  	closeNetworkDBInstances(dbs)
   599  }
   600  
   601  func TestFindNode(t *testing.T) {
   602  	dbs := createNetworkDBInstances(t, 1, "node", DefaultConfig())
   603  
   604  	dbs[0].nodes["active"] = &node{Node: memberlist.Node{Name: "active"}}
   605  	dbs[0].failedNodes["failed"] = &node{Node: memberlist.Node{Name: "failed"}}
   606  	dbs[0].leftNodes["left"] = &node{Node: memberlist.Node{Name: "left"}}
   607  
   608  	// active nodes is 2 because the testing node is in the list
   609  	assert.Check(t, is.Len(dbs[0].nodes, 2))
   610  	assert.Check(t, is.Len(dbs[0].failedNodes, 1))
   611  	assert.Check(t, is.Len(dbs[0].leftNodes, 1))
   612  
   613  	n, currState, m := dbs[0].findNode("active")
   614  	assert.Check(t, n != nil)
   615  	assert.Check(t, is.Equal("active", n.Name))
   616  	assert.Check(t, is.Equal(nodeActiveState, currState))
   617  	assert.Check(t, m != nil)
   618  	// delete the entry manually
   619  	delete(m, "active")
   620  
   621  	// test if can be still find
   622  	n, currState, m = dbs[0].findNode("active")
   623  	assert.Check(t, is.Nil(n))
   624  	assert.Check(t, is.Equal(nodeNotFound, currState))
   625  	assert.Check(t, is.Nil(m))
   626  
   627  	n, currState, m = dbs[0].findNode("failed")
   628  	assert.Check(t, n != nil)
   629  	assert.Check(t, is.Equal("failed", n.Name))
   630  	assert.Check(t, is.Equal(nodeFailedState, currState))
   631  	assert.Check(t, m != nil)
   632  
   633  	// find and remove
   634  	n, currState, m = dbs[0].findNode("left")
   635  	assert.Check(t, n != nil)
   636  	assert.Check(t, is.Equal("left", n.Name))
   637  	assert.Check(t, is.Equal(nodeLeftState, currState))
   638  	assert.Check(t, m != nil)
   639  	delete(m, "left")
   640  
   641  	n, currState, m = dbs[0].findNode("left")
   642  	assert.Check(t, is.Nil(n))
   643  	assert.Check(t, is.Equal(nodeNotFound, currState))
   644  	assert.Check(t, is.Nil(m))
   645  
   646  	closeNetworkDBInstances(dbs)
   647  }
   648  
   649  func TestChangeNodeState(t *testing.T) {
   650  	dbs := createNetworkDBInstances(t, 1, "node", DefaultConfig())
   651  
   652  	dbs[0].nodes["node1"] = &node{Node: memberlist.Node{Name: "node1"}}
   653  	dbs[0].nodes["node2"] = &node{Node: memberlist.Node{Name: "node2"}}
   654  	dbs[0].nodes["node3"] = &node{Node: memberlist.Node{Name: "node3"}}
   655  
   656  	// active nodes is 4 because the testing node is in the list
   657  	assert.Check(t, is.Len(dbs[0].nodes, 4))
   658  
   659  	n, currState, m := dbs[0].findNode("node1")
   660  	assert.Check(t, n != nil)
   661  	assert.Check(t, is.Equal(nodeActiveState, currState))
   662  	assert.Check(t, is.Equal("node1", n.Name))
   663  	assert.Check(t, m != nil)
   664  
   665  	// node1 to failed
   666  	dbs[0].changeNodeState("node1", nodeFailedState)
   667  
   668  	n, currState, m = dbs[0].findNode("node1")
   669  	assert.Check(t, n != nil)
   670  	assert.Check(t, is.Equal(nodeFailedState, currState))
   671  	assert.Check(t, is.Equal("node1", n.Name))
   672  	assert.Check(t, m != nil)
   673  	assert.Check(t, time.Duration(0) != n.reapTime)
   674  
   675  	// node1 back to active
   676  	dbs[0].changeNodeState("node1", nodeActiveState)
   677  
   678  	n, currState, m = dbs[0].findNode("node1")
   679  	assert.Check(t, n != nil)
   680  	assert.Check(t, is.Equal(nodeActiveState, currState))
   681  	assert.Check(t, is.Equal("node1", n.Name))
   682  	assert.Check(t, m != nil)
   683  	assert.Check(t, is.Equal(time.Duration(0), n.reapTime))
   684  
   685  	// node1 to left
   686  	dbs[0].changeNodeState("node1", nodeLeftState)
   687  	dbs[0].changeNodeState("node2", nodeLeftState)
   688  	dbs[0].changeNodeState("node3", nodeLeftState)
   689  
   690  	n, currState, m = dbs[0].findNode("node1")
   691  	assert.Check(t, n != nil)
   692  	assert.Check(t, is.Equal(nodeLeftState, currState))
   693  	assert.Check(t, is.Equal("node1", n.Name))
   694  	assert.Check(t, m != nil)
   695  	assert.Check(t, time.Duration(0) != n.reapTime)
   696  
   697  	n, currState, m = dbs[0].findNode("node2")
   698  	assert.Check(t, n != nil)
   699  	assert.Check(t, is.Equal(nodeLeftState, currState))
   700  	assert.Check(t, is.Equal("node2", n.Name))
   701  	assert.Check(t, m != nil)
   702  	assert.Check(t, time.Duration(0) != n.reapTime)
   703  
   704  	n, currState, m = dbs[0].findNode("node3")
   705  	assert.Check(t, n != nil)
   706  	assert.Check(t, is.Equal(nodeLeftState, currState))
   707  	assert.Check(t, is.Equal("node3", n.Name))
   708  	assert.Check(t, m != nil)
   709  	assert.Check(t, time.Duration(0) != n.reapTime)
   710  
   711  	// active nodes is 1 because the testing node is in the list
   712  	assert.Check(t, is.Len(dbs[0].nodes, 1))
   713  	assert.Check(t, is.Len(dbs[0].failedNodes, 0))
   714  	assert.Check(t, is.Len(dbs[0].leftNodes, 3))
   715  
   716  	closeNetworkDBInstances(dbs)
   717  }
   718  
   719  func TestNodeReincarnation(t *testing.T) {
   720  	dbs := createNetworkDBInstances(t, 1, "node", DefaultConfig())
   721  
   722  	dbs[0].nodes["node1"] = &node{Node: memberlist.Node{Name: "node1", Addr: net.ParseIP("192.168.1.1")}}
   723  	dbs[0].leftNodes["node2"] = &node{Node: memberlist.Node{Name: "node2", Addr: net.ParseIP("192.168.1.2")}}
   724  	dbs[0].failedNodes["node3"] = &node{Node: memberlist.Node{Name: "node3", Addr: net.ParseIP("192.168.1.3")}}
   725  
   726  	// active nodes is 2 because the testing node is in the list
   727  	assert.Check(t, is.Len(dbs[0].nodes, 2))
   728  	assert.Check(t, is.Len(dbs[0].failedNodes, 1))
   729  	assert.Check(t, is.Len(dbs[0].leftNodes, 1))
   730  
   731  	b := dbs[0].purgeReincarnation(&memberlist.Node{Name: "node4", Addr: net.ParseIP("192.168.1.1")})
   732  	assert.Check(t, b)
   733  	dbs[0].nodes["node4"] = &node{Node: memberlist.Node{Name: "node4", Addr: net.ParseIP("192.168.1.1")}}
   734  
   735  	b = dbs[0].purgeReincarnation(&memberlist.Node{Name: "node5", Addr: net.ParseIP("192.168.1.2")})
   736  	assert.Check(t, b)
   737  	dbs[0].nodes["node5"] = &node{Node: memberlist.Node{Name: "node5", Addr: net.ParseIP("192.168.1.1")}}
   738  
   739  	b = dbs[0].purgeReincarnation(&memberlist.Node{Name: "node6", Addr: net.ParseIP("192.168.1.3")})
   740  	assert.Check(t, b)
   741  	dbs[0].nodes["node6"] = &node{Node: memberlist.Node{Name: "node6", Addr: net.ParseIP("192.168.1.1")}}
   742  
   743  	b = dbs[0].purgeReincarnation(&memberlist.Node{Name: "node6", Addr: net.ParseIP("192.168.1.10")})
   744  	assert.Check(t, !b)
   745  
   746  	// active nodes is 1 because the testing node is in the list
   747  	assert.Check(t, is.Len(dbs[0].nodes, 4))
   748  	assert.Check(t, is.Len(dbs[0].failedNodes, 0))
   749  	assert.Check(t, is.Len(dbs[0].leftNodes, 3))
   750  
   751  	closeNetworkDBInstances(dbs)
   752  }
   753  
   754  func TestParallelCreate(t *testing.T) {
   755  	dbs := createNetworkDBInstances(t, 1, "node", DefaultConfig())
   756  
   757  	startCh := make(chan int)
   758  	doneCh := make(chan error)
   759  	var success int32
   760  	for i := 0; i < 20; i++ {
   761  		go func() {
   762  			<-startCh
   763  			err := dbs[0].CreateEntry("testTable", "testNetwork", "key", []byte("value"))
   764  			if err == nil {
   765  				atomic.AddInt32(&success, 1)
   766  			}
   767  			doneCh <- err
   768  		}()
   769  	}
   770  
   771  	close(startCh)
   772  
   773  	for i := 0; i < 20; i++ {
   774  		<-doneCh
   775  	}
   776  	close(doneCh)
   777  	// Only 1 write should have succeeded
   778  	assert.Check(t, is.Equal(int32(1), success))
   779  
   780  	closeNetworkDBInstances(dbs)
   781  }
   782  
   783  func TestParallelDelete(t *testing.T) {
   784  	dbs := createNetworkDBInstances(t, 1, "node", DefaultConfig())
   785  
   786  	err := dbs[0].CreateEntry("testTable", "testNetwork", "key", []byte("value"))
   787  	assert.NilError(t, err)
   788  
   789  	startCh := make(chan int)
   790  	doneCh := make(chan error)
   791  	var success int32
   792  	for i := 0; i < 20; i++ {
   793  		go func() {
   794  			<-startCh
   795  			err := dbs[0].DeleteEntry("testTable", "testNetwork", "key")
   796  			if err == nil {
   797  				atomic.AddInt32(&success, 1)
   798  			}
   799  			doneCh <- err
   800  		}()
   801  	}
   802  
   803  	close(startCh)
   804  
   805  	for i := 0; i < 20; i++ {
   806  		<-doneCh
   807  	}
   808  	close(doneCh)
   809  	// Only 1 write should have succeeded
   810  	assert.Check(t, is.Equal(int32(1), success))
   811  
   812  	closeNetworkDBInstances(dbs)
   813  }
   814  
   815  func TestNetworkDBIslands(t *testing.T) {
   816  	logrus.SetLevel(logrus.DebugLevel)
   817  	dbs := createNetworkDBInstances(t, 5, "node", DefaultConfig())
   818  
   819  	// Get the node IP used currently
   820  	node, _ := dbs[0].nodes[dbs[0].config.NodeID]
   821  	baseIPStr := node.Addr.String()
   822  	// Node 0,1,2 are going to be the 3 bootstrap nodes
   823  	members := []string{fmt.Sprintf("%s:%d", baseIPStr, dbs[0].config.BindPort),
   824  		fmt.Sprintf("%s:%d", baseIPStr, dbs[1].config.BindPort),
   825  		fmt.Sprintf("%s:%d", baseIPStr, dbs[2].config.BindPort)}
   826  	// Rejoining will update the list of the bootstrap members
   827  	for i := 3; i < 5; i++ {
   828  		assert.Check(t, dbs[i].Join(members))
   829  	}
   830  
   831  	// Now the 3 bootstrap nodes will cleanly leave, and will be properly removed from the other 2 nodes
   832  	for i := 0; i < 3; i++ {
   833  		logrus.Infof("node %d leaving", i)
   834  		dbs[i].Close()
   835  	}
   836  
   837  	// Give some time to let the system propagate the messages and free up the ports
   838  	check := func(t poll.LogT) poll.Result {
   839  		// Verify that the nodes are actually all gone and marked appropiately
   840  		for i := 3; i < 5; i++ {
   841  			if (len(dbs[i].leftNodes) != 3) || (len(dbs[i].failedNodes) != 0) {
   842  				return poll.Continue("%s:Waiting for all nodes to cleanly leave", dbs[i].config.Hostname)
   843  			}
   844  		}
   845  		return poll.Success()
   846  	}
   847  	poll.WaitOn(t, check, poll.WithDelay(20*time.Second), poll.WithTimeout(120*time.Second))
   848  
   849  	// Spawn again the first 3 nodes with different names but same IP:port
   850  	for i := 0; i < 3; i++ {
   851  		logrus.Infof("node %d coming back", i)
   852  		dbs[i].config.NodeID = stringid.TruncateID(stringid.GenerateRandomID())
   853  		dbs[i] = launchNode(t, *dbs[i].config)
   854  	}
   855  
   856  	// Give some time for the reconnect routine to run, it runs every 60s
   857  	check = func(t poll.LogT) poll.Result {
   858  		// Verify that the cluster is again all connected. Note that the 3 previous node did not do any join
   859  		for i := 0; i < 5; i++ {
   860  			if len(dbs[i].nodes) != 5 {
   861  				return poll.Continue("%s:Waiting to connect to all nodes", dbs[i].config.Hostname)
   862  			}
   863  			if len(dbs[i].failedNodes) != 0 {
   864  				return poll.Continue("%s:Waiting for 0 failedNodes", dbs[i].config.Hostname)
   865  			}
   866  			if i < 3 {
   867  				// nodes from 0 to 3 has no left nodes
   868  				if len(dbs[i].leftNodes) != 0 {
   869  					return poll.Continue("%s:Waiting to have no leftNodes", dbs[i].config.Hostname)
   870  				}
   871  			} else {
   872  				// nodes from 4 to 5 has the 3 previous left nodes
   873  				if len(dbs[i].leftNodes) != 3 {
   874  					return poll.Continue("%s:Waiting to have 3 leftNodes", dbs[i].config.Hostname)
   875  				}
   876  			}
   877  		}
   878  		return poll.Success()
   879  	}
   880  	poll.WaitOn(t, check, poll.WithDelay(20*time.Second), poll.WithTimeout(120*time.Second))
   881  	closeNetworkDBInstances(dbs)
   882  }