github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/libnetwork/networkdb/networkdb_test.go (about)

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