github.com/asynkron/protoactor-go@v0.0.0-20240308120642-ef91a6abee75/cluster/member_list_test.go (about) 1 package cluster 2 3 import ( 4 "fmt" 5 "sort" 6 "sync" 7 "testing" 8 "time" 9 10 "github.com/stretchr/testify/assert" 11 ) 12 13 //func TestPublishRaceCondition(t *testing.T) { 14 // actorSystem := actor.NewActorSystem() 15 // c := New(actorSystem, Configure("mycluster", nil, nil, remote.Configure("127.0.0.1", 0))) 16 // NewMemberList(c) 17 // rounds := 1000 18 // 19 // var wg sync.WaitGroup 20 // wg.Add(2 * rounds) 21 // 22 // go func() { 23 // for i := 0; i < rounds; i++ { 24 // actorSystem.EventStream.Publish(TopologyEvent(Members{{}, {}})) 25 // actorSystem.EventStream.Publish(TopologyEvent(Members{{}})) 26 // wg.Done() 27 // } 28 // }() 29 // 30 // go func() { 31 // for i := 0; i < rounds; i++ { 32 // s := actorSystem.EventStream.Subscribe(func(evt interface{}) {}) 33 // actorSystem.EventStream.Unsubscribe(s) 34 // wg.Done() 35 // } 36 // }() 37 // 38 // if waitTimeout(&wg, 2*time.Second) { 39 // t.Error("Should not run into a timeout") 40 // } 41 //} 42 43 // https://stackoverflow.com/questions/32840687/timeout-for-waitgroup-wait 44 func waitTimeout(wg *sync.WaitGroup, timeout time.Duration) bool { 45 c := make(chan struct{}) 46 go func() { 47 defer close(c) 48 wg.Wait() 49 }() 50 select { 51 case <-c: 52 return false // completed normally 53 case <-time.After(timeout): 54 return true // timed out 55 } 56 } 57 58 func TestMemberList_UpdateClusterTopology(t *testing.T) { 59 c := newClusterForTest("test-UpdateClusterTopology", nil) 60 obj := NewMemberList(c) 61 empty := make([]*Member, 0) 62 63 t.Run("init", func(t *testing.T) { 64 assert := assert.New(t) 65 members := newMembersForTest(2) 66 changes, unchanged, actives, _, _ := obj.getTopologyChanges(members) 67 assert.False(unchanged) 68 expected := &ClusterTopology{TopologyHash: TopologyHash(members), Members: members, Joined: members, Left: empty} 69 assert.Equal(expected.TopologyHash, changes.TopologyHash) 70 71 var m1, m2 *MemberSet 72 m1 = NewMemberSet(expected.Members) 73 m2 = NewMemberSet(changes.Members) 74 assert.Equal(m1, m2) 75 76 m1 = NewMemberSet(expected.Joined) 77 m2 = NewMemberSet(changes.Joined) 78 assert.Equal(m1, m2) 79 80 m1 = NewMemberSet(expected.Left) 81 m2 = NewMemberSet(changes.Left) 82 assert.Equal(m1, m2) 83 84 // current members 85 obj.members = actives 86 }) 87 88 t.Run("join", func(t *testing.T) { 89 assert := assert.New(t) 90 assert.Equal(2, obj.members.Len()) 91 members := newMembersForTest(4) 92 changes, unchanged, actives, _, _ := obj.getTopologyChanges(members) 93 assert.False(unchanged) 94 // _sorted(changes) 95 expected := &ClusterTopology{TopologyHash: TopologyHash(members), Members: members, Joined: members[2:4], Left: empty} 96 assert.Equal(expected.TopologyHash, changes.TopologyHash) 97 98 var m1, m2 *MemberSet 99 m1 = NewMemberSet(expected.Members) 100 m2 = NewMemberSet(changes.Members) 101 assert.Equal(m1, m2) 102 103 m1 = NewMemberSet(expected.Joined) 104 m2 = NewMemberSet(changes.Joined) 105 assert.Equal(m1, m2) 106 107 m1 = NewMemberSet(expected.Left) 108 m2 = NewMemberSet(changes.Left) 109 assert.Equal(m1, m2) 110 111 obj.members = actives 112 }) 113 114 t.Run("left", func(t *testing.T) { 115 assert := assert.New(t) 116 assert.Equal(4, obj.members.Len()) 117 members := newMembersForTest(4) 118 changes, _, _, _, _ := obj.getTopologyChanges(members[2:4]) 119 expected := &ClusterTopology{TopologyHash: TopologyHash(members[2:4]), Members: members[2:4], Joined: empty, Left: members[0:2]} 120 assert.Equal(expected.TopologyHash, changes.TopologyHash) 121 122 var m1, m2 *MemberSet 123 m1 = NewMemberSet(expected.Members) 124 m2 = NewMemberSet(changes.Members) 125 assert.Equal(m1, m2) 126 127 m1 = NewMemberSet(expected.Joined) 128 m2 = NewMemberSet(changes.Joined) 129 assert.Equal(m1, m2) 130 131 m1 = NewMemberSet(expected.Left) 132 m2 = NewMemberSet(changes.Left) 133 assert.Equal(m1, m2) 134 }) 135 } 136 137 func newMembersForTest(count int, kinds ...string) Members { 138 if len(kinds) == 0 { 139 kinds = append(kinds, "kind") 140 } 141 members := make(Members, count) 142 for i := 0; i < count; i++ { 143 members[i] = &Member{ 144 Id: fmt.Sprintf("memberId-%d", i), 145 Host: "127.0.0.1", 146 Port: int32(i), 147 Kinds: kinds, 148 } 149 } 150 return members 151 } 152 153 func TestMemberList_UpdateClusterTopology2(t *testing.T) { 154 c := newClusterForTest("test-UpdateClusterTopology", nil) 155 156 obj := NewMemberList(c) 157 dumpMembers := func(list Members) { 158 t.Logf("membersByMemberId=%d", len(list)) 159 160 for _, m := range list { 161 t.Logf("\t%s", m.Address()) 162 } 163 } 164 165 empty := make([]*Member, 0) 166 167 _ = dumpMembers 168 _sorted := func(tpl *ClusterTopology) { 169 _sortMembers := func(list Members) { 170 sort.Slice(list, func(i, j int) bool { 171 return (list)[i].Port < (list)[j].Port 172 }) 173 } 174 _sortMembers(tpl.Members) 175 _sortMembers(tpl.Left) 176 _sortMembers(tpl.Joined) 177 } 178 179 a := assert.New(t) 180 members := newMembersForTest(2) 181 changes, _, _, _, _ := obj.getTopologyChanges(members) //nolint:dogsled 182 _sorted(changes) 183 184 expected := &ClusterTopology{TopologyHash: TopologyHash(members), Members: members, Joined: members, Left: empty} 185 186 a.Equal(expected.TopologyHash, changes.TopologyHash) 187 188 var m1, m2 *MemberSet 189 m1 = NewMemberSet(expected.Members) 190 m2 = NewMemberSet(changes.Members) 191 a.Equal(m1, m2) 192 193 m1 = NewMemberSet(expected.Joined) 194 m2 = NewMemberSet(changes.Joined) 195 a.Equal(m1, m2) 196 197 m1 = NewMemberSet(expected.Left) 198 m2 = NewMemberSet(changes.Left) 199 a.Equal(m1, m2) 200 } 201 202 func TestMemberList_getPartitionMember(t *testing.T) { 203 t.Parallel() 204 205 c := newClusterForTest("test-memberlist", nil) 206 obj := NewMemberList(c) 207 208 for _, v := range []int{1, 2, 10, 100, 1000} { 209 members := newMembersForTest(v) 210 obj.UpdateClusterTopology(members) 211 212 testName := fmt.Sprintf("member*%d", v) 213 t.Run(testName, func(t *testing.T) { 214 //assert := assert.New(t) 215 // 216 //identity := NewClusterIdentity("name", "kind") 217 //// address := obj.getPartitionMemberV2(identity) 218 //// assert.NotEmpty(address) 219 // 220 //identity = NewClusterIdentity("name", "nonkind") 221 //// address = obj.getPartitionMemberV2(identity) 222 //// assert.Empty(address) 223 }) 224 } 225 } 226 227 //func BenchmarkMemberList_getPartitionMemberV2(b *testing.B) { 228 // SetLogLevel(log.ErrorLevel) 229 // actorSystem := actor.NewActorSystem() 230 // c := New(actorSystem, Configure("mycluster", nil, nil, remote.Configure("127.0.0.1", 0))) 231 // obj := NewMemberList(c) 232 // for i, v := range []int{1, 2, 3, 5, 10, 100, 1000, 2000} { 233 // members := _newTopologyEventForTest(v) 234 // obj.UpdateClusterTopology(members) 235 // testName := fmt.Sprintf("member*%d", v) 236 // runtime.GC() 237 // 238 // identity := &ClusterIdentity{Identity: fmt.Sprintf("name-%d", rand.Int()), Kind: "kind"} 239 // b.Run(testName, func(b *testing.B) { 240 // for i := 0; i < b.N; i++ { 241 // address := obj.getPartitionMemberV2(identity) 242 // if address == "" { 243 // b.Fatalf("empty address membersByMemberId=%d", v) 244 // } 245 // } 246 // }) 247 // } 248 //} 249 250 //func TestMemberList_getPartitionMemberV2(t *testing.T) { 251 // assert := assert.New(t) 252 // 253 // tplg := _newTopologyEventForTest(10) 254 // c := _newClusterForTest("test-memberlist") 255 // obj := NewMemberList(c) 256 // obj.UpdateClusterTopology(tplg, 1) 257 // 258 // assert.Contains(obj.memberStrategyByKind, "kind") 259 // addr := obj.getPartitionMemberV2(&ClusterIdentity{Kind: "kind", Identity: "name"}) 260 // assert.NotEmpty(addr) 261 // 262 // // consistent 263 // for i := 0; i < 10; i++ { 264 // addr2 := obj.getPartitionMemberV2(&ClusterIdentity{Kind: "kind", Identity: "name"}) 265 // assert.NotEmpty(addr2) 266 // assert.Equal(addr, addr2) 267 // } 268 //} 269 270 func TestMemberList_newMemberStrategies(t *testing.T) { 271 t.Parallel() 272 a := assert.New(t) 273 274 c := newClusterForTest("test-memberlist", nil) 275 obj := NewMemberList(c) 276 277 for _, v := range []int{1, 10, 100, 1000} { 278 members := newMembersForTest(v, "kind1", "kind2") 279 obj.UpdateClusterTopology(members) 280 a.Equal(2, len(obj.memberStrategyByKind)) 281 a.Contains(obj.memberStrategyByKind, "kind1") 282 283 a.Equal(v, len(obj.memberStrategyByKind["kind1"].GetAllMembers())) 284 a.Equal(v, len(obj.memberStrategyByKind["kind2"].GetAllMembers())) 285 } 286 }