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

     1  package memberlist
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/google/btree"
     7  	"github.com/stretchr/testify/require"
     8  )
     9  
    10  func TestLimitedBroadcastLess(t *testing.T) {
    11  	cases := []struct {
    12  		Name string
    13  		A    *limitedBroadcast // lesser
    14  		B    *limitedBroadcast
    15  	}{
    16  		{
    17  			"diff-transmits",
    18  			&limitedBroadcast{transmits: 0, msgLen: 10, id: 100},
    19  			&limitedBroadcast{transmits: 1, msgLen: 10, id: 100},
    20  		},
    21  		{
    22  			"same-transmits--diff-len",
    23  			&limitedBroadcast{transmits: 0, msgLen: 12, id: 100},
    24  			&limitedBroadcast{transmits: 0, msgLen: 10, id: 100},
    25  		},
    26  		{
    27  			"same-transmits--same-len--diff-id",
    28  			&limitedBroadcast{transmits: 0, msgLen: 12, id: 100},
    29  			&limitedBroadcast{transmits: 0, msgLen: 12, id: 90},
    30  		},
    31  	}
    32  
    33  	for _, c := range cases {
    34  		t.Run(c.Name, func(t *testing.T) {
    35  			a, b := c.A, c.B
    36  
    37  			require.True(t, a.Less(b))
    38  
    39  			tree := btree.New(32)
    40  
    41  			tree.ReplaceOrInsert(b)
    42  			tree.ReplaceOrInsert(a)
    43  
    44  			min := tree.Min().(*limitedBroadcast)
    45  			require.Equal(t, a.transmits, min.transmits)
    46  			require.Equal(t, a.msgLen, min.msgLen)
    47  			require.Equal(t, a.id, min.id)
    48  
    49  			max := tree.Max().(*limitedBroadcast)
    50  			require.Equal(t, b.transmits, max.transmits)
    51  			require.Equal(t, b.msgLen, max.msgLen)
    52  			require.Equal(t, b.id, max.id)
    53  		})
    54  	}
    55  }
    56  
    57  func TestTransmitLimited_Queue(t *testing.T) {
    58  	q := &TransmitLimitedQueue{RetransmitMult: 1, NumNodes: func() int { return 1 }}
    59  	q.QueueBroadcast(&memberlistBroadcast{"test", nil, nil})
    60  	q.QueueBroadcast(&memberlistBroadcast{"foo", nil, nil})
    61  	q.QueueBroadcast(&memberlistBroadcast{"bar", nil, nil})
    62  
    63  	if q.NumQueued() != 3 {
    64  		t.Fatalf("bad len")
    65  	}
    66  	dump := q.orderedView(true)
    67  	if dump[0].b.(*memberlistBroadcast).node != "test" {
    68  		t.Fatalf("missing test")
    69  	}
    70  	if dump[1].b.(*memberlistBroadcast).node != "foo" {
    71  		t.Fatalf("missing foo")
    72  	}
    73  	if dump[2].b.(*memberlistBroadcast).node != "bar" {
    74  		t.Fatalf("missing bar")
    75  	}
    76  
    77  	// Should invalidate previous message
    78  	q.QueueBroadcast(&memberlistBroadcast{"test", nil, nil})
    79  
    80  	if q.NumQueued() != 3 {
    81  		t.Fatalf("bad len")
    82  	}
    83  	dump = q.orderedView(true)
    84  	if dump[0].b.(*memberlistBroadcast).node != "foo" {
    85  		t.Fatalf("missing foo")
    86  	}
    87  	if dump[1].b.(*memberlistBroadcast).node != "bar" {
    88  		t.Fatalf("missing bar")
    89  	}
    90  	if dump[2].b.(*memberlistBroadcast).node != "test" {
    91  		t.Fatalf("missing test")
    92  	}
    93  }
    94  
    95  func TestTransmitLimited_GetBroadcasts(t *testing.T) {
    96  	q := &TransmitLimitedQueue{RetransmitMult: 3, NumNodes: func() int { return 10 }}
    97  
    98  	// 18 bytes per message
    99  	q.QueueBroadcast(&memberlistBroadcast{"test", []byte("1. this is a test."), nil})
   100  	q.QueueBroadcast(&memberlistBroadcast{"foo", []byte("2. this is a test."), nil})
   101  	q.QueueBroadcast(&memberlistBroadcast{"bar", []byte("3. this is a test."), nil})
   102  	q.QueueBroadcast(&memberlistBroadcast{"baz", []byte("4. this is a test."), nil})
   103  
   104  	// 2 byte overhead per message, should get all 4 messages
   105  	all := q.GetBroadcasts(2, 80)
   106  	require.Equal(t, 4, len(all), "missing messages: %v", prettyPrintMessages(all))
   107  
   108  	// 3 byte overhead, should only get 3 messages back
   109  	partial := q.GetBroadcasts(3, 80)
   110  	require.Equal(t, 3, len(partial), "missing messages: %v", prettyPrintMessages(partial))
   111  }
   112  
   113  func TestTransmitLimited_GetBroadcasts_Limit(t *testing.T) {
   114  	q := &TransmitLimitedQueue{RetransmitMult: 1, NumNodes: func() int { return 10 }}
   115  
   116  	require.Equal(t, int64(0), q.idGen, "the id generator seed starts at zero")
   117  	require.Equal(t, 2, retransmitLimit(q.RetransmitMult, q.NumNodes()), "sanity check transmit limits")
   118  
   119  	// 18 bytes per message
   120  	q.QueueBroadcast(&memberlistBroadcast{"test", []byte("1. this is a test."), nil})
   121  	q.QueueBroadcast(&memberlistBroadcast{"foo", []byte("2. this is a test."), nil})
   122  	q.QueueBroadcast(&memberlistBroadcast{"bar", []byte("3. this is a test."), nil})
   123  	q.QueueBroadcast(&memberlistBroadcast{"baz", []byte("4. this is a test."), nil})
   124  
   125  	require.Equal(t, int64(4), q.idGen, "we handed out 4 IDs")
   126  
   127  	// 3 byte overhead, should only get 3 messages back
   128  	partial1 := q.GetBroadcasts(3, 80)
   129  	require.Equal(t, 3, len(partial1), "missing messages: %v", prettyPrintMessages(partial1))
   130  
   131  	require.Equal(t, int64(4), q.idGen, "id generator doesn't reset until empty")
   132  
   133  	partial2 := q.GetBroadcasts(3, 80)
   134  	require.Equal(t, 3, len(partial2), "missing messages: %v", prettyPrintMessages(partial2))
   135  
   136  	require.Equal(t, int64(4), q.idGen, "id generator doesn't reset until empty")
   137  
   138  	// Only two not expired
   139  	partial3 := q.GetBroadcasts(3, 80)
   140  	require.Equal(t, 2, len(partial3), "missing messages: %v", prettyPrintMessages(partial3))
   141  
   142  	require.Equal(t, int64(0), q.idGen, "id generator resets on empty")
   143  
   144  	// Should get nothing
   145  	partial5 := q.GetBroadcasts(3, 80)
   146  	require.Equal(t, 0, len(partial5), "missing messages: %v", prettyPrintMessages(partial5))
   147  
   148  	require.Equal(t, int64(0), q.idGen, "id generator resets on empty")
   149  }
   150  
   151  func prettyPrintMessages(msgs [][]byte) []string {
   152  	var out []string
   153  	for _, msg := range msgs {
   154  		out = append(out, "'"+string(msg)+"'")
   155  	}
   156  	return out
   157  }
   158  
   159  func TestTransmitLimited_Prune(t *testing.T) {
   160  	q := &TransmitLimitedQueue{RetransmitMult: 1, NumNodes: func() int { return 10 }}
   161  
   162  	ch1 := make(chan struct{}, 1)
   163  	ch2 := make(chan struct{}, 1)
   164  
   165  	// 18 bytes per message
   166  	q.QueueBroadcast(&memberlistBroadcast{"test", []byte("1. this is a test."), ch1})
   167  	q.QueueBroadcast(&memberlistBroadcast{"foo", []byte("2. this is a test."), ch2})
   168  	q.QueueBroadcast(&memberlistBroadcast{"bar", []byte("3. this is a test."), nil})
   169  	q.QueueBroadcast(&memberlistBroadcast{"baz", []byte("4. this is a test."), nil})
   170  
   171  	// Keep only 2
   172  	q.Prune(2)
   173  
   174  	require.Equal(t, 2, q.NumQueued())
   175  
   176  	// Should notify the first two
   177  	select {
   178  	case <-ch1:
   179  	default:
   180  		t.Fatalf("expected invalidation")
   181  	}
   182  	select {
   183  	case <-ch2:
   184  	default:
   185  		t.Fatalf("expected invalidation")
   186  	}
   187  
   188  	dump := q.orderedView(true)
   189  
   190  	if dump[0].b.(*memberlistBroadcast).node != "bar" {
   191  		t.Fatalf("missing bar")
   192  	}
   193  	if dump[1].b.(*memberlistBroadcast).node != "baz" {
   194  		t.Fatalf("missing baz")
   195  	}
   196  }
   197  
   198  func TestTransmitLimited_ordering(t *testing.T) {
   199  	q := &TransmitLimitedQueue{RetransmitMult: 1, NumNodes: func() int { return 10 }}
   200  
   201  	insert := func(name string, transmits int) {
   202  		q.queueBroadcast(&memberlistBroadcast{name, []byte(name), make(chan struct{})}, transmits)
   203  	}
   204  
   205  	insert("node0", 0)
   206  	insert("node1", 10)
   207  	insert("node2", 3)
   208  	insert("node3", 4)
   209  	insert("node4", 7)
   210  
   211  	dump := q.orderedView(true)
   212  
   213  	if dump[0].transmits != 10 {
   214  		t.Fatalf("bad val %v, %d", dump[0].b.(*memberlistBroadcast).node, dump[0].transmits)
   215  	}
   216  	if dump[1].transmits != 7 {
   217  		t.Fatalf("bad val %v, %d", dump[7].b.(*memberlistBroadcast).node, dump[7].transmits)
   218  	}
   219  	if dump[2].transmits != 4 {
   220  		t.Fatalf("bad val %v, %d", dump[2].b.(*memberlistBroadcast).node, dump[2].transmits)
   221  	}
   222  	if dump[3].transmits != 3 {
   223  		t.Fatalf("bad val %v, %d", dump[3].b.(*memberlistBroadcast).node, dump[3].transmits)
   224  	}
   225  	if dump[4].transmits != 0 {
   226  		t.Fatalf("bad val %v, %d", dump[4].b.(*memberlistBroadcast).node, dump[4].transmits)
   227  	}
   228  }