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