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 }