github.com/pwn-term/docker@v0.0.0-20210616085119-6e977cce2565/libnetwork/networkdb/networkdb_test.go (about)

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