github.com/unionj-cloud/go-doudou/v2@v2.3.5/toolkit/memberlist/util_test.go (about)

     1  package memberlist
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/stretchr/testify/require"
    10  )
    11  
    12  func TestUtil_PortFunctions(t *testing.T) {
    13  	tests := []struct {
    14  		addr       string
    15  		hasPort    bool
    16  		ensurePort string
    17  	}{
    18  		{"1.2.3.4", false, "1.2.3.4:8301"},
    19  		{"1.2.3.4:1234", true, "1.2.3.4:1234"},
    20  		{"2600:1f14:e22:1501:f9a:2e0c:a167:67e8", false, "[2600:1f14:e22:1501:f9a:2e0c:a167:67e8]:8301"},
    21  		{"[2600:1f14:e22:1501:f9a:2e0c:a167:67e8]", false, "[2600:1f14:e22:1501:f9a:2e0c:a167:67e8]:8301"},
    22  		{"[2600:1f14:e22:1501:f9a:2e0c:a167:67e8]:1234", true, "[2600:1f14:e22:1501:f9a:2e0c:a167:67e8]:1234"},
    23  		{"localhost", false, "localhost:8301"},
    24  		{"localhost:1234", true, "localhost:1234"},
    25  		{"hashicorp.com", false, "hashicorp.com:8301"},
    26  		{"hashicorp.com:1234", true, "hashicorp.com:1234"},
    27  	}
    28  	for _, tt := range tests {
    29  		t.Run(tt.addr, func(t *testing.T) {
    30  			if got, want := hasPort(tt.addr), tt.hasPort; got != want {
    31  				t.Fatalf("got %v want %v", got, want)
    32  			}
    33  			if got, want := ensurePort(tt.addr, 8301), tt.ensurePort; got != want {
    34  				t.Fatalf("got %v want %v", got, want)
    35  			}
    36  		})
    37  	}
    38  }
    39  
    40  func TestEncodeDecode(t *testing.T) {
    41  	msg := &ping{SeqNo: 100}
    42  	buf, err := encode(pingMsg, msg)
    43  	if err != nil {
    44  		t.Fatalf("unexpected err: %s", err)
    45  	}
    46  	var out ping
    47  	if err := decode(buf.Bytes()[1:], &out); err != nil {
    48  		t.Fatalf("unexpected err: %s", err)
    49  	}
    50  	if msg.SeqNo != out.SeqNo {
    51  		t.Fatalf("bad sequence no")
    52  	}
    53  }
    54  
    55  func TestRandomOffset(t *testing.T) {
    56  	vals := make(map[int]struct{})
    57  	for i := 0; i < 100; i++ {
    58  		offset := randomOffset(2 << 30)
    59  		if _, ok := vals[offset]; ok {
    60  			t.Fatalf("got collision")
    61  		}
    62  		vals[offset] = struct{}{}
    63  	}
    64  }
    65  
    66  func TestRandomOffset_Zero(t *testing.T) {
    67  	offset := randomOffset(0)
    68  	if offset != 0 {
    69  		t.Fatalf("bad offset")
    70  	}
    71  }
    72  
    73  func TestSuspicionTimeout(t *testing.T) {
    74  	timeouts := map[int]time.Duration{
    75  		5:    1000 * time.Millisecond,
    76  		10:   1000 * time.Millisecond,
    77  		50:   1698 * time.Millisecond,
    78  		100:  2000 * time.Millisecond,
    79  		500:  2698 * time.Millisecond,
    80  		1000: 3000 * time.Millisecond,
    81  	}
    82  	for n, expected := range timeouts {
    83  		timeout := suspicionTimeout(3, n, time.Second) / 3
    84  		if timeout != expected {
    85  			t.Fatalf("bad: %v, %v", expected, timeout)
    86  		}
    87  	}
    88  }
    89  
    90  func TestSuspicionTimeout2(t *testing.T) {
    91  	timeout := suspicionTimeout(6, 6, 5*time.Second)
    92  	fmt.Println(timeout)
    93  }
    94  
    95  func TestRetransmitLimit(t *testing.T) {
    96  	lim := retransmitLimit(3, 0)
    97  	if lim != 0 {
    98  		t.Fatalf("bad val %v", lim)
    99  	}
   100  	lim = retransmitLimit(3, 1)
   101  	if lim != 3 {
   102  		t.Fatalf("bad val %v", lim)
   103  	}
   104  	lim = retransmitLimit(3, 99)
   105  	if lim != 6 {
   106  		t.Fatalf("bad val %v", lim)
   107  	}
   108  	lim = retransmitLimit(4, 15)
   109  	if lim != 8 {
   110  		t.Fatalf("bad val %v", lim)
   111  	}
   112  }
   113  
   114  func TestShuffleNodes(t *testing.T) {
   115  	orig := []*nodeState{
   116  		&nodeState{
   117  			State: StateDead,
   118  		},
   119  		&nodeState{
   120  			State: StateAlive,
   121  		},
   122  		&nodeState{
   123  			State: StateAlive,
   124  		},
   125  		&nodeState{
   126  			State: StateDead,
   127  		},
   128  		&nodeState{
   129  			State: StateAlive,
   130  		},
   131  		&nodeState{
   132  			State: StateAlive,
   133  		},
   134  		&nodeState{
   135  			State: StateDead,
   136  		},
   137  		&nodeState{
   138  			State: StateAlive,
   139  		},
   140  	}
   141  	nodes := make([]*nodeState, len(orig))
   142  	copy(nodes[:], orig[:])
   143  
   144  	if !reflect.DeepEqual(nodes, orig) {
   145  		t.Fatalf("should match")
   146  	}
   147  
   148  	shuffleNodes(nodes)
   149  }
   150  
   151  func TestPushPullScale(t *testing.T) {
   152  	sec := time.Second
   153  	for i := 0; i <= 32; i++ {
   154  		if s := pushPullScale(sec, i); s != sec {
   155  			t.Fatalf("Bad time scale: %v", s)
   156  		}
   157  	}
   158  	for i := 33; i <= 64; i++ {
   159  		if s := pushPullScale(sec, i); s != 2*sec {
   160  			t.Fatalf("Bad time scale: %v", s)
   161  		}
   162  	}
   163  	for i := 65; i <= 128; i++ {
   164  		if s := pushPullScale(sec, i); s != 3*sec {
   165  			t.Fatalf("Bad time scale: %v", s)
   166  		}
   167  	}
   168  }
   169  
   170  func TestMoveDeadNodes(t *testing.T) {
   171  	nodes := []*nodeState{
   172  		&nodeState{
   173  			State:       StateDead,
   174  			StateChange: time.Now().Add(-20 * time.Second),
   175  		},
   176  		&nodeState{
   177  			State:       StateAlive,
   178  			StateChange: time.Now().Add(-20 * time.Second),
   179  		},
   180  		// This dead node should not be moved, as its state changed
   181  		// less than the specified GossipToTheDead time ago
   182  		&nodeState{
   183  			State:       StateDead,
   184  			StateChange: time.Now().Add(-10 * time.Second),
   185  		},
   186  		&nodeState{
   187  			State:       StateAlive,
   188  			StateChange: time.Now().Add(-20 * time.Second),
   189  		},
   190  		&nodeState{
   191  			State:       StateDead,
   192  			StateChange: time.Now().Add(-20 * time.Second),
   193  		},
   194  		&nodeState{
   195  			State:       StateAlive,
   196  			StateChange: time.Now().Add(-20 * time.Second),
   197  		},
   198  	}
   199  
   200  	idx := moveDeadNodes(nodes, (15 * time.Second))
   201  	if idx != 4 {
   202  		t.Fatalf("bad index")
   203  	}
   204  	for i := 0; i < idx; i++ {
   205  		switch i {
   206  		case 2:
   207  			// Recently dead node remains at index 2,
   208  			// since nodes are swapped out to move to end.
   209  			if nodes[i].State != StateDead {
   210  				t.Fatalf("Bad state %d", i)
   211  			}
   212  		default:
   213  			if nodes[i].State != StateAlive {
   214  				t.Fatalf("Bad state %d", i)
   215  			}
   216  		}
   217  	}
   218  	for i := idx; i < len(nodes); i++ {
   219  		if nodes[i].State != StateDead {
   220  			t.Fatalf("Bad state %d", i)
   221  		}
   222  	}
   223  }
   224  
   225  func TestKRandomNodes(t *testing.T) {
   226  	nodes := []*nodeState{}
   227  	for i := 0; i < 90; i++ {
   228  		// Half the nodes are in a bad state
   229  		state := StateAlive
   230  		switch i % 3 {
   231  		case 0:
   232  			state = StateAlive
   233  		case 1:
   234  			state = StateSuspect
   235  		case 2:
   236  			state = StateDead
   237  		}
   238  		nodes = append(nodes, &nodeState{
   239  			Node: Node{
   240  				Name: fmt.Sprintf("test%d", i),
   241  			},
   242  			State: state,
   243  		})
   244  	}
   245  
   246  	filterFunc := func(n *nodeState) bool {
   247  		if n.Name == "test0" || n.State != StateAlive {
   248  			return true
   249  		}
   250  		return false
   251  	}
   252  
   253  	s1 := kRandomNodes(3, nodes, filterFunc)
   254  	s2 := kRandomNodes(3, nodes, filterFunc)
   255  	s3 := kRandomNodes(3, nodes, filterFunc)
   256  
   257  	if reflect.DeepEqual(s1, s2) {
   258  		t.Fatalf("unexpected equal")
   259  	}
   260  	if reflect.DeepEqual(s1, s3) {
   261  		t.Fatalf("unexpected equal")
   262  	}
   263  	if reflect.DeepEqual(s2, s3) {
   264  		t.Fatalf("unexpected equal")
   265  	}
   266  
   267  	for _, s := range [][]Node{s1, s2, s3} {
   268  		if len(s) != 3 {
   269  			t.Fatalf("bad len")
   270  		}
   271  		for _, n := range s {
   272  			if n.Name == "test0" {
   273  				t.Fatalf("Bad name")
   274  			}
   275  			if n.State != StateAlive {
   276  				t.Fatalf("Bad state")
   277  			}
   278  		}
   279  	}
   280  }
   281  
   282  func TestMakeCompoundMessage(t *testing.T) {
   283  	msg := &ping{SeqNo: 100}
   284  	buf, err := encode(pingMsg, msg)
   285  	if err != nil {
   286  		t.Fatalf("unexpected err: %s", err)
   287  	}
   288  
   289  	msgs := [][]byte{buf.Bytes(), buf.Bytes(), buf.Bytes()}
   290  	compound := makeCompoundMessage(msgs)
   291  
   292  	if compound.Len() != 3*buf.Len()+3*compoundOverhead+compoundHeaderOverhead {
   293  		t.Fatalf("bad len")
   294  	}
   295  }
   296  
   297  func TestDecodeCompoundMessage(t *testing.T) {
   298  	msg := &ping{SeqNo: 100}
   299  	buf, err := encode(pingMsg, msg)
   300  	if err != nil {
   301  		t.Fatalf("unexpected err: %s", err)
   302  	}
   303  
   304  	msgs := [][]byte{buf.Bytes(), buf.Bytes(), buf.Bytes()}
   305  	compound := makeCompoundMessage(msgs)
   306  
   307  	trunc, parts, err := decodeCompoundMessage(compound.Bytes()[1:])
   308  	if err != nil {
   309  		t.Fatalf("unexpected err: %s", err)
   310  	}
   311  	if trunc != 0 {
   312  		t.Fatalf("should not truncate")
   313  	}
   314  	if len(parts) != 3 {
   315  		t.Fatalf("bad parts")
   316  	}
   317  	for _, p := range parts {
   318  		if len(p) != buf.Len() {
   319  			t.Fatalf("bad part len")
   320  		}
   321  	}
   322  }
   323  
   324  func TestDecodeCompoundMessage_NumberOfPartsOverflow(t *testing.T) {
   325  	buf := []byte{0x80}
   326  	_, _, err := decodeCompoundMessage(buf)
   327  	require.Error(t, err)
   328  	require.Equal(t, err.Error(), "truncated len slice")
   329  }
   330  
   331  func TestDecodeCompoundMessage_Trunc(t *testing.T) {
   332  	msg := &ping{SeqNo: 100}
   333  	buf, err := encode(pingMsg, msg)
   334  	if err != nil {
   335  		t.Fatalf("unexpected err: %s", err)
   336  	}
   337  
   338  	msgs := [][]byte{buf.Bytes(), buf.Bytes(), buf.Bytes()}
   339  	compound := makeCompoundMessage(msgs)
   340  
   341  	trunc, parts, err := decodeCompoundMessage(compound.Bytes()[1:38])
   342  	if err != nil {
   343  		t.Fatalf("unexpected err: %s", err)
   344  	}
   345  	if trunc != 1 {
   346  		t.Fatalf("truncate: %d", trunc)
   347  	}
   348  	if len(parts) != 2 {
   349  		t.Fatalf("bad parts")
   350  	}
   351  	for _, p := range parts {
   352  		if len(p) != buf.Len() {
   353  			t.Fatalf("bad part len")
   354  		}
   355  	}
   356  }
   357  
   358  func TestCompressDecompressPayload(t *testing.T) {
   359  	buf, err := compressPayload([]byte("testing"))
   360  	if err != nil {
   361  		t.Fatalf("unexpected err: %s", err)
   362  	}
   363  
   364  	decomp, err := decompressPayload(buf.Bytes()[1:])
   365  	if err != nil {
   366  		t.Fatalf("unexpected err: %s", err)
   367  	}
   368  
   369  	if !reflect.DeepEqual(decomp, []byte("testing")) {
   370  		t.Fatalf("bad payload: %v", decomp)
   371  	}
   372  }